update at 2025-10-16 12:45:05

This commit is contained in:
douboer
2025-10-16 12:45:05 +08:00
parent 4e670ad5f6
commit 298b5aa931
18 changed files with 3311 additions and 1176 deletions

View File

@@ -0,0 +1,251 @@
/**
* MessageService
* 负责消息的 CRUD 操作
*
* 职责:
* - 消息的创建、读取、更新、删除
* - 消息状态管理
* - 消息查询和过滤
*/
import type { Message, Conversation } from '../../types/chat'
import type { CreateMessageOptions, UpdateMessageOptions, MessageQueryResult } from './types'
export class MessageService {
private conversations: Map<string, Conversation>
constructor(conversations: Map<string, Conversation>) {
this.conversations = conversations
}
/**
* 在指定对话中创建新消息
*/
createMessage(conversationId: string, options: CreateMessageOptions): Message {
const conversation = this.conversations.get(conversationId)
if (!conversation) {
throw new Error(`Conversation not found: ${conversationId}`)
}
const message: Message = {
id: this.generateId(),
role: options.role,
content: options.content,
status: options.status || 'success',
timestamp: new Date(),
model: options.model,
tokens: options.tokens
}
conversation.messages.push(message)
conversation.updatedAt = new Date()
return message
}
/**
* 获取指定对话的所有消息
*/
getMessages(conversationId: string): Message[] {
const conversation = this.conversations.get(conversationId)
return conversation?.messages || []
}
/**
* 根据 topicId 获取消息
*/
getMessagesByTopicId(topicId: string): Message[] {
for (const conv of this.conversations.values()) {
if (conv.topicId === topicId) {
return conv.messages
}
}
return []
}
/**
* 获取指定消息
*/
getMessage(conversationId: string, messageId: string): Message | undefined {
const conversation = this.conversations.get(conversationId)
if (!conversation) return undefined
return conversation.messages.find(m => m.id === messageId)
}
/**
* 查找消息及其位置信息
*/
findMessage(messageId: string, topicId?: string): MessageQueryResult {
for (const conv of this.conversations.values()) {
if (topicId && conv.topicId !== topicId) continue
const index = conv.messages.findIndex(m => m.id === messageId)
if (index !== -1) {
return {
message: conv.messages[index],
conversation: conv,
index
}
}
}
return {
message: undefined,
conversation: undefined,
index: -1
}
}
/**
* 更新消息
*/
updateMessage(
conversationId: string,
messageId: string,
options: UpdateMessageOptions
): boolean {
const conversation = this.conversations.get(conversationId)
if (!conversation) return false
const message = conversation.messages.find(m => m.id === messageId)
if (!message) return false
// 更新消息字段
if (options.content !== undefined) {
message.content = options.content
}
if (options.status !== undefined) {
message.status = options.status
}
if (options.tokens !== undefined) {
message.tokens = options.tokens
}
conversation.updatedAt = new Date()
return true
}
/**
* 更新消息状态
*/
updateMessageStatus(
conversationId: string,
messageId: string,
status: 'sending' | 'success' | 'error' | 'paused'
): boolean {
return this.updateMessage(conversationId, messageId, { status })
}
/**
* 追加消息内容(用于流式响应)
*/
appendMessageContent(
conversationId: string,
messageId: string,
content: string
): boolean {
const conversation = this.conversations.get(conversationId)
if (!conversation) return false
const message = conversation.messages.find(m => m.id === messageId)
if (!message) return false
message.content += content
conversation.updatedAt = new Date()
return true
}
/**
* 删除消息
*/
deleteMessage(conversationId: string, messageId: string): boolean {
const conversation = this.conversations.get(conversationId)
if (!conversation) return false
const index = conversation.messages.findIndex(m => m.id === messageId)
if (index === -1) return false
conversation.messages.splice(index, 1)
conversation.updatedAt = new Date()
return true
}
/**
* 删除指定消息之后的所有消息(包括该消息)
*/
deleteMessagesAfter(conversationId: string, messageId: string): boolean {
const conversation = this.conversations.get(conversationId)
if (!conversation) return false
const index = conversation.messages.findIndex(m => m.id === messageId)
if (index === -1) return false
conversation.messages.splice(index)
conversation.updatedAt = new Date()
return true
}
/**
* 获取对话中最后一条用户消息
*/
getLastUserMessage(conversationId: string): Message | undefined {
const conversation = this.conversations.get(conversationId)
if (!conversation) return undefined
for (let i = conversation.messages.length - 1; i >= 0; i--) {
if (conversation.messages[i].role === 'user') {
return conversation.messages[i]
}
}
return undefined
}
/**
* 获取对话中最后一条消息
*/
getLastMessage(conversationId: string): Message | undefined {
const conversation = this.conversations.get(conversationId)
if (!conversation) return undefined
const messages = conversation.messages
return messages.length > 0 ? messages[messages.length - 1] : undefined
}
/**
* 获取消息预览文本
*/
getMessagePreview(content: string, maxLength = 50): string {
if (!content) return ''
const text = content.replace(/\n/g, ' ').trim()
return text.length > maxLength ? text.slice(0, maxLength) + '...' : text
}
/**
* 获取对话中成功的消息(用于发送给 LLM
*/
getSuccessMessages(conversationId: string): Message[] {
const conversation = this.conversations.get(conversationId)
if (!conversation) return []
return conversation.messages.filter(m =>
m.status === 'success' || m.status === 'paused'
)
}
/**
* 获取最近的 N 条成功消息
*/
getRecentSuccessMessages(conversationId: string, limit: number): Message[] {
const successMessages = this.getSuccessMessages(conversationId)
return successMessages.slice(-limit)
}
/**
* 生成唯一 ID
*/
private generateId(): string {
return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
}
}