← 返回列表
需源码安装
给你的 agent 一张脸、一副嗓音,以及属于她自己的房间。
暂不能直接安装(需源码编译或环境不满足):仓库 package.json 标记 private,未发布到 npm,需从源码安装。 · 最近上游提交 2026/9/16 · 已提供中文文档
DeepSeek Harness 的 Galgame / 视觉小说 UI 插件:一位带有动态表情的鲸鱼少女伙伴,逐场景推进的对话,以及一个 LLM 情感判定器
综合分
35.9
GitHub 分
35.9
用户评分
—
★ Stars
3
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add omdsh-dev/dsh-gal仓库 package.json 标记 private,未发布到 npm,需从源码安装,改用 GitHub 源安装
数据截至 2026/9/19(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查需源码安装
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包@dsh-external/dsh-gal(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
仓库 package.json 标记 private,未发布到 npm,需从源码安装
验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/19 19:15:57
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-llm@deepseek-ai/dsh-session@deepseek-ai/dsh-system-prompt@deepseek-ai/dsh-tools用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
dsh-gal
给你的 agent 一张脸、一副嗓音,以及属于她自己的房间。
一个为 DeepSeek Harness(dsh)打造的 galgame / 视觉小说伴侣,以 dsh 插件形式打包——另附一个小巧的 macOS 应用,可独立运行它。底层的 agent 没有改变:同样的工具、同样的会话、同样的预设。改变的是,你能看见她工作、听见她回答,并留住她创造的东西。
实时角色舞台 · 语音回复 · 列表与文件 · 记忆 · 个人数据连接器
dsh-gal —— 聊天布局:左侧是对话,右侧是角色,正对 agent 的所作所为做出反应
演示
https://github.com/user-attachments/assets/261b456b-f147-46f5-942a-32c67d12dc2d
两分半钟:她记住一个偏好,查询周末天气,设置提醒,维护一份剧集追看清单,搜索网页,并写出一份 Markdown 计划,每条回复都用日语说出。等待过程已加速;连接器中显示的个人数据已模糊处理。(如果上方播放器无法加载,可查看仓库中的 MP4。)
它是什么
你的 agent 变成了一个角色。对话读起来就像普通的聊天,但窗口的右半边是一个舞台:当回合运行时,她会被展示为正在阅读、写作、搜索或运行命令——直接来自 harness 自身的工具事件,没有额外的模型调用,也没有猜测。回复会被朗读出来。她沿途产出的东西——一份列表、一个文件——会变成一个你之后可以打开的对象,而不是一条滚走的消息。
换一个角色包,同一个 agent 就会以另一个人的形象出现:美术、人设和嗓音一应俱全。角色包的人设注册为一个仅影响语气的人设系统提示层——它决定回复听起来如何,绝不决定 agent 做什么或运行哪些工具。
快速开始
git clone https://github.com/omdsh-dev/dsh-gal && cd dsh-gal
./scripts/build.sh # compile src/ → lib/ against your installed dsh
npm run start:web # opens the UI in your browser
需要 Node.js 22+ 和一个已配置的 dsh。在 macOS 上,你也可以双击 启动网页端.command。桌面窗口见启动,将其挂载到你已运行的 dsh 中见安装到你自己的 dsh。
dsh-gal 为你的 agent 添加的五件事
她会被展示为正在做 agent 正在做的事
舞台跟随工具流,而不是文本。每次工具调用都会将她切换为阅读、写作、搜索或运行;一次失败的调用是一个短暂的节拍;等待你处理的审批是 waiting;一个完成的回合是 done。当回复流式输出时,她正在写作,而她台词开头的舞台指示((耳根微微发红))会挑选一种情绪——兴奋、悲伤、惊讶——并在她大声说出这句台词时保持;当你打字时,她在倾听。舞台会在资源包的循环之间交叉淡入淡出,因此一个长回合一眼就能看懂,而不是一个旋转指示器。
| 活动 | 她何时展示它 | 缺失时替代为 |
| --- | --- | --- |
| idle | 回合之间的休息状态 | neutral |
| reading | 回合正在进行中:推理、查看文件、任何插件无法识别的工具 | thinking |
| writing | 编辑器、present、记忆笔记、任何类似写入的工具 | reading |
| searching | 网页搜索和抓取工具 | reading |
| running | shell 和命令运行器 | writing |
| waiting | 有一个审批正等待你处理(在 dsh 网页 UI 中决定它) | idle |
| failed | 一次工具调用出错——一个节拍,然后回到工作 | surprised |
| done | 回合刚刚结束;在回复后淡出 | happy |
活动、语音和角色被作为一个语义状态(window.galCharacter.state)跟踪,独立于它如何被渲染——见 CHARACTER-STATES.md。
她会说出回复
回复以真实 markdown 逐 token 流式输出(marked + DOMPurify,因此半到达的表格或围栏仍能渲染),并通过 VOICEVOX(免费、本地、日语)或 Settings › Voice 中配置的提供方朗读。像(放下托盘)这样的括号舞台指示会显示,但绝不会被朗读。
当 voiceLanguage: ja(默认值)时,会先进行一次小型旁路 LLM 调用,以角色的声音将回复改写为一句日语口语台词——你阅读中文/英文字幕,听到日语,就像真正的 VN。配音台词会被缓存,因此重放不会为改写再次付费。每个资源包选择自己的说话风格。
安装引擎(从其 GitHub releases 获取 voicevox_engine-macos-.7z,解压到 ~/Library/Application Support/dsh-gal/voicevox/macos-arm64),插件会按需启动它,或者将 voicevoxUrl 指向你自己运行的引擎。没有引擎时,该功能会静默关闭。提供方和密钥:SPEECH.md。
列表和文件,不只是消息
聊天答案一旦滚动过去就消失了。有两样东西能在之后保留下来:
- 列表(⌥L)——当一条回复是一组你可能会回头再看的内容(要追的剧、要比较的选项、要买的东西)时,她会在同一轮中用 list_create / list_add 把它放进一个列表,并在你说完成某项时用 list_update 标记完成或删除。你可以在面板中手动编辑同一个列表。
- 文件(⌥F)——她为你写的任何内容,从她运行过的写入工具中收集而来,可以直接从面板打开,而不必在对话记录中翻找。
属于你的记忆
关于你的笔记,而不是关于角色的。当你说出下周仍然成立的事情时,她会通过 gal_remember 自己写下这些笔记,并且它们会在每一轮中被注入。打开 记忆(⌥M)来阅读或编辑它们。它们存放在共享存储中,因此每个包看到的都是相同的笔记,切换角色不会丢失任何东西。
连接器:她对你一天的了解
dsh 自始至终都是插件,因此数据源本身就是独立的 dsh 插件——它拥有自己的同步、存储、工具和提示词部分,并且可在任何 dsh 会话中工作。当 dsh-gal 也被加载时,数据源会自行注册并显示在 数据 面板(⌥D、/data)中,每个都有一个“对角色可见”开关,可以在不删除任何内容的情况下将其从提示词中隐藏。
官方套件随本仓库发布在 plugins/ 下;每一个仍然是独立的 dsh 插件,构建到 plugins//lib/index.js,并且可以单独挂载:
| 插件 | 它带来什么 |
| --- | --- |
| dsh-health | 从手机推送的 Apple Health(Health Auto Export 或快捷指令)或从 export.zip 导入。每周平均值、两周图表、锻炼,以及与 28 天基线相比的突出项 |
| dsh-calendar | 通过 EventKit 访问日历和提醒事项,覆盖所有已同步账户。今天、下一个、本周;逾期提醒;添加和完成它们的工具 |
| dsh-weather | Open-Meteo,无需密钥。现在、今天、明天、24 小时图表和一周;位置根据时区推测。带日期的目的地会获得跟随行程的 16 天预报 |
| dsh-contacts | 通过 Contacts 框架访问通讯录。某个名字是谁,即将到来的生日 |
| dsh-notes | 通过自动化访问 Apple Notes。搜索和阅读;在被要求时创建和追加 |
| dsh-photos | 照片图库(提示词中仅元数据)。每天的照片、类似旅行的聚类、视觉模型可以查看的缩略图 |
| dsh-messages | 来自本地数据库的 iMessage 和 SMS(需要完全磁盘访问权限)。谁在等待回复;在你开启共享之前对角色隐藏 |
| dsh-location | 带反向地理编码的 CoreLocation。你在哪里、离家距离、最近去过的地方 |
| dsh-home | 通过快捷指令或 Home Assistant 令牌访问的家。读数与一键操作 |
| dsh-weread | 微信读书书架、阅读进度和划线,使用已登录会话的 cookie |
| dsh-douban | 豆瓣电影、图书和音乐的 想看/看过,这样她就不会推荐你已经看过的东西 |
| dsh-gmail | 通过 IMAP 使用应用密码访问 Gmail,只读。未读数量、本周收件箱、六个月的预订和行程;使用 Gmail 自己的语法搜索,将一封邮件读取为文本 |
| dsh-flights | 来自 AeroDataBox(RapidAPI,免费套餐)的航班状态。按航班号和日期跟踪:时间、航站楼、登机口、延误、取消,在起飞前后保持最新 |
| dsh-images | 她可以在房间里展示的图片搜索:有密钥时用 Brave Search,没有密钥时用 Wikimedia Commons。选中的图片会被下载并以卡片形式呈现,因此它能经受住防盗链检查和重新加载 |
| dsh-images | 她可以在房间里展示的图片搜索:有密钥时用 Brave Search,没有密钥时用 Wikimedia Commons。选中的图片会被下载并以卡片形式呈现,因此它能经受住防盗链检查和重新加载 |
要编写一个源,可选地注入 galSources 并以声明式方式描述自己;面板永远不需要特定于源的代码:
ctx.inject(['galSources'], gal => {
gal.effect(() => gal.galSources.register({
id: 'my-source', label: 'My source', category: 'calendar',
describe: () => ({ status: 'connected', summary: '12 events this week', shared: true,
stats: [{ label: 'Today', value: '3 events' }], lists: [...], setup: [...], actions: [...] }),
act: async (action, input) => { / POST /sources/my-source/; uploads arrive as input.file / },
}))
})
describe() 返回统计信息、每日序列、列表、带有可复制字段的设置说明,以及操作(button、upload、toggle、danger)。在新数据之后调用 gal.galSources.changed(id),以便面板刷新。契约见 src/sources.ts。
角色包
一个包就是一个目录:character.json 加上以活动命名的静态图或循环动画。较早的六个表情名称仍可作为替代使用,因此一个包含 neutral / thinking / happy / surprised 的包就能覆盖所有活动。
characters/xiaoheiyu/
character.json name, greeting, persona, theme, playbackRate, voice, art prompts
idle.png idle.mp4 (or neutral.)
reading.png reading.mp4 (or thinking.)
writing.png writing.mp4 falls back to reading
searching.png searching.mp4 falls back to reading
running.png running.mp4 falls back to writing
waiting.png waiting.mp4 falls back to idle
failed.png failed.mp4 (or surprised.)
done.png done.mp4 (or happy.)
- 内置包:小黑鱼 (Xiaoheiyu),一位原创的虎鲸女仆鲸鱼女孩,带有 5 秒的待机循环动画。她是本仓库唯一附带的艺术资源;她的包 id 是 xiaoheiyu。
- 你自己的包 位于 ~/.dsh/gal/characters/,永远不会触碰仓库。设置 DSH_GAL_CHARACTER= 即可作为某个包启动。
- 仅提示词包只提供文本和图像提示词,不包含美术资源——选一个包,自己生成图像,再将它们放到画廊图块上。参见 prompts/README.md 和 characters/README.md。
- 从 Character 面板以 .zip 形式导入 / 导出一个包。导出的内容包含美术资源和 character.json;她关于你的记忆则保留在你自己的机器上。
编辑或上传内置包的美术资源时,会先将其复制到 ~/.dsh/gal/characters/,因此仓库中的副本保持原样。
控制
一切都有按钮;快捷键是为你阅读而非点击时准备的。⌥ 快捷键在任何地方都可用,即使在句子中间。/(或 、,中文输入法下的同一个键)聚焦消息框,Esc 离开消息框或关闭面板。
| | |
| --- | --- |
| Enter · Shift+Enter | 发送 · 换行 |
| ⌥M | 记忆——她关于你的记忆,所有角色共享 |
| ⌥F | 她为你写的文件 |
| ⌥L | 她为你保存的列表 |
| ⌥D | 连接器——她能看到的内容 |
| ⌥C | 角色——切换包、编辑人设、浏览并替换活动美术资源 |
| ⌥S | 设置——语音提供方、声音和语言 |
| ⌥V · ⌥R | 静音 / 取消静音语音 · 重新朗读当前行 |
| ⌥/ | 命令和快捷键 |
消息框中的斜杠命令:/new、/char [id]、/edit、/memory、/files、/lists、/data、/gallery、/voice、/help。
你的数据
她为你保存的一切都在一个地方:~/.dsh/gal/store.sqlite。记忆、列表、她写的文件、朗读设置、当前房间的对话记录,以及每个连接器已同步的内容,都是该文件中的文档和仅追加日志(src/store.ts;本仓库之外的插件会获得与 galStore 服务相同的对象)。重启后房间会恢复:对话记录会重新显示在屏幕上,其背后的 dsh 会话会在你下次发消息时恢复,因此她会从上次中断的地方继续。旧版本写入的文件(memory.md、lists.json 等)会被导入一次,并重命名为 .migrated。
有意不放在存储中的内容:API 密钥和 cookie(各自保留在 ~/.config/dsh-gal/ 或 ~/.dsh// 下的独立文件中)、编译后的辅助程序和缩略图(机器本地),以及主题(由各浏览器保存)。存储的形态——带更新时间的文档、带序列号的日志——正是托管后端日后要同步的内容;除此之外无需任何改动。
启动(macOS)
在 Finder 中双击以下之一:
- 启动客户端.command —— 独立的原生窗口
- 启动网页端.command —— 在默认浏览器中打开相同的 UI
- 选择启动方式.command —— 询问选择哪种方式(按 Enter 选择桌面端)
或者从终端启动:
npm start # choose desktop or browser
npm run start:desktop # standalone window
npm run start:web # default browser
两个启动器都通过 http://127.0.0.1:4878/ 为此检出提供 UI,后端由 4877 端口上的 dsh 支撑。它们复用已经启动的匹配服务,只启动缺失的部分。会话和已保存的语音提供方设置是共享的;诸如界面语言之类的浏览器本地偏好则在浏览器和原生 WebView 之间保持独立。
在运行服务期间,请保持终端窗口打开。Ctrl+C 只会停止该启动器启动的进程;桌面模式在退出时还会清理自己的进程。被复用的服务仍归其原所有者管理——如果该所有者退出,依赖它的窗口将失去连接。如果端口被无关的或较旧的服务器占用,会报错而不是将其杀死。
前提条件:Node.js 22+、已配置的 dsh(优先使用应用自带的私有运行时,否则使用 PATH 上的 dsh),以及已编译的 lib/(./scripts/build.sh)。桌面模式还需要已构建的 shell(cd app && npm run build)。无头启动检查:node scripts/launch.mjs web --smoke --no-open。
应用(macOS)
app/ 是一个 Tauri 2 shell:围绕插件 UI 的原生窗口,带有一个拥有自己 dsh 的 supervisor。
首次启动时,它会在 ~/Library/Application Support/dsh-gal/runtime 下安装一个固定版本的私有 dsh 运行时,将捆绑的插件暂存到其旁边,并以挂载该插件的方式启动 dsh --profile web。它会复用你的 ~/.dsh(密钥、设置、会话)。如果 4877 端口上已有 dsh-gal 服务器响应,它只会附加到该服务器。关闭窗口会停止它启动的 dsh。
./scripts/build.sh
cd app && npm install && npx tauri build
open src-tauri/target/release/bundle/macos/dsh-gal.app
安装到你自己的 dsh 中
git clone https://github.com/omdsh-dev/dsh-gal
cd dsh-gal && ./scripts/build.sh
在 ~/.dsh/cordis.patch.yml 中注册它:
- insert:
- id: dsh-gal
name: /absolute/path/to/dsh-gal/lib/index.js
config:
port: 4877 # UI at http://127.0.0.1:4877/
character: xiaoheiyu # pack id, or a path to a pack directory
像往常一样启动 dsh web,然后打开 http://127.0.0.1:4877/。基于 dsh 0.1.5-rc.1 构建并测试;scripts/build.sh 会链接到 PATH 上 dsh 背后的安装(可通过 DSH_PKG_ROOT 覆盖)。
配置
| key | default | description |
| --- | --- | --- |
| port | 4877 | 在 127.0.0.1 上监听的端口 |
| token | "" | 可选的共享令牌,附加到 URL 中 |
| character | xiaoheiyu | 包 id(~/.dsh/gal/characters/,然后是捆绑的 characters/)或路径 |
| characterName | pack name | 覆盖名牌 |
| greeting | pack greeting | 覆盖包的开场白 |
| personaEnabled | true | 将包人设注册为系统提示词语音层 |
| judgeProvider / judgeModel | agent's route | 插件所做的一次侧调用(语音配音)的路由覆盖 |
| judgeReasoningEffort | off | 该侧调用的推理强度("" = 路由的默认值) |
| voiceEnabled | true | 当 VOICEVOX 引擎可访问时朗读回复 |
| voicevoxUrl | http://127.0.0.1:50021 | VOICEVOX 引擎基础 URL |
| voicevoxEngine | ~/Library/Application Support/dsh-gal/voicevox/macos-arm64/run | 要自动启动的本地引擎二进制文件("" = 从不) |
| voiceSpeaker | 2 | 当角色包未设置时使用的后备 VOICEVOX 风格 id(character.json 中的 voice.speaker) |
| voiceLanguage | ja | ja 在合成前翻译非日语回复;auto 按原文朗读回复 |
制作角色包
最快速可靠的途径——即内置的小黑鱼角色包所采用的途径:
1. 一张基础立绘。 在纯色背景上生成角色的全身像。这是设计参考;此步骤之后不允许任何环节重绘她。
2. 一张舞台关键帧。 重新生成她在场景中的形象,16:9,取景从大约大腿中部向上,并让下三分之一保持视觉上平静,因为对话框就位于那里。保留基础立绘作为参考图像。
3. 更多静帧——使用两张参考图。 最重要的几张是 writing、reading、failed 和 done;任何缺失的都会借用相邻的(参见 CHARACTER-STATES.md)。同时传入基础立绘(她是谁)和舞台关键帧(构图、色调、光照、镜头距离),并让提示词只改变面部和手臂。两张参考图正是防止背景和取景在静帧之间漂移的关键;一张参考图不够。
4. 待机循环。 scripts/animate.sh "" [h3] 在 fal.ai 上将每张静帧转换为循环片段(默认使用 Seedance 2.0 mini,使用 h3 时则为 MiniMax H3——对于风格化角色,H3 是两者中更宽容的)。将运动提示词写为呼吸、眨眼、头发和衣物飘动,并明确说明摄像机固定不动且姿势不变。
一个循环需要其最后一帧衔接到第一帧,否则每个周期都会跳一下。脚本分两步做到这一点:它将静帧同时作为结束帧和起始帧传入,然后在本地将尾部交叉淡化回开头。仅靠模型是不够的——要求结束帧能让姿势接近,但无法精确落到该姿势上。
5. 安装。 从 Character › Art 上传每个文件,或者将所有内容加上一个 character.json 放入 ~/.dsh/gal/characters//。
最快捷的方式:从 Character › Pick 选择一个纯提示词角色包,打开其 Persona 标签页,将图像提示词复制到你选择的图像模型中,然后把结果拖放到画廊图块上。
保持 character.json 中的 art.base、art.expressions 和 art.motion 为最新——它们是日后重新生成该角色包的配方,也是纯提示词角色包交给其下一位拥有者的内容。
状态与限制
- 舞台位于角色身后一块固定背景板上。没有背景选择器:卡牌美术是全画幅的,自带环境,因此单独的背景选项只会与之冲突。
- 待机循环是 5 秒的片段,而非无缝循环;如果盯着看,接缝处是可见的。
- 活动是整段片段的切换,而非骨骼绑定。她无法在逐字对口型说某句台词时保持某个姿势,也没有逐音素的嘴部动作。
- 大多数连接器本质上仅限 macOS(EventKit、Contacts、Photos、Messages、Shortcuts)。
本仓库分发的内容
仅文本,用于第三方角色:位于 prompts/ 下的角色人设提示词、问候语、主题和图像提示词描述。它不附带、也不会接受授权角色的图像、视频或语音样本。这些由你自己生成,在你自己的机器上,为你自己的用途,并保存在仓库之外的 ~/.dsh/gal/characters// 中。唯一捆绑的美术资源是 小黑鱼,一个原创角色。
UI 开发
该页面就是聊天布局:整个对话在左侧,角色在右侧。其源码位于 ui/src/chat/,构建输出到 web/chat/,已检入并由浏览器和桌面外壳共享。(ui/src/ 和 web/ui/ 是更早的每次一个场景的舞台,保留在 /classic.html,不再开发。)
npm ci --prefix ui # once
npm run check:ui && npm run build:ui
npm --prefix ui run dev # rebuild on change; refresh the page to see it
组件、控制器适配器和验证说明:ui/README.md。
社区
在 LINUX DO 和 V2EX 上讨论。欢迎在那里或 issue 中提问、报告 bug 和提交角色包。
许可证
BSD-3-Clause同作者(omdsh-dev)的其他插件
扫码进群