API Path
/aipaas/voice/v1/tts/synthesis8k
请求协议
WS
建立连接时的请求参数(websocket open) :
请求头部 :
| 头部标签 | 必填 | 说明 | 类型 | 数据字典 | 限制 | 头部内容 | 示例 |
|---|---|---|---|---|---|---|---|
| Content-Type | 是 | application/json | [string] | application/json | application/json | ||
| X-APP-ID | 是 | 控制台-应用管理-创建应用-AppID | [string] | ||||
| Device-Uuid | 否 | 设备管理-设备uuid | [string] | ||||
| Authorization | 是 | 鉴权信息 | [string] |
请求参数 Json:
| 参数名 | 说明 | 必填 | 类型 | 数据字典 | 限制 | 示例 |
|---|---|---|---|---|---|---|
| req_id | 请求ID,记录该值便于排查问题 | 是 | [string] | |||
| text | 待合成的文本,需要为 UTF-8 编码 | 是 | [string] | |||
| format | 音频编码格式,支持 PCM 格式,默认值:PCM | 否 | [string] | |||
| sample_ rate | 音频采样率,支持 8000 Hz,默认值:8000 | 否 | [int] | |||
| voice | 说话人,默认值:yixiaoling,yixiaoke,yixiaochao,yixiaotong,yixiaoxuan,yixiaotian,yixiaoluo,yixiaohui,yixiaowei, yixiaoliang,yixiaoshen,yixiaojing,yixiaorou,yixiaobei | 否 | [string] | |||
| volume | 音量,取值范围:[0, 100],默认值:50 | 否 | [int] | |||
| speech_ rate | 语速,取值范围:[0.5, 2.0],默认值:1.0 | 否 | [float] | |||
| pitch | 语调,取值范围:[0.5, 2.0],默认值:1.0 | 否 | [float] |
返回结果
> 成功 (200)
> Json
> Object
| 参数名 | 说明 | 必填 | 类型 | 数据字典 | 限制 | 示例 |
|---|---|---|---|---|---|---|
| status | 状态码 | 是 | [int] | |||
| status_msg | 状态说明 | 是 | [string] | |||
| sid | 会话 id,用于记录本次会话 | 否 | [string] | |||
| result | 合成结果 | 否 | [object] | |||
| result>>audio | 合成音频数据,经过 base64 编码 | 否 | [string] | |||
| result>>audio_len | 合成音频长度,单位:ms | 否 | [int] | |||
| result>>is_end | 标志位。true:最后一个合成片段;false:中间合成片段 | 否 | [boolean] | |||
| result>>phn_seq_len | 合成音频音素序列长度 | 否 | [int] | |||
| result>>phn_id_seq | 合成音频音素 ID 序列 | 否 | [array] | |||
| result>>phn_name_seq | 合成音频音素名称序列 | 否 | [array] | |||
| result>>phn_dur_seq | 合成音频音素持续时间序列 | 否 | [array] |
流式语音合成提供将输入文本合成为语音二进制数据的功能。支持输出格式:PCM 编码;支持设置采样率:8000 Hz;支持设置语速、音量;支持设置多种说话人;支持一次性合成 500 字符以内的文字,其中 1 个汉字、1 个英文字母、1 个标点或 1 个句子中间空格均算作 1 个字符,超过 500 个字符的内容将会截断;仅支持采用 UTF-8 编码的文本输入。
服务接口调用时需要严格遵循服务鉴权规则,服务调用鉴权规则请参见:开发指南 - 接口签名认证。
| 返回码 | 解释 | 说明 | 解决方法 |
|---|---|---|---|
| 10301 | Required parameter miss | 参数错误 | 请检查参数是否正确 |
| 10302 | Too many requests | 并发请求过多 | 联系商务,增加并发 |
| 10304 | Parse request body fail | 请求格式错误 | 查看请求的 URL body 格式是否正确,参考接口文档 |
| 10503 | Server connection time out | 服务连接超时 | 联系技术人员 |
| 10903 | Synthesis failed | 合成失败 | 联系技术人员 |
| 10000 | Success | 成功 | 执行下一步操作 |
通用状态码请参考【状态码】中的【网关认证】
{
"req_id": "test001",
"text": "yourText"
}
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import com.alibaba.fastjson.JSONObject;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* 为保证示例可以正常运行,请确认maven中是否存在以下依赖:
*
* org.java-websocket
* Java-WebSocket
* 1.5.4
*
*
* com.alibaba
* fastjson
* 1.2.83
*
*/
public class WebSocketExample extends WebSocketClient {
private CountDownLatch connectedLatch = new CountDownLatch(1);
private boolean isConnected = false;
// 构造函数 - 使用 Fastjson 1.x 的 Map 类型
public WebSocketExample(URI serverUri, Map headers) {
super(serverUri, headers);
}
public static void main(String[] args) {
try {
// 创建WebSocket客户端
URI uri = new URI("算法调用地址"); // 替换为实际的 WebSocket 地址
Map headers = new HashMap();
// 调用鉴权
headers.put("X-APP-ID", "yourAppId");
headers.put("Authorization", "yourAuthorization");
headers.put("Content-Type", "application/json");
WebSocketExample client = new WebSocketExample(uri, headers);
// 添加连接监听
System.out.println("正在连接 WebSocket...");
client.connect();
// 等待连接建立(使用 CountDownLatch 更可靠)
if (client.connectedLatch.await(10, TimeUnit.SECONDS)) {
System.out.println("连接成功,开始通信...");
// 发送消息
client.sendMessage();
// 保持连接运行,等待服务器响应
System.out.println("等待服务器响应,按 Ctrl+C 退出...");
// 保持主线程运行,而不是立即关闭
Thread.sleep(30000); // 等待30秒,根据实际需求调整
} else {
System.out.println("连接超时");
}
// 关闭连接
System.out.println("关闭连接...");
client.close();
} catch (URISyntaxException e) {
System.err.println("URI 格式错误: " + e.getMessage());
} catch (InterruptedException e) {
System.err.println("线程被中断: " + e.getMessage());
Thread.currentThread().interrupt();
} catch (Exception e) {
System.err.println("WebSocket 错误: " + e.getMessage());
e.printStackTrace();
}
}
@Override
public void onOpen(ServerHandshake handshakedata) {
System.out.println("WebSocket 连接已建立");
System.out.println("HTTP 状态: " + handshakedata.getHttpStatus());
System.out.println("状态描述: " + handshakedata.getHttpStatusMessage());
this.isConnected = true;
connectedLatch.countDown(); // 通知主线程连接已建立
}
private void sendMessage() {
try {
// 初始化连接消息 - 使用 Fastjson 1.x 的 JSONObject
JSONObject initSend = new JSONObject();
initSend.put("req_id", "test001");
initSend.put("text", "yourText");
String message = initSend.toJSONString();
System.out.println("发送消息: " + message);
send(message);
} catch (Exception e) {
System.err.println("发送消息失败: " + e.getMessage());
e.printStackTrace();
}
}
@Override
public void onMessage(String message) {
System.out.println("收到消息: " + message);
try {
// 解析服务器响应 - 使用 Fastjson 1.x 的 parseObject 方法
JSONObject response = JSONObject.parseObject(message);
// 根据响应类型处理
handleServerResponse(response);
} catch (Exception e) {
// 如果消息不是 JSON,直接输出
System.out.println("收到文本消息: " + message);
}
}
private void handleServerResponse(JSONObject response) {
if (response == null) return;
String type = response.getString("type");
String reqId = response.getString("req_id");
String status = response.getString("status");
System.out.println("处理响应 - 类型: " + type + ", 请求ID: " + reqId + ", 状态: " + status);
// 根据不同的消息类型进行处理
if ("result".equals(type)) {
handleResultMessage(response);
} else if ("error".equals(type)) {
handleErrorMessage(response);
} else if ("progress".equals(type)) {
handleProgressMessage(response);
} else if ("end".equals(type)) {
handleEndMessage(response);
} else {
System.out.println("未知消息类型: " + type);
}
}
private void handleResultMessage(JSONObject response) {
// 处理算法结果
Object result = response.get("result");
System.out.println("收到算法结果: " + result);
}
private void handleErrorMessage(JSONObject response) {
// 处理错误消息
String errorCode = response.getString("error_code");
String errorMsg = response.getString("error_message");
System.err.println("算法错误 [" + errorCode + "]: " + errorMsg);
}
private void handleProgressMessage(JSONObject response) {
// 处理进度消息
Integer progress = response.getInteger("progress");
String status = response.getString("status");
System.out.println("处理进度: " + progress + "%, 状态: " + status);
}
private void handleEndMessage(JSONObject response) {
// 处理结束消息
System.out.println(" 算法处理完成");
// 可以在这里添加清理逻辑或发送确认消息
try {
JSONObject ack = new JSONObject();
ack.put("type", "ack");
ack.put("req_id", response.getString("req_id"));
ack.put("status", "received");
send(ack.toJSONString());
System.out.println("发送确认消息");
} catch (Exception e) {
System.err.println("发送确认消息失败: " + e.getMessage());
}
}
@Override
public void onClose(int code, String reason, boolean remote) {
System.out.println(" WebSocket 连接关闭");
System.out.println(" 关闭代码: " + code);
System.out.println(" 关闭原因: " + reason);
System.out.println(" 是否远程关闭: " + remote);
this.isConnected = false;
}
@Override
public void onError(Exception ex) {
System.err.println(" WebSocket 错误: " + ex.getMessage());
ex.printStackTrace();
}
// 辅助方法
public boolean isConnected() {
return isConnected && super.isOpen();
}
}
import argparse
import asyncio
import websockets
import json
import base64
import logging
import time
# 配置日志,设置日志级别为INFO,并指定日志格式
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger()
async def uws_call(args):
# 获取命令行参数中的URL
url = args.url
# 记录开始时间
start_time = time.time()
logger.info(f"开始建立websocket连接,获取当前时间:{start_time}")
header = {
"Content-Type": "application/json",
'X-APP-ID': args.X_APP_ID,
'Authorization': args.Authorization
}
# 建立WebSocket连接
async with websockets.connect(url, extra_headers=header) as websocket:
logger.info("=================================请求参数start_json===============================")
# 构建请求参数
start_json = {
'req_id': 'test001',
'text': 'yourText'
}
logger.info(f"请求参数:{start_json}")
# 发送请求参数
await websocket.send(json.dumps(start_json))
try:
# 接收响应
resp_str = await websocket.recv()
resp_data = json.loads(resp_str)
if resp_data['status'] == 10000:
logger.info('Received initial response: %s', resp_str)
# 记录连接建立(即收到第一个响应)的时间
connection_established_time = time.time()
logger.info('WebSocket connection established in %.2f seconds',
connection_established_time - start_time)
is_end = False
# 打开文件以写入音频数据
with open("test.pcm", "wb") as f:
while not is_end:
# 接收音频数据
resp_audio_str = await websocket.recv()
resp_audio_data = json.loads(resp_audio_str)
if resp_audio_data['status'] != 10000:
logger.error('Received non-success status: %s', resp_audio_data)
break
if 'result' in resp_audio_data:
synth_info = resp_audio_data['result']
logger.info('Received synthesis info: %s', synth_info)
# 解码音频数据并写入文件
audio_wav = base64.b64decode(synth_info['audio'])
f.write(audio_wav)
is_end = synth_info['is_end']
else:
logger.error('No result in response: %s', resp_audio_data)
break
# 计算整个交互的耗时(从尝试连接到接收完所有消息)
total_duration = time.time() - start_time
logger.info('Total interaction duration: %.2f seconds', total_duration)
except websockets.exceptions.ConnectionClosed as e:
logger.error('WebSocket connection closed: %s', e)
# 如果连接关闭了,我们仍然可以记录到目前为止的耗时
logger.info('Duration until connection closed: %.2f seconds', time.time() - start_time)
except Exception as e:
logger.error('An error occurred: %s', e)
# 如果发生错误,我们同样记录到目前为止的耗时
logger.info('Duration until error occurred: %.2f seconds', time.time() - start_time)
finally:
# 关闭WebSocket连接
await websocket.close()
def main(args):
# 运行异步函数
asyncio.get_event_loop().run_until_complete(uws_call(args))
if __name__ == '__main__':
# 解析命令行参数
parser = argparse.ArgumentParser()
parser.add_argument('--url', type=str, default='算法调用地址')
parser.add_argument('--X_APP_ID', type=str, default='yourAppId')
parser.add_argument('--Device_Uuid', type=str, default='yourDeviceUuid')
parser.add_argument('--Authorization', type=str, default='yourAuthorization')
args = parser.parse_args()
# 调用主函数
main(args)