在用户与智能体进行语音互动过程中,你可能需要智能体主动播报外部文本内容,引导客户互动、提醒用户注意事项、或提供重要信息。你可以使用该功能实现。
场景 | 描述 | 示例 |
---|---|---|
AI 陪练 | 用户长时间不说话时,智能体播放内容吸引用户继续互动。 | "我注意到你有一会儿没说话了,需要我解释一下刚才的内容吗?" |
桌游主持 | 智能体扮演主持人角色,引导用户完成游戏流程。 | “现在轮到玩家 A 发言,请开始。” |
安全监管 | 用户问题或大模型生成内容不合规时,引导用户调整会话内容。 | "抱歉,对话内容不符合社区规范。" |
延迟安抚 | 触发 Function Calling 或联网造成智能体回答延迟偏大时,引导用户耐心等待。 | "正在处理,请稍等。" |
参考场景搭建 Web 已实现场景搭建。
你可以通过以下两种方式传入外部文本信息:
调用 UpdateVoiceChat
接口,设置以下参数传入播报内容,并控制智能体的播报行为:
Command
:填入 ExternalTextToSpeech
,表示通过文本转语音(TTS)进行播报。Message
:填入外部文本内容,长度不超过 200 个字符。InterruptMode
:设置文本内容播报的优先级。
InterruptMode
为 1
时:高优先级。智能体会终止当前交互,直接播放传入的文本内容。InterruptMode
为 2
时:中优先级。智能体会在当前交互结束后,播放传入的文本内容。InterruptMode
为 3
时:低优先级。如果此时智能体正在交互,智能体会直接丢弃传入的文本内容。如果未在交互,智能体会播放传入的文本内容。你可参看以下示例进行传入外部文本信息进行播放:
POST https://rtc.volcengineapi.com?Action=UpdateVoiceChat&Version=2024-12-01 { "AppId": "661e****543cf", // RTC 应用 AppId "RoomId": "Room1", // 会话房间 ID "TaskId": "task1", // 会话任务 ID "Command": "ExternalTextToSpeech", //控制命令,此处填入 ExternalTextToSpeech "Message": "你刚才的故事讲的真棒,能再讲一个吗。" // 外部文本内容,长度不超过 200 个字符。 "InterruptMode": 1 //文本内容播报的优先级。 }
调用 SendUserBinaryMessage
在 buffer
参数中传入二进制格式的外部文本信息及相关配置,buffer
参数传入内容格式如下:
参数名 | 类型 | 描述 |
---|---|---|
magic number | binary | 消息格式,此处填入 ctrl 。 |
length | binary | 外部文本消息长度,单位为 bytes。存放方式为大端序。 |
control_message | binary | 外部文本配置信息。JSON 格式,具体内容格式参看 control_message 格式。 |
control_message:
参数名 | 类型 | 描述 |
---|---|---|
Command | String | 控制命令,此处填入 ExternalTextToSpeech 。 |
Message | String | 外部文本内容,长度不超过 200 个字符。 |
InterruptMode | String | 文本内容播报的优先级。
|
你可参看以下示例进行传入外部文本信息进行播放:
// 发送文本转语音(TTS)指令,让智能体播报指定的文本内容。 void sendTTSMessage(const std::string &uid, const std::string& content) { nlohmann::json json_data; json_data["Command"] = "ExternalTextToSpeech"; json_data["Message"] = content; json_data["InterruptMode"] = 1; // InterruptMode 可选值1,2,3 sendUserBinaryMessage(uid, json_data.dump()); } void buildBinaryMessage(const std::string& magic_number, const std::string& message, size_t& binary_message_length, std::shared_ptr<uint8_t[]>& binary_message) { auto magic_number_length = magic_number.size(); auto message_length = message.size(); binary_message_length = magic_number_length + 4 + message_length; binary_message = std::shared_ptr<uint8_t[]>(new uint8_t[binary_message_length]); std::memcpy(binary_message.get(), magic_number.data(), magic_number_length); binary_message[magic_number_length] = static_cast<uint8_t>((message_length >> 24) & 0xFF); binary_message[magic_number_length+1] = static_cast<uint8_t>((message_length >> 16) & 0xFF); binary_message[magic_number_length+2] = static_cast<uint8_t>((message_length >> 8) & 0xFF); binary_message[magic_number_length+3] = static_cast<uint8_t>(message_length & 0xFF); std::memcpy(binary_message.get()+magic_number_length+4, message.data(), message_length); } int sendUserBinaryMessage(const std::string &uid, const std::string& message) { if (rtcRoom_ != nullptr) { size_t length = 0; std::shared_ptr<uint8_t[]> binary_message = nullptr; buildBinaryMessage("ctrl", message, length, binary_message); return rtcRoom_->sendUserBinaryMessage(uid.c_str(), static_cast<int>(length), binary_message.get()); } return -1; }
// 发送文本转语音(TTS)指令,让智能体播报指定的文本内容。 public void sendTTSMessage(String userId, String content) { JSONObject json = new JSONObject(); try { json.put("Command", "ExternalTextToSpeech"); json.put("Message", content); json.put("InterruptMode", 1); // InterruptMode 可选值1,2,3 } catch (JSONException e) { throw new RuntimeException(e); } String jsonString = json.toString(); byte[] buildBinary = buildBinaryMessage("ctrl", jsonString); sendUserBinaryMessage(userId, buildBinary); } private byte[] buildBinaryMessage(String magic_number, String content) { byte[] prefixBytes = magic_number.getBytes(StandardCharsets.UTF_8); byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8); int contentLength = contentBytes.length; ByteBuffer buffer = ByteBuffer.allocate(prefixBytes.length + 4 + contentLength); buffer.order(ByteOrder.BIG_ENDIAN); buffer.put(prefixBytes); buffer.putInt(contentLength); buffer.put(contentBytes); return buffer.array(); } public void sendUserBinaryMessage(String userId, byte[] buffer) { if (rtcRoom_ != null) { rtcRoom_.sendUserBinaryMessage(userId, buffer, MessageConfig.RELIABLE_ORDERED); } }
import VERTC from '@volcengine/rtc'; const BotName = 'RobotMan_'; // 自定义智能体名称 const CommandKey = 'ctrl'; const engine = VERTC.createEngine('Your AppID'); // 你的 RTC 应用 APPId /** * @brief 指令类型 */ enum COMMAND { /** * @brief 发送文本转语音(TTS)指令,让智能体播报指定的文本内容。 */ EXTERNAL_TEXT_TO_SPEECH = 'ExternalTextToSpeech', }; /** * @brief 打断的类型 */ enum INTERRUPT_PRIORITY { /** * @brief 占位 */ NONE, /** * @brief 高优先级。智能体会终止当前交互,直接播放传入的文本内容。 */ HIGH, /** * @brief 中优先级。智能体会在当前交互结束后,播放传入的文本内容。 */ MEDIUM, /** * @brief 低优先级。如果此时智能体正在交互,智能体会直接丢弃传入的文本内容。如果未在交互,智能体会播放传入的文本内容 */ LOW, }; /** * @brief 将字符串包装成 TLV */ function stringToTLV(inputString: string, type = '') { const typeBuffer = new Uint8Array(4); for (let i = 0; i < type.length; i++) { typeBuffer[i] = type.charCodeAt(i); } const lengthBuffer = new Uint32Array(1); const valueBuffer = new TextEncoder().encode(inputString); lengthBuffer[0] = valueBuffer.length; const tlvBuffer = new Uint8Array(typeBuffer.length + 4 + valueBuffer.length); tlvBuffer.set(typeBuffer, 0); tlvBuffer[4] = (lengthBuffer[0] >> 24) & 0xff; tlvBuffer[5] = (lengthBuffer[0] >> 16) & 0xff; tlvBuffer[6] = (lengthBuffer[0] >> 8) & 0xff; tlvBuffer[7] = lengthBuffer[0] & 0xff; tlvBuffer.set(valueBuffer, 8); return tlvBuffer.buffer; }; /** * @brief 发送文本转语音(TTS)指令,让智能体播报指定的文本内容 */ engine.sendUserBinaryMessage( BotName, stringToTLV( JSON.stringify({ Command: COMMAND.EXTERNAL_TEXT_TO_SPEECH, Message: '自定义文本内容', InterruptMode: INTERRUPT_PRIORITY.HIGH, }), CommandKey, ) );
Q1:如果设置智能体支持语音打断,外部文本信息不打断智能体输出。本次交互被语音打断时,外部文本信息何时播放?
A1:此时外部文本信息会被丢弃。
Q2:播放的外部文本信息是否会放入历史对话?
A2:会。
Q3:如果设置智能体支持语音打断,外部文本消息不打断智能体输出。外部文本播放时被打断,该文本消息是否会放在历史对话中?
A3:已输出的内容会放入历史对话中。