import { defineStore } from 'pinia' import { sendMessage } from '@/api/chat' const chatModes = { training: { name: '寿险代理人AI陪练', icon: 'fas fa-user-tie', token: 'app-88ae2GN49aUyNO6qGg7tbTfX' }, quote_objection: { name: '报价中异议', icon: 'fas fa-comments', token: 'app-88ae2GN49aUyNO6qGg7tbTfX' }, post_quote_objection: { name: '报价后异议', icon: 'fas fa-comment-dollar', token: 'app-88ae2GN49aUyNO6qGg7tbTfX' } } // 返回示例 /* data: {"event": "message", "conversation_id": "fac9e3e7-2b2e-4fc2-bf19-0a6d4cfcf529", "message_id": "e8f42230-205c-4f31-b068-86b37a18c2ee", "created_at": 1744881805, "task_id": "ec521a05-6068-427a-ac5d-d349f0d05874", "id": "e8f42230-205c-4f31-b068-86b37a18c2ee", "answer": "\u7684\u65b9\u5411", "from_variable_selector": ["17441814078920", "text"]} data: {"event": "message", "conversation_id": "fac9e3e7-2b2e-4fc2-bf19-0a6d4cfcf529", "message_id": "e8f42230-205c-4f31-b068-86b37a18c2ee", "created_at": 1744881805, "task_id": "ec521a05-6068-427a-ac5d-d349f0d05874", "id": "e8f42230-205c-4f31-b068-86b37a18c2ee", "answer": "\u3002", "from_variable_selector": ["17441814078920", "text"]} data: {"event": "message_end", "conversation_id": "fac9e3e7-2b2e-4fc2-bf19-0a6d4cfcf529", "message_id": "e8f42230-205c-4f31-b068-86b37a18c2ee", "created_at": 1744881805, "task_id": "ec521a05-6068-427a-ac5d-d349f0d05874", "id": "e8f42230-205c-4f31-b068-86b37a18c2ee", "metadata": {"usage": {"prompt_tokens": 2483, "prompt_unit_price": "4.13", "prompt_price_unit": "0.000001", "prompt_price": "0.0102548", "completion_tokens": 142, "completion_unit_price": "4.13", "completion_price_unit": "0.000001", "completion_price": "0.0005865", "total_tokens": 2625, "total_price": "0.0108413", "currency": "RMB", "latency": 13.045417829882354}}, "files": []} */ const tagList = ['kehu', 'pingfen', 'zongjie', 'dafen'] // 处理标签内容的辅助函数 const processTagContent = (answerCache, tagName, cachedMessage) => { // 检查是否包含完整的开始标签 const startTag = `<${tagName}>` const endTag = `` // 如果正在处理该标签 if (cachedMessage.respondingType === tagName) { // 检查是否包含结束标签 if (answerCache.includes(endTag)) { // 提取结束标签前的内容 const content = answerCache.split(endTag)[0] cachedMessage[tagName] += content cachedMessage.respondingType = '' return answerCache.split(endTag)[1] || '' } else { // 继续累积内容 cachedMessage[tagName] += answerCache return '' } } // 检查是否包含开始标签 if (answerCache.includes(startTag)) { cachedMessage.respondingType = tagName const tagContent = answerCache.split(startTag)[1] || '' // 检查开始标签后是否立即包含结束标签 if (tagContent.includes(endTag)) { const content = tagContent.split(endTag)[0] cachedMessage[tagName] = content cachedMessage.respondingType = '' return answerCache.split(endTag)[1] || '' } else { // 只有开始标签,累积内容 cachedMessage[tagName] = tagContent return '' } } return answerCache } export const useChatStore = defineStore('chat', { state: () => ({ messages: {}, currentMode: 'training', conversationId: null, messageCache: {}, }), getters: { chatModes: () => chatModes, currentToken: (state) => chatModes[state.currentMode].token, currentConversation: (state) => { return state.conversationId ? state.messages[state.conversationId] : null }, currentMessages: (state) => { // 根据conversationId和currentMode找到对应的messageCache的messageId const cache = Object.values(state.messageCache).find(message => message.mode === state.currentMode && message.conversationId === state.conversationId ) // 获取当前会话的消息 const currentConversation = state.conversationId ? state.messages[state.conversationId] : null const conversationMessages = currentConversation ? currentConversation.chatMessages : [] return conversationMessages.filter(message => message.mode === state.currentMode && (message.conversationId === state.conversationId || !state.conversationId) && (!cache || message.messageId !== cache.messageId) ).concat(cache ? [cache] : []) }, // 获取所有会话列表 conversations: (state) => { return Object.entries(state.messages).map(([conversationId, conversation]) => ({ conversationId, mode: conversation.chatModes, messages: conversation.chatMessages, status: conversation.conversationStatus, summary: conversation.summary, // 使用第一条消息的时间作为会话创建时间 createdAt: conversation.chatMessages[0]?.createdAt || 0 })).sort((a, b) => b.createdAt - a.createdAt) // 按时间倒序排序 } }, actions: { setCurrentMode(mode) { this.currentMode = mode // 找到当前模式的最后一条会话 const lastConversation = this.conversations .filter(conv => conv.mode === mode) .sort((a, b) => b.createdAt - a.createdAt)[0] // 设置当前会话ID this.conversationId = lastConversation?.conversationId || null console.log('%c currentConversation:', 'color: #2196F3; font-weight: bold', { mode, lastConversation, currentConversation: this.currentConversation }) }, // 切换到指定会话 switchConversation(conversationId) { if (this.messages[conversationId]) { this.conversationId = conversationId // 清除当前的消息缓存 Object.keys(this.messageCache).forEach(messageId => { if (this.messageCache[messageId].conversationId === conversationId) { delete this.messageCache[messageId] } }) } }, async sendMessage(question) { if (!question.trim()) return // 设置会话状态为正在输入 if (this.conversationId && this.messages[this.conversationId]) { this.messages[this.conversationId].conversationStatus = 'typing' } this.hasStartedResponse = false try { const messageStream = await sendMessage({ inputs: {}, query: question, response_mode: 'streaming', conversation_id: this.conversationId, user: 'sys123' }, this.currentToken) let answerCache = '' for await (const message of messageStream) { if (!message || !message.event) { continue } switch (message.event) { case 'workflow_started': console.log('%c workflow_started:message:', 'color: #2196F3; font-weight: bold', message) // 创建新消息对象 const currentMessage = { mode: this.currentMode, conversationId: message.conversation_id, messageId: message.message_id, createdAt: message.created_at, question: question, answerBuffer: '', showEvaluation: true, respondingType: '', kehu: '', pingfen: '', zongjie: '', dafen: '', } this.conversationId = message.conversation_id this.messageCache[message.message_id] = currentMessage // 初始化会话消息结构 if (!this.messages[currentMessage.conversationId]) { this.messages[currentMessage.conversationId] = { chatModes: currentMessage.mode, chatMessages: [], conversationStatus: 'typing', // 会话状态 active 活跃,finished 已完成, typing 正在输入 //总结 summary: '', } } break case 'message': if (message.answer) { console.log('%c message:answer:', 'color: #2196F3; font-weight: bold', message.answer) answerCache += message.answer const cachedMessage = this.messageCache[message.message_id] if (cachedMessage) { // 依次处理每个标签 for (const tag of tagList) { answerCache = processTagContent(answerCache, tag, cachedMessage) } } } break case 'workflow_finished': console.log('%c workflow_finished:message:', 'color: #2196F3; font-weight: bold', message) if (this.messageCache[message.message_id]) { const cachedMessage = this.messageCache[message.message_id] if (cachedMessage) { cachedMessage.respondingType = '' cachedMessage.answerBuffer = message.data.outputs.answer this.messages[cachedMessage.conversationId].chatMessages.push(cachedMessage) // 如果包含dafen标签,将会话标记为完成并将打分内容归档到summary if (cachedMessage.dafen) { this.messages[cachedMessage.conversationId].conversationStatus = 'finished' this.messages[cachedMessage.conversationId].summary = cachedMessage.dafen } else { // 恢复会话状态为活跃 this.messages[cachedMessage.conversationId].conversationStatus = 'active' } console.log('%c workflow_finished:cachedMessage:', 'color: #ff0000; font-weight: bold', cachedMessage) } delete this.messageCache[message.message_id] } break } } } catch (error) { console.error('发送消息失败:', error) throw error } }, toggleEvaluation(messageId) { console.log('%c toggleEvaluation:messageId:', 'color: #2196F3; font-weight: bold', messageId) const cache = Object.values(this.messageCache).find(message => message.mode === this.currentMode && message.messageId === messageId ) if (cache) { cache.showEvaluation = !cache.showEvaluation } else { // 遍历所有会话查找消息 for (const conversationId in this.messages) { const conversation = this.messages[conversationId] const message = conversation.chatMessages.find(msg => msg.messageId === messageId) if (message) { message.showEvaluation = !message.showEvaluation break } } } }, startNewChat() { // 如果当前有活跃会话,将其标记为完成 if (this.conversationId && this.messages[this.conversationId]) { this.messages[this.conversationId].conversationStatus = 'finished' } // 只清除当前会话相关的消息缓存 if (this.conversationId) { // 从messageCache中删除当前会话的消息 Object.keys(this.messageCache).forEach(messageId => { if (this.messageCache[messageId].conversationId === this.conversationId) { delete this.messageCache[messageId] } }) } // 清除当前会话ID this.conversationId = null }, // 删除指定会话 deleteConversation(conversationId) { // 如果要删除的是当前会话,先清除相关缓存 if (this.conversationId === conversationId) { Object.keys(this.messageCache).forEach(messageId => { if (this.messageCache[messageId].conversationId === conversationId) { delete this.messageCache[messageId] } }) this.conversationId = null } // 从messages中删除会话 if (this.messages[conversationId]) { delete this.messages[conversationId] } } }, persist: { key: 'chatStore', storage: sessionStorage, paths: ['messages', 'currentMode', 'conversationId'] } })