php实现语音识别 (百度语音识别+ffmpeg转码)

缘起,业务中需要实现一个功能,要靠语音识别后筛选数据,生成订单,我小脑壳一拍便来了兴致,何不趁此机会研究研究语音转文字的原理,好好好,开始找了一大堆资料,五分钟后计划夭折,不是技术不行【狗头保命】,纯粹照顾发量,深思熟虑后,决定采用百度云的语音识别(ps:其实是因为科大讯飞接口略微繁琐)

正文开始,对接口想必大家都会,在此不多赘述,先去百度云申请语音识别极速版,领取免费数量,如果你是个人用户,相信这些够你用了。

下面是接口类代码附上:

    public $api_key = '*****************';
    public $secret_key = '******************';

    public function run($file_path) {
        //获取文件位置
        $file_path = public_path($file_path);
        $file_path = str_replace('/', '\\', $file_path);
        $file_path = substr($file_path, 0, -1);
        $fileSizeInBytes = filesize($file_path);
        $speech = $this->getFileContentAsBase64($file_path);
        $curlopt_postfields = '{
            "format":"m4a",
            "rate":16000,
            "channel":1,
            "cuid":"2phaiRNdcUPOMlLVvWC8sdQdDdynmfWp",
            "dev_pid":80001,
            "speech":"'.$speech.'",
            "len":'.$fileSizeInBytes.',
            "token":"'. $this->getAccessToken() .'"
            }';
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => "https://vop.baidu.com/pro_api",
            CURLOPT_TIMEOUT => 30,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER  => false,
            CURLOPT_SSL_VERIFYHOST  => false,
            CURLOPT_CUSTOMREQUEST => 'POST',
            // speech 可以通过 $this.getFileBase64Content() 方法获取
            CURLOPT_POSTFIELDS =>$curlopt_postfields,
            CURLOPT_HTTPHEADER => array(
                'Content-Type: application/json',
                'Accept: application/json'
            ),
        ));
        $response = curl_exec($curl);
        curl_close($curl);
        return $response;
    }

    /**
     * 获取文件base64编码
     * @param string  $path 文件路径
     * @return string base64编码信息,不带文件头
     */
    private function getFileContentAsBase64($path){
        return base64_encode(file_get_contents($path));
    }

    /**
     * 使用 AK,SK 生成鉴权签名(Access Token)
     * @return string 鉴权签名信息(Access Token)
     */
    private function getAccessToken(){
        $curl = curl_init();
        $postData = array(
            'grant_type' => 'client_credentials',
            'client_id' => $this->api_key,
            'client_secret' => $this->secret_key
        );
        curl_setopt_array($curl, array(
            CURLOPT_URL => 'https://aip.baidubce.com/oauth/2.0/token',
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_SSL_VERIFYPEER  => false,
            CURLOPT_SSL_VERIFYHOST  => false,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POSTFIELDS => http_build_query($postData)
        ));
        $response = curl_exec($curl);
        curl_close($curl);
        $rtn = json_decode($response);
        return $rtn->access_token;
    }

无重点说明,跟着官方提供的文档对接即可,apikey参数和secret_key参数你可以采用更安全的方式存储,不然代码暴露苦茶子都给你看光,让你试试一天调用完一年的量,还有filesize()方法,切记是本地路径哈。

坑来了,因为php不像java有丰富的jar包,所以有些功能实现比较麻烦,我这里为什么要使用ffmpeg来转码呢,总结下来是前端得背锅,因为他请求时给我了一个假的mp3格式的文件,导致百度云无法正确识别,他提供过来的wav格式的文件亦无法识别,他说他没招了,我说我来吧,谁让我宠着你、爱着你呢,至此,wav转mp3操作开始。

首先,下载ffmpeg,不会下载的,可以联系我邮箱:mroldliu@qq.com

下载好后,进入bin目录,如上图,将ffmpeg.exe文件复制到项目的根目录下,准确来说是运行目录下,这样,我们的准备工作已经做完,可以愉快的开始编码了,先上代码。

/**
     * 语音识别生成订单(返回数组)
     * @param File path
     * @return array list
     */
    public function get_voice_baidu_list(){
        //获取录音文件路径
        $path = input('path');
        if (empty($path)) {
            throw new ApiException("请选择录音文件");
        }
        //获取运行目录
        $currentDirectory = getcwd();
        //判断是否是一个路径,防止注入
        if (!is_file($currentDirectory . $path)) {
            throw new ApiException("非法操作");
        }
        $path = str_replace('/', '\\', $path);
        $before_path_arr = explode('.', $path);
        $later_path = $before_path_arr[0] . '.mp3';
        //命令拼接
        $command = "ffmpeg -i $currentDirectory$path $currentDirectory$later_path";
        //执行$command命令
        exec($command);
        $baidu = new BaiDuVoice(app());
        $result = $baidu->run($later_path);
        $result = json_decode($result, true);
        if (empty($result) || $result['err_no'] != 0) {
            throw new ApiException("识别失败");
        }
        $text = $result['result'][0];
        $text = chineseToNumberInString($text);
        $text = str_replace([',', ','], '', $text);
        $goods_list = Goods::where('is_on_sale', 1)->select();
        $buy_list = [];
        foreach ($goods_list as $k => $v) {
            // 使用 '/' 作为正则表达式的分隔符,并对特殊字符进行转义
            $goodsName = preg_quote($v['goods_name'], '/');
            $goodsUnit = preg_quote($v['goods_unit'], '/');
            // 匹配正整数的模式,加括号匹配成一个单独分组
            $integerPattern = '([1-9]\d*)';
            // 匹配正浮点数的模式
            $floatPattern = '([1-9]\d*\.\d*)';
            // 构建正则表达式
            $regularExpression = '/' . $goodsName . $integerPattern . $goodsUnit . '|' . $goodsName . $floatPattern . $goodsUnit . '/';
            if (preg_match($regularExpression, $text, $match)) {
                $lists = [
                    'goods_id' => $v['goods_id'],
                    'goods_img' => $this->site_url . $v['goods_img'],
                    'goods_name' => $v['goods_name'],
                    'goods_num' => $match[1],
                    'goods_unit' => $v['goods_unit'],
                ];
                $buy_list[] = $lists;
            }
        }
        throw new ApiException("识别成功", 200, $buy_list);
    }
命令说明:ffmpeg -i 老文件路径 新文件路径

我使用了is_file()方法来防止命令注入,请君根据自己的实际业务,来确定如何防止注入攻击,另有escapeshellarg()方法或realpath()方法也可以进行一定的规避,请谨慎编码

到这一步,已经实现了一个简单的语音识别,下面的正则匹配请忽略。

希望能帮助到新手小伙伴,也祝愿天下的前端技术能越来越好,祝郭郎能提供真的mp3文件给我【滑稽狗头】!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SongShan Liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值