使用 Speech-to-Text 实现生产就绪的实时音频转录(教程)

在本教程中,您将使用 Speech-to-TextGoogle Kubernetes Engine (GKE)Memorystore 创建一个对音频流进行实时转录的应用。这是一个设计为具备高可用性和高弹性的应用,并可为生产转录应用提供基准。您在本教程中创建的应用的代码位于 GitHub 代码库中。

本教程是使用 Speech-to-Text 实现生产就绪的实时音频转录的架构指南的配套教程。如需查看对使用场景和设计决策的深入探讨,请参阅该文档。

目标

  • 创建 GKE 集群和 Memorystore 实例。
  • 构建应用微服务并将其部署到 GKE 集群。
  • 通过流式传输音频文件来验证应用行为。
  • 通过引入故障来测试应用的弹性。

费用

本教程使用 Google Cloud 的以下收费组件:

您可使用价格计算器根据您的预计使用情况来估算费用。 Google Cloud 新用户可能有资格申请免费试用

准备工作

  1. 登录您的 Google Cloud 帐号。如果您是 Google Cloud 新手,请创建一个帐号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. 在 Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目。

    转到“项目选择器”

  3. 确保您的 Cloud 项目已启用结算功能。 了解如何确认您的项目是否已启用结算功能

  4. 启用 Cloud Build API and the Speech-to-Text, GKE, and Memorystore API。

    启用 API

  5. 在 Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目。

    转到“项目选择器”

  6. 确保您的 Cloud 项目已启用结算功能。 了解如何确认您的项目是否已启用结算功能

  7. 启用 Cloud Build API and the Speech-to-Text, GKE, and Memorystore API。

    启用 API

架构

下图展示了您将在本教程中部署的架构。

Google Cloud 上适用于生产就绪转录应用的基础架构

该架构包含以下功能:

  • 三个应用微服务:
    • Ingestor:此服务使用源音频流。
    • Transcriber:此服务调用 Speech-to-Text 并发出转录结果。
    • Reviewer:此服务在 Web 应用中显示转录以供审核。
  • GKE,用于托管跨多个区域的地区级 GKE 集群内的应用微服务。应用微服务是跨区域部署的。
  • Memorystore for Redis,用作快速的中间存储。它部署在高可用性配置中。
  • 向互联网公开应用功能以便执行以下操作的负载平衡器:
    • 提供源音频流可以定向到的 IP 地址。
    • 提供审核器 Web 应用。

在本教程中,您将使用以下客户端来测试应用功能:

  • 将音频文件流式传输到 Ingestor 服务的音频客户端脚本。
  • 显示来自 Reviewer 服务的转录的演示版 Web 客户端。

创建 Google Cloud 基础架构

  1. 在 Cloud Shell 中,为您的 Cloud 项目 ID 创建一个变量:

    export PROJECT_ID=project-id
    

    project-id 替换为您为本教程创建或选择的 Cloud 项目的 ID。

  2. 为您的活跃 Cloud Shell 会话设置项目:

    gcloud config set project $PROJECT_ID
    
  3. 创建并启动地区级 GKE 集群:

    gcloud container clusters create transcription-cluster \
        --release-channel=regular \
        --region=us-central1 \
        --node-locations=us-central1-a,us-central1-b \
        --num-nodes=1 \
        --machine-type=n1-highcpu-2 \
        --scopes=cloud-platform \
        --enable-ip-alias \
        --metadata disable-legacy-endpoints=true
    

    在本教程中,您将在 us-central1 地区创建资源。该地区内的两个区域中的单个节点足以完成本教程中的任务。

    此任务可能需要几分钟时间才能完成。

  4. 在 GKE 集群所在的地区中创建标准层级 Memorystore 实例:

    gcloud redis instances create redis-captions \
        --tier=standard \
        --region=us-central1 \
        --zone=us-central1-a
    

    标准层级实例通过复制和自动故障转移提供高可用性。该实例包含指定区域中的一个主节点,以及相同地区内的不同区域中的一个副本。此任务可能需要几分钟时间才能完成。

  5. 创建一个环境变量来存储 Memorystore 实例的 IP 地址:

    export REDIS_HOST=`gcloud redis instances describe redis-captions \
        --region=us-central1 --format='value(host)'`
    

部署微服务

  1. 在 Cloud Shell 中,克隆您将部署的应用代码的 GitHub 代码库:

    git clone https://github.com/GoogleCloudPlatform/solutions-speech-productionized-transcription
    
    
  2. 切换到代码库目录:

    cd solutions-speech-productionized-transcription
    
  3. 启动 Cloud Build 流水线,为应用微服务构建 Docker 容器:

    gcloud builds submit --config cloudbuild.yaml
    

    构建的容器将保存到项目的 Container Registry 中。

  4. 更改 Kubernetes YAML 配置文件以使用您的 Cloud 项目 ID:

    sed -i "s/myproject/$PROJECT_ID/" k8s/*.yaml
    
  5. 更改 Kubernetes YAML 配置文件以设置您的 Memorystore 实例的 IP 地址:

    sed -i "s/redisHost=.*/redisHost=$REDIS_HOST/" k8s/*.yaml
    
  6. IngestorTranscriberReviewer 微服务部署到 GKE 集群:

    kubectl apply -f \
        k8s/ingestor.yaml,k8s/transcriber.yaml,k8s/reviewer.yaml
    
  7. 验证是否已在 GKE 集群中创建所有三个 Kubernetes Deployment:

    kubectl get deployments
    

    输出类似于以下内容:请注意,每个部署都有两个 pod。

    NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
    ingestor-deployment     2/2     2            2           13s
    reviewer-deployment     2/2     2            2           12s
    transcriber-deployment  2/2     2            2           12s
    
  8. 验证是否已在 GKE 集群中创建 IngestorReviewer Kubernetes 服务:

    kubectl get services
    

    输出类似于以下内容:

    NAME               TYPE           CLUSTER-IP   EXTERNAL-IP
    ingestor-service   LoadBalancer   10.0.9.193   35.224.219.112
    kubernetes         ClusterIP      10.0.0.1     <none>
    reviewer-service   LoadBalancer   10.0.9.203   35.223.138.37
    
  9. 将环境变量设置为 Ingestor 服务的外部 IP 地址:

    export INGEST_IP=`kubectl get services ingestor-service \
        -o jsonpath='{.status.loadBalancer.ingress[0].ip}'`
    
  10. 获取 Ingestor 页面的内容以检查页面是否可用:

    curl $INGEST_IP; echo
    

    如果该页面正常运行,您会看到一条 Hello 消息。

  11. 使用 Reviewer 服务的外部 IP 地址设置环境变量,并在控制台中显示变量值:

    export REVIEWER_IP=`kubectl get services reviewer-service \
        -o jsonpath='{.status.loadBalancer.ingress[0].ip}'`; \
        echo $REVIEWER_IP
    
  12. 复制上述命令中显示的 REVIEWER_IP 地址。

  13. 在本地机器上打开一个浏览器标签页,访问刚才复制的 IP 地址。

    您会看到一个显示文本 Live Transcription demo 的审核器网页。之后,转录将写入此网页,因此请确保此页面保持打开状态。

验证音频流的转录

在本部分中,您将音频文件流式传输到刚刚部署的应用,并检查生成的转录内容。该音频朗读了路易斯·卡罗所著《爱丽丝镜中奇遇记》的《矮胖子》一章中的前几句。如需比较 Speech-to-Text 转录音频的质量,您可以在 Gutenberg.org 网站上查看该章节的文本。

音频客户端使用 SocketIO 库将音频流式传输到 Ingestor 服务,该库是一个开源软件包,用于提供实时、可靠的双向通信。同样,Reviewer 服务使用 SocketIO 将转录传送给演示版 Web 客户端。

Transcriber 服务包括与示例音频文件的特征匹配的 Speech-to-Text 配置。具体来说,该配置定义了音频采样率 (44100 kHz)、音频通道数(单通道;单声道)和输入语言(美国英语)。如果要流式传输其他音频文件,则可能需要更新配置以匹配输入音频。

  1. 在 Cloud Shell 中,切换到客户端目录:

    cd client
    
  2. 创建并激活新的 Python 3 虚拟环境。virtualenv 实用程序已安装在 Cloud Shell 中。

    virtualenv -p python3 venv
    source venv/bin/activate
    
  3. 安装演示版 Web 客户端所需的 Python 软件包:

    pip install -r requirements.txt
    
  4. 运行音频客户端脚本,将音频文件流式传输到 Ingestor 服务:

    python audio_client.py --targetip $INGEST_IP \
        --file humptydumpty.wav
    
  5. 在本地机器上,返回到审核器网页。

    您将看到转录正在流式传输到该页面。

  6. 比较 Speech-to-Text 转录与章节文本,以确定转录的准确度。

    以下屏幕截图显示了文本和示例转录。

    原始文本位于上方,转录位于下方。

  7. 在 Cloud Shell 中,按 Ctrl+C 停止音频流。

测试转录器故障转移

配套指南中所述,Transcriber 服务使用领导者选举模式来确保只有一个 Transcriber pod 连接到 Speech- to-Text,其余 pod 充当热备用 pod,以实现高效的故障转移。在本部分中,您将通过监控主要 pod 被删除时的转录输出来验证故障转移行为。

在恢复过程中,当新的 Transcriber pod 被选为主要 pod 时,新的主要 pod 会重放最近收到的音频的最后几秒钟。这有助于最大限度地减少之前的主要 pod 离线时的音频损失。由于重放上一个音频,此方法可能会导致一些重复的转录字词。在生产应用中,使用转录的流程必须协调任何重复内容。

  1. 在本地机器上,刷新浏览器标签页,以从审核器网页中清除任何现有的转录。

  2. 在 Cloud Shell 中重启音频客户端:

    python audio_client.py --targetip $INGEST_IP \
        --file humptydumpty.wav
    

    您将看到转录出现在审核器网页中。

  3. 在同一浏览器标签页中,打开另一个 Cloud Shell 标签页,这样您就有两个打开的 Cloud Shell 终端。

  4. 在新的 Cloud Shell 标签页中,将环境变量设置为您的项目 ID:

    export PROJECT_ID=project-id
    

    project-id 替换为您为本教程创建或选择的 Cloud 项目的 ID。

  5. 切换到代码库目录:

    cd solutions-speech-reliable-transcription
    
  6. 删除主要转录器 pod:

    python3 deleter.py --leader --iterations 3 --delay 15
    

    脚本查询 Kubernetes 控制层面以获取当前主要 pod 的身份,然后删除该 pod。该命令删除主要 pod 三次,每次迭代之间等待 15 秒。

  7. 监控审核器网页。

    您会在转录流中看到 [REPLAY] 通知。这表示新的 Transcriber pod 已被选为主要 pod,并且正在重放最后几秒钟的音频数据。您可能会在转录中看到一些重复的字词。您会观察到故障转移非常迅速,并且转录输出的中断时间极短。

  8. 验证 Transcriber 部署是否仍然有两个 pod:

    kubectl get pods -l=app=transcriber
    

    输出类似于以下内容:

    NAME                                      READY   STATUS
    transcriber-deployment-7f57746c7c-rjwm5   2/2     Running
    transcriber-deployment-7f57746c7c-t7srr   2/2     Running
    

    由于 Transcriber 是 Kubernetes Deployment,因此 Kubernetes 会自动创建新的 pod 以满足指定的 pod 副本数量。

  9. 返回到第一个 Cloud Shell 标签页,然后按 Ctrl+C 停止音频客户端。

删除其他微服务 pod

在上一部分中,您已经验证了 Transcriber pod 被删除时转录传送不会中断。在本部分中,您将测试其他微服务 pod 被删除时的应用行为。

IngestorReviewer pod 由 LoadBalancer 类型的 Kubernetes 服务向互联网公开。客户端使用稳定的 IP 地址连接到每个 Kubernetes 服务,Kubernetes 将流量路由到可用的 pod。IngestorReviewer pod 被删除时,Kubernetes 会更新相应的服务,这样流量就不会定向到不存在的 pod。同样,随后创建新 pod 以满足配置的 pod 副本数量时,Kubernetes 会更新服务,以便将流量发送到新的 pod。

在此应用中,您依靠此行为使流量持续通过应用传输。由于 IngestorReviewer 服务都有两个 pod,因此当一个 pod 被移除时,Kubernetes 可以迅速将流量重定向到另一个已就绪并且可以开始处理流量的 pod。

音频客户端和演示版 Web 客户端都使用 SocketIO 连接 IngestorReviewer 服务。当 SocketIO 断开连接时,它会自动尝试重新连接。这样一来,如果当前 pod 被删除,则客户端会使用相同的服务 IP 地址重新连接到新的 pod。

删除提取器 pod

  1. 在本地机器上,刷新浏览器标签页,以从审核器网页中清除现有的转录。

  2. 在 Cloud Shell 中重启音频客户端:

    python audio_client.py --targetip $INGEST_IP \
        --file humptydumpty.wav
    

    您将看到转录出现在审核器页面中。

  3. 切换到另一个 Cloud Shell 标签页。

  4. 删除 Ingestor pod:

    python3 deleter.py --applabel ingestor --iterations 5 --delay 15
    

    该脚本查询 Kubernetes 控制层面以获取所有 Ingestor pod 的名称,然后删除一个随机选择的 pod。该命令删除 pod 五次,每次迭代之间等待 15 秒。

    由于脚本随机选择要删除的 Ingestor pod,因此与音频客户端连接的 pod 只有大约一半的时间处于删除状态。删除未连接到音频客户端的 pod 不会产生任何影响。

  5. 监控审核器网页。即使系统正在删除 pod,转录仍然继续流式传输到页面,没有出现重大中断现象。

  6. 切换到正在运行音频客户端的另一个 Cloud Shell 标签页。

    您会观察到,每当与 Ingestor pod 的连接断开并重新建立时,客户端都会显示消息。

  7. Ctrl+C 停止音频客户端。

删除审核器 pod

  1. 在本地机器上,刷新浏览器标签页,以从审核器网页中清除现有的转录。

  2. 在 Cloud Shell 中重启音频客户端:

    python audio_client.py --targetip $INGEST_IP \
        --file humptydumpty.wav
    

    您将看到转录出现在审核器网页中。

  3. 切换到另一个 Cloud Shell 标签页。

  4. 删除 Reviewer pod:

    python3 deleter.py --applabel reviewer --iterations 5 --delay 15
    

    该脚本查询 Kubernetes 控制层面以获取所有 Reviewer pod 的名称,然后删除一个随机选择的 pod。该命令删除 pod 五次,每次迭代之间等待 15 秒。

  5. 监控审核器网页。

    即使系统正在删除 pod,转录仍然继续流式传输到页面,没有出现重大中断现象。页面会显示它所连接的 Reviewer pod 的名称。当 pod 被删除并且页面与其他 pod 建立连接时,您会看到此字段发生变化。

    与之前一样,由于 Reviewer pod 是随机选择来删除的,因此审核器网页连接的 pod 大约只有一半的时间处于删除状态。删除未连接到演示版 Web 客户端的 pod 对转录传送没有任何影响。

  6. 切换到另一个 Cloud Shell 标签页,然后按 Ctrl+C 停止音频客户端。

测试 Memorystore for Redis 故障转移

应用使用 Memorystore for Redis 实现快速的内存存储。它使用 Memorystore for Redis 标准层级实例,该实例通过复制和自动故障转移提供高可用性。标准层级实例会自动配置为一个主实例和副本对。副本充当备用实例,并且与主实例位于不同的区域。如果主实例发生故障,请求会自动重定向至副本。

在本部分中,您将通过启动手动故障转移来测试 Memorystore for Redis 故障转移行为。在 Memorystore for Redis 服务将副本提升为主实例期间,Memorystore for Redis 实例暂时不可用。这意味着在故障转移期间,转录会停止。

  1. 在本地机器上,刷新浏览器标签页,以从审核器网页中清除现有的转录。
  2. 在 Cloud Shell 中,重启音频客户端以开始流式传输音频:

    python audio_client.py --targetip $INGEST_IP \
        --file humptydumpty.wav
    
  3. 在另一个 Cloud Shell 标签页中,启动 Memorystore for Redis 的手动故障转移,并确认要继续进行故障转移。

    gcloud redis instances failover redis-captions \
        --region us-central1 --project $PROJECT_ID
    
  4. 在审核器网页上查看转录输出。

    您会看到 [REDIS-FAILOVER] 通知,表示 Memorystore 不可用。与预期一样,在副本提升为主实例时转录会停止。此过程完成后,系统会处理缓冲的音频数据,并恢复转录。

清除数据

为避免因本教程中使用的资源导致您的 Google Cloud 帐号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

删除项目

  1. 在 Cloud Console 中,转到管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

后续步骤