lmx 2 日 前
コミット
6033705239

+ 27 - 5
fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticCallLogCallphoneServiceImpl.java

@@ -5,6 +5,7 @@ import java.math.RoundingMode;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
 
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
@@ -16,30 +17,30 @@ import com.fs.aicall.domain.apiresult.PushIIntentionResult;
 import com.fs.aicall.domain.param.getDialogMapDomain;
 import com.fs.aicall.service.AiCallService;
 import com.fs.common.constant.Constants;
+import com.fs.common.core.domain.entity.SysDictData;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.DateUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.*;
-import com.fs.company.mapper.CompanyVoiceRoboticBusinessMapper;
-import com.fs.company.mapper.CompanyVoiceRoboticCalleesMapper;
-import com.fs.company.mapper.CompanyWxAccountMapper;
+import com.fs.company.mapper.*;
 import com.fs.company.service.CompanyWorkflowEngine;
 import com.fs.company.vo.CidConfigVO;
 import com.fs.company.vo.CompanyVoiceRoboticCallLogCallPhoneVO;
 import com.fs.company.vo.CompanyVoiceRoboticCallLogCount;
+import com.fs.company.vo.DictVO;
 import com.fs.company.vo.easycall.EasyCallCallPhoneVO;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.store.config.StoreConfig;
 import com.fs.system.service.ISysConfigService;
+import com.fs.system.service.impl.SysDictTypeServiceImpl;
 import com.fs.voice.constant.Constant;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
-import com.fs.company.mapper.CompanyVoiceRoboticCallLogCallphoneMapper;
 import com.fs.company.service.ICompanyVoiceRoboticCallLogCallphoneService;
 
 import static com.fs.company.service.impl.call.node.AiCallTaskNode.EASYCALL_WORKFLOW_REDIS_KEY;
@@ -76,6 +77,8 @@ public class CompanyVoiceRoboticCallLogCallphoneServiceImpl extends ServiceImpl<
     @Qualifier("cidWorkFlowExecutor")
     private Executor cidWorkFlowExecutor;
 
+    @Autowired
+    SysDictTypeServiceImpl sysDictTypeService;
     /**
      * 查询调用日志_ai打电话
      *
@@ -307,7 +310,17 @@ public class CompanyVoiceRoboticCallLogCallphoneServiceImpl extends ServiceImpl<
                 companyVoiceRoboticCallLog.setCallCreateTime(createTime);
                 Long answerTime = result.getCallEndTime();
                 companyVoiceRoboticCallLog.setCallAnswerTime(answerTime);
-                companyVoiceRoboticCallLog.setIntention(result.getIntent());
+                String intention = result.getIntent();
+                String intentf = null;
+                List<SysDictData> customerIntentionLevel = sysDictTypeService.selectDictDataByType("customer_intention_level");
+                if (!isPositiveInteger(intention)) {
+                    Optional<SysDictData> firstDict = customerIntentionLevel.stream().filter(e -> e.getDictLabel().equals(intention)).findFirst();
+                    if (firstDict.isPresent()) {
+                        SysDictData sysDictData = firstDict.get();
+                        intentf = sysDictData.getDictValue();
+                    }
+                }
+                companyVoiceRoboticCallLog.setIntention(intentf);
                 companyVoiceRoboticCallLog.setCallTime(Long.valueOf(result.getTimeLen()/1000));
                 BigDecimal callCharge = cidConfigVO.getCallCharge();
                 //
@@ -381,4 +394,13 @@ public class CompanyVoiceRoboticCallLogCallphoneServiceImpl extends ServiceImpl<
     public List<CompanyVoiceRoboticCallLogCallPhoneVO> listByRoboticId(CompanyVoiceRoboticCallLogCallphone companyVoiceRoboticCallLogCallphone) {
         return baseMapper.listByRoboticId(companyVoiceRoboticCallLogCallphone);
     }
+    /**
+     * 判断整数
+     *
+     * @param str
+     * @return
+     */
+    public boolean isPositiveInteger(String str) {
+        return str != null && str.matches("[1-9]\\d*");
+    }
 }

+ 83 - 3
fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticServiceImpl.java

@@ -129,6 +129,13 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
 
     final int BATCH_SIZE = 1500;
 
+    /** EasyCall intent 意向度重试队列 Redis key 前缀,value 为已重试次数 */
+    private static final String EASYCALL_INTENT_RETRY_KEY = "easycall:intent:retry:";
+    /** intent 意向度等待重试最大次数(每次间隔约30秒,最多等待 5*30=150秒) */
+    private static final int EASYCALL_INTENT_MAX_RETRY = 5;
+    /** 每次重试等待时长(毫秒) */
+    private static final long EASYCALL_INTENT_RETRY_INTERVAL_MS = 30000L;
+
     /**
      * 查询机器人外呼任务
      *
@@ -819,18 +826,90 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
             return;
         }
         log.info("进入easyCall外呼结果查询结果callPhoneRes:{}", JSON.toJSONString(callPhoneRes));
+        // intent(意向度)由对方异步评估写入,回调时可能尚未赋值,进入延迟重试队列等待
+        if (StringUtils.isBlank(callPhoneRes.getIntent())) {
+            String retryKey = EASYCALL_INTENT_RETRY_KEY + result.getUuid();
+            Integer retryCount = redisCache2.getCacheObject(retryKey);
+            if (retryCount == null) {
+                retryCount = 0;
+            }
+            if (retryCount < EASYCALL_INTENT_MAX_RETRY) {
+                redisCache2.setCacheObject(retryKey, retryCount + 1, 10, java.util.concurrent.TimeUnit.MINUTES);
+                log.info("easyCall外呼回调intent意向度暂未评估完成,uuid={},第{}次放入延迟重试队列", result.getUuid(), retryCount + 1);
+                doRetryCallerResult4EasyCall(result, retryCount + 1);
+            } else {
+                // 超过最大重试次数,以 intent 为空(意向未知)兜底继续处理
+                log.warn("easyCall外呼回调intent意向度在{}次重试后仍为空,uuid={},以意向未知兜底处理", EASYCALL_INTENT_MAX_RETRY, result.getUuid());
+                redisCache2.deleteObject(retryKey);
+                doHandleEasyCallResult(callPhoneRes);
+            }
+            return;
+        }
+        // intent 已有值,直接正常处理
+        redisCache2.deleteObject(EASYCALL_INTENT_RETRY_KEY + result.getUuid());
+        doHandleEasyCallResult(callPhoneRes);
+    }
+
+    /**
+     * 延迟重试处理 EasyCall 外呼回调(等待 intent 意向度异步评估完成)
+     * 每次重试前等待 {@link #EASYCALL_INTENT_RETRY_INTERVAL_MS} 毫秒后重新拉取数据
+     */
+    @Async("cidWorkFlowExecutor")
+    public void doRetryCallerResult4EasyCall(CdrDetailVo result, int currentRetry) {
+        try {
+            Thread.sleep(EASYCALL_INTENT_RETRY_INTERVAL_MS);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            log.warn("easyCall intent重试等待被中断, uuid={}", result.getUuid());
+            return;
+        }
+        log.info("easyCall intent重试第{}次开始, uuid={}", currentRetry, result.getUuid());
+        EasyCallCallPhoneVO callPhoneRes = easyCallMapper.getCallPhoneInfoByUuid(result.getUuid());
+        if (null == callPhoneRes) {
+            log.error("easyCall intent重试时仍未查询到外呼结果, uuid={}", result.getUuid());
+            return;
+        }
+        if (StringUtils.isBlank(callPhoneRes.getIntent())) {
+            // intent 仍为空,继续判断是否还有剩余重试次数
+            String retryKey = EASYCALL_INTENT_RETRY_KEY + result.getUuid();
+            Integer retryCount = redisCache2.getCacheObject(retryKey);
+            if (retryCount == null) {
+                retryCount = currentRetry;
+            }
+            if (retryCount < EASYCALL_INTENT_MAX_RETRY) {
+                redisCache2.setCacheObject(retryKey, retryCount + 1, 10, java.util.concurrent.TimeUnit.MINUTES);
+                log.info("easyCall intent仍未评估完成,uuid={},第{}次继续延迟重试", result.getUuid(), retryCount + 1);
+                doRetryCallerResult4EasyCall(result, retryCount + 1);
+            } else {
+                log.warn("easyCall intent在{}次重试后仍为空,uuid={},以意向未知兜底处理", EASYCALL_INTENT_MAX_RETRY, result.getUuid());
+                redisCache2.deleteObject(retryKey);
+                doHandleEasyCallResult(callPhoneRes);
+            }
+            return;
+        }
+        // intent 已评估完成,正常处理
+        log.info("easyCall intent重试第{}次成功获取到意向度={},uuid={}", currentRetry, callPhoneRes.getIntent(), result.getUuid());
+        redisCache2.deleteObject(EASYCALL_INTENT_RETRY_KEY + result.getUuid());
+        doHandleEasyCallResult(callPhoneRes);
+    }
+
+    /**
+     * 执行 EasyCall 外呼回调核心业务处理(推送对话内容、更新通话日志)
+     * 供 {@link #callerResult4EasyCall} 和重试逻辑统一调用
+     */
+    private void doHandleEasyCallResult(EasyCallCallPhoneVO callPhoneRes) {
         //等待数据信息
         JSONObject bizJson = JSONObject.parseObject(callPhoneRes.getBizJson());
         String cacheString = (String) redisCache2.getCacheObject(EASYCALL_WORKFLOW_REDIS_KEY + bizJson.getString("callBackUuid"));
         if (StringUtils.isBlank(cacheString)) {
-            log.error("easyCall外呼回调缓存信息缺失:{}", JSON.toJSONString(result));
+            log.error("easyCall外呼回调缓存信息缺失, uuid={}", callPhoneRes.getUuid());
             return;
         }
         JSONObject cacheInfo = JSONObject.parseObject(cacheString);
         pushDialogContent4EasyCall(cacheInfo, callPhoneRes);
         CompanyVoiceRoboticCallees callee = companyVoiceRoboticCalleesMapper.selectCompanyVoiceRoboticCalleesById(cacheInfo.getLong("calleeId"));
         companyVoiceRoboticCallLogCallphoneService.asyncHandleCalleeCallBackResult4EasyCall(callPhoneRes, callee);
-        System.out.println(callPhoneRes);
+        log.info("easyCall外呼回调业务处理完成, uuid={}, intent={}", callPhoneRes.getUuid(), callPhoneRes.getIntent());
     }
 
     public void pushDialogContent(PushIIntentionResult result) {
@@ -1751,7 +1830,7 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
                 targetExec.setCurrentNodeKey(nodeInfoVo.getTargetNodeKey());
                 targetExec.setCurrentNodeName(nodeInfoVo.getNodeName());
                 targetExec.setCurrentNodeType(NodeTypeEnum.fromCode(nodeInfoVo.getNodeType()).getValue());
-                targetExec.setStatus(ExecutionStatusEnum.FAILURE.getValue());
+                targetExec.setStatus(ExecutionStatusEnum.INTERRUPT.getValue());
                 targetExec.setStartTime(now);
                 targetExec.setVariables(variables.toJSONString());
                 targetExec.setBusinessKey(startExec.getBusinessKey());
@@ -1783,6 +1862,7 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
         int rows = companyAiWorkflowExecMapper.insertBatchInfo(workflowExecs);
         if(rows > 0){
             workflowExecLogBatchInsert(startExecList);//第一节点
+            workflowExecs.stream().forEach(a->a.setStatus(ExecutionStatusEnum.FAILURE.getValue()));
             workflowExecLogBatchInsert(workflowExecs);//第二节点
         }
         workflowExecs.clear();