外观
迁移指南(数字人 → 新大屏项目)
适用场景:把现有数字人(前端
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/recognizeruoyi-aihuman-nlu:语义识别/digital-human/nlu/recognizeruoyi-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/各模块、对外暴露 APIcore/:会话各职责模块(拆分自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.4 | UE 像素流(版本必须与 UE 推流端一致,可选 -ue5.3/-ue5.4/-ue5.5) |
fuse.js | demoQA.js 模糊搜索匹配指令 |
marked + dompurify | AI 回复 Markdown 渲染 + 消毒 |
qrcode | 扫码配对二维码生成 |
安装命令示例:
bash
pnpm add @epicgames-ps/lib-pixelstreamingfrontend-ue5.4 fuse.js marked dompurify qrcode3.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.vue | system.switchModule(切换底部菜单) |
views/device/MenuBox、device/leftWidgets/LeftWidget1/Left1Content | device.* |
views/hazard/MenuBox、hazard/mainBox/totalView | hazard.* |
views/inspection/realTimeOverview | inspection.* |
views/pipeLine/totalView、pipeLine/statusDistribution | pipeLine.* |
views/construct/MenuBox、construct/leftWidgets/LeftWidget1 | construct.* |
views/roam/leftWidgets/LeftWidget1/Left1Content | roam.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 已迁移
五、常见坑
clientTools不能照搬:弹框内飞点 / 定位依赖目标项目真实地图能力,未实现则助手能对话但点不动地图。- UE 像素流库版本必须匹配 UE 推流端,否则信令握手协议版本不符、一直连不上。
actionId与业务组件一一对应:目标业务模块改名 / 拆分后,需同步改actions/*.js与组件内useAssistantAction声明。- 后端 SSE 必须
FlushingSseEmitter+X-Accel-Buffering: no,否则流式问答卡很久才出字。 - 数字人「音频一律前端播放」:UE 只驱动口型,不负责出声,迁移时不要让 UE 侧也播放导致回声,否则会有以下问题:
- UE的声音比系统音量小,在线语音与内置音频,一听就能明显感觉出来;
- 前端发声,便于控制数字人开始、结束,因为系统有演示模式;
- 前端发声,通过音频流不断推送给UE,可以实现相同的效果,UE端不用单独配置音频接口前缀等环境变量;