refactor: repartition server-side and client-side code

This commit is contained in:
LIlGG
2025-10-11 18:26:07 +08:00
parent 7acc4949fb
commit e9b573a276
309 changed files with 631 additions and 962 deletions

329
app/.server/service/chat.ts Normal file
View File

@@ -0,0 +1,329 @@
import { prisma } from '~/.server/service/prisma';
import { createScopedLogger } from '~/utils/logger';
const logger = createScopedLogger('chat.server');
/**
* 聊天创建参数接口
*/
export interface ChatCreateParams {
userId: string;
id?: string;
// 聊天URL ID
urlId?: string;
// 聊天描述
description?: string;
// 包含额外信息的元数据
metadata?: Record<string, any>;
}
/**
* 聊天更新参数接口
*/
export interface ChatUpdateParams {
description?: string;
metadata?: Record<string, any>;
}
/**
* 聊天创建或更新参数接口
*/
export interface ChatUpsertParams {
id: string;
userId: string;
urlId?: string;
description?: string;
metadata?: Record<string, any>;
}
/**
* 创建新的聊天
* @param params 聊天创建参数
* @returns 创建的聊天记录
*/
export async function createChat(params: ChatCreateParams) {
const { userId, id, urlId, description, metadata } = params;
try {
const chat = await prisma.chat.create({
data: {
...(id ? { id } : {}),
userId,
urlId,
description,
metadata,
},
});
logger.info(`[Chat] 创建了用户 ${userId} 的聊天: ${chat.id}`);
return chat;
} catch (error) {
logger.error('[Chat] 创建聊天失败:', error);
throw error;
}
}
/**
* 根据ID获取聊天
* @param id 聊天ID
* @returns 聊天记录
*/
export async function getChatById(id: string) {
try {
const chat = await prisma.chat.findUnique({
where: { id },
include: {
messages: {
where: {
isDiscarded: false,
},
orderBy: {
createdAt: 'asc',
},
include: {
sections: true,
page: true,
},
},
},
});
return chat;
} catch (error) {
logger.error(`[Chat] 获取聊天 ${id} 失败:`, error);
throw error;
}
}
/**
* 根据 URL ID 获取聊天
* @param urlId 聊天的 URL ID
* @returns 聊天记录
*/
export async function getChatByUrlId(urlId: string) {
try {
const chat = await prisma.chat.findUnique({
where: { urlId },
include: {
messages: {
where: {
isDiscarded: false,
},
orderBy: {
createdAt: 'asc',
},
},
},
});
return chat;
} catch (error) {
logger.error(`[Chat] 获取聊天 URL ${urlId} 失败:`, error);
throw error;
}
}
/**
* 获取用户的所有聊天
* @param userId 用户ID
* @param limit 限制返回记录数量
* @param offset 偏移量
* @returns 聊天记录列表
*/
export async function getUserChats(userId: string, limit = 20, offset = 0) {
try {
const chats = await prisma.chat.findMany({
where: { userId },
include: {
messages: {
where: {
isDiscarded: false,
},
take: 1,
orderBy: {
createdAt: 'asc',
},
},
},
orderBy: {
updatedAt: 'desc',
},
skip: offset,
take: limit,
});
const total = await prisma.chat.count({
where: { userId },
});
return {
chats,
total,
};
} catch (error) {
logger.error(`[Chat] 获取用户 ${userId} 的聊天列表失败:`, error);
throw error;
}
}
/**
* 更新聊天信息
* @param id 聊天ID
* @param params 更新参数
* @returns 更新后的聊天记录
*/
export async function updateChat(id: string, params: ChatUpdateParams) {
try {
const updatedChat = await prisma.chat.update({
where: { id },
data: {
...params,
version: {
increment: 1,
},
},
});
logger.info(`[Chat] 更新了聊天 ${id}`);
return updatedChat;
} catch (error) {
logger.error(`[Chat] 更新聊天 ${id} 失败:`, error);
throw error;
}
}
/**
* 删除聊天
* @param id 聊天ID
* @returns 删除结果
*
* 注意:由于在 Prisma Schema 中配置了级联删除关系:
*
* 1. 删除 Chat 会自动级联删除所有关联的 Message 记录
* 2. 删除 Message 会自动级联删除关联的 Section 记录
*/
export async function deleteChat(id: string) {
try {
const chatToDelete = await prisma.chat.findUnique({
where: { id },
include: {
_count: {
select: {
messages: true,
},
},
},
});
if (!chatToDelete) {
logger.info(`[Chat] 未找到ID为 ${id} 的聊天,无法删除`);
return false;
}
await prisma.chat.delete({
where: { id },
});
logger.info(`[Chat] 删除了聊天 ${id},级联删除了 ${chatToDelete._count.messages} 条关联消息及其项目数据`);
return true;
} catch (error) {
logger.error(`[Chat] 删除聊天 ${id} 失败:`, error);
throw error;
}
}
/**
* 获取或创建指定ID的聊天
* @param chatId 指定的聊天ID
* @param params 创建聊天所需的参数
* @returns 聊天记录
*/
export async function getOrCreateChat(chatId: string, params: Omit<ChatCreateParams, 'id'>) {
try {
// 尝试查找现有聊天
const existingChat = await getChatById(chatId);
if (existingChat) {
logger.info(`[Chat] 找到现有聊天: ${chatId}`);
return existingChat;
}
// 聊天不存在创建新聊天使用指定的ID
const newChat = await createChat({
...params,
id: chatId,
});
logger.info(`[Chat] 聊天不存在,创建新聊天: ${newChat.id}`);
return newChat;
} catch (error) {
logger.error(`[Chat] 获取或创建聊天失败:`, error);
throw error;
}
}
/**
* 根据 ID 获取当前用户的聊天
* @param id 聊天ID
* @returns 聊天记录
*/
export async function getUserChatById(id: string, userId: string) {
try {
const chat = await prisma.chat.findUnique({
where: { id, userId },
include: {
messages: {
where: {
isDiscarded: false,
},
orderBy: {
createdAt: 'asc',
},
include: {
sections: true,
page: true,
},
},
},
});
return chat;
} catch (error) {
logger.error(`[Chat] 获取聊天 ${id} 失败:`, error);
throw error;
}
}
/**
* 根据ID创建或更新聊天upsert操作
* @param params 聊天创建或更新参数
* @returns 创建或更新后的聊天记录
*/
export async function upsertChat(params: ChatUpsertParams) {
const { id, userId, urlId, description, metadata } = params;
try {
const chat = await prisma.chat.upsert({
where: { id },
update: {
version: {
increment: 1,
},
description,
metadata,
},
create: {
id,
userId,
urlId,
description,
metadata,
},
});
logger.info(`[Chat] 创建或更新了聊天 ${id}`);
return chat;
} catch (error) {
logger.error(`[Chat] 创建或更新聊天 ${id} 失败:`, error);
throw error;
}
}