语音音色融合(WebSocket) | 大装置帮助中心
跳到主要内容

语音合成-音色融合WebSocket

接口描述(Description)

该 API 提供基于文本到语音(Text-to-Speech, TTS)的同步语音合成功能。


请求地址(Request URL)

[POST] wss://api.sensenova.cn/v1/audio/ws/speech_fusion

请求头(Request Header)

在请求头中,添加 Authorization 字段,生成 API Key,如下所示:

HEADERS = {
"Authorization": "Bearer {API_KEY}" //$API_KEY 在大装置万象模型平台ModelStudio中服务管理获取
}

接口调用时序图

wss时序图

开始事件(task_start)

请求参数

参数名类型是否必填默认值说明
eventstring在开始请求时使用task_start,在持续进行请求时使用task_continue,结束请求时使用task_finish
modelstring模型名称: 用于指定语音合成所采用的模型, 当前为 SenseNova-Audio-Fusion-0603。
voice_settingobject声音设置
audio_settingobject音频格式设置
timbre_weightsobject融合音色权重 (音色名称: 权重值): 用于自定义混合多种音色的合成效果。各音色的权重值总和建议为 1.0, voice 参数指定的主音色必须包含在该权重列表中。支持最多不超过 4 款音色融合。
  • voice_setting 参数如下:
参数名类型是否必填默认值说明
voicestring主音色名称: 用于指定语音合成时的主要音色, 详见音色列表, 在使用融合音色功能时, 该音色也必须包含在 timbre_weights 中。
speedfloat1语速: 用于设置语音的播放速度, 取值范围为 [0.5, 2.0]。其中, 1.0 表示正常语速, 数值越小语速越慢, 数值越大语速越快。
volumefloat1音量: 用于调节合成语音的响度, 取值范围为 (0, 10], 值越大音量越高。
pitchint0音调: 用于控制合成语音的音高, 取值范围为整数 [-12, 12]。其中, 0 表示保持原始音调, 正值提高音调, 负值降低音调。
  • audio_setting 参数如下:
参数名类型是否必填默认值说明
sample_rateint32000音频采样率, 取值范围 [8000, 16000, 22050, 24000, 32000, 44100]
channelint2音频声道, 支持单声道 1, 双声道 2
bitrateint128000音频码率, 支持 MP3, 取值范围 [32000, 64000, 128000, 256000]
response_formatstringmp3输出结果格式: 可选值 mp3、wav、pcm。
  • timbre_weights 参数如下:
参数名类型是否必填默认值说明
voiceweight融合音色
weightfloat(0, 1.0]融合音色权重

timbre_weights: 融合音色权重为空或不存在,默认是单音色。否则是融合音色。

  • voice 可选音色如下:
Voice ID名称是否支持融合
child_reqing热情孩童
man_zhengqi正气中年
man_weiyan威严霸总
guy_qingshuang清爽帅哥
guy_wenrun温润暖男
male_shenqing深情男友
male_miantian腼腆男友
woman_daihuo带货女神
female_chunzhen纯真少女
female_jiaomei娇媚女友
woman_fengyun风韵少妇
man_qiangyu强欲霸总
guy_shizun清冷师尊
guy_nangong挚爱男攻
female_taimei甜甜台妹
guy_guimi男性闺蜜
female_shumei熟媚女神
man_nuanren暖人青叔
guy_naigou1贴心奶狗
guy_xingui冷御新贵
female_sajiao撒娇甜妹
female_diantai电台女声
female_diantai_b娇俏小妹
female_jiejie明魅御姐
female_jiejie_a爱欲女王
female_jiejie_b柔情女王
girl_banxia娇怜软妹
girl_banxia_a破碎少女
man_cucao冷面硬汉
guy_xingui_b深情病娇
guy_qiangai强爱病娇
guy_shengse生涩奶狗
female_jiaonv_a羞婉娇女
female_ruanmei_a俏萌软妹
oldman_zhangzhe威严长者
woman_xiuse羞涩御姐

响应参数(Response Body)

connected_success:初次请求接口时,表示连接建立成功,此时会话未开始,无session_id

参数名类型说明
eventstring请求事件类型, 成功返回 connected_success
trace_idstring本次请求的唯一标识, 用于定位请求

task_started: 标志任务已成功开始

参数名类型说明
eventstring请求事件类型, 成功返回 task_started, 失败返回task_failed
trace_idstring本次请求的唯一标识, 用于定位请求
session_idstring本次流式会话的唯一标识,仅在服务端返回task_starteds时该值不为空

继续事件(task_continued)

请求参数

参数名类型是否必填默认值说明
eventstring在开始请求时使用task_start,在持续进行请求时使用task_continue,结束请求时使用task_finish
inputstring合成文本内容: 待转换为语音的文本信息, 支持中文及英文内容输入。

响应参数(Response Body)

参数名类型说明
eventstring请求事件类型
dataobject返回的音频数据,仅在is_final为false的数据包中包含音频数据
trace_idstring本次请求的唯一标识, 用于定位请求
session_idstring本次流式会话的唯一标识,仅在服务端返回task_starteds时该值不为空
is_finalbool是否结束
extra_inoobject扩展信息,is_final为true的消息包含usage信息
  • data 参数如下:
参数名类型说明
audiostring音频数据内容或者音频文件 url, 由 output_format 决定
statusint当前音频流状态: 1 表示合成中, 2 表示合成结束
  • extra_info 参数如下:
参数名类型说明
lengthint音频时长, 单位毫秒
sizeint音频文件大小
sample_rateint音频采样率
bitratefloat音频码率, 支持 MP3
channelint音频声道, 支持单声道 1, 双声道 2
response_formatstring输出结果格式: 可选值 mp3、wav、pcm
usage_charactersint计费字符数
word_countint已发音的字符数

结束事件(task_finish)

请求参数

参数名类型是否必填默认值说明
eventstring在开始请求时使用task_start,在持续进行请求时使用task_continue,结束请求时使用task_finish

响应参数(Response Body)

task_finished: 标志任务已结束

参数名类型说明
eventstring请求事件类型
trace_idstring本次请求的唯一标识, 用于定位请求
session_idstring本次流式会话的唯一标识,仅在服务端返回task_starteds时该值不为空

当最后一次收到服务端返回结果后超过 120s 没有发送新事件时 webSocket 连接自动断开。

task_failed: 标志任务失败

参数名类型说明
eventstring请求事件类型
trace_idstring本次请求的唯一标识, 用于定位请求
session_idstring本次流式会话的唯一标识,仅在服务端返回task_starteds时该值不为空
error_msgstring失败message信息

请求示例(Request Example)

Python 示例


import websocket
import json
import base64
import threading
import time

class SpeechFusionClient:
def __init__(self, api_key):
self.api_key = api_key
self.ws_url = "wss://api.sensenova.cn/v1/audio/ws/speech_fusion"
self.ws = None
self.session_id = None
self.trace_id = None

def on_message(self, ws, message):
"""处理服务器返回的消息"""
try:
data = json.loads(message)
event_type = data.get("event")

print(f"收到消息 - 事件类型: {event_type}")
print(f"Trace ID: {data.get('trace_id')}")

if event_type == "task_started":
self.session_id = data.get("session_id")
print(f"会话建立成功,Session ID: {self.session_id}")

elif event_type == "audio_data":
# 处理音频数据
audio_data = data.get("data", {})
audio_content = audio_data.get("audio")
status = audio_data.get("status")

if audio_content and status == 1:
# 解码base64音频数据(如果是base64格式)
try:
audio_bytes = base64.b64decode(audio_content)
print(f"收到音频数据,长度: {len(audio_bytes)} 字节")
# 这里可以保存或处理音频数据
# with open("output_audio.mp3", "wb") as f:
# f.write(audio_bytes)
except:
print(f"收到音频URL或数据: {audio_content}")

if data.get("is_final"):
extra_info = data.get("extra_info", {})
print(f"合成完成 - 时长: {extra_info.get('length')}ms, 字符数: {extra_info.get('word_count')}")

elif event_type == "task_failed":
print(f"任务失败: {data}")

except json.JSONDecodeError as e:
print(f"JSON解析错误: {e}")
print(f"原始消息: {message}")

def on_error(self, ws, error):
"""处理错误"""
print(f"WebSocket错误: {error}")

def on_close(self, ws, close_status_code, close_msg):
"""连接关闭"""
print("WebSocket连接已关闭")

def on_open(self, ws):
"""连接建立后发送开始事件"""
print("WebSocket连接已建立")
self.send_start_event()

def send_start_event(self):
"""发送开始事件"""
start_data = {
"event": "task_start",
"model": "SenseNova-Audio-Fusion-0603",
"voice_setting": {
"voice": "female_jiejie",
"speed": 1.0,
"volume": 1.0,
"pitch": 0
},
"audio_setting": {
"sample_rate": 32000,
"channel": 2,
"bitrate": 128000,
"response_format": "mp3"
},
"timbre_weights": {
"female_jiejie": 0.7,
"female_diantai": 0.3
}
}

self.send_message(start_data)

def send_continue_event(self, text):
"""发送继续事件(文本合成)"""
continue_data = {
"event": "task_continue",
"input": text
}
self.send_message(continue_data)

def send_finish_event(self):
"""发送结束事件"""
finish_data = {
"event": "task_finish"
}
self.send_message(finish_data)

def send_message(self, data):
"""发送消息到服务器"""
if self.ws and self.ws.sock and self.ws.sock.connected:
message = json.dumps(data)
self.ws.send(message)
print(f"已发送: {data['event']}")
else:
print("WebSocket未连接")

def connect(self):
"""建立WebSocket连接"""
headers = {
"Authorization": f"Bearer {self.api_key}"
}

self.ws = websocket.WebSocketApp(
self.ws_url,
header=headers,
on_message=self.on_message,
on_error=self.on_error,
on_close=self.on_close,
on_open=self.on_open
)

# 运行WebSocket客户端
self.ws.run_forever()

def synthesize_speech(self, text):
"""合成语音的完整流程"""
def run_synthesis():
# 等待连接建立
time.sleep(2)

# 发送文本进行合成
self.send_continue_event(text)

# 等待合成完成
time.sleep(5)

# 发送结束事件
self.send_finish_event()

# 等待一会后关闭连接
time.sleep(2)
self.ws.close()

# 在新线程中运行合成流程
synthesis_thread = threading.Thread(target=run_synthesis)
synthesis_thread.start()

# 使用示例
if __name__ == "__main__":
# 替换为您的实际API Key
API_KEY = "your_api_key_here"

# 创建客户端实例
client = SpeechFusionClient(API_KEY)

# 要合成的文本
text_to_synthesize = "大家好,这是一个语音合成测试示例。欢迎使用语音音色融合功能。"

try:
# 连接并合成语音
client.connect()

# 或者使用完整的合成流程
# client.synthesize_speech(text_to_synthesize)

except KeyboardInterrupt:
print("用户中断程序")
except Exception as e:
print(f"程序错误: {e}")