Procházet zdrojové kódy

对外会话记录存储接口增添

Zhangbw před 2 měsíci
rodič
revize
55399d4807
16 změnil soubory, kde provedl 242 přidání a 82 odebrání
  1. 1 1
      ruoyi-admin/src/main/resources/application.yml
  2. 2 2
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/controller/api/ChatController.java
  3. 30 11
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/controller/api/WhatsAppHistoryApiController.java
  4. 0 5
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/domain/WhatsAppHistory.java
  5. 0 5
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/domain/bo/WhatsAppHistoryBo.java
  6. 2 2
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/domain/dto/MessageStreamRequest.java
  7. 0 26
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/domain/dto/WhatsAppMessageRequest.java
  8. 7 0
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/domain/vo/WhatsAppUserVo.java
  9. 1 1
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/IChatService.java
  10. 1 1
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/IDifyService.java
  11. 9 0
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/ITalkSessionService.java
  12. 6 4
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/IWhatsAppHistoryService.java
  13. 4 1
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/impl/ChatServiceImpl.java
  14. 3 3
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/impl/DifyServiceImpl.java
  15. 99 4
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/impl/TalkSessionServiceImpl.java
  16. 77 16
      ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/impl/WhatsAppHistoryServiceImpl.java

+ 1 - 1
ruoyi-admin/src/main/resources/application.yml

@@ -118,7 +118,7 @@ security:
     - /warm-flow-ui/config
     - /talk/auth/**
     - /talk/message/stream
-    - /talk/whatsapp/**
+    - /talk/conversation/**
 
 # 多租户配置
 tenant:

+ 2 - 2
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/controller/api/ChatController.java

@@ -132,9 +132,9 @@ public class ChatController {
      */
     @PostMapping("/message/stream")
     public SseEmitter handleMessageStream(@RequestBody MessageStreamRequest request) {
-        log.info("收到流式消息请求: {}, 客服ID: {}, 对话ID: {}, 请求ID: {}, 客户电话: {}, 类型: {}",
+        log.info("收到流式消息请求: {}, 客服ID: {}, 对话ID: {}, 请求ID: {}, 客户电话: {}, 来源: {}",
             request.getMessage(), request.getAgentId(), request.getConversationId(),
-            request.getRequestId(), request.getCustomerPhone(), request.getType());
+            request.getRequestId(), request.getCustomerPhone(), request.getSource());
 
         SseEmitter emitter = new SseEmitter(60000L);
         chatService.processMessageStream(

+ 30 - 11
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/controller/api/WhatsAppHistoryApiController.java

@@ -3,37 +3,56 @@ package org.dromara.talk.controller.api;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.domain.R;
-import org.dromara.talk.domain.dto.WhatsAppMessageRequest;
+import org.dromara.talk.domain.dto.ConversationMessageRequest;
 import org.dromara.talk.service.IWhatsAppHistoryService;
+import org.dromara.talk.service.ITalkSessionService;
 import org.springframework.web.bind.annotation.*;
 
 /**
- * WhatsApp历史记录API接口(对外)
+ * 对话历史记录API接口(对外)
  */
 @Slf4j
 @RequiredArgsConstructor
 @RestController
-@RequestMapping("/talk/whatsapp/history")
+@RequestMapping("/talk/conversation")
 @CrossOrigin(origins = "*", maxAge = 3600)
 public class WhatsAppHistoryApiController {
 
     private final IWhatsAppHistoryService whatsAppHistoryService;
+    private final ITalkSessionService talkSessionService;
 
     /**
-     * 接收WhatsApp消息
+     * 接收对话消息(支持WhatsApp和ZoomPhone)
      */
     @PostMapping("/receive")
-    public R<Void> receiveMessage(@RequestBody WhatsAppMessageRequest request) {
+    public R<Void> receiveMessage(@RequestBody ConversationMessageRequest request) {
         try {
-            Boolean success = whatsAppHistoryService.receiveMessage(request);
-            if (Boolean.TRUE.equals(success)) {
-                return R.ok();
-            } else {
-                return R.fail("保存消息失败");
+            log.info("接收到{}消息 - conversationId: {}, userId: {}, round: {}",
+                request.getSource(), request.getConversationId(), request.getUserId(), request.getRound());
+
+            // 根据source路由到不同的Service
+            if ("whatsapp".equalsIgnoreCase(request.getSource())) {
+                Boolean success = whatsAppHistoryService.receiveConversationMessage(request);
+                if (Boolean.TRUE.equals(success)) {
+                    return R.ok();
+                } else {
+                    return R.fail("保存WhatsApp消息失败");
+                }
+            } else if ("zoomphone".equalsIgnoreCase(request.getSource())) {
+                Boolean success =talkSessionService.receiveConversationMessage(request);
+                if (Boolean.TRUE.equals(success)) {
+                    return R.ok();
+                } else {
+                    return R.fail("保存ZoomPhone消息失败");
+                }
+            }else{
+                return R.fail("不支持的消息来源: " + request.getSource());
             }
         } catch (Exception e) {
-            log.error("保存WhatsApp消息失败", e);
+            log.error("保存消息失败", e);
             return R.fail("保存消息失败: " + e.getMessage());
         }
     }
+
+
 }

+ 0 - 5
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/domain/WhatsAppHistory.java

@@ -48,11 +48,6 @@ public class WhatsAppHistory extends TenantEntity {
      */
     private Date startTime;
 
-    /**
-     * 会话结束时间
-     */
-    private Date endTime;
-
     /**
      * 删除标志
      */

+ 0 - 5
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/domain/bo/WhatsAppHistoryBo.java

@@ -49,9 +49,4 @@ public class WhatsAppHistoryBo extends BaseEntity {
      */
     private Date startTime;
 
-    /**
-     * 会话结束时间
-     */
-    private Date endTime;
-
 }

+ 2 - 2
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/domain/dto/MessageStreamRequest.java

@@ -55,7 +55,7 @@ public class MessageStreamRequest {
     private String customerPhone;
 
     /**
-     * 客户类型:2=ZoomPhone客户
+     * 来源:whatsapp / zoomphone
      */
-    private Integer type;
+    private String source;
 }

+ 0 - 26
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/domain/dto/WhatsAppMessageRequest.java

@@ -1,26 +0,0 @@
-package org.dromara.talk.domain.dto;
-
-import lombok.Data;
-/**
- * WhatsApp消息接收请求
- */
-@Data
-public class WhatsAppMessageRequest {
-
-    /**
-     * 会话ID
-     */
-    private String sessionId;
-
-    /**
-     * 用户账号
-     */
-    private String userAccount;
-
-    /**
-     * 对话历史
-     */
-    private String conversationHistory;
-
-    
-}

+ 7 - 0
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/domain/vo/WhatsAppUserVo.java

@@ -8,6 +8,7 @@ import lombok.Data;
 
 import java.io.Serial;
 import java.io.Serializable;
+import java.util.Date;
 
 
 /**
@@ -36,4 +37,10 @@ public class WhatsAppUserVo implements Serializable {
     @ExcelProperty(value = "用户账号")
     private String userAccount;
 
+    /**
+     * 创建时间
+     */
+    @ExcelProperty(value = "创建时间")
+    private Date createTime;
+
 }

+ 1 - 1
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/IChatService.java

@@ -21,7 +21,7 @@ public interface IChatService {
      *  isGreeting 是否为欢迎语
      *  requestId 请求ID(用于判断是否为最新请求)
      *  customerPhone 客户电话号码
-     *  type 客户类型:2=ZoomPhone客户
+     *  source 来源:whatsapp / zoomphone
      *  emitter SSE发射器
      */
     void processMessageStream(MessageStreamRequest request, SseEmitter emitter);

+ 1 - 1
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/IDifyService.java

@@ -12,7 +12,7 @@ public interface IDifyService {
     * 流式调用Dify工作流(按句子分段)
     */
    void callWorkflowStream(String userMessage, String agentGender, List<Map<String, String>> ttsVcnList,
-                          TalkAgentVo agentConfig, Long userId, String conversationId, String customerPhone, Integer type,
+                          TalkAgentVo agentConfig, Long userId, String conversationId, String customerPhone, String source,
                           Consumer<String> onTextChunk,
                           SentenceCallback onSentence);
 

+ 9 - 0
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/ITalkSessionService.java

@@ -2,6 +2,7 @@ package org.dromara.talk.service;
 
 import org.dromara.talk.domain.vo.TalkSessionVo;
 import org.dromara.talk.domain.bo.TalkSessionBo;
+import org.dromara.talk.domain.dto.ConversationMessageRequest;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.mybatis.core.page.PageQuery;
 
@@ -104,4 +105,12 @@ public interface ITalkSessionService {
      * @return 是否成功
      */
     Boolean updateEndTime(String sessionId);
+
+     /**
+     * 接收并保存对话消息
+     *
+     * @param request 对话消息请求
+     * @return 是否保存成功
+     */
+    Boolean receiveConversationMessage(ConversationMessageRequest request);
 }

+ 6 - 4
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/IWhatsAppHistoryService.java

@@ -2,7 +2,7 @@ package org.dromara.talk.service;
 
 import org.dromara.talk.domain.vo.WhatsAppHistoryVo;
 import org.dromara.talk.domain.bo.WhatsAppHistoryBo;
-import org.dromara.talk.domain.dto.WhatsAppMessageRequest;
+import org.dromara.talk.domain.dto.ConversationMessageRequest;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.mybatis.core.page.PageQuery;
 
@@ -67,11 +67,13 @@ public interface IWhatsAppHistoryService {
      */
     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
 
+
+
     /**
-     * 接收并保存WhatsApp消息
+     * 接收并保存对话消息
      *
-     * @param request WhatsApp消息请求
+     * @param request 对话消息请求
      * @return 是否保存成功
      */
-    Boolean receiveMessage(WhatsAppMessageRequest request);
+    Boolean receiveConversationMessage(ConversationMessageRequest request);
 }

+ 4 - 1
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/impl/ChatServiceImpl.java

@@ -156,7 +156,10 @@ public class ChatServiceImpl implements IChatService {
                     }
                 }
 
-                difyService.callWorkflowStream(request.getMessage(), request.getAgentGender(), request.getTtsVcnList(), agentConfig, finalUserId, difyConversationId, request.getCustomerPhone(), request.getType(),
+                // 处理source字段,去除前后空格
+                String source = request.getSource() != null ? request.getSource().trim() : null;
+
+                difyService.callWorkflowStream(request.getMessage(), request.getAgentGender(), request.getTtsVcnList(), agentConfig, finalUserId, difyConversationId, request.getCustomerPhone(), source,
                     (textChunk) -> {
                         try {
                             // 累积AI回复文本

+ 3 - 3
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/impl/DifyServiceImpl.java

@@ -27,7 +27,7 @@ public class DifyServiceImpl implements IDifyService {
     public void callWorkflowStream(String userMessage, String agentGender,
                                    java.util.List<java.util.Map<String, String>> ttsVcnList,
                                    org.dromara.talk.domain.vo.TalkAgentVo agentConfig,
-                                   Long userId, String conversationId, String customerPhone, Integer type,
+                                   Long userId, String conversationId, String customerPhone, String source,
                                    java.util.function.Consumer<String> onTextChunk,
                                    IDifyService.SentenceCallback onSentence) {
         try {
@@ -41,8 +41,8 @@ public class DifyServiceImpl implements IDifyService {
             if (customerPhone != null && !customerPhone.isEmpty()) {
                 inputs.put("customerPhone", customerPhone);
             }
-            if (type != null) {
-                inputs.put("type", type);
+            if (source != null && !source.isEmpty()) {
+                inputs.put("source", source);
             }
 
             JSONObject requestBody = new JSONObject();

+ 99 - 4
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/impl/TalkSessionServiceImpl.java

@@ -1,5 +1,7 @@
 package org.dromara.talk.service.impl;
 
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.TypeReference;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -9,16 +11,16 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.talk.domain.bo.*;
+import org.dromara.talk.domain.dto.ConversationMessageRequest;
+import org.dromara.talk.service.IPhoneUserService;
 import org.springframework.stereotype.Service;
-import org.dromara.talk.domain.bo.TalkSessionBo;
 import org.dromara.talk.domain.vo.TalkSessionVo;
 import org.dromara.talk.domain.TalkSession;
 import org.dromara.talk.mapper.TalkSessionMapper;
 import org.dromara.talk.service.ITalkSessionService;
 
-import java.util.Date;
-import java.util.List;
-import java.util.Collection;
+import java.util.*;
 
 /**
  * 对话会话Service业务层处理
@@ -33,6 +35,9 @@ public class TalkSessionServiceImpl implements ITalkSessionService {
 
     private final TalkSessionMapper baseMapper;
 
+    private final IPhoneUserService phoneUserService;
+
+
     /**
      * 查询对话会话
      *
@@ -206,4 +211,94 @@ public class TalkSessionServiceImpl implements ITalkSessionService {
         }
         return false;
     }
+
+    /**
+     * 接收对话内容
+     *
+     * @param request 对话内容
+     * @return 是否成功
+     */
+    @Override
+    public Boolean receiveConversationMessage(ConversationMessageRequest request) {
+        log.info("接收到对话消息 - conversationId: {}, userId: {}, round: {}",
+            request.getConversationId(), request.getUserId(), request.getRound());
+
+        // 1. 检查并保存用户
+        PhoneUserBo userBo = new PhoneUserBo();
+        userBo.setCustomerPhone(request.getUserId());
+        try {
+            phoneUserService.insertByBo(userBo);
+            log.info("新用户已保存: {}", request.getUserId());
+        } catch (Exception e) {
+            log.debug("用户可能已存在: {}", request.getUserId());
+        }
+
+        // 2. 查询是否已存在该会话的记录
+        TalkSessionBo queryBo = new TalkSessionBo();
+        queryBo.setSessionId(request.getConversationId());
+        List<TalkSessionVo> existingRecords = queryList(queryBo);
+
+        List<Map<String, String>> conversationHistory;
+        TalkSessionBo historyBo;
+
+        if (!existingRecords.isEmpty()) {
+            // 已存在记录,读取并追加
+            TalkSessionVo existing = existingRecords.get(0);
+            String existingJson = existing.getConversationJson();
+            conversationHistory = JSON.parseObject(existingJson, new TypeReference<List<Map<String, String>>>() {});
+
+            historyBo = new TalkSessionBo();
+            historyBo.setId(existing.getId());
+        } else {
+            // 新会话,创建新记录
+            conversationHistory = new ArrayList<>();
+            historyBo = new TalkSessionBo();
+            historyBo.setSessionId(request.getConversationId());
+            historyBo.setCustomerPhone(request.getUserId());
+            historyBo.setStartTime(new Date());
+        }
+
+        // 3. 追加新的对话轮次(user消息 + assistant消息)
+        Map<String, String> userMessage = new HashMap<>();
+        userMessage.put("role", "user");
+        userMessage.put("content", request.getQuery());
+        userMessage.put("timestamp", request.getTimestamp());
+        userMessage.put("round", String.valueOf(request.getRound()));
+        conversationHistory.add(userMessage);
+
+        Map<String, String> assistantMessage = new HashMap<>();
+        assistantMessage.put("role", "assistant");
+        assistantMessage.put("content", request.getAgent());
+        assistantMessage.put("timestamp", request.getTimestamp());
+        assistantMessage.put("round", String.valueOf(request.getRound()));
+        conversationHistory.add(assistantMessage);
+
+        // 4. 按round排序,同一轮内user在assistant之前
+        conversationHistory.sort((m1, m2) -> {
+            int round1 = Integer.parseInt(m1.getOrDefault("round", "0"));
+            int round2 = Integer.parseInt(m2.getOrDefault("round", "0"));
+            int roundCompare = Integer.compare(round1, round2);
+            if (roundCompare != 0) {
+                return roundCompare;
+            }
+            // 同一轮内,user 在 assistant 之前
+            String role1 = m1.getOrDefault("role", "");
+            String role2 = m2.getOrDefault("role", "");
+            if ("user".equals(role1) && "assistant".equals(role2)) {
+                return -1;
+            } else if ("assistant".equals(role1) && "user".equals(role2)) {
+                return 1;
+            }
+            return 0;
+        });
+
+        // 5. 保存或更新记录
+        historyBo.setConversationJson(JSON.toJSONString(conversationHistory));
+
+        if (historyBo.getId() != null) {
+            return updateByBo(historyBo);
+        } else {
+            return insertByBo(historyBo);
+        }
+    }
 }

+ 77 - 16
ruoyi-modules/yp-talk/src/main/java/org/dromara/talk/service/impl/WhatsAppHistoryServiceImpl.java

@@ -17,12 +17,16 @@ import org.dromara.talk.mapper.WhatsAppHistoryMapper;
 import org.dromara.talk.service.IWhatsAppHistoryService;
 import org.dromara.talk.service.IWhatsAppUserService;
 import org.dromara.talk.domain.bo.WhatsAppUserBo;
-import org.dromara.talk.domain.dto.WhatsAppMessageRequest;
+import org.dromara.talk.domain.dto.ConversationMessageRequest;
 import com.alibaba.fastjson2.JSON;
 
 import java.util.List;
 import java.util.Collection;
 import java.util.Date;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.ArrayList;
+import com.alibaba.fastjson2.TypeReference;
 
 /**
  * WhatsApp历史记录Service业务层处理
@@ -81,7 +85,6 @@ public class WhatsAppHistoryServiceImpl implements IWhatsAppHistoryService {
         lqw.eq(StringUtils.isNotBlank(bo.getSessionId()), WhatsAppHistory::getSessionId, bo.getSessionId());
         lqw.eq(StringUtils.isNotBlank(bo.getUserAccount()), WhatsAppHistory::getUserAccount, bo.getUserAccount());
         lqw.eq(bo.getStartTime() != null, WhatsAppHistory::getStartTime, bo.getStartTime());
-        lqw.eq(bo.getEndTime() != null, WhatsAppHistory::getEndTime, bo.getEndTime());
         return lqw;
     }
 
@@ -133,28 +136,86 @@ public class WhatsAppHistoryServiceImpl implements IWhatsAppHistoryService {
      * @return 是否保存成功
      */
     @Override
-    public Boolean receiveMessage(WhatsAppMessageRequest request) {
-        log.info("接收到WhatsApp消息 - sessionId: {}, userAccount: {}",
-            request.getSessionId(), request.getUserAccount());
+    public Boolean receiveConversationMessage(ConversationMessageRequest request) {
+        log.info("接收到对话消息 - conversationId: {}, userId: {}, round: {}",
+            request.getConversationId(), request.getUserId(), request.getRound());
 
         // 1. 检查并保存用户
         WhatsAppUserBo userBo = new WhatsAppUserBo();
-        userBo.setUserAccount(request.getUserAccount());
+        userBo.setUserAccount(request.getUserId());
         try {
             whatsAppUserService.insertByBo(userBo);
-            log.info("新用户已保存: {}", request.getUserAccount());
+            log.info("新用户已保存: {}", request.getUserId());
         } catch (Exception e) {
-            // 用户可能已存在,忽略错误
-            log.debug("用户可能已存在: {}", request.getUserAccount());
+            log.debug("用户可能已存在: {}", request.getUserId());
         }
 
-        // 2. 保存对话历史
-        WhatsAppHistoryBo historyBo = new WhatsAppHistoryBo();
-        historyBo.setSessionId(request.getSessionId());
-        historyBo.setUserAccount(request.getUserAccount());
-        historyBo.setConversationJson(JSON.toJSONString(request.getConversationHistory()));
-        historyBo.setStartTime(new Date());
+        // 2. 查询是否已存在该会话的记录
+        WhatsAppHistoryBo queryBo = new WhatsAppHistoryBo();
+        queryBo.setSessionId(request.getConversationId());
+        List<WhatsAppHistoryVo> existingRecords = queryList(queryBo);
+
+        List<Map<String, String>> conversationHistory;
+        WhatsAppHistoryBo historyBo;
+
+        if (!existingRecords.isEmpty()) {
+            // 已存在记录,读取并追加
+            WhatsAppHistoryVo existing = existingRecords.get(0);
+            String existingJson = existing.getConversationJson();
+            conversationHistory = JSON.parseObject(existingJson, new TypeReference<List<Map<String, String>>>() {});
+
+            historyBo = new WhatsAppHistoryBo();
+            historyBo.setId(existing.getId());
+        } else {
+            // 新会话,创建新记录
+            conversationHistory = new ArrayList<>();
+            historyBo = new WhatsAppHistoryBo();
+            historyBo.setSessionId(request.getConversationId());
+            historyBo.setUserAccount(request.getUserId());
+            historyBo.setStartTime(new Date());
+        }
 
-        return insertByBo(historyBo);
+        // 3. 追加新的对话轮次(user消息 + assistant消息)
+        Map<String, String> userMessage = new HashMap<>();
+        userMessage.put("role", "user");
+        userMessage.put("content", request.getQuery());
+        userMessage.put("timestamp", request.getTimestamp());
+        userMessage.put("round", String.valueOf(request.getRound()));
+        conversationHistory.add(userMessage);
+
+        Map<String, String> assistantMessage = new HashMap<>();
+        assistantMessage.put("role", "assistant");
+        assistantMessage.put("content", request.getAgent());
+        assistantMessage.put("timestamp", request.getTimestamp());
+        assistantMessage.put("round", String.valueOf(request.getRound()));
+        conversationHistory.add(assistantMessage);
+
+        // 4. 按round排序,同一轮内user在assistant之前
+        conversationHistory.sort((m1, m2) -> {
+            int round1 = Integer.parseInt(m1.getOrDefault("round", "0"));
+            int round2 = Integer.parseInt(m2.getOrDefault("round", "0"));
+            int roundCompare = Integer.compare(round1, round2);
+            if (roundCompare != 0) {
+                return roundCompare;
+            }
+            // 同一轮内,user 在 assistant 之前
+            String role1 = m1.getOrDefault("role", "");
+            String role2 = m2.getOrDefault("role", "");
+            if ("user".equals(role1) && "assistant".equals(role2)) {
+                return -1;
+            } else if ("assistant".equals(role1) && "user".equals(role2)) {
+                return 1;
+            }
+            return 0;
+        });
+
+        // 5. 保存或更新记录
+        historyBo.setConversationJson(JSON.toJSONString(conversationHistory));
+
+        if (historyBo.getId() != null) {
+            return updateByBo(historyBo);
+        } else {
+            return insertByBo(historyBo);
+        }
     }
 }