找回密码
 立即注册
首页 业界区 科技 语音识别服务funasr搭建

语音识别服务funasr搭建

窝酴 前天 12:30
<p>本文讨论语音识别功能,使用的是阿里的开源语音识别项目FunASR,含两种部署方式,社区windows版和docker容器化部署,windows社区版的可以用于本地开发使用,生产环境建议使用容器版。</p>
<h2>1、windows社区版部署</h2>
<h3>  1.1、环境安装</h3>
<p>    软件需要Visual Studio 2022 c++环境,如果没有Visual Studio 2022 c++运行环境,双击 VC_redist.x64(2022).exe 安装 Visual Studio 2022环境下编译的C++程序运行所需要的库。</p>
<h3>   1.2、下载windows社区软件包<br></h3>
<p>    https://www.modelscope.cn/models/iic/funasr-runtime-win-cpu-x64/files</p>
<p>    
<img alt="image" width="1253" height="478" loading="lazy" data-src="https://img2024.cnblogs.com/blog/1607557/202512/1607557-20251226091034169-345184089.png" >
</p>
<p>    随便选个版本的下载,这里选择的是0.2.0版本</p>
<h3>   1.3、下载所需模型</h3>
  1. git clone https://www.modelscope.cn/damo/speech_fsmn_vad_zh-cn-16k-common-onnx.git;
  2. git clone https://www.modelscope.cn/damo/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-onnx.git;
  3. git clone https://www.modelscope.cn/damo/speech_ngram_lm_zh-cn-ai-wesp-fst.git;
  4. git clone https://www.modelscope.cn/damo/punc_ct-transformer_cn-en-common-vocab471067-large-onnx.git;
  5. git clone https://www.modelscope.cn/thuduj12/fst_itn_zh.git
复制代码

<h3>   1.4、启动服务</h3>
<p>     将上面下载的windows社区软件包解压后,打开powershell,进入到解压后的目录,执行下面的命令</p>
  1. ./funasr-wss-server.exe  
  2. --vad-dir D:/developTest/funasr-runtime-resources/models/speech_fsmn_vad_zh-cn-16k-common-onnx
  3. --model-dir D:/developTest/funasr-runtime-resources/models/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-onnx
  4. --lm-dir D:/developTest/funasr-runtime-resources/models/speech_ngram_lm_zh-cn-ai-wesp-fst  
  5. --punc-dir D:/developTest/funasr-runtime-resources/models/punc_ct-transformer_cn-en-common-vocab471067-large-onnx
  6. --itn-dir D:/developTest/funasr-runtime-resources/models/fst_itn_zh
  7. --certfile 0
复制代码

<p>    参数说明:</p>
  1. --model-dir  modelscope model ID 或者 本地模型路径
  2. --vad-dir  modelscope model ID 或者 本地模型路径
  3. --punc-dir  modelscope model ID 或者 本地模型路径
  4. --lm-dir modelscope model ID 或者 本地模型路径
  5. --itn-dir modelscope model ID 或者 本地模型路径
  6. --certfile  ssl的证书文件,如果需要关闭ssl,参数设置为0
复制代码

<h3>   1.5、客户端调用</h3>
<p>    在windows社区版的解压目录下有客户端执行文件funasr-wss-client.exe</p>
  1. ./funasr-wss-client.exe --server-ip 127.0.0.1 --port 10095 --wav-path asr_example_zh.wav
复制代码

<p>    服务默认端口是10095,--wav-path指定音频文件地址</p>
<h2>2、docker容器化部署</h2>
<h3>   2.1、拉取docker镜像</h3>
  1. docker pull registry.cn-hangzhou.aliyuncs.com/funasr_repo/funasr:funasr-runtime-sdk-cpu-0.4.6
复制代码

<h3>   2.2、启动容器</h3>
<p>    在宿主机创建模型目录放置模型,这里的模型建议手动下载,就用上面的git下载下来,如果使用启动命令自动下载会很慢很卡。</p>
  1. docker run -p 10095:10095 -it --privileged=true -v D:\developTest\funasr-runtime-resources\models:/workspace/models registry.cn-hangzhou.aliyuncs.com/funasr_repo/funasr:funasr-runtime-sdk-cpu-0.4.6
复制代码

<p>    映射容器端口,挂载之前创建的存放模型目录到容器内部。</p>
<h3>   2.3、启动服务</h3>
<p>    进入容器内部,进到FunASR/runtime目录下</p>
<p>    
<img alt="image" loading="lazy" data-src="https://img2024.cnblogs.com/blog/1607557/202512/1607557-20251226092232599-408304639.png" >
</p>
<p>     执行如下命令启动服务</p>
  1. nohup bash run_server.sh \
  2.   --certfile 0 \
  3.   --vad-dir speech_fsmn_vad_zh-cn-16k-common-onnx \
  4.   --model-dir speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-onnx   \
  5.   --punc-dir punc_ct-transformer_cn-en-common-vocab471067-large-onnx  \
  6.   --lm-dir speech_ngram_lm_zh-cn-ai-wesp-fst \
  7.   --itn-dir fst_itn_zh  > log.txt 2>&1 &
复制代码

<p>    指定模型目录,这里的模型都是事先下载好的,就不需要通过启动命令下载了,certfile设为0,表示关闭ssl。</p>
<h2>3、调用示例</h2>
<p>  这里大致写了两种java调用方式一种是通过ProcessBuilder,一种是WebSocketClient,大家可以用来看看。</p>

<ul >
<li id="u0a0bed12" data-lake-index-type="0">使用ProcessBuilder,运行上面的客户端执行命令,获取执行结果</li>
</ul>
<img id="code_img_closed_ee8da724-9620-48b4-9e11-58304394a99c"  data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif">
<img id="code_img_opened_ee8da724-9620-48b4-9e11-58304394a99c"   data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">

  1. public String localTranslation(MultipartRequest multipartRequest) {
  2.         StringBuffer resultBuffer = new StringBuffer();
  3.         // 需要传递给exe程序的参数
  4.         String exePath = "D:\\developTest\\funasr-runtime-resources\\funasr-runtime-win-cpu-x64\\funasr-runtime-win-cpu-x64-v0.2.0\\funasr-wss-client.exe";
  5.         String serveIp = "127.0.0.1"; // 假设你想要设置的IP地址
  6.         String port = "10095";
  7.         File targetFile = null;
  8.         try {
  9.             MultipartFile mFile = multipartRequest.getFile("file");
  10.             File dir = new File("D:\\developTest\\funasr-runtime-resources\\wav");
  11.             if (!dir.exists()) {
  12.                 dir.mkdirs();
  13.             }
  14.             targetFile = File.createTempFile("tmp_", ".wav", dir);
  15.             mFile.transferTo(targetFile);
  16.             String wavPath = "D:\\developTest\\funasr-runtime-resources\\wav\"+ targetFile.getName();
  17.             String[] cmd = new String[]{exePath, "--server-ip", serveIp, "--port", port, "--wav-path", wavPath};
  18.             ProcessBuilder pb = new ProcessBuilder();
  19.             pb.command(cmd);
  20.             Process process = pb.start();
  21.             //超时时间
  22.             int timeoutSeconds = 30;//超时30秒自动断开
  23.             //创建单线程线程池
  24.             ExecutorService executor = Executors.newSingleThreadExecutor();
  25.             Future<?> future = executor.submit(() -> {
  26.                 try {
  27.                     pb.redirectErrorStream(true);
  28.                     // 读取外部程序的输出
  29.                     BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
  30.                     String line;
  31.                     while ((line = reader.readLine()) != null) {
  32.                         System.out.println(line);
  33.                         resultBuffer.append(line);
  34.                     }
  35.                     // 处理错误输出
  36.                     BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
  37.                     while ((line = errorReader.readLine()) != null) {
  38.                         System.out.println(line);
  39.                         if(line.contains("on_message")){
  40.                             String[] array = line.split("on_message =");
  41.                             resultBuffer.append(array[1]);
  42.                         }
  43.                     }
  44.                     // 等待程序执行完成
  45.                     process.waitFor();
  46.                 } catch (Exception e) {
  47.                     e.printStackTrace();
  48.                 }finally {
  49.                     if(process.isAlive()){
  50.                         process.destroy();
  51.                     }
  52.                 }
  53.             });
  54.             try {
  55.                 // 等待进程完成或超时
  56.                 future.get(timeoutSeconds, TimeUnit.SECONDS);
  57.                 System.out.println("进程在规定时间内完成。");
  58.             } catch (Exception e) {
  59.                 System.out.println("超时预警: 进程可能挂起。");
  60.                 resultBuffer.append("timeout");
  61.             } finally {
  62.                 //关闭连接
  63.                 if(process.isAlive()){
  64.                     process.destroy();
  65.                 }
  66.                 executor.shutdownNow(); // 取消任务并关闭线程池
  67.             }
  68.         } catch (Exception e) {
  69.             e.printStackTrace();
  70.             resultBuffer.append("error");
  71.         }finally {
  72.             if (targetFile.exists()) {
  73.                 targetFile.delete();
  74.             }
  75.         }
  76.         System.out.println(resultBuffer.toString());
  77.         return resultBuffer.toString();
  78.     }
复制代码

View Code

<ul >
<li id="u199a6f15" data-lake-index-type="0">使用WebSocketClient直接调用FunASR服务</li>
</ul>
<p>  Client工具类</p>
<img id="code_img_closed_b0c7855c-8229-4a70-a43a-7df98e723287"  data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif">
<img id="code_img_opened_b0c7855c-8229-4a70-a43a-7df98e723287"   data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">

  1. package com.example.demo1.web;
  2. import java.io.*;
  3. import java.net.URI;
  4. import java.util.Map;
  5. import org.java_websocket.client.WebSocketClient;
  6. import org.java_websocket.drafts.Draft;
  7. import org.java_websocket.handshake.ServerHandshake;
  8. import org.json.simple.JSONArray;
  9. import org.json.simple.JSONObject;
  10. import org.json.simple.parser.JSONParser;
  11. import org.slf4j.Logger;
  12. import org.slf4j.LoggerFactory;
  13. import java.util.regex.Matcher;
  14. import java.util.regex.Pattern;
  15. public class FunasrWsClient extends WebSocketClient {
  16.     private static final Logger logger = LoggerFactory.getLogger(FunasrWsClient.class);
  17.     private boolean iseof = false;
  18.     private static String wavPath;
  19.     private static String mode = "offline";
  20.     private static String strChunkSize = "5,10,5";
  21.     private static int chunkInterval = 10;
  22.     private static int sendChunkSize = 1920;
  23.     private static String hotwords="";
  24.     private static String fsthotwords="";
  25.     private String wavName = "javatest";
  26.     private MyCallBack callBack;
  27.     public FunasrWsClient(URI serverUri,MyCallBack callBack) {
  28.         super(serverUri);
  29.         this.callBack = callBack;
  30.     }
  31.     public FunasrWsClient(URI serverUri,String wavPath,MyCallBack callBack) {
  32.         super(serverUri);
  33.         this.callBack = callBack;
  34.         this.wavPath = wavPath;
  35.     }
  36.     public FunasrWsClient(URI serverUri,String strChunkSize,int chunkInterval,String mode,String hotwords,String wavPath,MyCallBack callBack) {
  37.         super(serverUri);
  38.         this.callBack = callBack;
  39.         this.strChunkSize = strChunkSize;
  40.         this.chunkInterval = chunkInterval;
  41.         this.mode = mode;
  42.         this.fsthotwords = hotwords;
  43.         this.wavPath = wavPath;
  44.         int RATE = 16000;
  45.         String[] chunkList = strChunkSize.split(",");
  46.         int int_chunk_size = 60 * Integer.valueOf(chunkList[1].trim()) / chunkInterval;
  47.         int CHUNK = Integer.valueOf(RATE / 1000 * int_chunk_size);
  48.         this.sendChunkSize = CHUNK * 2;
  49.     }
  50.     public class RecWavThread extends Thread {
  51.         private FunasrWsClient funasrClient;
  52.         public RecWavThread(FunasrWsClient funasrClient) {
  53.             this.funasrClient = funasrClient;
  54.         }
  55.         public void run() {
  56.             this.funasrClient.recWav();
  57.         }
  58.     }
  59.     public FunasrWsClient(URI serverUri, Draft draft) {
  60.         super(serverUri, draft);
  61.     }
  62.     public FunasrWsClient(URI serverURI) {
  63.         super(serverURI);
  64.     }
  65.     public FunasrWsClient(URI serverUri, Map<String, String> httpHeaders) {
  66.         super(serverUri, httpHeaders);
  67.     }
  68.     public void getSslContext(String keyfile, String certfile) {
  69.         // TODO
  70.         return;
  71.     }
  72.     public void sendJson(
  73.         String mode, String strChunkSize, int chunkInterval, String wavName, boolean isSpeaking,String suffix) {
  74.         try {
  75.             JSONObject obj = new JSONObject();
  76.             obj.put("mode", mode);
  77.             JSONArray array = new JSONArray();
  78.             String[] chunkList = strChunkSize.split(",");
  79.             for (int i = 0; i < chunkList.length; i++) {
  80.                 array.add(Integer.valueOf(chunkList[i].trim()));
  81.             }
  82.             obj.put("chunk_size", array);
  83.             obj.put("chunk_interval", new Integer(chunkInterval));
  84.             obj.put("wav_name", wavName);
  85.             if(FunasrWsClient.hotwords.trim().length()>0)
  86.             {
  87.                 String regex = "\\d+";
  88.                 JSONObject jsonitems = new JSONObject();
  89.                 String[] items=FunasrWsClient.hotwords.trim().split(" ");
  90.                 Pattern pattern = Pattern.compile(regex);
  91.                 String tmpWords="";
  92.                 for(int i=0;i<items.length;i++)
  93.                 {
  94.                     Matcher matcher = pattern.matcher(items[i]);
  95.                     if (matcher.matches()) {
  96.                         jsonitems.put(tmpWords.trim(), items[i].trim());
  97.                         tmpWords="";
  98.                         continue;
  99.                     }
  100.                     tmpWords=tmpWords+items[i]+" ";
  101.                 }
  102.                 obj.put("hotwords", jsonitems.toString());
  103.             }
  104.             if(suffix.equals("wav")){
  105.                 suffix="pcm";
  106.             }
  107.             obj.put("wav_format", suffix);
  108.             if (isSpeaking) {
  109.                 obj.put("is_speaking", new Boolean(true));
  110.             } else {
  111.                 obj.put("is_speaking", new Boolean(false));
  112.             }
  113.             logger.info("sendJson: " + obj);
  114.             // return;
  115.             send(obj.toString());
  116.             return;
  117.         } catch (Exception e) {
  118.             e.printStackTrace();
  119.         }
  120.     }
  121.     public void sendEof() {
  122.         try {
  123.             JSONObject obj = new JSONObject();
  124.             obj.put("is_speaking", new Boolean(false));
  125.             logger.info("sendEof: " + obj);
  126.             // return;
  127.             send(obj.toString());
  128.             iseof = true;
  129.             return;
  130.         } catch (Exception e) {
  131.             e.printStackTrace();
  132.         }
  133.     }
  134.    
  135.     public void recWav() {
  136.         String fileName=FunasrWsClient.wavPath;
  137.         String suffix=fileName.split("\\.")[fileName.split("\\.").length-1];
  138.         sendJson(mode, strChunkSize, chunkInterval, wavName, true,suffix);
  139.         File file = new File(FunasrWsClient.wavPath);
  140.         int chunkSize = sendChunkSize;
  141.         byte[] bytes = new byte[chunkSize];
  142.         int readSize = 0;
  143.         try (FileInputStream fis = new FileInputStream(file)) {
  144.             if (FunasrWsClient.wavPath.endsWith(".wav")) {
  145.                 fis.read(bytes, 0, 44);
  146.             }
  147.             readSize = fis.read(bytes, 0, chunkSize);
  148.             while (readSize > 0) {
  149.                 if (readSize == chunkSize) {
  150.                     send(bytes);
  151.                 } else {
  152.                     byte[] tmpBytes = new byte[readSize];
  153.                     for (int i = 0; i < readSize; i++) {
  154.                         tmpBytes[i] = bytes[i];
  155.                     }
  156.                     send(tmpBytes);
  157.                 }
  158.                
  159.                 if (!mode.equals("offline")) {
  160.                     Thread.sleep(Integer.valueOf(chunkSize / 32));
  161.                 }
  162.                 readSize = fis.read(bytes, 0, chunkSize);
  163.             }
  164.             if (!mode.equals("offline")) {
  165.                 Thread.sleep(2000);
  166.                 sendEof();
  167.                 Thread.sleep(3000);
  168.                 close();
  169.             } else {
  170.                 sendEof();
  171.             }
  172.         } catch (Exception e) {
  173.             e.printStackTrace();
  174.         }
  175.     }
  176.     @Override
  177.     public void onOpen(ServerHandshake handshakedata) {
  178.         RecWavThread thread = new RecWavThread(this);
  179.         thread.start();
  180.     }
  181.     @Override
  182.     public void onMessage(String message) {
  183.         JSONObject jsonObject = new JSONObject();
  184.         JSONParser jsonParser = new JSONParser();
  185.         logger.info("received: " + message);
  186.         try {
  187.             jsonObject = (JSONObject) jsonParser.parse(message);
  188.             logger.info("text: " + jsonObject.get("text"));
  189.             callBack.callBack(jsonObject.get("text"));
  190.             if(jsonObject.containsKey("timestamp"))
  191.             {
  192.                 logger.info("timestamp: " + jsonObject.get("timestamp"));
  193.             }
  194.         } catch (org.json.simple.parser.ParseException e) {
  195.             e.printStackTrace();
  196.         }
  197.         if (iseof && mode.equals("offline") && !jsonObject.containsKey("is_final")) {
  198.             close();
  199.         }
  200.         if (iseof && mode.equals("offline") && jsonObject.containsKey("is_final") && jsonObject.get("is_final").equals("false")) {
  201.             close();
  202.         }
  203.     }
  204.     @Override
  205.     public void onClose(int code, String reason, boolean remote) {
  206.         logger.info(
  207.                 "Connection closed by "
  208.                         + (remote ? "remote peer" : "us")
  209.                         + " Code: "
  210.                         + code
  211.                         + " Reason: "
  212.                         + reason);
  213.     }
  214.     @Override
  215.     public void onError(Exception ex) {
  216.         logger.info("ex: " + ex);
  217.         ex.printStackTrace();
  218.     }
  219. }
复制代码

View Code
  调用工具类

<img id="code_img_closed_2af70ca2-29d6-46e7-92ec-d8fd7d13b2df"  data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif">
<img id="code_img_opened_2af70ca2-29d6-46e7-92ec-d8fd7d13b2df"   data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">

  1. public static void main(String[] args) throws URISyntaxException {
  2.     String srvIp = "localhost";
  3.     String srvPort = "10095";
  4.     String wavPath = "D:\\developTest\\funasr-runtime-resources\\wav\\tmp_84677349854990998.wav";
  5.     Object lock = new Object();
  6.     StringBuffer text = new StringBuffer();
  7.     ExecutorService executor = Executors.newSingleThreadExecutor();
  8.     Future<?> future = executor.submit(()->{
  9.         try {
  10.             String wsAddress = "ws://" + srvIp + ":" + srvPort;
  11.             FunasrWsClient c = new FunasrWsClient(new URI(wsAddress),wavPath,new MyCallBack(){
  12.                 @Override
  13.                 public void callBack(Object obj){
  14.                     text.append(obj.toString());
  15.                     synchronized (lock){
  16.                         try {
  17.                             lock.notify();
  18.                         }catch (Exception e){
  19.                             e.printStackTrace();
  20.                         }
  21.                     }
  22.                 }
  23.             });
  24.             synchronized (lock){
  25.                 c.connect();
  26.                 lock.wait();
  27.             }
  28.         }catch (Exception e){
  29.             // e.printStackTrace();
  30.         }
  31.     });
  32.     try {
  33.         future.get(10, TimeUnit.SECONDS);
  34.         System.out.println("规定时间内完成");
  35.     }catch (Exception e){
  36.         // e.printStackTrace();
  37.         System.out.println("任务超时");
  38.         text.append("任务超时");
  39.     }finally {
  40.         executor.shutdownNow(); // 取消任务并关闭线程池
  41.     }
  42.     System.out.println(text.toString());
  43. }
复制代码

View Code
<p> </p>


<p> </p>



<p> </p><br>来源:程序园用户自行投稿发布,如果侵权,请联系站长删除<br>免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册