feat(chat): 新增重置会话接口并优化主键策略
- ChatController 增加 /session/reset 端点,支持用户主动重置与 AI 角色的会话 - 会话重置逻辑:将当前活跃会话置为失效,并创建版本号递增的新会话 - 新增 SessionResetReq DTO 与 ChatSessionVO 返回视图 - KeyboardAiChatSession 主键生成策略由 AUTO 改为 ASSIGN_ID,适配分布式场景
This commit is contained in:
@@ -14,12 +14,15 @@ import com.yolo.keyborad.model.dto.chat.ChatMessageReq;
|
|||||||
import com.yolo.keyborad.model.dto.chat.ChatReq;
|
import com.yolo.keyborad.model.dto.chat.ChatReq;
|
||||||
import com.yolo.keyborad.model.dto.chat.ChatSaveReq;
|
import com.yolo.keyborad.model.dto.chat.ChatSaveReq;
|
||||||
import com.yolo.keyborad.model.dto.chat.ChatStreamMessage;
|
import com.yolo.keyborad.model.dto.chat.ChatStreamMessage;
|
||||||
|
import com.yolo.keyborad.model.dto.chat.SessionResetReq;
|
||||||
import com.yolo.keyborad.model.vo.AudioTaskVO;
|
import com.yolo.keyborad.model.vo.AudioTaskVO;
|
||||||
import com.yolo.keyborad.model.vo.ChatMessageHistoryVO;
|
import com.yolo.keyborad.model.vo.ChatMessageHistoryVO;
|
||||||
import com.yolo.keyborad.model.vo.ChatMessageVO;
|
import com.yolo.keyborad.model.vo.ChatMessageVO;
|
||||||
|
import com.yolo.keyborad.model.vo.ChatSessionVO;
|
||||||
import com.yolo.keyborad.model.vo.ChatVoiceVO;
|
import com.yolo.keyborad.model.vo.ChatVoiceVO;
|
||||||
import com.yolo.keyborad.service.ChatService;
|
import com.yolo.keyborad.service.ChatService;
|
||||||
import com.yolo.keyborad.service.KeyboardAiChatMessageService;
|
import com.yolo.keyborad.service.KeyboardAiChatMessageService;
|
||||||
|
import com.yolo.keyborad.service.KeyboardAiChatSessionService;
|
||||||
import com.yolo.keyborad.service.impl.QdrantVectorService;
|
import com.yolo.keyborad.service.impl.QdrantVectorService;
|
||||||
import io.qdrant.client.grpc.JsonWithInt;
|
import io.qdrant.client.grpc.JsonWithInt;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@@ -55,6 +58,9 @@ public class ChatController {
|
|||||||
@Resource
|
@Resource
|
||||||
private KeyboardAiChatMessageService aiChatMessageService;
|
private KeyboardAiChatMessageService aiChatMessageService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private KeyboardAiChatSessionService aiChatSessionService;
|
||||||
|
|
||||||
|
|
||||||
@PostMapping("/message")
|
@PostMapping("/message")
|
||||||
@Operation(summary = "同步对话", description = "发送消息给大模型,同步返回 AI 响应,异步生成音频")
|
@Operation(summary = "同步对话", description = "发送消息给大模型,同步返回 AI 响应,异步生成音频")
|
||||||
@@ -131,4 +137,24 @@ public class ChatController {
|
|||||||
userId, req.getCompanionId(), req.getPageNum(), req.getPageSize());
|
userId, req.getCompanionId(), req.getPageNum(), req.getPageSize());
|
||||||
return ResultUtils.success(result);
|
return ResultUtils.success(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/session/reset")
|
||||||
|
@Operation(summary = "重置会话", description = "重置与AI角色的聊天会话,将当前会话设为不活跃并创建新会话,后续聊天记录将绑定到新会话")
|
||||||
|
public BaseResponse<ChatSessionVO> resetSession(@RequestBody SessionResetReq req) {
|
||||||
|
if (req.getCompanionId() == null) {
|
||||||
|
throw new BusinessException(ErrorCode.COMPANION_ID_EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
Long userId = StpUtil.getLoginIdAsLong();
|
||||||
|
var newSession = aiChatSessionService.resetSession(userId, req.getCompanionId());
|
||||||
|
|
||||||
|
ChatSessionVO vo = ChatSessionVO.builder()
|
||||||
|
.sessionId(newSession.getId())
|
||||||
|
.companionId(newSession.getCompanionId())
|
||||||
|
.resetVersion(newSession.getResetVersion())
|
||||||
|
.createdAt(newSession.getCreatedAt())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return ResultUtils.success(vo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.yolo.keyborad.model.dto.chat;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author: ziin
|
||||||
|
* @date: 2026/1/28
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "会话重置请求")
|
||||||
|
public class SessionResetReq {
|
||||||
|
|
||||||
|
@Schema(description = "AI陪聊角色ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private Long companionId;
|
||||||
|
}
|
||||||
29
src/main/java/com/yolo/keyborad/model/vo/ChatSessionVO.java
Normal file
29
src/main/java/com/yolo/keyborad/model/vo/ChatSessionVO.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package com.yolo.keyborad.model.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author: ziin
|
||||||
|
* @date: 2026/1/28
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@Schema(description = "会话信息VO")
|
||||||
|
public class ChatSessionVO {
|
||||||
|
|
||||||
|
@Schema(description = "会话ID")
|
||||||
|
private Long sessionId;
|
||||||
|
|
||||||
|
@Schema(description = "AI陪聊角色ID")
|
||||||
|
private Long companionId;
|
||||||
|
|
||||||
|
@Schema(description = "会话版本号")
|
||||||
|
private Integer resetVersion;
|
||||||
|
|
||||||
|
@Schema(description = "会话创建时间")
|
||||||
|
private Date createdAt;
|
||||||
|
}
|
||||||
@@ -26,4 +26,13 @@ public interface KeyboardAiChatSessionService extends IService<KeyboardAiChatSes
|
|||||||
* @return 活跃会话ID
|
* @return 活跃会话ID
|
||||||
*/
|
*/
|
||||||
Long getOrCreateActiveSessionId(Long userId, Long companionId);
|
Long getOrCreateActiveSessionId(Long userId, Long companionId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置会话:将当前活跃会话设为不活跃,并创建新的活跃会话
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param companionId AI角色ID
|
||||||
|
* @return 新创建的活跃会话
|
||||||
|
*/
|
||||||
|
KeyboardAiChatSession resetSession(Long userId, Long companionId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,4 +55,43 @@ public class KeyboardAiChatSessionServiceImpl extends ServiceImpl<KeyboardAiChat
|
|||||||
public Long getOrCreateActiveSessionId(Long userId, Long companionId) {
|
public Long getOrCreateActiveSessionId(Long userId, Long companionId) {
|
||||||
return getOrCreateActiveSession(userId, companionId).getId();
|
return getOrCreateActiveSession(userId, companionId).getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeyboardAiChatSession resetSession(Long userId, Long companionId) {
|
||||||
|
Date now = new Date();
|
||||||
|
|
||||||
|
// 查询当前活跃会话
|
||||||
|
LambdaQueryWrapper<KeyboardAiChatSession> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(KeyboardAiChatSession::getUserId, userId)
|
||||||
|
.eq(KeyboardAiChatSession::getCompanionId, companionId)
|
||||||
|
.eq(KeyboardAiChatSession::getIsActive, true);
|
||||||
|
KeyboardAiChatSession activeSession = this.getOne(queryWrapper);
|
||||||
|
|
||||||
|
// 如果存在活跃会话,将其设为不活跃
|
||||||
|
if (activeSession != null) {
|
||||||
|
activeSession.setIsActive(false);
|
||||||
|
activeSession.setEndedAt(now);
|
||||||
|
this.updateById(activeSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询该用户与该角色的最大版本号
|
||||||
|
LambdaQueryWrapper<KeyboardAiChatSession> maxVersionWrapper = new LambdaQueryWrapper<>();
|
||||||
|
maxVersionWrapper.eq(KeyboardAiChatSession::getUserId, userId)
|
||||||
|
.eq(KeyboardAiChatSession::getCompanionId, companionId)
|
||||||
|
.orderByDesc(KeyboardAiChatSession::getResetVersion)
|
||||||
|
.last("LIMIT 1");
|
||||||
|
KeyboardAiChatSession lastSession = this.getOne(maxVersionWrapper);
|
||||||
|
int newVersion = lastSession != null ? lastSession.getResetVersion() + 1 : 1;
|
||||||
|
|
||||||
|
// 创建新的活跃会话
|
||||||
|
KeyboardAiChatSession newSession = new KeyboardAiChatSession();
|
||||||
|
newSession.setUserId(userId);
|
||||||
|
newSession.setCompanionId(companionId);
|
||||||
|
newSession.setResetVersion(newVersion);
|
||||||
|
newSession.setIsActive(true);
|
||||||
|
newSession.setCreatedAt(now);
|
||||||
|
this.save(newSession);
|
||||||
|
|
||||||
|
return newSession;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user