Browse Source
Merge branch 'master' of http://82.156.111.58:3000/maojian/opai-service-center.git
master
Merge branch 'master' of http://82.156.111.58:3000/maojian/opai-service-center.git
master
46 changed files with 5016 additions and 58 deletions
-
1asr-service/.settings/org.eclipse.core.resources.prefs
-
185asr-service/pom.xml
-
13asr-service/src/main/java/com/bw/App.java
-
19asr-service/src/main/java/com/bw/asr/Application.java
-
37asr-service/src/main/java/com/bw/asr/cache/ConfigCache.java
-
39asr-service/src/main/java/com/bw/asr/controller/TaskReceiveController.java
-
42asr-service/src/main/java/com/bw/asr/entity/AppResultDoc.java
-
45asr-service/src/main/java/com/bw/asr/entity/Constants.java
-
52asr-service/src/main/java/com/bw/asr/entity/VideoResult.java
-
206asr-service/src/main/java/com/bw/asr/handler/MainHandler.java
-
18asr-service/src/main/java/com/bw/asr/service/AsrTaskService.java
-
17asr-service/src/main/java/com/bw/asr/service/TaskReceiveService.java
-
553asr-service/src/main/java/com/bw/asr/service/impl/AsrTaskServiceImpl.java
-
55asr-service/src/main/java/com/bw/asr/service/impl/TaskReceiveServiceImpl.java
-
177asr-service/src/main/java/com/bw/asr/utils/DateUtil.java
-
1045asr-service/src/main/java/com/bw/asr/utils/DownLoadUtil.java
-
41asr-service/src/main/java/com/bw/asr/utils/FileUtil.java
-
45asr-service/src/main/java/com/bw/asr/utils/SpringBootKafka.java
-
23asr-service/src/main/java/com/bw/asr/utils/ThrowMessageUtil.java
-
52asr-service/src/main/resources/bootstrap.yml
-
36asr-service/src/main/resources/logback-spring.xml
-
38asr-service/src/test/java/com/bw/AppTest.java
-
40funasr-service/.classpath
-
1funasr-service/.gitignore
-
23funasr-service/.project
-
4funasr-service/.settings/org.eclipse.core.resources.prefs
-
9funasr-service/.settings/org.eclipse.jdt.core.prefs
-
4funasr-service/.settings/org.eclipse.m2e.core.prefs
-
213funasr-service/pom.xml
-
19funasr-service/src/main/java/com/bw/funasr/Application.java
-
37funasr-service/src/main/java/com/bw/funasr/cache/ConfigCache.java
-
39funasr-service/src/main/java/com/bw/funasr/controller/TaskReceiveController.java
-
42funasr-service/src/main/java/com/bw/funasr/entity/AppResultDoc.java
-
34funasr-service/src/main/java/com/bw/funasr/entity/Constants.java
-
206funasr-service/src/main/java/com/bw/funasr/handler/MainHandler.java
-
17funasr-service/src/main/java/com/bw/funasr/service/FunasrTaskService.java
-
190funasr-service/src/main/java/com/bw/funasr/service/Impl/FunasrTaskServiceImpl.java
-
55funasr-service/src/main/java/com/bw/funasr/service/Impl/TaskReceiveServiceImpl.java
-
17funasr-service/src/main/java/com/bw/funasr/service/TaskReceiveService.java
-
177funasr-service/src/main/java/com/bw/funasr/utils/DateUtil.java
-
1045funasr-service/src/main/java/com/bw/funasr/utils/DownLoadUtil.java
-
41funasr-service/src/main/java/com/bw/funasr/utils/FileUtil.java
-
23funasr-service/src/main/java/com/bw/funasr/utils/ThrowMessageUtil.java
-
52funasr-service/src/main/resources/bootstrap.yml
-
36funasr-service/src/main/resources/logback-spring.xml
-
11pom.xml
@ -1,4 +1,3 @@ |
|||
eclipse.preferences.version=1 |
|||
encoding//src/main/java=UTF-8 |
|||
encoding//src/test/java=UTF-8 |
|||
encoding/<project>=UTF-8 |
|||
@ -1,13 +0,0 @@ |
|||
package com.bw; |
|||
|
|||
/** |
|||
* Hello world! |
|||
* |
|||
*/ |
|||
public class App |
|||
{ |
|||
public static void main( String[] args ) |
|||
{ |
|||
System.out.println( "Hello World!" ); |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
package com.bw.asr; |
|||
|
|||
import org.springframework.boot.SpringApplication; |
|||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
|||
|
|||
|
|||
/** |
|||
* 系统接口启动类 |
|||
* @author jian.mao |
|||
* @date 2025年12月30日 |
|||
* @description |
|||
*/ |
|||
@SpringBootApplication |
|||
public class Application { |
|||
|
|||
public static void main(String[] args) { |
|||
SpringApplication.run(Application.class, args); |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
package com.bw.asr.cache; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import java.util.Map; |
|||
import java.util.concurrent.LinkedBlockingDeque; |
|||
|
|||
/** |
|||
* @author jian.mao |
|||
* @date 2022年11月11日 |
|||
* @description 静态变量类 |
|||
*/ |
|||
@Slf4j |
|||
public class ConfigCache { |
|||
|
|||
/**启动条件**/ |
|||
public static boolean isStart = true; |
|||
/*****任务队列*****/ |
|||
public static LinkedBlockingDeque<Map<String, Object>> taskQueue = new LinkedBlockingDeque<Map<String,Object>>(); |
|||
/****结果队列****/ |
|||
public static LinkedBlockingDeque<Map<String, Object>> resultQueue = new LinkedBlockingDeque<Map<String,Object>>(); |
|||
|
|||
|
|||
/** |
|||
* 队列录入任务 |
|||
* @param queue |
|||
* @param task |
|||
*/ |
|||
public static void putQueue(LinkedBlockingDeque<Map<String, Object>> queue,Map<String, Object> task){ |
|||
//next app 写入队列准备调出 |
|||
try { |
|||
queue.put(task); |
|||
} catch (InterruptedException e) { |
|||
log.error("队列写入data失败---"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
package com.bw.asr.controller; |
|||
|
|||
import javax.annotation.Resource; |
|||
|
|||
import org.springframework.stereotype.Controller; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestBody; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestMethod; |
|||
import org.springframework.web.bind.annotation.ResponseBody; |
|||
|
|||
import com.bw.asr.service.TaskReceiveService; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
/** |
|||
* 任务接收控制层 |
|||
* @author jian.mao |
|||
* @date 2025年1月14日 |
|||
* @description |
|||
*/ |
|||
@Controller |
|||
@RequestMapping("/task") |
|||
@Slf4j |
|||
public class TaskReceiveController { |
|||
@Resource |
|||
private TaskReceiveService taskReceiveService; |
|||
@PostMapping("/put") |
|||
@ResponseBody |
|||
public String put(@RequestBody String param){ |
|||
String response = taskReceiveService.put(param); |
|||
return response; |
|||
} |
|||
@RequestMapping(value = "/hello", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public String hello(String param, String token) { |
|||
return "123"; |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
package com.bw.asr.entity; |
|||
|
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Map; |
|||
|
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* ES 索引:opai_app_result |
|||
* 应用执行结果文档 |
|||
* |
|||
* @author jian.mao |
|||
*/ |
|||
@Data |
|||
public class AppResultDoc implements Serializable { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** 任务ID */ |
|||
private String taskId; |
|||
|
|||
/** 应用id */ |
|||
private Integer appId; |
|||
|
|||
/** 状态 0 进行中,1成功,2失败 */ |
|||
private Integer status; |
|||
|
|||
/** 创建时间(毫秒时间戳) */ |
|||
private Long createTime; |
|||
|
|||
/** 执行结果(可索引) */ |
|||
private Map<String, Object> result; |
|||
|
|||
/** 逻辑删除标识:0-未删除 1-已删除 */ |
|||
private Integer del; |
|||
|
|||
/***前端输入参数 ***/ |
|||
private Map<String, Object> input; |
|||
|
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
package com.bw.asr.entity; |
|||
|
|||
|
|||
/** |
|||
* 常量实体类 |
|||
* @author jian.mao |
|||
* @date 2022年11月15日 |
|||
* @description |
|||
*/ |
|||
|
|||
public class Constants { |
|||
|
|||
/** |
|||
* 空字符串常量 |
|||
*/ |
|||
public static final String EMPTY = ""; |
|||
|
|||
/************************应用参数*************************************/ |
|||
public static final String CODE = "code"; |
|||
public static final String ID = "id"; |
|||
public static final String MESSAGE = "message"; |
|||
/******************************api使用*******************************/ |
|||
public static final String ERROR = "error"; |
|||
public static final String TRACE = "trace"; |
|||
public static final String WORKSPACEID = "workspaceId"; |
|||
public static final String VIDEOURL = "videoUrl"; |
|||
public static final String VIDEOMODELID = "videoModelId"; |
|||
public static final String SNAPSHOTINTERVAL = "snapshotInterval";//1-10秒 |
|||
public static final String LANGUAGE = "language"; |
|||
public static final String METHODNAME = "methodName";//userdefined |
|||
public static final String INTERVAL = "interval"; |
|||
public static final String STARTTIME = "startTime"; |
|||
public static final String ENDTIME = "endTime"; |
|||
public static final String DATA_KEY = "videoCaptionInfo"; |
|||
public static final String SUBCONTENT = "subContent"; |
|||
public static final String SUBTITLES = "subtitles"; |
|||
public static final String VIDEOCONTENTS = "videoContents"; |
|||
public static final String JOBID = "jobId"; |
|||
|
|||
|
|||
/** |
|||
* 任务id |
|||
*/ |
|||
public static final String TASKID = "taskId"; |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
package com.bw.asr.entity; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* 视频解析结果实体 - 根据阿里云实际数据结构更新 |
|||
*/ |
|||
@Data |
|||
public class VideoResult { |
|||
// 基础信息 |
|||
private String taskId; |
|||
private String taskStatus; |
|||
private String errorMessage; |
|||
private Long createTime = System.currentTimeMillis(); |
|||
private List<Map<String, Object>> subtitles; // 字幕列表 |
|||
private Integer captionCount; // 字幕数量 |
|||
private String headerInfo; // header信息 |
|||
|
|||
// 辅助字段 |
|||
private String videoUrl; // 视频URL |
|||
|
|||
// 格式化方法 |
|||
public String getFormattedCreateTime() { |
|||
if (createTime != null) { |
|||
return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date(createTime)); |
|||
} |
|||
return "未知时间"; |
|||
} |
|||
|
|||
/** |
|||
* 获取第一条字幕(如果有) |
|||
*/ |
|||
public Map<String, Object> getFirstSubtitle() { |
|||
if (subtitles != null && !subtitles.isEmpty()) { |
|||
return subtitles.get(0); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* 获取最后一条字幕(如果有) |
|||
*/ |
|||
public Map<String, Object> getLastSubtitle() { |
|||
if (subtitles != null && !subtitles.isEmpty()) { |
|||
return subtitles.get(subtitles.size() - 1); |
|||
} |
|||
return null; |
|||
} |
|||
} |
|||
@ -0,0 +1,206 @@ |
|||
package com.bw.asr.handler; |
|||
|
|||
import java.io.File; |
|||
import java.io.IOException; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.concurrent.LinkedBlockingDeque; |
|||
import java.util.concurrent.LinkedBlockingQueue; |
|||
import java.util.concurrent.ThreadPoolExecutor; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
|
|||
import org.apache.commons.io.FileUtils; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.ApplicationArguments; |
|||
import org.springframework.boot.ApplicationRunner; |
|||
import org.springframework.core.annotation.Order; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.bw.asr.cache.ConfigCache; |
|||
import com.bw.asr.service.AsrTaskService; |
|||
import com.bw.asr.utils.DateUtil; |
|||
import com.bw.asr.utils.FileUtil; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
|
|||
/** |
|||
* @author jian.mao |
|||
* @date 2025年1月13日 |
|||
* @description |
|||
*/ |
|||
@Component |
|||
@Order(value = 1) |
|||
@Slf4j |
|||
public class MainHandler implements ApplicationRunner { |
|||
|
|||
@Value("${task.task-queue-path}") |
|||
private String taskPath; |
|||
@Value("${task.result-task-queue-path}") |
|||
private String resultTaskPath; |
|||
@Autowired |
|||
private AsrTaskService asrTaskService; |
|||
/***线程池参数***/ |
|||
@Value("${threadPool.corePoolSize}") |
|||
private int corePoolSize; |
|||
@Value("${threadPool.maximumPoolSize}") |
|||
private int maximumPoolSize; |
|||
@Value("${threadPool.keepAliveTime}") |
|||
private long keepAliveTime; |
|||
@Value("${threadPool.queueSize}") |
|||
private int queueSize; |
|||
|
|||
/** |
|||
*执行入口 |
|||
*/ |
|||
@Override |
|||
public void run(ApplicationArguments args) throws Exception { |
|||
//线程池方式 |
|||
ThreadPoolExecutor executor = new ThreadPoolExecutor( |
|||
corePoolSize, |
|||
maximumPoolSize, |
|||
keepAliveTime, |
|||
TimeUnit.SECONDS, |
|||
new LinkedBlockingQueue<>(queueSize), |
|||
new ThreadPoolExecutor.CallerRunsPolicy() |
|||
); |
|||
//消费创建任务队列数据 |
|||
Thread consumerThread = new Thread(() -> { |
|||
while (true) { |
|||
try { |
|||
// 从队列中获取任务 |
|||
Map<String, Object> task = ConfigCache.taskQueue.take(); |
|||
// 提交给线程池执行 |
|||
executor.execute(() -> createTask(task)); |
|||
} catch (InterruptedException e) { |
|||
// 恢复中断状态 |
|||
Thread.currentThread().interrupt(); |
|||
log.error("任务消费线程被中断"); |
|||
break; |
|||
} |
|||
} |
|||
}); |
|||
consumerThread.start(); |
|||
log.info("创建任务消费线程启动-----"); |
|||
|
|||
|
|||
//消费结果任务队列数据 |
|||
Thread resultConsumerThread = new Thread(() -> { |
|||
while (true) { |
|||
try { |
|||
// 从队列中获取任务 |
|||
Map<String, Object> task = ConfigCache.resultQueue.take(); |
|||
// 提交给线程池执行 |
|||
executor.execute(() -> getResult(task)); |
|||
} catch (InterruptedException e) { |
|||
// 恢复中断状态 |
|||
Thread.currentThread().interrupt(); |
|||
log.error("任务消费线程被中断"); |
|||
break; |
|||
} |
|||
DateUtil.sleep(3000); |
|||
} |
|||
}); |
|||
resultConsumerThread.start(); |
|||
log.info("结果任务消费线程启动-----"); |
|||
//启动加载缓存任务 |
|||
readTask(taskPath, ConfigCache.taskQueue); |
|||
readTask(resultTaskPath, ConfigCache.resultQueue); |
|||
//停止处理 |
|||
waitDown(); |
|||
} |
|||
|
|||
/** |
|||
* 创建任务执行方法 |
|||
* @param task |
|||
*/ |
|||
private void createTask(Map<String, Object> task) { |
|||
asrTaskService.create(task); |
|||
} |
|||
|
|||
private void getResult(Map<String, Object> task) { |
|||
asrTaskService.parse(task); |
|||
} |
|||
|
|||
|
|||
/****************************************************************load******************************************************************************/ |
|||
/** |
|||
* 加载文件中的任务 |
|||
* @param path 文件地址 |
|||
* @param queue 队列 |
|||
*/ |
|||
@SuppressWarnings("unchecked") |
|||
public static void readTask(String path, LinkedBlockingDeque<Map<String, Object>> queue) { |
|||
File file = new File(path); |
|||
if (file.exists()) { |
|||
List<String> tasks = null; |
|||
try { |
|||
tasks = FileUtils.readLines(file, "UTF-8"); |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
for (String taskStr : tasks) { |
|||
Map<String, Object> task = JSONObject.parseObject(taskStr); |
|||
try { |
|||
queue.put(task); |
|||
} catch (InterruptedException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
file.delete(); |
|||
} |
|||
} |
|||
|
|||
/*******************************************************************stop************************************************************************/ |
|||
|
|||
/** |
|||
* 结束触发钩子 |
|||
*/ |
|||
public void waitDown() { |
|||
Runtime.getRuntime().addShutdownHook(new Thread() { |
|||
@Override |
|||
public void run() { |
|||
// 停止线程 |
|||
ConfigCache.isStart = false; |
|||
log.info("stop-------"); |
|||
writeTsskToFile(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 任务持久化到硬盘 |
|||
*/ |
|||
public void writeTsskToFile() { |
|||
while (true) { |
|||
if (ConfigCache.taskQueue.size() > 0) { |
|||
try { |
|||
Map<String, Object> task = ConfigCache.taskQueue.take(); |
|||
FileUtil.writeFile(taskPath, JSONObject.toJSONString(task)); |
|||
} catch (InterruptedException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} else { |
|||
log.info("taskQueue write is file end"); |
|||
break; |
|||
} |
|||
} |
|||
while (true) { |
|||
if (ConfigCache.resultQueue.size() > 0) { |
|||
try { |
|||
Map<String, Object> task = ConfigCache.resultQueue.take(); |
|||
FileUtil.writeFile(resultTaskPath, JSONObject.toJSONString(task)); |
|||
} catch (InterruptedException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} else { |
|||
log.info("taskQueue write is file end"); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
package com.bw.asr.service; |
|||
|
|||
import java.util.Map; |
|||
|
|||
public interface AsrTaskService { |
|||
/** |
|||
* ocr远端任务 |
|||
* @param task |
|||
*/ |
|||
public void create(Map<String, Object> task); |
|||
|
|||
/** |
|||
* 解析结果 |
|||
* @param task |
|||
*/ |
|||
public void parse(Map<String, Object> task); |
|||
|
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
package com.bw.asr.service; |
|||
|
|||
/** |
|||
* 任务接收服务层 |
|||
* @author jian.mao |
|||
* @date 2025年1月14日 |
|||
* @description |
|||
*/ |
|||
public interface TaskReceiveService { |
|||
|
|||
/** |
|||
* 任务新增 |
|||
* @param dataJson |
|||
* @return |
|||
*/ |
|||
public String put(String dataJson); |
|||
} |
|||
@ -0,0 +1,553 @@ |
|||
package com.bw.asr.service.impl; |
|||
|
|||
import java.io.IOException; |
|||
import java.net.URLEncoder; |
|||
import java.nio.file.Files; |
|||
import java.nio.file.Paths; |
|||
import java.util.*; |
|||
|
|||
import com.alibaba.fastjson2.JSON; |
|||
import com.alibaba.fastjson2.JSONArray; |
|||
import com.alibaba.fastjson2.JSONObject; |
|||
import com.aliyun.auth.credentials.Credential; |
|||
import com.aliyun.auth.credentials.provider.StaticCredentialProvider; |
|||
import com.aliyun.core.http.HttpClient; |
|||
import com.aliyun.httpcomponent.httpclient.ApacheAsyncHttpClientBuilder; |
|||
import com.aliyun.sdk.gateway.pop.Configuration; |
|||
import com.aliyun.sdk.gateway.pop.auth.SignatureVersion; |
|||
import com.aliyun.sdk.service.quanmiaolightapp20240801.AsyncClient; |
|||
import com.aliyun.sdk.service.quanmiaolightapp20240801.models.*; |
|||
import darabonba.core.client.ClientOverrideConfiguration; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.cloud.context.config.annotation.RefreshScope; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import com.bw.asr.entity.Constants; |
|||
import com.bw.asr.entity.VideoResult; |
|||
import com.bw.asr.service.AsrTaskService; |
|||
import com.bw.asr.utils.DownLoadUtil; |
|||
import com.bw.asr.utils.FileUtil; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import com.bw.asr.entity.AppResultDoc; |
|||
import com.bw.asr.cache.ConfigCache; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import java.time.Duration; |
|||
import java.util.concurrent.CompletableFuture; |
|||
|
|||
/** |
|||
* 视频解析服务实现类 |
|||
*/ |
|||
@Service |
|||
@Slf4j |
|||
@RefreshScope |
|||
public class AsrTaskServiceImpl implements AsrTaskService { |
|||
@Value("${file.path-prefix}") |
|||
private String downloadFilePathPrefix; |
|||
|
|||
@Value("${aliyun.access-key-id}") |
|||
private String accessKeyId; |
|||
|
|||
@Value("${aliyun.access-key-secret}") |
|||
private String accessKeySecret; |
|||
|
|||
@Value("${aliyun.workspace-id}") |
|||
private String workspaceId; |
|||
|
|||
@Value("${video.analysis.model-id}") |
|||
private String modelId; |
|||
|
|||
@Value("${video.analysis.video-model-id}") |
|||
private String videoModelId; |
|||
|
|||
@Value("${api.save-url}") |
|||
private String saveUrl; |
|||
|
|||
// 语言映射表(中文 -> 英文) |
|||
private static final Map<String, String> LANGUAGE_MAPPING = new HashMap<>(); |
|||
|
|||
static { |
|||
LANGUAGE_MAPPING.put("中文", "chinese"); |
|||
LANGUAGE_MAPPING.put("法语", "french"); |
|||
LANGUAGE_MAPPING.put("英语", "english"); |
|||
LANGUAGE_MAPPING.put("日语", "japanese"); |
|||
LANGUAGE_MAPPING.put("中英文自由说", "chineseEnglishFreely"); |
|||
LANGUAGE_MAPPING.put("阿拉伯语", "arabic"); |
|||
LANGUAGE_MAPPING.put("韩语", "korean"); |
|||
LANGUAGE_MAPPING.put("马来语", "malay"); |
|||
LANGUAGE_MAPPING.put("泰语", "thai"); |
|||
LANGUAGE_MAPPING.put("葡萄牙语", "portuguese"); |
|||
LANGUAGE_MAPPING.put("西班牙语", "spanish"); |
|||
LANGUAGE_MAPPING.put("印尼语", "indonesian"); |
|||
LANGUAGE_MAPPING.put("越南语", "vietnamese"); |
|||
} |
|||
|
|||
/** |
|||
* 获取阿里云客户端 |
|||
*/ |
|||
private AsyncClient getClient() { |
|||
try { |
|||
Credential credential = Credential.builder() |
|||
.accessKeyId(accessKeyId) |
|||
.accessKeySecret(accessKeySecret) |
|||
.build(); |
|||
|
|||
HttpClient httpClient = new ApacheAsyncHttpClientBuilder() |
|||
.connectionTimeout(Duration.ofSeconds(30)) |
|||
.responseTimeout(Duration.ofSeconds(60)) |
|||
.ignoreSSL(false) |
|||
.build(); |
|||
|
|||
return AsyncClient.builder() |
|||
.credentialsProvider(StaticCredentialProvider.create(credential)) |
|||
.serviceConfiguration(Configuration.create().setSignatureVersion(SignatureVersion.V3)) |
|||
.overrideConfiguration(ClientOverrideConfiguration.create() |
|||
.setProtocol("HTTPS") |
|||
.setEndpointOverride("quanmiaolightapp.cn-beijing.aliyuncs.com")) |
|||
.httpClient(httpClient) |
|||
.build(); |
|||
} catch (Exception e) { |
|||
log.error("初始化阿里云客户端失败", e); |
|||
return null; |
|||
} |
|||
} |
|||
/** |
|||
* 提交视频分析任务 |
|||
*/ |
|||
@Override |
|||
public void create(Map<String, Object> task) { |
|||
try { |
|||
//源文件链接 |
|||
String videoUrl = task.get(Constants.VIDEOURL).toString(); |
|||
String url = videoUrl.replace("10.8.0.16", "182.92.120.176"); |
|||
String inputLanguage = task.get(Constants.LANGUAGE).toString(); |
|||
// 映射语言参数 |
|||
String language = mapLanguage(inputLanguage); |
|||
// 构建请求 |
|||
SubmitVideoAnalysisTaskRequest request = buildVideoAnalysisRequest(url,language); |
|||
|
|||
// 提交任务 |
|||
AsyncClient client = getClient(); |
|||
CompletableFuture<SubmitVideoAnalysisTaskResponse> responseFuture = |
|||
client.submitVideoAnalysisTask(request); |
|||
SubmitVideoAnalysisTaskResponse response = responseFuture.get(); |
|||
|
|||
if (response != null && response.getBody().getSuccess() && |
|||
response.getBody().getData() != null) { |
|||
String jobId = response.getBody().getData().getTaskId(); |
|||
log.info("视频解析任务提交成功,任务ID:{}", (String)task.get(Constants.TASKID)); |
|||
|
|||
task.put(Constants.JOBID, URLEncoder.encode(jobId.replace("\"", ""), "UTF-8")); |
|||
|
|||
//任务创建成功,放到监控结果队列中 |
|||
ConfigCache.resultQueue.put(task); |
|||
|
|||
} else { |
|||
throw new RuntimeException("视频解析任务提交失败"); |
|||
} |
|||
|
|||
} catch (Throwable e) { |
|||
log.error("提交视频解析任务异常", e); |
|||
//失败直接发送结果 |
|||
AppResultDoc entity = new AppResultDoc(); |
|||
entity.setTaskId((String)task.get(Constants.TASKID)); |
|||
entity.setAppId((Integer)task.get(Constants.ID)); |
|||
long now = System.currentTimeMillis(); |
|||
entity.setCreateTime(now); |
|||
Map<String, Object> result = new HashMap<String, Object>(16); |
|||
result.put(Constants.ERROR, "识别任务创建异常"); |
|||
entity.setResult(result); |
|||
entity.setStatus(2); |
|||
entity.setDel(0); |
|||
entity.setInput(task); |
|||
//回传给api服务保存 |
|||
DownLoadUtil.doPost(saveUrl, JSONObject.toJSONString(entity)); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 构建视频理解请求 |
|||
*/ |
|||
private SubmitVideoAnalysisTaskRequest buildVideoAnalysisRequest(String videoUrl,String language) { |
|||
return SubmitVideoAnalysisTaskRequest.builder() |
|||
.workspaceId(workspaceId) |
|||
.videoUrl(videoUrl) |
|||
.videoModelId(videoModelId) |
|||
.language(language) |
|||
.generateOptions(Arrays.asList("videoAnalysis", "videoGenerate")) |
|||
.videoModelCustomPromptTemplate("# 角色\n你是一名专业的视频字幕提取员\n\n# 任务\n提取视频中的所有对话和字幕内容\n\n# 输入\n{videoAsrText}\n\n# 输出格式\n时间戳:00:00:00 - 内容:这里是字幕内容") |
|||
.textProcessTasks(Collections.singletonList( |
|||
SubmitVideoAnalysisTaskRequest.TextProcessTasks.builder() |
|||
.modelId(modelId) |
|||
.modelCustomPromptTemplate("# 角色\n视频内容分析师\n\n# 输入\n{videoAnalysisText}\n{videoAsrText}\n\n# 任务\n提取视频字幕并标记时间戳\n\n# 输出格式\n=== 视频字幕时间轴 ===") |
|||
.build() |
|||
)) |
|||
.frameSampleMethod(SubmitVideoAnalysisTaskRequest.FrameSampleMethod.builder() |
|||
.methodName("standard") |
|||
.build()) |
|||
.build(); |
|||
} |
|||
|
|||
@Override |
|||
public void parse(Map<String, Object> task) { |
|||
ObjectMapper objectMapper = new ObjectMapper(); |
|||
// TODO Auto-generated method stub |
|||
try { |
|||
String jobId = (String) task.get(Constants.JOBID); |
|||
//获取视频解析结果 |
|||
VideoResult videoResult = getVideoAnalysisResult(jobId); |
|||
System.out.println("result ---------------" +videoResult); |
|||
log.info("获取解析结果-jobId:{},result:{}",jobId,videoResult); |
|||
if (videoResult != null) { |
|||
String status = videoResult.getTaskStatus(); |
|||
// 1. 检查headerInfo中是否有错误信息 |
|||
Object headerInfo = videoResult.getHeaderInfo(); |
|||
String errorMessage = ""; |
|||
if (headerInfo != null && headerInfo.toString().contains("errorCode")) { |
|||
log.error("阿里云返回错误信息: {}", headerInfo); |
|||
errorMessage = extractErrorMessageFromHeader(headerInfo.toString()); |
|||
} |
|||
if ("SUCCESSED".equals(status)) { |
|||
// String content = printSimpleCaptions(videoResult); |
|||
// String jsonString = objectMapper.writeValueAsString(videoResult.getSubtitles()); |
|||
// if(jsonString.isEmpty() || jsonString == null || "[]".equals(jsonString.trim())) { |
|||
// jsonString = "未解析到字幕信息"; |
|||
// } |
|||
|
|||
List<Map<String, Object>> subtitles = videoResult.getSubtitles(); |
|||
// 检查字幕是否为空 |
|||
if (subtitles == null || subtitles.isEmpty()) { |
|||
AppResultDoc entity = new AppResultDoc(); |
|||
entity.setTaskId((String)task.get(Constants.TASKID)); |
|||
entity.setAppId((Integer)task.get(Constants.ID)); |
|||
long now = System.currentTimeMillis(); |
|||
entity.setCreateTime(now); |
|||
Map<String, Object> result = new HashMap<String, Object>(16); |
|||
result.put(Constants.ERROR, "未解析到字幕信息"); |
|||
entity.setResult(result); |
|||
entity.setStatus(2); |
|||
entity.setDel(0); |
|||
entity.setInput(task); |
|||
//回传给api服务保存 |
|||
DownLoadUtil.doPost(saveUrl, JSONObject.toJSONString(entity)); |
|||
} |
|||
|
|||
//成功 发送结果 |
|||
AppResultDoc entity = new AppResultDoc(); |
|||
entity.setTaskId((String)task.get(Constants.TASKID)); |
|||
entity.setAppId((Integer)task.get(Constants.ID)); |
|||
long now = System.currentTimeMillis(); |
|||
entity.setCreateTime(now); |
|||
Map<String, Object> result = new HashMap<String, Object>(16); |
|||
result.put(Constants.SUBCONTENT, subtitles);//videoResult.getSubtitles() |
|||
result.put(Constants.SUBTITLES, videoResult.getCaptionCount()); |
|||
entity.setResult(result); |
|||
entity.setStatus(1); |
|||
entity.setDel(0); |
|||
entity.setInput(task); |
|||
//回传给api服务保存 |
|||
DownLoadUtil.doPost(saveUrl, JSONObject.toJSONString(entity)); |
|||
}else if("FAILED".equals(status) || "CANCELED".equals(status)) { |
|||
System.out.println("视频解析失败: " + videoResult.getErrorMessage()); |
|||
//发送失败结果 |
|||
AppResultDoc entity = new AppResultDoc(); |
|||
entity.setTaskId((String)task.get(Constants.TASKID)); |
|||
entity.setAppId((Integer)task.get(Constants.ID)); |
|||
long now = System.currentTimeMillis(); |
|||
entity.setCreateTime(now); |
|||
Map<String, Object> result = new HashMap<String, Object>(16); |
|||
result.put(Constants.ERROR, "识别失败"); |
|||
entity.setResult(result); |
|||
entity.setStatus(2); |
|||
entity.setDel(0); |
|||
entity.setInput(task); |
|||
//回传给api服务保存 |
|||
DownLoadUtil.doPost(saveUrl, JSONObject.toJSONString(entity)); |
|||
}else if("PENDING".equals(status) && !errorMessage.isEmpty() && errorMessage !=null){ |
|||
log.error("任务处于PENDING状态但有错误信息,立即处理。taskId: {}, 错误: {}", (String)task.get(Constants.TASKID), errorMessage); |
|||
//发送失败结果 |
|||
AppResultDoc entity = new AppResultDoc(); |
|||
entity.setTaskId((String)task.get(Constants.TASKID)); |
|||
entity.setAppId((Integer)task.get(Constants.ID)); |
|||
long now = System.currentTimeMillis(); |
|||
entity.setCreateTime(now); |
|||
Map<String, Object> result = new HashMap<String, Object>(16); |
|||
result.put(Constants.ERROR, errorMessage); |
|||
entity.setResult(result); |
|||
entity.setStatus(2); |
|||
entity.setDel(0); |
|||
entity.setInput(task); |
|||
//回传给api服务保存 |
|||
DownLoadUtil.doPost(saveUrl, JSONObject.toJSONString(entity)); |
|||
}else { |
|||
//识别中 -- 放回队列 |
|||
ConfigCache.resultQueue.put(task); |
|||
} |
|||
} |
|||
} catch (Throwable e) { |
|||
// TODO: handle exception |
|||
log.error("创建文档解析任务异常。e:",e); |
|||
//发送失败结果 |
|||
AppResultDoc entity = new AppResultDoc(); |
|||
entity.setTaskId((String)task.get(Constants.TASKID)); |
|||
entity.setAppId((Integer)task.get(Constants.ID)); |
|||
long now = System.currentTimeMillis(); |
|||
entity.setCreateTime(now); |
|||
Map<String, Object> result = new HashMap<String, Object>(16); |
|||
result.put(Constants.ERROR, "源文件解析异常"); |
|||
entity.setResult(result); |
|||
entity.setStatus(2); |
|||
entity.setDel(0); |
|||
entity.setInput(task); |
|||
//回传给api服务保存 |
|||
DownLoadUtil.doPost(saveUrl, JSONObject.toJSONString(entity)); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取视频分析结果 |
|||
*/ |
|||
public VideoResult getVideoAnalysisResult(String taskId) { |
|||
try { |
|||
AsyncClient client = getClient(); |
|||
GetVideoAnalysisTaskRequest request = GetVideoAnalysisTaskRequest.builder() |
|||
.taskId(taskId) |
|||
.workspaceId(workspaceId) |
|||
.build(); |
|||
|
|||
CompletableFuture<GetVideoAnalysisTaskResponse> responseFuture = |
|||
client.getVideoAnalysisTask(request); |
|||
GetVideoAnalysisTaskResponse response = responseFuture.get(); |
|||
|
|||
if (response != null && response.getBody().getSuccess() && |
|||
response.getBody().getData() != null) { |
|||
return parseVideoAnalysisResult(response.getBody().getData(), taskId); |
|||
} |
|||
|
|||
} catch (Exception e) { |
|||
log.error("获取视频解析结果异常", e); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
|
|||
|
|||
/** |
|||
* 解析视频分析结果 |
|||
*/ |
|||
private VideoResult parseVideoAnalysisResult(GetVideoAnalysisTaskResponseBody.Data data, String taskId) { |
|||
VideoResult result = new VideoResult(); |
|||
result.setTaskId(taskId); |
|||
result.setTaskStatus(data.getTaskStatus()); |
|||
|
|||
try { |
|||
String jsonStr = JSON.toJSONString(data); |
|||
JSONObject json = JSON.parseObject(jsonStr); |
|||
|
|||
// 提取错误信息 |
|||
if (json.containsKey("errorMessage")) { |
|||
result.setErrorMessage(json.getString("errorMessage")); |
|||
} |
|||
|
|||
// 提取payload中的数据 |
|||
if (json.containsKey("payload")) { |
|||
JSONObject payload = json.getJSONObject("payload"); |
|||
if (payload.containsKey("output")) { |
|||
JSONObject output = payload.getJSONObject("output"); |
|||
extractCaptionsFromOutput(output, result); |
|||
} |
|||
} |
|||
|
|||
// 提取header信息 |
|||
if (json.containsKey("header")) { |
|||
JSONObject header = json.getJSONObject("header"); |
|||
result.setHeaderInfo(JSON.toJSONString(header)); |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("解析视频分析结果异常", e); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* 从output中提取字幕 |
|||
*/ |
|||
private void extractCaptionsFromOutput(JSONObject output, VideoResult result) { |
|||
try { |
|||
// 提取视频字幕结果 |
|||
if (output.containsKey("videoCaptionResult")) { |
|||
JSONObject captionResult = output.getJSONObject("videoCaptionResult"); |
|||
if (captionResult.getBooleanValue("generateFinished") && |
|||
captionResult.containsKey("videoCaptions")) { |
|||
|
|||
JSONArray captions = captionResult.getJSONArray("videoCaptions"); |
|||
List<Map<String, Object>> subtitleList = new ArrayList<>(); |
|||
|
|||
for (int i = 0; i < captions.size(); i++) { |
|||
JSONObject caption = captions.getJSONObject(i); |
|||
Map<String, Object> subtitle = new HashMap<>(); |
|||
|
|||
// subtitle.put("startTime", caption.getLong("startTime")); |
|||
// subtitle.put("endTime", caption.getLong("endTime")); |
|||
subtitle.put("startTimeFormat", caption.getString("startTimeFormat")); |
|||
subtitle.put("endTimeFormat", caption.getString("endTimeFormat")); |
|||
subtitle.put("text", caption.getString("text")); |
|||
|
|||
// if (caption.containsKey("speaker")) { |
|||
// subtitle.put("speaker", caption.getString("speaker")); |
|||
// } |
|||
|
|||
subtitleList.add(subtitle); |
|||
} |
|||
|
|||
result.setSubtitles(subtitleList); |
|||
result.setCaptionCount(subtitleList.size()); |
|||
} |
|||
} |
|||
|
|||
} catch (Exception e) { |
|||
log.error("提取字幕异常", e); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 打印简化的字幕格式 |
|||
*/ |
|||
private String printSimpleCaptions(VideoResult result) { |
|||
if (result.getSubtitles() != null && !result.getSubtitles().isEmpty()) { |
|||
StringBuilder captionsBuilder = new StringBuilder(); |
|||
|
|||
for (Map<String, Object> subtitle : result.getSubtitles()) { |
|||
String startTime = (String) subtitle.get("startTimeFormat"); |
|||
String endTime = (String) subtitle.get("endTimeFormat"); |
|||
String text = (String) subtitle.get("text"); |
|||
String content = "[" + startTime + " - " + endTime + "] "+ text; |
|||
|
|||
// 添加到构建器 |
|||
captionsBuilder.append(content).append("\n"); |
|||
// 同时输出到控制台(如果需要的话) |
|||
System.out.println(content); |
|||
} |
|||
|
|||
// 返回所有字幕内容 |
|||
return captionsBuilder.toString(); |
|||
} else { |
|||
System.out.println("未检测到字幕内容"); |
|||
return "未检测到字幕内容"; |
|||
} |
|||
} |
|||
/** |
|||
* 从headerInfo中提取错误信息 |
|||
*/ |
|||
private String extractErrorMessageFromHeader(String headerInfo) { |
|||
try { |
|||
JSONObject json = JSON.parseObject(headerInfo); |
|||
|
|||
// 尝试提取errorMessage |
|||
if (json.containsKey("errorMessage")) { |
|||
String errorMsg = json.getString("errorMessage"); |
|||
|
|||
return errorMsg.length() > 200 ? |
|||
errorMsg.substring(0, 200) + "..." : errorMsg; |
|||
} |
|||
|
|||
if (json.containsKey("eventInfo")) { |
|||
return json.getString("eventInfo"); |
|||
} |
|||
|
|||
if (json.containsKey("errorCode")) { |
|||
return "错误代码: " + json.getString("errorCode"); |
|||
} |
|||
|
|||
} catch (Exception e) { |
|||
log.warn("解析headerInfo失败", e); |
|||
} |
|||
|
|||
// 如果解析失败,返回原始信息的前100个字符 |
|||
return headerInfo.length() > 100 ? |
|||
headerInfo.substring(0, 100) + "..." : headerInfo; |
|||
} |
|||
/** |
|||
* 映射语言参数(中文 -> 英文) |
|||
*/ |
|||
private String mapLanguage(String inputLanguage) { |
|||
if (inputLanguage == null || inputLanguage.trim().isEmpty()) { |
|||
return "chinese"; // 默认中文 |
|||
} |
|||
|
|||
String trimmed = inputLanguage.trim().toLowerCase(); |
|||
|
|||
// 首先尝试精确匹配 |
|||
for (Map.Entry<String, String> entry : LANGUAGE_MAPPING.entrySet()) { |
|||
if (trimmed.equals(entry.getKey().toLowerCase())) { |
|||
return entry.getValue(); |
|||
} |
|||
} |
|||
|
|||
// 尝试包含匹配(支持更灵活的输入) |
|||
for (Map.Entry<String, String> entry : LANGUAGE_MAPPING.entrySet()) { |
|||
if (trimmed.contains(entry.getKey().toLowerCase())) { |
|||
log.debug("语言包含匹配: {} -> {}", trimmed, entry.getValue()); |
|||
return entry.getValue(); |
|||
} |
|||
} |
|||
// 默认返回中文 |
|||
log.warn("无法识别的语言输入: {}, 使用默认值: chinese", inputLanguage); |
|||
return "chinese"; |
|||
} |
|||
/** |
|||
* 测试方法 |
|||
*/ |
|||
// public static void main(String[] args) { |
|||
// try { |
|||
// System.out.println("=== 视频字幕提取测试 ===\n"); |
|||
// |
|||
// // 创建服务实例 |
|||
// AsrTaskServiceImpl service = new AsrTaskServiceImpl(); |
|||
// |
|||
// // 设置配置 |
|||
// service.accessKeyId = "LTAI5tDbzNNXnSg9r6ncQi2x"; |
|||
// service.accessKeySecret = "f8aX6BM8ZiQbEfL1o4gcvX2PsziCw3"; |
|||
// service.workspaceId = "llm-7qk6vvzgxq7qhl8e"; |
|||
// service.modelId = "quanmiao-llm-plus"; |
|||
// service.videoModelId = "quanmiao-vl-plus"; |
|||
// service.language = "chinese"; |
|||
// |
|||
// // 测试视频URL |
|||
// String testVideoUrl = "https://vd9.bdstatic.com/mda-rmggrjqeweys54r8/mb/cae_h264/1765977811688977696/mda-rmggrjqeweys54r8.mp4"; |
|||
// |
|||
// // 创建任务 |
|||
// Map<String, Object> task = new HashMap<>(); |
|||
// task.put("videoUrl", testVideoUrl); |
|||
// |
|||
// System.out.println("提交视频分析任务..."); |
|||
// System.out.println("视频URL: " + testVideoUrl); |
|||
// |
|||
// // 提交任务 |
|||
// service.create(task); |
|||
// |
|||
// // 等待任务处理(实际使用中可以通过回调或轮询获取结果) |
|||
// System.out.println("任务已提交,正在处理中..."); |
|||
// |
|||
// // 为了测试,我们可以等待一段时间后手动获取结果 |
|||
// Thread.sleep(30000); // 等待30秒 |
|||
// |
|||
// String taskId = (String) task.get("taskId"); |
|||
// if (taskId != null) { |
|||
// System.out.println("\n任务ID: " + taskId); |
|||
// |
|||
// // 获取简化字幕 |
|||
// System.out.println("\n=== 提取到的字幕 ==="); |
|||
// String captions = service.getSimplifiedCaptions(taskId); |
|||
// System.out.println(captions); |
|||
// } |
|||
// |
|||
// } catch (Exception e) { |
|||
// System.err.println("测试失败: " + e.getMessage()); |
|||
// e.printStackTrace(); |
|||
// } |
|||
// } |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
package com.bw.asr.service.impl; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.bw.asr.cache.ConfigCache; |
|||
import com.bw.asr.entity.Constants; |
|||
import com.bw.asr.service.TaskReceiveService; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
/** |
|||
* 任务接收服务层实现类 |
|||
* @author jian.mao |
|||
* @date 2025年1月14日 |
|||
* @description |
|||
*/ |
|||
@Service |
|||
@Slf4j |
|||
public class TaskReceiveServiceImpl implements TaskReceiveService { |
|||
|
|||
@Override |
|||
public String put(String dataJson) { |
|||
Map<String, Object> response = new HashMap<>(16); |
|||
int code = 200; |
|||
String message = "success"; |
|||
Map<String, Object> task = null; |
|||
try { |
|||
task = JSONObject.parseObject(dataJson); |
|||
} catch (Exception e) { |
|||
log.error("参数结构不合法,", e); |
|||
code = 100010; |
|||
message = "参数不合法"; |
|||
} |
|||
// 写入队列 |
|||
try { |
|||
if(task.containsKey(Constants.TRACE) && (boolean)task.get(Constants.TRACE)){ |
|||
ConfigCache.taskQueue.putFirst(task); |
|||
}else{ |
|||
ConfigCache.taskQueue.put(task); |
|||
} |
|||
} catch (InterruptedException e) { |
|||
log.error("任务写入队列异常,", e); |
|||
code = 100011; |
|||
message = "任务写入队列失败"; |
|||
} |
|||
response.put(Constants.CODE, code); |
|||
response.put(Constants.MESSAGE, message); |
|||
return JSONObject.toJSONString(response); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,177 @@ |
|||
package com.bw.asr.utils; |
|||
|
|||
|
|||
import java.math.BigInteger; |
|||
import java.security.MessageDigest; |
|||
import java.security.NoSuchAlgorithmException; |
|||
import java.text.ParseException; |
|||
import java.text.SimpleDateFormat; |
|||
import java.time.LocalDateTime; |
|||
import java.time.format.DateTimeFormatter; |
|||
import java.util.Date; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import com.alibaba.fastjson.JSON; |
|||
import com.alibaba.fastjson.JSONObject; |
|||
|
|||
/** |
|||
* 日期工具类 |
|||
* |
|||
* @author jian.mao |
|||
* @date 2022年11月15日 |
|||
* @description |
|||
*/ |
|||
@Slf4j |
|||
public class DateUtil { |
|||
|
|||
/** |
|||
* @return |
|||
*/ |
|||
public static String getTimeStrForNow() { |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH"); |
|||
return sdf.format(new Date()); |
|||
} |
|||
|
|||
|
|||
public static String getTimeStrForDay(long time) { |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); |
|||
|
|||
return sdf.format(new Date(time * 1000)); |
|||
} |
|||
|
|||
public static String getTimeStrForDay() { |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); |
|||
|
|||
return sdf.format(new Date()); |
|||
} |
|||
|
|||
|
|||
public static String getDateTime() { |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
|||
String time = sdf.format(new Date()); |
|||
return time; |
|||
} |
|||
|
|||
public static String getDateTime(Long timestap) { |
|||
|
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
|||
String time = sdf.format(new Date(timestap)); |
|||
return time; |
|||
} |
|||
|
|||
public static String getDate(Long timestap) { |
|||
|
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
|||
String time = sdf.format(new Date(timestap)); |
|||
return time; |
|||
} |
|||
|
|||
public static String getDateTimeForMonth() { |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM"); |
|||
String time = sdf.format(new Date()); |
|||
return time; |
|||
} |
|||
|
|||
/** |
|||
* 休眠 |
|||
* |
|||
* @param millis 毫秒 |
|||
*/ |
|||
public static void sleep(long millis) { |
|||
try { |
|||
Thread.sleep(millis); |
|||
} catch (InterruptedException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 1. @Description:时间戳转时间 |
|||
* 2. @Author: ying.zhao |
|||
* 3. @Date: 2023/3/28 |
|||
*/ |
|||
|
|||
public static String timestampToDate(String time) { |
|||
int thirteen = 13; |
|||
int ten = 10; |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
|||
// if (time.length() == thirteen) { |
|||
if (time.length() > ten) { |
|||
return sdf.format(new Date(Long.parseLong(time))); |
|||
} else { |
|||
return sdf.format(new Date(Integer.parseInt(time) * 1000L)); |
|||
} |
|||
} |
|||
|
|||
public static String parseCreated(String jsonTime){ |
|||
String formattedDateTime = getDateTime(); |
|||
try { |
|||
// 使用fastjson解析JSON数据 |
|||
JSONObject jsonObject = JSON.parseObject(jsonTime); |
|||
// 获取日期和时间的值 |
|||
JSONObject dateObject = jsonObject.getJSONObject("date"); |
|||
int day = dateObject.getIntValue("day"); |
|||
int month = dateObject.getIntValue("month"); |
|||
int year = dateObject.getIntValue("year"); |
|||
|
|||
JSONObject timeObject = jsonObject.getJSONObject("time"); |
|||
int hour = timeObject.getIntValue("hour"); |
|||
int minute = timeObject.getIntValue("minute"); |
|||
int second = timeObject.getIntValue("second"); |
|||
|
|||
// 创建LocalDateTime对象 |
|||
LocalDateTime dateTime = LocalDateTime.of(year, month, day, hour, minute, second); |
|||
|
|||
// 定义日期时间格式化器 |
|||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
|||
|
|||
// 格式化日期时间 |
|||
formattedDateTime = dateTime.format(formatter); |
|||
} catch (Exception e) { |
|||
log.info("日期转换失败:{}",e); |
|||
} |
|||
return formattedDateTime; |
|||
} |
|||
|
|||
/** |
|||
* 字符串转换日期 |
|||
* @param format |
|||
* @param date |
|||
* @return |
|||
*/ |
|||
public static Date strToDate(String format,String date){ |
|||
SimpleDateFormat sdf = new SimpleDateFormat(format); |
|||
if (date == null || date.equals("")){ |
|||
return new Date(); |
|||
}else{ |
|||
Date ru = null; |
|||
try { |
|||
ru = sdf.parse(date); |
|||
} catch (ParseException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
return ru; |
|||
} |
|||
} |
|||
/** |
|||
* 日期格式话 |
|||
* @param format 日期格式 |
|||
* @param dater 要转换的日期,默认当前时间 |
|||
* @return |
|||
*/ |
|||
public static String FormatDate(String format,Date date){ |
|||
String fromatDate = null; |
|||
SimpleDateFormat sdf = new SimpleDateFormat(format); |
|||
if (date == null){ |
|||
fromatDate = sdf.format(new Date()); |
|||
}else{ |
|||
fromatDate = sdf.format(date); |
|||
} |
|||
return fromatDate; |
|||
} |
|||
public static void main(String[] args) { |
|||
String time = timestampToDate("955814400000"); |
|||
System.out.println(time); |
|||
} |
|||
} |
|||
1045
asr-service/src/main/java/com/bw/asr/utils/DownLoadUtil.java
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,41 @@ |
|||
package com.bw.asr.utils; |
|||
|
|||
import java.io.File; |
|||
import java.io.FileWriter; |
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* 文件工具类 |
|||
* @author jian.mao |
|||
* @date 2023年7月14日 |
|||
* @description |
|||
*/ |
|||
public class FileUtil { |
|||
|
|||
/** |
|||
* 数据写入文件 |
|||
* @param Path 文件路径 |
|||
* @param result 数据 |
|||
* @throws IOException |
|||
*/ |
|||
public static void writeFile(String path,String result){ |
|||
try { |
|||
FileWriter fw = new FileWriter(path,true); |
|||
fw.write(result+"\n"); |
|||
fw.flush(); |
|||
fw.close(); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
public static void delFile(String path) { |
|||
try { |
|||
File file = new File(path); |
|||
file.delete(); |
|||
} catch (Exception e) { |
|||
// TODO: handle exception |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
package com.bw.asr.utils; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.kafka.core.KafkaTemplate; |
|||
import org.springframework.kafka.support.SendResult; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.util.concurrent.ListenableFuture; |
|||
import org.springframework.util.concurrent.ListenableFutureCallback; |
|||
|
|||
/** |
|||
* @PROJECT_NAME: companybusinesscrawl |
|||
* @DESCRIPTION:SpringBootKafka 工具类 |
|||
* @DATE: 2023/4/6 11:09 |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
public class SpringBootKafka { |
|||
@Autowired |
|||
private KafkaTemplate<String, Object> kafkaTemplate; |
|||
/** |
|||
* 自定义topicKafkaTemplate |
|||
*/ |
|||
/** |
|||
* public static final String TOPIC = "companyBussTest"; |
|||
**/ |
|||
public void send(String topic, String message) { |
|||
//发送消息 |
|||
ListenableFuture<SendResult<String, Object>> future = kafkaTemplate.send(topic, message); |
|||
future.addCallback(new ListenableFutureCallback<SendResult<String, Object>>() { |
|||
@Override |
|||
public void onFailure(Throwable throwable) { |
|||
//发送失败的处理 |
|||
log.info(topic + " - 生产者 发送消息失败:" + throwable.getMessage()); |
|||
} |
|||
|
|||
@Override |
|||
public void onSuccess(SendResult<String, Object> stringObjectSendResult) { |
|||
//成功的处理 |
|||
log.info(topic + " - 生产者 发送消息成功" ); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
package com.bw.asr.utils; |
|||
|
|||
import java.io.PrintWriter; |
|||
import java.io.StringWriter; |
|||
|
|||
/** |
|||
* @author jian.mao |
|||
* @date 2023年3月22日 |
|||
* @description |
|||
*/ |
|||
public class ThrowMessageUtil { |
|||
|
|||
/** |
|||
* 获取异常信息 |
|||
* @param t |
|||
* @return |
|||
*/ |
|||
public static String getErrmessage(Throwable t){ |
|||
StringWriter stringWriter=new StringWriter(); |
|||
t.printStackTrace(new PrintWriter(stringWriter,true)); |
|||
return stringWriter.getBuffer().toString(); |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
# ==================== 必须文件:bootstrap.yml ==================== |
|||
# 这个文件用于配置Nacos客户端,优先级最高 |
|||
spring: |
|||
application: |
|||
name: asr-service # 服务名,对应Nacos中的Data ID |
|||
|
|||
cloud: |
|||
nacos: |
|||
# ======== 配置中心 ======== |
|||
config: |
|||
server-addr: 127.0.0.1:8848 # Nacos地址 |
|||
username: nacos # 用户名 |
|||
password: nacos # 密码 |
|||
group: public_dev # 分组 |
|||
namespace: opai # 命名空间(默认public) |
|||
file-extension: yaml # 配置文件格式 |
|||
timeout: 5000 # 超时时间(ms) |
|||
|
|||
# 核心配置:开启动态刷新 |
|||
refresh-enabled: true # 必须为true! |
|||
|
|||
# 主配置文件(从Nacos加载) |
|||
data-id: ${spring.application.name}.${spring.cloud.nacos.config.file-extension} |
|||
|
|||
# 共享配置文件(可选) |
|||
shared-configs[0]: |
|||
data-id: application.yaml # 公共配置 |
|||
group: public_dev # 公共分组 |
|||
namespace: opai |
|||
refresh: true # 公共配置也要刷新 |
|||
|
|||
# 扩展配置(可选) |
|||
# extension-configs[0]: |
|||
# data-id: datasource.yaml |
|||
# group: dev |
|||
# refresh: true |
|||
|
|||
# ======== 服务发现 ======== |
|||
discovery: |
|||
server-addr: ${spring.cloud.nacos.config.server-addr} |
|||
username: ${spring.cloud.nacos.config.username} |
|||
password: ${spring.cloud.nacos.config.password} |
|||
group: ${spring.cloud.nacos.config.group} |
|||
namespace: ${spring.cloud.nacos.config.namespace} |
|||
|
|||
logging: |
|||
level: |
|||
root: info |
|||
com.alibaba.nacos.client.config.impl: WARN |
|||
file: |
|||
path: ../logs |
|||
|
|||
@ -0,0 +1,36 @@ |
|||
<configuration> |
|||
<!-- 属性文件:在properties文件中找到对应的配置项 --> |
|||
<springProperty scope="context" name="log-path" source="logging.file.path"/> |
|||
<!--<springProperty scope="context" name="logging.level" source="logging.level.com.bfd"/>--> |
|||
<!-- 默认的控制台日志输出,一般生产环境都是后台启动,这个没太大作用 --> |
|||
<!-- <appender name="STDOUT" |
|||
class="ch.qos.logback.core.ConsoleAppender"> |
|||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
|||
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %line %-5level %logger{50} - %msg%n</Pattern> |
|||
</encoder> |
|||
</appender> --> |
|||
|
|||
<appender name="GLMAPPER-LOGGERONE" |
|||
class="ch.qos.logback.core.rolling.RollingFileAppender"> |
|||
<append>true</append> |
|||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> |
|||
<level>${logging.level}</level> |
|||
</filter> |
|||
<file> |
|||
${log-path}/asr-service.log |
|||
</file> |
|||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
|||
<FileNamePattern>${log-path}/asr-service.log.%d{yyyy-MM-dd}</FileNamePattern> |
|||
<MaxHistory>7</MaxHistory> |
|||
</rollingPolicy> |
|||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
|||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %line %-5level %logger{50} - %msg%n</pattern> |
|||
<charset>UTF-8</charset> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<root level="info"> |
|||
<appender-ref ref="GLMAPPER-LOGGERONE"/> |
|||
<!-- <appender-ref ref="STDOUT"/> --> |
|||
</root> |
|||
</configuration> |
|||
@ -1,38 +0,0 @@ |
|||
package com.bw; |
|||
|
|||
import junit.framework.Test; |
|||
import junit.framework.TestCase; |
|||
import junit.framework.TestSuite; |
|||
|
|||
/** |
|||
* Unit test for simple App. |
|||
*/ |
|||
public class AppTest |
|||
extends TestCase |
|||
{ |
|||
/** |
|||
* Create the test case |
|||
* |
|||
* @param testName name of the test case |
|||
*/ |
|||
public AppTest( String testName ) |
|||
{ |
|||
super( testName ); |
|||
} |
|||
|
|||
/** |
|||
* @return the suite of tests being tested |
|||
*/ |
|||
public static Test suite() |
|||
{ |
|||
return new TestSuite( AppTest.class ); |
|||
} |
|||
|
|||
/** |
|||
* Rigourous Test :-) |
|||
*/ |
|||
public void testApp() |
|||
{ |
|||
assertTrue( true ); |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<classpath> |
|||
<classpathentry kind="src" output="target/classes" path="src/main/java"> |
|||
<attributes> |
|||
<attribute name="optional" value="true"/> |
|||
<attribute name="maven.pomderived" value="true"/> |
|||
</attributes> |
|||
</classpathentry> |
|||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"> |
|||
<attributes> |
|||
<attribute name="maven.pomderived" value="true"/> |
|||
<attribute name="optional" value="true"/> |
|||
</attributes> |
|||
</classpathentry> |
|||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"> |
|||
<attributes> |
|||
<attribute name="optional" value="true"/> |
|||
<attribute name="maven.pomderived" value="true"/> |
|||
<attribute name="test" value="true"/> |
|||
</attributes> |
|||
</classpathentry> |
|||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"> |
|||
<attributes> |
|||
<attribute name="maven.pomderived" value="true"/> |
|||
<attribute name="test" value="true"/> |
|||
<attribute name="optional" value="true"/> |
|||
</attributes> |
|||
</classpathentry> |
|||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"> |
|||
<attributes> |
|||
<attribute name="maven.pomderived" value="true"/> |
|||
</attributes> |
|||
</classpathentry> |
|||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> |
|||
<attributes> |
|||
<attribute name="maven.pomderived" value="true"/> |
|||
</attributes> |
|||
</classpathentry> |
|||
<classpathentry kind="output" path="target/classes"/> |
|||
</classpath> |
|||
@ -0,0 +1 @@ |
|||
/target/ |
|||
@ -0,0 +1,23 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<projectDescription> |
|||
<name>funasr-service</name> |
|||
<comment></comment> |
|||
<projects> |
|||
</projects> |
|||
<buildSpec> |
|||
<buildCommand> |
|||
<name>org.eclipse.jdt.core.javabuilder</name> |
|||
<arguments> |
|||
</arguments> |
|||
</buildCommand> |
|||
<buildCommand> |
|||
<name>org.eclipse.m2e.core.maven2Builder</name> |
|||
<arguments> |
|||
</arguments> |
|||
</buildCommand> |
|||
</buildSpec> |
|||
<natures> |
|||
<nature>org.eclipse.jdt.core.javanature</nature> |
|||
<nature>org.eclipse.m2e.core.maven2Nature</nature> |
|||
</natures> |
|||
</projectDescription> |
|||
@ -0,0 +1,4 @@ |
|||
eclipse.preferences.version=1 |
|||
encoding//src/main/java=UTF-8 |
|||
encoding//src/main/resources=UTF-8 |
|||
encoding/<project>=UTF-8 |
|||
@ -0,0 +1,9 @@ |
|||
eclipse.preferences.version=1 |
|||
org.eclipse.jdt.core.compiler.codegen.methodParameters=generate |
|||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 |
|||
org.eclipse.jdt.core.compiler.compliance=1.8 |
|||
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled |
|||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning |
|||
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore |
|||
org.eclipse.jdt.core.compiler.release=disabled |
|||
org.eclipse.jdt.core.compiler.source=1.8 |
|||
@ -0,0 +1,4 @@ |
|||
activeProfiles= |
|||
eclipse.preferences.version=1 |
|||
resolveWorkspaceProjects=true |
|||
version=1 |
|||
@ -0,0 +1,213 @@ |
|||
<?xml version="1.0"?> |
|||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<parent> |
|||
<groupId>com.bw</groupId> |
|||
<artifactId>opai-service-center</artifactId> |
|||
<version>0.0.1-SNAPSHOT</version> |
|||
</parent> |
|||
<groupId>com.bw</groupId> |
|||
<artifactId>funasr-service</artifactId> |
|||
<version>0.0.1-SNAPSHOT</version> |
|||
<name>funasr-service</name> |
|||
<url>http://maven.apache.org</url> |
|||
<properties> |
|||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|||
</properties> |
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>junit</groupId> |
|||
<artifactId>junit</artifactId> |
|||
<version>3.8.1</version> |
|||
<scope>test</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-web</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.alibaba.cloud</groupId> |
|||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.cloud</groupId> |
|||
<artifactId>spring-cloud-starter-openfeign</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.alibaba.cloud</groupId> |
|||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-actuator</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.projectlombok</groupId> |
|||
<artifactId>lombok</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.alibaba</groupId> |
|||
<artifactId>fastjson</artifactId> |
|||
<version>2.0.17</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.httpcomponents</groupId> |
|||
<artifactId>httpclient</artifactId> |
|||
<version>4.5.3</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.httpcomponents</groupId> |
|||
<artifactId>httpmime</artifactId> |
|||
<version>4.5.13</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>commons-lang</groupId> |
|||
<artifactId>commons-lang</artifactId> |
|||
<version>2.6</version> |
|||
</dependency> |
|||
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp --> |
|||
<dependency> |
|||
<groupId>com.squareup.okhttp3</groupId> |
|||
<artifactId>okhttp</artifactId> |
|||
<version>3.14.9</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.kafka</groupId> |
|||
<artifactId>spring-kafka</artifactId> |
|||
</dependency> |
|||
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> |
|||
<dependency> |
|||
<groupId>org.apache.poi</groupId> |
|||
<artifactId>poi</artifactId> |
|||
<version>4.1.2</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.poi</groupId> |
|||
<artifactId>poi-ooxml</artifactId> |
|||
<version>4.1.2</version> |
|||
</dependency> |
|||
|
|||
<!-- Fastjson2 --> |
|||
<dependency> |
|||
<groupId>com.alibaba.fastjson2</groupId> |
|||
<artifactId>fastjson2</artifactId> |
|||
<version>2.0.21</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.aliyun</groupId> |
|||
<artifactId>alibabacloud-quanmiaolightapp20240801</artifactId> |
|||
<version>2.0.33</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.aliyun</groupId> |
|||
<artifactId>alibabacloud-aimiaobi20230801</artifactId> |
|||
<version>1.0.89</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.projectlombok</groupId> |
|||
<artifactId>lombok</artifactId> |
|||
<version>1.18.30</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.alibaba</groupId> |
|||
<artifactId>dashscope-sdk-java</artifactId> |
|||
<version>2.14.3</version> |
|||
</dependency> |
|||
</dependencies> |
|||
<build> |
|||
<!-- <pluginManagement> --><!-- lock down plugins versions to avoid using Maven defaults (may be |
|||
moved |
|||
to parent pom) --> |
|||
<plugins> |
|||
<!-- clean lifecycle, see |
|||
https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle --> |
|||
<plugin> |
|||
<artifactId>maven-clean-plugin</artifactId> |
|||
<version>3.1.0</version> |
|||
</plugin> |
|||
<!-- default lifecycle, jar packaging: see |
|||
https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging --> |
|||
<plugin> |
|||
<artifactId>maven-resources-plugin</artifactId> |
|||
<version>3.0.2</version> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-compiler-plugin</artifactId> |
|||
<version>3.8.0</version> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-surefire-plugin</artifactId> |
|||
<version>2.22.1</version> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-jar-plugin</artifactId> |
|||
<version>3.0.2</version> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-install-plugin</artifactId> |
|||
<version>2.5.2</version> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-deploy-plugin</artifactId> |
|||
<version>2.8.2</version> |
|||
</plugin> |
|||
<!-- site lifecycle, see |
|||
https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle --> |
|||
<plugin> |
|||
<artifactId>maven-site-plugin</artifactId> |
|||
<version>3.7.1</version> |
|||
</plugin> |
|||
<plugin> |
|||
<artifactId>maven-project-info-reports-plugin</artifactId> |
|||
<version>3.0.0</version> |
|||
</plugin> |
|||
<!-- spring-boot-maven-plugin插件就是打包spring boot应用的 --> |
|||
|
|||
<plugin> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-maven-plugin</artifactId> |
|||
<configuration> |
|||
<mainClass>com.bw.funasr.Application</mainClass> |
|||
<layout>ZIP</layout> |
|||
<includes> |
|||
<include> |
|||
<groupId>${project.groupId}</groupId> |
|||
<artifactId>${project.artifactId}</artifactId> |
|||
</include> |
|||
</includes> |
|||
</configuration> |
|||
<executions> |
|||
<execution> |
|||
<goals> |
|||
<goal>repackage</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-dependency-plugin</artifactId> |
|||
<version>3.1.1</version> |
|||
<executions> |
|||
<execution> |
|||
<id>copy</id> |
|||
<phase>package</phase> |
|||
<goals> |
|||
<goal>copy-dependencies</goal> |
|||
</goals> |
|||
<configuration> |
|||
<type>jar</type> |
|||
<includeTypes>jar</includeTypes> |
|||
<includeScope>runtime</includeScope> |
|||
<outputDirectory>${project.build.directory}/libs</outputDirectory> |
|||
</configuration> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
<!-- </pluginManagement> --> |
|||
</build> |
|||
</project> |
|||
|
|||
@ -0,0 +1,19 @@ |
|||
package com.bw.funasr; |
|||
|
|||
import org.springframework.boot.SpringApplication; |
|||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
|||
|
|||
|
|||
/** |
|||
* 系统接口启动类 |
|||
* @author jian.mao |
|||
* @date 2025年12月30日 |
|||
* @description |
|||
*/ |
|||
@SpringBootApplication |
|||
public class Application { |
|||
|
|||
public static void main(String[] args) { |
|||
SpringApplication.run(Application.class, args); |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
package com.bw.funasr.cache; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import java.util.Map; |
|||
import java.util.concurrent.LinkedBlockingDeque; |
|||
|
|||
/** |
|||
* @author jian.mao |
|||
* @date 2022年11月11日 |
|||
* @description 静态变量类 |
|||
*/ |
|||
@Slf4j |
|||
public class ConfigCache { |
|||
|
|||
/**启动条件**/ |
|||
public static boolean isStart = true; |
|||
/*****任务队列*****/ |
|||
public static LinkedBlockingDeque<Map<String, Object>> taskQueue = new LinkedBlockingDeque<Map<String,Object>>(); |
|||
/****结果队列****/ |
|||
public static LinkedBlockingDeque<Map<String, Object>> resultQueue = new LinkedBlockingDeque<Map<String,Object>>(); |
|||
|
|||
|
|||
/** |
|||
* 队列录入任务 |
|||
* @param queue |
|||
* @param task |
|||
*/ |
|||
public static void putQueue(LinkedBlockingDeque<Map<String, Object>> queue,Map<String, Object> task){ |
|||
//next app 写入队列准备调出 |
|||
try { |
|||
queue.put(task); |
|||
} catch (InterruptedException e) { |
|||
log.error("队列写入data失败---"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
package com.bw.funasr.controller; |
|||
|
|||
import javax.annotation.Resource; |
|||
|
|||
import org.springframework.stereotype.Controller; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestBody; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestMethod; |
|||
import org.springframework.web.bind.annotation.ResponseBody; |
|||
|
|||
import com.bw.funasr.service.TaskReceiveService; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
/** |
|||
* 任务接收控制层 |
|||
* @author jian.mao |
|||
* @date 2025年1月14日 |
|||
* @description |
|||
*/ |
|||
@Controller |
|||
@RequestMapping("/task") |
|||
@Slf4j |
|||
public class TaskReceiveController { |
|||
@Resource |
|||
private TaskReceiveService taskReceiveService; |
|||
@PostMapping("/put") |
|||
@ResponseBody |
|||
public String put(@RequestBody String param){ |
|||
String response = taskReceiveService.put(param); |
|||
return response; |
|||
} |
|||
@RequestMapping(value = "/hello", method = RequestMethod.GET) |
|||
@ResponseBody |
|||
public String hello(String param, String token) { |
|||
return "123"; |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
package com.bw.funasr.entity; |
|||
|
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Map; |
|||
|
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* ES 索引:opai_app_result |
|||
* 应用执行结果文档 |
|||
* |
|||
* @author jian.mao |
|||
*/ |
|||
@Data |
|||
public class AppResultDoc implements Serializable { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** 任务ID */ |
|||
private String taskId; |
|||
|
|||
/** 应用id */ |
|||
private Integer appId; |
|||
|
|||
/** 状态 0 进行中,1成功,2失败 */ |
|||
private Integer status; |
|||
|
|||
/** 创建时间(毫秒时间戳) */ |
|||
private Long createTime; |
|||
|
|||
/** 执行结果(可索引) */ |
|||
private Map<String, Object> result; |
|||
|
|||
/** 逻辑删除标识:0-未删除 1-已删除 */ |
|||
private Integer del; |
|||
|
|||
/***前端输入参数 ***/ |
|||
private Map<String, Object> input; |
|||
|
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
package com.bw.funasr.entity; |
|||
|
|||
|
|||
/** |
|||
* 常量实体类 |
|||
* @author jian.mao |
|||
* @date 2022年11月15日 |
|||
* @description |
|||
*/ |
|||
|
|||
public class Constants { |
|||
|
|||
/** |
|||
* 空字符串常量 |
|||
*/ |
|||
public static final String EMPTY = ""; |
|||
|
|||
/************************应用参数*************************************/ |
|||
public static final String CODE = "code"; |
|||
public static final String ID = "id"; |
|||
public static final String MESSAGE = "message"; |
|||
/******************************api使用*******************************/ |
|||
public static final String ERROR = "error"; |
|||
public static final String VIDEOURL = "videoUrl"; |
|||
public static final String VOICECONTENT = "voiceContent"; |
|||
public static final String TRACE = "trace"; |
|||
public static final String JOBID = "jobId"; |
|||
|
|||
|
|||
/** |
|||
* 任务id |
|||
*/ |
|||
public static final String TASKID = "taskId"; |
|||
} |
|||
@ -0,0 +1,206 @@ |
|||
package com.bw.funasr.handler; |
|||
|
|||
import java.io.File; |
|||
import java.io.IOException; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.concurrent.LinkedBlockingDeque; |
|||
import java.util.concurrent.LinkedBlockingQueue; |
|||
import java.util.concurrent.ThreadPoolExecutor; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
|
|||
import org.apache.commons.io.FileUtils; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.ApplicationArguments; |
|||
import org.springframework.boot.ApplicationRunner; |
|||
import org.springframework.core.annotation.Order; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.bw.funasr.cache.ConfigCache; |
|||
import com.bw.funasr.service.FunasrTaskService; |
|||
import com.bw.funasr.utils.DateUtil; |
|||
import com.bw.funasr.utils.FileUtil; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
|
|||
/** |
|||
* @author jian.mao |
|||
* @date 2025年1月13日 |
|||
* @description |
|||
*/ |
|||
@Component |
|||
@Order(value = 1) |
|||
@Slf4j |
|||
public class MainHandler implements ApplicationRunner { |
|||
|
|||
@Value("${task.task-queue-path}") |
|||
private String taskPath; |
|||
@Value("${task.result-task-queue-path}") |
|||
private String resultTaskPath; |
|||
@Autowired |
|||
private FunasrTaskService funasrTaskService; |
|||
/***线程池参数***/ |
|||
@Value("${threadPool.corePoolSize}") |
|||
private int corePoolSize; |
|||
@Value("${threadPool.maximumPoolSize}") |
|||
private int maximumPoolSize; |
|||
@Value("${threadPool.keepAliveTime}") |
|||
private long keepAliveTime; |
|||
@Value("${threadPool.queueSize}") |
|||
private int queueSize; |
|||
|
|||
/** |
|||
*执行入口 |
|||
*/ |
|||
@Override |
|||
public void run(ApplicationArguments args) throws Exception { |
|||
//线程池方式 |
|||
ThreadPoolExecutor executor = new ThreadPoolExecutor( |
|||
corePoolSize, |
|||
maximumPoolSize, |
|||
keepAliveTime, |
|||
TimeUnit.SECONDS, |
|||
new LinkedBlockingQueue<>(queueSize), |
|||
new ThreadPoolExecutor.CallerRunsPolicy() |
|||
); |
|||
//消费创建任务队列数据 |
|||
Thread consumerThread = new Thread(() -> { |
|||
while (true) { |
|||
try { |
|||
// 从队列中获取任务 |
|||
Map<String, Object> task = ConfigCache.taskQueue.take(); |
|||
// 提交给线程池执行 |
|||
executor.execute(() -> createTask(task)); |
|||
} catch (InterruptedException e) { |
|||
// 恢复中断状态 |
|||
Thread.currentThread().interrupt(); |
|||
log.error("任务消费线程被中断"); |
|||
break; |
|||
} |
|||
} |
|||
}); |
|||
consumerThread.start(); |
|||
log.info("创建任务消费线程启动-----"); |
|||
|
|||
|
|||
//消费结果任务队列数据 |
|||
Thread resultConsumerThread = new Thread(() -> { |
|||
while (true) { |
|||
try { |
|||
// 从队列中获取任务 |
|||
Map<String, Object> task = ConfigCache.resultQueue.take(); |
|||
// 提交给线程池执行 |
|||
executor.execute(() -> getResult(task)); |
|||
} catch (InterruptedException e) { |
|||
// 恢复中断状态 |
|||
Thread.currentThread().interrupt(); |
|||
log.error("任务消费线程被中断"); |
|||
break; |
|||
} |
|||
DateUtil.sleep(3000); |
|||
} |
|||
}); |
|||
resultConsumerThread.start(); |
|||
log.info("结果任务消费线程启动-----"); |
|||
//启动加载缓存任务 |
|||
readTask(taskPath, ConfigCache.taskQueue); |
|||
readTask(resultTaskPath, ConfigCache.resultQueue); |
|||
//停止处理 |
|||
waitDown(); |
|||
} |
|||
|
|||
/** |
|||
* 创建任务执行方法 |
|||
* @param task |
|||
*/ |
|||
private void createTask(Map<String, Object> task) { |
|||
funasrTaskService.create(task); |
|||
} |
|||
|
|||
private void getResult(Map<String, Object> task) { |
|||
funasrTaskService.parse(task); |
|||
} |
|||
|
|||
|
|||
/****************************************************************load******************************************************************************/ |
|||
/** |
|||
* 加载文件中的任务 |
|||
* @param path 文件地址 |
|||
* @param queue 队列 |
|||
*/ |
|||
@SuppressWarnings("unchecked") |
|||
public static void readTask(String path, LinkedBlockingDeque<Map<String, Object>> queue) { |
|||
File file = new File(path); |
|||
if (file.exists()) { |
|||
List<String> tasks = null; |
|||
try { |
|||
tasks = FileUtils.readLines(file, "UTF-8"); |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
for (String taskStr : tasks) { |
|||
Map<String, Object> task = JSONObject.parseObject(taskStr); |
|||
try { |
|||
queue.put(task); |
|||
} catch (InterruptedException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
file.delete(); |
|||
} |
|||
} |
|||
|
|||
/*******************************************************************stop************************************************************************/ |
|||
|
|||
/** |
|||
* 结束触发钩子 |
|||
*/ |
|||
public void waitDown() { |
|||
Runtime.getRuntime().addShutdownHook(new Thread() { |
|||
@Override |
|||
public void run() { |
|||
// 停止线程 |
|||
ConfigCache.isStart = false; |
|||
log.info("stop-------"); |
|||
writeTsskToFile(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 任务持久化到硬盘 |
|||
*/ |
|||
public void writeTsskToFile() { |
|||
while (true) { |
|||
if (ConfigCache.taskQueue.size() > 0) { |
|||
try { |
|||
Map<String, Object> task = ConfigCache.taskQueue.take(); |
|||
FileUtil.writeFile(taskPath, JSONObject.toJSONString(task)); |
|||
} catch (InterruptedException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} else { |
|||
log.info("taskQueue write is file end"); |
|||
break; |
|||
} |
|||
} |
|||
while (true) { |
|||
if (ConfigCache.resultQueue.size() > 0) { |
|||
try { |
|||
Map<String, Object> task = ConfigCache.resultQueue.take(); |
|||
FileUtil.writeFile(resultTaskPath, JSONObject.toJSONString(task)); |
|||
} catch (InterruptedException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} else { |
|||
log.info("taskQueue write is file end"); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
package com.bw.funasr.service; |
|||
|
|||
import java.util.Map; |
|||
|
|||
public interface FunasrTaskService { |
|||
/** |
|||
* ocr远端任务 |
|||
* @param task |
|||
*/ |
|||
public void create(Map<String, Object> task); |
|||
/** |
|||
* 解析结果 |
|||
* @param task |
|||
*/ |
|||
public void parse(Map<String, Object> task); |
|||
|
|||
} |
|||
@ -0,0 +1,190 @@ |
|||
package com.bw.funasr.service.Impl; |
|||
|
|||
import java.io.BufferedReader; |
|||
import java.io.InputStreamReader; |
|||
import java.net.HttpURLConnection; |
|||
import java.net.URL; |
|||
import java.net.URLEncoder; |
|||
import java.util.Arrays; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.cloud.context.config.annotation.RefreshScope; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import com.alibaba.dashscope.audio.asr.transcription.Transcription; |
|||
import com.alibaba.dashscope.audio.asr.transcription.TranscriptionParam; |
|||
import com.alibaba.dashscope.audio.asr.transcription.TranscriptionQueryParam; |
|||
import com.alibaba.dashscope.audio.asr.transcription.TranscriptionResult; |
|||
import com.alibaba.dashscope.audio.asr.transcription.TranscriptionTaskResult; |
|||
import com.alibaba.fastjson2.JSONObject; |
|||
import com.bw.funasr.service.FunasrTaskService; |
|||
import com.bw.funasr.entity.AppResultDoc; |
|||
import com.bw.funasr.utils.DownLoadUtil; |
|||
import com.bw.funasr.cache.ConfigCache; |
|||
import com.bw.funasr.entity.Constants; |
|||
import com.google.gson.*; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
/** |
|||
* 语音转文字服务实现类 |
|||
*/ |
|||
@Service |
|||
@Slf4j |
|||
@RefreshScope |
|||
public class FunasrTaskServiceImpl implements FunasrTaskService{ |
|||
|
|||
@Value("${aliyun.apiKey}") |
|||
private String apiKey; |
|||
|
|||
@Value("${aliyun.model}") |
|||
private String model; |
|||
|
|||
@Value("${aliyun.apiUrl}") |
|||
private String apiUrl; |
|||
|
|||
@Value("${api.save-url}") |
|||
private String saveUrl; |
|||
|
|||
@Override |
|||
public void create(Map<String, Object> task) { |
|||
// TODO Auto-generated method stub |
|||
String videoUrl = task.get(Constants.VIDEOURL).toString(); |
|||
|
|||
String url = videoUrl.replace("10.8.0.16", "182.92.120.176"); |
|||
com.alibaba.dashscope.utils.Constants.baseHttpApiUrl = apiUrl; |
|||
// 创建转写请求参数。 |
|||
TranscriptionParam param = |
|||
TranscriptionParam.builder() |
|||
.apiKey(apiKey) |
|||
.model(model) |
|||
// .parameter("language_hints", new String[]{"zh", "en"})//language_hints为可选参数,用于指定待识别音频的语言代码 |
|||
.fileUrls(Arrays.asList(url)) |
|||
.build(); |
|||
try { |
|||
Transcription transcription = new Transcription(); |
|||
// 提交转写请求 |
|||
TranscriptionResult result = transcription.asyncCall(param); |
|||
|
|||
System.out.println("RequestId: " + result.getRequestId()); |
|||
String jobId = result.getTaskId(); |
|||
log.info("语音解析任务提交成功,任务ID:{}", (String)task.get(Constants.TASKID)); |
|||
|
|||
task.put(Constants.JOBID, URLEncoder.encode(jobId.replace("\"", ""), "UTF-8")); |
|||
|
|||
//任务创建成功,放到监控结果队列中 |
|||
ConfigCache.resultQueue.put(task); |
|||
|
|||
} catch (Exception e) { |
|||
log.error("提交视频解析任务异常", e); |
|||
//失败直接发送结果 |
|||
AppResultDoc entity = new AppResultDoc(); |
|||
entity.setTaskId((String)task.get(Constants.TASKID)); |
|||
entity.setAppId((Integer)task.get(Constants.ID)); |
|||
long now = System.currentTimeMillis(); |
|||
entity.setCreateTime(now); |
|||
Map<String, Object> result = new HashMap<String, Object>(16); |
|||
result.put(Constants.ERROR, "识别任务创建异常"); |
|||
entity.setResult(result); |
|||
entity.setStatus(2); |
|||
entity.setDel(0); |
|||
entity.setInput(task); |
|||
//回传给api服务保存 |
|||
DownLoadUtil.doPost(saveUrl, JSONObject.toJSONString(entity)); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void parse(Map<String, Object> task) { |
|||
// TODO Auto-generated method stub |
|||
try { |
|||
String jobId = (String) task.get(Constants.JOBID); |
|||
TranscriptionQueryParam queryParam = TranscriptionQueryParam.builder() |
|||
.apiKey(apiKey) |
|||
.taskId(jobId) |
|||
.build(); |
|||
Transcription transcription = new Transcription(); |
|||
// 提交转写请求 |
|||
TranscriptionResult result = transcription.wait(queryParam); |
|||
String taskStatus = result.getTaskStatus().toString(); |
|||
log.info("获取解析结果-jobId:{},status:{}",jobId,taskStatus); |
|||
if ("SUCCEEDED".equals(taskStatus)) { |
|||
// 获取转写结果 |
|||
List<TranscriptionTaskResult> taskResultList = result.getResults(); |
|||
if (taskResultList != null && taskResultList.size() > 0) { |
|||
for (TranscriptionTaskResult taskResult : taskResultList) { |
|||
String transcriptionUrl = taskResult.getTranscriptionUrl(); |
|||
HttpURLConnection connection = (HttpURLConnection) new URL(transcriptionUrl).openConnection(); |
|||
connection.setRequestMethod("GET"); |
|||
connection.connect(); |
|||
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); |
|||
Gson gson = new GsonBuilder().setPrettyPrinting().create(); |
|||
JsonObject jsonResult = gson.fromJson(reader, JsonObject.class); |
|||
System.out.println(gson.toJson(jsonResult)); |
|||
JsonArray transcripts = jsonResult.getAsJsonArray("transcripts"); |
|||
if (transcripts != null && transcripts.size() > 0) { |
|||
JsonObject firstTranscript = transcripts.get(0).getAsJsonObject(); |
|||
String transcriptText = firstTranscript.get("text").getAsString(); |
|||
|
|||
//成功 发送结果 |
|||
log.info("发送解析结果-taskId{}",task.get(Constants.TASKID)); |
|||
AppResultDoc entity = new AppResultDoc(); |
|||
entity.setTaskId((String)task.get(Constants.TASKID)); |
|||
entity.setAppId((Integer)task.get(Constants.ID)); |
|||
long now = System.currentTimeMillis(); |
|||
entity.setCreateTime(now); |
|||
Map<String, Object> result1 = new HashMap<String, Object>(16); |
|||
result1.put(Constants.VOICECONTENT, transcriptText); |
|||
entity.setResult(result1); |
|||
entity.setStatus(1); |
|||
entity.setDel(0); |
|||
entity.setInput(task); |
|||
//回传给api服务保存 |
|||
DownLoadUtil.doPost(saveUrl, JSONObject.toJSONString(entity)); |
|||
} |
|||
} |
|||
} |
|||
}else if("PENDING".equals(taskStatus) || "RUNNING".equals(taskStatus)){ |
|||
//识别中 -- 放回队列 |
|||
ConfigCache.resultQueue.put(task); |
|||
}else { |
|||
log.error("语音转文字任务失败,jobId: {}, status: {}", jobId, taskStatus); |
|||
//获取错误信息 |
|||
JsonObject outputJson = result.getOutput(); |
|||
String message = outputJson.get("message").getAsString(); |
|||
//发送失败结果 |
|||
AppResultDoc entity = new AppResultDoc(); |
|||
entity.setTaskId((String)task.get(Constants.TASKID)); |
|||
entity.setAppId((Integer) task.get(Constants.ID)); |
|||
entity.setCreateTime(System.currentTimeMillis()); |
|||
|
|||
Map<String, Object> resultMap = new HashMap<>(16); |
|||
resultMap.put(Constants.ERROR, message); |
|||
entity.setResult(resultMap); |
|||
entity.setStatus(2); |
|||
entity.setDel(0); |
|||
entity.setInput(task); |
|||
DownLoadUtil.doPost(saveUrl, JSONObject.toJSONString(entity)); |
|||
} |
|||
} catch (Throwable e) { |
|||
log.error("创建文档解析任务异常。e:",e); |
|||
//发送失败结果 |
|||
AppResultDoc entity = new AppResultDoc(); |
|||
entity.setTaskId((String)task.get(Constants.TASKID)); |
|||
entity.setAppId((Integer)task.get(Constants.ID)); |
|||
long now = System.currentTimeMillis(); |
|||
entity.setCreateTime(now); |
|||
Map<String, Object> result = new HashMap<String, Object>(16); |
|||
result.put(Constants.ERROR, "源文件解析异常"); |
|||
entity.setResult(result); |
|||
entity.setStatus(2); |
|||
entity.setDel(0); |
|||
entity.setInput(task); |
|||
//回传给api服务保存 |
|||
DownLoadUtil.doPost(saveUrl, JSONObject.toJSONString(entity)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
package com.bw.funasr.service.Impl; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.bw.funasr.cache.ConfigCache; |
|||
import com.bw.funasr.entity.Constants; |
|||
import com.bw.funasr.service.TaskReceiveService; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
/** |
|||
* 任务接收服务层实现类 |
|||
* @author jian.mao |
|||
* @date 2025年1月14日 |
|||
* @description |
|||
*/ |
|||
@Service |
|||
@Slf4j |
|||
public class TaskReceiveServiceImpl implements TaskReceiveService { |
|||
|
|||
@Override |
|||
public String put(String dataJson) { |
|||
Map<String, Object> response = new HashMap<>(16); |
|||
int code = 200; |
|||
String message = "success"; |
|||
Map<String, Object> task = null; |
|||
try { |
|||
task = JSONObject.parseObject(dataJson); |
|||
} catch (Exception e) { |
|||
log.error("参数结构不合法,", e); |
|||
code = 100010; |
|||
message = "参数不合法"; |
|||
} |
|||
// 写入队列 |
|||
try { |
|||
if(task.containsKey(Constants.TRACE) && (boolean)task.get(Constants.TRACE)){ |
|||
ConfigCache.taskQueue.putFirst(task); |
|||
}else{ |
|||
ConfigCache.taskQueue.put(task); |
|||
} |
|||
} catch (InterruptedException e) { |
|||
log.error("任务写入队列异常,", e); |
|||
code = 100011; |
|||
message = "任务写入队列失败"; |
|||
} |
|||
response.put(Constants.CODE, code); |
|||
response.put(Constants.MESSAGE, message); |
|||
return JSONObject.toJSONString(response); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
package com.bw.funasr.service; |
|||
|
|||
/** |
|||
* 任务接收服务层 |
|||
* @author jian.mao |
|||
* @date 2025年1月14日 |
|||
* @description |
|||
*/ |
|||
public interface TaskReceiveService { |
|||
|
|||
/** |
|||
* 任务新增 |
|||
* @param dataJson |
|||
* @return |
|||
*/ |
|||
public String put(String dataJson); |
|||
} |
|||
@ -0,0 +1,177 @@ |
|||
package com.bw.funasr.utils; |
|||
|
|||
|
|||
import java.math.BigInteger; |
|||
import java.security.MessageDigest; |
|||
import java.security.NoSuchAlgorithmException; |
|||
import java.text.ParseException; |
|||
import java.text.SimpleDateFormat; |
|||
import java.time.LocalDateTime; |
|||
import java.time.format.DateTimeFormatter; |
|||
import java.util.Date; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import com.alibaba.fastjson.JSON; |
|||
import com.alibaba.fastjson.JSONObject; |
|||
|
|||
/** |
|||
* 日期工具类 |
|||
* |
|||
* @author jian.mao |
|||
* @date 2022年11月15日 |
|||
* @description |
|||
*/ |
|||
@Slf4j |
|||
public class DateUtil { |
|||
|
|||
/** |
|||
* @return |
|||
*/ |
|||
public static String getTimeStrForNow() { |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH"); |
|||
return sdf.format(new Date()); |
|||
} |
|||
|
|||
|
|||
public static String getTimeStrForDay(long time) { |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); |
|||
|
|||
return sdf.format(new Date(time * 1000)); |
|||
} |
|||
|
|||
public static String getTimeStrForDay() { |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); |
|||
|
|||
return sdf.format(new Date()); |
|||
} |
|||
|
|||
|
|||
public static String getDateTime() { |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
|||
String time = sdf.format(new Date()); |
|||
return time; |
|||
} |
|||
|
|||
public static String getDateTime(Long timestap) { |
|||
|
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
|||
String time = sdf.format(new Date(timestap)); |
|||
return time; |
|||
} |
|||
|
|||
public static String getDate(Long timestap) { |
|||
|
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
|||
String time = sdf.format(new Date(timestap)); |
|||
return time; |
|||
} |
|||
|
|||
public static String getDateTimeForMonth() { |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM"); |
|||
String time = sdf.format(new Date()); |
|||
return time; |
|||
} |
|||
|
|||
/** |
|||
* 休眠 |
|||
* |
|||
* @param millis 毫秒 |
|||
*/ |
|||
public static void sleep(long millis) { |
|||
try { |
|||
Thread.sleep(millis); |
|||
} catch (InterruptedException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 1. @Description:时间戳转时间 |
|||
* 2. @Author: ying.zhao |
|||
* 3. @Date: 2023/3/28 |
|||
*/ |
|||
|
|||
public static String timestampToDate(String time) { |
|||
int thirteen = 13; |
|||
int ten = 10; |
|||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
|||
// if (time.length() == thirteen) { |
|||
if (time.length() > ten) { |
|||
return sdf.format(new Date(Long.parseLong(time))); |
|||
} else { |
|||
return sdf.format(new Date(Integer.parseInt(time) * 1000L)); |
|||
} |
|||
} |
|||
|
|||
public static String parseCreated(String jsonTime){ |
|||
String formattedDateTime = getDateTime(); |
|||
try { |
|||
// 使用fastjson解析JSON数据 |
|||
JSONObject jsonObject = JSON.parseObject(jsonTime); |
|||
// 获取日期和时间的值 |
|||
JSONObject dateObject = jsonObject.getJSONObject("date"); |
|||
int day = dateObject.getIntValue("day"); |
|||
int month = dateObject.getIntValue("month"); |
|||
int year = dateObject.getIntValue("year"); |
|||
|
|||
JSONObject timeObject = jsonObject.getJSONObject("time"); |
|||
int hour = timeObject.getIntValue("hour"); |
|||
int minute = timeObject.getIntValue("minute"); |
|||
int second = timeObject.getIntValue("second"); |
|||
|
|||
// 创建LocalDateTime对象 |
|||
LocalDateTime dateTime = LocalDateTime.of(year, month, day, hour, minute, second); |
|||
|
|||
// 定义日期时间格式化器 |
|||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
|||
|
|||
// 格式化日期时间 |
|||
formattedDateTime = dateTime.format(formatter); |
|||
} catch (Exception e) { |
|||
log.info("日期转换失败:{}",e); |
|||
} |
|||
return formattedDateTime; |
|||
} |
|||
|
|||
/** |
|||
* 字符串转换日期 |
|||
* @param format |
|||
* @param date |
|||
* @return |
|||
*/ |
|||
public static Date strToDate(String format,String date){ |
|||
SimpleDateFormat sdf = new SimpleDateFormat(format); |
|||
if (date == null || date.equals("")){ |
|||
return new Date(); |
|||
}else{ |
|||
Date ru = null; |
|||
try { |
|||
ru = sdf.parse(date); |
|||
} catch (ParseException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
return ru; |
|||
} |
|||
} |
|||
/** |
|||
* 日期格式话 |
|||
* @param format 日期格式 |
|||
* @param dater 要转换的日期,默认当前时间 |
|||
* @return |
|||
*/ |
|||
public static String FormatDate(String format,Date date){ |
|||
String fromatDate = null; |
|||
SimpleDateFormat sdf = new SimpleDateFormat(format); |
|||
if (date == null){ |
|||
fromatDate = sdf.format(new Date()); |
|||
}else{ |
|||
fromatDate = sdf.format(date); |
|||
} |
|||
return fromatDate; |
|||
} |
|||
public static void main(String[] args) { |
|||
String time = timestampToDate("955814400000"); |
|||
System.out.println(time); |
|||
} |
|||
} |
|||
1045
funasr-service/src/main/java/com/bw/funasr/utils/DownLoadUtil.java
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,41 @@ |
|||
package com.bw.funasr.utils; |
|||
|
|||
import java.io.File; |
|||
import java.io.FileWriter; |
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* 文件工具类 |
|||
* @author jian.mao |
|||
* @date 2023年7月14日 |
|||
* @description |
|||
*/ |
|||
public class FileUtil { |
|||
|
|||
/** |
|||
* 数据写入文件 |
|||
* @param Path 文件路径 |
|||
* @param result 数据 |
|||
* @throws IOException |
|||
*/ |
|||
public static void writeFile(String path,String result){ |
|||
try { |
|||
FileWriter fw = new FileWriter(path,true); |
|||
fw.write(result+"\n"); |
|||
fw.flush(); |
|||
fw.close(); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
public static void delFile(String path) { |
|||
try { |
|||
File file = new File(path); |
|||
file.delete(); |
|||
} catch (Exception e) { |
|||
// TODO: handle exception |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
package com.bw.funasr.utils; |
|||
|
|||
import java.io.PrintWriter; |
|||
import java.io.StringWriter; |
|||
|
|||
/** |
|||
* @author jian.mao |
|||
* @date 2023年3月22日 |
|||
* @description |
|||
*/ |
|||
public class ThrowMessageUtil { |
|||
|
|||
/** |
|||
* 获取异常信息 |
|||
* @param t |
|||
* @return |
|||
*/ |
|||
public static String getErrmessage(Throwable t){ |
|||
StringWriter stringWriter=new StringWriter(); |
|||
t.printStackTrace(new PrintWriter(stringWriter,true)); |
|||
return stringWriter.getBuffer().toString(); |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
# ==================== 必须文件:bootstrap.yml ==================== |
|||
# 这个文件用于配置Nacos客户端,优先级最高 |
|||
spring: |
|||
application: |
|||
name: funasr-service # 服务名,对应Nacos中的Data ID |
|||
|
|||
cloud: |
|||
nacos: |
|||
# ======== 配置中心 ======== |
|||
config: |
|||
server-addr: 127.0.0.1:8848 # Nacos地址 |
|||
username: nacos # 用户名 |
|||
password: nacos # 密码 |
|||
group: public_dev # 分组 |
|||
namespace: opai # 命名空间(默认public) |
|||
file-extension: yaml # 配置文件格式 |
|||
timeout: 5000 # 超时时间(ms) |
|||
|
|||
# 核心配置:开启动态刷新 |
|||
refresh-enabled: true # 必须为true! |
|||
|
|||
# 主配置文件(从Nacos加载) |
|||
data-id: ${spring.application.name}.${spring.cloud.nacos.config.file-extension} |
|||
|
|||
# 共享配置文件(可选) |
|||
shared-configs[0]: |
|||
data-id: application.yaml # 公共配置 |
|||
group: public_dev # 公共分组 |
|||
namespace: opai |
|||
refresh: true # 公共配置也要刷新 |
|||
|
|||
# 扩展配置(可选) |
|||
# extension-configs[0]: |
|||
# data-id: datasource.yaml |
|||
# group: dev |
|||
# refresh: true |
|||
|
|||
# ======== 服务发现 ======== |
|||
discovery: |
|||
server-addr: ${spring.cloud.nacos.config.server-addr} |
|||
username: ${spring.cloud.nacos.config.username} |
|||
password: ${spring.cloud.nacos.config.password} |
|||
group: ${spring.cloud.nacos.config.group} |
|||
namespace: ${spring.cloud.nacos.config.namespace} |
|||
|
|||
logging: |
|||
level: |
|||
root: info |
|||
com.alibaba.nacos.client.config.impl: WARN |
|||
file: |
|||
path: ../logs |
|||
|
|||
@ -0,0 +1,36 @@ |
|||
<configuration> |
|||
<!-- 属性文件:在properties文件中找到对应的配置项 --> |
|||
<springProperty scope="context" name="log-path" source="logging.file.path"/> |
|||
<!--<springProperty scope="context" name="logging.level" source="logging.level.com.bfd"/>--> |
|||
<!-- 默认的控制台日志输出,一般生产环境都是后台启动,这个没太大作用 --> |
|||
<!-- <appender name="STDOUT" |
|||
class="ch.qos.logback.core.ConsoleAppender"> |
|||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
|||
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %line %-5level %logger{50} - %msg%n</Pattern> |
|||
</encoder> |
|||
</appender> --> |
|||
|
|||
<appender name="GLMAPPER-LOGGERONE" |
|||
class="ch.qos.logback.core.rolling.RollingFileAppender"> |
|||
<append>true</append> |
|||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> |
|||
<level>${logging.level}</level> |
|||
</filter> |
|||
<file> |
|||
${log-path}/funasr-service.log |
|||
</file> |
|||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
|||
<FileNamePattern>${log-path}/funasr-service.log.%d{yyyy-MM-dd}</FileNamePattern> |
|||
<MaxHistory>7</MaxHistory> |
|||
</rollingPolicy> |
|||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
|||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %line %-5level %logger{50} - %msg%n</pattern> |
|||
<charset>UTF-8</charset> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<root level="info"> |
|||
<appender-ref ref="GLMAPPER-LOGGERONE"/> |
|||
<!-- <appender-ref ref="STDOUT"/> --> |
|||
</root> |
|||
</configuration> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue