基于微信API的语音转文字实现
微信原文地址:智能接口 / 开放接口 / 获取语音识别结果
由上面官方文档可知,微信平台中提供了两个接口:第一个接口是语音上传接口,第二个接口是获取识别结果接口。
所以我们可以通过前端录音,然后将录音传至后端,由后端再去先后请求以上两个接口,以此达到语音转文字(STT)的目的。
重要!!!==》要先申请下来公众号或者服务号。因为后面要用appId和secret密钥来请求。
先获取到微信的token,然后携带这个token去请求微信接口。
第一部分:前端生成录音文件:
前端生成录音部分,可采用第三方的插件:Recorder: html5 js 录音 mp3 wav ogg webm amr g711a g711u 格式,支持pc和Android、iOS部分浏览器、Hybrid App(提供Android iOS App源码)、微信,提供ASR语音识别转文字 H5版语音通话聊天示例 DTMF编码解码
使用方式我参考了这位老哥的文章:vue3实现H5网页录音并上传(mp3、wav)兼容Android、iOS和PC端使用 Recorder插件 可以在HT - 掘金
不得不说,此插件非常方便。
第二部分,后端调用微信的两个接口:
因为微信语音上传接口规定了请求方式,所以不再赘述。
1、创建form-data式的请求(本人技术有限,可能写的有些潜在问题,比如流的关闭应该放在finally块中):
此段代码参考了这位老哥的文章:Java以form-data(表单)的形式调用第三方接口_java formdata-CSDN博客
//前缀
public static String PREFIX = "--";
//换行符
public static String ROW = "\r\n";
//产生一个边界
static String BOUNDARY = UUID.randomUUID().toString().replaceAll("-" , "");
/**
* 发送form-data表单数据
* @param url
* @param paramMap
* @param inputStream
* @return
*/
public static String sendPostWithFormData(String url,Map<String,String> paramMap,DataInputStream dataInputStream,String fileName) {
StringBuffer bufferUrl = new StringBuffer();
bufferUrl.append(url);
int mapSize = paramMap.size();
if (!paramMap.isEmpty()){
bufferUrl.append("?");
for (String mapKey : paramMap.keySet()) {
bufferUrl.append(mapKey+"=");
bufferUrl.append(paramMap.get(mapKey));
mapSize--;
if (mapSize>0){
bufferUrl.append("&");
}
}
}
DataOutputStream outputStream = null;
try {
URL myUrl = new URL(bufferUrl.toString());
HttpURLConnection connection = (HttpURLConnection) myUrl.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("accept","*/*");
connection.setRequestProperty("connection","Keep-Alive");
connection.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.setRequestProperty("Content-Type","multipart/form-data;boundary="+BOUNDARY);
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setDefaultUseCaches(false);
//连接超时
connection.setConnectTimeout(10000);
//读取超时
connection.setReadTimeout(20000);
outputStream = new DataOutputStream(connection.getOutputStream());
StringBuffer bufferData = new StringBuffer();
bufferData.append(PREFIX).append(BOUNDARY).append(ROW);
bufferData.append("Content-Disposition: form-data; name=\"");
bufferData.append("uploadFiles").append("\"; ");
bufferData.append("filename=\"").append(fileName).append("\"").append(ROW);
bufferData.append("Content-Type: application/octet-stream; charset=UTF-8");
byte[] bates = new byte[1024*1024];
int length = 0;
while ((length=dataInputStream.read(bates))!=-1){
outputStream.write(bates,0,length);
}
dataInputStream.close();
outputStream.write(ROW.getBytes(StandardCharsets.UTF_8));
//写入边界结束符
outputStream.write((PREFIX + BOUNDARY + PREFIX + ROW).getBytes(StandardCharsets.UTF_8));
outputStream.flush();//可以理解为发送请求
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
return bufferedReader.readLine();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
return null;
}
2、普通的Http Post请求:
/**
* 向指定 URL 发送POST方法的请求
*
* @param url
* 发送请求的 URL
* @param paramMap
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPostTwo(String url, Map<String, String> paramMap) {
OutputStreamWriter out = null;
BufferedReader in = null;
String result = "";
StringBuffer param=new StringBuffer();
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestMethod("POST");
conn.setRequestProperty("Accept-Charset", "UTF-8");
conn.setRequestProperty("contentType", "UTF-8");
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new OutputStreamWriter(conn.getOutputStream(),"UTF-8");
// 发送请求参数
Iterator it = paramMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
param.append(entry.getKey().toString());
param.append("=");
param.append(entry.getValue().toString());
param.append("&");
}
out.write(param.toString().substring(0, param.toString().length()-1));
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream(),"UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result+=line;
}
result=new String(result.getBytes(),"utf-8");
} catch (Exception e) {
// System.out.println("发送 POST 请求出现异常!"+e);
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
return result;
}
3、微信两个请求接口的工具类
@Slf4j
public class AudioToTextUtil {
private static final String WX_AUDIO_TO_TEXT = "https://api.weixin.qq.com/cgi-bin/media/voice/addvoicetorecofortext";
//上传语音文件
public static JSONObject wxSTT(MultipartFile multipartFile, String accessToken){
JSONObject jsonObject = new JSONObject();
if (multipartFile.isEmpty()){
jsonObject.put("code",-1);
return jsonObject;
}
String id = UUID.randomUUID().toString().replaceAll("-", "");
try{
DataInputStream dataInputStream = new DataInputStream(multipartFile.getInputStream());
Map<String,String> map = new HashMap<>();
map.put("access_token",accessToken);
map.put("format","mp3");
map.put("voice_id",id);
map.put("lang","zh_CN");
String responseData = HttpRequest.sendPostWithFormData(WX_AUDIO_TO_TEXT, map, dataInputStream, "PMSAUDIO");
jsonObject.put("data",responseData);
jsonObject.put("id",id);
log.error("语音信息upload==》{}",responseData);
return jsonObject;
} catch (IOException ioException) {
log.error("语音识别失败,id==>{},原因==>{}",id,ioException.getMessage());
throw new BaseApiException("语音识别失败,id==>{}",id);
}
}
//获取识别结果
public static String wxSTTResult(String accessToken,String id){
Map<String,String> map = new HashMap<>();
map.put("access_token",accessToken);
map.put("voice_id",id);
map.put("lang","zh_CN");
String postWx = HttpRequest.sendPostTwo("https://api.weixin.qq.com/cgi-bin/media/voice/queryrecoresultfortext", map);
log.error("语音识别信息success==》{}",postWx);
return postWx;
}
}
4、controller层的调用部分
@RestController
@RequestMapping("/management/sTTCenter")
public class STTController extends AbstractBaseController {
@Value("${weChat.token.appid}")
private String appid;
@Value("${weChat.token.secret}")
private String appsecret;
@PostMapping("/STTParse")
public MonoDataBodyResponse<Object> audioToText(@RequestBody MultipartFile multipartFile) throws InterruptedException,WxErrorException {
AccessToken accessToken = WxApi.getAccessToken(appid, appsecret);
String accessTokenAccessToken = accessToken.getAccessToken();
JSONObject jsonObject = AudioToTextUtil.wxSTT(multipartFile, accessTokenAccessToken);
if(!Objects.isNull(jsonObject) && Objects.isNull(jsonObject.get("code"))){
Thread.sleep(500L);
String sttResult = AudioToTextUtil.wxSTTResult(accessTokenAccessToken, String.valueOf(jsonObject.get("id")));
JSONObject result = JSONObject.parseObject(sttResult);
return new MonoDataBodyResponse<Object>().addBody(result);
}
return new MonoDataBodyResponse<Object>().addBody(jsonObject);
}
}
到此,没有意外的话应该是可以实现上面说的语音转文字了。
更多推荐
所有评论(0)