Java 接入讯飞语音听写Speech to Text(STT)功能

article/2025/8/20 21:10:15

标题

    • 讯飞认证配置
    • 封装监听器
    • 客户端工具` Speech2TextClient.java `
    • 对外开放接口
    • 对外开放接口实现
    • 结果
    • 参考

根据官方提供的 WebIATWS 工具扩展修改,接入了讯飞的语音听写(STT)服务

讯飞认证配置

public class XFAuthorityConfig {public static final String hostUrl = "https://iat-api.xfyun.cn/v2/iat";public static final String apiKey = "xxxx";public static final String apiSecret = "xxx";public static final String appid = "5ede17d7";
}

封装监听器

public class WrapListener extends WebSocketListener {private static final Logger LOGGER = LoggerFactory.getLogger(WrapListener.class);// 下面三个参数是我根据需要新增的// file 是要听写的音频文件,而language 支持 zh-CN,en-US]// result 是返回结果private InputStream file;private String language;private String result;private String appId = XFConfig.appid;public static final int StatusFirstFrame = 0;public static final int StatusContinueFrame = 1;public static final int StatusLastFrame = 2;public static final Gson json = new Gson();Decoder decoder = new Decoder();// 开始时间private static Date dateBegin = new Date();// 结束时间private static Date dateEnd = new Date();private static final SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss.SSS");public InputStream getFile() {return file;}public void setFile(InputStream file) {this.file = file;}public String getLanguage() {return language;}public void setLanguage(String language) {this.language = language;}public String getResult() {return result;}public void setResult(String result) {this.result = result;}@Overridepublic void onOpen(WebSocket webSocket, Response response) {super.onOpen(webSocket, response);int frameSize = 1280;int intervel = 40;int status = 0;try {byte[] buffer = new byte[frameSize];// 发送音频end:while (true) {int len = file.read(buffer);if (len == -1) {status = StatusLastFrame;}switch (status) {case StatusFirstFrame:JsonObject frame = new JsonObject();JsonObject business = new JsonObject()JsonObject common = new JsonObject();JsonObject data = new JsonObject();// 填充commoncommon.addProperty("app_id", appId);//填充businessbusiness.addProperty("language", language);business.addProperty("domain", "iat");business.addProperty("accent", "mandarin");//中文方言请在控制台添加试用,添加后即展示相应参数值business.addProperty("dwa", "wpgs");data.addProperty("status", StatusFirstFrame);data.addProperty("format", "audio/L16;rate=8000");data.addProperty("encoding", "raw");data.addProperty("audio", Base64.getEncoder().encodeToString(Arrays.copyOf(buffer, len)));//填充frameframe.add("common", common);frame.add("business", business);frame.add("data", data);webSocket.send(frame.toString());status = StatusContinueFrame;  // 发送完第一帧改变status 为 1break;case StatusContinueFrame:  //中间帧status = 1JsonObject frame1 = new JsonObject();JsonObject data1 = new JsonObject();data1.addProperty("status", StatusContinueFrame);data1.addProperty("format", "audio/L16;rate=8000");data1.addProperty("encoding", "raw");data1.addProperty("audio", Base64.getEncoder().encodeToString(Arrays.copyOf(buffer, len)));frame1.add("data", data1);webSocket.send(frame1.toString());break;case StatusLastFrame:    // 最后一帧音频status = 2 ,标志音频发送结束JsonObject frame2 = new JsonObject();JsonObject data2 = new JsonObject();data2.addProperty("status", StatusLastFrame);data2.addProperty("audio", "");data2.addProperty("format", "audio/L16;rate=8000");data2.addProperty("encoding", "raw");frame2.add("data", data2);webSocket.send(frame2.toString());break end;}Thread.sleep(intervel);}LOGGER.info("all data is send");} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic void onMessage(WebSocket webSocket, String text) {super.onMessage(webSocket, text);ResponseData resp = json.fromJson(text, ResponseData.class);if (resp != null) {if (resp.getCode() != 0) {LOGGER.debug("code=>" + resp.getCode() + " error=>" + resp.getMessage() + " sid=" + resp.getSid());LOGGER.debug("错误码查询链接:https://www.xfyun.cn/document/error-code");return;}if (resp.getData() != null) {if (resp.getData().getResult() != null) {Text te = resp.getData().getResult().getText();try {decoder.decode(te);LOGGER.info("中间识别结果 ==》" + decoder.toString());} catch (Exception e) {e.printStackTrace();}}if (resp.getData().getStatus() == 2) {dateEnd = new Date();LOGGER.info(sdf.format(dateBegin) + "开始");LOGGER.info(sdf.format(dateEnd) + "结束");LOGGER.info("耗时:" + (dateEnd.getTime() - dateBegin.getTime()) + "ms");LOGGER.info("最终识别结果 ==》" + decoder.toString());this.result = decoder.toString();decoder.discard();webSocket.close(1000, "");} else {// todo 根据返回的数据处理}}}}@Overridepublic void onFailure(WebSocket webSocket, Throwable t, Response response) {super.onFailure(webSocket, t, response);try {if (null != response) {int code = response.code();LOGGER.info("onFailure code:" + code);LOGGER.info("onFailure body:" + response.body().string());if (101 != code) {LOGGER.debug("connection failed");System.exit(0);}}} catch (IOException e) {e.printStackTrace();}}public static class ResponseData {private int code;private String message;private String sid;private Data data;public int getCode() {return code;}public String getMessage() {return this.message;}public String getSid() {return sid;}public Data getData() {return data;}}public static class Data {private int status;private Result result;public int getStatus() {return status;}public Result getResult() {return result;}}public static class Result {int bg;int ed;String pgs;int[] rg;int sn;Ws[] ws;boolean ls;JsonObject vad;public Text getText() {Text text = new Text();StringBuilder sb = new StringBuilder();for (Ws ws : this.ws) {sb.append(ws.cw[0].w);}text.sn = this.sn;text.text = sb.toString();text.sn = this.sn;text.rg = this.rg;text.pgs = this.pgs;text.bg = this.bg;text.ed = this.ed;text.ls = this.ls;text.vad = this.vad == null ? null : this.vad;return text;}}public static class Ws {WebIATWS.Cw[] cw;int bg;int ed;}public static class Cw {int sc;String w;}public static class Text {int sn;int bg;int ed;String text;String pgs;int[] rg;boolean deleted;boolean ls;JsonObject vad;@Overridepublic String toString() {return "Text{" +"bg=" + bg +", ed=" + ed +", ls=" + ls +", sn=" + sn +", text='" + text + '\'' +", pgs=" + pgs +", rg=" + Arrays.toString(rg) +", deleted=" + deleted +", vad=" + (vad == null ? "null" : vad.getAsJsonArray("ws").toString()) +'}';}}public static class Decoder {private Text[] texts;private int defc = 10;public Decoder() {this.texts = new Text[this.defc];}public synchronized void decode(Text text) {if (text.sn >= this.defc) {this.resize();}if ("rpl".equals(text.pgs)) {for (int i = text.rg[0]; i <= text.rg[1]; i++) {this.texts[i].deleted = true;}}this.texts[text.sn] = text;}public String toString() {StringBuilder sb = new StringBuilder();for (Text t : this.texts) {if (t != null && !t.deleted) {sb.append(t.text);}}return sb.toString();}public void resize() {int oc = this.defc;this.defc <<= 1;Text[] old = this.texts;this.texts = new Text[this.defc];for (int i = 0; i < oc; i++) {this.texts[i] = old[i];}}public void discard() {for (int i = 0; i < this.texts.length; i++) {this.texts[i] = null;}}}}

客户端工具Speech2TextClient.java

@Component
public class Speech2TextClient {private String authUri;public Speech2TextClient() throws Exception {authUri = Speech2TextClient.getAuthUrl(XFConfig.hostUrl, XFConfig.apiKey, XFConfig.apiSecret);authUri = authUri.replace("http://", "ws://").replace("https://", "wss://");}public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {URL url = new URL(hostUrl);SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);format.setTimeZone(TimeZone.getTimeZone("GMT"));String date = format.format(new Date());StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").append("date: ").append(date).append("\n").append("GET ").append(url.getPath()).append(" HTTP/1.1");Charset charset = Charset.forName("UTF-8");Mac mac = Mac.getInstance("hmacsha256");SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");mac.init(spec);byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));String sha = Base64.getEncoder().encodeToString(hexDigits);String authorization =String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",apiKey, "hmac-sha256", "host date request-line", sha);HttpUrl httpUrl = HttpUrl.parse("https://" + url.getHost() + url.getPath()).newBuilder().addQueryParameter("authorization",Base64.getEncoder().encodeToString(authorization.getBytes(charset))).addQueryParameter("date", date).addQueryParameter("host", url.getHost()).build();return httpUrl.toString();}public String stt(InputStream is, String language) throws IOException, InterruptedException {OkHttpClient client = new OkHttpClient.Builder().build();Request request = new Request.Builder().url(authUri).build();WrapListener wrapListener = new WrapListener();wrapListener.setFile(is);wrapListener.setLanguage(language);WebSocket ws = client.newWebSocket(request, wrapListener);while (true) {if (wrapListener.getResult() != null) {return wrapListener.getResult();}Thread.sleep(500);// 因为监听器是异步的,需要返回结果}}
}

对外开放接口

@RequestMapping("/api/web/v2")
public interface CloudService {@PostMapping(value = "/xf/stt", consumes = "multipart/form-data")ResponseResult speech2TextByXf(@RequestParam("language") String language,@RequestPart("audio") MultipartFile audio);
}

对外开放接口实现

@RestController
public class CloudServiceImpl implements CloudService {/*** xf*/@AutowiredSpeech2TextClient speech2TextClient;@Overridepublic ResponseResult speech2TextByXf(String language, MultipartFile audio) {try {String text = speech2TextClient.stt(audio.getInputStream(), language);if (text == null) {return ResponseUtil.error("转换信息为空");}return ResponseUtil.ok(text);} catch (Exception e) {return ResponseUtil.error();}}}

结果

postman

好了,基本就到这里,具体的调优,去修改监听器和工具就可以了

参考

WebAPI 示例demo汇总(一)----语音听写(流式版)

语音听写(流式版)WebAPI 文档


http://chatgpt.dhexx.cn/article/0avVlyi9.shtml

相关文章

html5语音听写流式,iOS 讯飞语音听写(流式版)

最近项目中用到了讯飞的语音识别,然后稍微看了一下,里面有几个值得注意的点,记录一下,先说语音听写(流式版),实时语音转写后期会附上 ,文末有 demo //语音听写(流式版) 语音听写流式版其实没设么好说的,因为直接有 SDK,导入项目就可以了,需要注意的点就是每个创建的 APP 和 SDK…

科大讯飞语音听写(Android)

前面就不废话了&#xff0c;像申请应用&#xff0c;获取SDK等等&#xff0c;我相信大家应该都会的&#xff0c;科大讯飞采用的是两种语音听写功能,一种带有UI&#xff0c;一种没有UI&#xff0c;本人还是比较笨的&#xff0c;所以就写了较为简单的不带UI的语音听写&#xff0c;…

语音转写和语音听写_如何在Windows 10上使用语音听写

语音转写和语音听写 Windows 10’s Fall Creators Update makes voice dictation much easier to use. Now, you can immediately begin dictation by pressing a key WindowsH on your keyboard. You don’t have to dig through the Control Panel and set anything up first…

【超简单】之基于PaddleSpeech搭建个人语音听写服务

一、【超简单】之基于PaddleSpeech搭建个人语音听写服务 1.需求分析 亲们&#xff0c;你们要写会议纪要嘛&#xff1f;亲们&#xff0c;你们要写会议纪要嘛&#xff1f;亲们&#xff0c;你们要写会议纪要嘛&#xff1f; 当您面对成吨的会议录音&#xff0c;着急写会议纪要而…

遥感技术及高分遥感影像在地震中的应用及高分二号获取

长期以来&#xff0c;地震预报监测、灾害调查、灾情信息获取主要依靠实地勘测手段&#xff0c;其获取的数据精度和置信度虽然较高&#xff0c;但存在工作量大、效率低、费用高和信息不直观等缺点。遥感技术手段可在一定程度上克服传统实地勘测手段的缺点&#xff0c;并具有其他…

高分一号(GF-1)-中国高分辨率对地观测系统的第一颗卫星

2013年4月26日12时13分04秒由长征二号丁运载火箭成功发射&#xff0c;开启了中国对地观测的新时代。卫星全色分辨率是2米&#xff0c;多光谱分辨率为8米。高分一号卫星的宽幅多光谱相机幅宽达到了800公里。 “高分一号”的特点是增加了高分辨率多光谱相机&#xff0c;该相机的性…

历年(2017-2022)国产陆地观测卫星(高分1号2号6号等)外场绝对辐射定标系数

国产卫星绝对辐射定标系数&#xff08;2008——2022&#xff09; 2017年 参考博文&#xff1a;高分一号/二号/六号定标系数_desertsTsung的博客-CSDN博客

第059篇:高分二号遥感影像预处理流程(ENVI5.3.1平台+ENVI App Store中最新的中国国产卫星支持工具)

今天被袁老的新闻刷屏&#xff0c;湖南衡水县水稻基地传出好消息&#xff1a; 袁隆平团队第三代杂交水稻测产&#xff0c;测得晚稻平均亩产为911.7公斤 早稻晚稻实现亩产3061斤 伟大&#xff0c;除了伟大&#xff0c;不知道还能用什么词概括袁老的不凡成就&#xff01; 说到这…

envi5.3处理高分二号影像数据详细过程记录

目录 一、多光谱影像处理 1. 辐射定标 2.大气校正 1. 需要准备一些数据: 2.大气校正过程 3、正射校正 二、全色影像处理 1. 辐射定标 2. 正射校正 三、图像融合 1.几何配准 2.图像融合 高分二号处理流程 envi5.3的安装教程&#xff1a; ENVI5.3安装 安装完ENVI5.3后…

我国高分系列卫星遥感影像介绍

继上一篇介绍《遥感图像处理》的文章之后&#xff0c;本篇文章对我国的高分系列卫星遥感影像进行简单的整理。 高分系列卫星是在高分专项的支持下&#xff0c;也就是高分辨率对地观测系统重大专项&#xff0c;由国防科技工业局牵头&#xff0c;组织实施建设的一系列高分辨率对…

高分辨率遥感卫星影像在交通方面的应用及高分二号影像获取

高分辨率遥感影像在城市交通领域具有广泛的应用前景&#xff1a;如遥感交通调查、遥感影像地图与电子地图制作、道路工程地质遥感解译、交通安全与知道抗灾救灾、交通事故现场快速勘察、交通需求预测、车辆与车牌视频识别等等。高分辨率影像比如高分二号卫星、高分一号卫星&…

中国高分系列卫星介绍

中国高分系列卫星 中国高分系列卫星是"高分专项"所规划的高分辨率对地观测的系列卫星。它是《国家中长期科学和技术发展规划纲要&#xff08;2006&#xff5e;2020年&#xff09;》所确定的16个重大专项之一。由于课程汇报&#xff0c;所以作了一个PPT&#xff0c;在…

高分二号(GF-2)号卫星数据的查询下载地址和方法

高分二号卫星是我国自主研制的首颗空间分辨优于1米的民用光学遥感卫星可在平台中查询到&#xff0c;搭载有两台高分辨率1米全色、4米多光谱相机&#xff0c;具有亚米级空间分辨率、高定位精度和快速姿态机动能力等特点&#xff0c;有效地提升了卫星综合观测效能&#xff0c;达到…

遥感科普|中国高分系列卫星综述(2020版)

遥感科普|中国高分系列卫星综述(2020版) 文章来源&#xff1a;卫星遥感大数据公众号 高分系列卫星概述 中国高分系列卫星是"高分专项"所规划的高分辨率对地观测的系列卫星。它是《国家中长期科学和技术发展规划纲要&#xff08;2006&#xff5e;2020年&#xff09…

国产高分系列卫星平台介绍

目录 高分专项 高分一号&#xff08;GF-1&#xff09; 高分二号&#xff08;GF-2&#xff09; 高分三号&#xff08;GF-3) 高分四号&#xff08;GF-4&#xff09; 高分五号&#xff08;GF-5) 高分六号&#xff08;GF-6&#xff09; 高分七号&#xff08;GF-7&#xff09; 高分八…

高分三号卫星介绍

博主现在要用到高分三号卫星&#xff0c;但是因为高三2016年8月才发射&#xff0c;目前网上相关资料较少&#xff0c;便总结了一些相关信息&#xff0c;希望能为大家提供帮助~ 传感器 高分三号卫星搭载的传感器是C频段多极化合成孔径雷达&#xff0c;是迄今为止世界上成像模式…

法国Pleiades高分卫星/遥感影像/卫星影像/高分二号影像

引言 Pliades高分辨率卫星星座由2颗完全相同的卫星Pliades 1和Pliades 2组成。Pliades 1已于2011 年 12 月17 日成功发射并开始商业运营&#xff0c; Pliades2 于2012年12月1日成功发射并已成功获取第一幅影像。双星配合可实现全球任意地区的每日重访&#xff0c;最快速满足客户…

c语言中d1的分辨率是,高分一号(GF-1)、高分一号B、C、D星 卫星介绍

原标题&#xff1a;高分一号(GF-1)、高分一号B、C、D星 卫星介绍 高分一号卫星全色分辨率2米&#xff0c;多光谱分辨率8米。高分一号是国家高分辨率对地观测系统重大专项天基系统中的首发星&#xff0c;其主要目的是突破高空间分辨率、多光谱与高时间分辨率结合的光学遥感技术&…

使用ERDAS对国产卫星影像进行控制点正射校正—以高分二号卫星(GF2)为例

** 使用ERDAS对国产卫星影像进行控制点正射校正—以高分二号卫星(GF2)为例 ** 一、研究区影像: 1.1.高分二号原始影像 影像为山西介休市的一景获取时间为2019.01.22的GF2影像: 1.2.参考影像 参考影像为往期的该区域的DOM成果: 二、高分二号全色数据正射校正: 首…

天津市高分二号卫星影像获取/高分一号卫星影像

天津&#xff0c;简称津&#xff0c;地处太平洋西岸&#xff0c;华北平原东北部&#xff0c;海河流域下游&#xff0c;东临渤海&#xff0c;北依燕山&#xff0c;西靠首都北京&#xff0c;中华人民共和国直辖市&#xff0c;截止2021年1月27日天津市土地总面积11966.45平方公里&…