dsh-fish-buddy 0.7.9 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/LICENSE +50 -21
  2. package/README.md +181 -163
  3. package/lib/host.js +1780 -1671
  4. package/package.json +44 -44
package/LICENSE CHANGED
@@ -1,21 +1,50 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Yuuyuko-uu
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ Yuuyuko-uu 插件许可 1.2
2
+
3
+ 版权所有 (c) 2026 Yuuyuko-uu
4
+
5
+ ──────────────────────────────────────────────────────────────
6
+
7
+ 【为什么不用 MIT】
8
+
9
+ 2026 年 10 月,有人把我这几个插件(代码、README,还有我做的图)
10
+ 改名、去掉署名,在视频里说成「自研」发布。
11
+
12
+ 他没有违反 MIT —— MIT 只要求保留版权声明,不管「这是谁做的」。
13
+
14
+ 所以换成了这份许可。它只多要求一件事:
15
+ 你拿走的时候,说一声这是谁做的。
16
+
17
+ 安装、修改、商用,全都允许 —— 和 MIT 一样宽。
18
+
19
+ ──────────────────────────────────────────────────────────────
20
+
21
+ 一、允许,不需要另外问我
22
+
23
+ 1. 安装到自己的机器上使用,长期用,商用也行。
24
+ 2. 读源码、改源码、改成自己需要的版本(改给自己用,不必公开)。
25
+ 3. 把你的改动发给我(issue / PR);我采纳后,按仓库惯例记你的贡献。
26
+ 4. 在文章、视频、教程里介绍、演示、截图、引用本项目 —— 请附上原仓库地址。
27
+
28
+ 二、允许,但必须做到
29
+
30
+ 5. 再分发时(把代码或其实质性部分放进你自己的仓库、整合包、安装包,
31
+ 或者换一个包名发布),必须同时做到:
32
+ a) 完整保留本文件,不删、不改、不缩略;
33
+ b) 在 README 的第一屏写明:本项目派生自 <原仓库地址>,原作者 Yuuyuko-uu;
34
+ c) 说明你改了哪些部分。
35
+ 6. 公开的衍生作品必须继续使用本许可(或更严格的许可),不得改用更宽松的许可。
36
+
37
+ 三、禁止
38
+
39
+ 7. 不得把本项目的全部或实质性部分声称为你自己原创 ——
40
+ 包括在 README、发布说明、视频、插件市场条目里,
41
+ 把它写成「自研」「原创」「我写的」。
42
+ 8. 不得删除、替换、隐藏本项目的作者署名,
43
+ 包括 LICENSE、NOTICE、README、package.json 和源码注释里的。
44
+
45
+ 四、其他
46
+
47
+ 9. 本项目按「现状」提供,不附带任何明示或默示的担保。
48
+ 10. 违反第二、三条中任何一条,本许可立即终止;你还应当删除已发布的衍生作品。
49
+ 从违约那一刻起,你就不再拥有使用、复制、分发本项目的任何授权。
50
+ 11. 上面没写的情况想用,直接来问我,一般都会答应。
package/README.md CHANGED
@@ -1,163 +1,181 @@
1
- # 鱼搭子
2
-
3
- 桌面上一只小鲸鱼挂件 + 一个 DSH 插件。挂件负责听、看、说(语音、陪看字幕、游戏弹幕、截图),
4
- 插件负责把它和你绑定的一间会话接起来 —— 挂件说的话进那间会话,那边的回话再递回挂件。
5
-
6
- 这个仓库里**两半都在**:
7
-
8
- | 目录 | 是什么 |
9
- |---|---|
10
- | `app/` | 桌面挂件(Python + tkinter,打包成单文件 exe) |
11
- | `lib/` | DSH 插件(宿主半边 + 设置页) |
12
- | `tests/` | 插件与程序的测试 |
13
-
14
- > ⚠️ **两套版本号,别混**:`app/` 是挂件程序,`lib/` 是 DSH 插件,各自独立涨(不是同一个数)。
15
- > - 当前是多少:看 `app/version.py` 和 `package.json`(README 里**故意不写死**,免得每发一版改一次)
16
- > - 改了什么:看 `CHANGELOG.md`,条目开头会写「程序」还是「插件」
17
- > - 下载:看 [Releases](https://github.com/Yuuyuko-uu/dsh-fish-buddy/releases)(exe 的资产名带版本号)
18
-
19
- ## 插件这半边干什么
20
-
21
- 1. 在本机开一个口子(默认 `127.0.0.1:8777`),收挂件发来的话;
22
- 2. 把这句话**送进你绑定的那间会话**(相当于你在那间里说了一句);
23
- 3. 她那间回完一轮 → 把回话**递回挂件**(POST 到你填的回调地址);
24
- 4. 收到截图/游戏画面时,把**图片本身**发进会话(先存成附件再引用);
25
- 5. 设置页里能看到:口子通不通、发来几条、最近发生了什么、她最近说的一句。
26
-
27
- ## 素材说明
28
-
29
- `app/assets/` 里的角色图、气泡框、弹幕框是随程序一起分发的素材,**不单独授权二次使用**。
30
- `app/assets/ocr/` 里是 PP-OCRv6 的检测/识别模型(Apache-2.0),`app/assets/字体/` 里是站酷快乐体(免费商用)。
31
-
32
- ## 装好之后怎么配
33
-
34
- **DSH 设置 → 鱼搭子**(第一栏):
35
-
36
- | 项 | 填什么 |
37
- |---|---|
38
- | 开着 | 默认开。关掉之后挂件发什么都不往里送 |
39
- | 送到哪一间 | 从下拉里选你那间会话(没选就送不进去) |
40
- | 本机口子 | 端口,默认 8777。**改端口要重启 DSH 才生效** |
41
- | 回话递回 | 挂件那边留的接收地址,例如 `http://127.0.0.1:8778/hands/reply` |
42
- | 标一句来源 | 塞进会话时前面加「(挂件里说的话)」,方便你分清是打字的还是说的 |
43
- | 截图留几天 / 最多几张 | 插件自己攒的截图按这两条清(默认 30 天 / 800 张,填 0 = 那一条不限);只删它自己目录里的图 |
44
- | **检查更新** | 点「查一下」:同时查**插件本身**(对比仓库 main 上的版本)和**挂件 exe**(对比最新 release) |
45
-
46
- **挂件设置 → 游戏**:
47
-
48
- | 项 | 填什么 |
49
- |---|---|
50
- | 截图怎么送 | **每张都说一遍**:截一张就发一轮;**攒着,说话时一起看**:只存着,你说话(或她主动看一眼)时全部带过去 |
51
- | 她主动看一眼 | 每 N 分钟自己开口一次(**只在「攒着」那一档生效**;「每张都说」时截图本来就叫醒她,再叠一层就是白花钱) |
52
- | 组合键 | 退出游戏模式 / 锁解锁弹幕框,默认 `Alt+G` / `Alt+H`,写法 `Ctrl+Alt+G`、`F9` 都行 |
53
- | 锁住弹幕框 | 锁上就是**真穿透**(鼠标穿到游戏里),解锁用右键菜单或这一项 |
54
-
55
- ## 语音识别模型怎么选
56
-
57
- 挂件 **设置 → 语音 → 识别模型**,三档选一个,装的时候只下选中的那一档:
58
-
59
- | 档 | 大小 | 什么样 |
60
- |---|---|---|
61
- | 小 | 228MB | **默认**。省 CPU,平时说话够用 —— 拿不准就选它 |
62
- | 大 | 894MB | 识别最准,也最吃 CPU 和内存;机器一般的话,别的程序会跟着变慢 |
63
- | 最快 | 78MB | 最省,但**不出标点**,字幕会连成一片 |
64
-
65
- - 每档后面标着「已装 / 没装」,下载按钮只下当前选中的那一档;换档不用重下别的档。
66
- - 电话、陪看、按住说话用的是同一档。换完,陪看要点一下「开始听」、电话要挂断重打一次,才用新的。
67
- - 机器上已经有一档装好的,不会被当成「没装」:默认值变了,也还是先用那份能用的。
68
- - 老版本放错地方的模型(`models\sensevoice-fp32\`、`models\` 根上的 `model.int8.onnx`)
69
- 第一次启动会自动搬到该在的目录,不用重下。
70
- - 目录约定:`models\` 根上是「大」,`models\int8\` 是「小」,`models\paraformer\` 是「最快」;
71
- 每档目录里都叫 `model.onnx` + `tokens.txt`。
72
-
73
- > 下不动的时候:2026-10-30 凌晨实测,国内镜像 `hf-mirror.com` 在限流 / 跳转,官方 `huggingface.co`
74
- > 直连不通,那一刻确实下不了。下载本身(按档选仓库、按档落目录、断点续传、失败重试)是验过的,
75
- > 网络好了再点一次就行;已经下到一半的部分不会作废。
76
-
77
- ## 插件自己攒的截图会自己清
78
-
79
- 陪看抽的帧、她主动开口那张、按住说话带的那张,插件都在 `~\.dsh\fish-buddy-frames` 留一份。
80
- 以前只进不出,用久了能堆几十上百 MB —— 现在按两条清:
81
-
82
- - **留几天**(默认 30)、**最多几张**(默认 800),在 DSH 设置 → 鱼搭子 → 第一栏里调;填 0 = 那一条不限。
83
- - 插件一起来先清一次,之后每写一张图顺带看一眼(十分钟最多查一次目录,不会一直扫盘)。
84
- - 只删这个目录里的图片(`.jpg` / `.png`),别的地方一概不碰;删了会在设置页「最近发生了什么」里记一行。
85
-
86
- ## 协议(挂件那边照这个对接)
87
-
88
- **挂件 → DSH**
89
-
90
- ```
91
- POST http://127.0.0.1:8777/hands/say {"text": "说了什么"}
92
- POST http://127.0.0.1:8777/hands/talk {"text": "说了什么", "图片": "<base64,可省>"}
93
- POST http://127.0.0.1:8777/hands/frame {"图片": "<base64>", "立即": 1|0, "存档": 1|0, "来源": "游戏"}
94
- POST http://127.0.0.1:8777/hands/mode {"游戏": true|false}
95
- POST http://127.0.0.1:8777/hands/subtitle {"字幕": [{"文本": "…", "ts": 1690000000}]}
96
- POST http://127.0.0.1:8777/hands/watch {"watch": true|false}
97
- ```
98
-
99
- - `/hands/talk` 会把攒着的截图一起带过去(`图片` 可省)
100
- - `/hands/frame` 的 `存档=1`:只存不叫醒(「攒着」用);`立即=1`:立刻发一轮
101
- - `/hands/say` 也可以带 `"session": "session-xxx"` 指定这一次送进哪间
102
- - 回:`{"ok": true, "说": "送进去了"}`;没绑会话 / 会话没开 / 总开关关着 → `409` + 一句人话
103
-
104
- **DSH → 挂件**
105
-
106
- ```
107
- POST <设置页里填的回调地址> {"text": "她那句", "session": "session-xxx"}
108
- GET http://127.0.0.1:8778/hands/devices → {"ok": true, "设备": [...], "版本": "<挂件版本>"}
109
- ```
110
-
111
- - **只递「挂件叫起来的那一轮」**:你自己在 DSH 里聊的,不会往挂件推
112
- - 回调没填就什么都不发(不会报错)
113
-
114
- ## 已知边界
115
-
116
- - **端口是启动时定死的**:改端口要重启 DSH。
117
- - 会话得在 DSH 里**打开过一次**,否则 `agents.get()` 找不到它(会回一句「那间会话没开着」)。
118
- - 每送一句话 = 一轮模型请求 = 花额度。**上下文越长越贵**:同一个上下文每轮都要重读一遍,
119
- 所以「一小时说了多少次话」直接决定账单(实测:一小时 111 次、每次约 60 万 token 上下文 → 几十块)。
120
- - **游戏截图会制造轮次**:「每张都说」一小时能叫醒她几十轮;「攒着」只在你说话 / 主动看一眼时花一次。
121
- 攒着的图**不删、不重复发**,但**攒得越多,那一次带过去的图越多、越贵**。
122
- - 回话只取那一轮里**最后一段文字**;纯图轮的没有文字,不递。
123
- - 攒图队列在**内存里**:DSH 重启就清空。图本身分两处:挂件自己在 `%LOCALAPPDATA%\鱼搭子\frames`
124
- 留最近 20 张,插件收下的在 `~\.dsh\fish-buddy-frames`(按天数和张数自己清,见上面那节)。
125
-
126
- ## 自测
127
-
128
- ```bash
129
- node tests/宿主半边.mjs # 75 项:真的起一个 http 口子发请求,不碰真实 DSH
130
- node tests/网页半边.mjs # 设置页那半边
131
- node tests/inbound-batching.mjs # 群消息攒批
132
- node tests/inbound-lifecycle.mjs # 收消息生命周期
133
- node tests/inbound-singleflight.mjs
134
- ```
135
-
136
- 挂件那边:`python ball.py --selftest`(108 项,含热区、气泡、弹幕、快捷键)。
137
-
138
- ## 一起看(字幕白板)
139
-
140
- 挂件的陪看在放视频/直播时,每出一句**定稿**字幕就推给插件(`POST /hands/subtitle`)。
141
- 插件按会话留**最近 90 秒、最多 40 句**,每轮用 `systemPrompt.context` 现拼一段「【你正在看的】…」(挂在消息尾部,不动系统提示词的前缀,缓存才不掉)——
142
-
143
- - **不写进对话历史**,所以不会越看越厚;没字幕时是空串,不占上下文;
144
- - 她一眼看完,想说的时候再说,不用每句都应;
145
- - 另外可开「随机搭话」(`随机搭话分钟`):每隔这么久掷一次骰子,中了就让 DSH 开一轮让她自己说一句。
146
-
147
- ## 打游戏
148
-
149
- 进游戏模式之后:悬浮球收起来,桌面只剩**飘的弹幕**(她的话横着飞过去)和**弹幕框**(攒着最近几句)。
150
-
151
- - **弹幕 / 弹幕框 / 气泡**都做了「缺字换字体」:主字体(站酷)没有的颜文字、符号自动换系统字体补,不出方块;
152
- - **截图**按设定间隔抓,三种送法见上面「挂件设置 → 游戏」(每张都说 / 攒着);
153
- - **主动看一眼**:攒着那一档里,隔 N 分钟她自己开口一次,顺带把攒的图带上;
154
- - **锁定**:弹幕框锁住后是真穿透,全屏游戏里鼠标不会被它接住;解锁走右键菜单 / 设置 / 组合键;
155
- - 弹幕框可以拖到**副屏**;弹幕本身只在主屏横飞(跨屏会两边各一半)。
156
-
157
- ## 已经能用的
158
-
159
- - **插件**:接线、回话递回、字幕白板、随机搭话、游戏截图三种送法、主动看一眼、检查更新、设置页
160
- - **挂件**:电话(语音识别)、一起看(字幕)、游戏模式(弹幕 + 弹幕框 + 截图)、气泡、
161
- 多显示器摆位、颜文字混排、组合键、锁定穿透
162
-
163
- (各版本改了什么、最新是多少 —— 见 `CHANGELOG.md` 和 Releases。)
1
+ # 鱼搭子
2
+
3
+ 桌面上一只小鲸鱼挂件 + 一个 DSH 插件。挂件负责听、看、说(语音、陪看字幕、游戏弹幕、截图),
4
+ 插件负责把它和你绑定的一间会话接起来 —— 挂件说的话进那间会话,那边的回话再递回挂件。
5
+
6
+ 这个仓库里**两半都在**:
7
+
8
+ | 目录 | 是什么 |
9
+ |---|---|
10
+ | `app/` | 桌面挂件(Python + tkinter,打包成单文件 exe) |
11
+ | `lib/` | DSH 插件(宿主半边 + 设置页) |
12
+ | `tests/` | 插件与程序的测试 |
13
+
14
+ > ⚠️ **两套版本号,别混**:`app/` 是挂件程序,`lib/` 是 DSH 插件,各自独立涨(不是同一个数)。
15
+ > - 当前是多少:看 `app/version.py` 和 `package.json`(README 里**故意不写死**,免得每发一版改一次)
16
+ > - 改了什么:看 `CHANGELOG.md`,条目开头会写「程序」还是「插件」
17
+ > - 下载:看 [Releases](https://github.com/Yuuyuko-uu/dsh-fish-buddy/releases)(exe 的资产名带版本号)
18
+
19
+ ## 插件这半边干什么
20
+
21
+ 1. 在本机开一个口子(默认 `127.0.0.1:8777`),收挂件发来的话;
22
+ 2. 把这句话**送进你绑定的那间会话**(相当于你在那间里说了一句);
23
+ 3. 她那间回完一轮 → 把回话**递回挂件**(POST 到你填的回调地址);
24
+ 4. 收到截图/游戏画面时,把**图片本身**发进会话(先存成附件再引用);
25
+ 5. 设置页里能看到:口子通不通、发来几条、最近发生了什么、她最近说的一句。
26
+
27
+ ## 素材说明
28
+
29
+ `app/assets/` 里的角色图、气泡框、弹幕框是随程序一起分发的素材,**不单独授权二次使用**。
30
+ `app/assets/ocr/` 里是 PP-OCRv6 的检测/识别模型(Apache-2.0),`app/assets/字体/` 里是站酷快乐体(免费商用)。
31
+
32
+ ## 装好之后怎么配
33
+
34
+ **先把插件装上**(已经发布到 npm,不用 git):
35
+
36
+ ```bash
37
+ dsh plugin --profile desktop add dsh-fish-buddy
38
+ ```
39
+
40
+ > 也可以在 npm 上直接看到这个包(含历史版本):<https://www.npmjs.com/package/dsh-fish-buddy>
41
+
42
+ 装完**重启一次 DSH**;挂件那个 exe 另外去 [Releases](https://github.com/Yuuyuko-uu/dsh-fish-buddy/releases) 下。
43
+
44
+ **DSH 设置 → 鱼搭子**(第一栏):
45
+
46
+ | 项 | 填什么 |
47
+ |---|---|
48
+ | 开着 | 默认开。关掉之后挂件发什么都不往里送 |
49
+ | 送到哪一间 | 从下拉里选你那间会话(没选就送不进去) |
50
+ | 本机口子 | 端口,默认 8777。**改端口要重启 DSH 才生效** |
51
+ | 回话递回 | 挂件那边留的接收地址,例如 `http://127.0.0.1:8778/hands/reply` |
52
+ | 标一句来源 | 塞进会话时前面加「(挂件里说的话)」,方便你分清是打字的还是说的 |
53
+ | 截图留几天 / 最多几张 | 插件自己攒的截图按这两条清(默认 30 天 / 800 张,填 0 = 那一条不限);只删它自己目录里的图 |
54
+ | **检查更新** | 点「查一下」:同时查**插件本身**(对比仓库 main 上的版本)和**挂件 exe**(对比最新 release) |
55
+
56
+ **挂件设置 → 游戏**:
57
+
58
+ | 项 | 填什么 |
59
+ |---|---|
60
+ | 截图怎么送 | **每张都说一遍**:截一张就发一轮;**攒着,说话时一起看**:只存着,你说话(或她主动看一眼)时全部带过去 |
61
+ | 她主动看一眼 | 每 N 分钟自己开口一次(**只在「攒着」那一档生效**;「每张都说」时截图本来就叫醒她,再叠一层就是白花钱) |
62
+ | 组合键 | 退出游戏模式 / 锁解锁弹幕框,默认 `Alt+G` / `Alt+H`,写法 `Ctrl+Alt+G`、`F9` 都行 |
63
+ | 锁住弹幕框 | 锁上就是**真穿透**(鼠标穿到游戏里),解锁用右键菜单或这一项 |
64
+
65
+ ## 语音识别模型怎么选
66
+
67
+ 挂件 **设置 → 语音 → 识别模型**,三档选一个,装的时候只下选中的那一档:
68
+
69
+ | 档 | 大小 | 什么样 |
70
+ |---|---|---|
71
+ | 小 | 228MB | **默认**。省 CPU,平时说话够用 —— 拿不准就选它 |
72
+ | 大 | 894MB | 识别最准,也最吃 CPU 和内存;机器一般的话,别的程序会跟着变慢 |
73
+ | 最快 | 78MB | 最省,但**不出标点**,字幕会连成一片 |
74
+
75
+ - 每档后面标着「已装 / 没装」,下载按钮只下当前选中的那一档;换档不用重下别的档。
76
+ - 电话、陪看、按住说话用的是同一档。换完,陪看要点一下「开始听」、电话要挂断重打一次,才用新的。
77
+ - 机器上已经有一档装好的,不会被当成「没装」:默认值变了,也还是先用那份能用的。
78
+ - 老版本放错地方的模型(`models\sensevoice-fp32\`、`models\` 根上的 `model.int8.onnx`)
79
+ 第一次启动会自动搬到该在的目录,不用重下。
80
+ - 目录约定:`models\` 根上是「大」,`models\int8\` 是「小」,`models\paraformer\` 是「最快」;
81
+ 每档目录里都叫 `model.onnx` + `tokens.txt`。
82
+
83
+ > 下不动的时候:2026-10-30 凌晨实测,国内镜像 `hf-mirror.com` 在限流 / 跳转,官方 `huggingface.co`
84
+ > 直连不通,那一刻确实下不了。下载本身(按档选仓库、按档落目录、断点续传、失败重试)是验过的,
85
+ > 网络好了再点一次就行;已经下到一半的部分不会作废。
86
+
87
+ ## 插件自己攒的截图会自己清
88
+
89
+ 陪看抽的帧、她主动开口那张、按住说话带的那张,插件都在 `~\.dsh\fish-buddy-frames` 留一份。
90
+ 以前只进不出,用久了能堆几十上百 MB —— 现在按两条清:
91
+
92
+ - **留几天**(默认 30)、**最多几张**(默认 800),在 DSH 设置 → 鱼搭子 → 第一栏里调;填 0 = 那一条不限。
93
+ - 插件一起来先清一次,之后每写一张图顺带看一眼(十分钟最多查一次目录,不会一直扫盘)。
94
+ - 只删这个目录里的图片(`.jpg` / `.png`),别的地方一概不碰;删了会在设置页「最近发生了什么」里记一行。
95
+
96
+ ## 协议(挂件那边照这个对接)
97
+
98
+ **挂件 → DSH**
99
+
100
+ ```
101
+ POST http://127.0.0.1:8777/hands/say {"text": "说了什么"}
102
+ POST http://127.0.0.1:8777/hands/talk {"text": "说了什么", "图片": "<base64,可省>"}
103
+ POST http://127.0.0.1:8777/hands/frame {"图片": "<base64>", "立即": 1|0, "存档": 1|0, "来源": "游戏"}
104
+ POST http://127.0.0.1:8777/hands/mode {"游戏": true|false}
105
+ POST http://127.0.0.1:8777/hands/subtitle {"字幕": [{"文本": "…", "ts": 1690000000}]}
106
+ POST http://127.0.0.1:8777/hands/watch {"watch": true|false}
107
+ ```
108
+
109
+ - `/hands/talk` 会把攒着的截图一起带过去(`图片` 可省)
110
+ - `/hands/frame` 的 `存档=1`:只存不叫醒(「攒着」用);`立即=1`:立刻发一轮
111
+ - `/hands/say` 也可以带 `"session": "session-xxx"` 指定这一次送进哪间
112
+ - 回:`{"ok": true, "说": "送进去了"}`;没绑会话 / 会话没开 / 总开关关着 → `409` + 一句人话
113
+
114
+ **DSH → 挂件**
115
+
116
+ ```
117
+ POST <设置页里填的回调地址> {"text": "她那句", "session": "session-xxx"}
118
+ GET http://127.0.0.1:8778/hands/devices → {"ok": true, "设备": [...], "版本": "<挂件版本>"}
119
+ ```
120
+
121
+ - **只递「挂件叫起来的那一轮」**:你自己在 DSH 里聊的,不会往挂件推
122
+ - 回调没填就什么都不发(不会报错)
123
+
124
+ ## 已知边界
125
+
126
+ - **端口是启动时定死的**:改端口要重启 DSH。
127
+ - 会话得在 DSH 里**打开过一次**,否则 `agents.get()` 找不到它(会回一句「那间会话没开着」)。
128
+ - 每送一句话 = 一轮模型请求 = 花额度。**上下文越长越贵**:同一个上下文每轮都要重读一遍,
129
+ 所以「一小时说了多少次话」直接决定账单(实测:一小时 111 次、每次约 60 万 token 上下文 → 几十块)。
130
+ - **游戏截图会制造轮次**:「每张都说」一小时能叫醒她几十轮;「攒着」只在你说话 / 主动看一眼时花一次。
131
+ 攒着的图**不删、不重复发**,但**攒得越多,那一次带过去的图越多、越贵**。
132
+ - 回话只取那一轮里**最后一段文字**;纯图轮的没有文字,不递。
133
+ - 攒图队列在**内存里**:DSH 重启就清空。图本身分两处:挂件自己在 `%LOCALAPPDATA%\鱼搭子\frames`
134
+ 留最近 20 张,插件收下的在 `~\.dsh\fish-buddy-frames`(按天数和张数自己清,见上面那节)。
135
+
136
+ ## 自测
137
+
138
+ ```bash
139
+ node tests/宿主半边.mjs # 75 项:真的起一个 http 口子发请求,不碰真实 DSH
140
+ node tests/网页半边.mjs # 设置页那半边
141
+ node tests/inbound-batching.mjs # 群消息攒批
142
+ node tests/inbound-lifecycle.mjs # 收消息生命周期
143
+ node tests/inbound-singleflight.mjs
144
+ ```
145
+
146
+ 挂件那边:`python ball.py --selftest`(108 项,含热区、气泡、弹幕、快捷键)。
147
+
148
+ ## 一起看(字幕白板)
149
+
150
+ 挂件的陪看在放视频/直播时,每出一句**定稿**字幕就推给插件(`POST /hands/subtitle`)。
151
+ 插件按会话留**最近 90 秒、最多 40 句**,每轮用 `systemPrompt.context` 现拼一段「【你正在看的】…」(挂在消息尾部,不动系统提示词的前缀,缓存才不掉)——
152
+
153
+ - **不写进对话历史**,所以不会越看越厚;没字幕时是空串,不占上下文;
154
+ - 她一眼看完,想说的时候再说,不用每句都应;
155
+ - 另外可开「随机搭话」(`随机搭话分钟`):每隔这么久掷一次骰子,中了就让 DSH 开一轮让她自己说一句。
156
+
157
+ ## 打游戏
158
+
159
+ 进游戏模式之后:悬浮球收起来,桌面只剩**飘的弹幕**(它说的话横着飞过去)和**弹幕框**(攒着最近几句)。
160
+
161
+ - **弹幕 / 弹幕框 / 气泡**都做了「缺字换字体」:主字体(站酷)没有的颜文字、符号自动换系统字体补,不出方块;
162
+ - **截图**按设定间隔抓,三种送法见上面「挂件设置 → 游戏」(每张都说 / 攒着);
163
+ - **主动看一眼**:攒着那一档里,隔 N 分钟她自己开口一次,顺带把攒的图带上;
164
+ - **锁定**:弹幕框锁住后是真穿透,全屏游戏里鼠标不会被它接住;解锁走右键菜单 / 设置 / 组合键;
165
+ - 弹幕框可以拖到**副屏**;弹幕本身只在主屏横飞(跨屏会两边各一半)。
166
+
167
+ ## 已经能用的
168
+
169
+ - **插件**:接线、回话递回、字幕白板、随机搭话、游戏截图三种送法、主动看一眼、检查更新、设置页
170
+ - **挂件**:电话(语音识别)、一起看(字幕)、游戏模式(弹幕 + 弹幕框 + 截图)、气泡、
171
+ 多显示器摆位、颜文字混排、组合键、锁定穿透
172
+
173
+ (各版本改了什么、最新是多少 —— 见 `CHANGELOG.md` 和 Releases。)
174
+
175
+ ---
176
+
177
+ ## 许可
178
+
179
+ [Yuuyuko-uu 插件许可 1.0](./LICENSE):允许使用、修改、商用;
180
+ 再分发时要在 README 第一屏注明原仓库和原作者;禁止把本项目说成自己的原创。
181
+ 这份许可不是 OSI 认证的开源许可,用之前请读一遍全文。