跳转到内容

迁移指南(数字人 → 新大屏项目) ​

适用场景:把现有数字人(前端 bigscreen 的 vis-assistant + 后端 ruoyi-aihuman-backend)整体迁移到另一个大屏项目。

最后更新:2026-09-28

一、总体结论 ​

端迁移难度说明
后端低(直接迁移)引入模块 + 补齐依赖与配置即可,无业务代码侵入;全部状态走 Redis,无需建表。
前端中(有代码侵入)需要「复制组件目录 + 注册能力中心插件 + 挂载助手组件 + 注入 clientTools + 在业务组件声明原子能力」。

二、后端迁移(直接迁移即可) ​

2.1 引入的 Maven 模块 ​

把以下模块作为依赖引入新后端(或整体拷贝模块目录):

  • ruoyi-aihuman-core:对话历史、工具挂起等核心能力 【暂未使用,按需迁移】
  • ruoyi-aihuman-business:流式 AI 对话 /digital-human/agent/*、工具结果回传 【暂未使用,按需迁移;前端对话使用的是业务后台 /ai/*】
  • ruoyi-aihuman-asr:语音转文本 /digital-human/asr/recognize
  • ruoyi-aihuman-nlu:语义识别 /digital-human/nlu/recognize
  • ruoyi-aihuman-tts:文本转语音 流式双工 WebSocket /digital-human/tts/aliyunStream/ws(实时播报统一采用);NLS 非流式 /digital-human/tts/aliyun* 即将弃用、按需迁移;百炼版 /digital-human/tts/qwen/download(生成预设语音 mp3)保留
  • ruoyi-aihuman-pairing:扫码配对 /digital-human/pairing/*、配对 WebSocket /ws/digital-human

完整端点见 其他注意事项 · 完整 API 端点清单。

2.2 必须补齐的依赖与配置 ​

类别具体项
配置前缀aihuman.*(ASR siliconflow.api-key、NLU siliconflow / zhipu、TTS aliyun.* 与 aliyun.realtime.*);aihuman.llm.* / aihuman.chat.* / aihuman.prompt.* / aihuman.client-tools.* 服务于暂未使用的内置 LLM 对话(前端对话走业务后台),按需配置
文件上传spring.servlet.multipart.*(ASR 为 multipart 上传)
安全放行SecurityConfig 放行:/digital-human/**、/ws/digital-human、/digital-human/tts/**
Bean提供 RestTemplate Bean(后端内部 HTTP 调用用)
包扫描@MapperScan("com.ruoyi.**.mapper")
线程池ThreadPoolConfig(core=50 / max=200 / queue=1000)
存储Redis 必需(配对状态;对话历史、工具挂起属暂未使用的内置 LLM 对话)。无需 MySQL 建表
密钥SiliconFlow API Key(配置在 aihuman.asr.siliconflow.api-key;aihuman.llm.openai.api-key 属暂未使用的内置 LLM 对话,按需配置)

2.3 上线注意 ​

  • SSE 缓冲:Controller 必须用 FlushingSseEmitter,且响应头加 X-Accel-Buffering: no(Nginx 代理时必需)——用于内置 LLM 对话 SSE(暂未使用)。
  • 本后端不依赖 MySQL,迁移新项目时无需做数据库迁移。

三、前端迁移(重点:组件引入 + 代码侵入) ​

3.1 需要复制的文件 / 目录 ​

路径作用
src/components/vis-assistant/(整目录)数字人助手 UI + 工具函数 + 演示脚本数据
src/components/Avatar/Core/(整目录)数字人容器 Avatar.vue + UE 像素流 UePixelStreaming.vue
src/assistant/(整目录)AI 能力注册中心(actions/ 语义映射 + orchestrations/ 演示编排)
public/audios/预生成 mp3(本地演示音频,若有)
public/ue-bridge.js仅「跨域 iframe 老方案」需要,自集成模式可不要
views/mobile/RemotePanel.vue、views/mobile/MobileMessageItem.vue移动端遥控(可选,要手机遥控才复制)
stores/mobile.js、composables/mobile/useWebSocket.js、composables/useSuggestedQuestions.js移动端依赖(可选)
下列 store / composable(若目标项目没有需一并迁移或适配)stores/modules/settings(currentMenu)、stores/zBaseModalStore、composables/useCloseAllChildModals、useModalStore

vis-assistant 内部关键文件一览:

  • VisAssistant.vue:UI 装配层(面板 / 数字人 / 气泡 / 停止播报)
  • useAssistantCore.js:会话组装层(组合根,约 410 行)—— 解构入参、创建共享状态、创建并拼装 core/ 各模块、对外暴露 API
  • core/:会话各职责模块(拆分自 useAssistantCore.js,每个文件一个职责)
    • config.js / state.js / session.js / duplex.js / messages.js:配置常量、响应式状态、跨模块共享状态、双工投喂状态、消息列表
    • speech.js:TTS 播放编排(整段序列 / 增量队列 / 取消 / 停止播报)
    • aiChatStream.js:智能交互 SSE + 边收边播 + 双工节流投喂
    • expertChat.js:专家问答 SSE 事件解析;clientTools.js:工具执行与流式消息固化
    • demoTour.js:系统导览(分段播报 / 打字机 / 预取 / 预投喂)
    • connection.js:WebSocket 连接、心跳重连、配对码、移动端指令
    • ttsText.js / thinkFilter.js / sseParse.js / utils.js:纯工具
    • 详见前端项目结构 → 第三节
  • utils/audio.js:前端音频播放(音频一律前端播放)
  • utils/uePcm.js、utils/ueSound.js:UE 口型驱动(PCM 重采样 + 指令下发)
  • utils/sse.js、utils/network.js:SSE / 网络封装
  • data/demoQA.js:内置演示脚本(demoList 同时生成「演示指令」按钮)
  • data/demoFuncs.js:演示模式工具函数(注入 clientTools)
  • data/demoBus.js:轻量事件总线(系统级广播:打断信号 demo-interrupt、open-pipe-list / hideWindows 等地图事件)

3.2 需要新增的依赖(package.json) ​

数字人专属依赖(vue / element-plus / pinia / axios / @vueuse/core 假设目标项目已有):

依赖用途
@epicgames-ps/lib-pixelstreamingfrontend-ue5.4UE 像素流(版本必须与 UE 推流端一致,可选 -ue5.3/-ue5.4/-ue5.5)
fuse.jsdemoQA.js 模糊搜索匹配指令
marked + dompurifyAI 回复 Markdown 渲染 + 消毒
qrcode扫码配对二维码生成

安装命令示例:

bash
pnpm add @epicgames-ps/lib-pixelstreamingfrontend-ue5.4 fuse.js marked dompurify qrcode

3.3 环境变量(.env.development / .env.production / .env.staging) ​

bash
# 后端 AI 接口 base(对应 VITE_APP_AI_API)
VITE_APP_AI_API = 'http://localhost:8080'
# WebSocket host(协议随页面自动 ws/wss,仅填 host)
VITE_AI_APP_HOST = 'localhost:8080'
# UE 信令地址(配了走 UE 自集成,注释掉回退 iframe)
VITE_APP_UE_SIGNALLING_URL = 'ws://localhost:91'
# iframe 兜底地址(旧 React 数字人页面)
VITE_APP_AVATAR_URL = 'http://localhost:91/'
# 移动端入口(可选,默认 origin + #/mobile)
VITE_MOBILE_URL = 'http://localhost:8080/#/mobile'

大屏页里这样取:apiBase = import.meta.env.VITE_APP_AI_API;wsUrl = ${协议}//${VITE_AI_APP_HOST}/ws/digital-human;mobileUrl 同理。

3.4 代码侵入点(必须改目标项目) ​

3.4.1 注册能力中心插件(src/main.js) ​

js
import '@/assistant' // AI 能力注册表:自动 import.meta.glob 注册 actions/ 与 orchestrations/ 下所有插件

3.4.2 主大屏页挂载 <VisAssistant> + 悬浮按钮 + 注入 clientTools ​

参考现有 views/home/index.vue:

vue
<template v-if="assistantEverOpened">
  <VisAssistant
    v-show="showAssistant"
    :api-base="apiBase"
    :ws-url="wsUrl"
    :mobile-url="mobileUrl"
    :client-tools="clientTools"
    @close="showAssistant = false"
  />
</template>
<!-- 另加一个悬浮 FAB 按钮控制 showAssistant 显隐 -->

clientTools 必须由目标大屏页根据自身地图能力实现(弹框里「飞向某点」「定位」等指令由大屏页执行),不能直接照搬:

js
const clientTools = {
  mapLocate: async (args) => { /* 目标项目真实飞点逻辑 */ },
  cameraFlyTo: async (args) => { /* 目标项目真实镜头逻辑 */ },
  closeAssistant: () => { /* 关闭助手面板 */ },
  ...demoFuncList, // 演示模式入口(来自 data/demoFuncs.js)
}

3.4.3 业务组件声明「原子能力」(每处 1 行) ​

数字人要能操作各业务模块,需在对应业务组件里声明 useAssistantAction(目标项目业务模块不同则改写 actionId / handler):

文件(示例,对标现有 bigscreen)声明的 actionId
views/home/FooterBox/index.vuesystem.switchModule(切换底部菜单)
views/device/MenuBox、device/leftWidgets/LeftWidget1/Left1Contentdevice.*
views/hazard/MenuBox、hazard/mainBox/totalViewhazard.*
views/inspection/realTimeOverviewinspection.*
views/pipeLine/totalView、pipeLine/statusDistributionpipeLine.*
views/construct/MenuBox、construct/leftWidgets/LeftWidget1construct.*
views/roam/leftWidgets/LeftWidget1/Left1Contentroam.start

AI 语义映射放在 src/assistant/actions/*.js,演示编排放在 src/assistant/orchestrations/*.js——这两类文件随组件迁移即可,无需改业务组件。

3.4.4 依赖的 store / composable ​

  • stores/modules/settings(currentMenu):切模块时序依赖
  • stores/zBaseModalStore / composables/useCloseAllChildModals:弹框开关
  • useModalStore(gallery 编排用)
  • stores/mobile + composables/mobile/*(仅移动端遥控)

若目标项目已有等价实现,改引用即可;没有则把上述文件一并复制。

3.5 移动端遥控(可选) ​

要支持手机扫码遥控,还需迁移:views/mobile/RemotePanel.vue、views/mobile/MobileMessageItem.vue、stores/mobile.js、composables/mobile/useWebSocket.js、composables/useSuggestedQuestions.js。它们依赖后端 /ws/digital-human 配对通道与 /digitalHuman/question/list 「猜你想问」接口。


四、迁移校验清单 ​

  • [ ] 后端在用模块(ruoyi-aihuman-nlu / -asr / -tts / -pairing)已引入,aihuman.asr.* / aihuman.nlu.* / aihuman.tts.* 配置、RestTemplate、@MapperScan、线程池、SecurityConfig 放行已补齐(-core / -business(内置 LLM 对话)暂未使用,按需引入)
  • [ ] Redis 可用,SiliconFlow Key 已配置(两处)
  • [ ] Nginx 已加 X-Accel-Buffering: no
  • [ ] 前端已复制 vis-assistant/、Avatar/Core/、assistant/ 三目录
  • [ ] package.json 已加 pixelstreamingfrontend-ue5.4 / fuse.js / marked / dompurify / qrcode
  • [ ] .env.* 已配 VITE_APP_AI_API / VITE_AI_APP_HOST / VITE_APP_UE_SIGNALLING_URL 等
  • [ ] main.js 已 import '@/assistant'
  • [ ] 主大屏页已挂载 <VisAssistant> 并实现了 clientTools
  • [ ] 目标业务组件已按实际模块声明 useAssistantAction
  • [ ] (可选)移动端页面与 store 已迁移

五、常见坑 ​

  1. clientTools 不能照搬:弹框内飞点 / 定位依赖目标项目真实地图能力,未实现则助手能对话但点不动地图。
  2. UE 像素流库版本必须匹配 UE 推流端,否则信令握手协议版本不符、一直连不上。
  3. actionId 与业务组件一一对应:目标业务模块改名 / 拆分后,需同步改 actions/*.js 与组件内 useAssistantAction 声明。
  4. 后端 SSE 必须 FlushingSseEmitter + X-Accel-Buffering: no,否则流式问答卡很久才出字。
  5. 数字人「音频一律前端播放」:UE 只驱动口型,不负责出声,迁移时不要让 UE 侧也播放导致回声,否则会有以下问题:
    • UE的声音比系统音量小,在线语音与内置音频,一听就能明显感觉出来;
    • 前端发声,便于控制数字人开始、结束,因为系统有演示模式;
    • 前端发声,通过音频流不断推送给UE,可以实现相同的效果,UE端不用单独配置音频接口前缀等环境变量;

数字人「小慧」项目文档