From 5e40dee0e0a4e4cff4a1aafca2444f61c39cbf32 Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期四, 19 三月 2026 11:17:14 +0800
Subject: [PATCH] #AI.会话能力增强
---
rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiChatMemoryServiceImpl.java | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 110 insertions(+), 9 deletions(-)
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiChatMemoryServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiChatMemoryServiceImpl.java
index b663a6a..c0a4a61 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiChatMemoryServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiChatMemoryServiceImpl.java
@@ -5,6 +5,8 @@
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.ai.dto.AiChatMemoryDto;
import com.vincent.rsf.server.ai.dto.AiChatMessageDto;
+import com.vincent.rsf.server.ai.dto.AiChatSessionPinRequest;
+import com.vincent.rsf.server.ai.dto.AiChatSessionRenameRequest;
import com.vincent.rsf.server.ai.dto.AiChatSessionDto;
import com.vincent.rsf.server.ai.entity.AiChatMessage;
import com.vincent.rsf.server.ai.entity.AiChatSession;
@@ -19,6 +21,7 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.Locale;
@Service
@RequiredArgsConstructor
@@ -47,7 +50,7 @@
}
@Override
- public List<AiChatSessionDto> listSessions(Long userId, Long tenantId, String promptCode) {
+ public List<AiChatSessionDto> listSessions(Long userId, Long tenantId, String promptCode, String keyword) {
ensureIdentity(userId, tenantId);
String resolvedPromptCode = requirePromptCode(promptCode);
List<AiChatSession> sessions = aiChatSessionMapper.selectList(new LambdaQueryWrapper<AiChatSession>()
@@ -56,6 +59,8 @@
.eq(AiChatSession::getPromptCode, resolvedPromptCode)
.eq(AiChatSession::getDeleted, 0)
.eq(AiChatSession::getStatus, StatusType.ENABLE.val)
+ .like(StringUtils.hasText(keyword), AiChatSession::getTitle, keyword == null ? null : keyword.trim())
+ .orderByDesc(AiChatSession::getPinned)
.orderByDesc(AiChatSession::getLastMessageTime)
.orderByDesc(AiChatSession::getId));
if (Cools.isEmpty(sessions)) {
@@ -63,12 +68,7 @@
}
List<AiChatSessionDto> result = new ArrayList<>();
for (AiChatSession session : sessions) {
- result.add(AiChatSessionDto.builder()
- .sessionId(session.getId())
- .title(session.getTitle())
- .promptCode(session.getPromptCode())
- .lastMessageTime(session.getLastMessageTime())
- .build());
+ result.add(buildSessionDto(session));
}
return result;
}
@@ -87,6 +87,7 @@
.setUserId(userId)
.setTenantId(tenantId)
.setLastMessageTime(now)
+ .setPinned(0)
.setStatus(StatusType.ENABLE.val)
.setDeleted(0)
.setCreateBy(userId)
@@ -157,6 +158,40 @@
}
}
+ @Override
+ public AiChatSessionDto renameSession(Long userId, Long tenantId, Long sessionId, AiChatSessionRenameRequest request) {
+ ensureIdentity(userId, tenantId);
+ if (request == null || !StringUtils.hasText(request.getTitle())) {
+ throw new CoolException("浼氳瘽鏍囬涓嶈兘涓虹┖");
+ }
+ AiChatSession session = requireOwnedSession(sessionId, userId, tenantId);
+ Date now = new Date();
+ AiChatSession update = new AiChatSession()
+ .setId(sessionId)
+ .setTitle(buildSessionTitle(request.getTitle()))
+ .setUpdateBy(userId)
+ .setUpdateTime(now);
+ aiChatSessionMapper.updateById(update);
+ return buildSessionDto(requireOwnedSession(sessionId, userId, tenantId));
+ }
+
+ @Override
+ public AiChatSessionDto pinSession(Long userId, Long tenantId, Long sessionId, AiChatSessionPinRequest request) {
+ ensureIdentity(userId, tenantId);
+ if (request == null || request.getPinned() == null) {
+ throw new CoolException("缃《鐘舵�佷笉鑳戒负绌�");
+ }
+ AiChatSession session = requireOwnedSession(sessionId, userId, tenantId);
+ Date now = new Date();
+ AiChatSession update = new AiChatSession()
+ .setId(sessionId)
+ .setPinned(Boolean.TRUE.equals(request.getPinned()) ? 1 : 0)
+ .setUpdateBy(userId)
+ .setUpdateTime(now);
+ aiChatSessionMapper.updateById(update);
+ return buildSessionDto(requireOwnedSession(sessionId, userId, tenantId));
+ }
+
private AiChatSession findLatestSession(Long userId, Long tenantId, String promptCode) {
return aiChatSessionMapper.selectOne(new LambdaQueryWrapper<AiChatSession>()
.eq(AiChatSession::getUserId, userId)
@@ -175,6 +210,23 @@
.eq(AiChatSession::getUserId, userId)
.eq(AiChatSession::getTenantId, tenantId)
.eq(AiChatSession::getPromptCode, promptCode)
+ .eq(AiChatSession::getDeleted, 0)
+ .eq(AiChatSession::getStatus, StatusType.ENABLE.val)
+ .last("limit 1"));
+ if (session == null) {
+ throw new CoolException("AI 浼氳瘽涓嶅瓨鍦ㄦ垨鏃犳潈璁块棶");
+ }
+ return session;
+ }
+
+ private AiChatSession requireOwnedSession(Long sessionId, Long userId, Long tenantId) {
+ if (sessionId == null) {
+ throw new CoolException("AI 浼氳瘽 ID 涓嶈兘涓虹┖");
+ }
+ AiChatSession session = aiChatSessionMapper.selectOne(new LambdaQueryWrapper<AiChatSession>()
+ .eq(AiChatSession::getId, sessionId)
+ .eq(AiChatSession::getUserId, userId)
+ .eq(AiChatSession::getTenantId, tenantId)
.eq(AiChatSession::getDeleted, 0)
.eq(AiChatSession::getStatus, StatusType.ENABLE.val)
.last("limit 1"));
@@ -266,8 +318,57 @@
if (!StringUtils.hasText(titleSeed)) {
throw new CoolException("AI 浼氳瘽鏍囬涓嶈兘涓虹┖");
}
- String title = titleSeed.trim().replace("\r", " ").replace("\n", " ");
- return title.length() > 60 ? title.substring(0, 60) : title;
+ String title = titleSeed.trim()
+ .replace("\r", " ")
+ .replace("\n", " ")
+ .replaceAll("\\s+", " ");
+ int punctuationIndex = findSummaryBreakIndex(title);
+ if (punctuationIndex > 0) {
+ title = title.substring(0, punctuationIndex).trim();
+ }
+ return title.length() > 48 ? title.substring(0, 48) : title;
+ }
+
+ private int findSummaryBreakIndex(String title) {
+ String[] separators = {"銆�", "锛�", "锛�", ".", "!", "?"};
+ int result = -1;
+ for (String separator : separators) {
+ int index = title.indexOf(separator);
+ if (index > 0 && (result < 0 || index < result)) {
+ result = index;
+ }
+ }
+ return result;
+ }
+
+ private AiChatSessionDto buildSessionDto(AiChatSession session) {
+ AiChatMessage lastMessage = aiChatMessageMapper.selectOne(new LambdaQueryWrapper<AiChatMessage>()
+ .eq(AiChatMessage::getSessionId, session.getId())
+ .eq(AiChatMessage::getDeleted, 0)
+ .orderByDesc(AiChatMessage::getSeqNo)
+ .orderByDesc(AiChatMessage::getId)
+ .last("limit 1"));
+ return AiChatSessionDto.builder()
+ .sessionId(session.getId())
+ .title(session.getTitle())
+ .promptCode(session.getPromptCode())
+ .pinned(session.getPinned() != null && session.getPinned() == 1)
+ .lastMessagePreview(buildLastMessagePreview(lastMessage))
+ .lastMessageTime(session.getLastMessageTime())
+ .build();
+ }
+
+ private String buildLastMessagePreview(AiChatMessage message) {
+ if (message == null || !StringUtils.hasText(message.getContent())) {
+ return null;
+ }
+ String preview = message.getContent().trim()
+ .replace("\r", " ")
+ .replace("\n", " ")
+ .replaceAll("\\s+", " ");
+ String prefix = "assistant".equalsIgnoreCase(message.getRole()) ? "AI: " : "浣�: ";
+ String normalized = prefix + preview;
+ return normalized.length() > 80 ? normalized.substring(0, 80) : normalized;
}
private void ensureIdentity(Long userId, Long tenantId) {
--
Gitblit v1.9.1