chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,398 @@
|
||||
//
|
||||
// Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights
|
||||
// Reserved. MIT License (https://opensource.org/licenses/MIT)
|
||||
//
|
||||
/*
|
||||
* // 2022-2023 by zhaomingwork@qq.com
|
||||
*/
|
||||
// java FunasrWsClient
|
||||
// usage: FunasrWsClient [-h] [--port PORT] [--host HOST] [--audio_in AUDIO_IN] [--num_threads NUM_THREADS]
|
||||
// [--chunk_size CHUNK_SIZE] [--chunk_interval CHUNK_INTERVAL] [--mode MODE]
|
||||
package websocket;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.*;
|
||||
import java.util.Map;
|
||||
import net.sourceforge.argparse4j.ArgumentParsers;
|
||||
import net.sourceforge.argparse4j.inf.ArgumentParser;
|
||||
import net.sourceforge.argparse4j.inf.ArgumentParserException;
|
||||
import net.sourceforge.argparse4j.inf.Namespace;
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
import org.java_websocket.drafts.Draft;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
/** This example demonstrates how to connect to websocket server. */
|
||||
public class FunasrWsClient extends WebSocketClient {
|
||||
|
||||
public class RecWavThread extends Thread {
|
||||
private FunasrWsClient funasrClient;
|
||||
|
||||
public RecWavThread(FunasrWsClient funasrClient) {
|
||||
this.funasrClient = funasrClient;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
this.funasrClient.recWav();
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FunasrWsClient.class);
|
||||
|
||||
public FunasrWsClient(URI serverUri, Draft draft) {
|
||||
super(serverUri, draft);
|
||||
}
|
||||
|
||||
public FunasrWsClient(URI serverURI) {
|
||||
|
||||
super(serverURI);
|
||||
}
|
||||
|
||||
public FunasrWsClient(URI serverUri, Map<String, String> httpHeaders) {
|
||||
super(serverUri, httpHeaders);
|
||||
}
|
||||
|
||||
public void getSslContext(String keyfile, String certfile) {
|
||||
// TODO
|
||||
return;
|
||||
}
|
||||
|
||||
// send json at first time
|
||||
public void sendJson(
|
||||
String mode, String strChunkSize, int chunkInterval, String wavName, boolean isSpeaking,String suffix) {
|
||||
try {
|
||||
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("mode", mode);
|
||||
JSONArray array = new JSONArray();
|
||||
String[] chunkList = strChunkSize.split(",");
|
||||
for (int i = 0; i < chunkList.length; i++) {
|
||||
array.add(Integer.valueOf(chunkList[i].trim()));
|
||||
}
|
||||
|
||||
obj.put("chunk_size", array);
|
||||
obj.put("chunk_interval", new Integer(chunkInterval));
|
||||
obj.put("wav_name", wavName);
|
||||
|
||||
if(FunasrWsClient.hotwords.trim().length()>0)
|
||||
{
|
||||
String regex = "\\d+";
|
||||
JSONObject jsonitems = new JSONObject();
|
||||
String[] items=FunasrWsClient.hotwords.trim().split(" ");
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
String tmpWords="";
|
||||
for(int i=0;i<items.length;i++)
|
||||
{
|
||||
|
||||
Matcher matcher = pattern.matcher(items[i]);
|
||||
|
||||
if (matcher.matches()) {
|
||||
|
||||
jsonitems.put(tmpWords.trim(), items[i].trim());
|
||||
tmpWords="";
|
||||
continue;
|
||||
}
|
||||
tmpWords=tmpWords+items[i]+" ";
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
obj.put("hotwords", jsonitems.toString());
|
||||
}
|
||||
|
||||
if(suffix.equals("wav")){
|
||||
suffix="pcm";
|
||||
}
|
||||
obj.put("wav_format", suffix);
|
||||
if (isSpeaking) {
|
||||
obj.put("is_speaking", new Boolean(true));
|
||||
} else {
|
||||
obj.put("is_speaking", new Boolean(false));
|
||||
}
|
||||
logger.info("sendJson: " + obj);
|
||||
// return;
|
||||
|
||||
send(obj.toString());
|
||||
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// send json at end of wav
|
||||
public void sendEof() {
|
||||
try {
|
||||
JSONObject obj = new JSONObject();
|
||||
|
||||
obj.put("is_speaking", new Boolean(false));
|
||||
|
||||
logger.info("sendEof: " + obj);
|
||||
// return;
|
||||
|
||||
send(obj.toString());
|
||||
iseof = true;
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// function for rec wav file
|
||||
public void recWav() {
|
||||
String fileName=FunasrWsClient.wavPath;
|
||||
String suffix=fileName.split("\\.")[fileName.split("\\.").length-1];
|
||||
sendJson(mode, strChunkSize, chunkInterval, wavName, true,suffix);
|
||||
File file = new File(FunasrWsClient.wavPath);
|
||||
|
||||
int chunkSize = sendChunkSize;
|
||||
byte[] bytes = new byte[chunkSize];
|
||||
|
||||
int readSize = 0;
|
||||
try (FileInputStream fis = new FileInputStream(file)) {
|
||||
if (FunasrWsClient.wavPath.endsWith(".wav")) {
|
||||
fis.read(bytes, 0, 44); //skip first 44 wav header
|
||||
}
|
||||
readSize = fis.read(bytes, 0, chunkSize);
|
||||
while (readSize > 0) {
|
||||
// send when it is chunk size
|
||||
if (readSize == chunkSize) {
|
||||
send(bytes); // send buf to server
|
||||
|
||||
} else {
|
||||
// send when at last or not is chunk size
|
||||
byte[] tmpBytes = new byte[readSize];
|
||||
for (int i = 0; i < readSize; i++) {
|
||||
tmpBytes[i] = bytes[i];
|
||||
}
|
||||
send(tmpBytes);
|
||||
}
|
||||
// if not in offline mode, we simulate online stream by sleep
|
||||
if (!mode.equals("offline")) {
|
||||
Thread.sleep(Integer.valueOf(chunkSize / 32));
|
||||
}
|
||||
|
||||
readSize = fis.read(bytes, 0, chunkSize);
|
||||
}
|
||||
|
||||
if (!mode.equals("offline")) {
|
||||
// if not offline, we send eof and wait for 3 seconds to close
|
||||
Thread.sleep(2000);
|
||||
sendEof();
|
||||
Thread.sleep(3000);
|
||||
close();
|
||||
} else {
|
||||
// if offline, just send eof
|
||||
sendEof();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(ServerHandshake handshakedata) {
|
||||
|
||||
RecWavThread thread = new RecWavThread(this);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String message) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
JSONParser jsonParser = new JSONParser();
|
||||
logger.info("received: " + message);
|
||||
try {
|
||||
jsonObject = (JSONObject) jsonParser.parse(message);
|
||||
logger.info("text: " + jsonObject.get("text"));
|
||||
if(jsonObject.containsKey("timestamp"))
|
||||
{
|
||||
logger.info("timestamp: " + jsonObject.get("timestamp"));
|
||||
}
|
||||
} catch (org.json.simple.parser.ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (iseof && mode.equals("offline") && !jsonObject.containsKey("is_final")) {
|
||||
close();
|
||||
}
|
||||
|
||||
if (iseof && mode.equals("offline") && jsonObject.containsKey("is_final") && jsonObject.get("is_final").equals("false")) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int code, String reason, boolean remote) {
|
||||
|
||||
logger.info(
|
||||
"Connection closed by "
|
||||
+ (remote ? "remote peer" : "us")
|
||||
+ " Code: "
|
||||
+ code
|
||||
+ " Reason: "
|
||||
+ reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception ex) {
|
||||
logger.info("ex: " + ex);
|
||||
ex.printStackTrace();
|
||||
// if the error is fatal then onClose will be called additionally
|
||||
}
|
||||
|
||||
private boolean iseof = false;
|
||||
public static String wavPath;
|
||||
static String mode = "online";
|
||||
static String strChunkSize = "5,10,5";
|
||||
static int chunkInterval = 10;
|
||||
static int sendChunkSize = 1920;
|
||||
static String hotwords="";
|
||||
static String fsthotwords="";
|
||||
|
||||
String wavName = "javatest";
|
||||
|
||||
public static void main(String[] args) throws URISyntaxException {
|
||||
ArgumentParser parser = ArgumentParsers.newArgumentParser("ws client").defaultHelp(true);
|
||||
parser
|
||||
.addArgument("--port")
|
||||
.help("Port on which to listen.")
|
||||
.setDefault("8889")
|
||||
.type(String.class)
|
||||
.required(false);
|
||||
parser
|
||||
.addArgument("--host")
|
||||
.help("the IP address of server.")
|
||||
.setDefault("127.0.0.1")
|
||||
.type(String.class)
|
||||
.required(false);
|
||||
parser
|
||||
.addArgument("--audio_in")
|
||||
.help("wav path for decoding.")
|
||||
.setDefault("asr_example.wav")
|
||||
.type(String.class)
|
||||
.required(false);
|
||||
parser
|
||||
.addArgument("--num_threads")
|
||||
.help("num of threads for test.")
|
||||
.setDefault(1)
|
||||
.type(Integer.class)
|
||||
.required(false);
|
||||
parser
|
||||
.addArgument("--chunk_size")
|
||||
.help("chunk size for asr.")
|
||||
.setDefault("5, 10, 5")
|
||||
.type(String.class)
|
||||
.required(false);
|
||||
parser
|
||||
.addArgument("--chunk_interval")
|
||||
.help("chunk for asr.")
|
||||
.setDefault(10)
|
||||
.type(Integer.class)
|
||||
.required(false);
|
||||
|
||||
parser
|
||||
.addArgument("--mode")
|
||||
.help("mode for asr.")
|
||||
.setDefault("offline")
|
||||
.type(String.class)
|
||||
.required(false);
|
||||
parser
|
||||
.addArgument("--hotwords")
|
||||
.help("hotwords, splited by space, hello 30 nihao 40")
|
||||
.setDefault("")
|
||||
.type(String.class)
|
||||
.required(false);
|
||||
String srvIp = "";
|
||||
String srvPort = "";
|
||||
String wavPath = "";
|
||||
int numThreads = 1;
|
||||
String chunk_size = "";
|
||||
int chunk_interval = 10;
|
||||
String strmode = "offline";
|
||||
String hot="";
|
||||
try {
|
||||
Namespace ns = parser.parseArgs(args);
|
||||
srvIp = ns.get("host");
|
||||
srvPort = ns.get("port");
|
||||
wavPath = ns.get("audio_in");
|
||||
numThreads = ns.get("num_threads");
|
||||
chunk_size = ns.get("chunk_size");
|
||||
chunk_interval = ns.get("chunk_interval");
|
||||
strmode = ns.get("mode");
|
||||
hot=ns.get("hotwords");
|
||||
System.out.println(srvPort);
|
||||
|
||||
} catch (ArgumentParserException ex) {
|
||||
ex.getParser().handleError(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
FunasrWsClient.strChunkSize = chunk_size;
|
||||
FunasrWsClient.chunkInterval = chunk_interval;
|
||||
FunasrWsClient.wavPath = wavPath;
|
||||
FunasrWsClient.mode = strmode;
|
||||
FunasrWsClient.hotwords=hot;
|
||||
System.out.println(
|
||||
"serIp="
|
||||
+ srvIp
|
||||
+ ",srvPort="
|
||||
+ srvPort
|
||||
+ ",wavPath="
|
||||
+ wavPath
|
||||
+ ",strChunkSize"
|
||||
+ strChunkSize);
|
||||
|
||||
class ClientThread implements Runnable {
|
||||
|
||||
String srvIp;
|
||||
String srvPort;
|
||||
|
||||
ClientThread(String srvIp, String srvPort, String wavPath) {
|
||||
this.srvIp = srvIp;
|
||||
this.srvPort = srvPort;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
|
||||
int RATE = 16000;
|
||||
String[] chunkList = strChunkSize.split(",");
|
||||
int int_chunk_size = 60 * Integer.valueOf(chunkList[1].trim()) / chunkInterval;
|
||||
int CHUNK = Integer.valueOf(RATE / 1000 * int_chunk_size);
|
||||
int stride =
|
||||
Integer.valueOf(
|
||||
60 * Integer.valueOf(chunkList[1].trim()) / chunkInterval / 1000 * 16000 * 2);
|
||||
System.out.println("chunk_size:" + String.valueOf(int_chunk_size));
|
||||
System.out.println("CHUNK:" + CHUNK);
|
||||
System.out.println("stride:" + String.valueOf(stride));
|
||||
FunasrWsClient.sendChunkSize = CHUNK * 2;
|
||||
|
||||
String wsAddress = "ws://" + srvIp + ":" + srvPort;
|
||||
|
||||
FunasrWsClient c = new FunasrWsClient(new URI(wsAddress));
|
||||
|
||||
c.connect();
|
||||
|
||||
System.out.println("wsAddress:" + wsAddress);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("e:" + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < numThreads; i++) {
|
||||
System.out.println("Thread1 is running...");
|
||||
Thread t = new Thread(new ClientThread(srvIp, srvPort, wavPath));
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
|
||||
ENTRY_POINT = ./
|
||||
|
||||
|
||||
|
||||
|
||||
WEBSOCKET_DIR:= ./
|
||||
WEBSOCKET_FILES = \
|
||||
$(WEBSOCKET_DIR)/FunasrWsClient.java \
|
||||
|
||||
|
||||
|
||||
LIB_BUILD_DIR = ./lib
|
||||
|
||||
|
||||
|
||||
|
||||
JAVAC = javac
|
||||
|
||||
BUILD_DIR = build
|
||||
|
||||
|
||||
RUNJFLAGS = -Dfile.encoding=utf-8
|
||||
|
||||
|
||||
vpath %.class $(BUILD_DIR)
|
||||
vpath %.java src
|
||||
|
||||
|
||||
|
||||
|
||||
rebuild: clean all
|
||||
|
||||
.PHONY: clean run downjar
|
||||
|
||||
downjar:
|
||||
wget https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar -P ./lib/
|
||||
wget https://repo1.maven.org/maven2/org/slf4j/slf4j-simple/1.7.25/slf4j-simple-1.7.25.jar -P ./lib/
|
||||
#wget https://github.com/TooTallNate/Java-WebSocket/releases/download/v1.5.3/Java-WebSocket-1.5.3.jar -P ./lib/
|
||||
wget https://repo1.maven.org/maven2/org/java-websocket/Java-WebSocket/1.5.3/Java-WebSocket-1.5.3.jar -P ./lib/
|
||||
wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/json-simple/json-simple-1.1.1.jar -P ./lib/
|
||||
wget https://github.com/argparse4j/argparse4j/releases/download/argparse4j-0.9.0/argparse4j-0.9.0.jar -P ./lib/
|
||||
rm -frv build
|
||||
mkdir build
|
||||
clean:
|
||||
rm -frv $(BUILD_DIR)/*
|
||||
rm -frv $(LIB_BUILD_DIR)/*
|
||||
mkdir -p $(BUILD_DIR)
|
||||
mkdir -p ./lib
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
runclient:
|
||||
java -cp $(BUILD_DIR):lib/Java-WebSocket-1.5.3.jar:lib/slf4j-simple-1.7.25.jar:lib/slf4j-api-1.7.25.jar:lib/json-simple-1.1.1.jar:lib/argparse4j-0.9.0.jar $(RUNJFLAGS) websocket.FunasrWsClient --host localhost --port 8889 --audio_in ./asr_example.wav --num_threads 1 --mode 2pass
|
||||
|
||||
|
||||
|
||||
buildwebsocket: $(WEBSOCKET_FILES:.java=.class)
|
||||
|
||||
|
||||
%.class: %.java
|
||||
|
||||
$(JAVAC) -cp $(BUILD_DIR):lib/slf4j-simple-1.7.25.jar:lib/slf4j-api-1.7.25.jar:lib/Java-WebSocket-1.5.3.jar:lib/json-simple-1.1.1.jar:lib/argparse4j-0.9.0.jar -d $(BUILD_DIR) -encoding UTF-8 $<
|
||||
|
||||
packjar:
|
||||
jar cvfe lib/funasrclient.jar . -C $(BUILD_DIR) .
|
||||
|
||||
all: clean buildlib packjar buildfile buildmic downjar buildwebsocket
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
dependencies {
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
implementation("org.json:json:20240303")
|
||||
implementation("org.springframework.boot:spring-boot-starter-websocket")
|
||||
}
|
||||
|
||||
|
||||
使用接口测试工具 form-data格式传入文件 返回测试成功即运行成功
|
||||
|
||||
默认访问路径:
|
||||
io路径: http://localhost:8081/recognition/testIO
|
||||
nio路径: http://localhost:8081/recognition/testNIO
|
||||
|
||||
application.yml中可根据自身需要修改对应模型参数
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.example.funasr_java_client;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Virgil Qiu
|
||||
* @since 2024/04/24
|
||||
*
|
||||
*/
|
||||
|
||||
@SpringBootApplication
|
||||
public class FunasrJavaClientApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(FunasrJavaClientApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.example.funasr_java_client.Servcvice;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Virgil Qiu
|
||||
* @since 2024/04/24
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/recognition")
|
||||
public class RecognitionController {
|
||||
|
||||
private final RecognitionService recognitionService;
|
||||
|
||||
public RecognitionController(RecognitionService recognitionService) {
|
||||
this.recognitionService = recognitionService;
|
||||
}
|
||||
@PostMapping("/testNIO")
|
||||
public String testIO(@RequestParam MultipartFile file) throws IOException, ExecutionException, InterruptedException {
|
||||
recognitionService.recognition(file);
|
||||
return "测试成功";
|
||||
}
|
||||
|
||||
@PostMapping("/testIO")
|
||||
public String testNIO(@RequestParam MultipartFile file) throws IOException, ExecutionException, InterruptedException {
|
||||
recognitionService.recognition(file);
|
||||
return "测试成功";
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.example.funasr_java_client.Servcvice;
|
||||
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Virgil Qiu
|
||||
* @since 2024/04/24
|
||||
*
|
||||
*/
|
||||
|
||||
public interface RecognitionService {
|
||||
|
||||
Object recognition(MultipartFile file) throws IOException, ExecutionException, InterruptedException;
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.example.funasr_java_client.Servcvice;
|
||||
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Virgil Qiu
|
||||
* @since 2024/04/24
|
||||
*
|
||||
*/
|
||||
|
||||
public interface RecognitionService2 {
|
||||
|
||||
Object recognition(MultipartFile file) throws IOException, ExecutionException, InterruptedException;
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package com.example.funasr_java_client.Servcvice.impl;
|
||||
|
||||
import com.example.funasr_java_client.Servcvice.RecognitionService;
|
||||
import com.example.funasr_java_client.WebSocketClient;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.socket.BinaryMessage;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Virgil Qiu
|
||||
* @since 2024/04/24
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
public class RecognitionServiceImpl implements RecognitionService {
|
||||
@Value("${parameters.fileUrl}")
|
||||
private String fileUrl;
|
||||
@Value("${parameters.model}")
|
||||
private String model;
|
||||
@Value("${parameters.hotWords}")
|
||||
private String hotWords;
|
||||
@Value("${parameters.serverIpPort}")
|
||||
private String serverIpPort;
|
||||
@Override
|
||||
public Object recognition(MultipartFile file) throws IOException, ExecutionException, InterruptedException {
|
||||
if (file.isEmpty()) {
|
||||
return "0"; // 文件为空,返回特殊值
|
||||
}
|
||||
|
||||
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
String[] parts = originalFilename.split("\\.");
|
||||
String prefix = (parts.length > 0) ? parts[0] : originalFilename;
|
||||
System.out.println(prefix);
|
||||
String localFilePath = fileUrl + prefix + ".pcm";
|
||||
|
||||
File localFile = new File(localFilePath);
|
||||
|
||||
File destDir = localFile.getParentFile();
|
||||
if (!destDir.exists() && !destDir.mkdirs()) {
|
||||
throw new IOException("Unable to create destination directory: " + localFilePath);
|
||||
}
|
||||
|
||||
file.transferTo(localFile);
|
||||
|
||||
WebSocketClient client = new WebSocketClient();
|
||||
URI uri = URI.create(serverIpPort);
|
||||
StandardWebSocketClient standardWebSocketClient = new StandardWebSocketClient();
|
||||
WebSocketSession webSocketSession = standardWebSocketClient.execute(client, null, uri).get();
|
||||
|
||||
|
||||
JSONObject configJson = new JSONObject();
|
||||
configJson.put("mode", model);
|
||||
configJson.put("wav_name", prefix);
|
||||
configJson.put("wav_format", "pcm"); // 文件格式为pcm
|
||||
configJson.put("is_speaking", true);
|
||||
configJson.put("hotwords", hotWords");
|
||||
configJson.put("itn", true);
|
||||
|
||||
// 发送配置参数与meta信息
|
||||
webSocketSession.sendMessage(new TextMessage(configJson.toString()));
|
||||
|
||||
byte[] audioData;
|
||||
try {
|
||||
audioData = Files.readAllBytes(Paths.get(localFilePath));
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error reading file: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return "Error reading audio file"; // Return an appropriate error message or throw an exception
|
||||
}
|
||||
|
||||
ByteBuffer audioByteBuffer = ByteBuffer.wrap(audioData);
|
||||
|
||||
BinaryMessage binaryMessage = new BinaryMessage(audioByteBuffer);
|
||||
webSocketSession.sendMessage(binaryMessage);
|
||||
|
||||
// 发送音频结束标志
|
||||
JSONObject endMarkerJson = new JSONObject();
|
||||
endMarkerJson.put("is_speaking", false);
|
||||
webSocketSession.sendMessage(new TextMessage(endMarkerJson.toString()));
|
||||
|
||||
// TODO: 实现接收并处理服务端返回的识别结果
|
||||
|
||||
return "test";
|
||||
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
package com.example.funasr_java_client.Servcvice.impl;
|
||||
|
||||
import com.example.funasr_java_client.Servcvice.RecognitionService;
|
||||
import com.example.funasr_java_client.Servcvice.RecognitionService2;
|
||||
import com.example.funasr_java_client.WebSocketClient;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.socket.BinaryMessage;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Virgil Qiu
|
||||
* @since 2024/04/24
|
||||
*
|
||||
*/
|
||||
|
||||
@Service
|
||||
public class RecognitionServiceImpl2 implements RecognitionService2 {
|
||||
@Value("${parameters.fileUrl}")
|
||||
private String fileUrl;
|
||||
@Value("${parameters.model}")
|
||||
private String model;
|
||||
@Value("${parameters.hotWords}")
|
||||
private String hotWords;
|
||||
@Value("${parameters.serverIpPort}")
|
||||
private String serverIpPort;
|
||||
@Override
|
||||
public Object recognition(MultipartFile file) throws IOException, ExecutionException, InterruptedException {
|
||||
if (file.isEmpty()) {
|
||||
return "0"; // 文件为空,返回特殊值
|
||||
}
|
||||
|
||||
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
String[] parts = originalFilename.split("\\.");
|
||||
String prefix = (parts.length > 0) ? parts[0] : originalFilename;
|
||||
System.out.println(prefix);
|
||||
String localFilePath = fileUrl + prefix + ".pcm";
|
||||
|
||||
File localFile = new File(localFilePath);
|
||||
|
||||
File destDir = localFile.getParentFile();
|
||||
if (!destDir.exists() && !destDir.mkdirs()) {
|
||||
throw new IOException("Unable to create destination directory: " + localFilePath);
|
||||
}
|
||||
|
||||
file.transferTo(localFile);
|
||||
|
||||
WebSocketClient client = new WebSocketClient();
|
||||
URI uri = URI.create(serverIpPort);
|
||||
StandardWebSocketClient standardWebSocketClient = new StandardWebSocketClient();
|
||||
WebSocketSession webSocketSession = standardWebSocketClient.execute(client, null, uri).get();
|
||||
|
||||
|
||||
JSONObject configJson = new JSONObject();
|
||||
configJson.put("mode", model);
|
||||
configJson.put("wav_name", prefix);
|
||||
configJson.put("wav_format", "pcm"); // 文件格式为pcm
|
||||
configJson.put("is_speaking", true);
|
||||
configJson.put("hotwords", hotWords);
|
||||
configJson.put("itn", true);
|
||||
|
||||
// 发送配置参数与meta信息
|
||||
webSocketSession.sendMessage(new TextMessage(configJson.toString()));
|
||||
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(localFilePath)) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = fis.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, bytesRead);
|
||||
}
|
||||
|
||||
// 将所有读取的字节合并到一个字节数组中
|
||||
byte[] completeData = baos.toByteArray();
|
||||
|
||||
// 使用字节数组创建BinaryMessage实例
|
||||
BinaryMessage binaryMessage = new BinaryMessage(completeData);
|
||||
webSocketSession.sendMessage(binaryMessage);
|
||||
// 使用或发送binaryMessage...
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error reading file: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
// 发送音频结束标志
|
||||
JSONObject endMarkerJson = new JSONObject();
|
||||
endMarkerJson.put("is_speaking", false);
|
||||
webSocketSession.sendMessage(new TextMessage(endMarkerJson.toString()));
|
||||
|
||||
// TODO: 实现接收并处理服务端返回的识别结果
|
||||
|
||||
return "test";
|
||||
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.example.funasr_java_client;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.socket.*;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Virgil Qiu
|
||||
* @since 2024/04/24
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@Component
|
||||
public class WebSocketClient implements WebSocketHandler {
|
||||
|
||||
private WebSocketSession session;
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||
this.session = session;
|
||||
System.out.println("WebSocket connection established.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
|
||||
if (message instanceof TextMessage) {
|
||||
String receivedMessage = ((TextMessage) message).getPayload();
|
||||
System.out.println("Received message from server: " + receivedMessage);
|
||||
// 在这里处理接收到的消息
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
|
||||
System.err.println("WebSocket transport error: " + exception.getMessage());
|
||||
session.close(CloseStatus.SERVER_ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
|
||||
System.out.println("WebSocket connection closed with status: " + status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsPartialMessages() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void sendMessage(String message) {
|
||||
if (session != null && session.isOpen()) {
|
||||
try {
|
||||
session.sendMessage(new TextMessage(message));
|
||||
System.out.println("Sent message to server: " + message);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
System.err.println("WebSocket session is not open. Cannot send message.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
spring.application.name=funasr_java_client
|
||||
server.port=8081
|
||||
@@ -0,0 +1,21 @@
|
||||
#/**
|
||||
# *
|
||||
# * @author Virgil Qiu
|
||||
# * @since 2024/04/24
|
||||
# *
|
||||
# */
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: java_http_client
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
|
||||
parameters:
|
||||
model: "offline" #离线模型为例
|
||||
hotWords: "{\"自定义\":20,\"热词\":20,\"设置\":30}"
|
||||
fileUrl: "E:/EI/Audio"
|
||||
serverIpPort: "ws://your_funasr_ip:port"
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# Client for java websocket example
|
||||
|
||||
|
||||
|
||||
## Building for Linux/Unix
|
||||
|
||||
### install java environment
|
||||
```shell
|
||||
# in ubuntu
|
||||
apt-get install openjdk-11-jdk
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Build and run by make
|
||||
|
||||
|
||||
```shell
|
||||
cd funasr/runtime/java
|
||||
# download java lib
|
||||
make downjar
|
||||
# compile
|
||||
make buildwebsocket
|
||||
# run client
|
||||
make runclient
|
||||
|
||||
```
|
||||
|
||||
## Run java websocket client by shell
|
||||
|
||||
```shell
|
||||
# full command refer to Makefile runclient
|
||||
usage: FunasrWsClient [-h] [--port PORT] [--host HOST] [--audio_in AUDIO_IN] [--num_threads NUM_THREADS]
|
||||
[--chunk_size CHUNK_SIZE] [--chunk_interval CHUNK_INTERVAL] [--mode MODE]
|
||||
|
||||
Where:
|
||||
--host <string>
|
||||
(required) server-ip
|
||||
|
||||
--port <int>
|
||||
(required) port
|
||||
|
||||
--audio_in <string>
|
||||
(required) the wav or pcm file path
|
||||
|
||||
--num_threads <int>
|
||||
thread number for test
|
||||
|
||||
--mode
|
||||
asr mode, support "offline" "online" "2pass"
|
||||
|
||||
|
||||
|
||||
example:
|
||||
FunasrWsClient --host localhost --port 8889 --audio_in ./asr_example.wav --num_threads 1 --mode 2pass
|
||||
|
||||
result json, example like:
|
||||
{"mode":"offline","text":"欢迎大家来体验达摩院推出的语音识别模型","wav_name":"javatest"}
|
||||
```
|
||||
|
||||
|
||||
## Acknowledge
|
||||
1. This project is maintained by [FunASR community](https://github.com/modelscope/FunASR).
|
||||
2. We acknowledge [zhaoming](https://github.com/zhaomingwork/FunASR/tree/java-ws-client-support/funasr/runtime/java) for contributing the java websocket client example.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user