专栏首页技术拓展与说明腾讯云ASR产品-PHP实现实时语音鉴权请求
原创

腾讯云ASR产品-PHP实现实时语音鉴权请求

一、准备工作

(1)开通腾讯云 https://cloud.tencent.com/

(2)腾讯云控制台开通实时语音权限 https://console.cloud.tencent.com/asr

(3)控制台设置秘钥 https://console.cloud.tencent.com/cam/capi

内容

说明

支持语言

中文普通话、英文、粤语、韩语、日语、泰语、上海话方言

支持行业

通用、金融、游戏、教育、医疗

音频属性

采样率:16000Hz或8000Hz、采样精度:16bits、声道:单声道

音频格式

wav、pcm、opus、speex、silk、mp3、m4a、aac

数据长度

音频流中每个数据包的音频分片建议为200ms,8k采样率对应的音频分片大小为3200字节,16k采样率对应的音频分片大小为6400字节

二、代码(HTTP、Websocket)

http协议代码如下(https://cloud.tencent.com/document/product/1093/35799)需注意,目前Http协议实时语音官方已下线:

<?php
//实时语音功能

class voiceTest{
    // -------------- Required. 请登录腾讯云官网控制台获取 ---------------------
    const APPID = "appid";#需要配置
    const SECRET_ID = "秘钥id";#需要配置
    const SECRET_KEY = "秘钥key";#需要配置

    const AGREEMENT             = "https";
    const VOICE_URL             = "asr.cloud.tencent.com/asr/v1/";
    const HTTPRequestMethod     = "POST";
    // --------------- Optional, 请按需修改 ---------------------
    /** 引擎模型类型
        • 8k_zh:电话 8k 中文普通话通用;
        • 8k_zh_finance:电话 8k 金融领域模型;
        非电话场景:
        • 16k_zh:16k 中文普通话通用;
        • 16k_en:16k 英语;
        • 16k_ca:16k 粤语;
        • 16k_ko:16k 韩语;
        • 16k_zh-TW:16k 中文普通话繁体;
        • 16k_ja:16k 日语。
     **/

    static $ENGINE_MODEL_TYPE = '16k_zh';

    //结果返回方式 0:同步返回,拿到全部中间结果, or 1:尾包返回
    static $RES_TYPE = 1;
    //1:实时流式识别
    static $SUB_SERVICE_TYPE = 1;

    // 识别结果文本编码方式 0:UTF-8, 1:GB2312, 2:GBK,3:BIG5
    static $RESULT_TEXT_FORMAT = 0;

    // 语音编码方式 1:wav 4:sp 6:silk
    static $VOICE_FORMAT = 8;

    //热词
    static $HOT_WORD_ID = "";

    //如果音频流总时长超过60秒,用户需开启 vad。0:关闭 vad,1:开启 vad。
    static $NEEDVAD = 0;

    //语音断句检测阈值,静音时长超过该阈值会被认为断句(多用在智能客服场景,需配合 needvad=1 使用),取值范围150-2000,单位 ms,目前仅支持 8k_zh 引擎模型
    static $VAD_SILENCE_TIME = 2000;

    //默认0
    static $SOURCE = 0;
    //后处理参数
    static $FILTER_DIRTY = 0;
    static $FILTER_MODAL = 0;
    static $FILTER_PUNC  = 0;
    static $CONVERT_NUM_MODE = 0;
    static $WORD_INFO = 0;

    // 语音切片长度 cutlength<200000
    static $CUTLENGTH = 60000;


    public static function voice($pathFile){
        //get请求 设置url参数
        $timestamp      = time();

        $httpUrlParams  =
        [
            "appid"         => self::APPID,
            "projectid"     => 0,
            "secretid"      => self::SECRET_ID,
            "sub_service_type"      => self::$SUB_SERVICE_TYPE, //1:实时流式识别
            "engine_model_type"     => self::$ENGINE_MODEL_TYPE,
            "result_text_format"    => self::$RESULT_TEXT_FORMAT,
            "res_type"      => self::$RES_TYPE,
            "voice_format"  => self::$VOICE_FORMAT,
            "needvad"       => self::$NEEDVAD,
            "source"        => self::$SOURCE,
            "voice_id"      => self::getRandomString(16),//16 位 String 串作为每个音频的唯一标识,用户自己生成。
            "timestamp"     => $timestamp,
            "expired"       => $timestamp + 24 * 60 * 60,
            "nonce"         => rand(1, 100000),//随机正整数
            "filter_dirty"  => self::$FILTER_DIRTY,
            "filter_modal"  => self::$FILTER_MODAL,
            "filter_punc"   => self::$FILTER_PUNC,
            "convert_num_mode"  => self::$CONVERT_NUM_MODE,
            "word_info"         => self::$WORD_INFO,
        ];
        //print_r($httpUrlParams);exit;
        //查询是否设置热词
        if (self::$HOT_WORD_ID != "")
        {
            $httpUrlParams["hotword_id"] = self::$HOT_WORD_ID;
        }
        //查询是否设置语音断句检测阈值 需配合 needvad=1 使用,取值范围150-2000,目前仅支持8k_zh
        if (self::$VAD_SILENCE_TIME >= 150
            && self::$VAD_SILENCE_TIME <= 2000
            && $httpUrlParams["needvad"] == 1
            && $httpUrlParams["engine_model_type"] == "8k_zh")
        {
            $httpUrlParams["vad_silence_time"] = self::$VAD_SILENCE_TIME;
        }

        //获取传入语音包大小
        $voice_data = file_get_contents($pathFile);
        //计算数据包可分片次数
        $voicelen   = strlen($voice_data);
        $whilenum   = ceil($voicelen /  self::$CUTLENGTH);

        $voiceSeq = 0;
        //分片传入
        while ($voiceSeq < $whilenum) {
            $voiceEnd = 0;

            //最后分片
            if ($voiceSeq == ($whilenum - 1)) {
                $voiceEnd = 1;
            }

            $httpUrlParams["seq"] = $voiceSeq;
            $httpUrlParams["end"] = $voiceEnd;//最后一片为1
            //计算包节点
            $offset = $voiceSeq * self::$CUTLENGTH;
            $voiceSeq++;
            //get请求url拼接
            $requestUrl = self::AGREEMENT."://".self::VOICE_URL.self::APPID."?";
            //剔除appid
            unset($httpUrlParams["appid"]);
            //生成URL请求地址
            $requestUrl .= http_build_query($httpUrlParams);
            //鉴权
            $sign = self::getAuthorizationString($httpUrlParams);

            //分片数据包
            $sectionData = file_get_contents($pathFile, NULL, NULL, $offset, self::$CUTLENGTH);
            $headers = [
                'Authorization: ' . $sign,
                'Content-Length: ' . strlen($sectionData),
            ];
            $result = self::get_curl_request($requestUrl, $sectionData, 'POST', $headers);
            echo $result , "\n";
        }
    }


    /**
     * 发送请求
     * @param $url
     * @param array $param
     * @param string $mothod
     * @param array $headers
     * @param int $return_status
     * @param int $flag 关闭https证书
     * @return array|bool|string
     */
    static private function get_curl_request($url, $param, $mothod = 'POST', $headers = [], $return_status = 0, $flag = 0)
    {
        $ch = curl_init();
        if (!$flag) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        }

        curl_setopt($ch, CURLOPT_TIMEOUT, 6);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        if (strtolower($mothod) == 'post') {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
        } else {
            $url = $url . "?" . http_build_query($param);
        }
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 2);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        //代理
//        curl_setopt($ch, CURLOPT_PROXY, "127.0.0.1");
//        curl_setopt($ch, CURLOPT_PROXYPORT, "12639");

        $ret = curl_exec($ch);
        $code = curl_getinfo($ch);
        curl_close($ch);
        if ($return_status == "1") {
            return array($ret, $code);
        }
        return $ret;
    }

    /**
     * 生成随机字符串
     * @param $len
     * @param bool $special 是否开启特殊字符
     * @return string
     */
    private static function getRandomString($len, $special=false){
        $chars = array(
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
            "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
            "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
            "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
            "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
            "3", "4", "5", "6", "7", "8", "9"
        );

        if($special){
            $chars = array_merge($chars, array(
                "!", "@", "#", "$", "?", "|", "{", "/", ":", ";",
                "%", "^", "&", "*", "(", ")", "-", "_", "[", "]",
                "}", "<", ">", "~", "+", "=", ",", "."
            ));
        }

        $charsLen = count($chars) - 1;
        shuffle($chars);                            //打乱数组顺序
        $str = '';
        for($i=0; $i<$len; $i++){
            $str .= $chars[mt_rand(0, $charsLen)];    //随机取出一位
        }
        return $str;
    }

    /**
     * 创建签名
     * @param $params array 提交参数数组
     * @return string
     */
    private static function getAuthorizationString($params){
        //加密字符串拼接
        $signString = self::HTTPRequestMethod.self::VOICE_URL.self::APPID."?";
        //排序
        ksort($params, SORT_STRING);
        //去除appid
        unset($params["appid"]);
        //转url
        $signString .= http_build_query($params);
        $sign = base64_encode(hash_hmac('SHA1', $signString, self::SECRET_KEY, true));
        return $sign;
    }
}

//设置参数
//请求
voiceTest::voice("./test_wav/16k/16k_30s.wav");

websocket协议代码如下(https://cloud.tencent.com/document/product/1093/48982):

<?php
//第一步安装socket 包 # https://github.com/Textalk/websocket-php
// composer require textalk/websocket
//第二步引用
require_once "vendor/autoload.php";
//PHP 关于实时语音识别请求鉴权
class wsVoice{
    const APPID = "appid";#需要配置
    const SECRET_ID = "秘钥id";# 需要配置
    const SECRET_KEY = "秘钥key";# 需要配置

    const AGREEMENT             = "wss://";
    const VOICE_URL             = "asr.cloud.tencent.com/asr/v2/";

    /** 引擎模型类型
    • 8k_zh:电话 8k 中文普通话通用;
    • 8k_zh_finance:电话 8k 金融领域模型;
    非电话场景:
    • 16k_zh:16k 中文普通话通用;
    • 16k_en:16k 英语;
    • 16k_ca:16k 粤语;
    • 16k_ko:16k 韩语;
    • 16k_zh-TW:16k 中文普通话繁体;
    • 16k_ja:16k 日语。
     **/
    static $ENGINE_MODEL_TYPE = '16k_zh';

    // 语音编码方式 1:wav 4:sp 6:silk
    static $VOICE_FORMAT = 1;

    //热词
    static $HOT_WORD_ID = "";

    //如果音频流总时长超过60秒,用户需开启 vad。0:关闭 vad,1:开启 vad。
    static $NEEDVAD = 0;

    //语音断句检测阈值,静音时长超过该阈值会被认为断句(多用在智能客服场景,需配合 needvad=1 使用),取值范围150-2000,单位 ms,目前仅支持 8k_zh 引擎模型
    static $VAD_SILENCE_TIME = 2000;

    //后处理参数
    static $FILTER_DIRTY = 0;
    static $FILTER_MODAL = 0;
    static $FILTER_PUNC  = 0;

    // 语音切片长度 cutlength<200000
    static $CUTLENGTH = 6000;


    public function ws($pathFile = ""){
        $timestamp      = time();
        $httpUrlParams  =
            [
                "secretid"      => self::SECRET_ID,
                "timestamp"     => $timestamp,
                "expired"       => $timestamp + 24 * 60 * 60,
                "nonce"         => rand(1, 100000),//随机正整数
                "engine_model_type"     => self::$ENGINE_MODEL_TYPE,
                "voice_id"      => self::getRandomString(16),//16 位 String 串作为每个音频的唯一标识,用户自己生成。
                "voice_format"  => self::$VOICE_FORMAT,
                "needvad"       => self::$NEEDVAD,
                "filter_dirty"  => self::$FILTER_DIRTY,
                "filter_modal"  => self::$FILTER_MODAL,
                "filter_punc"   => self::$FILTER_PUNC,
                "convert_num_mode" => 1,
                "word_info" => 0,
                //"hotword_id"
                //"vad_silence_time"
                //"signature"
            ];

        //查询是否设置热词
        if (self::$HOT_WORD_ID != "")
        {
            $httpUrlParams["hotword_id"] = self::$HOT_WORD_ID;
        }

        //查询是否设置语音断句检测阈值 需配合 needvad=1 使用,取值范围150-2000,目前仅支持8k_zh
        if (self::$VAD_SILENCE_TIME >= 240
            && self::$VAD_SILENCE_TIME <= 2000
            && $httpUrlParams["needvad"] == 1
            && in_array($httpUrlParams["engine_model_type"], ["8k_zh", "8k_zh_finance", "16k_zh"]))
        {
            $httpUrlParams["vad_silence_time"] = self::$VAD_SILENCE_TIME;
        }

        //获取加密
        $signature =  self::getAuthorizationString($httpUrlParams);
        echo $signature." \n";
        //请求地址
        $httpUrlParams["signature"] = $signature;
        $requestUrl = self::AGREEMENT.self::VOICE_URL.self::APPID."?";
        $requestUrl .= http_build_query($httpUrlParams);
        echo $requestUrl. " \n";

        //获取传入语音包大小
        $voice_data = file_get_contents($pathFile);
        //计算数据包可分片次数
        $voicelen   = strlen($voice_data);
        $whilenum   = ceil($voicelen /  self::$CUTLENGTH);
        $voiceSeq = 0;
        //分片传入

        $client = new WebSocket\Client($requestUrl);
//        $client->binary("初次握手");
//        echo $client->receive();

        echo "总次数".$whilenum. " \n";
        while ($voiceSeq < $whilenum) {
            //计算包节点
            $offset = $voiceSeq * self::$CUTLENGTH;

            $voiceSeq++;
            //分片数据包
            $sectionData = file_get_contents($pathFile, NULL, NULL, $offset, self::$CUTLENGTH);
            //echo $sectionData;exit;
            //ws请求
            $client->binary($sectionData);
            echo $client->receive();
            echo "\n";
        }
        echo "结束 \n";
        $client->text('{"type": "end"}');
        echo $client->receive();
        $client->close();
    }


    /**
     * 创建签名
     * @param $params array 提交参数数组
     * @return string
     */
    private static function getAuthorizationString($params){
        //加密字符串拼接
        $signString = self::VOICE_URL.self::APPID."?";
        //排序
        ksort($params, SORT_STRING);
        //转url
        $signString .= http_build_query($params);
        $sign = base64_encode(hash_hmac('SHA1', $signString, self::SECRET_KEY, true));
        return $sign;
    }

    /**
     * 生成随机字符串
     * @param $len
     * @param bool $special 是否开启特殊字符
     * @return string
     */
    private static function getRandomString($len, $special=false){
        $chars = array(
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
            "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
            "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
            "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
            "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
            "3", "4", "5", "6", "7", "8", "9"
        );

        if($special){
            $chars = array_merge($chars, array(
                "!", "@", "#", "$", "?", "|", "{", "/", ":", ";",
                "%", "^", "&", "*", "(", ")", "-", "_", "[", "]",
                "}", "<", ">", "~", "+", "=", ",", "."
            ));
        }

        $charsLen = count($chars) - 1;
        shuffle($chars);                            //打乱数组顺序
        $str = '';
        for($i=0; $i<$len; $i++){
            $str .= $chars[mt_rand(0, $charsLen)];    //随机取出一位
        }
        return $str;
    }

}

$model = new wsVoice();
$model->ws("./test.pcm");

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

关注作者,阅读全部精彩内容

我来说两句

0 条评论
登录 后参与评论

相关文章

  • V3手动鉴权失败之PHP篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • 【玩转腾讯云】【腾讯云语音识别】如何在微信小程序中进行接口鉴权

    腾讯云语音识别(Automatic Speech Recognition,ASR) 为开发者提供语音转文字服务的最佳体验。语音识别服务经微信、腾讯视频、王者荣耀...

    LinSP
  • 语音识别内容

    A1:但是你传过来的音频,必须是双通道的。是你音频文件生成好的。是一个实时音频流的概念。

    算法发
  • V3手动鉴权失败之Python篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • 内网环境请求腾讯云3.0 API详解

    公司项目环境是内网,无法直连公网,需要通过代理服务器向腾讯云发起接口请求,请问这个过程应该怎样实现?

    张世强
  • V3手动鉴权失败之Go篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之C#篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • 【玩转腾讯云】【腾讯云语音合成】智能语音交互之语音合成篇

    语音合成(Text To Speech,TTS)满足将文本转化成拟人化语音的需求,打通人机交互闭环。 提供多种音色选择,支持自定义音量、语速,让发音更自然、更专...

    ruskin
  • V3手动鉴权失败之Nodejs篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • 产品动态|腾讯云AI 8月产品更新

    ? 腾讯云AI团队联合腾讯优图、AILab、微信智聆、微信智言等实验室,帮助合作伙伴和客户高效打造针对性的解决方案,助力各行各业的数字化和智能化转型。 8月,...

    腾讯云AI
  • 又双叒叕有银行与腾讯云合作了,这次是中信银行!

    10月14日,腾讯云和中信银行在深圳腾讯滨海大厦召开题为“语见·美好未来”的发布会,推出手机银行智能语音产品。

    曾响铃
  • V3手动鉴权失败之Java篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • 豌豆思维落地腾讯云Serverless 在线教育解决方案

    受疫情影响,2020年在线教育用户增长幅度大幅领先于其它互联网应用,行业增长趋势明显。在教育部“停课不停学“的指导下,传统线下教育培训机构逐渐从线下向线上延伸...

    鹅老师
  • 智能云上手指南:如何使用腾讯云开放的图片鉴黄能力?

    今天,腾讯云发布2017战略新品——智能云,对于普通开发者而言,现在可以通过腾讯云开发者实验室0门槛体验优图鉴黄等AI能力。

    云加社区
  • 多款重磅产品能力发布,腾讯云视频产品矩阵拼图补齐

    11月6日,在腾讯云Techo开发者大会音视频及通信技术专场上,腾讯云视频业务产品总监黄斌为现场来宾全景展现了腾讯视频云最新的产品矩阵,并在会上发布了内容制作云...

    腾讯云音视频
  • 腾讯云语音识别v1签名算法详解

    v1的签名文档:https://cloud.tencent.com/document/product/1093/35642

    算法发
  • Serverless 在线教育解决方案——豌豆思维落地实践

    在线教育蓬勃发展 技术保障面临新挑战 2020年的互联网市场中,受疫情影响,在线教育用户增长幅度大幅领先于其它互联网应用,行业增长趋势明显。在教育部“停课不停...

    腾讯云serverless团队
  • 如何快速搭建一个 AI 识别处理的流水线?

    本文为您介绍如何使用 ASW 编排云函数与 AI 产品服务,快速搭建一个 AI 智能识别的处理流水线。通过 ASW 编排调用腾讯云 AI 能力,完成 活体检测...

    腾讯云serverless团队
  • 微信小程序对接云开发录音文件识别nodejs sdk

    拷贝"tencentcloud"目录到云函数"voiceRecognize"的包管理目录"node_modules"下

    张世强

扫码关注云+社区

领取腾讯云代金券