diff --git a/public/images/avatars/custom.png b/public/images/avatars/custom.png new file mode 100644 index 0000000..a08241b Binary files /dev/null and b/public/images/avatars/custom.png differ diff --git a/public/images/avatars/user.png b/public/images/avatars/user.png new file mode 100644 index 0000000..8328b07 Binary files /dev/null and b/public/images/avatars/user.png differ diff --git a/src/mocks/modules/chat.js b/src/mocks/modules/chat.js index 31541d1..8a369d7 100644 --- a/src/mocks/modules/chat.js +++ b/src/mocks/modules/chat.js @@ -36,7 +36,7 @@ const chatModes = { export default [ // 获取聊天模式配置 { - url: '/api/chat/modes', + url: 'api/chat/modes', method: 'POST', response: () => { return { diff --git a/src/store/chat.js b/src/store/chat.js index e1e2fa6..74ce7dc 100644 --- a/src/store/chat.js +++ b/src/store/chat.js @@ -1,53 +1,45 @@ import { getChatModes, sendMessage } from '@/api/chat' import { useSpeakStore } from '@/store/speak' +import { processTagContent } from '@/utils' import { speakText } from '@/utils/speak' import { defineStore } from 'pinia' - +const chatModes = { + training: { + name: "寿险代理人AI陪练", + customerAvatar: "/images/avatars/custom.png", + userAvatar: "/images/avatars/user.png", + token: "app-88ae2GN49aUyNO6qGg7tbTfX", + background: "# 客户信息\n### **基础背景与性格设定** \n**姓名**:刘勇 \n**年龄**:34 岁 \n**职业**:腾讯员工 \n**家庭**:妻子为全职太太,女儿 9 岁,双方父母健在 \n**性格**:冷静、理性、务实,偏好客观数据和逻辑分析,对保险持观望态度,防备心较强 \n**近期状态**: \n- 体检显示中度脂肪肝,担心投保问题 \n- 已为全家配置百万医疗险,妻子有重疾险,但认为保障不足 (保费 50W)\n- 对理财型保险收益不认可,但对补充重疾险有潜在需求 ", + chatBackground: "通过尚先生介绍,你和他的老同学在他的家里首次面谈。他的家中布置简洁,茶几上摆放着一套茶具。" + }, + ai_agent: { + name: "AI寿险代理人", + customerAvatar: "/images/avatars/user.png", + userAvatar: "/images/avatars/custom.png", + token: "app-eYoE51WXCaEKXvzb9ZCj6lBn", + background: "# AI寿险代理人\n### **角色设定** \n**身份**:AI寿险代理人 \n**特点**:专业、耐心、细致、富有同理心 \n**能力**:\n- 精通各类寿险产品知识\n- 擅长需求分析和方案定制\n- 具备优秀的沟通和谈判技巧\n- 能够处理各类客户异议\n- 熟悉保险行业最新动态", + chatBackground: "一位AI的保险代理人,通过聊天来确认用户的需求,收集用户的基本信息" + }, + quote_objection: { + name: "报价中异议", + customerAvatar: "/images/avatars/custom.png", + userAvatar: "/images/avatars/user.png", + token: "app-ur2Altw2LHR6niX8Q1S7Cn41", + background: "# 客户信息\n### **基础背景与性格设定** \n**姓名**: 王大牛\n**年龄**: 40岁\n**职业**: 私营企业主\n**车牌号**: 闽C12345\n**车辆信息**:拥有一辆行驶4年的大众途观L,购买价格约25万,主要用于商务出行及家庭使用。\n**投保信息**:在其他保司购买交强险及商业险(三者险、车损险),还有1个月到期。有过一次轻微追尾事故,已通过保司处理。王先生对成本控制非常敏感,但也能意识到保险的重要性。他希望得到保障全面、价格合理的产品和优质的服务。", + chatBackground: "现在你将扮演坐席专员,与系统扮演的客户针对报价中的各类异议开展对练,着重训练处理\"报价中异议\"的能力。按照\"保全保足\"原则给出险种推荐方案。" + }, + post_quote_objection: { + name: "报价后异议", + customerAvatar: "/images/avatars/custom.png", + userAvatar: "/images/avatars/user.png", + token: "app-Yiccl0JoXs2QF2lkHxO6f822", + background: "# 客户信息\n### **基础背景与性格设定** \n**姓名**: 张灵女士\n**年龄**: 32岁\n**职业**: 公司行政主管\n**车牌号**: 粤B56789\n**车辆信息**:拥有一辆行驶4年多的本田思域,1.5T,CVT燃动版,购买价格约15万,用于日常通勤及周末短途出行。\n**投保信息**:在其他保司购买交强险及商业险(三者险、车损险、不计免赔险、车上人员责任险),还有2个月到期。无事故记录,仅有两次违章停车记录。张女士注重性价比和服务质量,希望保险的保障全面、价格合理、服务贴心。", + chatBackground: "现在你将扮演坐席专员,与系统扮演的客户针对报价后的各类异议开展对练,着重训练处理\"报价后异议\"的能力。按照\"保全保足\"原则给出险种推荐方案。" + } +} const tagList = ['kehu', 'pingfen', 'zongjie', 'huaxiang', 'dafen'] -// 处理标签内容的辅助函数 -const processTagContent = (answerCache, tagName, cachedMessage) => { - // 检查是否包含完整的开始标签 - const startTag = `<${tagName}>` - const endTag = `${tagName}>` - // 如果正在处理该标签 - if (cachedMessage.respondingType === tagName) { - // 检查是否包含结束标签 - if (answerCache.includes(endTag)) { - // 提取结束标签前的内容 - const content = answerCache.split(endTag)[0] - cachedMessage[tagName] += content - cachedMessage.respondingType = '' - cachedMessage[`${tagName}Finished`] = true - 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: () => ({ @@ -55,11 +47,11 @@ export const useChatStore = defineStore('chat', { currentMode: 'training', conversationId: null, messageCache: {}, - chatModes: {}, chatModesLoading: false, }), getters: { + chatModes: () => chatModes, currentToken: (state) => state.chatModes[state.currentMode]?.token, currentConversation: (state) => { return state.conversationId ? state.messages[state.conversationId] : null diff --git a/src/utils/index.js b/src/utils/index.js new file mode 100644 index 0000000..b7879bf --- /dev/null +++ b/src/utils/index.js @@ -0,0 +1,43 @@ +// 处理标签内容的辅助函数 +export const processTagContent = (answerCache, tagName, cachedMessage) => { + // 检查是否包含完整的开始标签 + const startTag = `<${tagName}>` + const endTag = `${tagName}>` + + // 如果正在处理该标签 + if (cachedMessage.respondingType === tagName) { + // 检查是否包含结束标签 + if (answerCache.includes(endTag)) { + // 提取结束标签前的内容 + const content = answerCache.split(endTag)[0] + cachedMessage[tagName] += content + cachedMessage.respondingType = '' + cachedMessage[`${tagName}Finished`] = true + 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 +} diff --git a/src/views/chat/ChatInterface.vue b/src/views/chat/ChatInterface.vue index 2b813f5..4e668b7 100644 --- a/src/views/chat/ChatInterface.vue +++ b/src/views/chat/ChatInterface.vue @@ -19,7 +19,7 @@