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
声纹识别 声纹识别
开发者文档下拉
RESTful API
协议规则 协议规则
开发者文档下拉
平台服务协议
平台通用规则
法律声明及隐私政策
服务等级协议SLA
常见问题 常见问题
开发者文档下拉
语音合成
语音识别

实时长语音识别Websocket API

功能介绍

对长时间持续输入的语音流进行识别,适用于视频直播,会议研究等场景。

  • 支持语言:中文普通话、英文
  • 支持添加标点,支持将中文数字转换为阿拉伯数字进行输出。
  • 支持连续返回中间识别结果,实现连续上屏效果

音频要求

  • 支持音频格式:wav,pcm(Linear pcm)
  • 音频采样率:8000Hz,16000Hz
  • 位深:16bits
  • 声道:单声道
  • 时长限制:不超过3小时

使用方法

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

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

3. 建立websocket连接

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

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

6. 关闭连接。

服务地址

访问类型 说明 URL Host
外网访问 支持中文普通话、英文 wss://openapi.data-baker.com/asr/realtime openapi.data-baker.com

交互流程

测试音频

测试音频

请求参数

参数名称 类型 是否必填项 说明
access_token string yes 通过client_id,client_secret调用授权服务获得见 获取访问令牌
version string yes 版本信息,目前为1.0
asr_params jsonObject yes asr相关参数

asr相关参数如下:

参数名称 类型 是否必填项 说明
audio_data string 采样率为16000时,每包取5120字节原始音频进行base64加密,最后一包除外
audio_format string 音频编码格式:
pcm
wav
sample_rate int 音频采样率:
8000
16000
req_idx int 音频序号索引,步长为1递增
0:起始音频帧
>0:中间音频帧(如1 2 3 4 … 1000)
-n:结束音频帧(如-1001)
domain string 模型名称,通用模型 "common",
英文模型"english",
默认值为“common”
add_pct boolean no true: 加标点,默认值
false:不添加标点

请求示例

{
"access_token":" 1ccbbc2d************0cfce63eec55",
"version":"1.0",
"asr_params":
	{
        "audio_data":"xxxxxxxxxxxxxxx",  //已对二进制音频数据进行base64加密
        "audio_format":"pcm",
        "sample_rate":16000,
        "req_idx":0,
        "domain":"common"  //非必填
	}
}

Python示例代码

代码地址:Github

Python3示例:

import argparse
import json
import base64
import time
from threading import Thread

import requests
import websocket


class Client:
    def __init__(self, data, uri):
        self.data = data
        self.uri = uri

    #建立连接
    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):
        def run(*args):
            for i in range(len(self.data)):
                ws.send(self.data[i])

        Thread(target=run).start()


    # 接收消息
    def on_message(self, ws, message):
        code = json.loads(message).get("code")
        if code != 90000:
            # 打印接口错误
            print(message)
        if json.loads(message).get('sentence_end') == "true":
            print(json.loads(message).get('asr_text'))

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

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


# 准备数据
def prepare_data(args, access_token):
    # 读取音频文件
    with open(args.file_path, 'rb') as f:
        file = f.read()

    # 填写Header信息
    audio_format = args.audio_format
    sample_rate = args.sample_rate

    splited_data = [str(base64.b64encode(file[i:i + 5120]), encoding='utf-8') for i in range(0, len(file), 5120)]
    asr_params = {"audio_format": audio_format, "sample_rate": int(sample_rate), "speech_type": 1}

    json_list = []
    for i in range(len(splited_data)):
        if i != len(splited_data) - 1:
            asr_params['req_idx'] = i
        else:
            asr_params['req_idx'] = -len(splited_data) + 1
        asr_params["audio_data"] = splited_data[i]
        data = {"access_token": access_token, "version": "1.0", "asr_params": asr_params}

        json_list.append(json.dumps(data))

    return json_list


# 获取命令行输入参数
def get_args():
    parser = argparse.ArgumentParser(description='ASR')
    parser.add_argument('-client_secret', type=str, required=True)
    parser.add_argument('-client_id', type=str, required=True)
    parser.add_argument('-file_path', type=str, required=True)
    parser.add_argument('--audio_format', type=str, default='wav')
    parser.add_argument('--sample_rate', type=str, default='8000')
    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/asr/realtime"
        # 建立Websocket连接
        client = Client(data, uri)
        client.connect()
    except Exception as e:
        print(e)

命令行执行

默认wav格式,16000采样率,如有需要可自行修改参数

python real_time_audio_recognition.py -client_secret=您的client_secret -client_id=您的client_id -file_path=test.wav --audio_format=wav --sample_rate=16000

JAVA示例代码

package com.databaker.web.asr;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Base64;
import java.util.Date;

/**
 * 流式语音识别 webSocket接口调用示例
 * 附1:一句话识别Websocket API文档 【/specs/file/asr_word_api_websocket】
 * 附2:长语音识别Websocket API文档 【/specs/file/asr_stream_websocket】
 *
 * 注意:
 * 1.作为demo,进行了一些简化,采用直接从文件中读取的方式获取音频流,实际场景很可能是从麦克风获取音频流。
 * 2.一句话识别Websocket和长语音识别Websocket使用方式类似,主要区别在于时长限制。
 * 3.如果从麦克风获取音频流,请注意每次发送的数据流大小为52K,不足时补静音段。
 * 4.本demo仅完成基本的接口调用,失败重试、token过期重新获取、日志打印等优化工作需要开发者自行完成。
 *
 * @author data-baker
 */

public class AsrWebSocketDemo 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/asr/realtime";
    /**
     * 文件路径【开发者需要根据实际路径调整。支持的音频编码格式:PCM(无压缩的PCM文件或WAV文件),采样率8K或16K,位深16bit,单声道】
     */
    private static final String file = "/home/asr/16k_16bit.pcm";


    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();

    private StringBuilder resultAsr = new StringBuilder();

    @Override
    public void onOpen(WebSocket webSocket, Response response) {
        super.onOpen(webSocket, response);
        this.startTime = timeBegin.get();
        //该demo直接从文件中读取音频流【实际场景可能是实时从麦克风获取音频流,开发者自行修改获取音频流的逻辑即可】
        new Thread(() -> {
            //连接成功,开始发送数据
            //每一帧音频的大小,固定值,具体参考接口文档
            int frameSize = 5120;
            int interval = 40;
            // 音频的序号
            int req_idx = 0;
            try (FileInputStream fs = new FileInputStream(file)) {
                byte[] buffer = new byte[frameSize];
                // 发送音频
                while (true) {
                    int len = fs.read(buffer);
                    if (len < frameSize) {
                        //文件已读完
                        req_idx = -1 - req_idx;
                    }
                    //发送音频
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("access_token", accessToken);
                    jsonObject.put("version", "1.0");
                    //填充asr_params
                    JSONObject asrParams = new JSONObject();
                    //domain非必填
                    asrParams.put("domain", "common");
                    asrParams.put("audio_format", "pcm");
                    asrParams.put("sample_rate", 16000);
                    asrParams.put("req_idx", req_idx);
                    asrParams.put("audio_data", Base64.getEncoder().encodeToString(Arrays.copyOf(buffer, len)));
                    jsonObject.put("asr_params", asrParams);
                    webSocket.send(jsonObject.toString());
                    if (req_idx >= 0) {
                        req_idx++;
                    }else {
                        break;
                    }
                    //模拟音频采样延时【如果从麦克风获取音频流,可删除这句代码】
                    Thread.sleep(interval);
                }
                System.out.println("all data is send");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

    @Override
    public void onMessage(WebSocket webSocket, String text) {
        super.onMessage(webSocket, text);
        ResponseData resp = JSON.parseObject(text, ResponseData.class);
        if (resp != null) {
            if (resp.getCode() != 90000) {
                System.out.println("code=>" + resp.getCode() + " error=>" + resp.getMessage() + " trace_id=" + resp.getTrace_id());
                //关闭连接
                webSocket.close(1000, "");
                System.out.println("发生错误,关闭连接");
                return;
            }
            if (resp.getAsr_text() != null) {
                if (resp.getSentence_end()) {
                    resultAsr.append(resp.getAsr_text());
                    System.out.println("当前句子识别结束,识别结果 ==》" + resp.getAsr_text());
                } else {
                    System.out.println("当前句子识别未结束,中间识别结果 ==》" + resp.getAsr_text());
                }
            }
            if (resp.getEnd_flag() == 1) {
                //说明数据全部返回完毕,可以关闭连接,释放资源
                System.out.println("session end ");
                System.out.println(sdf.format(startTime) + "开始");
                System.out.println(sdf.format(timeEnd.get()) + "结束");
                System.out.println("耗时:" + (timeEnd.get().getTime() - startTime.getTime()) + "ms");
                System.out.println("最终识别结果 ==》" + resultAsr.toString());
                System.out.println("本次识别traceId ==》" + resp.getTrace_id());
                webSocket.close(1000, "");
            } else {
                // todo 根据返回的数据处理
            }
        }
    }

    @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());
                if (101 != code) {
                    System.out.println("connection failed");
                    System.exit(0);
                }
            }
        } 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();
        client.newWebSocket(request, new AsrWebSocketDemo());
    }

    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;
    }

    public static class ResponseData {
        /**
         * 状态码(4xxxx表示客户端参数错误,5xxxx表示服务端内部错误)
         */
        private Integer code;
        /**
         * 错误描述
         */
        private String message;
        /**
         * 任务id
         */
        private String trace_id;
        /**
         * 识别结果(code为90000时包含有效数据)
         */
        private String asr_text;
        /**
         * 句子id,从1递增
         */
        private Integer sentence_id;
        /**
         * 句子结束标志
         */
        private Boolean sentence_end;

        /**
         * 是否是最后一个数据块(0:否,1:是)
         */
        private Integer end_flag;


        public Integer getCode() {
            return code;
        }

        public void setCode(Integer code) {
            this.code = code;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        public String getTrace_id() {
            return trace_id;
        }

        public void setTrace_id(String trace_id) {
            this.trace_id = trace_id;
        }

        public String getAsr_text() {
            return asr_text;
        }

        public void setAsr_text(String asr_text) {
            this.asr_text = asr_text;
        }

        public Integer getSentence_id() {
            return sentence_id;
        }

        public void setSentence_id(Integer sentence_id) {
            this.sentence_id = sentence_id;
        }

        public Boolean getSentence_end() {
            return sentence_end;
        }

        public void setSentence_end(Boolean sentence_end) {
            this.sentence_end = sentence_end;
        }

        public Integer getEnd_flag() {
            return end_flag;
        }

        public void setEnd_flag(Integer end_flag) {
            this.end_flag = end_flag;
        }
    }
}

PHP示例代码

send($data); //发送数据
        $i++;
    }

    //监听数据
    $flag = true;
    while ($flag) {
        try {
            $message = $client->receive();//获取数据
            $result_info = json_decode($message,1);
            if($result_info['code'] == 90000){
                if($result_info['end_flag']==1){
                    //(说明,根据业务逻辑情况使用,本示例对返回完整信息进行展示)
                    $flag=false;//最后一包数据获取完成 停止获取数据
                    var_dump($result_info['asr_text']);
                }
            }else{
                throw new Exception($result_info['message']);
            }

        } catch (\WebSocket\ConnectionException $e) {
            die($e->getMessage());
        }
    }

C示例代码

代码地址:Github

响应结果

参数名称 类型 描述
code int 错误码
4xxxx表示客户端参数错误
5xxxx表示服务端内部错误
message string 错误描述
trace_id string 任务id
asr_text string 识别结果
code为9000时包含有效数据
sentence_id int 句子id,从1递增
sentence_end string 句子结束标志
false:当前句子识别未结束,后续还有识别内容
true:当前句子识别已结束,后续识别内容为下一句的识别结果
end_flag int 是否是最后一个数据块,0:否,1:是
sos double 句子起始时间(只有在sentence_end为“true"时存在)
eos double 句子结束时间(只有在sentence_end为“true"时存在)

成功时:

识别文本消息json结构如下:

{
    "asr_text":"以语音连接场景数据服务技术为理念,打造有温度有情感的声音体验个性化场景化的语音交互体验让人机交互变得美好,生活变得更简单。",
    "code":90000,
    "end_flag":1,
    "eos":6.71999979019165,
    "message":"Success",
    "sentence_end":"true",
    "sentence_id":1,
    "sos":0.07999999821186066,
    "trace_id":"1627902981043679"
}

失败时:

json示例:

{
      "code":40001,
      "message":"Invalid json data",
      "trace_id":" 1572234229176271",
      "sid":"b311d1cd-f7a7-4378-9730-0c12d194231f",//可能不存在
}

错误码

错误码 描述 解决方案
90000 文本数据
30001 HTTP请求参数错误 服务器内部错误,提交traceid,标贝后台排查。
30002 服务内部错误
30003 识别结果解析出错
30004 应用包名未知
30005 语音质量问题
30006 输入语音过长
30007 连接识别引擎失败
30008 会话id不存在
30009 Rpc调用非法
30010 redis rpop操作返回空
30011 redis rpop值不合法
30012 rpc调用识别引擎失败
30013 Redis rpop操作失败
30014 redis lpush操作失败
30015 单个语音分片过长
30016 回调url失败
40001 json解析失败 将请求序列化为json结构
40002 json字段不全 检查对应的参数是否正确
40003 版本错误
40004 json字段值类型错误
40005 参数错误
40006 idx超时 相邻idx间隔超过设置超时值(默认60s)
40007 idx顺序错误 idx乱序
40008 token校验失败
40009 token处于未激活状态 检查相应的client_id
40010 token已过期 重新获取token
40011 使用量已超过购买量 检查相应的client_id
40012 qps错误 增大qps
40013 音频包长度错误 检查包长度是否为5120字节
40014 access_token与当前服务不匹配 检查access_token是否匹配
40015 音频大小错误 检查音频大小
40016 错误的音频格式 检查音频格式
40017 错误的采样率 检查采样率
40018 错误的req_idx 检查req_idx
40019 错误的version 检查version
40020 错误的access_token 检查access_token
40021 错误的domain 检查domain
50001 处理超时
50002 内部 rpc 调用失败
50003 服务端繁忙
50004 其他内部错误