/** * 数字人直播系统 - 主控制逻辑 * 对接 ECS 后端 (124.70.146.192:8001) 完整API * * 数据流: * 评论输入 → process-comment → 9智能体协同 → 回复展示 * 直播控制 → start/stop/switch → 状态同步 * 场景管理 → templates → apply → 预览更新 */ (function() { 'use strict'; // ==================== 应用状态 ==================== const AppState = { isLive: false, streamId: null, currentPlatform: 'douyin', selectedTemplate: null, selectedSceneConfig: null, viewers: 0, likes: 0, commentCount: 0, conversionRate: 0, comments: [], connected: false, wsConnection: null, statsTimer: null }; // ==================== DOM 引用缓存 ==================== const $ = (sel) => document.querySelector(sel); const $$ = (sel) => document.querySelectorAll(sel); // ==================== 初始化 ==================== async function init() { console.log('[数字人直播] 初始化中控台...'); bindEvents(); await healthCheck(); if (AppState.connected) { await Promise.all([ loadSceneTemplates(), loadTalkTemplates(), loadLiveStats() ]); connectWebSocket(); startStatsPolling(); } console.log('[数字人直播] 中控台初始化完成'); } // ==================== 事件绑定 ==================== function bindEvents() { // 直播控制 $('#dhStartLiveBtn')?.addEventListener('click', startLive); $('#dhStopLiveBtn')?.addEventListener('click', stopLive); $('#dhSwitchHumanBtn')?.addEventListener('click', switchToHuman); // 场景 $('#dhSceneSwitchBtn')?.addEventListener('click', openSceneModal); $('#dhApplySceneBtn')?.addEventListener('click', applyScene); $('#dhCloseSceneModal')?.addEventListener('click', closeSceneModal); // 话术 $('#dhApplyScriptBtn')?.addEventListener('click', applyTalkScript); // 评论处理(核心) $('#dhSendCommentBtn')?.addEventListener('click', sendComment); $('#dhCommentInput')?.addEventListener('keydown', (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendComment(); } }); // 快捷操作 $('#dhComplianceBtn')?.addEventListener('click', runComplianceCheck); $('#dhSyncDataBtn')?.addEventListener('click', syncLiveData); $('#dhGenerateContentBtn')?.addEventListener('click', generateContent); // 平台切换 $$('.dh-platform-item').forEach(item => { item.addEventListener('click', function() { switchPlatform(this.dataset.platform); }); }); // 场景自定义配置实时预览 const sceneInputs = $$('#dhSceneModal input, #dhSceneModal textarea'); sceneInputs.forEach(input => { input.addEventListener('input', updateLivePreview); }); // 模态框点击关闭 $('#dhSceneModal')?.addEventListener('click', function(e) { if (e.target === this) closeSceneModal(); }); // 刷新按钮 $('#dhRefreshBtn')?.addEventListener('click', async () => { await Promise.all([loadSceneTemplates(), loadTalkTemplates(), loadLiveStats()]); DigitalHumanToast.success('数据已刷新'); }); } // ==================== 健康检查 ==================== async function healthCheck() { try { DigitalHumanLoading.show('正在连接ECS后端...'); const result = await digitalHumanAPI.healthCheck(); AppState.connected = true; updateConnectionStatus(true); DigitalHumanToast.success('ECS后端连接成功'); console.log('[数字人直播] 健康检查通过:', result); } catch (error) { AppState.connected = false; updateConnectionStatus(false); DigitalHumanToast.error('无法连接ECS后端: ' + error.message); console.error('[数字人直播] 健康检查失败:', error); } finally { DigitalHumanLoading.hide(); } } function updateConnectionStatus(connected) { const badge = $('#dhConnectionBadge'); const dot = $('#dhConnectionDot'); if (badge && dot) { badge.className = 'dh-status-badge ' + (connected ? 'online' : 'offline'); dot.className = 'dh-status-dot ' + (connected ? 'online' : 'offline'); badge.innerHTML = `${connected ? 'ECS已连接' : 'ECS未连接'}`; } } // ==================== WebSocket(生产环境通过网关不支持WS,使用轮询模式) ==================== function connectWebSocket() { console.log('[数字人直播] 生产环境使用轮询模式(WebSocket通过网关不可用)'); // 不尝试连接WebSocket,使用纯轮询 } function handleWSMessage(data) { switch (data.type) { case 'stats_update': if (data.viewers) { AppState.viewers = data.viewers; updateStatDisplay(); } if (data.likes) { AppState.likes = data.likes; updateStatDisplay(); } if (data.comment_count !== undefined) { AppState.commentCount = data.comment_count; updateStatDisplay(); } if (data.conversion_rate !== undefined) { AppState.conversionRate = data.conversion_rate; updateStatDisplay(); } break; case 'new_comment': addCommentToList(data.comment, 'user-comment'); // 如果开启自动回复 if (data.comment && data.comment.text) { autoProcessComment(data.comment.text); } break; case 'reply': addCommentToList(data.reply, 'ai-reply', data.agent_chain); break; default: console.log('[数字人直播] 未知WS消息:', data.type); } } // ==================== 直播控制 ==================== async function startLive() { if (!AppState.connected) { DigitalHumanToast.error('请先连接ECS后端'); return; } const confirmed = await DigitalHumanDialog.confirm( `确定要在 ${getPlatformDisplayName(AppState.currentPlatform)} 开始直播吗?`, { title: '开始直播', confirmText: '开始直播' } ); if (!confirmed) return; try { DigitalHumanLoading.show('正在启动直播...'); const result = await digitalHumanAPI.startLiveStream({ platform: AppState.currentPlatform, template: AppState.selectedTemplate?.id || null, config: AppState.selectedSceneConfig || {} }); AppState.isLive = true; AppState.streamId = result.stream_id || `stream_${Date.now()}`; AppState._liveStartTime = Date.now(); updateLiveUI(true); updateLivePreview(); DigitalHumanToast.success('直播已开始!平台: ' + getPlatformDisplayName(AppState.currentPlatform)); console.log('[数字人直播] 直播已开始:', result); } catch (error) { DigitalHumanToast.error('启动直播失败: ' + error.message); console.error('[数字人直播] 启动失败:', error); } finally { DigitalHumanLoading.hide(); } } async function stopLive() { const confirmed = await DigitalHumanDialog.confirm( '确定要停止当前直播吗?', { title: '停止直播', confirmText: '停止', type: 'warning' } ); if (!confirmed) return; try { DigitalHumanLoading.show('正在停止直播...'); await digitalHumanAPI.stopLiveStream({ stream_id: AppState.streamId, platform: AppState.currentPlatform }); AppState.isLive = false; AppState.streamId = null; AppState._liveStartTime = null; updateLiveUI(false); DigitalHumanToast.success('直播已停止'); } catch (error) { DigitalHumanToast.error('停止直播失败: ' + error.message); } finally { DigitalHumanLoading.hide(); } } async function switchToHuman() { if (!AppState.isLive) { DigitalHumanToast.warning('请先开始直播'); return; } const targetType = $('#dhSwitchHumanBtn').dataset.target === 'human' ? 'digital_human' : 'human'; const displayText = targetType === 'human' ? '真人主播' : '数字人'; const confirmed = await DigitalHumanDialog.confirm( `确定切换到${displayText}模式吗?`, { title: '切换直播模式', confirmText: `切换到${displayText}` } ); if (!confirmed) return; try { DigitalHumanLoading.show('正在切换...'); await digitalHumanAPI.switchStream({ stream_id: AppState.streamId, target_type: targetType }); const btn = $('#dhSwitchHumanBtn'); if (targetType === 'human') { btn.textContent = '切换数字人'; btn.dataset.target = 'digital_human'; DigitalHumanToast.success('已切换到真人主播模式'); } else { btn.textContent = '真人接管'; btn.dataset.target = 'human'; DigitalHumanToast.success('已切换到数字人模式'); } } catch (error) { DigitalHumanToast.error('切换失败: ' + error.message); } finally { DigitalHumanLoading.hide(); } } function updateLiveUI(isLive) { const startBtn = $('#dhStartLiveBtn'); const stopBtn = $('#dhStopLiveBtn'); const switchBtn = $('#dhSwitchHumanBtn'); if (startBtn) startBtn.disabled = isLive; if (stopBtn) stopBtn.disabled = !isLive; if (switchBtn) switchBtn.disabled = !isLive; // 更新预览区域 LIVE 标记 const preview = $('#dhLivePreview'); if (preview) { if (isLive) { preview.classList.add('live-active'); } else { preview.classList.remove('live-active'); } } } // ==================== 场景管理 ==================== async function loadSceneTemplates() { try { const result = await digitalHumanAPI.getSceneTemplates(); const templates = result.templates || result.data || result || []; renderSceneTemplates(Array.isArray(templates) ? templates : []); } catch (error) { console.warn('[数字人直播] 加载场景模板失败:', error.message); renderSceneTemplates(getDefaultTemplates()); } } function renderSceneTemplates(templates) { const container = $('#dhSceneGrid'); if (!container) return; if (templates.length === 0) { container.innerHTML = `
🎬

暂无场景模板

`; return; } container.innerHTML = templates.map(t => `
${t.name || t.id}
${t.description || ''}
${(t.type || '通用').replace(/_/g, ' ')} ${t.tags ? `
${t.tags.map(tag => `${tag}`).join(' ')}
` : ''}
`).join(''); // 绑定选择事件 container.querySelectorAll('.dh-scene-card').forEach(card => { card.addEventListener('click', function() { container.querySelectorAll('.dh-scene-card').forEach(c => c.classList.remove('selected')); this.classList.add('selected'); try { AppState.selectedTemplate = JSON.parse(this.dataset.template); } catch(e) { AppState.selectedTemplate = { id: this.dataset.templateId }; } }); }); } function getDefaultTemplates() { return [ { id: 'product_live', name: '带货直播', description: '电商带货标准场景', type: 'product', tags: ['带货', '电商'] }, { id: 'knowledge_share', name: '知识分享', description: '教育培训知识分享场景', type: 'knowledge', tags: ['教育', '知识'] }, { id: 'brand_launch', name: '品牌发布', description: '新品发布会专用场景', type: 'brand', tags: ['品牌', '发布'] }, { id: 'interactive_qa', name: '互动问答', description: '观众互动问答场景', type: 'interactive', tags: ['互动', '问答'] } ]; } function openSceneModal() { const modal = $('#dhSceneModal'); if (modal) modal.style.display = 'flex'; } function closeSceneModal() { const modal = $('#dhSceneModal'); if (modal) modal.style.display = 'none'; } async function applyScene() { if (!AppState.selectedTemplate) { DigitalHumanToast.warning('请先选择一个场景模板'); return; } const config = { scene_id: AppState.selectedTemplate.id, brand_text: $('#dhBrandText')?.value || '', title: $('#dhSceneTitle')?.value || '', description: $('#dhSceneDesc')?.value || '', logo_path: $('#dhLogoPath')?.value || '', color_scheme: { primary: $('#dhPrimaryColor')?.value || '#667eea', secondary: $('#dhSecondaryColor')?.value || '#764ba2' } }; try { const result = await digitalHumanAPI.applyScene(config); AppState.selectedSceneConfig = config; updateLivePreview(); closeSceneModal(); if (result.success || result.status === 'applied') { DigitalHumanToast.success('场景应用成功!'); } else { DigitalHumanToast.info('场景已应用(本地预览)'); } } catch (error) { // 离线模式:本地应用 AppState.selectedSceneConfig = config; updateLivePreview(); closeSceneModal(); DigitalHumanToast.info('场景已在本地应用(后端未响应)'); } } function updateLivePreview() { const preview = $('#dhLivePreview'); if (!preview) return; const brand = $('#dhBrandText')?.value || AppState.selectedSceneConfig?.brand_text || AppState.selectedTemplate?.name || '数字人直播'; const title = $('#dhSceneTitle')?.value || AppState.selectedSceneConfig?.title || '正在直播中...'; const desc = $('#dhSceneDesc')?.value || AppState.selectedSceneConfig?.description || '欢迎来到我们的直播间'; const primary = $('#dhPrimaryColor')?.value || AppState.selectedSceneConfig?.color_scheme?.primary || '#667eea'; preview.innerHTML = `
🤖
${escapeHTML(brand)}
${escapeHTML(title)}
${escapeHTML(desc)}
👁 ${formatNumber(AppState.viewers)} 观看 ❤ ${formatNumber(AppState.likes)} 点赞 💬 ${AppState.commentCount} 评论 📊 ${AppState.conversionRate}% 转化
`; } // ==================== 话术管理 ==================== async function loadTalkTemplates() { try { const result = await digitalHumanAPI.getTalkTemplates(AppState.currentPlatform); const data = result.templates || result.data || result; populateScriptSelects(data); } catch (error) { console.warn('[数字人直播] 加载话术模板失败:', error.message); populateScriptSelects(getDefaultScripts()); } } function populateScriptSelects(data) { const categories = [ { id: 'dhOpeningSelect', key: 'opening', label: '开场白' }, { id: 'dhProductSelect', key: 'product_introduction', label: '产品介绍' }, { id: 'dhWelfareSelect', key: 'welfare_promotion', label: '福利推广' } ]; categories.forEach(cat => { const select = document.getElementById(cat.id); if (!select) return; select.innerHTML = ``; const items = data?.[cat.key]; if (!items) return; // 处理字符串、对象或数组格式 if (typeof items === 'string') { const option = document.createElement('option'); option.value = cat.key; option.textContent = items.substring(0, 40) + '...'; option.title = items; select.appendChild(option); } else if (Array.isArray(items)) { items.forEach((item, i) => { const option = document.createElement('option'); option.value = `${cat.key}_${i}`; option.textContent = typeof item === 'string' ? item.substring(0, 40) : (item.content || item.name || JSON.stringify(item)); select.appendChild(option); }); } else if (typeof items === 'object') { Object.entries(items).forEach(([key, value]) => { const option = document.createElement('option'); option.value = key; option.textContent = typeof value === 'string' ? value.substring(0, 40) : (value.content || key); select.appendChild(option); }); } }); } function getDefaultScripts() { return { opening: { welcome1: '欢迎各位宝宝来到直播间!今天给大家带来超值好物,千万不要错过!', welcome2: '大家好呀~我是你们的AI数字人主播,感谢大家的支持!', welcome3: '新进来的朋友点点关注,精彩内容马上开始!' }, product_introduction: { product1: '这款产品真的非常好用,我自己都在用,强烈推荐给大家!', product2: '库存有限,手慢就没了!这个价格绝对是全网最低!', product3: '品质保证,售后无忧,大家可以放心购买!' }, welfare_promotion: { welfare1: '今天直播间专属福利,前100名下单享8折优惠!', welfare2: '关注主播+加入粉丝团,即可参与抽奖活动!', welfare3: '限时秒杀,只剩最后10分钟,错过等一年!' } }; } async function applyTalkScript() { const opening = $('#dhOpeningSelect')?.value; const product = $('#dhProductSelect')?.value; const welfare = $('#dhWelfareSelect')?.value; if (!opening && !product && !welfare) { DigitalHumanToast.warning('请选择至少一种话术'); return; } const applied = []; if (opening) applied.push('开场白'); if (product) applied.push('产品介绍'); if (welfare) applied.push('福利推广'); DigitalHumanToast.success(`话术已应用: ${applied.join('、')}`); } // ==================== 评论处理(核心:9智能体协同) ==================== async function sendComment() { const input = $('#dhCommentInput'); const comment = input?.value?.trim(); if (!comment) { DigitalHumanToast.warning('请输入评论内容'); return; } if (!AppState.isLive) { // 在非直播状态也可以测试评论处理 console.log('[数字人直播] 非直播状态,测试评论处理'); } // 清空输入 input.value = ''; // 添加用户评论到列表 addCommentToList({ text: comment, username: '测试用户', timestamp: new Date().toISOString() }, 'user-comment'); // 调用后端智能评论处理 await processComment(comment); } async function autoProcessComment(commentText) { try { const result = await digitalHumanAPI.processComment( commentText, AppState.currentPlatform, { stream_id: AppState.streamId, is_live: AppState.isLive } ); const reply = result.reply || result.response || result.message; const agentChain = result.agent_chain || result.pipeline || []; addCommentToList({ text: reply, username: 'AI数字人', timestamp: new Date().toISOString() }, 'ai-reply', agentChain); } catch (error) { console.error('[数字人直播] 自动处理评论失败:', error); } } async function processComment(commentText) { try { DigitalHumanLoading.show('AI智能体处理中...', 'dhCommentSection'); const result = await digitalHumanAPI.processComment( commentText, AppState.currentPlatform, { stream_id: AppState.streamId, is_live: AppState.isLive, user_id: `user_${Date.now()}` } ); // 解析ECS后端实际返回格式 const reply = result.reply_text || result.reply || result.response || '感谢您的评论!'; // 构建智能体处理链路 const agentChain = []; if (result.agent_responses) { const ar = result.agent_responses; if (ar.emotion_agent) agentChain.push({ name: '情感识别', type: 'emotion', agent: ar.emotion_agent }); if (ar.response_agent) agentChain.push({ name: '意图处理', type: 'intent', agent: ar.response_agent }); if (ar.digital_human_agent) agentChain.push({ name: '数字人生成', type: 'digital_human', agent: ar.digital_human_agent }); } else if (result.agent_chain) { agentChain.push(...result.agent_chain); } // 情感和意图信息 const emotion = result.emotion_analysis?.emotion_type || result.emotion || 'neutral'; const intent = result.intent_classification?.intent_type || result.intent || 'general'; // 添加到评论列表 addCommentToList( { text: reply, username: 'AI数字人', timestamp: new Date().toISOString() }, 'ai-reply', agentChain, { emotion, intent } ); // 播放提示音 playNotificationSound(); } catch (error) { console.error('[数字人直播] 评论处理失败:', error); // 降级:生成模拟回复 const fallbackReply = generateFallbackReply(commentText); addCommentToList( { text: fallbackReply, username: 'AI数字人(离线)', timestamp: new Date().toISOString() }, 'ai-reply', [{ name: '离线模式', type: 'fallback' }], { emotion: 'neutral', intent: 'fallback' } ); DigitalHumanToast.warning('后端处理超时,使用离线回复'); } finally { DigitalHumanLoading.hide('dhCommentSection'); } } function addCommentToList(comment, type, agentChain = [], meta = {}) { const list = $('#dhCommentList'); if (!list) return; const time = comment.timestamp ? formatRelativeTime(comment.timestamp) : '刚刚'; const item = document.createElement('div'); item.className = `dh-comment-item ${type} dh-animate-in`; let agentHTML = ''; if (agentChain && agentChain.length > 0) { agentHTML = `
${agentChain.map((agent, i) => ` ${i > 0 ? '→' : ''} ${agent.name || agent} `).join('')}
`; } let metaHTML = ''; if (type === 'ai-reply' && meta.emotion) { metaHTML = `
情感: ${getEmotionLabel(meta.emotion)} 意图: ${getIntentLabel(meta.intent)}
`; } item.innerHTML = `
${escapeHTML(comment.username || '匿名用户')} ${time}
${metaHTML}
${escapeHTML(comment.text)}
${agentHTML} `; list.insertBefore(item, list.firstChild); // 限制显示数量 while (list.children.length > 100) { list.removeChild(list.lastChild); } AppState.commentCount++; updateStatDisplay(); } function generateFallbackReply(comment) { const replies = [ '感谢您的留言,我们的客服会尽快回复您!', '您的问题已收到,正在为您查询相关信息...', '感谢关注!如有产品相关问题,欢迎随时咨询。', '您的建议对我们非常重要,感谢支持!' ]; return replies[Math.floor(Math.random() * replies.length)]; } // ==================== 合规检查 ==================== async function runComplianceCheck() { const content = '欢迎来到直播间,今天给大家带来超值好物,价格非常优惠!'; try { DigitalHumanLoading.show('合规检查中...'); const result = await digitalHumanAPI.complianceCheck(content, AppState.currentPlatform); if (result.is_compliant || result.compliant) { DigitalHumanToast.success('合规检查通过,内容符合规范!'); } else { const words = result.sensitive_words_found || result.sensitive_words || []; DigitalHumanToast.warning(`发现敏感词: ${words.join(', ')}`); } } catch (error) { DigitalHumanToast.error('合规检查失败: ' + error.message); } finally { DigitalHumanLoading.hide(); } } // ==================== 数据同步 ==================== async function syncLiveData() { try { DigitalHumanLoading.show('正在同步数据...'); const result = await digitalHumanAPI.syncData(); DigitalHumanToast.success('数据同步完成!'); console.log('[数字人直播] 同步结果:', result); } catch (error) { DigitalHumanToast.error('数据同步失败: ' + error.message); } finally { DigitalHumanLoading.hide(); } } async function loadLiveStats() { try { const result = await digitalHumanAPI.getLiveStats(); if (result) { AppState.viewers = result.viewers || result.active_viewers || 0; AppState.likes = result.likes || result.total_likes || 0; AppState.commentCount = result.comment_count || result.comments || 0; AppState.conversionRate = result.conversion_rate || 0; updateStatDisplay(); } } catch (error) { console.warn('[数字人直播] 获取统计数据失败:', error.message); } } function updateStatDisplay() { // 顶部统计卡片 const viewersEl = $('#dhStatViewers'); const likesEl = $('#dhStatLikes'); const commentsEl = $('#dhStatComments'); const conversionEl = $('#dhStatConversion'); const activeEl = $('#dhStatActive'); if (viewersEl) viewersEl.textContent = formatNumber(AppState.viewers); if (likesEl) likesEl.textContent = formatNumber(AppState.likes); if (commentsEl) commentsEl.textContent = AppState.commentCount; if (conversionEl) conversionEl.textContent = AppState.conversionRate + '%'; if (activeEl) activeEl.textContent = AppState.isLive ? '1' : '0'; // 右侧栏实时数据 const rtViewers = $('#dhRtViewers'); const rtLikes = $('#dhRtLikes'); const rtComments = $('#dhRtComments'); const rtConversion = $('#dhRtConversion'); if (rtViewers) rtViewers.textContent = formatNumber(AppState.viewers); if (rtLikes) rtLikes.textContent = formatNumber(AppState.likes); if (rtComments) rtComments.textContent = AppState.commentCount; if (rtConversion) rtConversion.textContent = AppState.conversionRate + '%'; // 更新直播时长 updateLiveDuration(); } function updateLiveDuration() { const durationEl = $('#dhRtDuration'); if (!durationEl || !AppState.isLive) return; // 使用本地计时(startLive时记录的时间) if (!AppState._liveStartTime) AppState._liveStartTime = Date.now(); const elapsed = Math.floor((Date.now() - AppState._liveStartTime) / 1000); const h = Math.floor(elapsed / 3600); const m = Math.floor((elapsed % 3600) / 60); const s = elapsed % 60; durationEl.textContent = `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`; } function startStatsPolling() { if (AppState.statsTimer) clearInterval(AppState.statsTimer); AppState.statsTimer = setInterval(() => { loadLiveStats(); updateLiveDuration(); }, 5000); } // ==================== 内容生成 ==================== async function generateContent() { DigitalHumanToast.info('正在生成短视频内容...(功能开发中)'); } // ==================== 平台切换 ==================== async function switchPlatform(platform) { AppState.currentPlatform = platform; // 更新平台列表UI $$('.dh-platform-item').forEach(item => { item.classList.toggle('active', item.dataset.platform === platform); }); // 重新加载话术模板 await loadTalkTemplates(); DigitalHumanToast.info(`已切换到 ${getPlatformDisplayName(platform)}`); } // ==================== 播放提示音 ==================== function playNotificationSound() { try { const ctx = new (window.AudioContext || window.webkitAudioContext)(); const oscillator = ctx.createOscillator(); const gainNode = ctx.createGain(); oscillator.connect(gainNode); gainNode.connect(ctx.destination); oscillator.frequency.value = 800; oscillator.type = 'sine'; gainNode.gain.value = 0.1; oscillator.start(); gainNode.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.15); oscillator.stop(ctx.currentTime + 0.15); } catch (e) { // 忽略音频播放错误 } } // ==================== 工具函数 ==================== function getPlatformDisplayName(platform) { const names = { 'douyin': '抖音', 'wechat_video': '视频号', 'taobao': '淘宝', 'kuaishou': '快手' }; return names[platform] || platform; } function getEmotionLabel(emotion) { const labels = { 'neutral': '中立', 'happy': '开心', 'excited': '兴奋', 'frustrated': '沮丧', 'angry': '愤怒', 'sad': '悲伤', 'surprised': '惊讶', 'concerned': '关切', 'curious': '好奇', 'satisfied': '满意', 'dissatisfied': '不满', 'confused': '困惑', 'anxious': '焦虑' }; return labels[emotion] || emotion || '未知'; } function getIntentLabel(intent) { const labels = { 'product_price': '产品价格咨询', 'product_quality': '产品质量咨询', 'product_inquiry': '产品询问', 'technical_issue': '技术问题', 'order_inquiry': '订单查询', 'order_status': '订单状态', 'general_chat': '闲聊互动', 'complaint': '投诉建议', 'purchase_intent': '购买意向', 'after_sales': '售后服务', 'fallback': '离线兜底' }; return labels[intent] || intent || '通用'; } function formatNumber(num) { if (num >= 10000) return (num / 10000).toFixed(1) + '万'; if (num >= 1000) return (num / 1000).toFixed(1) + 'K'; return String(num); } function formatRelativeTime(timestamp) { const diff = Date.now() - new Date(timestamp).getTime(); if (diff < 60000) return '刚刚'; if (diff < 3600000) return Math.floor(diff / 60000) + '分钟前'; if (diff < 86400000) return Math.floor(diff / 3600000) + '小时前'; return new Date(timestamp).toLocaleDateString(); } function escapeHTML(str) { if (!str) return ''; const div = document.createElement('div'); div.textContent = str; return div.innerHTML; } // ==================== 暴露全局API ==================== window.DigitalHumanLive = { init, startLive, stopLive, switchToHuman, sendComment, processComment, getState: () => AppState }; // ==================== 页面加载完成后初始化 ==================== document.addEventListener('DOMContentLoaded', init); console.log('[数字人直播] 主控逻辑已加载'); })();