基于 LiveTalking 的双屏数字人产品讲解系统设计实践

1 张 GPU 卡 + 1 台 NUC → 双屏独立数字人讲解 + PPT 叠加 + 观众互动问答

📅 2026-06-10 ⏱️ 15分钟 👤 数智研发部
LiveTalking 数字人 MuseTalk RAG WebGL FunASR 架构设计

📑 目录

  1. 背景与需求
  2. 整体架构设计
  3. 画面叠加方案:数字人浮在 PPT 上
  4. 极致精简:1 张卡 + 1 台 NUC 搞定
  5. 讲解脚本与 PPT 联动翻页
  6. 观众互动问答:FunASR + RAG
  7. 部署方案:展厅固定 + 移动展示
  8. 开发路线图
  9. 踩坑与经验
  10. 总结

1. 背景与需求

企业展厅和产品发布会上,传统的 PPT 讲解依赖真人讲解员,存在排班成本高、讲解水平参差不齐、无法 7×24 运行等问题。随着实时数字人技术的成熟,我们尝试用 AI 数字人替代真人讲解员,实现产品 PPT 的自动化讲解。

核心需求:

💡 关键约束:GPU 服务器上已部署 DeepSeek、Qwen 等大模型,8 张 A100 只能挪出 1 张给数字人用。如何在 1 张卡上跑通双屏数字人?这是本文的核心设计挑战。

2. 整体架构设计

经过多轮方案对比,最终确定了 "NUC 控制中心 + A100 单卡推理" 的精简架构:

  ┌─────────────────────────────────────────────────────────────┐
  │  A100 服务器(仅占用 1 张卡,其余 7 张留给大模型)            │
  │                                                             │
  │  GPU 7(80GB)                                              │
  │  ┌───────────────────────────────────────────────────────┐  │
  │  │  LiveTalking + MuseTalk          ≈ 6GB               │  │
  │  │  ├── session_1 → 数字人 A(屏1)                      │  │
  │  │  └── session_2 → 数字人 B(屏2)                      │  │
  │  │  CosyVoice TTS                   ≈ 3GB               │  │
  │  │  合计 ≈ 9GB / 80GB                                    │  │
  │  └───────────────────────────────────────────────────────┘  │
  │  GPU 0-6: 其他大模型(不动)                                │
  └─────────────────────────┬───────────────────────────────────┘
                            │ 局域网(WebRTC)
  ┌─────────────────────────▼───────────────────────────────────┐
  │  NUC(i9 / 16GB / Ubuntu)                                  │
  │  ├── 调度引擎 + WebSocket + FunASR CPU + Nginx  ≈ 3GB      │
  │  ├── 浏览器标签页① → HDMI  → 大屏1(数字人A + PPT叠加)     │
  │  └── 浏览器标签页② → Type-C → 大屏2(数字人B + PPT叠加)    │
  │  内存合计 ≈ 6GB / 16GB                                      │
  └─────────────────────────────────────────────────────────────┘

为什么只需 1 个 LiveTalking 实例?

这是方案精简的关键洞察:NUC 是一台电脑接两块屏,不是两台电脑。LiveTalking 天然支持多会话(--max_session),一个进程可以同时服务多个 WebRTC 连接。两个浏览器标签页各自建立独立的 session,共享同一套模型权重,不额外占显存。

类比:就像一个视频网站服务器同时给 100 个用户推流,LiveTalking 也是同样的道理——模型只加载一次,推理时按 session 分发。

技术栈选型

层级选型选型理由
数字人驱动LiveTalking + MuseTalk开源、实时、支持多会话、中文效果好
语音合成CosyVoice支持声音克隆、中文自然度高
PPT 渲染reveal.jsWeb 原生、支持动画、WebSocket 可控
绿幕抠像WebGL ShaderGPU 加速、零延迟、浏览器原生
语音识别FunASR(CPU 模式)Nano 模型仅 500MB 内存、1.5x 实时
知识问答RAG(已有部署)直接调 API,不额外占算力
调度引擎Python asyncio异步并发、双屏独立编排

3. 画面叠加方案:数字人浮在 PPT 上

传统方案是数字人和 PPT 各占半屏,效果生硬。我们采用全屏叠加——数字人以透明前景的形式浮在 PPT 页面上方,类似直播带货的画中画效果。

分层结构

  浏览器全屏(1920×1080)
  ┌─────────────────────────────┐
  │ z:1  ┌───────────────────┐  │
  │      │   PPT 背景层       │  │  ← reveal.js 渲染
  │      │   (全屏铺满)       │  │
  │      └───────────────────┘  │
  │ z:2  ┌──────────┐          │
  │      │ 数字人前景 │          │  ← WebRTC 视频流
  │      │(绿幕抠像) │          │     位置可配置
  │      └──────────┘          │
  │ z:3  ┌───────────────────┐  │
  │      │   实时字幕条       │  │  ← ASR 转写
  │      └───────────────────┘  │
  └─────────────────────────────┘

绿幕抠像:WebGL Shader 实现

LiveTalking 支持输出绿幕背景的视频流。浏览器端通过 WebGL Fragment Shader 实时做绿幕透明处理,性能远优于逐像素 Canvas 操作:

precision mediump float;
uniform sampler2D u_video;   // 数字人视频(绿幕背景)
uniform sampler2D u_ppt;     // PPT 背景
varying vec2 v_texCoord;

void main() {
    vec4 video = texture2D(u_video, v_texCoord);
    vec4 ppt = texture2D(u_ppt, v_texCoord);

    // 在 HSV 色彩空间检测绿色
    float maxC = max(video.r, max(video.g, video.b));
    float minC = min(video.r, min(video.g, video.b));
    float diff = maxC - minC;

    float hue = 0.0;
    if (diff > 0.01 && maxC == video.g) {
        hue = 60.0 * (2.0 + (video.b - video.r) / diff);
    }

    // 绿幕区域 → 显示 PPT 背景
    float isGreen = step(60.0, hue) * step(hue, 180.0)
                   * step(0.15, diff) * smoothstep(0.25, 0.45, video.g);

    gl_FragColor = mix(ppt, video, 1.0 - isGreen);
}

数字人位置动态调整

根据 PPT 内容动态调整数字人位置,避免遮挡关键信息:

// 讲解脚本中定义每页的数字人位置
{
    "slide": 3,
    "title": "数据治理体系架构",
    "narration": "请看这张架构图...",
    "avatar_position": "right-bottom",  // 不遮挡左侧架构图
    "avatar_size": "medium"
}

4. 极致精简:1 张卡 + 1 台 NUC 搞定

这是本方案最核心的设计决策。在算力紧张的情况下,我们通过三个手段把资源占用压到最低:

手段一:LiveTalking 多会话共享

LiveTalking 的 --max_session 参数允许单个进程同时服务多个 WebRTC 会话。两个数字人共享同一套 MuseTalk 模型权重,显存占用从 12GB(两个独立进程)降到 6GB(一个进程两路会话)。

手段二:FunASR 跑 CPU

FunASR Nano 模型专门为 CPU 优化:INT8 量化后仅 100MB,内存占用 500MB 以下,识别速度达 1.5 倍实时。NUC 的 i9 处理器完全够用,零 GPU 占用。

手段三:TTS 与数字人同卡

CosyVoice 占 2-4GB 显存,和数字人的 6GB 放在同一张 A100 80GB 卡上,总共才用 9GB,对大模型的运行几乎无影响。

✅ 最终资源占用:
• A100 GPU 7:9GB / 80GB(仅占 11%)
• NUC 内存:6GB / 16GB(仅占 37%)
• 其余 7 张 GPU 卡:完全不受影响

NUC 服务分布

服务端口内存说明
Nginx80~50MBPPT HTML 托管 + API 反向代理
WebSocket Server9090~100MBPPT 翻页控制指令推送
Orchestrator8080~300MB双屏讲解调度引擎
FunASR10095~500MB语音识别(CPU 推理)
Chromium × 2—~3GB两个全屏 kiosk 标签页

5. 讲解脚本与 PPT 联动翻页

联动翻页的核心思路:PPT 转成 Web 页面,用同一个调度引擎同时控制数字人和 PPT。

讲解脚本格式

采用 JSON 格式定义每页的讲解内容、数字人行为和问答策略:

{
    "slides": [
        {
            "id": 1,
            "title": "产品概述",
            "narration": "欢迎来到我们的产品展示...",
            "avatar_position": "right-bottom",
            "avatar_size": "medium",
            "post_qa": true,
            "qa_context": "产品概述"
        },
        {
            "id": 2,
            "title": "核心架构",
            "narration": "接下来介绍核心架构设计...",
            "avatar_position": "left-bottom",
            "post_qa": true,
            "qa_context": "技术架构"
        }
    ]
}

调度引擎核心流程

async def play_slide(orchestrator, slide):
    """单页讲解流程"""
    # 1. PPT 翻页(通过 WebSocket 推送到浏览器)
    await orchestrator.goto_slide(slide["id"])
    await asyncio.sleep(0.8)  # 等翻页动画完成

    # 2. 调整数字人位置
    await orchestrator.position_avatar(slide["avatar_position"])

    # 3. 数字人开始讲解(调用 LiveTalking /human API)
    orchestrator.narrate(slide["narration"])
    await orchestrator.wait_narration_end()

    # 4. 可选:进入观众问答
    if slide.get("post_qa"):
        orchestrator.narrate("大家有什么问题吗?")
        question = await orchestrator.listen(timeout=45)
        if question:
            answer = orchestrator.call_rag(question, slide["qa_context"])
            orchestrator.narrate(answer)

    # 5. 自动翻到下一页

LiveTalking API 调用

接口说明
POST /offerWebRTC 协商,获取数字人视频流
POST /human发送文字驱动数字人说话(echo=播报 / chat=对话)
POST /interrupt_talk打断数字人当前说话
POST /set_audiotype切换数字人播放的自定义视频

6. 观众互动问答:FunASR + RAG

互动问答是数字人讲解系统的"灵魂"——让展示从单向播报变成双向对话。

问答流程

观众提问 → 麦克风采集 → FunASR 语音识别(CPU) → 文字转写
                                                      ↓
数字人回答 ← TTS 语音合成 ← RAG 知识库生成回答 ← 问题 + 上下文

问答策略设计

策略说明
主动开启每页讲完后,数字人询问"大家有什么问题吗?"
等待超时等待 30-60 秒无提问,自动翻到下一页
追问支持回答后可再给一次追问机会(超时 20 秒)
打断机制数字人讲解中可通过控制台打断,进入问答
兜底回答RAG 无法回答时,回复"这个问题我记录下来,稍后由专家解答"

FunASR CPU 部署

# FunASR Nano 模型,CPU 推理,INT8 量化
# 模型仅 100MB,内存占用 ~500MB,识别速度 1.5x 实时
cd /opt/FunASR
python -m funasr.bin.asr_server \
  --model-dir FunAudioLLM/Fun-ASR-Nano-2512 \
  --device cpu \
  --port 10095
⚠️ 收音环境很重要:展厅噪音大,建议使用指向性麦克风或麦克风阵列,配合降噪算法。实测中,噪音导致的误识别是最常见的问题。

7. 部署方案:展厅固定 + 移动展示

展厅固定部署

┌──────────────────────────────────────────┐
│                 展厅                       │
│                                          │
│   ┌──────────┐          ┌──────────┐    │
│   │  大屏 1   │          │  大屏 2   │    │
│   │  产品线 A  │          │  产品线 B  │    │
│   └─────┬────┘          └────┬─────┘    │
│         │HDMI                │Type-C     │
│   ┌─────▼────────────────────▼─────┐    │
│   │         NUC(藏在电视后面)       │    │
│   └──────────────┬─────────────────┘    │
│                  │ 网线                   │
│              ┌───▼───┐                   │
│              │ 交换机 │                   │
│              └───┬───┘                   │
│                  │ 局域网/专线             │
│          ┌───────▼───────┐               │
│          │ 机房 A100 服务器│               │
│          └───────────────┘               │
│                                          │
│   🎤 麦克风1          🎤 麦克风2          │
└──────────────────────────────────────────┘

移动部署

移动部署只需搬运 NUC + 两块大屏 + 麦克风,A100 留在机房通过网络连接。搭建时间约 15 分钟:

开机自启动

配置 systemd 服务,NUC 开机后自动启动全部服务和双屏浏览器:

# start.sh — 一键启动所有服务
#!/bin/bash

# 1. FunASR(CPU 模式)
cd /opt/FunASR && python -m funasr.bin.asr_server \
  --model-dir FunAudioLLM/Fun-ASR-Nano-2512 \
  --device cpu --port 10095 &

# 2. WebSocket Server + 调度引擎
cd /opt/digital-human && python orchestrator.py &

# 3. Nginx
sudo systemctl start nginx

# 4. 双屏浏览器(kiosk 全屏模式)
chromium-browser --kiosk http://localhost/screen1.html &
sleep 2
chromium-browser --kiosk --new-window http://localhost/screen2.html &

8. 开发路线图

阶段任务周期产出
P0A100 部署 LiveTalking + CosyVoice3-5 天单屏数字人跑通
P1绿幕录制 avatar + 声音克隆3-5 天数字人形象 + 统一音色
P2PPT 转 reveal.js + 叠加页面开发1 周Web 幻灯片 + 抠像叠加
P3NUC 部署:FunASR + 调度引擎 + 双屏1 周双屏自动讲解
P4讲解脚本编写 + PPT 联动翻页1 周完整讲解流程
P5RAG 对接 + 问答流程1 周观众互动能力
P6双屏联调 + 稳定性测试1 周可交付系统
总周期:约 5-6 周。核心瓶颈不在技术,而在 avatar 录制(需要真人 + 绿幕场地 + 灯光调试)和讲解脚本内容打磨。

9. 踩坑与经验

9.1 绿幕灯光比设备更重要

一开始用普通绿色布料 + 顶灯,抠像边缘有明显绿边。换成专业的绿幕柔光箱 + 均匀打光后,效果立刻提升一个档次。灯光均匀度 > 绿幕材质 > 抠像算法。

9.2 FunASR CPU 模式够用但要调参

Nano 模型在安静环境下识别率很高,但展厅噪音大。解决方案:用指向性麦克风 + VAD(语音活动检测)过滤非人声段 + 在脚本中设置"请对着麦克风提问"的引导语。

9.3 reveal.js 动画与 PPT 的差异

PowerPoint 的复杂动画(如渐变擦除、3D 旋转)在 reveal.js 中无法完美还原。建议:简化动画效果,用 CSS transition 替代复杂动画,或者干脆用静态图 + 数字人口述来表达。

9.4 WebRTC 的网络要求

WebRTC 对网络延迟敏感。展厅场景下 NUC 和 A100 在同一局域网,延迟 <1ms,完全没问题。移动部署时如果走 VPN 跨网段,延迟可能到 20-50ms,数字人会有轻微卡顿。建议移动场景也用专线或同局域网。

9.5 数字人"讲完"的判定

最简单的方案是根据 TTS 生成的音频时长来估算讲完时间。更精确的方案是监听 LiveTalking 的音频播放完成回调。不要用固定定时器——不同文案长度差异很大。

10. 总结

这套方案的核心价值在于极致的资源利用效率:

技术选型上,LiveTalking 的多会话能力是方案可行的基础,FunASR 的 CPU 模式解放了 GPU 资源,WebGL Shader 实现了零延迟的绿幕抠像叠加。这些开源工具的组合,让"1 张卡 + 1 个盒子"的精简架构成为可能。

适用场景:企业展厅产品讲解、发布会数字人主持、会议室智能导览、展会互动展示。只要有一台 GPU 服务器(哪怕只空出一张卡)和一台小电脑,就能跑起来。

参考资料

📖 更多文章

1/6