/** * AI 聊天助手(plan.md「8.1 AI 聊天助手」)。 * * 参考 BeeCount 的 AIChatService(GLM-4): * - 意图判定:是否为记账意图(金额关键词检测) * - 记账模式 → processNaturalLanguage 返回草稿 * - 自由对话 → AI 自由回答 * * 复用 domain/ai.ts 的 processNaturalLanguage + buildNaturalLanguagePrompt。 */ import { CHAT_TRANSACTION_KEYWORDS } from '../domain/constants'; import { processNaturalLanguage, removeThink, type AiProvider, type AiBillResult } from '../domain/ai'; export interface ChatMessage { role: 'user' | 'assistant'; content: string; } export interface ChatConversation { id: string; messages: ChatMessage[]; createdAt: string; } export interface ChatResponse { type: 'bill_card' | 'text' | 'error'; text?: string; billCards?: AiBillResult[]; error?: string; } const AMOUNT_PATTERN = /\d+(?:\.\d+)?/; /** 判断是否为记账意图(金额 + 关键词)。 */ export function isTransactionIntent(input: string): boolean { const hasAmount = AMOUNT_PATTERN.test(input); const hasKeyword = CHAT_TRANSACTION_KEYWORDS.some(kw => input.includes(kw)); return hasAmount && hasKeyword; } /** * 处理用户消息:判定意图 → 记账或自由对话。 */ export async function processChatMessage( input: string, provider: AiProvider, conversation?: ChatConversation, ): Promise { try { // 意图判定 if (isTransactionIntent(input)) { const result = await processNaturalLanguage(input, provider); if (result.type === 'draft') { return { type: 'bill_card', billCards: [result.draft] }; } // 非 draft 但有意图 → 返回 AI 文本 return { type: 'text', text: result.text }; } // 自由对话 const messages = buildChatContext(input, conversation); const response = await provider.chat(messages); return { type: 'text', text: removeThink(response) }; } catch (e) { return { type: 'error', error: e instanceof Error ? e.message : String(e) }; } } /** 构建对话上下文(含历史消息)。 */ function buildChatContext(input: string, conversation?: ChatConversation) { const systemPrompt = { role: 'system' as const, content: '你是一个记账助手。用户描述消费/收入时,帮助解析为交易。其他问题正常回答。回答简洁。', }; const history = (conversation?.messages ?? []).slice(-10).map(m => ({ role: m.role === 'user' ? 'user' as const : 'assistant' as const, content: m.content, })); return [systemPrompt, ...history, { role: 'user' as const, content: input }]; } /** 创建新对话。 */ export function createConversation(): ChatConversation { return { id: `chat-${Date.now()}`, messages: [], createdAt: new Date().toISOString(), }; } /** 添加消息到对话。 */ export function appendMessage(conversation: ChatConversation, message: ChatMessage): ChatConversation { return { ...conversation, messages: [...conversation.messages, message], }; }