MaaS_DB_Speech API
1. 接口说明
接口地址为 wss://genaiapi.cloudsway.net/ws/api/v1/tts/ws_binary
2. 身份认证
认证方式使用 Bearer Token,在请求 header 中加上"Authorization": "Bearer {YOUR_ACCESS_KEY}"
、"ModelName":"MaaS_DB_Speech"
。
3. 请求方式
二进制协议
字段描述
字段 Field (大小, 单位 bit) |
描述 Description |
值 Values |
协议版本(Protocol version) (4) |
可能会在将来使用不同的协议版本,所以这个字段是为了让客户端和服务器在版本上保持一致。 |
0b0001 - 版本 1 (目前只有版本 1) |
报头大小(Header size) (4) |
header 实际大小是 header size value x 4 bytes. 这里有个特殊值 0b1111 表示 header 大小大于或等于 60(15 x 4 bytes),也就是会存在 header extension 字段。 |
0b0001 - 报头大小 = 4 (1 x 4)
0b0010 - 报头大小 = 8 (2 x 4)
0b1010 - 报头大小 = 40 (10 x 4) 0b1110 - 报头大小 = 56 (14 x 4) 0b1111 - 报头大小为 60 或更大; 实际大小在 header extension 中定义 |
消息类型(Message type) (4) |
定义消息类型。 |
0b0001 - full client request.
0b1001 - full server response(弃用). 0b1011 - Audio-only server response (ACK).
0b1111 - Error message from server (例如错误的消息类型,不支持的序列化方法等等) |
Message type specific flags (4) |
flags 含义取决于消息类型。 具体内容请看消息类型小节. |
|
序列化方法(Message serialization method) (4) |
定义序列化 payload 的方法。 注意:它只对某些特定的消息类型有意义 (例如 Audio-only server response 0b1011 就不需要序列化). |
0b0000 - 无序列化 (raw bytes) 0b0001 - JSON
0b1111 - 自定义类型, 在 header extension 中定义 注:目前只支持JSON格式 |
压缩方法(Message Compression) (4) |
定义 payload 的压缩方法。 Payload size 字段不压缩(如果有的话,取决于消息类型),而且 Payload size 指的是 payload 压缩后的大小。 Header 不压缩。 |
0b0000 - 无压缩
0b0001 - gzip
0b1111 - 自定义压缩方法, 在 header extension 中定义 注:目前只支持无压缩 |
保留字段(Reserved) (8) |
保留字段,同时作为边界 (使整个报头大小为 4 个字节). |
0x00 - 目前只有 0 |
消息类型详细说明
目前所有 TTS websocket 请求都使用 full client request 格式,无论"query"还是"submit"。
Full client request
- Header size为
b0001
(即 4B,没有 header extension)。
- Message type为
b0001
.
- Message type specific flags 固定为
b0000
.
- Message serialization method为
b0001
JSON。字段参考上方表格。
- 如果使用 gzip 压缩 payload,则 payload size 为压缩后的大小。
Audio-only server response
- Header size 应该为
b0001
.
- Message type为
b1011
.
- Message type specific flags 可能的值有:
b0000
- 没有 sequence number.
b0001
- sequence number > 0.
b0010
orb0011
- sequence number < 0,表示来自服务器的最后一条消息,此时客户端应合并所有音频片段(如果有多条)。
- Message serialization method为
b0000
(raw bytes).
4.请求参数
字段 |
含义 |
层级 |
格式 |
必需 |
备注 |
app |
应用相关配置 |
1 |
dict |
✓ |
|
appid |
应用标识 |
2 |
string |
✓ |
需要申请 |
token |
应用令牌 |
2 |
string |
✓ |
可传任意非空字符串 |
cluster |
业务集群 |
2 |
string |
✓ |
volcano_tts |
user |
用户相关配置 |
1 |
dict |
✓ |
|
uid |
用户标识 |
2 |
string |
✓ |
可传任意非空字符串,传入值可以通过服务端日志追溯 |
audio |
音频相关配置 |
1 |
dict |
✓ |
|
voice_type |
音色类型 |
2 |
string |
✓ |
|
emotion |
音色情感 |
2 |
string |
|
设置音色的情感。示例:"emotion": "angry" 注:当前仅部分音色支持设置情感,且不同音色支持的情感范围存在不同。 |
enable_emotion |
开启音色情感 |
2 |
bool |
|
是否可以设置音色情感,需将enable_emotion设为true 示例:"enable_emotion": True |
encoding |
音频编码格式 |
2 |
string |
|
wav / pcm / ogg_opus / mp3,默认为 pcm 注意:wav 不支持流式 |
speed_ratio |
语速 |
2 |
float |
|
[0.8,2],默认为 1,通常保留一位小数即可 |
rate |
音频采样率 |
2 |
int |
|
默认为 24000,可选8000,16000 |
BitRate |
比特率 |
2 |
int |
|
可传16 96 128等 |
explicit_language |
明确语种 |
2 |
string |
|
仅读指定语种的文本不给定参数,正常中英混crosslingual 启用多语种前端(包含zh/en/ja/es-ms/id/pt-br)zh 中文为主,支持中英混en 仅英文ja 仅日文es-mx 仅墨西id 仅印尼pt-br 仅巴葡 |
context_language |
参考语种 |
2 |
string |
|
给模型提供参考的语种不给定 西欧语种采用英语id 西欧语种采用印尼es 西欧语种采用墨西pt 西欧语种采用巴葡 |
loudness_ratio |
音量调节 |
2 |
float |
|
[0.5,2],默认为1,通常保留一位小数即可。0.5代表原音量0.5倍,2代表原音量2倍 |
request |
请求相关配置 |
1 |
dict |
✓ |
|
reqid |
请求标识 |
2 |
string |
✓ |
需要保证每次调用传入值唯一,建议使用 UUID |
text |
文本 |
2 |
string |
✓ |
合成语音的文本,长度限制 1024 字节(UTF-8 编码) |
text_type |
文本类型 |
2 |
string |
|
使用 ssml 时需要指定,值为"ssml" |
silence_duration |
句尾静音 |
2 |
float |
|
设置该参数可在句尾增加静音时长,范围0~30000ms。(注:增加的句尾静音主要针对传入文本最后的句尾,而非每句话的句尾)若启用该参数,必须在request下首先设置enable_trailing_silence_audio = true |
with_timestamp |
时间戳相关 |
2 |
int string |
|
传入1时表示启用,将返回TN后文本的时间戳,例如:2025。根据语义,TN后文本为“两千零二十五”或“二零二五”。 注:原文本中的多个标点连用或者空格仍会被处理,但不影响时间戳的连贯性(仅限大模型场景使用)。 附加说明(小模型和大模型时间戳原理差异):小模型依据前端模型生成时间戳,然后合成音频。在处理时间戳时,TN前后文本进行了映射,所以小模型可返回TN前原文本的时间戳,即保留原文中的阿拉伯数字或者特殊符号等。大模型在对传入文本语义理解后合成音频,再针对合成音频进行TN后打轴以输出时间戳。若不采用TN后文本,输出的时间戳将与合成音频无法对齐,所以大模型返回的时间戳对应TN后的文本。 |
operation |
操作 |
2 |
string |
✓ |
query(非流式,http 只能 query) / submit(流式) |
extra_param |
附加参数 |
2 |
jsonstring |
|
|
disable_markdown_filter |
|
3 |
bool |
|
是否开启markdown解析过滤, 为true时,解析并过滤markdown语法,例如,你好,会读为“你好”, 为false时,不解析不过滤,例如,你好,会读为“星星‘你好’星星” 示例:"disable_markdown_filter": True |
enable_latex_tn |
|
3 |
bool |
|
是否可以播报latex公式,需将disable_markdown_filter设为true 示例:"enable_latex_tn": True |
备注:
- 已支持字级别时间戳能力(ssml文本类型不支持)
- 暂时不支持音高调节
- 大模型音色语种支持中英混
- 大模型非双向流式已支持latex公式
- 在 websocket握手成功后,会返回这些 Response header
{
"user": {
"uid": "uid123"
},
"audio": {
"voice_type": "zh_male_M392_conversation_wvae_bigtts",
"encoding": "mp3",
"speed_ratio": 1.0,
},
"request": {
"reqid": "uuid",
"text": "我爱中国",
"operation": "query",
}
}
5.注意事项
- websocket 单条链接仅支持单次合成,若需要合成多次,则需要多次建立链接
- 每次合成时 reqid 这个参数需要重新设置,且要保证唯一性(建议使用 uuid.V4 生成)
- operation 需要设置为 submit
返回码说明
错误码 |
错误描述 |
举例 |
建议行为 |
3000 |
请求正确 |
正常合成 |
正常处理 |
3001 |
无效的请求 |
一些参数的值非法,比如 operation 配置错误 |
检查参数 |
3003 |
并发超限 |
超过在线设置的并发阈值 |
重试;使用 sdk 的情况下切换离线 |
3005 |
后端服务忙 |
后端服务器负载高 |
重试;使用 sdk 的情况下切换离线 |
3006 |
服务中断 |
请求已完成/失败之后,相同 reqid 再次请求 |
检查参数 |
3010 |
文本长度超限 |
单次请求超过设置的文本长度阈值 |
检查参数 |
3011 |
无效文本 |
参数有误或者文本为空、文本与语种不匹配、文本只含标点 |
检查参数 |
3030 |
处理超时 |
单次请求超过服务最长时间限制 |
重试或检查文本 |
3031 |
处理错误 |
后端出现异常 |
重试;使用 sdk 的情况下切换离线 |
3032 |
等待获取音频超时 |
后端网络异常 |
重试;使用 sdk 的情况下切换离线 |
3040 |
后端链路连接错误 |
后端网络异常 |
重试 |
3050 |
音色不存在 |
检查使用的 voice_type 代号 |
检查参数 |
6.音色列表
多情感
音色名称 |
voice_type |
时间戳 |
语种 |
支持的情感 |
北京小爷(多情感) |
zh_male_beijingxiaoye_emo_v2_mars_bigtts |
√ |
中文 |
生气,惊讶,恐惧,激动,冷漠,中性对应的传参(emotion)分别为:angry,surprised,fear,excited,coldness,neutral |
柔美女友(多情感) |
zh_female_roumeinvyou_emo_v2_mars_bigtts |
√ |
中文 |
开心,悲伤,生气,惊讶,恐惧,厌恶,激动,冷漠,中性对应的传参(emotion)分别为:happy,sad,angry,surprised,fear,hate,excited,coldness,neutral |
阳光青年(多情感) |
zh_male_yangguangqingnian_emo_v2_mars_bigtts |
√ |
中文 |
开心,悲伤,生气,恐惧,激动,冷漠,中性对应的传参(emotion)分别为:happy,sad,angry,fear,excited,coldness,neutral |
魅力女友(多情感) |
zh_female_meilinvyou_emo_v2_mars_bigtts |
√ |
中文 |
悲伤,恐惧,中性对应的传参(emotion)分别为:sad,fear,neutral |
爽快思思(多情感) |
zh_female_shuangkuaisisi_emo_v2_mars_bigtts |
√ |
中文、美式英语 |
开心,悲伤,生气,惊讶,激动,冷漠,中性对应的传参(emotion)分别为:happy,sad,angry,surprised,excited,coldness,neutral |
通用场景
音色名称 |
voice_type |
时间戳 |
语种 |
支持的情感 |
灿灿/Shiny |
zh_female_cancan_mars_bigtts |
√ |
中文、美式英语 |
|
清新女声 |
zh_female_qingxinnvsheng_mars_bigtts |
√ |
中文 |
|
爽快思思/Skye |
zh_female_shuangkuaisisi_moon_bigtts |
√ |
中文、美式英语 |
|
温暖阿虎/Alvin |
zh_male_wennuanahu_moon_bigtts |
√ |
中文、美式英语 |
|
少年梓辛/Brayan |
zh_male_shaonianzixin_moon_bigtts |
√ |
中文、美式英语 |
|
知性女声 |
zh_female_zhixingnvsheng_mars_bigtts |
√ |
中文 |
|
清爽男大 |
zh_male_qingshuangnanda_mars_bigtts |
√ |
中文 |
|
邻家女孩 |
zh_female_linjianvhai_moon_bigtts |
√ |
中文 |
|
渊博小叔 |
zh_male_yuanboxiaoshu_moon_bigtts |
√ |
中文 |
|
阳光青年 |
zh_male_yangguangqingnian_moon_bigtts |
√ |
中文 |
|
甜美小源 |
zh_female_tianmeixiaoyuan_moon_bigtts |
√ |
中文 |
|
清澈梓梓 |
zh_female_qingchezizi_moon_bigtts |
√ |
中文 |
|
解说小明 |
zh_male_jieshuoxiaoming_moon_bigtts |
√ |
中文 |
|
开朗姐姐 |
zh_female_kailangjiejie_moon_bigtts |
√ |
中文 |
|
邻家男孩 |
zh_male_linjiananhai_moon_bigtts |
√ |
中文 |
|
甜美悦悦 |
zh_female_tianmeiyueyue_moon_bigtts |
√ |
中文 |
|
心灵鸡汤 |
zh_female_xinlingjitang_moon_bigtts |
√ |
中文 |
|
知性温婉 |
ICL_zh_female_zhixingwenwan_tob |
√ |
中文 |
|
暖心体贴 |
ICL_zh_male_nuanxintitie_tob |
√ |
中文 |
|
温柔文雅 |
ICL_zh_female_wenrouwenya_tob |
√ |
中文 |
|
开朗轻快 |
ICL_zh_male_kailangqingkuai_tob |
√ |
中文 |
|
活泼爽朗 |
ICL_zh_male_huoposhuanglang_tob |
√ |
中文 |
|
率真小伙 |
ICL_zh_male_shuaizhenxiaohuo_tob |
√ |
中文 |
|
温柔小哥 |
zh_male_wenrouxiaoge_mars_bigtts |
√ |
中文 |
|
Smith |
en_male_smith_mars_bigtts |
√ |
英式英语 |
|
Anna |
en_female_anna_mars_bigtts |
√ |
英式英语 |
|
Adam |
en_male_adam_mars_bigtts |
√ |
美式英语 |
|
Sarah |
en_female_sarah_mars_bigtts |
√ |
澳洲英语 |
|
Dryw |
en_male_dryw_mars_bigtts |
√ |
澳洲英语 |
|
多语种
音色名称 |
voice_type |
时间戳 |
语种 |
支持的情感 |
かずね(和音)/Javier or Álvaro |
multi_male_jingqiangkanye_moon_bigtts |
√ |
日语、西语 |
|
はるこ(晴子)/Esmeralda |
multi_female_shuangkuaisisi_moon_bigtts |
√ |
日语、西语 |
|
ひろし(広志)/Roberto |
multi_male_wanqudashu_moon_bigtts |
√ |
日语、西语 |
|
あけみ(朱美) |
multi_female_gaolengyujie_moon_bigtts |
√ |
日语 |
|
Amanda |
en_female_amanda_mars_bigtts |
√ |
美式英语 |
|
Jackson |
en_male_jackson_mars_bigtts |
√ |
美式英语 |
|
趣味口音
音色名称 |
voice_type |
时间戳 |
语种 |
支持的情感 |
京腔侃爷/Harmony |
zh_male_jingqiangkanye_moon_bigtts |
√ |
中文-北京口音、英文 |
|
湾湾小何 |
zh_female_wanwanxiaohe_moon_bigtts |
√ |
中文-台湾口音 |
|
湾区大叔 |
zh_female_wanqudashu_moon_bigtts |
√ |
中文-广东口音 |
|
呆萌川妹 |
zh_female_daimengchuanmei_moon_bigtts |
√ |
中文-四川口音 |
|
广州德哥 |
zh_male_guozhoudege_moon_bigtts |
√ |
中文-广东口音 |
|
北京小爷 |
zh_male_beijingxiaoye_moon_bigtts |
√ |
中文-北京口音 |
|
浩宇小哥 |
zh_male_haoyuxiaoge_moon_bigtts |
√ |
中文-青岛口音 |
|
广西远舟 |
zh_male_guangxiyuanzhou_moon_bigtts |
√ |
中文-广西口音 |
|
妹坨洁儿 |
zh_female_meituojieer_moon_bigtts |
√ |
中文-长沙口音 |
|
豫州子轩 |
zh_male_yuzhouzixuan_moon_bigtts |
√ |
中文-河南口音 |
|
角色扮演
音色名称 |
voice_type |
时间戳 |
语种 |
支持的情感 |
奶气萌娃 |
zh_male_naiqimengwa_mars_bigtts |
√ |
中文 |
|
婆婆 |
zh_female_popo_mars_bigtts |
√ |
中文 |
|
高冷御姐 |
zh_female_gaolengyujie_moon_bigtts |
√ |
中文 |
|
傲娇霸总 |
zh_male_aojiaobazong_moon_bigtts |
√ |
中文 |
|
魅力女友 |
zh_female_meilinvyou_moon_bigtts |
√ |
中文 |
|
深夜播客 |
zh_male_shenyeboke_moon_bigtts |
√ |
中文 |
|
柔美女友 |
zh_female_sajiaonvyou_moon_bigtts |
√ |
中文 |
|
撒娇学妹 |
zh_female_yuanqinvyou_moon_bigtts |
√ |
中文 |
|
病弱少女 |
ICL_zh_female_bingruoshaonv_tob |
√ |
中文 |
|
活泼女孩 |
ICL_zh_female_huoponvhai_tob |
√ |
中文 |
|
东方浩然 |
zh_male_dongfanghaoran_moon_bigtts |
√ |
中文 |
|
绿茶小哥 |
ICL_zh_male_lvchaxiaoge_tob |
√ |
中文 |
|
娇弱萝莉 |
ICL_zh_female_jiaoruoluoli_tob |
√ |
中文 |
|
冷淡疏离 |
ICL_zh_male_lengdanshuli_tob |
√ |
中文 |
|
憨厚敦实 |
ICL_zh_male_hanhoudunshi_tob |
√ |
中文 |
|
傲气凌人 |
ICL_zh_male_aiqilingren_tob |
√ |
中文 |
|
活泼刁蛮 |
ICL_zh_female_huopodiaoman_tob |
√ |
中文 |
|
固执病娇 |
ICL_zh_male_guzhibingjiao_tob |
√ |
中文 |
|
撒娇粘人 |
ICL_zh_male_sajiaonianren_tob |
√ |
中文 |
|
傲慢娇声 |
ICL_zh_female_aomanjiaosheng_tob |
√ |
中文 |
|
潇洒随性 |
ICL_zh_male_xiaosasuixing_tob |
√ |
中文 |
|
腹黑公子 |
ICL_zh_male_fuheigongzi_tob |
√ |
中文 |
|
诡异神秘 |
ICL_zh_male_guiyishenmi_tob |
√ |
中文 |
|
儒雅才俊 |
ICL_zh_male_ruyacaijun_tob |
√ |
中文 |
|
病娇白莲 |
ICL_zh_male_bingjiaobailian_tob |
√ |
中文 |
|
正直青年 |
ICL_zh_male_zhengzhiqingnian_tob |
√ |
中文 |
|
娇憨女王 |
ICL_zh_female_jiaohannvwang_tob |
√ |
中文 |
|
病娇萌妹 |
ICL_zh_female_bingjiaomengmei_tob |
√ |
中文 |
|
青涩小生 |
ICL_zh_male_qingsenaigou_tob |
√ |
中文 |
|
纯真学弟 |
ICL_zh_male_chunzhenxuedi_tob |
√ |
中文 |
|
暖心学姐 |
ICL_zh_female_nuanxinxuejie_tob |
√ |
中文 |
|
可爱女生 |
ICL_zh_female_keainvsheng_tob |
√ |
中文 |
|
成熟姐姐 |
ICL_zh_female_chengshujiejie_tob |
√ |
中文 |
|
病娇姐姐 |
ICL_zh_female_bingjiaojiejie_tob |
√ |
中文 |
|
优柔帮主 |
ICL_zh_male_youroubangzhu_tob |
√ |
中文 |
|
优柔公子 |
ICL_zh_male_yourougongzi_tob |
√ |
中文 |
|
妩媚御姐 |
ICL_zh_female_wumeiyujie_tob |
√ |
中文 |
|
调皮公主 |
ICL_zh_female_tiaopigongzhu_tob |
√ |
中文 |
|
傲娇女友 |
ICL_zh_female_aojiaonvyou_tob |
√ |
中文 |
|
贴心男友 |
ICL_zh_male_tiexinnanyou_tob |
√ |
中文 |
|
少年将军 |
ICL_zh_male_shaonianjiangjun_tob |
√ |
中文 |
|
贴心女友 |
ICL_zh_female_tiexinnvyou_tob |
√ |
中文 |
|
病娇哥哥 |
ICL_zh_male_bingjiaogege_tob |
√ |
中文 |
|
学霸男同桌 |
ICL_zh_male_xuebanantongzhuo_tob |
√ |
中文 |
|
幽默叔叔 |
ICL_zh_male_youmoshushu_tob |
√ |
中文 |
|
性感御姐 |
ICL_zh_female_xingganyujie_tob |
√ |
中文 |
|
假小子 |
ICL_zh_female_jiaxiaozi_tob |
√ |
中文 |
|
冷峻上司 |
ICL_zh_male_lengjunshangsi_tob |
√ |
中文 |
|
温柔男同桌 |
ICL_zh_male_wenrounantongzhuo_tob |
√ |
中文 |
|
病娇弟弟 |
ICL_zh_male_bingjiaodidi_tob |
√ |
中文 |
|
幽默大爷 |
ICL_zh_male_youmodaye_tob |
√ |
中文 |
|
傲慢少爷 |
ICL_zh_male_aomanshaoye_tob |
√ |
中文 |
|
神秘法师 |
ICL_zh_male_shenmifashi_tob |
√ |
中文 |
|
视频配音
音色名称 |
voice_type |
时间戳 |
语种 |
支持的情感 |
和蔼奶奶 |
ICL_zh_female_heainainai_tob |
√ |
中文 |
|
邻居阿姨 |
ICL_zh_female_linjuayi_tob |
√ |
中文 |
|
温柔小雅 |
zh_female_wenrouxiaoya_moon_bigtts |
√ |
中文 |
|
天才童声 |
zh_male_tiancaitongsheng_mars_bigtts |
√ |
中文 |
|
猴哥 |
zh_male_sunwukong_mars_bigtts |
√ |
中文 |
|
熊二 |
zh_male_xionger_mars_bigtts |
√ |
中文 |
|
佩奇猪 |
zh_female_peiqi_mars_bigtts |
√ |
中文 |
|
武则天 |
zh_female_wuzetian_mars_bigtts |
√ |
中文 |
|
顾姐 |
zh_female_gujie_mars_bigtts |
√ |
中文 |
|
樱桃丸子 |
zh_female_yingtaowanzi_mars_bigtts |
√ |
中文 |
|
广告解说 |
zh_male_chunhui_mars_bigtts |
√ |
中文 |
|
少儿故事 |
zh_female_shaoergushi_mars_bigtts |
√ |
中文 |
|
四郎 |
zh_male_silang_mars_bigtts |
√ |
中文 |
|
磁性解说男声/Morgan |
zh_male_jieshuonansheng_mars_bigtts |
√ |
中文、美式英语 |
|
鸡汤妹妹/Hope |
zh_female_jitangmeimei_mars_bigtts |
√ |
中文、美式英语 |
|
贴心女声/Candy |
zh_female_tiexinnvsheng_mars_bigtts |
√ |
中文、美式英语 |
|
俏皮女声 |
zh_female_qiaopinvsheng_mars_bigtts |
√ |
中文 |
|
萌丫头/Cutey |
zh_female_mengyatou_mars_bigtts |
√ |
中文、美式英语 |
|
懒音绵宝 |
zh_male_lanxiaoyang_mars_bigtts |
√ |
中文 |
|
亮嗓萌仔 |
zh_male_dongmanhaimian_mars_bigtts |
√ |
中文 |
|
有声阅读
音色名称 |
voice_type |
时间戳 |
语种 |
支持的情感 |
悬疑解说 |
zh_male_changtianyi_mars_bigtts |
√ |
中文 |
|
儒雅青年 |
zh_male_ruyaqingnian_mars_bigtts |
√ |
中文 |
|
霸气青叔 |
zh_male_baqiqingshu_mars_bigtts |
√ |
中文 |
|
擎苍 |
zh_male_qingcang_mars_bigtts |
√ |
中文 |
|
活力小哥 |
zh_male_yangguangqingnian_mars_bigtts |
√ |
中文 |
|
古风少御 |
zh_female_gufengshaoyu_mars_bigtts |
√ |
中文 |
|
温柔淑女 |
zh_female_wenroushunv_mars_bigtts |
√ |
中文 |
|
反卷青年 |
zh_male_fanjuanqingnian_mars_bigtts |
√ |
中文 |
|
注:
- 上述中文音色可支持中英文混合场景。
- 病弱少女、 活泼女孩、和蔼奶奶、邻居阿姨四个音色暂不支持双向流式接口调用。
7.示例代码
package org.example.websocket.tts.demo;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class TtsRequest {
@JSONField(name = "app")
private App app;
@JSONField(name = "user")
private User user;
@JSONField(name = "audio")
private Audio audio;
@JSONField(name = "request")
private Request request;
@Data
@Builder
public static class App {
@JSONField(name = "appid")
private String appid;
@JSONField(name = "token")
private String token; // 目前未生效,使用默认值即可
@JSONField(name = "cluster")
private String cluster;
}
@Data
@Builder
public static class User {
@JSONField(name = "uid")
private String uid;
}
@Data
@Builder
public static class Audio {
@JSONField(name = "voice_type")
private String voiceType;
@JSONField(name = "emotion")
private String emotion;
@JSONField(name = "enable_emotion")
private Boolean enableEmotion;
@JSONField(name = "encoding")
private String encoding;
@JSONField(name = "speed_ratio")
private Double speedRatio;
@JSONField(name = "rate")
private Integer rate;
@JSONField(name = "BitRate")
private Integer BitRate;
@JSONField(name = "explicit_language")
private String explicitLanguage;
@JSONField(name = "context_language")
private String contextLanguage;
@JSONField(name = "loudness_ratio")
private Double loudnessRatio;
@JSONField(name = "volume_ratio")
private Double volumeRatio;
@JSONField(name = "voice")
private String voice;
@JSONField(name = "pitch_ratio")
private Double pitchRatio;
@JSONField(name = "language")
private String language;
}
@Data
@Builder
public static class Request {
@JSONField(name = "reqid")
private String reqid;
@JSONField(name = "text")
private String text;
@JSONField(name = "text_type")
private String textType;
@JSONField(name = "silence_duration")
private Double silenceDuration;
@JSONField(name = "with_timestamp")
private Integer withTimestamp;
@JSONField(name = "operation")
private String operation;
@JSONField(name = "extra_param")
private String extraParam;
}
}
package org.example.websocket.tts;
import com.alibaba.fastjson.JSON;
import lombok.Getter;
import org.example.websocket.tts.demo.TtsRequest;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.framing.CloseFrame;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.math.BigInteger;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class TtsWebsocketDemo {
private static final Logger log = LoggerFactory.getLogger(TtsWebsocketDemo.class);
public static final String API_URL = "";
public static void main(String[] args) throws Exception {
String accessToken = "";
TtsRequest ttsRequest;
ttsRequest = TtsRequest.builder()
.user(TtsRequest.User.builder()
.uid("dadadadwd1e12121rtdawq")
.build())
.audio(TtsRequest.Audio.builder()
.encoding("mp3")
.voiceType("zh_female_qingchezizi_moon_bigtts")
.language("en")
.build())
.request(TtsRequest.Request.builder()
.reqid(UUID.randomUUID().toString())
.operation("query")
.text("我爱中国")
.build())
.build();
String json = JSON.toJSONString(ttsRequest);
log.info("request: {}", json);
HashMap<String, String> authorization = new HashMap<>();
authorization.put("Authorization", "Bearer " + accessToken);
authorization.put("ModelName","MaaS_DB_Speech");
TtsWebsocketClient ttsWebsocketClient = new TtsWebsocketClient(authorization);
byte[] audio = ttsWebsocketClient.submit(ttsRequest);
FileOutputStream fos = new FileOutputStream("test4.mp3");
fos.write(audio);
fos.close();
log.info("TTS done.");
}
public static class TtsWebsocketClient extends WebSocketClient {
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
public TtsWebsocketClient(Map<String, String> authorization) {
super(URI.create(API_URL), authorization);
// super(URI.create(API_URL));
}
public byte[] submit(TtsRequest ttsRequest) throws InterruptedException {
String json = JSON.toJSONString(ttsRequest);
log.info("request: {}", json);
byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8);
byte[] header = {0x11, 0x10, 0x10, 0x00};
ByteBuffer requestByte = ByteBuffer.allocate(8 + jsonBytes.length);
requestByte.put(header).putInt(jsonBytes.length).put(jsonBytes);
this.connectBlocking();
synchronized (this) {
this.send(requestByte.array());
wait();
return this.buffer.toByteArray();
}
}
@Override
public void onMessage(ByteBuffer bytes) {
log.info("received message:" + bytes.remaining() + " bytes");
int protocolVersion = (bytes.get(0) & 0xff) >> 4;
int headerSize = bytes.get(0) & 0x0f;
int messageType = (bytes.get(1) & 0xff) >> 4;
int messageTypeSpecificFlags = bytes.get(1) & 0x0f;
int serializationMethod = (bytes.get(2) & 0xff) >> 4;
int messageCompression = bytes.get(2) & 0x0f;
int reserved = bytes.get(3) & 0xff;
bytes.position(headerSize * 4);
byte[] fourByte = new byte[4];
if (messageType == 11) {
// Audio-only server response
log.info("received audio-only response.");
if (messageTypeSpecificFlags == 0) {
// Ack without audio data
} else {
bytes.get(fourByte, 0, 4);
int sequenceNumber = new BigInteger(fourByte).intValue();
bytes.get(fourByte, 0, 4);
int payloadSize = new BigInteger(fourByte).intValue();
byte[] payload = new byte[payloadSize];
bytes.get(payload, 0, payloadSize);
try {
this.buffer.write(payload);
} catch (IOException e) {
throw new RuntimeException(e);
}
if (sequenceNumber < 0) {
// received the last segment
this.close(CloseFrame.NORMAL, "received all audio data.");
}
}
} else if (messageType == 15) {
// Error message from server
bytes.get(fourByte, 0, 4);
int code = new BigInteger(fourByte).intValue();
bytes.get(fourByte, 0, 4);
int messageSize = new BigInteger(fourByte).intValue();
byte[] messageBytes = new byte[messageSize];
bytes.get(messageBytes, 0, messageSize);
String message = new String(messageBytes, StandardCharsets.UTF_8);
throw new TtsException(code, message);
} else {
log.warn("Received unknown response message type: {}", messageType);
}
}
@Override
public void onOpen(ServerHandshake serverHandshake) {
log.info("opened connection");
}
@Override
public void onMessage(String message) {
log.info("received message: " + message);
}
@Override
public void onClose(int code, String reason, boolean remote) {
log.info("Connection closed by {}, Code: {}, Reason: {}", (remote ? "remote" : "us"), code, reason);
synchronized (this) {
notify();
}
}
@Override
public void onError(Exception e) {
close(CloseFrame.NORMAL, e.toString());
}
}
@Getter
public static class TtsException extends RuntimeException {
private final int code;
private final String message;
public TtsException(int code, String message) {
super("code=" + code + ", message=" + message);
this.code = code;
this.message = message;
}
}
}