直播 SDK AI 字幕

这篇档介绍如何在 TUILiveKit 中集成 AI 字幕功能。通过该功能,用户可以在进入房间后,将房间内的实时语音内容转写为文字字幕,并支持将识别出的文字实时翻译为多种目标语言,方便不同语言背景的用户进行跨语种沟通。

相关产品
直播 SDK 产品页,含版本规格、价格与购买入口。

注意:说明:

一、核心概念

在正式接入 AI 字幕前,建议先了解以下核心概念:

概念 说明
SourceLanguage 设置需要进行语音识别的语言,用于语音识别。支持 20 种语言,包括中英混合识别。详细可参见:源语言列表。
TranslationLanguage 开启翻译后,生成的翻译字幕的语言类型,用于开启翻译功能后区分语言类型。详细可参见:翻译语言列表。
TranscriberMessage 单条字幕消息,对应说话人的一段连续语音,包含原文、译文、说话人信息与完成状态。
TranscriberState 字幕模块的实时状态数据,通过订阅该状态可在 UI 上展示字幕列表与运行状态。

二、环境配置

AI 字幕功能基于 AtomicXCore SDK 提供的 AITranscriberStore 接口实现。在正式调用接口前,请确保已完成对应平台的 AtomicXCore SDK 集成,并成功进房。

AndroidiOSFlutterWeb

·已集成 atomicxcore 依赖,并在工程中引入 io.trtc.tuikit.atomicxcore.api.ai.AITranscriberStore。

·确保已在房间内(完成 startLive 或 joinLive)再调用字幕相关接口。

·已通过 CocoaPods 集成 AtomicXCore,并在源码中 import AtomicXCore。

·确保已在房间内(完成 startLive 或 joinLive)再调用字幕相关接口。

·已在 pubspec.yaml 中引入 atomic_x_core 依赖。

·确保已在房间内(完成 startLive 或 joinLive)再调用字幕相关接口。

·已集成 tuikit-atomicx-vue3 依赖,并从中引入 useAITranscriberStateLive。

·确保已在房间内(完成 startLive 或 joinLive)再调用字幕相关接口。

三、创建 AITranscriberStore 实例

AI 字幕相关接口通过 AITranscriberStore 管理,需使用工厂方法按房间 ID 创建实例。同一房间 ID 多次创建会返回同一实例。

AndroidiOSFlutterWebimport io.trtc.tuikit.atomicxcore.api.ai.AITranscriberStore// 按房间 ID 创建实例(同一房间多次调用返回同一实例)val transcriberStore = AITranscriberStore.create("your_room_id")import AtomicXCore// 按房间 ID 创建实例(同一房间多次调用返回同一实例)let transcriberStore = AITranscriberStore.create(roomID: "your_room_id")import 'package:atomic_x_core/api/ai/ai_transcriber_store.dart';// 按房间 ID 创建实例(同一房间多次调用返回同一实例)final transcriberStore = AITranscriberStore.create("your_room_id");Web 端通过 tuikit-atomicx-vue3 提供的 useAITranscriberStateLive Composable 使用 AI 字幕能力,无需手动按房间 ID 创建实例。在组件中调用该 Hook 即可获取字幕状态与操作方法,内部会自动关联当前所在房间。import { useAITranscriberStateLive } from 'tuikit-atomicx-vue3';// 在组件 setup 中调用,获取状态与操作方法(同一房间共享同一份状态)const { myLanguage, realtimeMessageList, isTranscriptionRunning, transcriptionConfig, startTranscription, updateTranscription, stopTranscription,} = useAITranscriberStateLive();

四、订阅字幕状态

字幕的实时数据(消息列表、运行状态、配置等)通过状态发布器(State / StateFlow / ValueListenable)对外提供。建议在开启字幕前先完成订阅,以便及时刷新 UI。

五、状态字段说明

字段 类型 说明
selfLanguage SourceLanguage 当前用户设置的源语言
realtimeMessageList List<TranscriberMessage> 实时字幕消息列表,随转写进度自动更新
isTranscriptionRunning Bool 转写服务是否正在运行
transcriptionConfig TranscriptionConfig 当前转写配置

六、订阅示例

AndroidiOSFlutterWebimport kotlinx.coroutines.launchimport androidx.lifecycle.lifecycleScopeimport io.trtc.tuikit.atomicxcore.api.ai.AITranscriberStore// 订阅实时字幕消息列表lifecycleScope.launch { transcriberStore.transcriberState.realtimeMessageList.collect { messages -> messages.forEach { message -> println("Speaker: ${message.speakerUserName}") println("Source text: ${message.sourceText}") message.translationTexts.forEach { (lang, text) -> println("Translation[$lang]: $text") } } }}// 订阅转写运行状态lifecycleScope.launch { transcriberStore.transcriberState.isTranscriptionRunning.collect { running -> println("Transcription running: $running") }}// 订阅字幕整体状态transcriberStore.state.subscribe { state in for message in state.realtimeMessageList { print("Speaker: \\(message.speakerUserName)") print("Source text: \\(message.sourceText)") for (lang, text) in message.translationTexts { print("Translation[\\(lang)]: \\(text)") } } print("Transcription running: \\(state.isTranscriptionRunning)")}import 'package:atomic_x_core/api/ai/ai_transcriber_store.dart';// 订阅实时字幕消息列表transcriberStore.transcriberState.realtimeMessageList.addListener(() { final messages = transcriberStore.transcriberState.realtimeMessageList.value; for (final message in messages) { print("Speaker: ${message.speakerUserName}"); print("Source text: ${message.sourceText}"); message.translationTexts.forEach((lang, text) { print("Translation[$lang]: $text"); }); }});// 订阅转写运行状态transcriberStore.transcriberState.isTranscriptionRunning.addListener(() { final running = transcriberStore.transcriberState.isTranscriptionRunning.value; print("Transcription running: $running");});Web 端字幕状态以 Vue 响应式数据(ref)形式对外提供,可直接在模板中渲染,或使用 watch 监听变化。import { watch } from 'vue';import { useAITranscriberStateLive } from 'tuikit-atomicx-vue3';const { realtimeMessageList, isTranscriptionRunning,} = useAITranscriberStateLive();// 订阅实时字幕消息列表watch(realtimeMessageList, (messages) => { messages.forEach((message) => { console.log(`Speaker: ${message.speakerUserName}`); console.log(`Source text: ${message.sourceText}`); Object.entries(message.translationTexts).forEach(([lang, text]) => { console.log(`Translation[${lang}]: ${text}`); }); });});// 订阅转写运行状态watch(isTranscriptionRunning, (running) => { console.log(`Transcription running: ${running}`);});

七、开启 AI 字幕

完成实例创建与状态订阅后,调用 startTranscription 开启实时转写。如需同时开启翻译,请在 TranscriptionConfig 中将 enableTranslation 设置为 true。

开启 AI 字幕后,系统会根据麦上成员的语音流生成转写内容;若同时开启翻译,系统会根据说话人的源语言与当前配置的目标语言生成译文。使用时请注意以下规则:

·只有当麦上其他成员设置的源语言和自己的源语言不同时,才会显示翻译语言。

myLanguage 表示当前用户希望看到的字幕语言,也会作为当前用户本人说话语言的默认判断依据。

例如,房主开启了字幕和翻译,并将自己的 myLanguage 设置为英语。如果当前麦上只有房主一人,且房主本人说话,系统会认为该语音的源语言就是英语,因此只会看到原文,不会额外生成“翻译后的英语内容”。

如需验证翻译效果,可以让另一位说不同语言的麦上成员参与发言。例如麦上观众使用中文发言,房主侧即可看到该成员的原文及对应译文。

·建议麦上成员主动传入自己的说话语言。

myLanguage 用于声明当前用户的说话语言,传入与实际语言匹配的值可以提升识别准确率。

如果麦上成员未调用相关接口传入 myLanguage,系统会默认读取该用户的手机系统语言作为兜底语言。因此,即使未显式设置语言,用户开启 AI 字幕后仍可能看到字幕内容,但为了获得更准确的识别效果,建议引导用户主动选择或传入自己的常用说话语言。

·麦下观众开启字幕不会主动触发转写任务,但可以追加翻译任务。

麦下观众开启字幕时,只会订阅房间内已有的转写结果,不会单独触发转写机器人进房拉取麦上成员的音频流进行识别。

如果房间内已有麦上成员开启字幕,并且转写任务正在运行,麦下观众开启字幕后即可看到转写内容;此时麦下观众也可以开启翻译,系统会基于已有转写结果为该观众追加对应的翻译任务。

注意:说明:

注意:源语言 myLanguage 表示当前用户希望看到的字幕语言,同时也会作为当前用户本人发言时的识别语言。建议传入与当前用户使用语言一致的值。开启翻译后,系统会将其他语言的麦上成员发言翻译为 myLanguage 对应的语言。

AndroidiOSFlutterWebimport io.trtc.tuikit.atomicxcore.api.ai.SourceLanguageimport io.trtc.tuikit.atomicxcore.api.ai.TranscriptionConfigimport io.trtc.tuikit.atomicxcore.api.ai.AITranscriberStore// 1. 配置转写参数:开启翻译val config = TranscriptionConfig(enableTranslation = true)// 2. 开启转写,指定源语言为中英混合transcriberStore.startTranscription( myLanguage = SourceLanguage.CHINESE_ENGLISH, config = config) { code, message -> if (code != 0) { println("Start transcription failed: $message") } else { println("Start transcription success") }}import AtomicXCore// 1. 配置转写参数:开启翻译let config = TranscriptionConfig(enableTranslation: true)// 2. 开启转写,指定源语言为中英混合transcriberStore.startTranscription(myLanguage: .chineseEnglish, config: config) { error in if let error = error { print("Start transcription failed: \\(error)") } else { print("Start transcription success") }}import 'package:atomic_x_core/api/ai/ai_transcriber_store.dart';// 1. 配置转写参数:开启翻译final config = TranscriptionConfig(enableTranslation: true);// 2. 开启转写,指定源语言为中英混合final result = await transcriberStore.startTranscription( SourceLanguage.chineseEnglish, config: config,);if (!result.isSuccess) { print("Start transcription failed: ${result.errorMessage}");} else { print("Start transcription success");}Web 端通过 startTranscription 传入 myLanguage 与 config 开启转写。接口返回 Promise,可用 try/catch 处理结果。import { useAITranscriberStateLive } from 'tuikit-atomicx-vue3';const { startTranscription } = useAITranscriberStateLive();// 开启转写,指定源语言为中英混合,并开启翻译try { await startTranscription({ myLanguage: 'zh_en', config: { enableTranslation: true }, }); console.log('Start transcription success');} catch (error) { console.error('Start transcription failed:', error);}

八、更新字幕配置

转写服务运行期间,可调用 updateTranscription 动态修改源语言或翻译开关,无需停止后重启。

AndroidiOSFlutterWebimport io.trtc.tuikit.atomicxcore.api.ai.SourceLanguageimport io.trtc.tuikit.atomicxcore.api.ai.TranscriptionConfigimport io.trtc.tuikit.atomicxcore.api.ai.AITranscriberStore// 运行中切换源语言为英语,并关闭翻译val newConfig = TranscriptionConfig(enableTranslation = false)transcriberStore.updateTranscription( myLanguage = SourceLanguage.ENGLISH, config = newConfig) { code, message -> if (code != 0) { println("Update transcription failed: $message") }}import AtomicXCore// 运行中切换源语言为英语,并关闭翻译var newConfig = TranscriptionConfig(enableTranslation: false)transcriberStore.updateTranscription(myLanguage: .english, config: newConfig) { error in if let error = error { print("Update transcription failed: \\(error)") }}import 'package:atomic_x_core/api/ai/ai_transcriber_store.dart';// 运行中切换源语言为英语,并关闭翻译final newConfig = TranscriptionConfig(enableTranslation: false);final result = await transcriberStore.updateTranscription( SourceLanguage.english, config: newConfig,);if (!result.isSuccess) { print("Update transcription failed: ${result.errorMessage}");}import { useAITranscriberStateLive } from 'tuikit-atomicx-vue3';const { updateTranscription } = useAITranscriberStateLive();// 运行中切换源语言为英语,并关闭翻译try { await updateTranscription({ myLanguage: 'en', config: { enableTranslation: false }, });} catch (error) { console.error('Update transcription failed:', error);}

九、停止 AI 字幕

当需要停止转写时,调用 stopTranscription。停止后转写机器人将不再识别语音,字幕消息列表也不再更新。

AndroidiOSFlutterWebimport io.trtc.tuikit.atomicxcore.api.ai.AITranscriberStoretranscriberStore.stopTranscription { code, message -> if (code != 0) { println("Stop transcription failed: $message") } else { println("Stop transcription success") }}import AtomicXCoretranscriberStore.stopTranscription { error in if let error = error { print("Stop transcription failed: \\(error)") } else { print("Stop transcription success") }}import 'package:atomic_x_core/api/ai/ai_transcriber_store.dart';final result = await transcriberStore.stopTranscription();if (!result.isSuccess) { print("Stop transcription failed: ${result.errorMessage}");} else { print("Stop transcription success");}import { useAITranscriberStateLive } from 'tuikit-atomicx-vue3';const { stopTranscription } = useAITranscriberStateLive();try { await stopTranscription(); console.log('Stop transcription success');} catch (error) { console.error('Stop transcription failed:', error);}

十、字幕消息结构

每条字幕消息对应说话人的一段连续语音,结构如下:

属性 类型 说明
segmentId String 字幕段唯一标识
speakerUserId String 说话人用户 ID
speakerUserName String 说话人昵称
sourceText String 识别出的原文
translationTexts Map<TranslationLanguage, String> 目标语言的译文
timestamp Int / Long 消息时间戳
isCompleted Bool 该段语音是否已结束。为 true 后原文与译文不再更新

注意:说明:

十一、完整使用示例

以下示例展示从创建实例、订阅状态到开启字幕的完整流程。

AndroidiOSFlutterWebimport io.trtc.tuikit.atomicxcore.api.ai.AITranscriberStoreimport io.trtc.tuikit.atomicxcore.api.ai.SourceLanguageimport io.trtc.tuikit.atomicxcore.api.ai.TranscriptionConfigimport androidx.lifecycle.lifecycleScopeimport kotlinx.coroutines.launchfun setupAITranscriber(roomID: String) { // 1. 创建实例 val store = AITranscriberStore.create(roomID) // 2. 订阅字幕消息 lifecycleScope.launch { store.transcriberState.realtimeMessageList.collect { messages -> messages.forEach { msg -> Log.d("AITranscriber", "[${msg.speakerUserName}] ${msg.sourceText}") } } } // 3. 开启字幕(含翻译) val transConfig = TranscriptionConfig(enableTranslation = true) store.startTranscription( myLanguage = SourceLanguage.CHINESE_ENGLISH, config = transConfig ) { code, message -> if (code != 0) Log.e("AITranscriber", "start failed: $message") }}import AtomicXCorefunc setupAITranscriber(roomID: String) { // 1. 创建实例 let store = AITranscriberStore.create(roomID: roomID) // 2. 订阅字幕状态 store.state.subscribe { state in for msg in state.realtimeMessageList { print("[\\(msg.speakerUserName)] \\(msg.sourceText)") } } // 3. 开启字幕(含翻译) let transConfig = TranscriptionConfig(enableTranslation: true) store.startTranscription(myLanguage: .chineseEnglish, config: transConfig) { error in if let error = error { print("start failed: \\(error)") } }}import 'package:atomic_x_core/api/ai/ai_transcriber_store.dart';Future<void> setupAITranscriber(String roomID) async { // 1. 创建实例 final store = AITranscriberStore.create(roomID); // 2. 订阅字幕消息 store.transcriberState.realtimeMessageList.addListener(() { final messages = store.transcriberState.realtimeMessageList.value; for (final msg in messages) { print("[${msg.speakerUserName}] ${msg.sourceText}"); } }); // 3. 开启字幕(含翻译) final transConfig = TranscriptionConfig(enableTranslation: true); final transResult = await store.startTranscription( SourceLanguage.chineseEnglish, config: transConfig, ); if (!transResult.isSuccess) { print("start failed: ${transResult.errorMessage}"); }}<script setup lang="ts">import { ref } from 'vue';import { useAITranscriberStateLive } from 'tuikit-atomicx-vue3';const { realtimeMessageList, isTranscriptionRunning, startTranscription, updateTranscription, stopTranscription,} = useAITranscriberStateLive();const myLanguage = ref<'zh' | 'en' | 'ja' | 'ko'>('zh');const enableTranslation = ref(true);const loading = ref(false);// 开启 / 停止字幕async function handleClick() { if (loading.value) { return; } loading.value = true; try { if (isTranscriptionRunning.value) { await stopTranscription(); } else { await startTranscription({ myLanguage: myLanguage.value, config: { enableTranslation: enableTranslation.value }, }); } } catch (error: any) { console.error('[AITranscriber] failed:', error); } finally { loading.value = false; }}// 运行中动态切换源语言async function handleLanguageChange(next: typeof myLanguage.value) { myLanguage.value = next; if (isTranscriptionRunning.value) { await updateTranscription({ myLanguage: next, config: { enableTranslation: enableTranslation.value }, }); }}</script><template> <div> <select :value="myLanguage" @change="handleLanguageChange(($event.target as HTMLSelectElement).value as any)" > <option value="zh">中文</option> <option value="en">English</option> <option value="ja">日本語</option> <option value="ko">한국어</option> </select> <label> <input v-model="enableTranslation" type="checkbox" :disabled="isTranscriptionRunning" /> Enable translation </label> <button :disabled="loading" @click="handleClick"> {{ isTranscriptionRunning ? 'Stop subtitle' : 'Start subtitle' }} </button> <ul> <li v-for="msg in realtimeMessageList" :key="msg.segmentID" > <strong>{{ msg.speakerUserName || msg.speakerUserID }}:</strong> <span>{{ msg.sourceText }}</span> <em v-if="msg.translationTexts?.[myLanguage]"> ({{ msg.translationTexts[myLanguage] }}) </em> </li> </ul> </div></template>

十三、源语言列表

转写服务支持以下 20 种源语言,请选择与说话人语言匹配的项以获得最佳识别准确率。中英混合场景建议使用 chineseEnglish。

注意:说明:

注意:AI 字幕默认支持识别中文、英文、日文、韩文,如需支持其他语言,请 联系我们 进行配置。

语言 取值 说明
chineseEnglish zh_en 中英文混合
chinese zh 中文
english en 英语
cantonese zh-yue 粤语
vietnamese vi 越南语
japanese ja 日语
korean ko 韩语
indonesian id 印尼语
thai th 泰语
portuguese pt 葡萄牙语
turkish tr 土耳其语
arabic ar 阿拉伯语
spanish es 西班牙语
hindi hi 印地语
french fr 法语
malay ms 马来语
filipino fil 菲律宾语
german de 德语
italian it 意大利语
russian ru 俄语

十四、翻译语言列表

转写文字支持实时翻译为以下 15 种目标语言。

语言 取值 说明
chinese zh 中文
english en 英语
vietnamese vi 越南语
japanese ja 日语
korean ko 韩语
indonesian id 印尼语
thai th 泰语
portuguese pt 葡萄牙语
arabic ar 阿拉伯语
spanish es 西班牙语
french fr 法语
malay ms 马来语
german de 德语
italian it 意大利语
russian ru 俄语

十六、开启字幕失败,调用 startTranscription 接口报错。

请确认以下前置条件是否满足:

1. 当前 SDKAppID 可能未开通直播 AI 实时转写服务,请先在控制台开通对应能力。

2. 已成功进房(房间状态为已连接),AI 字幕仅在房内可用。

3. 源语言 myLanguage 已正确传入,且取值在支持的语言列表内。

4. 房间内至少存在一路有效的音频流,否则转写机器人无语音可识别。

十七、开启翻译后,为什么只看到原文,没有看到译文。

请确认当前麦上是否存在使用其他语言发言的成员。

myLanguage 表示当前用户希望看到的字幕语言,也会作为当前用户本人说话语言的默认判断依据。

例如,房主开启字幕和翻译时传入 myLanguage 为英语,如果当前麦上只有房主一人或者其他麦上成员的 myLanguage 也为英语,系统会默认认为两位麦上成员说的都是英语,因此只会返回原文,不会再生成一份英语译文。

如需验证翻译效果,可以让另一位说不同语言的麦上成员发言。例如中文观众上麦发言,房主侧即可看到该成员的原文和翻译结果。

十八、麦上成员没有传入 myLanguage,是否还能使用 AI 字幕?

可以,如果麦上成员未显式传入 myLanguage,系统会读取该成员的手机系统语言作为兜底语言。用户开启 AI 字幕后仍可以看到字幕内容。

但手机系统语言不一定等同于用户实际说话语言,因此建议在业务侧引导用户选择或传入自己的实际说话语言,以提升语音识别准确率。

十九、麦下观众开启字幕或翻译后,为什么没有内容?

1. 麦下观众开启字幕不会主动触发转写任务。只有麦上成员开启了 AI 字幕,房间内已有转写任务正在运行时,麦下观众开启字幕后才能接收到字幕内容。

2. 如果麦上主播没有开启字幕,麦下观众单独开启字幕不会产生内容,因为此时房间内没有可订阅的转写结果。

3. 当已有转写任务运行时,麦下观众可以在接收原文字幕的基础上开启翻译,系统会基于已有转写结果追加对应的翻译任务。

20、字幕消息一直不更新,realtimeMessageList 为空。

请检查:

1. 房间内是否有成员正在说话(有音频上行)。

2. 是否已正确订阅 realtimeMessageList 状态,且订阅时机早于或等于开启转写的时机。

3. 转写服务是否处于运行中(isTranscriptionRunning 为 true)。

21、转写过程中切换源语言后,历史字幕是否会保留?

切换源语言不会清空历史字幕消息列表。历史消息保持不变,新的语音段将以新的源语言进行识别。如需清空展示,可在 UI 层自行处理列表数据。

赞 (0)
上一篇 4天前
下一篇 4天前