You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Angular中安全实现Google Speech-To-Text流式识别?

在Angular客户端安全实现Google Speech-To-Text流式处理的方案

问题背景

原本在Node.js Firebase Functions中通过@google-cloud/speech实现非流式语音转文字,但无法满足流式处理需求,计划迁移到Angular客户端实现,需要安全的认证方案,且希望避免引入gRPC相关库带来的额外工作量。

原Firebase Functions代码:

import {SpeechClient} from "@google-cloud/speech";

export const transcriptAudio = onCall(async (data) => {
  let userId = data.auth?.token?.uid;
  if(!userId)
    throw new HttpsError('unauthenticated', 'The user is not authenticated.');

  let audioByte = data.data.audioByte as string;

  // Detects speech in the audio file
  const client = new SpeechClient();
  const response = await client.recognize(
    {
      audio: {content: audioByte},
      config: {
        encoding: "LINEAR16",
        audioChannelCount: 2,
        languageCode: "en-US"}});

  const transcription = response[0].results?.map(result => result.alternatives![0].transcript).join('\n');
  return transcription;
});

一、安全认证方案(基于Firebase Functions生成受限令牌)

1. 在Firebase Functions中添加令牌生成接口

通过Callable Function验证用户身份后,生成仅授权访问Speech-To-Text流式API的短期访问令牌,避免直接暴露服务账号密钥:

import { onCall, HttpsError } from "firebase-functions/v2/https";
import { GoogleAuth } from "google-auth-library";

export const getSpeechToken = onCall(async (request) => {
  const userId = request.auth?.token?.uid;
  if (!userId) {
    throw new HttpsError('unauthenticated', '用户未认证');
  }

  const auth = new GoogleAuth({
    scopes: ['https://www.googleapis.com/auth/cloud-platform']
  });
  const client = await auth.getClient();
  // 生成有效期1小时的令牌,可根据需求调整
  const tokenResponse = await client.getAccessToken();
  
  return {
    accessToken: tokenResponse.token,
    expiresAt: tokenResponse.res!.data.expires_in
  };
});

注意:需确保Firebase Functions的服务账号拥有roles/speech.client权限,避免过度授权。

2. Angular客户端获取令牌并发起请求

在Angular组件中调用上述Callable Function获取令牌,之后用该令牌请求Speech-To-Text API:

import { AngularFireFunctions } from '@angular/fire/compat/functions';
import { HttpClient } from '@angular/common/http';

export class SpeechComponent {
  private speechToken: string | null = null;

  constructor(
    private fireFunctions: AngularFireFunctions,
    private http: HttpClient
  ) {}

  async getAuthToken(): Promise<void> {
    const getToken = this.fireFunctions.httpsCallable('getSpeechToken');
    const result = await getToken({}).toPromise();
    this.speechToken = result.accessToken;
  }
}

二、简化流式处理的替代方案(无需gRPC)

Google Speech-To-Text支持REST流式API(基于HTTP/2),无需引入gRPC或ngx-grpc库,可直接用Angular的HttpClient结合RxJS处理流式响应:

1. 流式请求核心代码

startStreamingRecognition(audioStream: ReadableStream) {
  if (!this.speechToken) {
    throw new Error('未获取到认证令牌');
  }

  const url = 'https://speech.googleapis.com/v1/speech:streamingRecognize';
  
  // 构建请求体,先发送配置信息,再流式发送音频数据
  const requestBody = new ReadableStream({
    async start(controller) {
      // 发送初始配置帧
      controller.enqueue(JSON.stringify({
        streamingConfig: {
          config: {
            encoding: 'LINEAR16',
            audioChannelCount: 2,
            languageCode: 'en-US'
          },
          interimResults: true // 返回实时中间识别结果
        }
      }) + '\r\n');

      // 流式转发音频数据
      const reader = audioStream.getReader();
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        // 将音频二进制数据包装成JSON帧发送
        controller.enqueue(JSON.stringify({ audioContent: btoa(String.fromCharCode(...new Uint8Array(value))) }) + '\r\n');
      }
      controller.close();
    }
  });

  // 发起流式POST请求
  this.http.post(url, requestBody, {
    headers: {
      'Authorization': `Bearer ${this.speechToken}`,
      'Content-Type': 'application/json'
    },
    responseType: 'text',
    observe: 'response'
  }).subscribe({
    next: (response) => {
      // 解析流式响应的每一行结果
      const chunks = response.body?.split('\r\n').filter(chunk => chunk);
      chunks?.forEach(chunk => {
        const result = JSON.parse(chunk);
        const transcript = result.results?.[0]?.alternatives?.[0]?.transcript;
        if (transcript) {
          console.log('识别结果:', transcript);
          // 更新UI展示识别内容
        }
      });
    },
    error: (err) => {
      console.error('流式识别出错:', err);
    }
  });
}

2. 关键说明

  • 该方案基于HTTP/2的分块传输,Angular的HttpClient会自动处理流式响应
  • interimResults: true配置可返回实时的中间识别结果,满足流式场景需求
  • 音频数据需按要求编码为Base64字符串后发送

内容的提问来源于stack exchange,提问作者mctuna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 05:54:53