llm-chat/backend/services/ConversationService.js

351 lines
9.6 KiB
JavaScript
Raw Normal View History

const Conversation = require('../models/Conversation');
const Message = require('../models/Message');
const cacheManager = require('../utils/cache');
class ConversationService {
constructor() {
this.cachePrefix = 'conv_service';
}
/**
* 创建新对话
*/
async createConversation(title = '新对话') {
try {
const conversation = await Conversation.create(title);
// 清除对话列表缓存
this.clearConversationListCache();
console.log('创建新对话:', conversation.id);
return conversation;
} catch (error) {
console.error('ConversationService.createConversation错误:', error);
throw new Error('创建对话失败');
}
}
/**
* 获取对话列表
*/
async getConversations(limit = 50) {
try {
const cacheKey = `${this.cachePrefix}:list:${limit}`;
// 尝试从缓存获取
let conversations = cacheManager.get(cacheKey);
if (conversations) {
console.log('从缓存获取对话列表');
return conversations;
}
// 从数据库获取
conversations = await Conversation.findAll(limit);
// 缓存结果5分钟
cacheManager.set(cacheKey, conversations, { ttl: 300000 });
console.log(`获取对话列表: ${conversations.length}`);
return conversations;
} catch (error) {
console.error('ConversationService.getConversations错误:', error);
throw new Error('获取对话列表失败');
}
}
/**
* 根据ID获取对话详情
*/
async getConversationById(id) {
try {
if (!id || isNaN(id)) {
throw new Error('无效的对话ID');
}
const cacheKey = `${this.cachePrefix}:detail:${id}`;
// 尝试从缓存获取
let conversation = cacheManager.get(cacheKey);
if (conversation) {
console.log(`从缓存获取对话详情: ${id}`);
return conversation;
}
// 从数据库获取
conversation = await Conversation.findById(id);
if (!conversation) {
throw new Error('对话不存在');
}
// 缓存结果10分钟
cacheManager.set(cacheKey, conversation, { ttl: 600000 });
console.log(`获取对话详情: ${id}`);
return conversation;
} catch (error) {
console.error('ConversationService.getConversationById错误:', error);
throw error;
}
}
/**
* 获取对话的消息列表
*/
async getConversationMessages(conversationId, limit = 100, offset = 0) {
try {
if (!conversationId || isNaN(conversationId)) {
throw new Error('无效的对话ID');
}
// 确保对话存在
const conversation = await this.getConversationById(conversationId);
if (!conversation) {
throw new Error('对话不存在');
}
const cacheKey = `${this.cachePrefix}:messages:${conversationId}:${limit}:${offset}`;
// 尝试从缓存获取
let messages = cacheManager.get(cacheKey);
if (messages) {
console.log(`从缓存获取对话消息: ${conversationId}`);
return messages;
}
// 从数据库获取
messages = await Message.findByConversationId(conversationId, limit, offset);
// 缓存结果5分钟
cacheManager.set(cacheKey, messages, { ttl: 300000 });
console.log(`获取对话消息: ${conversationId}, ${messages.length}`);
return messages;
} catch (error) {
console.error('ConversationService.getConversationMessages错误:', error);
throw error;
}
}
/**
* 更新对话标题
*/
async updateConversationTitle(id, title) {
try {
if (!id || isNaN(id)) {
throw new Error('无效的对话ID');
}
if (!title || title.trim().length === 0) {
throw new Error('标题不能为空');
}
const conversation = await Conversation.updateTitle(id, title.trim());
// 清除相关缓存
this.clearConversationCache(id);
this.clearConversationListCache();
console.log(`更新对话标题: ${id} -> ${title}`);
return conversation;
} catch (error) {
console.error('ConversationService.updateConversationTitle错误:', error);
throw error;
}
}
/**
* 删除对话
*/
async deleteConversation(id) {
try {
if (!id || isNaN(id)) {
throw new Error('无效的对话ID');
}
// 确保对话存在
const conversation = await this.getConversationById(id);
if (!conversation) {
throw new Error('对话不存在');
}
await Conversation.delete(id);
// 清除相关缓存
this.clearConversationCache(id);
this.clearConversationListCache();
cacheManager.deleteConversationContext(id);
console.log(`删除对话: ${id}`);
return true;
} catch (error) {
console.error('ConversationService.deleteConversation错误:', error);
throw error;
}
}
/**
* 批量删除对话
*/
async deleteMultipleConversations(ids) {
try {
if (!Array.isArray(ids) || ids.length === 0) {
throw new Error('无效的对话ID列表');
}
// 验证所有ID
const validIds = ids.filter(id => id && !isNaN(id));
if (validIds.length === 0) {
throw new Error('没有有效的对话ID');
}
const deletedCount = await Conversation.deleteMultiple(validIds);
// 清除相关缓存
validIds.forEach(id => {
this.clearConversationCache(id);
cacheManager.deleteConversationContext(id);
});
this.clearConversationListCache();
console.log(`批量删除对话: ${deletedCount}`);
return deletedCount;
} catch (error) {
console.error('ConversationService.deleteMultipleConversations错误:', error);
throw error;
}
}
/**
* 获取对话统计信息
*/
async getConversationStats(conversationId) {
try {
if (!conversationId || isNaN(conversationId)) {
throw new Error('无效的对话ID');
}
const conversation = await this.getConversationById(conversationId);
if (!conversation) {
throw new Error('对话不存在');
}
const messageCount = await Message.getMessageCount(conversationId);
return {
id: conversation.id,
title: conversation.title,
created_at: conversation.created_at,
updated_at: conversation.updated_at,
message_count: messageCount
};
} catch (error) {
console.error('ConversationService.getConversationStats错误:', error);
throw error;
}
}
/**
* 搜索对话
*/
async searchConversations(query, limit = 20) {
try {
if (!query || query.trim().length === 0) {
throw new Error('搜索关键词不能为空');
}
// 搜索消息内容
const messages = await Message.search(query.trim(), null, limit);
// 提取关联的对话ID
const conversationIds = [...new Set(messages.map(msg => msg.conversation_id))];
// 获取对话详情
const conversations = await Promise.all(
conversationIds.map(id => this.getConversationById(id))
);
// 过滤掉不存在的对话
const validConversations = conversations.filter(conv => conv !== null);
console.log(`搜索对话: "${query}" -> ${validConversations.length}条结果`);
return validConversations;
} catch (error) {
console.error('ConversationService.searchConversations错误:', error);
throw error;
}
}
/**
* 自动生成对话标题基于第一条用户消息
*/
async generateConversationTitle(conversationId) {
try {
const messages = await Message.findByConversationId(conversationId, 5);
// 找到第一条用户消息
const firstUserMessage = messages.find(msg => msg.role === 'user');
if (!firstUserMessage) {
return '新对话';
}
// 从第一条用户消息生成标题取前20个字符
let title = firstUserMessage.content.trim();
if (title.length > 20) {
title = title.substring(0, 20) + '...';
}
// 更新对话标题
await this.updateConversationTitle(conversationId, title);
console.log(`自动生成对话标题: ${conversationId} -> ${title}`);
return title;
} catch (error) {
console.error('ConversationService.generateConversationTitle错误:', error);
return '新对话';
}
}
/**
* 清除对话详情缓存
*/
clearConversationCache(conversationId) {
const detailKey = `${this.cachePrefix}:detail:${conversationId}`;
cacheManager.delete(detailKey);
// 清除消息缓存(可能有多个分页)
for (let i = 0; i < 10; i++) {
const messageKey = `${this.cachePrefix}:messages:${conversationId}:100:${i * 100}`;
cacheManager.delete(messageKey);
}
}
/**
* 清除对话列表缓存
*/
clearConversationListCache() {
// 清除不同分页的列表缓存
for (let limit = 10; limit <= 100; limit += 10) {
const listKey = `${this.cachePrefix}:list:${limit}`;
cacheManager.delete(listKey);
}
}
/**
* 更新对话活动时间
*/
async updateLastActivity(conversationId) {
try {
await Conversation.updateLastActivity(conversationId);
// 清除相关缓存
this.clearConversationCache(conversationId);
this.clearConversationListCache();
} catch (error) {
console.error('ConversationService.updateLastActivity错误:', error);
// 这是一个辅助操作,失败不应该影响主流程
}
}
}
module.exports = ConversationService;