Procházet zdrojové kódy

1.提交ai客服夜间不回复设置

jzp před 1 dnem
rodič
revize
d34d4bbd75

+ 45 - 4
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -3,6 +3,7 @@ package com.fs.his.task;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -33,12 +34,10 @@ import com.fs.erp.dto.ErpOrderQueryResponse;
 import com.fs.erp.dto.ErpOrderResponse;
 import com.fs.erp.mapper.FsErpFinishPushMapper;
 import com.fs.erp.service.IErpOrderService;
-import com.fs.fastGpt.domain.FastGptEventTokenLog;
-import com.fs.fastGpt.domain.FastGptPushTokenTotal;
-import com.fs.fastGpt.domain.FastgptChatVoiceHomo;
-import com.fs.fastGpt.domain.FastgptEventLogTotal;
+import com.fs.fastGpt.domain.*;
 import com.fs.fastGpt.mapper.FastGptChatSessionMapper;
 import com.fs.fastGpt.mapper.FastgptChatVoiceHomoMapper;
+import com.fs.fastGpt.service.AiHookService;
 import com.fs.fastGpt.service.IFastgptEventLogTotalService;
 import com.fs.fastgptApi.util.AudioUtils;
 import com.fs.fastgptApi.vo.AudioVO;
@@ -67,7 +66,9 @@ import com.fs.im.dto.*;
 import com.fs.im.service.IImService;
 import com.fs.im.service.OpenIMService;
 import com.fs.qw.domain.QwCompany;
+import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwRestrictionPushRecordMapper;
+import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.*;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.sop.domain.QwSopTempVoice;
@@ -225,6 +226,46 @@ public class Task {
     @Autowired
     private FsIntegralOrderMapper fsIntegralOrderMapper;
 
+    private final String DELAY_MSG = "delayMsg";
+
+    @Autowired
+    private QwUserMapper qwUserMapper;
+
+    @Autowired
+    private AiHookService aiHookService;
+
+
+    /**
+     * 定时任务,处理ai禁止回复之后的消息
+     */
+    public void forbidTimeMsgTask() {
+        Map<String, Object> cacheMap = redisCache.hGetAll(DELAY_MSG);
+        for (String key : cacheMap.keySet()) {
+            String value = (String) cacheMap.get(key);
+            //获取sessionId
+            Long sessionId = Long.parseLong(key);
+            try {
+                if (value != null && !value.isEmpty()) {
+                    FastGptChatSession chatSession = fastGptChatSessionMapper.selectFastGptChatSessionBySessionId(sessionId);
+                    Long qwUserId = chatSession.getQwUserId();
+                    QwUser qwUser = qwUserMapper.selectQwUserById(qwUserId);
+                    String uid = qwUser.getUid();
+
+                    JSONObject jsonObject = JSONObject.parseObject(value);
+                    String content = jsonObject.getString("content");
+                    Long sender = jsonObject.getLong("sender");
+                    Integer type = jsonObject.getInteger("type");
+
+                    aiHookService.qwHookNotifyAiReply(qwUserId,sender,content,uid,type);
+                    //删除已经处理的缓存
+                    redisCache.hDel(DELAY_MSG,key);
+                }
+            } catch (Exception e) {
+                log.error("个人定时消息处理异常,会话id:{},文本:{}",sessionId,value,e);
+            }
+        }
+    }
+
     /**
      * sop任务token消耗统计
      */

+ 33 - 0
fs-common/src/main/java/com/fs/common/core/redis/RedisCache.java

@@ -451,4 +451,37 @@ public class RedisCache
     public Long size(String key) {
         return redisTemplate.opsForHash().size(key);
     }
+
+    // ========== 新增Hash操作方法 ==========
+    /**
+     * 存储Hash结构:field-value
+     */
+    public <T> void hPut(String mainKey, String field, T value) {
+        redisTemplate.opsForHash().put(mainKey, field, value);
+    }
+
+    /**
+     * 获取Hash中指定field的值
+     */
+    public <T> T hGet(String mainKey, String field) {
+        return (T) redisTemplate.opsForHash().get(mainKey, field);
+    }
+
+    /**
+     * 获取Hash中所有field-value(方便批量读取)
+     */
+    public Map<String, Object> hGetAll(String mainKey) {
+        return (Map<String, Object>) redisTemplate.opsForHash().entries(mainKey);
+    }
+
+    /**
+     * 删除Hash中指定field
+     */
+    public void hDel(String mainKey, Object... fields) {
+        redisTemplate.opsForHash().delete(mainKey, (Object[]) fields);
+    }
+
+    public boolean hasKey(String key) {
+        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
+    }
 }

+ 13 - 0
fs-service/src/main/java/com/fs/fastGpt/domain/FastGptRole.java

@@ -4,6 +4,8 @@ import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
 import lombok.Data;
 
+import java.sql.Time;
+
 /**
  * 应用对象 fastgpt_role
  *
@@ -65,4 +67,15 @@ public class FastGptRole extends BaseEntity
     private String channelType;
 
     private Integer logistics;
+
+    //回复禁止起始时间
+    private Time forbidSendStart;
+
+    //回复禁止结束时间
+    private Time forbidSendEnd;
+
+    /**
+     * 是否禁止时段回复 0是不开启禁止  1是开启禁止 默认为1
+     */
+    private Integer forbidStatus;
 }

+ 39 - 1
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java

@@ -66,14 +66,17 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.jetbrains.annotations.Nullable;
+import org.json.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import java.lang.reflect.Field;
+import java.sql.Time;
 import java.time.DayOfWeek;
 import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
@@ -169,6 +172,8 @@ public class AiHookServiceImpl implements AiHookService {
     private static final String AI_REPLY = "AI_REPLY:";
     private static final String AI_REPLY_TAG = "AI_REPLY_TAG:";
 
+    private final String DELAY_MSG = "delayMsg";
+
 
     /** Ai半小时未回复提醒 **/
     /**
@@ -479,6 +484,39 @@ public class AiHookServiceImpl implements AiHookService {
                 }
             }
 
+            //规定时间不发送内容
+            if(role.getForbidStatus() == null){
+                role.setForbidStatus(1);
+            }
+
+            if(role.getForbidStatus() == 1){
+                Time forbidSendStart = role.getForbidSendStart()==null? Time.valueOf("00:00:00") :role.getForbidSendStart();
+                Time forbidSendEnd = role.getForbidSendEnd()==null? Time.valueOf("04:59:59") :role.getForbidSendEnd();
+                //设置规定时间不发送消息
+                Time now = Time.valueOf(LocalDateTime.now().toLocalTime());
+                // 判断当前时间是否在禁止发送时间段内
+                if (now.after(forbidSendStart) && now.before(forbidSendEnd)) {
+                    String sessionId = String.valueOf(fastGptChatSession.getSessionId());
+                    log.info("当前时间 {} 在禁止发送时间段内 ({} - {}),会话id:{},跳过回复", now, forbidSendStart, forbidSendEnd,fastGptChatSession.getSessionId());
+
+                    // HSET命令是原子的,多个线程同时写不同field不会互相覆盖;同field会覆盖(符合需求)
+                    JSONObject jsonObject = new JSONObject();
+                    jsonObject.put("content",contentEmj);
+                    jsonObject.put("sender",sender);
+                    jsonObject.put("type",type);
+                    String objectString = jsonObject.toString();
+
+                    redisCache.hPut(DELAY_MSG, sessionId, objectString);
+
+                    // 4. 确保主Key有8小时过期时间(只在首次设置时生效,避免重复刷新)
+                    if (!redisCache.hasKey(DELAY_MSG)) {
+                        redisCache.expire(DELAY_MSG, 8, TimeUnit.HOURS);
+                    }
+
+                    return R.ok();
+                }
+            }
+
 
             //判断是否转人工
             if (fastGptChatSession.getIsArtificial()==1){
@@ -549,7 +587,7 @@ public class AiHookServiceImpl implements AiHookService {
                 //从fastgpt_chat_artificial_words表中查询所有转人工文本
                 List<FastgptChatArtificialWords> chatArtificialWords = qwExternalContactMapper.selectChatGptChatArtificialWords();
                 List<String> collect = chatArtificialWords.stream().map(m -> m.getContent()).collect(Collectors.toList());
-                if (collect.stream().anyMatch(contentKh::contains)){
+                if (collect.stream().anyMatch(content::contains)){
                     log.info("触发关键词:"+role.getRoleId()+":"+qwExternalContacts.getName());
                     notifyArtificial(fastGptChatSession.getSessionId(),user,qwExternalContacts.getName()," 触发关键词",qwExternalContacts.getId(),sender);
                     return R.ok();

+ 8 - 1
fs-service/src/main/resources/mapper/fastGpt/FastGptRoleMapper.xml

@@ -22,10 +22,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="contactInfo"    column="contact_info"    />
         <result property="channelType"    column="channel_type"    />
         <result property="logistics"    column="logistics"    />
+        <result property="forbidSendStart"    column="forbid_send_start"    />
+        <result property="forbidSendEnd"    column="forbid_send_end"    />
+        <result property="forbidStatus"    column="forbid_status"    />
     </resultMap>
 
     <sql id="selectFastGptRoleVo">
-        select role_id, role_name,contact_info,company_id, create_time, update_time, role_type, mode_config_json, mode, kf_id, kf_url, avatar, kf_media_id,reminder_words, bind_corp_id,channel_type,logistics from fastgpt_role
+        select role_id, role_name,contact_info,company_id, create_time, update_time, role_type, mode_config_json,
+               mode, kf_id, kf_url, avatar, kf_media_id,reminder_words, bind_corp_id,channel_type,logistics,forbid_send_start,
+               forbid_send_end,forbid_status
+        from fastgpt_role
     </sql>
 
     <select id="selectFastGptRoleList" parameterType="FastGptRole" resultMap="FastGptRoleResult">
@@ -136,6 +142,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="contactInfo != null">contact_info = #{contactInfo},</if>
             <if test="channelType != null">channel_type = #{channelType},</if>
             <if test="logistics != null">logistics = #{logistics},</if>
+            <if test="forbidStatus != null">forbid_status = #{forbidStatus},</if>
         </trim>
         where role_id = #{roleId}
     </update>