/**
* 数字人直播系统 - 主控制逻辑
* 对接 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 = `
`;
}
let metaHTML = '';
if (type === 'ai-reply' && meta.emotion) {
metaHTML = `
`;
}
item.innerHTML = `
${metaHTML}
${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('[数字人直播] 主控逻辑已加载');
})();