dsh-avatar
为 DSH(DeepSeek Harness)添加常驻界面的 AI 数字人:渲染 VRM 形象,由大模型通过工具驱动表情与动作,并提供模型与动作素材管理页。
插件专注于形象表现,不提供人格、记忆、字幕或语音功能。
![]()
![]()
以上图片通过独立预览加载本项目的 VRM 渲染器和原有管理页组件生成,不包含 DSH 宿主外壳。实际使用时,从 DSH 左侧菜单「数字人」打开管理页。
功能
- 常驻浮层:数字人默认显示在界面右下角,通过全局
shell.overlay在各页面与会话中保持可见。 - 拖拽定位:按住数字人浮层即可拖动;按人物实际显示范围限制拖拽位置,窗口缩放后重新调整边界。
- 工具表情:大模型调用
set_expression,可选表情来自当前模型的 blend shapes,5 秒后自动复位。工具表情优先于待机素材中的同名表情通道。 - 工具动作:大模型调用
play_motion,可选动作来自当前动作清单。一次性动作结束后回到待机。 - 循环待机:优先播放
idle_stand,其次使用idle;素材缺失时使用程序化上半身待机。待机素材优先加载,其余动作在后台加载。 - 资产管理:从左侧菜单「数字人」打开中央管理页,导入 VRM 模型与 VRMA 动作、切换模型、删除用户导入的素材。内置资产不可删除,导入的模型自动成为当前模型。
- 资产即时生效:管理页变更后,浮层自动重载模型与动作,工具参数同步更新,无需重启;浮层拖拽位置保持不变。导入资产保存在用户数据目录,升级插件不会覆盖。
左侧菜单收窄时,入口显示为图标;若取消固定,可从「更多」菜单打开。管理页需要宿主提供 sidebar.panellist 和 main 插槽。
安装
从 GitHub 安装
在已安装 DSH 的环境中,选择要使用的 profile:
dsh plugin --profile <你的profile名> add github:sunqing975/dsh-avatar
例如使用 web profile:
dsh plugin --profile web add github:sunqing975/dsh-avatar
首次安装时,若 DSH 的供应链安全策略拦截 Git 源包的 prepare 构建脚本,可能出现 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED。确认来源后,将报错提示的完整条目加入 ~/.dsh/profiles/<profile>/pnpm-workspace.yaml 的 allowBuilds,例如:
allowBuilds:
dsh-avatar@https://codeload.github.com/sunqing975/dsh-avatar/tar.gz/<commit>: true
条目必须以实际报错提示为准。保存后重新执行相同的安装命令,再重启对应的 DSH 宿主。
本地开发安装
先按下方开发说明安装依赖并构建,再将项目链接到目标 profile:
dsh plugin --profile web add link:/path/to/dsh-avatar
dsh web --no-open
将 /path/to/dsh-avatar 替换为本地项目目录。若尚未全局安装 DSH,可将命令中的 dsh 替换为 npx @deepseek-ai/dsh。宿主已经运行时,重启后加载构建产物。
模型与动作
- 内置模型:
assets/models/nuomi.vrm。 - 内置动作:
assets/animations/,包括idle_stand、idle、bow、elbow_punch、Praying、sitting_laughing和Body Block。待机素材来源与许可见 素材署名。 - 自定义素材:推荐通过「数字人」管理页导入。也可在本地开发时向
assets/animations/放入.vrma文件,重启插件后加入动作清单。
表情与动作的实际效果取决于模型提供的表情、骨骼和素材兼容性。上传端点仅检查 GLB 魔数与文件大小(模型 128 MB、动作 64 MB),不保证所有素材均可播放。
开发
npm install
npm run build # esbuild 构建 host(lib/index.js) + client(lib/client.js)
npm run typecheck # 双 tsconfig 类型检查
npm run verify:bridge # 验证工具指令桥、资产热更新与客户端注册等行为
verify:bridge 依赖构建产物:加载 lib/index.js 注册路由与工具,启动 HTTP 服务,并在最小 window 环境执行 lib/client.js。修改代码后先构建,再验证;该脚本不替代浏览器中的 WebGL 渲染检查。
结构
src/
index.ts # host 插件:HTTP 端点 + 工具热更新
tools.ts # set_expression / play_motion 工具定义
pose.ts # 表情与动作指令队列
assets-registry.ts # 内置与用户资产合并、当前模型持久化、导入/删除
model-info.ts # GLB blend shapes 解析
config.ts # 配置 schema
client/
index.tsx # 浮层、左侧菜单与中央管理页注册;指令轮询
AvatarPanelIcon.tsx # 左侧「数字人」入口图标
AvatarSettingsPage.tsx # 中央管理页布局
AssetManagerPanel.tsx # 导入/切换/删除 VRM 与 VRMA 的表单
AvatarFloating.tsx # 常驻浮层,资产变更时自动重载
vrm.ts # three.js + @pixiv/three-vrm 渲染与动作播放
idle-motion.ts # 待机素材选择与程序化兜底
drag.ts # 拖拽边界计算
assets.ts # 资产条目归一化与动作 URL
event-bus.ts # 客户端内部事件总线
assets/
models/ # 内置 VRM 模型
animations/ # 内置 VRMA 动作
scripts/
build.mjs # host/client 构建
verify-bridge.mjs # 指令桥与资产等行为验证
HTTP 端点
| 端点 | 方法 | 说明 |
|---|---|---|
/dsh-avatar/model.vrm |
GET | 当前生效的模型(用户目录优先于内置) |
/dsh-avatar/animations/<name>.vrma |
GET | 动作文件(用户目录优先于内置) |
/dsh-avatar/assets/<rel> |
GET | 内置 assets 静态资源(防路径穿越) |
/dsh-avatar/info |
GET | 资产清单、当前模型、blend shapes 与带版本戳的 modelUrl |
/dsh-avatar/pose?since=<seq> |
GET | 当前水位线与表情/动作指令增量 |
/dsh-avatar/upload?kind=model|motion&name=<文件名> |
POST | 上传 VRM/VRMA,body 为原始 GLB 字节 |
/dsh-avatar/select-model |
POST | 切换模型,body 为 {"name":"<模型名>"} |
/dsh-avatar/delete?kind=model|motion&name=<资产名> |
POST | 删除用户导入资产 |
用户数据目录
<dshHome>/dsh-avatar/
models/ # 用户导入的 VRM
animations/ # 用户导入的 VRMA
state.json # 当前模型名
<dshHome> 默认是 ~/.dsh,可用 DSH_HOME 覆盖;测试或开发可用 DSH_AVATAR_DATA_DIR 指定独立目录。同名资产以用户文件优先,删除用户文件后恢复使用内置资产。
实现与排查
- 管理页通过
ctx.slots.inject等待宿主插槽:在sidebar.panellist注册「数字人」入口,在 keyed slotmain以相同 iddsh-avatar注册中央正文。浮层、指令桥与管理页分别注册,故障相互隔离。 - 工具执行后写入 Host 的
PoseHub;客户端每 400 ms 轮询/dsh-avatar/pose,按序号转发到内部事件总线。首次读取只建立水位线,避免重放历史动作。 - 工具参数随资产变化重新注册;同一画布使用
AvatarController.reload()重载资源,保留渲染器与浮层位置。 - 待机默认锁定胯部位移轨道,工具表情在动画更新后重新应用,减少位移漂移与表情通道覆盖。
- 若工具返回成功但数字人不响应,先检查
/dsh-avatar/pose是否为 404(可能是 Host 未加载新版插件),再检查浏览器的window.__dshAvatarLog:baseline seq=N表示已建立水位线,pose seq=N ...表示已接收指令,controller:idle:...与controller:motions:loaded=n/N:ms=...表示素材加载状态。
No comments yet. Be the first to write one.