缘起,业务中需要实现一个功能,要靠语音识别后筛选数据,生成订单,我小脑壳一拍便来了兴致,何不趁此机会研究研究语音转文字的原理,好好好,开始找了一大堆资料,五分钟后计划夭折,不是技术不行【狗头保命】,纯粹照顾发量,深思熟虑后,决定采用百度云的语音识别(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文件给我【滑稽狗头】!!!!