火山控制台开启试用:开通管理
对提供的长文本或网页链接进行分析总结,也可以对一个特定话题做联网总结,最终流式生成双人播客音频。
wss://openspeech.bytedance.com/api/v3/sami/podcasttts
Key | 说明 | 是否必须 | Value示例 |
|---|---|---|---|
X-Api-Key | 使用火山引擎控制台获取的API Key,可参考 获取API Key | 是 | your-api-key |
X-Api-Resource-Id | 表示调用服务的资源信息 ID
| 是 | volc.service_type.10050 |
X-Api-Request-Id | 标识客户端请求ID,uuid随机字符串 | 否 | 67ee89ba-7050-4c04-a3d7-ac61a63499b3 |
Key | 说明 | Value示例 |
|---|---|---|
X-Tt-Logid | 服务端返回的 logid,建议用户获取和打印方便定位问题 | 2025041513355271DF5CF1A0AE0508E78C |
WebSocket 使用二进制协议传输数据。
协议的组成由至少 4 个字节的可变 header、payload size 和 payload 三部分组成,其中
需注意:协议中整数类型的字段都使用大端表示。
Byte | Left 4-bit | Right 4-bit | 说明 |
|---|---|---|---|
0 - Left half | Protocol version | 目前只有v1,始终填0b0001 | |
0 - Right half | Header size (4x) | 目前只有4字节,始终填0b0001 | |
1 - Left half | Message type | 固定为0b001 | |
1 - Right half | Message type specific flags | 在sendText时,为0 | |
2 - Left half | Serialization method | 0b0000:Raw(无特殊序列化方式,主要针对二进制音频数据)0b0001:JSON(主要针对文本类型消息) | |
2 - Right half | Compression method | 0b0000:无压缩0b0001:gzip | |
3 | Reserved | 留空(0b0000 0000) | |
[4 ~ 7] | [Optional field,like event number,...] | 取决于Message type specific flags,可能有、也可能没有 | |
... | Payload | 可能是音频数据、文本数据、音频文本混合数据 | |
字段 | 描述 | 是否必须 | 类型 | 默认值 |
|---|---|---|---|---|
action | 生成类型:
| 是 | number | 0 |
input_text | 待播客合成输入文本,上下文最长 32k,超过会报错
| 否 | string | —— |
prompt_text | prompt文本,不具备指令能力
| 否 | string | —— |
nlp_texts | 待合成的播客轮次文本列表
| 否 | []object | —— |
nlp_texts.text | 每个轮次播客文本
| 否 | string | —— |
nlp_texts.speaker | 每个轮次播客发音人
| 否 | string | —— |
input_info | 输入辅助信息 | 否 | object | —— |
input_info.input_url | 网页链接或者可下载的文件(pdf,doc,txt)链接,会自动转换成长文播客文本 | 否 | string | —— |
input_info.only_nlp_text | 只输出播客轮次文本列表,没有音频,默认值为false | 否 | bool | —— |
input_info.return_audio_url | 返回可下载的完整播客音频链接,有效期 1h
| 否 | bool | —— |
input_info.input_text_max_length | 当action=0时,支持设置模型处理的最大字符数,默认为 20000 字符。系统会自动截断超过设定值的文本,为保证模型处理的稳定性,建议取值≦12000字符
| 否 | int | —— |
input_info.max_char_length_per_round | 每轮最大合成字符数,默认为 300 字符。达到上限时不做硬截断,优先在句号(。)等句末标点处断句,保证语句完整后,再判断是否超出字符上限 | 否 | int | —— |
input_info.strict_audit | 用于声明安全审核等级,true代表严格审核、false代表普通审核,默认为false | 否 | bool | false |
use_head_music | 是否使用开头音效 | 否 | bool | true |
use_tail_music | 是否使用结尾音效 | 否 | bool | false |
aigc_watermark | 是否在合成结尾增加音频节奏标识,作为显示水印 | 否 | bool | false |
aigc_metadata | 在合成音频 header加入元数据隐式水印,支持 mp3/wav/ogg_opus | 否 | object | —— |
aigc_metadata.enable | 是否启用隐式水印 | 否 | bool | false |
aigc_metadata.content_producer | 合成服务提供者的名称或编码 | 否 | string | "" |
aigc_metadata.produce_id | 内容制作编号 | 否 | string | "" |
aigc_metadata.content_propagator | 内容传播服务提供者的名称或编码 | 否 | string | "" |
aigc_metadata.propagate_id | 内容传播编号 | 否 | string | "" |
audio_config | 音频参数,便于服务节省音频解码耗时 | 否 | object | —— |
audio_config.format | 音频编码格式,mp3/ogg_opus/pcm/aac | 否 | string | pcm |
audio_config.sample_rate | 音频采样率,可选值 [16000, 24000, 48000] | 否 | number | 24000 |
audio_config.speech_rate | 语速,取值范围[-50,100],100代表2.0倍速,-50代表0.5倍数 | 否 | number | 0 |
speaker_info | 指定发音人信息 | 否 | object | —— |
speaker_info.random_order | 发音人是否随机顺序开始,默认是 | 否 | bool | true |
speaker_info.speakers | 播客发音人, 只能选择 2 发音人
| 否 | []string | |
speaker_info.speaker_additions | 发音人额外信息,使用 TTS 和 ICL 音色的时候可生效: 在使用复刻 2.0 音色的使用如果要切换模型也需要输入到下面的additions参数里面。model 参数的取值参考上述文档里面【req_params.model】的介绍。 参考:{"SPEAKERID1": additions, "SPEAKERID2": additions} Python: | 否 | map[string][string] | —— |
retry_info | 重试信息 | 否 | object | —— |
retry_info.retry_task_id | 前一个没获取完整的播客记录的 task_id(第一次StartSession使用的 session_id就是任务的 task_id) | 否 | string | —— |
retry_info.last_finished_round_id | 前一个获取完整的播客记录的轮次 id | 否 | number | —— |
可选发音人列表
发音人的选择最好用同个系列的配对使用会有更好的效果
默认:dayi/mizai 系列
系列 | 发音人名称 |
|---|---|
黑猫侦探社咪仔 | zh_female_mizaitongxue_v2_saturn_bigtts |
zh_male_dayixiansheng_v2_saturn_bigtts | |
刘飞和潇磊 | zh_male_liufei_v2_saturn_bigtts |
zh_male_xiaolei_v2_saturn_bigtts | |
TTS 音色列表 | https://www.volcengine.com/docs/6561/1257544?lang=zh |
参数使用示例
action = 0 长文本总结模式示例
{ "input_text": "分析下当前的大模型发展", "action": 0, "use_head_music": false, "audio_config": { "format": "mp3", "sample_rate": 24000, "speech_rate": 0 }, "speaker_info": { "random_order": true, "speakers": [ "zh_male_dayixiansheng_v2_saturn_bigtts", "zh_female_mizaitongxue_v2_saturn_bigtts" ] }, "aigc_watermark": false, "aigc_metadata": { "enable": true, "content_producer": "volcengine", "produce_id": "12abc", "content_propagator": "volcengine", "propagate_id": "34def" } }
action = 0 url 解析模式示例
{ "action": 0, "use_head_music": false, "audio_config": { "format": "mp3", "sample_rate": 24000, "speech_rate": 0, }, "input_info": { "input_url": "https://mp.weixin.qq.com/s/CiN0XRWQc3hIV9lLLS0rGA" } }
action = 3 根据提供的对话文本调用示例
{ "action": 3, "use_head_music": false, "audio_config": { "format": "mp3", "sample_rate": 24000, "speech_rate": 0, }, "nlp_texts": [ { "speaker": "zh_male_dayixiansheng_v2_saturn_bigtts", "text": "今天呢我们要聊的呢是火山引擎在这个 FORCE 原动力大会上面的一些比较重磅的发布。" }, { "speaker": "zh_female_mizaitongxue_v2_saturn_bigtts", "text": "来看看都有哪些亮点哈。" } ] }
action = 4 根据提供prompt文本联网总结调用示例
{ "action": 4, "prompt_text": "火山引擎", "use_head_music": false, "audio_config": { "format": "mp3", "sample_rate": 24000, "speech_rate": 0, } }
主要关注建连阶段 HTTP Response 的状态码和 Body
Byte | Left 4-bit | Right 4-bit | 说明 |
|---|---|---|---|
0 - Left half | Protocol version | 目前只有v1,始终填0b0001 | |
0 - Right half | Header size (4x) | 目前只有4字节,始终填0b0001 | |
1 - Left half | Message type | 音频帧返回:0b1011 | |
1 - Right half | Message type specific flags | 固定为0b0100 | |
2 - Left half | Serialization method | 0b0000:Raw(无特殊序列化方式,主要针对二进制音频数据)0b0001:JSON(主要针对文本类型消息) | |
2 - Right half | Compression method | 0b0000:无压缩0b0001:gzip | |
3 | Reserved | 留空(0b0000 0000) | |
[4 ~ 7] | [Optional field,like event number,...] | 取决于Message type specific flags,可能有、也可能没有 | |
... | Payload | 可能是音频数据、文本数据、音频文本混合数据 | |
字段 | 描述 | 类型 |
|---|---|---|
data | 返回的二进制数据包 | byte |
event | 返回的事件类型 | number |
Byte | Left 4-bit | Right 4-bit | 说明 |
|---|---|---|---|
0 - Left half | Protocol version | 目前只有v1,始终填0b0001 | |
0 - Right half | Header size (4x) | 目前只有4字节,始终填0b0001 | |
1 | Message type | Message type specific flags | 0b11110000 |
2 - Left half | Serialization method | 0b0000:Raw(无特殊序列化方式,主要针对二进制音频数据)0b0001:JSON(主要针对文本类型消息) | |
2 - Right half | Compression method | 0b0000:无压缩0b0001:gzip | |
3 | Reserved | 留空(0b0000 0000) | |
[4 ~ 7] | Error code | 错误码 | |
... | Payload | 错误消息对象 | |
在生成 podcast 阶段,不需要客户端发送上行的event帧。event类型如下:
Event code | 含义 | 事件类型 | 应用阶段:上行/下行 |
|---|---|---|---|
150 | SessionStarted,会话任务开始 | Session 类 | 下行 |
360 | PodcastRoundStart,播客返回新轮次内容开始,带着轮次 idx 和 speaker | 数据类 | 下行 |
361 | PodcastRoundResponse,播客返回轮次的音频内容 | 数据类 | 下行 |
362 | PodcastRoundEnd,播客返回内容当前轮次结束 | 数据类 | 下行 |
363 | PodcastEnd,返回一些播客总结性的信息,表示播客结束(为了兼容之前的使用,这个事件不一定会返回) | 数据类 | 下行 |
152 | SessionFinished,会话已结束(上行&下行) | Session 类 | 下行 |
154 | UsageResponse, 播客返回的用量事件。 | 数据类 | 下行 |
在关闭连接阶段,需要客户端传递上行event帧去关闭连接。event类型如下:
Event code | 含义 | 事件类型 | 应用阶段:上行/下行 |
|---|---|---|---|
2 | FinishConnection,结束连接 | Connect 类 | 上行 |
52 | ConnectionFinished 结束连接成功 | Connect 类 | 下行 |
示意图(重要!!!!):
Byte | Left 4-bit | Right 4-bit | 说明 | |
|---|---|---|---|---|
0 | 0001 | 0001 | v1 | 4-byte header |
1 | 1001 | 0100 | Full-client request | with event number |
2 | 0001 | 0000 | JSON | no compression |
3 | 0000 | 0000 | ||
4 ~ 7 | StartSession | event type | ||
8 ~ 11 | uint32(12) | len(<session_id>) | ||
12 ~ 23 | nxckjoejnkegf | session_id | ||
24 ~ 27 | uint32( ...) | len(payload) | ||
28 ~ ... | {} |
| ||
payload
{ "input_text": "分析下当前的大模型发展", "action": 0, "use_head_music": false, "audio_config": { "format": "pcm", "sample_rate": 24000, "speech_rate": 0, } }
断点续传的时候需要加上 retry 信息payload
{ "input_text": "分析下当前的大模型发展", "action": 0, "use_head_music": false, "audio_config": { "format": "pcm", "sample_rate": 24000, "speech_rate": 0, }, "retry_info": { "retry_task_id": "xxxxxxxxx", "last_finished_round_id": 5 } }
Byte | Left 4-bit | Right 4-bit | 说明 | |
|---|---|---|---|---|
0 | 0001 | 0001 | v1 | 4-byte header |
1 | 1011 | 0100 | Audio-only response | with event number |
2 | 0001 | 0000 | JSON | no compression |
3 | 0000 | 0000 | ||
4 ~ 7 | SessionStarted | event type | ||
8 ~ 11 | uint32(12) | len(<session_id>) | ||
12 ~ 23 | nxckjoejnkegf | session_id | ||
24 ~ 27 | uint32( ...) | len(audio_binary) | ||
28 ~ ... | { | payload_json | ||
UsageResponse
Byte | Left 4-bit | Right 4-bit | 说明 | |
|---|---|---|---|---|
0 | 0001 | 0001 | v1 | 4-byte header |
1 | 1011 | 0100 | Audio-only response | with event number |
2 | 0001 | 0000 | JSON | no compression |
3 | 0000 | 0000 | ||
4 ~ 7 | UsageResponse | event type | ||
8 ~ 11 | uint32(12) | len(<session_id>) | ||
12 ~ 23 | nxckjoejnkegf | session_id | ||
24 ~ 27 | uint32( ...) | len(audio_binary) | ||
28 ~ ... | 文本 token 消耗推送: | payload_json | ||
下面三个事件循环 ♻️,如果没有收到PodcastTTSRoundEnd(需要和PodcastSpeaker成对出现)就断掉了链接说明需要断点续传重新发起请求
Byte | Left 4-bit | Right 4-bit | 说明 | |
|---|---|---|---|---|
0 | 0001 | 0001 | v1 | 4-byte header |
1 | 1011 | 0100 | Audio-only response | with event number |
2 | 0001 | 0000 | JSON | no compression |
3 | 0000 | 0000 | ||
4 ~ 7 | PodcastRoundStart | event type | ||
8 ~ 11 | uint32(12) | len(<session_id>) | ||
12 ~ 23 | nxckjoejnkegf | session_id | ||
24 ~ 27 | uint32( ...) | len(audio_binary) | ||
28 ~ ... | { | response_meta_json round_id == -1,代表开头音频 | ||
Byte | Left 4-bit | Right 4-bit | 说明 | |
|---|---|---|---|---|
0 | 0001 | 0001 | v1 | 4-byte header |
1 | 1001 | 0100 | Full-client request | with event number |
2 | 0001 | 0000 | JSON | no compression |
3 | 0000 | 0000 | ||
4 ~ 7 | PodcastTTSResponse | event type | ||
8 ~ 11 | uint32(12) | len(<session_id>) | ||
12 ~ 23 | nxckjoejnkegf | session_id | ||
24 ~ 27 | uint32( ...) | len(payload) | ||
28 ~ ... | ... 音频内容 | payload | ||
Byte | Left 4-bit | Right 4-bit | 说明 | |
|---|---|---|---|---|
0 | 0001 | 0001 | v1 | 4-byte header |
1 | 1001 | 0100 | Full-client request | with event number |
2 | 0001 | 0000 | JSON | no compression |
3 | 0000 | 0000 | ||
4 ~ 7 | PodcastRoundEnd | event type | ||
8 ~ 11 | uint32(12) | len(<session_id>) | ||
12 ~ 23 | nxckjoejnkegf | session_id | ||
24 ~ 27 | uint32( ...) | len(response_meta_json) | ||
28 ~ ... | { 每句播客返回带着时长以及在完整播客音频的开始和结束时间位置。 | response_meta_json | ||
Byte | Left 4-bit | Right 4-bit | 说明 | |
|---|---|---|---|---|
0 | 0001 | 0001 | v1 | 4-byte header |
1 | 1001 | 0100 | Full-client request | with event number |
2 | 0001 | 0000 | JSON | no compression |
3 | 0000 | 0000 | ||
4 ~ 7 | PodcastEnd | event type | ||
8 ~ 11 | uint32(12) | len(<session_id>) | ||
12 ~ 23 | nxckjoejnkegf | session_id | ||
24 ~ 27 | uint32( ...) | len(response_meta_json) | ||
28 ~ ... | {'meta_info': {'audio_url': 'https://speech-tts-podcast.tos-cn-beijing.volces.com/speech-tts-podcast/tts_audio/aGjiRDfUWi/a0979493-196a-42ad-aff1-1dfe63c7e219/podcast_demo.mp3?X-Tos-Algorithm=TOS4-HMAC-SHA256&X-Tos-Credential=AKLTY2M5ZDg4NzA2MDUxNDI0ZThkMTU5YTNkNjk4ZDg5OTM%2F20250825%2Fcn-beijing%2Ftos%2Frequest&X-Tos-Date=20250825T084035Z&X-Tos-Expires=3600&X-Tos-Signature=2a549ee5f5ed8a32ce34d475ccf56f50a02e78b3431eb760fb9edc3d0d15296b&X-Tos-SignedHeaders=host', 'topics': None}} | response_meta_json | ||
Byte | Left 4-bit | Right 4-bit | 说明 | |
|---|---|---|---|---|
0 | 0001 | 0001 | v1 | 4-byte header |
1 | 1001 | 0100 | Full-client request | with event number |
2 | 0001 | 0000 | JSON | no compression |
3 | 0000 | 0000 | ||
4 ~ 7 | FinishSession | event type | ||
8 ~ 11 | uint32(12) | len(<session_id>) | ||
12 ~ 23 | nxckjoejnkegf | session_id | ||
24 ~ 27 | uint32( ...) | len(payload) | ||
28 ~ ... | {} | tts_session_meta | ||
Byte | Left 4-bit | Right 4-bit | 说明 | |
|---|---|---|---|---|
0 | 0001 | 0001 | v1 | 4-byte header |
1 | 1001 | 0100 | Full-client request | with event number |
2 | 0001 | 0000 | JSON | no compression |
3 | 0000 | 0000 | ||
4 ~ 7 | SessionFinished | event type | ||
8 ~ 11 | uint32(7) | len(<connection_id>) | ||
12 ~ 15 | uint32(58) | len(<response_meta_json>) | ||
28 ~ ... | { | response_meta_json
| ||
Byte | Left 4-bit | Right 4-bit | 说明 | |
|---|---|---|---|---|
0 | 0001 | 0001 | v1 | 4-byte header |
1 | 1001 | 0100 | Full-client request | with event number |
2 | 0001 | 0000 | JSON | no compression |
3 | 0000 | 0000 | ||
4 ~ 7 | FinishConnection | event type | ||
8 ~ 11 | uint32(2) | len(<response_meta_json>) | ||
12 ~ 13 | {} | tts_session_meta | ||
Byte | Left 4-bit | Right 4-bit | 说明 | |
|---|---|---|---|---|
0 | 0001 | 0001 | v1 | 4-byte header |
1 | 1001 | 0100 | Full-client request | with event number |
2 | 0001 | 0000 | JSON | no compression |
3 | 0000 | 0000 | ||
4 ~ 7 | ConnectionFinished | event type | ||
8 ~ 11 | uint32(7) | len(<connection_id>) | ||
12 ~ 15 | uint32(58) | len(<response_meta_json>) | ||
28 ~ ... | { | response_meta_json
| ||
Code | Message | 说明 |
|---|---|---|
20000000 | ok | 音频合成结束的成功状态码 |
45000000 | quota exceeded for types: concurrency | 并发限流,一般是请求并发数超过限制 |
40000010 | PodcastTTS invalid param | 参数错误,根据 msg 信息检测入参是否正确 |
40000022 | IllegalPayload:TextRiskAuditFailed | 开启严格风控之后命中风控合成失败,建议检查输入文本 |
55000000 | 服务端一些error | 服务端通用错误 |
50302102 | action = 0 的报错: action = 4 的报错: | 触发安全审核过滤 |
50302102 | NLP RespError(50000001/FangzhouPodcastNLPFailed:content length) | 文本上下文超过限制 |
<appid>:使用控制台获取的APP ID,可参考 控制台使用FAQ-Q1。<access_token>:使用控制台获取的Access Token,可参考 控制台使用FAQ-Q1。python3 -m pip install --upgrade pip
解压缩代码包,安装依赖
mkdir -p volcengine_podcasts_demo tar xvzf volcengine_podcasts_demo.tar.gz -C ./volcengine_podcasts_demo cd volcengine_podcasts_demo python3 -m venv .venv source .venv/bin/activate python3 -m pip install --upgrade pip pip3 install -e .
<appid>替换为您的APP ID。<access_token>替换为您的Access Token。<text>为播客文本。
python3 examples/volcengine/podcasts.py --appid <appid> --access_token <access_token> --text "介绍下火山引擎"
输出音频 demo: