First look at the effect picture: first record, after the recording is successful, add the recording to the list, click the list to play; after the recording is completed, upload the recording, and then voice recognition.
Official wechat documents https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html
Implementation process:
Official account configuration
1.JS security domain configuration: landing WeChat public platform: Official Account Settings > function Settings > JS security domain name, domain name written to the root domain name line, download the txt file to the domain name corresponding to the root directory.
2. Configure ip white list
2, Code display
1. Front end code
'startRecord', 'stopRecord', 'playVoice', 'uploadVoice' are used, Five interfaces of 'translatevoice'. First call startRecord to start recording, and then call stopRecord to stop recording. The local ID of an audio will be returned. Add the recording to the Html recording list to facilitate recording. Use playVoice to play the recording in the recording list, and then use uploadVoice Upload the recording to the wechat server, and it will return to the serverId on the wechat server (I feel that the uploaded recording is not used), and recognize the voice by using the local audio ID
<!DOCTYPE html> <html> <head> <title>speech recognition</title> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <script type="text/javascript" src="/static/index/js/jquery.js"></script> <script src="http://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script> <link rel="stylesheet" type="text/css" href="/static/index/layui/css/layui.css"> <style> button{ height: 40px; width: 120px; margin: 25px; } #ul{ margin-top: 15px; height: 40px; line-height: 40px; text-align: center; padding: 5px; } #ul li{ width: 80%; } #ullist button{ width:98%; height:40px; border-radius:5; text-align: center; margin: 5px; } </style> </head> <body> <div class="container" style="width:100%"> <div class="row"> <ul class="list-unstyled" id="ullist"> </ul> </div> <div id="btn" class="navbar-fixed-bottom" style="user-select:none:align-content:center"> <center> <button id="talk_btn" type="button" class="layui-btn">Sound recording</button> <button id="uploadVoice" type="button" class="layui-btn layui-btn-normal">Upload recording</button><br> <button id="translateVoice" type="button" class="layui-btn layui-btn-danger" style="width:90%;">Speech recognition</button><br> </center> </div> </div> <script type="text/javascript"> // global variable var recordTimer = 300; var voice={ localId:'', serverId:'' } wx.config({ debug: false, appId: '{$signPackage.appId}', timestamp: {$signPackage.timestamp}, nonceStr: '{$signPackage.nonceStr}', signature: '{$signPackage.signature}', jsApiList: [ // All to call API All added to this list 'startRecord', 'stopRecord', 'playVoice', 'uploadVoice', 'translateVoice' ] }); // Call here API wx.ready(function () { var START; var END; // Start recording $("#talk_btn").on('touchstart',function (event) { // console.log(event) event.preventDefault(); START = new Date().getTime(); // Recording after delay to avoid misoperation recordTimer = setTimeout(function () { wx.startRecord({ success:function () { // Authorized recording localStorage.rainAllowRecord = 'true'; }, cancel:function () { console.log('User rejected recording'); } }); },300) }); //Let go and finish recording $('#talk_btn').on('touchend', function(event){ event.preventDefault(); END = new Date().getTime(); if((END - START) < 3000){ END = 0; START = 0; alert('Recording time cannot be less than 3 seconds'); //Less than 300 ms,No recording clearTimeout(recordTimer); }else{ var mytime = new Date().toLocaleTimeString(); //Get current time wx.stopRecord({ success: function (res) { voice.localId = res.localId; console.log(voice.localId) var str="<li audioid='"+voice.localId+"'><button class='layui-btn layui-btn-primary'>Audio task"+mytime+"</button></li>"; $("#ullist").append(str);//Show to list }, fail: function (res) { alert(JSON.stringify(res)); } }); } }); }); wx.error(function (res) { console.log(res) }); //list Play voice $("ul").on("click", "li", function() { var audioid = $(this).attr("audioid"); wx.playVoice({ localId: audioid }); }) // Uploading voice $("#uploadVoice").click(function(){ //Call the upload recording interface of wechat to upload the local recording to the wechat server first wx.uploadVoice({ localId:voice.localId, // Local of audio to be uploaded ID,from stopRecord Interface acquisition isShowProgressTips: 1, // 1 by default, display progress prompt success:function(res){ if(res.errMsg == 'uploadVoice:ok'){ voice.serverId = res.serverId alert('Recording uploaded successfully'); }else{ alert(res.errMsg) } } }) }) // speech recognition $("#translateVoice").click(function(){ wx.translateVoice({ localId:voice.localId, // Local of audio to be identified Id,Obtained by recording related interface isShowProgressTips:1, // 1 by default, display progress prompt success:function(res){ console.log(res) if(res.errMsg == "translateVoice:ok"){ alert(res.translateResult); // Results of speech recognition }else{ alert(res.errMsg) } } }) }) </script> </body> </html>
Back end code (php)
Wechat.php mainly obtains accessToken and jsapiTicket
<?php namespace app\index\controller; use think\Controller; /** * WeChat class */ class Wechat extends Controller { protected $APPID = 'XXXXXXXXXXXXX'; protected $APPSECRET = 'xxxxxxxxxxxxxxxxxx'; /** * Verify the url of token when configuring wechat server */ public function checkToken() { header("Content-type: text/html; charset=utf-8"); //1.take timestamp,nonce,toke Sort by dictionary order $timestamp = $_GET['timestamp']; $nonce = $_GET['nonce']; $token = 'asd123456zxc'; $signature = $_GET['signature']; $array = array($timestamp,$nonce,$token); //2.After splicing the three sorted parameters, use the sha1 encryption $tmpstr = implode('',$array); $tmpstr = sha1($tmpstr); //3.The encrypted string and signature Compare to determine whether the request is from wechat if($tmpstr == $signature){ echo $_GET['echostr']; exit; } } /** * curl request */ public function http_curl($url, $type = 'get', $res = 'json', $arr = ''){ $cl = curl_init(); curl_setopt($cl, CURLOPT_URL, $url); curl_setopt($cl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($cl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($cl, CURLOPT_SSL_VERIFYHOST, false); if($type == 'post'){ curl_setopt($cl, CURLOPT_POST, 1); curl_setopt($cl, CURLOPT_POSTFIELDS, $arr); } $output = curl_exec($cl); curl_close($cl); return json_decode($output, true); if($res == 'json'){ if( curl_error($cl)){ return curl_error($cl); }else{ return json_decode($output, true); } } } /** * Get AccessToken */ public function getAccessToken() { $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$this->APPID."&secret=".$this->APPSECRET; // First judge access_token In file token Whether it is expired or not, continue to use if it is not expired, and update if it is expired $data = json_decode($this->get_php_file(ROOT_PATH."public".DS."wxtxt".DS."access_token.txt")); // Overdue updates if ($data->expire_time < time()) { $res = $this->http_curl($url); $access_token = $res['access_token']; if ($access_token) { // Add 7000 to the current timestamp s (Two hours) $data->expire_time = time() + 7000; $data->access_token = $res['access_token']; $this->set_php_file(ROOT_PATH."public".DS."wxtxt".DS."access_token.txt",json_encode($data)); } }else{ // Direct use without expiration $access_token = $data->access_token; } return $access_token; } /** * Get JsApiTicket */ public function getJsApiTicket() { // First judge jsapi_ticket Whether to continue to use after expiration or not, and update after expiration $data = json_decode($this->get_php_file(ROOT_PATH."public".DS."wxtxt".DS."jsapi_ticket.txt")); if ($data->expire_time < time()) { // Overdue updates $accessToken = $this->getAccessToken(); $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken"; $res = $this->http_curl($url); $ticket = $res['ticket']; if ($ticket) { $data->expire_time = time() + 7000; $data->jsapi_ticket = $ticket; $this->set_php_file(ROOT_PATH."public".DS."wxtxt".DS."jsapi_ticket.txt",json_encode($data)); } }else{ $ticket = $data->jsapi_ticket; } return $ticket; } // Get the token ticket private function get_php_file($filename) { return trim(file_get_contents($filename)); } // hold token ticket Store in file private function set_php_file($filename, $content) { $fp = fopen($filename, "w"); fwrite($fp, $content); fclose($fp); } }
Wxmedia.php this class is to return the configuration information of speech recognition
<?php namespace app\index\controller; use think\Controller; use app\index\controller\Wechat; /** * Wechat speech recognition */ class Wxmedia extends Wechat { /** * speech recognition */ public function index() { $signPackage = json_decode($this->getSignPackage(),true); $this->assign('signPackage',$signPackage); return $this->fetch(); } /** * Generate signature */ public function getSignPackage() { // Instantiate wechat operation class $wx = new Wechat(); // Obtain ticket $jsapiTicket = $wx->getJsApiTicket(); // Be careful URL It must be acquired dynamically, not hardcode. $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://"; // Of the current page url $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"; $timestamp = time(); //Generate signature timestamp $nonceStr = $this->createNonceStr(); //Generate previous random string // Here, the order of parameters should be in ascending order of key value ASCII code $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url"; // Yes string Conduct sha1 encryption $signature = sha1($string); $signPackage = array( "appId" => $wx->APPID, "nonceStr" => $nonceStr, "timestamp" => $timestamp, "url" => $url, "signature" => $signature, "rawString" => $string ); return json_encode($signPackage); } /** * Generate a random string of signatures */ private function createNonceStr($length = 16) { $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; $str = ""; for ($i = 0; $i < $length; $i++) { $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); } return $str; } }