package com.ruoyi.ai.service.impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.ruoyi.ai.dto.AiChatMessageDto;
|
import com.ruoyi.ai.dto.AiChatSessionDto;
|
import com.ruoyi.ai.mapper.AiChatSessionMapper;
|
import com.ruoyi.ai.pojo.AiChatSession;
|
import com.ruoyi.ai.service.AiChatSessionService;
|
import com.ruoyi.ai.store.MongoChatMemoryStore;
|
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.framework.security.LoginUser;
|
import dev.langchain4j.data.message.AiMessage;
|
import dev.langchain4j.data.message.ChatMessage;
|
import dev.langchain4j.data.message.SystemMessage;
|
import dev.langchain4j.data.message.ToolExecutionResultMessage;
|
import dev.langchain4j.data.message.UserMessage;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
|
import java.util.Date;
|
import java.util.LinkedList;
|
import java.util.List;
|
import java.util.stream.Collectors;
|
|
@Service
|
@RequiredArgsConstructor
|
public class AiChatSessionServiceImpl extends ServiceImpl<AiChatSessionMapper, AiChatSession> implements AiChatSessionService {
|
|
private static final int TITLE_MAX_LENGTH = 40;
|
private static final int LAST_MESSAGE_MAX_LENGTH = 300;
|
|
private final MongoChatMemoryStore mongoChatMemoryStore;
|
|
@Override
|
public void touchSession(String memoryId, LoginUser loginUser, String userMessage) {
|
if (!StringUtils.hasText(memoryId) || loginUser == null || loginUser.getUserId() == null) {
|
return;
|
}
|
Date now = new Date();
|
AiChatSession session = getSession(memoryId, loginUser.getUserId(), loginUser.getTenantId());
|
if (session == null) {
|
AiChatSession add = new AiChatSession();
|
add.setMemoryId(memoryId);
|
add.setUserId(loginUser.getUserId());
|
add.setTenantId(loginUser.getTenantId());
|
add.setTitle(buildTitle(userMessage));
|
add.setLastMessage(trimText(userMessage, LAST_MESSAGE_MAX_LENGTH));
|
add.setMessageCount(0);
|
add.setLastChatTime(now);
|
add.setCreateTime(now);
|
add.setUpdateTime(now);
|
save(add);
|
return;
|
}
|
|
AiChatSession update = new AiChatSession();
|
update.setId(session.getId());
|
if (!StringUtils.hasText(session.getTitle())) {
|
update.setTitle(buildTitle(userMessage));
|
}
|
update.setLastMessage(trimText(userMessage, LAST_MESSAGE_MAX_LENGTH));
|
update.setLastChatTime(now);
|
update.setUpdateTime(now);
|
updateById(update);
|
}
|
|
@Override
|
public void refreshSessionStats(String memoryId, LoginUser loginUser) {
|
if (!StringUtils.hasText(memoryId) || loginUser == null || loginUser.getUserId() == null) {
|
return;
|
}
|
AiChatSession session = getSession(memoryId, loginUser.getUserId(), loginUser.getTenantId());
|
if (session == null) {
|
return;
|
}
|
List<ChatMessage> messages = mongoChatMemoryStore.getMessages(memoryId);
|
AiChatSession update = new AiChatSession();
|
update.setId(session.getId());
|
update.setMessageCount(messages.size());
|
update.setLastMessage(trimText(lastMessageText(messages), LAST_MESSAGE_MAX_LENGTH));
|
update.setLastChatTime(new Date());
|
update.setUpdateTime(new Date());
|
updateById(update);
|
}
|
|
@Override
|
public List<AiChatSessionDto> listCurrentUserSessions(LoginUser loginUser) {
|
if (loginUser == null || loginUser.getUserId() == null) {
|
return new LinkedList<>();
|
}
|
LambdaQueryWrapper<AiChatSession> queryWrapper = new LambdaQueryWrapper<AiChatSession>()
|
.eq(AiChatSession::getUserId, loginUser.getUserId())
|
.orderByDesc(AiChatSession::getLastChatTime);
|
applyTenantCondition(queryWrapper, loginUser.getTenantId());
|
return list(queryWrapper).stream().map(item -> {
|
AiChatSessionDto dto = new AiChatSessionDto();
|
dto.setMemoryId(item.getMemoryId());
|
dto.setTitle(item.getTitle());
|
dto.setLastMessage(item.getLastMessage());
|
dto.setMessageCount(item.getMessageCount());
|
dto.setLastChatTime(item.getLastChatTime());
|
return dto;
|
}).collect(Collectors.toList());
|
}
|
|
@Override
|
public List<AiChatMessageDto> listCurrentUserMessages(String memoryId, LoginUser loginUser) {
|
if (!StringUtils.hasText(memoryId) || loginUser == null || loginUser.getUserId() == null) {
|
return new LinkedList<>();
|
}
|
AiChatSession session = getSession(memoryId, loginUser.getUserId(), loginUser.getTenantId());
|
if (session == null) {
|
return new LinkedList<>();
|
}
|
List<ChatMessage> messages = mongoChatMemoryStore.getMessages(memoryId);
|
return messages.stream().map(this::convertMessage).collect(Collectors.toList());
|
}
|
|
@Override
|
public boolean deleteCurrentUserSession(String memoryId, LoginUser loginUser) {
|
if (!StringUtils.hasText(memoryId) || loginUser == null || loginUser.getUserId() == null) {
|
return false;
|
}
|
LambdaQueryWrapper<AiChatSession> queryWrapper = new LambdaQueryWrapper<AiChatSession>()
|
.eq(AiChatSession::getMemoryId, memoryId)
|
.eq(AiChatSession::getUserId, loginUser.getUserId());
|
applyTenantCondition(queryWrapper, loginUser.getTenantId());
|
boolean removed = remove(queryWrapper);
|
mongoChatMemoryStore.deleteMessages(memoryId);
|
return removed;
|
}
|
|
private AiChatSession getSession(String memoryId, Long userId, Long tenantId) {
|
LambdaQueryWrapper<AiChatSession> queryWrapper = new LambdaQueryWrapper<AiChatSession>()
|
.eq(AiChatSession::getMemoryId, memoryId)
|
.eq(AiChatSession::getUserId, userId);
|
applyTenantCondition(queryWrapper, tenantId);
|
return getOne(queryWrapper, false);
|
}
|
|
private void applyTenantCondition(LambdaQueryWrapper<AiChatSession> queryWrapper, Long tenantId) {
|
if (tenantId == null) {
|
queryWrapper.isNull(AiChatSession::getTenantId);
|
return;
|
}
|
queryWrapper.eq(AiChatSession::getTenantId, tenantId);
|
}
|
|
private String buildTitle(String userMessage) {
|
if (!StringUtils.hasText(userMessage)) {
|
return "新会话";
|
}
|
return trimText(userMessage, TITLE_MAX_LENGTH);
|
}
|
|
private String trimText(String text, int maxLength) {
|
if (!StringUtils.hasText(text)) {
|
return "";
|
}
|
String source = text.trim();
|
if (source.length() <= maxLength) {
|
return source;
|
}
|
return source.substring(0, maxLength) + "...";
|
}
|
|
private String lastMessageText(List<ChatMessage> messages) {
|
if (messages == null || messages.isEmpty()) {
|
return "";
|
}
|
ChatMessage lastMessage = messages.get(messages.size() - 1);
|
return convertMessage(lastMessage).getContent();
|
}
|
|
private AiChatMessageDto convertMessage(ChatMessage message) {
|
if (message instanceof UserMessage userMessage) {
|
return new AiChatMessageDto("user", userMessage.singleText());
|
}
|
if (message instanceof AiMessage aiMessage) {
|
return new AiChatMessageDto("assistant", aiMessage.text());
|
}
|
if (message instanceof SystemMessage systemMessage) {
|
return new AiChatMessageDto("system", systemMessage.text());
|
}
|
if (message instanceof ToolExecutionResultMessage toolExecutionResultMessage) {
|
return new AiChatMessageDto("tool", toolExecutionResultMessage.text());
|
}
|
return new AiChatMessageDto("unknown", String.valueOf(message));
|
}
|
}
|