跳到主要内容

语音回复 (Reply Audio)

给 Agent 配置了声音之后,它的每一条回复都可以被朗读出来:SDK 流式拉取音频、边收边播,并在本地缓存,重复播放不再计费。 文字、音色和模型都由平台根据 Agent 的配置决定,客户端只需要指明「朗读哪一条回复」。

前提:Agent 的所有者需要先为 Agent 配置声音。没有配置声音的 Agent,朗读请求会失败;这时建议在组件上关闭朗读按钮(showAudioControls={false})。

在 React 组件里

<ChatBox> / <ChatWidget> 默认在每条已完成的回复上显示朗读按钮,点击即播放,再点停止;加载失败时按钮变为「重试」。

<ChatWidget agentId="" getToken={getToken} /> {/* 默认显示朗读按钮 */}
<ChatWidget agentId="" getToken={getToken} autoPlayAudio /> {/* 每条回复完成后自动朗读 */}
<ChatWidget agentId="" getToken={getToken} showAudioControls={false} /> {/* 不显示朗读按钮 */}

按钮的无障碍标签可以用 audioLabels 覆盖:

<ChatBox audioLabels={{ play: '朗读', stop: '停止', loading: '加载中', error: '重试' }} />

用无头 Hook 时:

const { messages, playAudio, stopAudio, audioPlayback } = useOpenhexChat({ agentId: '…', getToken });

// audioPlayback[message.id]: 'idle' | 'loading' | 'playing' | 'error'
<button onClick={() => playAudio(message)}>朗读</button>

playAudio 只对已经完成、并且带有 replyStreamId 的 Agent 回复生效。

在 JS / TS 里

client.chat.messageAudio 拉取一条回复的完整音频,返回 Blob

const audio = await client.chat.messageAudio(agentId, conversationId, messageId, {
onChunk: chunk => player.append(chunk), // 可选:边收边处理
});

audio.blob; // audio/mpeg
audio.billableCharacters; // 本次合成计费的字符数(可能为空)
audio.requestId; // 平台请求 id,排查问题时提供
audio.fallbackUsed; // 是否走了备用路径
参数说明
agentId回复所属的 Agent
conversationId回复所在的对话
messageId回复在事件流里的 id,即流式记录的 record.id(React 消息上的 replyStreamId
onChunk每收到一段音频字节时回调
fallback流式请求失败时是否改用非流式请求重试,默认 true
signal取消请求

SDK 先请求流式接口;流式失败且你没有主动取消时,自动改走非流式接口再试一次。

本地缓存

同一条回复重复播放时,用 MessageAudioCache 避免重复请求:

import { MessageAudioCache } from '@openhex-ai/agent-sdk';

const cache = new MessageAudioCache(10); // 最多缓存 10 条,按最近使用淘汰

let blob = cache.get(messageId);
if (!blob) {
blob = (await client.chat.messageAudio(agentId, conversationId, messageId)).blob;
cache.set(messageId, blob);
}
new Audio(URL.createObjectURL(blob)).play();

React 组件内部已经这样做了。

常见错误

状态码detail原因
403forbidden当前账号 / Agent 未开放语音回复
404reply message not foundmessageId 不是这个对话里该 Agent 的一条已完成回复,或这条回复没有可朗读的文本
413reply message is too long for speech synthesis回复超过 20000 字符

下一步