基于NVIDIA Jetson与Riva SDK的实时语音识别系统部署实战
1. 项目概述在边缘设备上实现实时语音转文字最近在折腾一个挺有意思的项目核心目标是在Nvidia Jetson这类边缘计算设备上实现一个高效、实时的语音字幕生成系统。简单来说就是让设备能“听懂”人说话并立刻把内容转换成文字显示出来就像我们看视频时的实时字幕一样。这个需求在智能会议记录、实时翻译、无障碍辅助工具甚至是一些需要即时反馈的交互式机器人场景里都非常实用。为什么偏偏选Jetson这其实是个很实际的考量。很多语音识别ASR服务都在云端延迟和网络稳定性是个大问题更别提隐私和数据安全了。而Jetson系列从入门的Nano到性能强悍的Orin都内置了NVIDIA的GPU能本地化运行经过优化的AI模型把延迟降到最低真正做到实时响应。我这次用的是一块Jetson Orin Nano算是中端性能兼顾了成本和能力。整个项目的核心就是围绕NVIDIA Riva这个语音AI SDK来搭建。Riva不是某个单一的模型而是一个集成了自动语音识别ASR、文本转语音TTS等功能的工具包并且针对NVIDIA的硬件尤其是Jetson做了深度优化。它提供了从服务器端部署到客户端调用的完整方案我们只需要在Jetson上把Riva服务跑起来然后写个简单的客户端程序去调用它就能获得高质量的语音转文字流。听起来好像很简单但在实际部署和调优过程中从驱动兼容性、服务配置到资源优化每一步都有不少细节需要注意这也是我想在这篇分享里重点聊的。2. 核心需求解析与技术选型2.1 为什么是本地化语音识别在深入技术细节之前我们先聊聊“为什么”。把语音识别放在Jetson这样的边缘设备上做而不是调用云端API主要基于几个硬核需求首先是实时性与低延迟。对于字幕生成尤其是直播、同声传译或交互式应用几百毫秒的延迟都是不可接受的。云端ASR需要经历“音频采集 - 编码 - 网络上传 - 云端处理 - 网络回传 - 解码显示”这一长串流程网络抖动会直接导致字幕卡顿或不同步。本地处理则完全规避了网络延迟音频数据直接在设备内存中流转处理速度仅取决于本地算力。其次是数据隐私与安全性。很多会议内容、医疗问诊或私人对话涉及敏感信息将原始音频流上传到第三方云端存在潜在风险。本地处理意味着数据不出设备从根本上解决了隐私顾虑这对于企业级应用和特定行业场景是刚性要求。最后是成本与可靠性。云端ASR服务通常按调用次数或时长收费长期运行成本不菲。而本地部署是一次性硬件投入后续边际成本极低。同时它不依赖外部网络在网络条件不佳或完全离线的环境下如野外作业、车载系统依然可以稳定工作。2.2 硬件平台NVIDIA Jetson家族简析Jetson系列是NVIDIA为边缘AI和机器人推出的模块化计算平台。选择哪一款直接决定了项目的性能上限和成本。Jetson Nano入门级选择功耗低5W/10W模式适合对实时性要求不高、识别词汇量有限的轻量级应用或原型验证。运行完整的Riva流式ASR可能会比较吃力。Jetson Orin Nano我本次项目的主力。它提供了比Nano强得多的AI算力最高40 TOPS内存也更充裕能够非常流畅地运行Riva的中等规模语音模型是平衡性能与成本的理想选择。Jetson Orin NX / AGX Orin高性能版本适用于需要处理多路音频流、极低延迟或运行更大、更精准ASR模型的场景比如多语种实时翻译系统。选择Orin Nano是因为它在一个合理的价格区间内提供了足以支撑高质量、流式语音识别的算力并且其功耗和散热设计也适合长时间运行。2.3 软件栈核心为什么是NVIDIA Riva市面上开源的ASR工具包不少比如Kaldi、ESPnet等。但在Jetson生态里Riva几乎是“官配”首选原因如下硬件深度优化Riva的底层引擎称为TAO Toolkit和运行时TensorRT与Jetson的GPU架构紧密结合。模型推理时能充分利用GPU的Tensor Core进行混合精度计算效率远高于在CPU上运行或使用通用框架如PyTorch/TensorFlow的未优化版本。生产就绪的流水线Riva不是一个单纯的模型它提供了一套完整的语音AI微服务。包括音频前端处理VAD-语音活动检测、去噪、回声消除、流式ASR引擎、标点符号与大小写恢复称为“标点恢复与大小写转换”等。这些组件都是开箱即用的省去了我们自己组装和调试复杂信号处理流水线的麻烦。灵活的模型部署Riva支持使用NVIDIA TAO Toolkit训练或微调的自定义模型也提供了预训练的、性能优异的官方模型如Citrinet、Conformer。我们可以根据对精度、速度和模型大小的需求进行选择。便捷的客户端APIRiva服务通过gRPC提供接口客户端调用非常简单。NVIDIA提供了Python、C等语言的SDK几行代码就能建立起流式语音识别连接。综合来看在Jetson上做语音字幕生成“Jetson硬件 Riva软件栈”是一条被验证过的高效路径。它降低了从零构建一个高性能ASR系统的门槛让我们能把精力更多集中在应用逻辑和优化上。3. 环境准备与Riva服务部署3.1 Jetson系统初始化与驱动确认拿到Jetson设备后第一件事是确保系统基础环境正确。官方推荐使用JetPack SDK它包含了适配该硬件版本的Linux操作系统、GPU驱动、CUDA、cuDNN和TensorRT等核心组件。注意务必使用与你的Jetson模块型号完全匹配的JetPack版本。不同版本间的驱动和库不兼容是后续所有问题的万恶之源。开机后首先打开终端进行一系列健康检查# 1. 检查JetPack版本和信息 sudo apt update sudo apt install -y jetson-stats jtop运行jtop后可能需要sudo一个交互式仪表盘会出现。在这里你要重点确认NV Power Mode确保不是最低功耗的MAXN模式对于Orin NanoMODE 15W或MODE 30W能提供更好性能。GPU、CPU、RAM状态是否正常。JetPack Info显示当前安装的JetPack版本、CUDA、TensorRT等关键库的版本号。# 2. 检查NVIDIA驱动和CUDA cat /proc/driver/nvidia/version nvcc --version第一条命令输出驱动版本第二条输出CUDA编译器版本。确保它们存在且无报错。# 3. 检查TensorRT dpkg -l | grep tensorrt python3 -c import tensorrt; print(tensorrt.__version__)TensorRT是Riva模型推理加速的核心必须正确安装。3.2 安装Docker与NVIDIA Container ToolkitRiva通常以Docker容器的方式部署这保证了环境的一致性。Jetson是ARM架构所以我们需要安装ARM版本的Docker。# 卸载可能存在的旧版本 sudo apt-get remove docker docker-engine docker.io containerd runc # 安装依赖和Docker官方GPG密钥 sudo apt-get update sudo apt-get install -y ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod ar /etc/apt/keyrings/docker.asc # 添加Docker的APT仓库 (注意此处以Ubuntu Jammy为例请根据你的JetPack底层系统调整) echo \ deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release echo $VERSION_CODENAME) stable | \ sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt-get update # 安装Docker引擎 sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # 将当前用户加入docker组避免每次都用sudo sudo usermod -aG docker $USER newgrp docker # 立即生效或需要重新登录 # 验证安装 docker --version接下来安装让Docker容器能使用Jetson GPU的关键组件——NVIDIA Container Toolkit。# 添加NVIDIA Container Toolkit仓库 distribution$(. /etc/os-release;echo $ID$VERSION_ID) curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \ sed s#deb https://#deb [signed-by/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g | \ sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list sudo apt-get update sudo apt-get install -y nvidia-container-toolkit # 配置Docker使用nvidia作为默认运行时 sudo nvidia-ctk runtime configure --runtimedocker sudo systemctl restart docker # 验证GPU在容器中是否可见 docker run --rm --runtimenvidia --gpus all nvidia/cuda:11.8.0-base-ubuntu22.04 nvidia-smi如果最后一条命令能成功输出Jetson的GPU信息恭喜你最棘手的部分已经完成。3.3 部署NVIDIA Riva语音服务Riva提供了详细的部署脚本。我们需要先下载Riva的快速启动资源包里面包含了配置文件和部署脚本。# 创建一个项目目录并进入 mkdir ~/riva_project cd ~/riva_project # 从NGCNVIDIA GPU Cloud拉取Riva快速启动包 # 你需要先在 https://ngc.nvidia.com 注册账号并获取API密钥 # 将下方的YOUR_NGC_API_KEY替换为你的密钥 export NGC_API_KEYYOUR_NGC_API_KEY # 登录NGC Docker Registry docker login nvcr.io # 用户名$oauthtoken # 密码你的NGC API密钥 # 下载部署脚本和配置文件 # 注意选择与你的JetPack/CUDA版本兼容的Riva版本。例如对于JetPack 5.x/6.x Riva 2.x.x 是常见选择。 # 以下命令仅为示例具体版本号请查阅NVIDIA Riva官方文档。 docker pull nvcr.io/nvidia/riva/riva-speech:2.18.0-slim docker pull nvcr.io/nvidia/riva/riva-speech:2.18.0-client # 实际上更常用的方式是使用 riva_init.sh 脚本它会自动处理模型下载和配置。 # 我们需要从NGC下载这个初始化脚本。 wget --content-disposition https://api.ngc.nvidia.com/v2/resources/nvidia/riva/riva_quickstart/versions/2.18.0/zip -O riva_quickstart_2.18.0.zip unzip riva_quickstart_2.18.0.zip cd riva_quickstart_2.18.0解压后目录里会有riva_init.sh,riva_start.sh,riva_stop.sh等脚本以及config.sh配置文件。接下来是关键步骤配置config.sh。# 编辑配置文件 nano config.sh你需要修改以下几个核心参数RIVA_LOCAL_USER保持默认或设为你的用户名。RIVA_LOCAL_GROUP保持默认。RIVA_LOCAL_MODEL_LOCATION模型存储路径例如~/riva_models。确保磁盘空间充足下载的模型可能超过10GB。RIVA_NGC_API_KEY你的NGC API密钥。RIVA_SPEECH_SERVICES定义启动哪些服务。对于字幕生成我们至少需要asr。可以设置为asr或asr,tts。RIVA_GPU_DEVICE指定GPU。Jetson通常只有一块GPU设为0。RIVA_ASR_LANGUAGE_CODE语音识别语言。设为zh-CN表示中文普通话。RIVA_ASR_SERVICE_DEFAULT_MODEL默认ASR模型。对于中文一个常见选择是 Mandarin-Citrinet-1024-Gamma具体可用模型名需查阅文档。你也可以选择更小更快的模型如 Mandarin-Citrinet-256-Gamma在Jetson上性能更好。非常重要找到关于RIVA_TARGET_DEVICE或RIVA_JETSON的参数。对于Jetson平台必须确保它被设置为“jetson”或类似标识这样脚本才会拉取ARM架构的、针对Jetson优化的容器镜像和模型。保存配置后运行初始化脚本。这个过程会从NGC下载指定的语音模型耗时较长取决于网络和模型大小。# 初始化下载模型 bash riva_init.sh初始化完成后启动Riva服务# 启动Riva服务器容器 bash riva_start.sh使用docker ps命令你应该能看到一个名为riva-speech的容器正在运行。服务默认会在:8000端口提供gRPC API在:8001端口提供HTTP健康检查。4. 客户端开发与流式字幕生成实现服务跑起来后我们就要编写客户端程序去调用它实现“录音 - 发送 - 接收文字 - 显示”的完整流程。4.1 理解Riva流式ASR的API工作流程Riva的流式ASR不是简单的“发送整个音频文件返回整个文本”。它采用双向流Bidirectional Streaming模式更贴近实时场景建立连接客户端通过gRPC与服务器的StreamingRecognize方法建立连接。发送配置客户端首先发送一个StreamingRecognizeRequest里面包含识别配置RecognitionConfig如语言编码、模型名、是否启用自动标点等。流式发送音频客户端将音频数据切成小块例如每块包含100ms的音频持续发送到服务器。这些请求里只包含音频内容。流式接收结果服务器一边处理音频一边实时返回中间结果is_finalfalse和最终结果is_finaltrue。中间结果会不断被修正这为我们实现“逐字打出”的动画效果提供了可能。结束识别当音频发送完毕后客户端发送一个标志位告知服务器然后关闭发送流等待接收所有剩余结果后关闭连接。4.2 Python客户端代码详解下面是一个精简但功能完整的Python客户端示例它使用麦克风实时录音并打印出识别结果。#!/usr/bin/env python3 实时语音字幕生成客户端 (用于NVIDIA Riva) import argparse import queue import sys import threading import time import grpc import pyaudio # 用于音频采集 import riva.client from riva.client.audio_io import MicrophoneStream from riva.client import ( AudioEncoding, RecognitionConfig, StreamingRecognitionConfig, StreamingRecognizeRequest, ) # Riva服务器地址 RIVA_SERVER_URL localhost:50051 # 默认gRPC端口根据你的riva_start.sh配置调整 def listen_print_loop(responses, output_queue): 从服务器响应流中迭代获取结果并处理。 for response in responses: if not response.results: continue result response.results[0] if not result.alternatives: continue transcript result.alternatives[0].transcript # 如果结果是最终版本is_finalTrue通常是一个完整的句子或段落 if result.is_final: # 将最终结果放入队列供主线程或其他显示线程使用 output_queue.put(([FINAL] transcript, True)) print(f\r[Final] {transcript}, flushTrue) else: # 中间结果可以用于实时显示“正在输入”的效果 output_queue.put((transcript, False)) print(f\r[Interim] {transcript} , end, flushTrue) def main(): parser argparse.ArgumentParser(descriptionRiva流式ASR客户端) parser.add_argument(--server, defaultRIVA_SERVER_URL, helpRiva服务器地址 (host:port)) parser.add_argument(--language-code, defaultzh-CN, help语言代码如 en-US, zh-CN) parser.add_argument(--sample-rate-hz, typeint, default16000, help音频采样率 (Hz)) parser.add_argument(--audio-channels, typeint, default1, help音频通道数 (单声道)) args parser.parse_args() # 1. 创建gRPC通道和客户端存根 auth riva.client.Auth(uriargs.server, use_sslFalse) # Jetson本地部署通常不用SSL client riva.client.ASRService(auth) # 2. 配置识别参数 config RecognitionConfig( encodingAudioEncoding.LINEAR_PCM, sample_rate_hertzargs.sample_rate_hz, language_codeargs.language_code, max_alternatives1, enable_automatic_punctuationTrue, # 启用自动标点对字幕很重要 enable_word_time_offsetsFalse, # 不需要词级时间戳可以关闭以节省资源 ) streaming_config StreamingRecognitionConfig(configconfig, interim_resultsTrue) # 必须开启中间结果 # 3. 创建一个队列用于传递识别结果用于跨线程通信 result_queue queue.Queue() # 4. 启动一个线程专门用于处理和显示结果 def result_printer(): current_interim while True: try: transcript, is_final result_queue.get(timeout0.1) if is_final: # 最终结果清空当前中间结果显示并打印最终结果 sys.stdout.write(\r * (len(current_interim) 12) \r) # 清空行 print(f {transcript}) current_interim else: # 更新中间结果 current_interim transcript except queue.Empty: continue print_thread threading.Thread(targetresult_printer, daemonTrue) print_thread.start() # 5. 设置音频流参数与配置一致 chunk int(args.sample_rate_hz / 10) # 100ms的音频帧 format pyaudio.paInt16 channels args.audio_channels # 6. 创建麦克风流并开始识别 print(\n 开始聆听请说话... (按 CtrlC 停止) \n) with MicrophoneStream( args.sample_rate_hz, chunk, channels, formatformat, device_indexNone # 使用默认麦克风 ) as stream: # 此方法内部会处理双向流通信 responses client.streaming_recognize( audio_chunksstream, streaming_configstreaming_config, ) # 将响应传递给处理循环 listen_print_loop(responses, result_queue) if __name__ __main__: try: main() except KeyboardInterrupt: print(\n\n识别已停止。) except Exception as e: print(f发生错误: {e}, filesys.stderr)4.3 代码关键点与优化音频流对齐MicrophoneStream生成器产生的音频块大小必须与Riva服务期望的块大小匹配。上述代码中chunk sample_rate / 10意味着每块是100ms的音频这是一个比较通用的值。如果出现识别不准确或延迟高可以尝试调整这个值例如50ms或200ms。中间结果处理interim_resultsTrue是实时字幕的灵魂。它让服务器返回未完成的假设客户端可以利用这个实现“逐字输出”的动态效果用户体验更好。处理时要注意用回车符\r来覆盖上一行中间结果避免屏幕滚动混乱。线程安全音频采集主线程和结果处理/显示result_printer线程是分离的通过queue.Queue进行通信。这避免了因显示操作阻塞而导致音频数据积压。错误处理与重连生产环境中需要增加更健壮的错误处理比如gRPC连接断开后的自动重连机制。资源清理确保在程序退出时正确关闭音频流和gRPC通道。5. 性能调优与资源管理在资源受限的Jetson上让Riva服务稳定、高效地运行需要一些调优技巧。5.1 Jetson电源模式与散热管理Jetson的性能和功耗直接相关。使用sudo jetson_clocks命令可以锁定CPU和GPU到最高频率但这会显著增加功耗和发热。对于长时间运行的语音服务更推荐使用nvpmodel工具选择平衡的模式。# 查看当前电源模式 sudo nvpmodel -q # 设置电源模式 (例如Jetson Orin Nano 模式0是15W模式1是30W) sudo nvpmodel -m 0 # 设置为15W模式平衡性能和功耗同时良好的物理散热至关重要。如果设备外壳封闭可以考虑增加散热风扇或改用散热更好的外壳防止因过热导致CPU/GPU降频。5.2 Riva服务配置调优在config.sh或更高级的config.py如果使用高级部署中可以调整服务参数模型选择在Jetson上模型大小直接影响推理速度和内存占用。Citrinet-256比Citrinet-1024小得多速度更快精度略有牺牲。对于中文可以尝试“ Mandarin-Citrinet-256-Gamma”。通过修改RIVA_ASR_SERVICE_DEFAULT_MODEL来切换。并发流数RIVA_ASR_NUM_CONCURRENT_STREAMS参数控制服务能同时处理多少个音频流。在Jetson Orin Nano上处理1-2个高质量流是稳妥的。增加此数会占用更多内存和计算资源可能影响延迟。批处理大小Riva服务内部可能会对请求进行批处理以提高GPU利用率。对于流式识别批处理大小通常较小如1或2。可以在高级配置中调整但非必要不建议改动。5.3 客户端音频处理优化采样率与格式确保客户端录音的采样率如16000 Hz和音频格式如16-bit PCM与Riva服务配置RecognitionConfig完全一致避免不必要的重采样开销。静音检测VAD虽然Riva服务端有VAD但在客户端增加一个轻量级的VAD前置过滤可以在无人说话时暂停向服务器发送数据节省带宽和服务器资源。WebRTC的VAD是一个不错的选择。音频压缩如果客户端与服务端不在同一台机器虽然本项目是可以考虑使用Opus等低比特率编码压缩音频后再传输减少网络负载。但本地部署通常不需要。5.4 监控工具使用持续监控系统资源有助于发现瓶颈jtop实时查看CPU/GPU/内存使用率、温度、功耗和频率。docker stats查看Riva容器的资源消耗。docker stats $(docker ps --filter nameriva-speech -q)Riva内置指标Riva服务暴露了Prometheus格式的指标默认在:8002/metrics可以监控请求延迟、队列长度等。6. 常见问题排查与实战心得在实际部署和开发过程中我遇到了不少坑这里总结一下希望能帮你绕过去。6.1 部署阶段问题问题1运行riva_init.sh或riva_start.sh时提示“镜像拉取失败”或“架构不匹配”。原因最可能的原因是config.sh中的RIVA_TARGET_DEVICE没有设置为“jetson”导致脚本试图拉取x86_64架构的镜像。也可能是NGC API密钥未正确设置或网络问题。解决仔细检查config.sh确保有针对Jetson的设置。运行docker login nvcr.io重新登录确认密钥有效。尝试手动拉取一个已知的Jetson ARM镜像测试网络docker pull nvcr.io/nvidia/riva/riva-speech:2.18.0-slim-arm64注意-arm64后缀。问题2Riva容器启动后立即退出查看日志显示CUDA或TensorRT错误。原因JetPack版本、容器内CUDA/TensorRT版本与Riva版本不兼容。解决这是最棘手的问题。必须严格对照 NVIDIA Riva官方文档 中的“版本支持矩阵”选择与你的JetPack版本完全兼容的Riva版本。降级或升级Riva版本通常是唯一办法。6.2 客户端连接与识别问题问题3客户端连接Riva服务器超时grpc._channel._InactiveRpcError。原因服务器没启动成功。用docker ps和docker logs riva-speech检查。防火墙或端口错误。客户端代码中的服务器地址localhost:50051必须与Riva服务实际暴露的gRPC端口一致。检查riva_start.sh输出或config.sh中的RIVA_SPEECH_API_PORT。解决确保服务运行并在客户端使用正确的IP和端口。如果是本地就是localhost:50051。问题4识别结果全是乱码或空白。原因音频格式不匹配客户端发送的音频编码LINEAR_PCM、采样率如16000、声道数如1必须与RecognitionConfig中的设置完全一致。麦克风设备问题客户端录不到音或录的是噪音。语言模型不匹配language_code设置为“en-US”但你在说中文。解决在客户端代码中打印或验证音频参数。使用arecord或audacity等工具先测试麦克风是否正常工作。确认RIVA_ASR_LANGUAGE_CODE和客户端RecognitionConfig中的语言代码一致。问题5识别延迟很高不“实时”。原因模型太大在Jetson Nano上运行1024维的Citrinet模型会非常慢。电源模式限制设备运行在最低功耗模式。系统负载过高有其他进程占用了大量CPU/GPU。音频块太大客户端每次发送的音频数据块过长如1秒导致服务器需要积累更多数据才能返回结果。解决换用更小的模型如256维。使用sudo nvpmodel -m 0切换到更高性能模式并确保散热良好。用jtop监控关闭不必要的进程。减少客户端发送的音频块大小尝试调整为50ms或80ms。6.3 实战心得与技巧从脚本到服务上述客户端脚本适合演示和测试。对于生产环境建议将客户端代码封装成一个常驻服务如使用systemd并增加守护进程、崩溃重启、日志轮转等功能。加入简单的回声消除AEC如果麦克风和扬声器距离近扬声器播放的声音可能被麦克风再次采集形成回声干扰识别。可以考虑在客户端音频采集后、发送前加入一个轻量级的软件AEC模块能显著提升嘈杂环境下的识别率。结果后处理Riva返回的文本已经包含了标点。但对于字幕显示你可能还需要过滤敏感词根据应用场景对识别结果进行实时过滤。分段与合并根据静音时间VAD或句子长度将连续的流式结果组合成更符合阅读习惯的字幕段落。时间戳对齐如果启用enable_word_time_offsets可以获得每个词的开始和结束时间。这对于生成SRT或VTT格式的字幕文件至关重要。多模态扩展既然已经在Jetson上跑通了语音识别完全可以结合其强大的视觉能力。例如使用Jetson的GPU同时运行一个视觉模型识别演讲者的唇动唇语识别作为ASR的辅助输入在嘈杂环境中提升鲁棒性。或者将生成的文字与摄像头捕捉到的演讲者画面进行合成制作成带字幕的视频流。这个项目从驱动配置到服务部署再到客户端调试几乎涵盖了边缘AI应用落地的全链路。最大的体会是在边缘设备上做AI除了算法和代码对硬件特性、系统配置和资源管理的理解同样重要。每一次性能瓶颈的突破往往不是改了模型而是调整了一个电源模式参数或者优化了一段数据流的处理逻辑。希望这篇超详细的踩坑记录能帮你更顺畅地在Jetson上搭建起属于自己的实时语音字幕系统。

相关新闻