diff --git a/src/main/java/com/yolo/keyborad/mapper/KeyboardAiChatSessionMapper.java b/src/main/java/com/yolo/keyborad/mapper/KeyboardAiChatSessionMapper.java new file mode 100644 index 0000000..0a6ed15 --- /dev/null +++ b/src/main/java/com/yolo/keyborad/mapper/KeyboardAiChatSessionMapper.java @@ -0,0 +1,12 @@ +package com.yolo.keyborad.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yolo.keyborad.model.entity.KeyboardAiChatSession; + +/* +* @author: ziin +* @date: 2026/1/28 16:20 +*/ + +public interface KeyboardAiChatSessionMapper extends BaseMapper { +} \ No newline at end of file diff --git a/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiChatMessage.java b/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiChatMessage.java index 659f16c..960b8bd 100644 --- a/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiChatMessage.java +++ b/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiChatMessage.java @@ -75,4 +75,8 @@ public class KeyboardAiChatMessage { @TableField(value = "created_at") @Schema(description="消息创建时间") private Date createdAt; + + @TableField(value = "session_id") + @Schema(description = "会话Id") + private Long sessionId; } \ No newline at end of file diff --git a/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiChatSession.java b/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiChatSession.java new file mode 100644 index 0000000..cfbba6d --- /dev/null +++ b/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiChatSession.java @@ -0,0 +1,71 @@ +package com.yolo.keyborad.model.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.Date; +import lombok.Data; + +/* +* @author: ziin +* @date: 2026/1/28 16:20 +*/ + +/** + * 用户与AI陪伴角色的聊天会话表,用于支持聊天重置与关系重启 + */ +@Schema(description="用户与AI陪伴角色的聊天会话表,用于支持聊天重置与关系重启") +@Data +@TableName(value = "keyboard_ai_chat_session") +public class KeyboardAiChatSession { + /** + * 聊天会话唯一ID + */ + @TableId(value = "id", type = IdType.AUTO) + @Schema(description="聊天会话唯一ID") + private Long id; + + /** + * 用户ID + */ + @TableField(value = "user_id") + @Schema(description="用户ID") + private Long userId; + + /** + * 陪伴角色ID + */ + @TableField(value = "companion_id") + @Schema(description="陪伴角色ID") + private Long companionId; + + /** + * 会话重置版本号,用于标识第几次重新开始陪伴关系 + */ + @TableField(value = "reset_version") + @Schema(description="会话重置版本号,用于标识第几次重新开始陪伴关系") + private Integer resetVersion; + + /** + * 是否为当前活跃会话(true=当前使用中) + */ + @TableField(value = "is_active") + @Schema(description="是否为当前活跃会话(true=当前使用中)") + private Boolean isActive; + + /** + * 会话创建时间 + */ + @TableField(value = "created_at") + @Schema(description="会话创建时间") + private Date createdAt; + + /** + * 会话结束时间(用户重置或系统关闭会话时记录) + */ + @TableField(value = "ended_at") + @Schema(description="会话结束时间(用户重置或系统关闭会话时记录)") + private Date endedAt; +} \ No newline at end of file diff --git a/src/main/java/com/yolo/keyborad/service/KeyboardAiChatSessionService.java b/src/main/java/com/yolo/keyborad/service/KeyboardAiChatSessionService.java new file mode 100644 index 0000000..b997878 --- /dev/null +++ b/src/main/java/com/yolo/keyborad/service/KeyboardAiChatSessionService.java @@ -0,0 +1,29 @@ +package com.yolo.keyborad.service; + +import com.yolo.keyborad.model.entity.KeyboardAiChatSession; +import com.baomidou.mybatisplus.extension.service.IService; + +/* + * @author: ziin + * @date: 2026/1/28 16:20 + */ +public interface KeyboardAiChatSessionService extends IService { + + /** + * 获取用户与AI角色的活跃会话,如果不存在则创建新会话 + * + * @param userId 用户ID + * @param companionId AI角色ID + * @return 活跃会话 + */ + KeyboardAiChatSession getOrCreateActiveSession(Long userId, Long companionId); + + /** + * 获取用户与AI角色的活跃会话ID,如果不存在则创建新会话 + * + * @param userId 用户ID + * @param companionId AI角色ID + * @return 活跃会话ID + */ + Long getOrCreateActiveSessionId(Long userId, Long companionId); +} diff --git a/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java index c167fd7..ff78b70 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java @@ -89,6 +89,9 @@ public class ChatServiceImpl implements ChatService { @Resource private KeyboardAiChatMessageService aiChatMessageService; + @Resource + private KeyboardAiChatSessionService aiChatSessionService; + @Resource private ElevenLabsService elevenLabsService; @@ -457,10 +460,14 @@ public class ChatServiceImpl implements ChatService { private void saveChatMessages(Long userId, Long companionId, String userContent, String aiResponse) { Date now = new Date(); + // 获取或创建活跃会话 + Long sessionId = aiChatSessionService.getOrCreateActiveSessionId(userId, companionId); + // 保存用户消息 (sender=1) KeyboardAiChatMessage userMessage = new KeyboardAiChatMessage(); userMessage.setUserId(userId); userMessage.setCompanionId(companionId); + userMessage.setSessionId(sessionId); userMessage.setSender((short) 1); userMessage.setContent(userContent); userMessage.setCreatedAt(now); @@ -469,13 +476,14 @@ public class ChatServiceImpl implements ChatService { KeyboardAiChatMessage aiMessage = new KeyboardAiChatMessage(); aiMessage.setUserId(userId); aiMessage.setCompanionId(companionId); + aiMessage.setSessionId(sessionId); aiMessage.setSender((short) 2); aiMessage.setContent(aiResponse); aiMessage.setCreatedAt(now); // 批量保存 aiChatMessageService.saveBatch(List.of(userMessage, aiMessage)); - log.info("聊天记录保存成功, userId: {}, companionId: {}", userId, companionId); + log.info("聊天记录保存成功, userId: {}, companionId: {}, sessionId: {}", userId, companionId, sessionId); } /** diff --git a/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiChatSessionServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiChatSessionServiceImpl.java new file mode 100644 index 0000000..77c2b78 --- /dev/null +++ b/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiChatSessionServiceImpl.java @@ -0,0 +1,58 @@ +package com.yolo.keyborad.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.springframework.stereotype.Service; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yolo.keyborad.mapper.KeyboardAiChatSessionMapper; +import com.yolo.keyborad.model.entity.KeyboardAiChatSession; +import com.yolo.keyborad.service.KeyboardAiChatSessionService; + +import java.util.Date; + +/* + * @author: ziin + * @date: 2026/1/28 16:20 + */ +@Service +public class KeyboardAiChatSessionServiceImpl extends ServiceImpl implements KeyboardAiChatSessionService { + + @Override + public KeyboardAiChatSession getOrCreateActiveSession(Long userId, Long companionId) { + // 查询当前活跃会话 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(KeyboardAiChatSession::getUserId, userId) + .eq(KeyboardAiChatSession::getCompanionId, companionId) + .eq(KeyboardAiChatSession::getIsActive, true); + KeyboardAiChatSession activeSession = this.getOne(queryWrapper); + + if (activeSession != null) { + return activeSession; + } + + // 不存在活跃会话,创建新会话 + // 先查询该用户与该角色的最大版本号 + LambdaQueryWrapper 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(new Date()); + this.save(newSession); + + return newSession; + } + + @Override + public Long getOrCreateActiveSessionId(Long userId, Long companionId) { + return getOrCreateActiveSession(userId, companionId).getId(); + } +} diff --git a/src/main/resources/mapper/KeyboardAiChatSessionMapper.xml b/src/main/resources/mapper/KeyboardAiChatSessionMapper.xml new file mode 100644 index 0000000..04b942d --- /dev/null +++ b/src/main/resources/mapper/KeyboardAiChatSessionMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + id, user_id, companion_id, reset_version, is_active, created_at, ended_at + + \ No newline at end of file