t.add('show'); } } // 初始化表情选择器 function initReactionPicker(btn) { const picker = document.createElement('div'); picker.className = 'reaction-picker'; picker.innerHTML = REACTION_EMOJIS.map(e => `${e}` ).join(''); btn.appendChild(picker); } // 检查消息是否可撤回 function canRecall(msgId) { const sendTime = parseInt(msgId.replace('msg_', '')); return Date.now() - sendTime <= RECALL_TIMEOUT; } // 获取剩余可撤回时间(秒) function getRecallRemainingTime(msgId) { const sendTime = parseInt(msgId.replace('msg_', '')); const remaining = Math.max(0, RECALL_TIMEOUT - (Date.now() - sendTime)); return Math.ceil(remaining / 1000); } // ================================================ // ==================== 智能推荐问题功能 ==================== const allQuestions = [ { q: '学习平台搭建需要多少钱?', keywords: ['平台', '搭建', '价格', '多少钱', '系统', 'LMS'] }, { q: '课件制作有哪些形式?多少钱一分钟?', keywords: ['课件', '动画', '制作', '视频', '多少钱', '价格'] }, { q: '你们有哪些行业的实战讲师?', keywords: ['讲师', '老师', '培训', '面授', '行业'] }, { q: '标杆企业访学有哪些城市和企业?', keywords: ['访学', '考察', '企业', '标杆', '游学'] }, { q: '你们有哪些行业通用课程?', keywords: ['课程', '培训', '行业', '金融', '医药', '化工'] }, { q: '动画微课制作周期多久?价格多少钱?', keywords: ['联系', '电话', '微信', '咨询', '地址'] }, { q: '动画微课制作周期多久?', keywords: ['动画', '微课', '周期', '时间', '制作'] }, { q: '平台支持移动端学习吗?', keywords: ['移动', '手机', '平板', 'APP', '学习'] }, { q: '讲师可以到我们公司培训吗?', keywords: ['讲师', '上门', '内训', '面授', '公司'] }, { q: '有试听课程吗?可以先看看效果吗?', keywords: ['试听', '试看', '案例', '效果', '展示'] }, { q: '你们的课程可以定制吗?', keywords: ['定制', '开发', '课程', '内容'] }, { q: '访学是怎么安排的?包含哪些内容?', keywords: ['访学', '安排', '行程', '内容', '考察'] } ]; // HTML转义函数,防止XSS function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } function updateSmartSuggestions(inputText) { const container = document.getElementById('smartSuggestions'); const listContainer = document.getElementById('smartSuggestionsList'); if (!inputText || inputText.length < 2) { container.style.display = 'none'; return; } // 根据输入文本匹配相关问题 const inputLower = inputText.toLowerCase(); const matched = allQuestions.filter(item => { return item.keywords.some(kw => inputLower.includes(kw.toLowerCase()) || kw.toLowerCase().includes(inputLower) ); }).slice(0, 3); if (matched.length > 0) { listContainer.innerHTML = matched.map(item => `` ).join(''); container.style.display = 'block'; } else { container.style.display = 'none'; } } // ================================================ // ==================== 关键词触发卡片功能 ==================== // 关键词卡片配置 const KEYWORD_CARDS = { // 价格相关 price: { keywords: ['价格', '报价', '多少钱', '费用', '收费', '成本', '预算', '便宜', '优惠', '折扣'], icon: '💰', title: '了解报价方案', desc: '根据企业规模和需求定制方案', price: '¥9800起', action: '点击获取专属报价' }, // 课程相关 course: { keywords: ['课程', '培训', '课件', '内容', '学习', '教材', '大纲', '体系', '体系搭建'], icon: '📚', title: '行业精品课程', desc: '500+实战讲师 70+行业覆盖', price: '', action: '了解课程详情' }, // 讲师相关 teacher: { keywords: ['讲师', '老师', '导师', '专家', '顾问', '师资', '谁来讲'], icon: '👨‍🏫', title: '签约实战讲师', desc: '520+位行业专家 21个行业覆盖', price: '', action: '查看讲师库' }, // 访学相关 visit: { keywords: ['访学', '参观', '考察', '游学', '标杆', '企业参访', '走进'], icon: '🏢', title: '标杆企业访学', desc: '253家标杆企业 覆盖25个城市', price: '', action: '查看访学路线' }, // 平台相关 platform: { keywords: ['平台', '系统', '软件', 'APP', '小程序', '搭建', '开发', '定制'], icon: '🖥️', title: '学习平台搭建', desc: 'SaaS部署 快速上线 个性化定制', price: '', action: '了解平台功能' }, // 动画相关 animation: { keywords: ['动画', '微课', '视频', 'MG', '制作', '拍摄', '录制'], icon: '🎬', title: '动画微课制作', desc: '专业团队 高品质交付', price: '', action: '了解制作案例' }, // 定制相关 custom: { keywords: ['定制', '专属', '个性化', '特色', '定制化', '内训'], icon: '✨', title: '定制化服务', desc: '根据企业需求量身定制方案', price: '', action: '获取定制方案' } }; // 存储已触发的卡片类型(避免重复显示) let triggeredCards = new Set(); // 检测用户消息中的关键词 function detectKeywordTriggers(message) { if (!message) return []; message = message.toLowerCase(); const matched = []; for (const [type, config] of Object.entries(KEYWORD_CARDS)) { // 避免重复触发同类卡片 if (triggeredCards.has(type)) continue; for (const keyword of config.keywords) { if (message.includes(keyword.toLowerCase()) || message.includes(keyword)) { matched.push(type); triggeredCards.add(type); // 标记已触发 break; } } } return matched; } // 生成卡片HTML function generateCardsHTML(types) { if (!types || types.length === 0) return ''; // 限制最多显示3张卡片 const limitedTypes = types.slice(0, 3); const cards = limitedTypes.map(type => { const config = KEYWORD_CARDS[type]; return `
${config.icon} ${config.title} ${config.price ? `${config.price}` : ''}
`; }).join(''); return `
${cards}
`; } // 处理卡片点击 function handleCardClick(type, element) { // 高亮效果 element.classList.add('clicked'); const config = KEYWORD_CARDS[type]; let response = ''; switch(type) { case 'price': response = `📋 **我们的报价方案:**\n\n根据企业规模和需求,我们提供多种方案选择:\n\n💰 **基础版**:¥9,800/年\n- 适合50人以下企业\n- 包含:平台使用+50门课程\n\n💰 **标准版**:¥19,800/年\n- 适合50-200人企业\n- 包含:平台使用+200门课程+数据分析\n\n💰 **企业版**:面议\n- 适合200人以上企业\n- 包含:全功能+定制开发+专属服务\n\n📞 了解更多,请拨打:**183-5928-1779**`; break; case 'course': response = `📚 **我们的课程体系:**\n\n涵盖 **70+行业**,包括:\n\n• 金融行业:银行、保险、基金、证券\n• 制造行业:精益生产、质量管理、智能制造\n• 医药行业:合规培训、销售技巧\n• 营销行业:顾问式销售、大客户营销\n• 管理通用:领导力、中层管理\n\n🎯 **支持定制开发**,根据企业实际需求打造专属课程。\n\n了解更多请回复"课程"或拨打热线咨询。`; break; case 'teacher': response = `👨‍🏫 **我们的师资力量:**\n\n🎯 **520+位签约实战讲师**\n覆盖 **21个行业**\n\n📍 **部分讲师代表:**\n\n**保险行业**:张轶、黄国亮、邹延渤\n**银行行业**:罗开位、杜晶晶、殷国辉\n**制造行业**:安岷、申明江、杨学军\n**TTT培训**:刘澈、杨素珍、张一丹\n**营销行业**:耿镔、郏智群、黎红华\n\n🎓 所有讲师均具有10年+实战经验!\n\n想了解特定行业的讲师吗?`; break; case 'visit': response = `🏢 **标杆企业访学服务:**\n\n📊 **253家标杆企业**覆盖 **25个城市**\n\n🔥 **热门访学路线:**\n\n🏭 **深圳线**:华为、腾讯、字节、大疆\n🏢 **杭州线**:阿里巴巴、蚂蚁金服、海康威视\n🏙️ **北京线**:京东、美团、小米\n🏭 **上海线**:上汽、通用、商飞\n\n📋 **服务包含**:\n- 行程定制\n- 讲师对接\n- 复盘总结\n\n💰 **价格**:根据路线定制,请咨询报价`; break; case 'platform': response = `🖥️ **华企网校学习平台:**\n\n✅ **核心功能**:\n• 在线课程播放(支持动画微课)\n• 学习进度跟踪\n• 考试测评系统\n• 数据分析报表\n• 移动端适配\n\n⏱️ **快速上线**:3-7个工作日\n💰 **价格**:¥9,800/年起\n\n🎁 **限时优惠**:现在咨询赠送价值¥5000的课程包\n\n📞 了解更多:**183-5928-1779**`; break; case 'animation': response = `🎬 **动画微课制作服务:**\n\n✨ **我们提供**:\n• MG动画微课\n• 情景剧拍摄\n• 真人出镜讲解\n• 屏幕录制剪辑\n\n🎯 **适用场景**:\n- 新员工培训\n- 产品介绍\n- 销售技巧\n- 安全教育\n\n💰 **价格区间**:¥2,000-10,000/分钟\n⏱️ **交付周期**:5-15个工作日\n\n📋 **近期案例**:已服务100+企业客户\n\n想看案例展示吗?`; break; case 'custom': response = `✨ **定制化企业培训服务:**\n\n🎯 **我们能为您定制**:\n\n📚 **课程定制**:根据企业实际案例开发专属课程\n🖥️ **平台定制**:按需开发个性化功能模块\n📹 **内容定制**:企业故事、文化、品牌定制拍摄\n🏢 **访学定制**:根据学习目标设计访学路线\n\n💡 **服务流程**:\n1️⃣ 需求调研(免费)\n2️⃣ 方案设计\n3️⃣ 签订合同\n4️⃣ 交付执行\n\n📞 **立即咨询**:183-5928-1779`; break; } // 隐藏打字指示器并添加回复 hideTyping(); addMessage(response); conversationHistory.push({role: 'assistant', content: response}); } // 在AI回复后检测关键词并显示卡片 function checkAndShowKeywordCards(message) { const triggers = detectKeywordTriggers(message); if (triggers.length === 0) return; const cardsHTML = generateCardsHTML(triggers); if (!cardsHTML) return; // 在最后一条AI消息后添加卡片 const messages = document.getElementById('chatMessages'); const lastBotMessage = messages.querySelector('.message.bot:last-child'); if (lastBotMessage) { lastBotMessage.insertAdjacentHTML('beforeend', cardsHTML); scrollToBottom(); } } // ================================================ // ==================== 转人工/留言功能(完整重构版) ==================== // Toast提示函数 function showToast(message, type = 'success', duration = 3000) { const container = document.getElementById('toastContainer'); const toast = document.createElement('div'); toast.className = `toast ${type}`; const icons = { success: '', error: '', warning: '' }; toast.innerHTML = ` ${icons[type]} ${message} `; container.appendChild(toast); setTimeout(() => { toast.style.animation = 'slideOut 0.3s ease forwards'; setTimeout(() => toast.remove(), 300); }, duration); } // 验证表单 function validateForm() { let isValid = true; const name = document.getElementById('msgName'); const phone = document.getElementById('msgPhone'); const content = document.getElementById('msgContent'); // 清除之前的错误 document.querySelectorAll('.error').forEach(el => el.classList.remove('error')); document.querySelectorAll('.error-tip').forEach(el => el.textContent = ''); // 验证姓名 if (!name.value.trim()) { name.classList.add('error'); document.getElementById('nameError').textContent = '请输入您的姓名'; isValid = false; } // 验证手机号 if (!phone.value.trim()) { phone.classList.add('error'); document.getElementById('phoneError').textContent = '请输入手机号码'; isValid = false; } else if (!/^1[3-9]\d{9}$/.test(phone.value.trim())) { phone.classList.add('error'); document.getElementById('phoneError').textContent = '请输入正确的手机号码'; isValid = false; } // 验证内容 if (!content.value.trim()) { content.classList.add('error'); document.getElementById('contentError').textContent = '请输入留言内容'; isValid = false; } else if (content.value.trim().length < 10) { content.classList.add('error'); document.getElementById('contentError').textContent = '留言内容至少10个字'; isValid = false; } return isValid; } // 显示留言弹窗 function showLeaveModal() { document.getElementById('leaveModalOverlay').classList.add('show'); // 清空表单 document.getElementById('msgName').value = ''; document.getElementById('msgPhone').value = ''; document.getElementById('msgContent').value = ''; document.getElementById('charCount').textContent = '0'; document.querySelector('input[name="msgType"][value="课程咨询"]').checked = true; // 清除错误状态 document.querySelectorAll('.error').forEach(el => el.classList.remove('error')); document.querySelectorAll('.error-tip').forEach(el => el.textContent = ''); } function hideLeaveModal() { document.getElementById('leaveModalOverlay').classList.remove('show'); } // 兼容旧调用 function toggleLeaveMessage() { showLeaveModal(); } // 字数统计 + 咨询类型切换 document.addEventListener('DOMContentLoaded', () => { // 字数统计 const content = document.getElementById('msgContent'); if (content) { content.addEventListener('input', () => { document.getElementById('charCount').textContent = content.value.length; }); } // 咨询类型切换效果 const typeOptions = document.querySelectorAll('.type-option input[name="msgType"]'); typeOptions.forEach(radio => { // 初始化选中状态 if (radio.checked) { radio.closest('.type-option').classList.add('selected'); } // 点击切换 radio.addEventListener('change', () => { typeOptions.forEach(r => r.closest('.type-option').classList.remove('selected')); radio.closest('.type-option').classList.add('selected'); }); }); }); // 提交留言(完整重构版) async function submitLeaveMessage() { // 验证表单 if (!validateForm()) { return; } const name = document.getElementById('msgName').value.trim(); const phone = document.getElementById('msgPhone').value.trim(); const content = document.getElementById('msgContent').value.trim(); const msgType = document.querySelector('input[name="msgType"]:checked').value; // 显示loading状态 const submitBtn = document.getElementById('submitBtn'); const btnText = submitBtn.querySelector('.btn-text'); const btnLoading = submitBtn.querySelector('.btn-loading'); submitBtn.disabled = true; btnText.style.display = 'none'; btnLoading.style.display = 'flex'; try { // 调用后端API保存留言 const res = await fetch(API_BASE + '/api/message/submit', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, phone, content, type: msgType, source: '官网客服', create_time: new Date().toISOString() }) }); if (!res.ok) { throw new Error('Network response was not ok'); } const data = await res.json(); // 保存到本地备份 const leaveData = JSON.parse(localStorage.getItem('huaqi_leave_messages') || '[]'); leaveData.push({ name, phone, content, type: msgType, time: new Date().toISOString(), status: '待处理', synced: data.success || false }); localStorage.setItem('huaqi_leave_messages', JSON.stringify(leaveData)); // 关闭弹窗 hideLeaveModal(); // 显示成功动画消息 const messages = document.getElementById('chatMessages'); messages.insertAdjacentHTML('beforeend', `

留言提交成功!

我们将在 1个工作日 内联系您

📞 ${phone}

`); scrollToBottom(); // 显示成功Toast showToast('留言提交成功!', 'success'); } catch (e) { console.error('提交失败:', e); // 即使后端失败,也保存到本地 const leaveData = JSON.parse(localStorage.getItem('huaqi_leave_messages') || '[]'); leaveData.push({ name, phone, content, type: msgType, time: new Date().toISOString(), status: '待处理(本地)', synced: false }); localStorage.setItem('huaqi_leave_messages', JSON.stringify(leaveData)); // 关闭弹窗 hideLeaveModal(); // 显示提示消息 const messages = document.getElementById('chatMessages'); messages.insertAdjacentHTML('beforeend', `

📝 您的留言已暂存到本地

网络异常,但您的信息已保存,稍后会自动重试提交

📞 如需紧急咨询,请拨打热线:183-5928-1779

`); scrollToBottom(); showToast('网络异常,信息已暂存', 'warning'); } finally { // 恢复按钮状态 submitBtn.disabled = false; btnText.style.display = 'inline'; btnLoading.style.display = 'none'; } } // ================================================ function toggleChat() { chatOpen = !chatOpen; const chatWindow = document.getElementById('chatWindow'); chatWindow.classList.toggle('active', chatOpen); if (chatOpen) { document.getElementById('chatInput').focus(); } } function showWechat() { document.getElementById('wechatModal').style.display = 'flex'; } function closeWechat() { document.getElementById('wechatModal').style.display = 'none'; } // ==================== 多模态交互功能 ==================== // 语音识别相关变量 let recognition = null; let isRecording = false; let recordingTimer = null; let recordingSeconds = 0; let uploadedImageData = null; let ttsEnabled = false; // 初始化语音识别 function initVoiceRecognition() { if ('webkitSpeechRecognition' in window || 'SpeechRecognition' in window) { const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; recognition = new SpeechRecognition(); recognition.continuous = false; recognition.interimResults = true; recognition.lang = 'zh-CN'; recognition.onresult = function(event) { let transcript = ''; for (let i = event.resultIndex; i < event.results.length; i++) { transcript += event.results[i][0].transcript; } document.getElementById('chatInput').value = transcript; updateSmartSuggestions(transcript); // 实时分析情绪和意图 if (transcript.length > 5) { analyzeEmotion(transcript); analyzeIntent(transcript); } }; recognition.onend = function() { stopRecording(); // 如果有文字,自动发送 const text = document.getElementById('chatInput').value.trim(); if (text) { sendMessage(); } }; recognition.onerror = function(event) { console.error('语音识别错误:', event.error); stopRecording(); if (event.error === 'not-allowed') { addMessage('请允许麦克风权限后重试', false); } }; } } // 切换语音输入 function toggleVoiceInput() { const voiceBtn = document.getElementById('voiceBtn'); const input = document.getElementById('chatInput'); if (!recognition) { initVoiceRecognition(); } if (!recognition) { addMessage('您的浏览器不支持语音识别功能,请使用Chrome浏览器', false); return; } if (isRecording) { recognition.stop(); } else { // 清除图片(语音和图片二选一) if (uploadedImageData) { removeImage(); } isRecording = true; voiceBtn.classList.add('recording'); document.getElementById('voiceTime').style.display = 'inline'; recordingSeconds = 0; updateRecordingTime(); recognition.start(); } } // 停止录音 function stopRecording() { isRecording = false; const voiceBtn = document.getElementById('voiceBtn'); voiceBtn.classList.remove('recording'); document.getElementById('voiceTime').style.display = 'none'; if (recordingTimer) { clearInterval(recordingTimer); recordingTimer = null; } } // 更新录音时间显示 function updateRecordingTime() { recordingTimer = setInterval(() => { recordingSeconds++; const minutes = Math.floor(recordingSeconds / 60); const seconds = recordingSeconds % 60; document.getElementById('voiceTime').textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`; // 最多录制60秒 if (recordingSeconds >= 60) { recognition.stop(); } }, 1000); } // 处理图片上传 function handleImageUpload(event) { const file = event.target.files[0]; if (!file) return; if (!file.type.startsWith('image/')) { alert('请上传图片文件'); return; } // 限制文件大小(5MB) if (file.size > 5 * 1024 * 1024) { alert('图片大小不能超过5MB'); return; } const reader = new FileReader(); reader.onload = function(e) { uploadedImageData = e.target.result; // 显示预览 const previewContainer = document.getElementById('imagePreview'); const previewImg = document.getElementById('previewImg'); previewImg.src = uploadedImageData; previewContainer.classList.add('show'); // 清除语音输入(图片和语音二选一) if (isRecording && recognition) { recognition.stop(); } }; reader.readAsDataURL(file); // 清空input以允许重复选择同一文件 event.target.value = ''; } // 移除上传的图片 function removeImage() { uploadedImageData = null; document.getElementById('imagePreview').classList.remove('show'); document.getElementById('previewImg').src = ''; } // 图片预览弹窗 function viewImage(src) { document.getElementById('viewerImage').src = src; document.getElementById('imageViewer').classList.add('show'); } function closeImageViewer() { document.getElementById('imageViewer').classList.remove('show'); } // 切换TTS语音播报 function toggleTTS() { ttsEnabled = !ttsEnabled; const ttsBtn = document.getElementById('ttsBtn'); ttsBtn.classList.toggle('active', ttsEnabled); if (ttsEnabled) { addMessage('已开启语音播报,AI回复将自动朗读', false); } } // 语音播报文本 function speakText(text) { if (!ttsEnabled) return; // 清除HTML标签,只保留纯文本 const cleanText = text.replace(/<[^>]*>/g, '').replace(/\s+/g, ' ').trim(); if (!cleanText) return; // 使用Web Speech API if ('speechSynthesis' in window) { // 取消之前的播报 speechSynthesis.cancel(); const utterance = new SpeechSynthesisUtterance(cleanText); utterance.lang = 'zh-CN'; utterance.rate = 1.0; utterance.pitch = 1.0; // 尝试选择中文语音 const voices = speechSynthesis.getVoices(); const zhVoice = voices.find(v => v.lang.includes('zh')); if (zhVoice) { utterance.voice = zhVoice; } speechSynthesis.speak(utterance); } } // ==================== 情绪识别(基于关键词分析)==================== const EMOTION_KEYWORDS = { positive: { emoji: '😊', text: '检测到积极情绪', keywords: ['好', '棒', '谢谢', '感谢', '满意', '喜欢', '太棒', '不错', '赞', '厉害', '期待', '希望', '好的', '可以', '行', '没问题'] }, negative: { emoji: '😠', text: '检测到消极情绪', keywords: ['不满', '投诉', '差', '烂', '垃圾', '骗子', '骗', '坑', '问题', '故障', '错误', '失败', '失望', '糟糕', '无奈', '气愤', '着急', '紧急'] }, neutral: { emoji: '😐', text: '检测到中性情绪', keywords: [] } }; // 分析情绪 function analyzeEmotion(text) { const indicator = document.getElementById('emotionIndicator'); const emojiEl = document.getElementById('emotionEmoji'); const textEl = document.getElementById('emotionText'); let maxScore = 0; let detectedEmotion = 'neutral'; for (const [emotion, data] of Object.entries(EMOTION_KEYWORDS)) { if (emotion === 'neutral') continue; let score = 0; for (const keyword of data.keywords) { if (text.includes(keyword)) { score++; } } if (score > maxScore) { maxScore = score; detectedEmotion = emotion; } } const emotionData = EMOTION_KEYWORDS[detectedEmotion]; emojiEl.textContent = emotionData.emoji; textEl.textContent = emotionData.text; // 移除旧的情绪类,添加新的 indicator.className = 'emotion-indicator emotion-' + detectedEmotion; indicator.classList.add('show'); // 3秒后自动隐藏 setTimeout(() => { indicator.classList.remove('show'); }, 3000); return detectedEmotion; } // ==================== 意图识别(多意图分类)==================== const INTENT_PATTERNS = { price_inquiry: { label: '价格咨询', keywords: ['价格', '收费', '多少钱', '报价', '费用', '成本', '便宜', '贵', '优惠', '打折', '折扣'] }, product_info: { label: '产品咨询', keywords: ['产品', '功能', '服务', '平台', '系统', '课程', '课件', '课程内容', '包含什么'] }, booking: { label: '预约咨询', keywords: ['预约', '报名', '参加', '安排', '时间', '什么时候', '哪天', '课程表', '档期'] }, complaint: { label: '投诉建议', keywords: ['投诉', '建议', '问题', '反馈', '不满', '意见', 'bug', '错误'] }, cooperation: { label: '合作洽谈', keywords: ['合作', '代理', '加盟', '代理', '定制', '开发', '采购', '签订', '合同'] }, basic_info: { label: '基础咨询', keywords: ['公司', '地址', '电话', '联系', '微信', '邮箱', '官网', '是什么', '干嘛的'] } }; // 分析意图 function analyzeIntent(text) { const container = document.getElementById('intentTags'); const matches = []; // 计算每个意图的匹配度 for (const [intent, data] of Object.entries(INTENT_PATTERNS)) { let score = 0; for (const keyword of data.keywords) { if (text.includes(keyword)) { score++; } } if (score > 0) { matches.push({ intent, label: data.label, score }); } } // 按匹配度排序 matches.sort((a, b) => b.score - a.score); // 显示前3个意图标签 if (matches.length > 0) { container.innerHTML = matches.slice(0, 3).map((m, i) => `${m.label}` ).join(''); container.classList.add('show'); // 5秒后自动隐藏 setTimeout(() => { container.classList.remove('show'); }, 5000); } else { container.classList.remove('show'); } return matches.map(m => m.intent); } // 更新置信度指示器 function updateConfidenceDisplay(confidence) { const tagEl = document.getElementById('confidenceTag'); const dotEl = document.getElementById('confidenceTagDot'); const textEl = document.getElementById('confidenceTagText'); if (confidence === null || confidence === undefined) { tagEl.classList.remove('show'); return; } const percent = Math.round(confidence * 100); let level = 'high'; let levelText = '高置信度'; if (confidence >= 0.7) { level = 'high'; levelText = '高置信度'; } else if (confidence >= 0.4) { level = 'medium'; levelText = '中置信度'; } else { level = 'low'; levelText = '低置信度'; } // 更新标签 dotEl.className = 'confidence-tag-dot ' + level; textEl.textContent = levelText; // 显示标签 tagEl.classList.add('show'); // 低置信度时显示转人工建议 if (confidence < 0.6) { showTransferSuggestion(); } } // ==================== 人机协同:转人工功能 ==================== // 置信度阈值 const CONFIDENCE_THRESHOLD = 0.6; let isTransferring = false; // 显示转人工建议 function showTransferSuggestion() { // 避免重复显示 if (document.getElementById('transferSuggestion')) return; const messages = document.getElementById('chatMessages'); const suggestionHTML = `
💡 AI置信度较低
当前问题可能需要人工介入处理
${new Date().toLocaleTimeString('zh-CN', {hour: '2-digit', minute: '2-digit'})}
`; messages.insertAdjacentHTML('beforeend', suggestionHTML); scrollToBottom(); } // 关闭转人工建议 function dismissTransferSuggestion() { const el = document.getElementById('transferSuggestion'); if (el) el.remove(); } // 请求转人工 async function requestHumanTransfer() { if (isTransferring) return; isTransferring = true; // 隐藏建议 dismissTransferSuggestion(); // 获取最后一条AI回复 const messages = document.querySelectorAll('#chatMessages .message.bot'); const lastBotMsg = messages[messages.length - 1]; const lastReply = lastBotMsg ? lastBotMsg.querySelector('.message-content').textContent : ''; const lastUserMsg = conversationHistory.length > 0 ? conversationHistory[conversationHistory.length - 1].content : ''; // 显示转接中状态 const messagesContainer = document.getElementById('chatMessages'); messagesContainer.insertAdjacentHTML('beforeend', `
🎧
正在转接人工客服...
请稍候,马上为您服务
排队中
${new Date().toLocaleTimeString('zh-CN', {hour: '2-digit', minute: '2-digit'})}
`); scrollToBottom(); try { // 调用后端转接API const response = await fetch(API_BASE + '/api/transfer', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: sessionId, user_message: lastUserMsg, ai_reply: lastReply, reason: 'AI置信度低,自动建议转人工' }) }); const result = await response.json(); // 更新转接状态 const statusEl = document.getElementById('transferringStatus'); if (statusEl && result.success) { statusEl.querySelector('.message-content').innerHTML = `
已转接成功
${result.message || '人工客服已收到您的请求'}
${result.queue_position || ''} · ${result.estimated_wait || ''}
`; // 显示联系方式 setTimeout(() => { messagesContainer.insertAdjacentHTML('beforeend', `
💡 如需紧急帮助,欢迎直接联系我们:
📞 183-5928-1779
${new Date().toLocaleTimeString('zh-CN', {hour: '2-digit', minute: '2-digit'})}
`); scrollToBottom(); }, 1500); } } catch (error) { console.error('转接失败:', error); // 显示失败状态 const statusEl = document.getElementById('transferringStatus'); if (statusEl) { statusEl.querySelector('.message-content').innerHTML = `
⚠️
转接遇到问题
请拨打热线:183-5928-1779
`; } } isTransferring = false; } // 用户主动点击"转人工"按钮 function showHumanTransferOption() { if (isTransferring) return; const messagesContainer = document.getElementById('chatMessages'); messagesContainer.insertAdjacentHTML('beforeend', `
👨‍💼 人工服务
您想转接人工客服吗?我们会尽快为您服务。
${new Date().toLocaleTimeString('zh-CN', {hour: '2-digit', minute: '2-digit'})}
`); scrollToBottom(); } // ==================== 增强的消息添加(支持图片)==================== function scrollToBottom() { const messages = document.getElementById('chatMessages'); messages.scrollTop = messages.scrollHeight; } function addMessage(content, isUser = false, imageData = null) { const messages = document.getElementById('chatMessages'); const time = new Date().toLocaleTimeString('zh-CN', {hour: '2-digit', minute: '2-digit'}); const msgId = 'msg_' + Date.now(); const messageDiv = document.createElement('div'); messageDiv.className = `message ${isUser ? 'user' : 'bot'}`; messageDiv.setAttribute('data-msg-id', msgId); messageDiv.style.position = 'relative'; // 图片HTML let imageHTML = ''; if (imageData) { imageHTML = `上传图片`; } // 消息操作按钮(撤回和表情) const actionsHTML = `
${isUser ? `` : ''}
`; messageDiv.innerHTML = `
${isUser ? '' : '' }
${actionsHTML}
${imageHTML}${content.replace(/n/g, '
')}
${time}
`; messages.appendChild(messageDiv); // 初始化表情选择器 const reactionBtn = messageDiv.querySelector('.reaction-btn'); if (reactionBtn) { initReactionPicker(reactionBtn); } // AI消息:语音播报 if (!isUser && ttsEnabled) { speakText(content); } // 用户消息2分钟后隐藏撤回按钮 if (isUser) { setTimeout(() => { const recallBtn = messageDiv.querySelector('.recall-btn'); if (recallBtn) { recallBtn.style.opacity = '0.5'; recallBtn.style.cursor = 'not-allowed'; recallBtn.title = '消息已超过2分钟,无法撤回'; } }, RECALL_TIMEOUT); } // 更新表情显示 setTimeout(() => updateReactionDisplay(msgId), 0); scrollToBottom(); } function showTyping() { const messages = document.getElementById('chatMessages'); const typingDiv = document.createElement('div'); typingDiv.className = 'message bot'; typingDiv.id = 'typingIndicator'; typingDiv.innerHTML = `
`; messages.appendChild(typingDiv); scrollToBottom(); } function hideTyping() { const typing = document.getElementById('typingIndicator'); if (typing) typing.remove(); } // ==================== 人机协同:转人工功能 ==================== // 显示低置信度转人工提示 function showLowConfidenceTransfer(callback) { const messagesContainer = document.getElementById('messagesContainer'); // 检查是否已显示过 if (document.getElementById('lowConfidenceTip')) return; const tip = document.createElement('div'); tip.id = 'lowConfidenceTip'; tip.className = 'low-confidence-tip'; tip.innerHTML = `
🤔
没解决您的问题?
人工客服可以提供更专业的解答
`; messagesContainer.appendChild(tip); // 3秒后自动移除(如果用户没点击) setTimeout(() => { if (tip.parentElement) { tip.style.opacity = '0'; setTimeout(() => tip.remove(), 300); } }, 10000); } // 显示转接中动画 function showTransferring() { const messagesContainer = document.getElementById('messagesContainer'); const transferring = document.createElement('div'); transferring.id = 'transferringIndicator'; transferring.className = 'transferring-indicator'; transferring.innerHTML = `
正在为您转接人工客服... `; messagesContainer.appendChild(transferring); messagesContainer.scrollTop = messagesContainer.scrollHeight; } // 移除转接中动画 function removeTransferring() { const indicator = document.getElementById('transferringIndicator'); if (indicator) indicator.remove(); } // 显示系统消息 function addSystemMessage(text) { const messagesContainer = document.getElementById('messagesContainer'); const msg = document.createElement('div'); msg.className = 'message system-message'; msg.innerHTML = `
💬 ${text}
`; messagesContainer.appendChild(msg); messagesContainer.scrollTop = messagesContainer.scrollHeight; } // 监听坐席接入(SSE或轮询) let agentJoined = false; function listenForAgent() { // 使用轮询监听坐席接入(简化版) const pollInterval = setInterval(async () => { if (agentJoined) { clearInterval(pollInterval); return; } try { const res = await fetch(API_BASE + '/api/session/' + currentSessionId); const data = await res.json(); if (data.success && data.session) { if (data.session.status === 'human_serving' && data.session.assigned_agent_name) { agentJoined = true; clearInterval(pollInterval); // 坐席已接入 removeTransferring(); addSystemMessage(`人工客服 ${data.session.assigned_agent_name} 已接入,正在为您服务...`); currentServiceMode = 'human'; currentAgentName = data.session.assigned_agent_name; updateServiceModeIndicator(); showAgentJoinedUI(data.session.assigned_agent_name); } } } catch (e) { console.log('监听坐席状态失败:', e); } }, 2000); // 最多监听5分钟 setTimeout(() => { clearInterval(pollInterval); if (!agentJoined) { removeTransferring(); addSystemMessage('当前排队人数较多,请耐心等待或稍后再试。您也可以拨打热线:183-5928-1779'); } }, 300000); } // 显示坐席接入后的UI function showAgentJoinedUI(agentName) { // 更新欢迎语区域 const welcome = document.querySelector('.welcome-message'); if (welcome) { welcome.innerHTML = `
${agentName.charAt(0)}
${agentName}
人工客服 · 在线
`; } // 显示会话时长 sessionStartTime = Date.now(); if (sessionTimer) clearInterval(sessionTimer); sessionTimer = setInterval(updateSessionTimer, 1000); } // 更新会话计时器 function updateSessionTimer() { if (!sessionStartTime) return; const elapsed = Math.floor((Date.now() - sessionStartTime) / 1000); const mins = Math.floor(elapsed / 60); const secs = elapsed % 60; // 更新状态栏 const statusEl = document.getElementById('headerStatus'); if (statusEl) { statusEl.innerHTML = ` 人工服务中 · ${mins}:${secs.toString().padStart(2, '0')} `; } } // 模拟回复(当没有API时使用) function getSimulatedReply(question) { const q = question.toLowerCase(); if (q.includes('课程') || q.includes('培训')) { return '我们提供丰富的企业培训课程,覆盖金融、医药、化工、电网、新能源、机器人、保险、制造等多个行业。主要包括:\n\n1. 学习平台搭建 - 企业在线培训平台定制(SaaS版¥2-5万/年,私有化¥8万起)\n2. 动画微课开发 - MG动画培训短视频(¥3000-12000/分钟)\n3. 行业通用课程 - 各行业专业课程\n4. 实战讲师面授 - 520+位签约实战讲师,覆盖21个行业\n5. 标杆企业访学 - 覆盖25城253家标杆企业(¥2000起/人)\n\n请问您对哪个方向比较感兴趣?'; } if (q.includes('价格') || q.includes('收费') || q.includes('多少钱')) { return '我们的培训服务根据需求定制:\n\n平台搭建:\n- SaaS版 ¥2-5万/年\n- 私有化部署 ¥8万起\n\n课件开发:\n- 动画类 ¥3000-12000/分钟\n- H5互动类 ¥2000-5000/分钟\n- 图文类 ¥500-1500/分钟\n\n讲师面授:全国可安排,欢迎电话咨询具体报价\n\n具体报价需要了解您的需求后提供,欢迎拨打热线:183-5928-1779 咨询!'; } if (q.includes('联系') || q.includes('电话') || q.includes('微信')) { return '您可以通过以下方式联系我们:\n\n- 电话:183-5928-1779\n- 邮箱:wll@siimen.com\n- 官网:www.aimank.com\n\n我们随时欢迎您的咨询!'; } if (q.includes('平台') || q.includes('系统')) { return '我们的学习平台功能完善:\n\n- 课程管理:支持视频、文档、图文等多种格式\n- 学习跟踪:实时记录学习进度和成绩\n- 考试测评:在线答题、自动判卷\n- 互动社区:讨论区、问答区\n- 数据报表:多维度分析效果\n- 移动学习:手机、平板随时学\n\nSaaS版¥2-5万/年,私有化¥8万起,欢迎咨询!'; } if (q.includes('微课') || q.includes('动画') || q.includes('课件制作')) { return '动画课件开发是我们的核心服务!\n\n5种课件形式:\n1. 动画类 - MG动画,最生动展示复杂概念(¥3000-12000/分钟)\n2. H5互动类 - 游戏化学习,强参与感(¥2000-5000/分钟)\n3. 卡通讲解类 - 卡通人物趣味讲解(¥4000-8000/分钟)\n4. 视频类 - 课堂实录/专家演讲(¥3000-8000/分钟)\n5. 图文类 - PPT转化,高性价比(¥500-1500/分钟)\n\n覆盖:金融动画/医学动画/化工安全/工业机械/安全规程等全场景\n20000+课件经验,批量享8折,欢迎咨询!'; } return '感谢您的咨询!我们的服务涵盖企业培训的各个方面,包括平台搭建、课程开发、讲师面授等。请问您具体想了解哪方面的内容?您也可以拨打热线:183-5928-1779,我们有专业顾问为您服务。'; } async function sendMessage() { const input = document.getElementById('chatInput'); const message = input.value.trim(); const image = uploadedImageData; if (!message && !image) return; // ========== 发送前:实时分析 ========== if (message) { analyzeEmotion(message); // 分析情绪 analyzeIntent(message); // 分析意图 } // 显示用户消息(带图片) addMessage(message, true, image); input.value = ''; closeSmartSuggestions(); removeImage(); // 清除图片 // 保存对话历史 const userContent = message || '[图片]'; conversationHistory.push({role: 'user', content: userContent}); // 保存到后端数据库 saveChatMessage(userContent, 'user'); // ========== 1. 先查本地知识库 ========== const kbMatch = message ? findKBMatch(message) : null; if (kbMatch) { // 知识库命中,增加命中计数 const kb = getAutoKB(); const idx = kb.findIndex(item => item.q === kbMatch.q); if (idx !== -1) { kb[idx].hitCount = (kb[idx].hitCount || 0) + 1; saveAutoKB(kb); } // 直接用知识库的答案 hideTyping(); addMessage(kbMatch.a); conversationHistory.push({role: 'assistant', content: kbMatch.a}); // 保存AI回复到后端 saveChatMessage(kbMatch.a, 'bot'); // 关键词触发卡片 checkAndShowKeywordCards(message); // 显示高置信度 updateConfidenceDisplay(0.95); return; } // ========== 2. 知识库未命中,调用AI ========== showTyping(); // 构建增强的系统提示(包含情绪上下文) let systemPrompt = SYSTEM_PROMPT; if (message) { const emotion = analyzeEmotion(message); if (emotion === 'negative') { systemPrompt += '\n\n【重要】检测到用户可能存在不满情绪,请用更加耐心、专业的语气回复,并主动表达歉意和解决方案。'; } else if (emotion === 'positive') { systemPrompt += '\n\n【提示】用户情绪积极,可以适当热情回应,并引导用户深入了解服务。'; } } // 如果有图片,添加图片描述请求 let enhancedMessage = message || '请描述这张图片中的内容,并回答用户可能想问的问题。'; let reply; try { // 构建消息格式 const imageMsg = image ? [ { role: 'user', content: [ { type: 'text', text: message || '请描述这张图片' }, { type: 'image_url', image_url: { url: image } } ]} ] : [{ role: 'user', content: message }]; // 调用后端统一AI接口 const response = await fetch(API_BASE + '/api/chat/ai', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ messages: [ { role: 'system', content: systemPrompt }, ...conversationHistory.slice(0, -1), ...imageMsg ], session_id: chatSessionId }) }); if (!response.ok) { throw new Error(`请求失败: ${response.status}`); } const data = await response.json(); if (!data.success) { throw new Error(data.error || 'AI服务异常'); } reply = data.reply; // 计算模拟置信度(基于回复长度和内容质量) let confidence = 0.7; if (reply.length > 100) confidence += 0.1; if (reply.includes('电话') || reply.includes('联系') || reply.includes('价格')) confidence += 0.1; updateConfidenceDisplay(Math.min(0.99, confidence)); // ========== 置信度监测:低于阈值时自动提示转人工 ========== const CONFIDENCE_THRESHOLD = 0.6; if (confidence < CONFIDENCE_THRESHOLD) { // 低置信度:显示转人工提示 setTimeout(() => { showLowConfidenceTransfer(reason => { // 用户选择转人工 requestHumanTransfer(reason || 'AI置信度低'); }); // 提示用户可以转人工 addMessage('💡 如果我的回答不够准确,您可以点击下方「转接人工客服」获得更专业的服务。', false, null, true); }, 500); } } catch (error) { console.warn('API调用失败,使用模拟回复:', error.message); reply = getSimulatedReply(message); updateConfidenceDisplay(0.5); // API失败时也提示可转人工 setTimeout(() => { addMessage('💡 如需更详细的解答,欢迎转接人工客服为您服务。', false, null, true); }, 500); } hideTyping(); addMessage(reply); conversationHistory.push({role: 'assistant', content: reply}); // 保存AI回复到后端数据库 saveChatMessage(reply, 'bot'); // ========== 关键词触发卡片 ========== checkAndShowKeywordCards(message); // ========== 3. 学习用户问题 ========== if (message) { learnQuestion(message, reply); autoLearnKnowledge(message, reply); } } function sendQuickQuestion(question) { document.getElementById('chatInput').value = question; closeSmartSuggestions(); sendMessage(); } function closeSmartSuggestions() { document.getElementById('smartSuggestions').style.display = 'none'; } function handleKeyDown(event) { if (event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); sendMessage(); } // Shift+Enter 允许换行,textarea默认行为即可 } document.getElementById('wechatModal').addEventListener('click', function(e) { if (e.target === this) closeWechat(); }); // 点击其他地方关闭表情选择器 document.addEventListener('click', function(e) { if (!e.target.closest('.reaction-btn') && !e.target.closest('.reaction-picker')) { document.querySelectorAll('.reaction-picker').forEach(p => p.classList.remove('show')); } }); // ==================== 上班时间控制 ==================== // 上班时间:周一至周五 9:00-18:00 const WORK_START_HOUR = 9; const WORK_END_HOUR = 18; // 判断当前是否为上班时间 function isWorkTime() { const now = new Date(); const day = now.getDay(); // 0=周日, 1=周一, ..., 6=周六 const hour = now.getHours(); // 周一到周五(1-5),且在9:00-18:00之间 return day >= 1 && day <= 5 && hour >= WORK_START_HOUR && hour < WORK_END_HOUR; } // 咨询联系方式(始终显示) const contactsHTML = `
电话咨询 微信咨询
`; // 在线坐席状态 let onlineAgentsCount = 0; // 更新顶部状态显示 async function updateHumanTransferButton() { const headerStatus = document.getElementById('headerStatus'); // 检查在线坐席数量 try { const res = await fetch(API_BASE + '/api/chat/online-agents'); const data = await res.json(); onlineAgentsCount = data.success ? data.online_count : 0; } catch (e) { onlineAgentsCount = 0; } if (!headerStatus) return; if (isWorkTime() && onlineAgentsCount > 0) { headerStatus.innerHTML = '人工客服在线'; } else if (isWorkTime()) { headerStatus.innerHTML = ' 暂无坐席'; } else { headerStatus.innerHTML = ' AI为您服务'; } } // 页面加载时初始化 document.addEventListener('DOMContentLoaded', function() { updateHumanTransferButton(); // 自动弹出功能已关闭 // ====== 自动弹出咨询对话框(6秒后)- 已禁用 ====== // if (!hasAutoShown) { // setTimeout(function() { // if (!chatOpen) { // toggleChat(); // addBotMessage('您好!欢迎访问华企网校 👋
有什么可以帮助您的吗?'); // sessionStorage.setItem(AUTO_POPUP_KEY, 'true'); // } // }, AUTO_POPUP_DELAY); // } // ====== 自动弹出功能结束 ====== }); // 页面可见性变化时更新状态(确保打开聊天窗口前状态已更新) document.addEventListener('visibilitychange', function() { if (!document.hidden) { updateHumanTransferButton(); } }); // 聊天窗口打开时更新状态 const originalToggleChat = toggleChat; toggleChat = function() { originalToggleChat(); if (chatOpen) { updateHumanTransferButton(); } }; // ====== 访问统计功能 ====== (function() { // 获取访问来源页面 var referer = document.referrer || '直接访问'; // 获取当前页面URL var currentUrl = window.location.href; // 获取User-Agent var userAgent = navigator.userAgent; // 获取屏幕分辨率 var screenSize = window.screen.width + 'x' + window.screen.height; // 获取语言设置 var language = navigator.language || navigator.userLanguage; // 获取访问时间 var visitTime = new Date().toLocaleString('zh-CN'); // 发送统计请求 fetch('https://www.aimank.com/Api/Hitstall/index', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ // 页面信息 url: currentUrl, referer: referer, title: document.title, // 客户端信息 user_agent: userAgent, screen: screenSize, language: language, // 时间 visit_time: visitTime, timestamp: Date.now() }) }).catch(function(err) { // 静默失败,不影响页面功能 }); })(); // ====== 访问统计结束 ======