AI 音频产品开发模板及流程(一)
6. 同声传译
- 实时翻译,发言与翻译几乎同步,极大提升沟通效率。
- 支持多语言互译,适用于国际会议、商务洽谈等多场景。
- 自动断句、转写和翻译,减少人工干预,提升准确性。
- 翻译结果可由设备自动播放,交流体验自然流畅。
功能展示

代码片段
// 录音相关配置,并开始录音
const startRcordFn = async () => {
// 设备需要在线
if (!isOnline) return;
// 开启了翻译,但没有选择翻译语言时,给出提示
if (needTranslate && !translationLanguage) {
showToast({
icon: 'none',
title: Strings.getLang('realtime_recording_translation_no_select_tip'),
});
return;
}
try {
setControlBtnLoading(true);
const config: any = {
// 录音类型,0:呼叫、1:会议
recordType: currRecordType,
// DP 控制超时时间,单位秒
controlTimeout: 5,
// 灌流超时时间,单位秒
dataTimeout: 10,
// 0:文件转写、1:实时转写
transferType: 1,
// 是否需要翻译
needTranslate,
// 输入语言
originalLanguage: originLanguage,
// 智能体 ID,后面具体根据提供的 SDK 获取 agentId
agentId: '',
// 录音通道,0:BLE、1:Bt、2:micro
recordChannel,
// TTS 流编码方式,通过编码后将流写入到耳机设备,0:opus_silk、1:opus_celt
ttsEncode: isOpusCelt ? 1 : 0,
};
if (needTranslate) {
// 目标语言
config.targetLanguage = translationLanguage;
}
await tttStartRecord({
deviceId,
config,
});
setInterval(1000);
lastTimeRef.current = Date.now();
setControlBtnLoading(false);
} catch (error) {
setControlBtnLoading(false);
}
};
// 点击开始录音对应的回调
const handleStartRecord = useCallback(async () => {
// 申请录音权限
if (isBtEntryVersion) {
ty.authorize({
scope: 'scope.record',
success: () => {
startRcordFn();
},
fail: e => {
ty.showToast({ title: Strings.getLang('no_record_permisson'), icon: 'error' });
console.log('cope.record: ', e);
},
});
return;
}
startRcordFn();
}, [
deviceId,
isOnline,
controlBtnLoading,
currRecordType,
needTranslate,
originLanguage,
translationLanguage,
recordChannel,
isBtEntryVersion,
offlineUsage,
]);
// 暂停
const handlePauseRecord = async () => {
if (controlBtnLoading) return;
try {
setControlBtnLoading(true);
const d = await tttPauseRecord(deviceId);
setInterval(undefined);
setControlBtnLoading(false);
} catch (error) {
console.log('fail', error);
setControlBtnLoading(false);
}
};
// 继续录音
const handleResumeRecord = async () => {
if (controlBtnLoading) return;
try {
setControlBtnLoading(true);
await tttResumeRecord(deviceId);
setInterval(1000);
lastTimeRef.current = Date.now();
setControlBtnLoading(false);
} catch (error) {
setControlBtnLoading(false);
}
};
// 停止
const handleStopRecord = async () => {
if (controlBtnLoading) return;
try {
ty.showLoading({ title: '' });
await tttStopRecord(deviceId);
setDuration(0);
setInterval(undefined);
ty.hideLoading({
complete: () => {
backToHome(fromType);
},
});
} catch (error) {
ty.hideLoading();
}
};
// 监听 ASR 和翻译返回
onRecordTransferRealTimeRecognizeStatusUpdateEvent(handleRecrodChange);
// 处理 ASR 和翻译
const handleRecrodChange = d => {
try {
const {
// 阶段,0:任务、4:ASR、5:翻译、6:skill、7:TTS
phase,
// 阶段状态,0:未开启、1:进行中、2:结束、3:取消
status,
requestId,
// 转写的文本
text,
// 错误码
errorCode,
} = d;
// ASR 阶段,接收并实时更新对应 requestId 文本
if (phase === 4) {
const currTextItemIdx = currTextListRef.current.findIndex(item => item.id === requestId);
if (currTextItemIdx > -1) {
const newList = currTextListRef.current.map(item =>
item.id === requestId ? { ...item, text } : item
);
currTextListRef.current = newList;
setTextList(newList);
} else {
if (!text) return;
const newList = [
...currTextListRef.current,
{
id: requestId,
text,
},
];
currTextListRef.current = newList;
setTextList(newList);
}
// 翻译返回阶段,接收并展示 status=2 即已完成翻译的
} else if (phase === 5 && status === 2) {
let resText = '';
if (text && text !== 'null') {
if (isJsonString(text)) {
const textArr = JSON.parse(text);
const isArr = Array.isArray(textArr);
// 数字的 string 类型如 111,isJsonString 判断为 json 字符串,会导致 .join 失败
resText = isArr ? textArr?.join('\n') : textArr;
} else {
resText = text;
}
}
if (!resText) {
return;
}
const newList = currTextListRef.current.map(item => {
return item.id === requestId ? { ...item, text: `${item.text}\n${resText}` } : item;
});
currTextListRef.current = newList;
setTextList(newList);
}
} catch (error) {
console.warn(error);
}
};
7. 现场录音
- 可自动录制现场环境中的所有声音,完整还原现场交流内容,便于后续查证和回顾。
- 支持录音内容的转写和 AI 总结,快速提炼关键信息,提高信息处理效率。
- 降低人工记录成本,避免遗漏重要细节,提升工作和沟通的准确性。
- 适用于会议记录、课堂笔记、采访等多种场景,增强产品的实用性和智能化水平。
功能展示

代码片段
// 录音相关配置,并调用 App 能力开始录音
const startRecordFn = async () => {
try {
setControlBtnLoading(true);
await tttStartRecord(
{
deviceId,
config: {
// 出错时是否要保留音频文件
saveDataWhenError: true,
// 录音类型,0:呼叫、1:会议
recordType: currRecordType,
// DP 控制超时时间,单位秒
controlTimeout: 5,
// 灌流超时时间 单位秒
dataTimeout: 10,
// 0:文件转写、1:实时转写
transferType: 0,
// 录音通道,0:BLE、1:Bt、2:micro
recordChannel,
// TTS 流编码方式,通过编码后将流写入到耳机设备,0:opus_silk、1:opus_celt
ttsEncode: isOpusCelt ? 1 : 0,
},
},
);
setInterval(1000);
lastTimeRef.current = Date.now();
setControlBtnLoading(false);
} catch (error) {
setControlBtnLoading(false);
}
};
// 点击开始录音的回调
const handleStartRecord = useCallback(async () => {
// 申请权限
if (isBtEntryVersion) {
ty.authorize({
scope: 'scope.record',
success: () => {
startRecordFn();
},
fail: e => {
ty.showToast({ title: Strings.getLang('no_record_permisson'), icon: 'error' });
},
});
return;
}
startRecordFn();
}, [currRecordType, recordChannel, isBtEntryVersion]);
// 暂停
const handlePauseRecord = async () => {
try {
setControlBtnLoading(true);
await tttPauseRecord(deviceId);
setInterval(undefined);
setControlBtnLoading(false);
} catch (error) {
console.log('fail', error);
setControlBtnLoading(false);
}
};
// 继续录音
const handleResumeRecord = async () => {
try {
setControlBtnLoading(true);
await tttResumeRecord(deviceId);
setInterval(1000);
lastTimeRef.current = Date.now();
setControlBtnLoading(false);
} catch (error) {
setControlBtnLoading(false);
}
};
// 停止
const handleStopRecord = async () => {
try {
ty.showLoading({ title: '' });
await tttStopRecord(deviceId);
setDuration(0);
setInterval(undefined);
ty.hideLoading();
backToHome();
} catch (error) {
ty.hideLoading();
}
};
8. 转录和 AI 总结
- 将音频内容转写为可编辑的文字,便于保存和后续处理。
- 利用 AI 技术根据选择的模板对转写内容进行智能总结,快速提炼关键信息,提升信息获取效率。
- 降低人工整理和阅读成本,避免遗漏重要内容。
- 支持生成结构化的 Markdown 格式文本,方便文档归档和分享。
- 适用于会议纪要、通话记录、面对面交流、课堂笔记等多种场景,增强产品的实用性和智能化水平。
功能展示

代码片段
{/* 转录结果 */}
<View className={styles.content}>
<Tabs.SegmentedPicker
activeKey={currTab}
tabActiveTextStyle={{
color: 'rgba(54, 120, 227, 1)',
fontWeight: '600',
}}
style={{ backgroundColor: 'rgba(241, 241, 241, 1)' }}
onChange={activeKey => {
setCurrTab(activeKey);
}}
>
<Tabs.TabPanel tab={Strings.getLang('recording_detail_tab_stt')} tabKey="stt" />
<Tabs.TabPanel tab={Strings.getLang('recording_detail_tab_summary')} tabKey="summary" />
<Tabs.TabPanel
tab={Strings.getLang('recording_detail_tab_mind_map')}
tabKey="mindMap"
/>
</Tabs.SegmentedPicker>
{currTab === 'stt' && (
<SttContent
playerStatus={playerStatus}
wavFilePath={recordFile?.wavFilePath}
transferStatus={transferStatus}
sttData={sttData}
recordType={recordFile?.recordType}
currPlayTime={currPlayTime}
onChangePlayerStatus={status => {
setPlayerStatus(status);
}}
innerAudioContextRef={innerAudioContextRef}
isEditMode={isEditMode}
onUpdateSttData={handleUpdateSttData}
/>
)}
{currTab === 'summary' && (
<SummaryContent summary={summary} transferStatus={transferStatus} />
)}
{currTab === 'mindMap' && (
<MindMapContent summary={summary} transferStatus={transferStatus} />
)}
{(transferStatus === TRANSFER_STATUS.Initial ||
transferStatus === TRANSFER_STATUS.Failed) &&
!(currTab === 'stt' && recordFile?.transferType === TransferType.REALTIME) && (
<>
<EmptyContent type={EMPTY_TYPE.NO_TRANSCRIPTION} />
<Button
className={styles.generateButton}
onClick={() => {
// 先选择模版
setShowTemplatePopup(true);
}}
>
<Text className={styles.generateText}>{Strings.getLang('generate')}</Text>
</Button>
</>
)}
</View>
// 开始转录总结
const handleStartTransfer = async (selectTemplate: TRANSFER_TEMPLATE) => {
if (isLoading.current) return;
try {
isLoading.current = true;
ty.showLoading({ title: '' });
await tttTransfer({
recordTransferId: currRecordTransferId.current,
template: selectTemplate,
language: recordFile?.originalLanguage || language,
});
setTransferStatus(TRANSFER_STATUS.Processing);
const fileDetail: any = await tttGetFilesDetail({
recordTransferId: currRecordTransferId.current,
amplitudeMaxCount: 100,
});
setRecordFile(fileDetail);
dispatch(updateRecordTransferResultList());
ty.hideLoading();
isLoading.current = false;
} catch (error) {
console.log(error);
dispatch(updateRecordTransferResultList());
ty.hideLoading();
isLoading.current = false;
}
};
// 获取转录和转写详情
const getFileDetail = async () => {
// loading
const finishLoading = () => {
ty.hideLoading();
isLoading.current = false;
};
try {
isLoading.current = true;
ty.showLoading({ title: '' });
const recordTransferId = currRecordTransferId.current;
// 获取录音详情
const fileDetail = await tttGetFilesDetail({
recordTransferId,
amplitudeMaxCount: 100,
});
if (fileDetail) {
setRecordFile(fileDetail);
const { storageKey, transfer, visit, status, recordId, transferType } = fileDetail;
if (!visit) {
updateFileVisitStatus();
}
setTransferStatus(transfer);
// 实时转写直接取用 App 接口的转写数据
if (transferType === TransferType.REALTIME) {
// 获取转写数据
const realTimeResult: any = await tttGetRecordTransferRealTimeResult({
recordId,
});
const { list } = realTimeResult;
const newData = list
.filter(item => !!item?.asr && item?.asr !== 'null')
.map(item => ({
asrId: item.asrId,
startSecond: Math.floor(item.beginOffset / 1000),
endSecond: Math.floor(item.endOffset / 1000),
text: item.asr,
transText: item.translate,
channel: item.channel,
}));
setSttData(newData);
originSttData.current = newData;
// 获取客户端本地总结数据
tttGetRecordTransferSummaryResult({
recordTransferId,
from: 0,
}).then((d: any) => {
if (d?.text) {
resolveSummaryText(d?.text);
}
});
// 获取云端总结数据
tttGetRecordTransferSummaryResult({
recordTransferId,
from: 1, // 云端
}).then((d: any) => {
if (d?.text) {
tttSaveRecordTransferSummaryResult({ recordTransferId, text: d?.text });
resolveSummaryText(d?.text);
}
});
} else {
// status 文件同步状态,0:未上传、1:上传中、2:已上传、3:上传失败
// transfer 转录状态,0:未转录、1:转录中、2:已转录、3:转录失败
if (status === 2 && transfer === 2) {
// 获取客户端本地转写数据
tttGetRecordTransferRecognizeResult({
recordTransferId,
from: 0, // 本地
}).then((d: any) => {
if (d?.text) {
resolveSttText(d?.text);
}
});
// 获取云端转写数据
tttGetRecordTransferRecognizeResult({
recordTransferId,
from: 1, // 云端
}).then((d: any) => {
if (d?.text) {
// 缓存到客户端本地
tttSaveRecordTransferRecognizeResult({ recordTransferId, text: d?.text });
resolveSttText(d?.text);
}
});
// 获取客户端本地总结数据
tttGetRecordTransferSummaryResult({
recordTransferId,
from: 0,
}).then((d: any) => {
if (d?.text) {
resolveSummaryText(d?.text);
}
});
// 获取云端总结数据
tttGetRecordTransferSummaryResult({
recordTransferId,
from: 1, // 云端
}).then((d: any) => {
if (d?.text) {
tttSaveRecordTransferSummaryResult({ recordTransferId, text: d?.text });
resolveSummaryText(d?.text);
}
});
}
}
finishLoading();
}
} catch (error) {
console.log('error', error);
finishLoading();
}
};
9. 结束