365bet注册开户- 首页

logo
产品简介 产品简介
基本概念 基本概念
平台新手指引 平台新手指引
计价模式 计价模式
开发者文档下拉
开放平台计价
定制服务计价
获取访问令牌 获取访问令牌
语音合成 语音合成
开发者文档下拉
接口说明
发音人列表
在线合成 开发者文档下拉
Android SDK
iOS SDK
C++(Linux) SDK
RESTful API
Websocket API
长文本语音合成API
离线合成 开发者文档下拉
离线合成 Android SDK
离线合成 iOS SDK
XML标签
语音识别 语音识别
开发者文档下拉
音频格式说明
一句话识别 开发者文档下拉
RESTful API
Websocket API
Android SDK
iOS SDK
实时长语音识别 开发者文档下拉
Websocket API
Android SDK
iOS SDK
录音文件识别 开发者文档下拉
RESTful API
声音复刻 声音复刻
开发者文档下拉
定制模型 开发者文档下拉
RESTful API
Android SDK
iOS SDK
定制声音合成 开发者文档下拉
RESTful API
声音转换 声音转换
开发者文档下拉
发音人列表
Websocket API
Android SDK
iOS SDK
离线声音转换 离线声音转换
开发者文档下拉
发音人列表
Android SDK
iOS SDK
声纹识别 声纹识别
开发者文档下拉
RESTful API
协议规则 协议规则
开发者文档下拉
平台服务协议
平台通用规则
法律声明及隐私政策
服务等级协议SLA
常见问题 常见问题
开发者文档下拉
语音合成
语音识别

在线合成Websocket API

功能介绍

语音合成Webcocket API满足用户希望尽快获得合成音频的场景,输入文本后音频以流的形式持续返回直至最后一帧成功返回。

参数设置

  • 支持设置合成音频的格式: PCM
  • 支持设置合成音频的采样率: 8000Hz,16000Hz
  • 支持设置多种发音人
  • 支持设置音量、语速、语调
  • 支持返回时间戳信息
  • 支持设置多种语言:中文(zh),英文(eng),粤语(cat),四川话(sch)

websocket协议简介

  • WebSocket ( https://tools.ietf.org/html/rfc6455)是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。
  • WebSocket和HTTP一样都是基于TCP的应用层协议。客户端开始建立WebSocket连接时要发送一个header标记了 Upgrade的HTTP请求,表示请求协议升级。所以服务器端做出响应是直接在现有的HTTP服务器软件和现有的端口上实现WebSocket协议,然后再回一个状态码为101的HTTP响应完成握手。握手完成后收发数据跟HTTP就没有关系了。
  • 握手部分的设计目的就是兼容现有的基于HTTP的服务端组件(web服务器软件)或者中间件(代理服务器软件)。这样一个端口就可以同时接受普通的HTTP请求或则WebSocket请求了。为了这个目的,WebSocket客户端的握手是一个 HTTP升级版的请求(HTTP Upgrade request)
  • 客户端发送一个请求
  • GET /wss HTTP/1.1
    Host: openapi.data-baker.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
    Sec-WebSocket-Protocol: chat, superchat
    Sec-WebSocket-Version: 13
    Origin: http://example.com
  • 服务端响应
  • HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
    Sec-WebSocket-Protocol: chat

使用方法

1. 创建账号和应用,详见平台新手指引,通过标贝开放平台/应用/服务获取client_id,client_secret

2. 发送请求获取access_token,详见获取访问令牌

3. 建立websocket连接

4. 实时发送需要合成的文字,具体参数详见 请求参数

5. 接收返回结果,具体参数定义详见响应结果说明。

6. 关闭连接。

服务地址

访问类型 说明 URL Host
外网访问 支持全部音色及语言 wss://openapi.data-baker.com/wss openapi.data-baker.com

交互流程

请求参数

参数名称 类型 是否必填项 说明
access_token string yes 通过client_id,client_secret调用授权服务获得见 获取访问令牌
version string yes 版本信息,目前为1.0
tts_params jsonObject,且内部的字段均为string数据类型,其中text字段是必需字段且需进行base64编码 yes tts相关参数

tts相关参数如下:

参数名称 类型 是否必填项 说明
text string 合成的文本,使用UTF-8编码,一次请求最多不超过300个汉字,且需进行base64编码。
domain string 应用所属领域如导航、客服等,以数字进行编码,目前值固定为1
language string 合成请求文本的语言
ZH(中文和中英混)
ENG(纯英文,中文部分不会合成)
CAT(粤语)
SCH(四川话)
speed string 设置播放的语速,在0~9之间(支持浮点值),默认值为5
volume string 设置语音的音量,在0~9之间(只支持整型值),默认值为5
pitch string 设置语音的音调,在0~9之间,(支持浮点值),默认值为5
audiotype string 音频种类:
audiotype = 4,返回16K采样率的pcm格式,默认值
audiotype = 5,返回8K采样率的pcm格式
voice_name string 发音人选择,如“Jiaojiao", 详见 发音人列表
spectrum string 高频频谱:取值范围1~20; 默认值为1,不调整频谱;
1代表不调整频谱;
1以上的值代表高频能量增加幅度, 值越大声音的高频部分增强越多,听起来更亮和尖细
spectrum_8k string 低频部分频谱:取值范围0~20;默认值为0,仅针对8K音频频谱的调整。 组合形式只有以下几种:
audiotype=5&spectrum_8k=xx
audiotype=6&rate=1&spectrum_8k=xx
audiotype=7&spectrum_8k=xx
audiotype=8&spectrum_8k=xx
interval string 取值0/1,interval=1时返回音子时间戳信息。

请求示例

{
    "access_token":" your_access_token",
    "version":"1.0",
    "tts_params":{
       "domain":"1",
       "interval":"1",
       "language":"zh",
       "voice_name":"Jiaojiao",
       "text":"5qCH6LSd56eR5oqA77yM5LiT5rOo5LqO5pm66IO96K+t6Z+z5oqA5pyv"//"标贝科技,专注于智能语音技术"
    }
}

Python示例代码

代码地址:Github

Python3示例:

import argparse
import json
import base64
from threading import Thread
import requests
import websocket
import wave


#websocket客户端
class Client:
    def __init__(self, data, uri):
        self.data = data
        self.uri = uri
        self.audio_data = b""

    #建立连接
    def connect(self):
        ws_app = websocket.WebSocketApp(uri,
                                        on_open=self.on_open,
                                        on_message=self.on_message,
                                        on_error=self.on_error,
                                        on_close=self.on_close)
        ws_app.run_forever()

    # 建立连接后发送消息
    def on_open(self, ws):
        print("sending..")
        def run(*args):
            ws.send(self.data)

        Thread(target=run).start()

    # 接收消息
    def on_message(self, ws, message):
        code = json.loads(message).get("code")
        if code != 90000:
            # 打印接口错误
            print(message)
        else:
            self.audio_data += base64.b64decode(bytes(json.loads(message).get("data")["audio_data"], encoding='utf-8'))
            if json.loads(message).get("data")["end_flag"] == 1:
                with wave.open('test.wav', 'wb') as wavfile:
                    wavfile.setparams((1, 2, 16000, 0, 'NONE', 'NONE'))
                    wavfile.writeframes(self.audio_data)
                ws.close()
                print("task finished successfully")

    # 打印错误
    def on_error(self, ws, error):
        print("error: ", str(error))

    # 关闭连接
    def on_close(ws):
        print("client closed.")


# 准备数据
def prepare_data(args, access_token):

    # 填写Header信息
    audiotype= args.audiotype
    voice_name = args.voice_name

    text = args.text
    # 单次调用不超过300个汉字
    if len(text) > 300:
        raise Exception("Text is too long. The maximum length of chinese character is 300")
    text_bytes = text.encode(encoding='UTF-8')
    text = str(base64.b64encode(text_bytes), encoding='UTF-8')
    tts_params = {"language": "ZH", "voice_name": voice_name, "audiotype": audiotype, "domain": "1", "text": text}

    data = {"access_token": access_token, "version": "1.0", "tts_params": tts_params}
    data = json.dumps(data)

    return data


# 获取命令行输入参数
def get_args():
    text = "今天天气不错哦!"
    parser = argparse.ArgumentParser(description='tts')
    parser.add_argument('-client_secret', type=str, required=True)
    parser.add_argument('-client_id', type=str, required=True)
    parser.add_argument('-file_save_path', type=str, required=True)
    parser.add_argument('--text', type=str, default=text)
    parser.add_argument('--audiotype', type=str, default='4')
    parser.add_argument('--voice_name', type=str, default='Lingling')
    args = parser.parse_args()

    return args


# 获取access_token用于鉴权
def get_access_token(client_secret, client_id):
    grant_type = "client_credentials"
    url = "https://openapi.data-baker.com/oauth/2.0/token?grant_type={}&client_secret={}&client_id={}" \
        .format(grant_type, client_secret, client_id)

    try:
        response = requests.post(url)
        response.raise_for_status()
    except Exception as e:
        print(response.text)
        raise Exception
    else:
        access_token = json.loads(response.text).get('access_token')
        return access_token


if __name__ == '__main__':
    try:
        args = get_args()

        # 获取access_token
        client_secret = args.client_secret
        client_id = args.client_id
        access_token = get_access_token(client_secret, client_id)

        # 准备数据
        data = prepare_data(args, access_token)

        uri = "wss://openapi.data-baker.com/wss"
        # 建立Websocket连接
        client = Client(data, uri)
        client.connect()

        print('end')
    except Exception as e:
        print(e)
      

命令行执行

python online_tts.py -client_secret=您的client_secret -client_id=您的client_id -file_save_path=test.wav --text=欢迎使用标贝开放平台

JAVA示例代码

package com.databaker.web.tts;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;

/**
 * 在线合成WebSocket API接口调用示例
 * 附:在线合成Websocket API文档 【/specs/file/tts_api_websocket】
 * 注意:
 * 1.本demo展示了如何保存音频流到本地文件
 * 2.本demo仅完成基本的接口调用,失败重试、token过期重新获取、日志打印等优化工作需要开发者自行完成
 *
 * @author data-baker
 */
public class TtsWebSocketDemo extends WebSocketListener {
    /**
     * 授权:需要在开放平台获取【https://ai.data-baker.com/】
     */
    private static final String clientId = "YOUR_CLIENT_ID";
    private static final String clientSecret = "YOUR_CLIENT_SECRET";

    /**
     * 获取token的地址信息
     */
    public static String tokenUrl = "https://openapi.data-baker.com/oauth/2.0/token?grant_type=client_credentials&client_secret=%s&client_id=%s";

    private static final String hostUrl = "wss://openapi.data-baker.com/wss";

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss.SSS");

    /**
     * 开始时间
     */
    private static ThreadLocal timeBegin = ThreadLocal.withInitial(() -> new Date());

    /**
     * 结束时间
     */
    private static ThreadLocal timeEnd = ThreadLocal.withInitial(() -> new Date());

    private Date startTime;

    private String accessToken = getAccessToken();

    /**
     * utf-8编码,不超过300个汉字(即900字节)
     */
    private static Integer MAX_BYTE_LENGTH = 900;

    /**
     * 文本
     */
    private String text = "感谢使用标贝科技语音合成服务,祝您使用愉快!";
    /**
     * 发音人
     */
    private String voiceName = "Tiantian";

    /**
     * 保存结果文件的路径,开发者需要根据实际路径调整
     */
    private File resultFile;

    public TtsWebSocketDemo(File resultFile) {
        this.resultFile = resultFile;
    }

    public TtsWebSocketDemo(String text, File resultFile) {
        this.text = text;
        this.resultFile = resultFile;
    }

    public TtsWebSocketDemo(String text, String voiceName, File resultFile) {
        this.text = text;
        this.voiceName = voiceName;
        this.resultFile = resultFile;
    }

    @Override
    public void onOpen(WebSocket webSocket, Response response) {
        super.onOpen(webSocket, response);
        this.startTime = timeBegin.get();
        new Thread(() -> {
            //连接成功,开始发送数据
            //发送文本
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("access_token", accessToken);
            jsonObject.put("version", "1.0");
            //填充asr_params
            JSONObject ttsParams = new JSONObject();
            //domain非必填
            ttsParams.put("domain", "1");
            ttsParams.put("interval", "0");
            ttsParams.put("language", "ZH");
            ttsParams.put("voice_name", voiceName);

            ttsParams.put("text", Base64.getEncoder().encodeToString(text.getBytes(Charset.forName("UTF-8"))));
            jsonObject.put("tts_params", ttsParams);
            System.out.println("dataSent:" + text);
            webSocket.send(jsonObject.toString());

            System.out.println("all data is send");
        }).start();
    }

    @Override
    public void onMessage(WebSocket webSocket, String text) {
        super.onMessage(webSocket, text);
        JSONObject resp = JSON.parseObject(text);
        if (resp != null) {
            if (resp.getInteger("code") != 90000) {
                System.out.println("code=>" + resp.getInteger("code") + " error=>" + resp.getString("message") + " trace_id=" + resp.getString("trace_id"));
                //关闭连接
                webSocket.close(1000, "");
                System.out.println("发生错误,关闭连接");
                return;
            }
            JSONObject dataObject = resp.getJSONObject("data");
            if (dataObject != null) {
                if (StringUtils.isNotEmpty(dataObject.getString("audio_data"))) {
                    //写入文件
                    FileOutputStream out = null;
                    try {
                        out = new FileOutputStream(resultFile, true);
                        byte[] b = Base64.getDecoder().decode(dataObject.getString("audio_data"));
                        out.write(b);
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        if (out != null) {
                            try {
                                out.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
                if (dataObject.getInteger("end_flag") == 1) {
                    //说明数据全部返回完毕,可以关闭连接,释放资源
                    System.out.println("session end,tts finished. ");
                    System.out.println(sdf.format(startTime) + "开始");
                    System.out.println(sdf.format(timeEnd.get()) + "结束");
                    System.out.println("耗时:" + (timeEnd.get().getTime() - startTime.getTime()) + "ms");
                    webSocket.close(1000, "");
                }
            }
        }
    }

    @Override
    public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        super.onFailure(webSocket, t, response);
        try {
            if (null != response) {
                int code = response.code();
                System.out.println("onFailure code:" + code);
                System.out.println("onFailure body:" + response.body().string());
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 测试方法
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        OkHttpClient client = new OkHttpClient.Builder().build();
        Request request = new Request.Builder().url(hostUrl).build();
        File file = new File("src/main/resources/tts1.pcm");
        //测试文本
        String ttsTestText = "教育部13日召开新闻通气会表示,暑期托管服务主要面向确有需求的家庭和学生,并由家长学生自愿选择参加。托管服务应以看护为主,合理组织提供一些集体游戏活动、文体活动、阅读指导、综合实践、兴趣拓展、作业辅导等服务,但不得组织集体补课、讲授新课。关于暑期托管变成第三学期的说法是不符合实际的。";
        //测试简单调用
        if ((ttsTestText.getBytes(Charset.forName("UTF-8"))).length > MAX_BYTE_LENGTH) {
            //单次调用长度不能超过300汉字即900字节
            //本demo策略是长度过长则直接返回,实际使用过程中可以进行文本切割
            System.out.println("文本不能超过300个汉字");
            return;
        }
        client.newWebSocket(request, new TtsWebSocketDemo(ttsTestText, file));
    }

    public static String getAccessToken() {
        String accessToken = "";
        OkHttpClient client = new OkHttpClient();
        //request 默认是get请求
        String url = String.format(tokenUrl, clientSecret, clientId);
        Request request = new Request.Builder().url(url).build();
        JSONObject jsonObject;
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                //解析
                String resultJson = response.body().string();
                jsonObject = JSON.parseObject(resultJson);
                accessToken = jsonObject.getString("access_token");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return accessToken;
    }
}
      

PHP示例代码

send($data); //发送数据

    //监听数据
    $info_list = [];
    $flag = true;
    while ($flag) {
        try {
            $message = $client->receive();//获取数据
            $result_info = json_decode($message,1);
            if($result_info['code'] == 90000){
                $info_list[$result_info['data']['idx']] = $result_info['data'];
            }else{
                throw new Exception($result_info['message']);
            }
            if($result_info['data']['end_flag']==1) $flag=false;//最后一包数据获取完成 停止获取数据
            //var_dump($result_info);
        } catch (\WebSocket\ConnectionException $e) {
            die($e->getMessage());
        }
    }
    //对获取数据进行处理 (说明,根据业务逻辑情况使用,本示例对返回信息一次性写入)
    if($info_list){
        ksort($info_list);//进行升序排序(说明,酌情使用,本示例对返回识别段落进行了二次排序)
        $file_name = './test.pcm';
        $handle=fopen($file_name,"w");
        foreach ($info_list as $v){
            //写入文件
            fwrite($handle, base64_decode($v['audio_data']));
        }
        die("识别音频保存完成");
    }else{
        die("获取的数据为空");
    }
      

C示例代码

代码地址:Github

响应结果

  • 请求识别响应
  • 参数名称 类型 描述
    code int 错误码4xxxx表示客户端参数错误,5xxxx表示服务端内部错误,详见错误码
    message string 错误描述
    trace_id string 任务id
    {
          "code":40001,
          "message":" Invalid json data",
          "trace_id":" 1572234229176271"
    }
  • 成功响应
  • 参数名称 类型 描述
    code int 错误码4xxxx表示客户端参数错误,5xxxx表示服务端内部错误
    message string 错误描述
    trace_id string 任务id
    data object 合成音频片段
    idx int 包序号
    audio_data string base64编码后的音频数据,需要解码后使用
    audio_type string 音频格式
    interval string 音子边界信息
    end_flag int 结束标志:
    0:未结束
    1:结束
    {
          "code":90000,
          "message":"Success",
          "trace_id":" 1572234229176271"
          "data":{
            "idx":1,
            "audio_data":" P8EAPz/AQAGAPf/8v/n/wkAAwD//wsA7f/q/x",
            "audio_type":"audio/pcm",
            "interval":" h=0.083746&e=0.175807",
            "end_flag":0
          }
    }

错误码

code 描述 处理建议
90000 返回音频数据
10001 access_token参数获取失败或未传输 检查参数
10002 domain参数值错误
10003 language参数错误
10004 voice_name参数错误
10005 audiotype参数错误
10006 rate参数错误
10007 idx错误
10008 single错误
10009 text参数错误
10010 文本太长
20000 获取资源错误
20001 断句失败
20002 分段数错误
20003 分段后的文本长度错误
20004 获取引擎链接错误
20005 RPC链接失败错误
20006 引擎内部错误
20007 操作redis错误
20008 音频编码错误
30000 鉴权错误(access_token值不正确或已经失效)
30001 并发错误
30002 内部配置错误
30003 json串解析错误
30004 获取url失败
30005 获取客户IP地址失败
30006 任务队列错误
40001 请求json不合法 检查参数
40002 请求缺失必须字段
40003 版本号错误
40004 字段值类型错误
40005 参数错误
50001 处理超时
50002 内部rpc调用失败
50004 其他内部错误