/**
* 指定录音文件转文字(异步)
* @param bo
* @return
*/
@Override
public JSONObject recognizeAudio(QueryRecognizeBo bo){
Map<String,Object> recordMap = extLxccCdrMapper.queryRelativePath(bo.getCallId());
String filePath = (String) recordMap.get(relativePathKey);
if (CollectionUtils.isEmpty(recordMap) || StringUtils.isBlank(filePath)
|| recordMap.get(fileSizeKey) == null || (Integer) recordMap.get("fileSize") == 0){
return ResponseUtil.setResponseMsg("000005","录音不存在");
}
List<RecognizeText> list = recognizeMapper.selectRecognizeTxt(bo.getCallId());
log.info("recognizeAudio list :{}",list);
if (CollectionUtils.isEmpty(list)){
recognizeDelayQueue.doProcess(filePath, new RecognizeDelayQueue.ItemQueueTask() {
@Override
public ItemDelayed setItemQueue(String taskId, LfasrClient lfasrClient) {
return setItemDelayed(taskId,bo.getCallId(),bo.getCallBackUrl(),lfasrClient);
}
});
return ResponseUtil.setResponseMsg(SUCCESS_CODE,SUCCESS_WAIT);
} else {
return setResponse(SUCCESS_CODE,SUCCESS_MSG,bo.getCallId(),list);
}
}
public ItemDelayed setItemDelayed(String taskId,String callbackUrl,String callId,LfasrClient lfasrClient){
return new ItemDelayed(taskId,lfasrClient,callId,callbackUrl,(int) LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")),
(int) LocalDateTime.now().plusMinutes(10).toEpochSecond(ZoneOffset.of("+8")));
}
public JSONObject setResponse(String code, String msg, String callId, List<RecognizeText> list){
JSONArray array = JSONArray.parseArray(list.toString());
JSONObject data = new JSONObject();
data.put("callId",callId);
data.put("recognizeData",array);
JSONObject jsonObject = new JSONObject();
jsonObject.put("code",code);
jsonObject.put("message",msg);
jsonObject.put("data",data);
return jsonObject;
}
队列处理
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.iflytek.msp.lfasr.LfasrClient;
import com.iflytek.msp.lfasr.model.Message;
import com.lxccb.common.util.http.HttpDeal;
import com.lxccb.mybatis.bean.auto.LxccRecognizeRequest;
import com.lxccb.mybatis.bean.auto.LxccRecognizeTxt;
import com.lxccb.mybatis.mapper.auto.LxccRecognizeRequestMapper;
import com.lxccb.mybatis.mapper.auto.LxccRecognizeTxtMapper;
import com.lxccb.mybatis.mapper.ext.ExtLxccRecognizeMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.ref.SoftReference;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.DelayQueue;
/**
* @author: datszhang
* @Date: 2021/5/29 15:20
* @Description: redis hash 延时队列
*/
@Slf4j
@Component
public class RecognizeDelayQueue {
/**
* 识别状态
*/
private final Integer NINE = 9;
/**
* 间隔10秒
*/
private final Integer interval = 10;
private static final String APP_ID = "2aaf4d90";
private static final String SECRET_KEY = "cdec42ef6bb2018d755a33a211fe30a4";
@Autowired
private LxccRecognizeRequestMapper lxccRecognizeRequestMapper;
@Autowired
private LxccRecognizeTxtMapper lxccRecognizeTxtMapper;
@Autowired
private ExtLxccRecognizeMapper lxccRecognizeMapper;
private final String SUCCESS_CODE = "000000";
private final String SUCCESS_MSG = "成功";
private final String SUCCESS_WAIT = "识别中";
@Autowired
private ExtLxccRecognizeMapper recognizeMapper;
public DelayQueue<ItemDelayed> delayQueue = new DelayQueue<>();
public DelayQueue<ItemDelayed> putDelayQueue(ItemDelayed item){
this.delayQueue.offer(item);
return this.delayQueue;
}
/**
* 识别处理
* @param filePath 存储路径
* @param itemQueueTask
*/
public void doProcess(String filePath,RecognizeDelayQueue.ItemQueueTask itemQueueTask) {
ItemDelayed item = addItemToQueue(filePath,itemQueueTask);
Integer count = recognizeMapper.selectCallIdCount(item.getCallId());
Long recognizedId = null;
if (count == null || count <= 0 ){
recognizedId = insertDb(item.getCallId(),item.getCallbackUrl());
newThreadRun(recognizedId);
}
log.info("doProcess -> count = {} ,recognizedId :{} end.",count,recognizedId);
}
public void newThreadRun(Long recognizedId){
log.info("newThreadRun -> start. delayQueue.size = {}",delayQueue.size());
new Thread(new Runnable(){
@Override
public void run() {
while (true){
try {
ItemDelayed itemDelayed = delayQueue.take();
log.info("newThreadRun -> itemDelayed:{}",JSONObject.toJSONString(itemDelayed));
Message message = itemDelayed.getLfasrClient().getProgress(itemDelayed.getTaskId());
// {"data":"{\"status\":2,\"desc\":\"音频合并完成\"}","errNo":0,"ok":0}
log.info("newThreadRun -> message:{}",JSONObject.toJSONString(message));
JSONObject object = JSON.parseObject(message.getData());
Integer status = object.getInteger("status");
if (status.equals(NINE)){
Message result = itemDelayed.getLfasrClient().getResult(itemDelayed.getTaskId());
log.info("newThreadRun -> callId:{},result:{}",itemDelayed.getCallId(),JSONObject.toJSONString(result));
if (result == null || result.getOk() == -1){
log.error("newThreadRun failed reason:{}",result.getFailed());
} else {
parseMessage(itemDelayed.getCallId(),itemDelayed.getCallbackUrl(),result,recognizedId);
}
break;
} else {
//没有结果,且还需要查询
log.info("newThreadRun -> callId:{} ,status :{} is not 9.",status,itemDelayed.getCallId());
itemDelayed.setTime(nextDelay(interval));
putDelayQueue(itemDelayed);
}
} catch (InterruptedException e) {
log.error("RedisHashDelayQueue.newThreadRun error :",e);
}
}
}
}).start();
}
/**
* 下一次触发时间
* @param plusTime
* @return
*/
public int nextDelay(Integer plusTime){
return (int) LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) + plusTime;
}
public ItemDelayed addItemToQueue(String filePath,RecognizeDelayQueue.ItemQueueTask itemQueueTask){
LfasrClient lfasrClient = LfasrClient.getInstance(APP_ID, SECRET_KEY);
SoftReference<LfasrClient> sflc = new SoftReference<>(lfasrClient);
Message message = lfasrClientUpload(filePath,sflc.get());
log.info("addItemToQueue -> message:{}",JSONObject.toJSONString(message));
SoftReference<Message> sfm = new SoftReference<>(message);
ItemDelayed item = itemQueueTask.setItemQueue(sfm.get().getData(),lfasrClient);
this.putDelayQueue(item);
return item;
}
public Message lfasrClientUpload(String filePath,LfasrClient lfasrClient){
//2、上传
//2.1、设置业务参数
Map<String, String> param = new HashMap<>(16);
//是否开启分词:默认 false
//param.put("has_participle","true");
//转写结果中最大的候选词个数:默认:0,最大不超过5
//param.put("max_alternatives","2");
//是否开启角色分离:默认为false
param.put("has_seperate","true");
//发音人个数,可选值:0-10,0表示盲分:默认 2
param.put("speaker_number","2");
//角色分离类型 1-通用角色分离;2-电话信道角色分离:默认 1
//param.put("role_type","1");
//语种: cn-中文(默认);en-英文(英文不支持热词)
param.put("language", "cn");
//垂直领域个性化:法院-court;教育-edu;金融-finance;医疗-medical;科技-tech
//param.put("pd","finance");
Message task = lfasrClient.upload(filePath, param);
log.info("lfasrClientUpload -> 转写任务 task:{}", JSONObject.toJSONString(task));
return task;
}
public boolean removeItem(ItemDelayed item){
return delayQueue.remove(item);
}
private void parseMessage(String callId,String callbackUrl,Message result,Long recognizedId){
JSONArray data = JSONObject.parseArray(result.getData());
List<LxccRecognizeTxt> list = new ArrayList<>(data.size());
JSONArray ja = new JSONArray(data.size());
for (int i = 0; i < data.size(); i++){
JSONObject jj = data.getJSONObject(i);
list.add(setText(jj,recognizedId));
ja.add(setCallback(jj));
}
lxccRecognizeMapper.batchInsertText(list);
JSONObject callbackData = new JSONObject();
callbackData.put("callId",callId);
callbackData.put("recognizeData",ja);
JSONObject callback = new JSONObject();
callback.put("data",callbackData);
callback.put("message",SUCCESS_MSG);
callback.put("code",SUCCESS_CODE);
sendCallback(callbackUrl,callbackData);
}
private JSONObject setCallback(JSONObject jd){
JSONObject jj = new JSONObject();
jj.put("bg",jd.getInteger("bg"));
jj.put("ed",jd.getInteger("ed"));
jj.put("onebest",jd.getString("onebest"));
jj.put("speaker",jd.getInteger("speaker"));
return jj;
}
private LxccRecognizeTxt setText(JSONObject jd,Long recognized){
LxccRecognizeTxt entity = new LxccRecognizeTxt();
entity.setBeginTime(jd.getInteger("bg"));
entity.setEndTime(jd.getInteger("ed"));
entity.setOnebest(jd.getString("onebest"));
entity.setRecognizeId(recognized);
entity.setSpeaker(jd.getInteger("speaker"));
return entity;
}
private Long insertDb(String callId,String callbackUrl){
LxccRecognizeRequest entity = new LxccRecognizeRequest();
entity.setCallBackUrl(callbackUrl);
entity.setCallId(callId);
entity.setCreateTime(new Date());
lxccRecognizeRequestMapper.insertSelective(entity);
return entity.getId();
}
private void sendCallback(String callbackUrl,JSONObject callbackData){
log.info("sendCallback -> callbackUrl:{},callbackData:{}",callbackUrl,callbackData);
HttpDeal.post(callbackUrl,callbackData.toJSONString());
}
public interface ItemQueueTask{
/**
* 添加任务ID到延时队列数据
* @param taskId
*/
ItemDelayed setItemQueue(String taskId,LfasrClient lfasrClient);
}
}
延时对象
import com.iflytek.msp.lfasr.LfasrClient;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
* @Auther: datszhang
* @Date: 2019/11/9 14:44
* @Description: 只对redis的hash有用
*/
@Slf4j
@Data
public class ItemDelayed implements Delayed {
/**
* 任务ID
*/
private String taskId;
/**
* 客户端实例
*/
private LfasrClient lfasrClient;
private String callId;
/**
* 用户的回调地址
*/
private String callbackUrl;
/**
* 延时时间
*/
private Integer time;
/**
* 截止时间
*/
private Integer deadline;
public ItemDelayed(){
}
public ItemDelayed(String taskId,LfasrClient lfasrClient,String callId,String callbackUrl,Integer time,Integer deadline) {
this.taskId = taskId;
this.lfasrClient = lfasrClient;
this.callId = callId;
this.callbackUrl = callbackUrl;
this.time = time;
this.deadline = deadline;
}
/**
* delayQueue.take()中的getDelay 获取剩余激活时间
* @param unit
* @return
*/
@Override
public long getDelay(TimeUnit unit) {
if (this.time >= this.deadline){
return -1L;
}
long delayTime = this.time - LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
return delayTime;
}
@Override
public int compareTo(Delayed o) {
ItemDelayed item = (ItemDelayed) o;
long diff = this.time - item.time;
if (diff <= 0) {
return -1;
}else {
return 1;
}
}
}