集成指引

最近更新时间:2024-11-12 16:06:52

我的收藏
本文将介绍如何基于 TRTC SDK 实现 AI 实时对话的解决方案。

方案介绍

方案基于 TRTC SDK 调用TRTC服务,通过调用 AI 实时对话的接口,可以实现极低延迟的 AI 实时对话服务。本方案为您提供了非常灵活的集成方案,您可以根据业务的实际需求接入第三方的 LLM 和 TTS,实现最佳的业务实践效果。在整体方案中,我们针对语音实时降噪、AI 智能打断、上下文管理都有较多的技术优化,不断提升用户体验。

方案架构图





业务流程图





集成指引

前提条件

注意:
联系商务 开通 AI 实时对话服务。
2. 创建腾讯云 TTS(可使用第三方)。
3. 创建 LLM 应用:可以自选适合的大模型厂商进行注册。

一、集成TRTC SDK

第一步:导入TRTC SDK到项目中

第二步:进入TRTC房间

第三步:发布音频流

您可以调用 startLocalAudio 来开启麦克风采集,该接口需要您通过 quality 参数确定采集模式。虽然这个参数的名字叫做 quality,但并不是说质量越高越好,不同的业务场景有最适合的参数选择(这个参数更准确的含义是 scene)。
AI 对话场景下推荐使用 SPEECH 模式,该模式下的 SDK 音频模块会专注于提炼语音信号,尽最大限度的过滤周围的环境噪音,同时该模式下的音频数据也会获得较好的差质量网络的抵抗能力,因此该模式特别适合于“视频通话”和“在线会议”等侧重于语音沟通的场景。
Android
iOS&Mac
// 开启麦克风采集,并设置当前场景为:语音模式(高噪声抑制能力、强弱网络抗性)
mCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_SPEECH );
// 开启麦克风采集,并设置当前场景为:语音模式(高噪声抑制能力、强弱网络抗性)
//对于高噪声抑制能力、强弱网抗性
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.trtcCloud startLocalAudio:TRTCAudioQualitySpeech];

二、发起 AI 对话

开始 AI 对话

以下接口推荐由业务后台来调用,客户端只调用业务后台提供的接口,来发起AI对话。
TRTC 提供以下云 API 用于发起和管理对话任务,具体如下:
目前支持的 TTS 和 LLM 模型调用方法:

LLM 交互

openai:
"LLMConfig": {
"LLMType": "openai",
"Model":"gpt-4o",
"APIKey":"api-key"
"APIUrl":"https://api.openai.com/v1/chat/completions",
"Streaming": true,
"SystemPrompt": "你是一个个人助手",
"Timeout": 3.0,
"History": 5 // 最大支持 50 轮对话, 默认为 0
}
minimax:
"LLMConfig":{
"APIKey": "eyJhbGcixxxx",
"LLMType": "minimax",
"Model": "abab6.5s-chat",
"Streaming": true,
"SystemPrompt": "你是一个个人助手",
"APIUrl": "https://api.minimax.chat/v1/text/chatcompletion_v2",
"History": 5 // 最大支持 50 轮对话
}
混元:
"LLMConfig":{
"LLMType": "openai",
"Model": "hunyuan-standard", # hunyuan-turbo、hunyuan-standard
"APIKey": "hunyuan-apikey",
"APIUrl": "https://hunyuan.cloud.tencent.com/openai/v1/chat/completions",
"Streaming": true,
"History": 10
}
此外我们会在 http header 中增加多个参数来辅助用户支持更复杂的逻辑:
X-Task-Id: <task_id_value> // 此任务的 id,
X-Rquest-Id: <request_id> // 此次请求的id, 重试会携带相同的requestId
X-Sdk-App-IdSdkAppId
X-User-IdUserId
X-Room-IdRoomId
X-Room-Id-Type: "0" // "0"表示数字房间号 "1"表示字符串房间号


TTS 交互

TTS 参数使用用户自己的第三方账号。
自定义 TTS
{
"TTSType": "custom", // String 必填
"APIKey": "ApiKey", // String 必填 用来鉴权
"APIUrl": "http://0.0.0.0:8080/stream-audio" // String,必填,TTS API URL
"AudioFormat": "wav", // String, 非必填,期望输出的音频格式,如mp3, ogg_opus,pcm,wav,默认为 wav,目前只支持pcm和wav,
"SampleRate": 16000, // Integer,非必填,音频采样率,默认为16000(16k),推荐值为16000
"AudioChannel": 1, // Integer,非必填,音频通道数,取值:1 或 2 默认为1
}
具体协议规范参见 自定义 TTS 协议
Tencent TTS:
{
"TTSType": "tencent", // String TTS类型,
"AppId": "您的应用ID", // String 必填
"SecretId": "您的密钥ID", // String 必填, 账号级别 SecretId
"SecretKey": "您的密钥Key", // String 必填,账号级别 SecretKey
"VoiceType": 101001, // Integer 必填,音色 ID,包括标准音色与精品音色,精品音色拟真度更高,价格不同于标准音色,请参见语音合成计费概述。完整的音色 ID 列表请参见语音合成音色列表。
"Speed": 1.25, // Integer 非必填,语速,范围:[-2,6],分别对应不同语速: -2: 代表0.6倍 -1: 代表0.8倍 0: 代表1.0倍(默认) 1: 代表1.2倍 2: 代表1.5倍 6: 代表2.5倍 如果需要更细化的语速,可以保留小数点后 2 位,例如0.5/1.25/2.81等。 参数值与实际语速转换,可参考 语速转换
"Volume": 5, // Integer 非必填,音量大小,范围:[0,10],分别对应11个等级的音量,默认值为0,代表正常音量。
"PrimaryLanguage": 1, // Integer 可选 主要语言 1-中文(默认) 2-英文 3-日文
"FastVoiceType": "xxxx" // 可选参数, 快速声音复刻的参数
}
minimax TTS
{
"TTSType": "minimax", // String TTS类型,
"Model": "speech-01-turbo-240228", // String 使用的模型,可选[speech-01-turbo, speech-01-turbo-240228, speech-01-240228]
"ApiUrl": "https://api.minimax.chat/v1/t2a_v2", //
"GroupId": "181000000000000", // String,需要在MiniMax管理后台获取:https://platform.minimaxi.com/user-center/basic-information
"ApiKey": "eyxxxx", // String,需要在MiniMax管理后台获取:https://platform.minimaxi.com/user-center/basic-information/interface-key
"VoiceType":"audiobook_female_1", // String,音色选择可以参考MiniMax文档
"Speed": 1.2 // Numer,范围[0.5,2],默认值为1.0
}
限频参见:速率限制(Rate limits) ,可能会导致回答卡顿。
接口名
T2A v2(语音生成)
T2A Pro(语音生成)
T2A(语音生成)
T2A Stream(流式语音生成)
T2A Stream(流式语音生成)

模型
speech-01-turbo、speech-01-240228、speech-01-turbo-240228
speech-01、speech-02
speech-01、speech-02
speech-01
speech-01
客户类型\\限制类型
RPM
RPM
RPM
RPM
CONN(最大并行运行任务数)
免费用户
3
3
3
3
1
充值用户
20
20
20
20
3
Azure TTS
{
"TTSType": "azure", // 必填:String TTS类型
"SubscriptionKey": "xxxxxxxx", // 必填:String 订阅的Key
"Region": "chinanorth3", // 必填:String 订阅的地区
"VoiceName": "zh-CN-XiaoxiaoNeural", // 必填:String 音色名必填
"Language": "zh-CN", // 必填:String 合成的语言
"Rate": 1 // 选填:float 语速 0.5~2 默认为 1
}

查询 AI 对话任务

停止 AI 对话

控制 AI 对话任务

三、接收AI对话及AI状态

通过 TRTC SDK 接收自定义消息功能,在客户端上监听回调来接收实时的字幕与 AI 状态的数据。cmdID 固定是1

接收实时字幕

消息格式
{
"type": 10000, // 10000表示是下发的实时字幕
"sender": "user_a", // 说话人的userid
"receiver": [], // 接收者userid列表,该消息实际是在房间内广播
"payload": {
"text":"", // 语音识别出的文本
"translation_text":"", // 翻译的文本
"start_time":"00:00:01", // 这句话的开始时间
"end_time":"00:00:02", // 这句话的结束时间
"roundid": "xxxxx", // 唯一标识一轮对话
"end": true // 如果为true,代表这是一句完整的话
}
}

接收机器人状态

消息格式
{
"type": 10001, // 机器人的状态
"sender": "user_a", // 发送者userid,这里是机器人的id
"receiver": [], // 接受者userid列表,该消息实际是在房间内广播
"payload": {
"roundid": "xxx", // 唯一标识一轮对话
"timestamp": 123,
"state": 1, // 1 聆听中 2 思考中 3 说话中 4 被打断
}
}


示例代码

Android
iOS
@Override
public void onRecvCustomCmdMsg(String userId, int cmdID, int seq, byte[] message) {
String data = new String(message, StandardCharsets.UTF_8);
try {
JSONObject jsonData = new JSONObject(data);
Log.i(TAG, String.format("receive custom msg from %s cmdId: %d seq: %d data: %s", userId, cmdID, seq, data));
} catch (JSONException e) {
Log.e(TAG, "onRecvCustomCmdMsg err");
throw new RuntimeException(e);
}
}
func onRecvCustomCmdMsgUserId(_ userId: String, cmdID: Int, seq: UInt32, message: Data) {
if cmdID == 1 {
do {
if let jsonObject = try JSONSerialization.jsonObject(with: message, options: []) as? [String: Any] {
print("Dictionary: \\(jsonObject)")
// handleMessage(jsonObject)
} else {
print("The data is not a dictionary.")
}
} catch {
print("Error parsing JSON: \\(error)")
}
}
}

四、发送自定义消息

统一通过端上发送 TRTC 自定义消息,cmdID 固定是2
可以通过发送自定义的文本,跳过 asr 过程,直接跟 ai service 进行文字沟通。
{
"type": 20000, // 端上发送自定义文本消息
"sender": "user_a", // 发送者userid, 服务端会check该userid是否有效
"receiver": ["user_bot"], // 接受者userid列表,只需要填写机器人userid,服务端会check该userid是否有效
"payload": {
"id": "uuid", // 消息id,可以使用uuid,排查问题使用
"message": "xxx", // 消息内容
"timestamp": 123 // 时间戳,排查问题使用
}
}

可以通过发送打断信令来进行打断。
{
"type": 20001, // 端上发送打断信令
"sender": "user_a", // 发送者userid, 服务端会check该userid是否有效
"receiver": ["user_bot"], // 接受者userid列表,只需要填写机器人userid,服务端会check该userid是否有效
"payload": {
"id": "uuid", // 消息id,可以使用uuid,排查问题使用
"timestamp": 123 // 时间戳,排查问题使用
}
}

示例代码

Android
iOS
public void sendInterruptCode() {
try {
int cmdID = 0x2;

long time = System.currentTimeMillis();
String timeStamp = String.valueOf(time/1000);
JSONObject payLoadContent = new JSONObject();
payLoadContent.put("timestamp", timeStamp);
payLoadContent.put("id", String.valueOf(GenerateTestUserSig.SDKAPPID) + "_" + mRoomId);

String[] receivers = new String[]{robotUserId};

JSONObject interruptContent = new JSONObject();
interruptContent.put("type", AICustomMsgType.AICustomMsgType_Send_Interrupt_CMD);
interruptContent.put("sender", mUserId);
interruptContent.put("receiver", new JSONArray(receivers));
interruptContent.put("payload", payLoadContent);

String interruptString = interruptContent.toString();
byte[] data = interruptString.getBytes("UTF-8");

Log.i(TAG, "sendInterruptCode :" + interruptString);

mTRTCCloud.sendCustomCmdMsg(cmdID, data, true, true);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (JSONException e) {
throw new RuntimeException(e);
}
}

@objc func interruptAi() {
print("interruptAi")
let cmdId = 0x2
let timestamp = Int(Date().timeIntervalSince1970 * 1000)
let payload = [
"id": userId + "_\\(roomId)" + "_\\(timestamp)", // 消息id,可以使用uuid,排查问题使用
"timestamp": timestamp // 时间戳,排查问题使用
] as [String : Any]
let dict = [
"type": 20001,
"sender": userId,
"receiver": [botId],
"payload": payload
] as [String : Any]
do {
let jsonData = try JSONSerialization.data(withJSONObject: dict, options: [])
self.trtcCloud.sendCustomCmdMsg(cmdId, data: jsonData, reliable: true, ordered: true)
} catch {
print("Error serializing dictionary to JSON: \\(error)")
}
}

五、停止 AI 对话,退出 TRTC 房间

1. 停止 AI 对话任务 :StopAIConversation
同样推荐由业务后台来调用,客户端只调用业务后台提供的接口,来停止 AI 对话。
2. 退出 TRTC 房间建议参见 退出房间(Android&iOS&Windows&Mac)

六、使用高级功能

1、接入回调接口

注意:
回调地址在 TRTC 控制台设置,AI实时对话回调。
字段名
类型
含义
EVENT_TYPE_AI_SERVICE_START
901
AI 任务开始,调用 start 接口,启动任务时产生
EVENT_TYPE_AI_SERVICE_STOP
902
AI 任务结束,调用 stop 接口,结束任务时产生
EVENT_TYPE_AI_SERVICE_MSG
903
识别出完整的一句话后回调
以及在 LLM 产生完整的回答时回调
EVENT_TYPE_AI_SERVICE_START_OF_SPEECH
904
识别到用户开始说话回调
EVENT_TYPE_AI_SPEAKING_FINISHED
905
在一轮对话中,AI机器人说完话时回调
说明:
可配合 TRTC 房间与媒体回调 配合使用,丰富功能。
开始事件901
{
"EventGroupId": 9, // 事件组ID,AI服务固定为9,EVENT_GROUP_AI_SERVICE
"EventType": 901, // 事件类型,详细事件类型见下方
"CallbackTs": 1687770730166, // 事件回调服务器向您的服务器发出回调请求的 Unix 时间戳,单位为毫秒
"EventInfo": {
"EventMsTs": 1622186275757, // 事件触发的ms时间戳
"TaskId": "xx", // 任务ID
"RoomId": "1234",
"RoomIdType": 0, // 0表示数字房间号,1表示字符串房间号
"Payload": {
"Status": 0
}
}
}
字段
类型
含义
Status
Number
0:启动 AI 任务成功
1:启动 AI 任务失败
结束事件902
{
"EventGroupId": 9, // 事件组ID,AI服务固定为9,EVENT_GROUP_AI_SERVICE
"EventType": 902, // 事件类型,详细事件类型见下方
"CallbackTs": 1687770730166, // 事件回调服务器向您的服务器发出回调请求的 Unix 时间戳,单位为毫秒
"EventInfo": {
"EventMsTs": 1622186275757, // 事件触发的ms时间戳
"TaskId": "xx", // 任务ID
"RoomId": "1234",
"RoomIdType" 0, // 0表示数字房间号,1表示字符串房间号
"Payload": {
"LeaveCode": 0
}
}
}

字段
类型
含义
LeaveCode
Number
0:正常调用停止接口后任务退出
1:业务自己踢掉转录机器人后任务退出
2:业务自己解散房间后任务退出
3:TRTC 服务端踢掉机器人
4:TRTC 服务端解散房间
98:内部异常错误,建议业务进行重试
99:代表房间内除了转录机器人没有其他用户流,超过指定时间退出
识别完成一句话回调 903
{
"EventGroupId": 9, // 事件组ID,AI服务固定为9,EVENT_GROUP_AI_SERVICE
"EventType": 903, // 事件类型,详细事件类型见下方
"CallbackTs": 1687770730166, // 事件回调服务器向您的服务器发出回调请求的 Unix 时间戳,单位为毫秒
"EventInfo": {
"EventMsTs": 1622186275757, // 事件触发的ms时间戳
"TaskId": "xx", // 任务ID
"RoomId": "1234",
"RoomIdType" 0, // 0表示数字房间号,1表示字符串房间号
"Payload": {
"type": "subtitle", // subtitle是字幕消息 transcription是转录消息
"userid": "xxx", // 消息对应的用户
"text": "xxxx", // 源语言文本
"translation_text": "xxx", // 翻译语言文本,没有翻译时为空字符串
"start_time": "00:30:00", // 开始时间
"end_time": "00:30:02" // 结束时间
"roundid": "xxxxx" // 一轮对话的唯一id
"start_ms_ts": 123245678 // 开始的毫秒时间戳
"end_ms_ts": 123245678 // 内容结束的毫秒时间戳(asr代表识别结束,llm代表回复结束)
}
}
}

用户开始说话回调 904
{
"EventGroupId": 9, // 事件组ID,AI服务固定为9,EVENT_GROUP_AI_SERVICE
"EventType": 904, // 事件类型,开始识别第一个字 "CallbackTs": 1687770730166, // 事件回调服务器向您的服务器发出回调请求的 Unix 时间戳,单位为毫秒
"EventInfo": {
"EventMsTs": 1622186275757, // 事件触发的ms时间戳
"TaskId": "xx", // 任务ID
"RoomId": "1234",
"RoomIdType" 0, // 0表示数字房间号,1表示字符串房间号
"Payload": {
"userid": "xxx",
"start_time": "00:30:00", // 开始时间
"roundid": "xxxxx" // 一轮对话的唯一id
}
}
}
AI机器人说完话时回调 905
{
"EventGroupId": 9, // 事件组ID,AI服务固定为9,EVENT_GROUP_AI_SERVICE
"EventType": 905, // 事件类型,详细事件类型见下方
"CallbackTs": 1687770730166, // 事件回调服务器向您的服务器发出回调请求的 Unix 时间戳,单位为毫秒
"EventInfo": {
"EventMsTs": 1622186275757, // 事件触发的ms时间戳
"TaskId": "xx", // 任务ID
"RoomId": "1234",
"RoomIdType" 0, // 0表示数字房间号,1表示字符串房间号
"Payload": {
"UserId": "UserId", // AI机器人的UserId
"RoundId": "RoundId", // 当前对话的RoundId
"Text": "Text" // 在本轮对话中,AI机器人已经说了文本
}
}
}

2、AI 对话的控制和更新:

3、其余高级功能介绍

功能
操作指引
智能打断
实现上下文管理
监听AI对话
实现实时字幕
调用 function call