🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

鱼搭子 Yuuyuko-uu/dsh-fish-buddy

DeepSeek Harnessv0.8.2
Yuuyuko-uu2 天前有提交已提供中文文档扫描:高危

把桌面鲸鱼挂件的语音和截图接进会话

48.2/100
综合分
38
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/11/4 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-fish-buddy
npm 源 · dsh-fish-buddy 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么[目录]—
dsh 原生插件 · other
暂无时间戳·判据 →
装得上吗[实装验证]✓
静态安装检查通过
未做真实安装
暂无时间戳·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/06·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 2 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-fish-buddy @ 0.8.2
✓Node 引擎要求 >=22 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/4 03:20:33

🔴 安全扫描发现高危能力自动 · 静态分析源码
v2.7.0
🔴 扫描:高危尚无人工评估

静态扫描发现安装期即执行代码,或命令参数由运行时变量拼接(参数来源无法静态判定,从严处理)。

命令参数由运行时变量拼接读写/删除本地文件发起外部网络请求
查看扫描证据(共 55 处,展示前 28 条)
  • 读取本地文件
    lib/host.js:111
    名们 = readdirSync(目录).filter((x) => /\.(jpg|jpeg|png)$/i.test(String(x)))
  • 读取本地文件
    lib/host.js:118
    const 资 = statSync(join(目录, 名))
  • 删除本地文件
    lib/host.js:135
    unlinkSync(路)
  • 读取本地文件
    lib/host.js:154
    if (existsSync(新) || !existsSync(老)) return false
  • 读取本地文件
    lib/host.js:155
    const 原文 = readFileSync(老, 'utf8').replace(/^ FEFF/, '')
  • 写入本地文件
    lib/host.js:157
    mkdirSync(家目录, { recursive: true })
  • 写入本地文件
    lib/host.js:158
    writeFileSync(新, 原文, 'utf8')
  • 读取本地文件
    lib/host.js:254
    const 原文 = readFileSync(配置文件, 'utf8').replace(/^ FEFF/, '')
  • 写入本地文件
    lib/host.js:264
    mkdirSync(目录, { recursive: true })
  • 写入本地文件
    lib/host.js:265
    writeFileSync(配置文件, JSON.stringify(合, null, 2), 'utf8')
  • 读取本地文件
    lib/host.js:321
    const w = JSON.parse(readFileSync(join(目录, 'storages', 'workspace.json'), 'utf8'))
  • 发起网络请求
    lib/host.js:480
    const r = await fetch(配置.回调, {
  • 发起网络请求
    lib/host.js:806
    const r = await fetch(基 + '/hands/shot', {
  • 写入本地文件
    lib/host.js:817
    mkdirSync(帧目录, { recursive: true })
  • 写入本地文件
    lib/host.js:819
    writeFileSync(路, Buffer.from(图, 'base64'))
  • 请求外部主机raw.githubusercontent.com
    lib/host.js:1286
    const r = await fetch('https://raw.githubusercontent.com/' + 仓库 + '/main/package.json',
  • 发起网络请求
    lib/host.js:1286
    const r = await fetch('https://raw.githubusercontent.com/' + 仓库 + '/main/package.json',
  • 发起网络请求
    lib/host.js:1301
    const r = await fetch('http://127.0.0.1:' + 端口 + '/hands/devices', { signal: AbortSignal.timeout(3000) })
  • 请求外部主机api.github.com
    lib/host.js:1310
    const r = await fetch('https://api.github.com/repos/' + 仓库 + '/releases/latest',
  • 发起网络请求
    lib/host.js:1310
    const r = await fetch('https://api.github.com/repos/' + 仓库 + '/releases/latest',
  • 执行外部命令表达式求值
    lib/host.js:1376
    const 子 = spawn(路径, [], { detached: true, stdio: 'ignore', windowsHide: false })
  • 发起网络请求
    lib/host.js:1454
    const r = await fetch(基 + '/hands/devices')
  • 删除本地文件
    lib/host.js:1534
    unlinkSync(join(帧目录, 名))
  • 请求外部主机api.github.com
    lib/host.js:1769
    const r = await fetch('https://api.github.com/repos/Yuuyuko-uu/dsh-fish-buddy/releases/latest', {
  • 删除本地文件
    lib/host.js:1806
    try { if (existsSync(目标)) rmSync(目标) } catch (error) {}
  • 执行外部命令表达式求值
    lib/host.js:1873
    const 子 = spawn(路径, [], { detached: true, stdio: 'ignore', windowsHide: false })
  • 发起网络请求
    lib/client.js:17
    const get = (p) => fetch(B + p, { cache: 'no-store' }).then((r) => r.json()).catch(() => null)
  • 发起网络请求
    lib/client.js:19
    fetch(B + p, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body || {}) })
扫描于 2026/11/6(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包
涉及外部主机:raw.githubusercontent.com、api.github.com

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

鱼搭子:桌面小鲸鱼挂件 + DSH 插件(语音送话、陪看字幕、游戏弹幕、截图)

v0.8.22026-11-03
插件 0.8.2 设置页「绑哪间会话」只列活着的会话,关掉窗口就选不到了 · 🐞 现象:会话窗口一关,设置里就选不到它;「未分组」那批更是从来没出现过。 · 根因:清单来自 sessions.list(),那是内存里活着的会话,不是磁盘上的全部。 · ✅ 改成扫 ~/.dsh/sessions/(两级目录都认 = 含未分组),并且: - 归档的实时排除(先问 workspaceRegistry,读不到再读存储文件); - 子代理的会话(origin/delegationDepth)不列; - 空会话(没说过话、日志不到 1 KB)不列; - 标题优先用会话缓存,没有就回日志里捞第一句真话。 · 📦 顺手按约定补上 engines(市场读这个字段,之前显示"未声明宿主要求")。
v1.7.22026-11-03
· 程序 1.7.2 — 2026-11-03 悬浮窗有时候会跑到别的窗口下面去(不是置顶了) · 🐞 现象:鱼球用着用着就被别的窗口盖住,有时过一会儿自己回来了,有时一直压着。 · 根因:Windows 的「置顶」不是永久属性,只是 z 序里的一个层。 tkinter 的 wm_attributes('-topmost') 只在设置那一瞬间生效一次,之后没人管: - 别的置顶窗一激活,就排到我们头上; - 全屏程序切出来、显示器休眠唤醒,标记会丢; - 自己 withdraw() → deiconify() 走一遍(托盘「显示悬浮窗」、切游戏模式),标记也会丢; - 还有一处真 bug:overrideredirect 的球有外层包装窗,普通 Toplevel (设置窗 / 功能窗)没有 —— 以前统一拿 GetParent 的结果去操作,对后者拿到 0, 等于什么都没做。 · ✅ 新增 _真窗号():有包装窗用包装窗,没有就用它自己。 · ✅ 新增 钉到最上层():直接 SetWindowPos(HWND_TOPMOST),带 NOACTIVATE | NOMOVE | NOSIZE —— 只抬手,不抢焦点、不动位置。 · ✅ 新增每 1.2 秒的 _守置顶():只在真的掉了的时候才抬手(还在上面就什么都不做)。 · ✅ 重建浮窗、托盘「显示悬浮窗」、进游戏模式之后都会实钉一次。 · ⚠ 判断「掉了」只看 WS_EX_TOPMOST 这一位:一开始还比了 z 序上挨着的那个窗口,结果一直误报 —— Windows 的输入法候选框(MSCTFIME UI)和任务栏缩略图预览(ThumbnailDeviceHelperWnd) 本身就是置顶的,永远压在所有人头上。
v1.7.12026-11-03
· 程序 1.7.1 / 插件 0.8.1 — 2026-11-03 设置页的「游戏搭话秒」不生效(挂件没把这个值传给插件) · 🐞 现象:设置 → 游戏 → 「她主动看一眼:每 N 分钟」改了并保存,挂件自己的 config.json 里确实变了, 但插件那边(~/.dsh/fish-buddy-config.json)一直是默认的 180,实际还是 3 分钟说一次。 · 根因:挂件 _报游戏模式() 只发了 {"游戏": true/false},没带间隔值; 插件只能读自己配置里那份 —— 两边的值各走各的。 (其它节奏值如 随机搭话秒 / 冷却最短秒 / 安静秒 本来就有「挂件随消息报上来」的通道,唯独这一项漏了。) · ✅ 挂件:/hands/mode 的请求体现在带 搭话秒;游戏模式里改了这个值也会立刻重发一次,不用退出再进。 · ✅ 插件:/hands/mode 收下 搭话秒,存进「挂件报的节奏」这条现有通道;用时优先取挂件报的, 拿不到才回落到自己也配置里的默认值。 · ✅ 那一格也从分钟改成秒(0 = 不说,最少 10 秒):以前是 int(分钟),填 0.5 会被截成 0, 想要「30 秒」根本填不出来。
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
鱼搭子 桌面上一只小鲸鱼挂件 + 一个 DSH 插件。挂件负责听、看、说(语音、陪看字幕、游戏弹幕、截图),插件负责把它和你绑定的一间会话接起来 —— 挂件说的话进那间会话,那边的回话再递回挂件。 这个仓库里两半都在: | 目录 | 是什么 | | app/ | 桌面挂件(Python + tkinter,打包成单文件 exe) | | lib/ | DSH 插件(宿主半边 + 设置页) | | tests/ | 插件与程序的测试 | ⚠️ 两套版本号,别混:app/ 是挂件程序,lib/ 是 DSH 插件,各自独立涨(不是同一个数)。 - 当前是多少:看 app/version.py 和 package.json(README 里故意不写死,免得每发一版改一次) - 改了什么:看 CHANGELOG.md,条目开头会写「程序」还是「插件」 - 下载:看 Releases(exe 的资产名带版本号) 插件这半边干什么 1. 在本机开一个口子(默认 127.0.0.1:8777),收挂件发来的话; 2. 把这句话送进你绑定的那间会话(相当于你在那间里说了一句); 3. 她那间回完一轮 → 把回话递回挂件(POST 到你填的回调地址); 4. 收到截图/游戏画面时,把图片本身发进会话(先存成附件再引用);
展开完整文档(README 剩余 1 节)
鱼搭子

桌面上一只小鲸鱼挂件 + 一个 DSH 插件。挂件负责听、看、说(语音、陪看字幕、游戏弹幕、截图),插件负责把它和你绑定的一间会话接起来 —— 挂件说的话进那间会话,那边的回话再递回挂件。

这个仓库里两半都在:

| 目录 | 是什么 |
| app/ | 桌面挂件(Python + tkinter,打包成单文件 exe) |
| lib/ | DSH 插件(宿主半边 + 设置页) |
| tests/ | 插件与程序的测试 |

⚠️ 两套版本号,别混:app/ 是挂件程序,lib/ 是 DSH 插件,各自独立涨(不是同一个数)。
- 当前是多少:看 app/version.py 和 package.json(README 里故意不写死,免得每发一版改一次)
- 改了什么:看 CHANGELOG.md,条目开头会写「程序」还是「插件」
- 下载:看 Releases(exe 的资产名带版本号)

插件这半边干什么

1. 在本机开一个口子(默认 127.0.0.1:8777),收挂件发来的话;
2. 把这句话送进你绑定的那间会话(相当于你在那间里说了一句);
3. 她那间回完一轮 → 把回话递回挂件(POST 到你填的回调地址);
4. 收到截图/游戏画面时,把图片本身发进会话(先存成附件再引用);
5. 设置页里能看到:口子通不通、发来几条、最近发生了什么、她最近说的一句。

素材说明

app/assets/ 里的角色图、气泡框、弹幕框是随程序一起分发的素材,不单独授权二次使用。
app/assets/ocr/ 里是 PP-OCRv6 的检测/识别模型(Apache-2.0),app/assets/字体/ 里是站酷快乐体(免费商用)。

装好之后怎么配

先把插件装上(已经发布到 npm,不用 git):

dsh plugin --profile desktop add dsh-fish-buddy

也可以在 npm 上直接看到这个包(含历史版本):<https://www.npmjs.com/package/dsh-fish-buddy>

装完重启一次 DSH;挂件那个 exe 另外去 Releases 下。

DSH 设置 → 鱼搭子(第一栏):

| 项 | 填什么 |
| 开着 | 默认开。关掉之后挂件发什么都不往里送 |
| 送到哪一间 | 从下拉里选你那间会话(没选就送不进去) |
| 本机口子 | 端口,默认 8777。改端口要重启 DSH 才生效 |
| 回话递回 | 挂件那边留的接收地址,例如 http://127.0.0.1:8778/hands/reply |
| 标一句来源 | 塞进会话时前面加「(挂件里说的话)」,方便你分清是打字的还是说的 |
| 截图留几天 / 最多几张 | 插件自己攒的截图按这两条清(默认 30 天 / 800 张,填 0 = 那一条不限);只删它自己目录里的图 |
| 检查更新 | 点「查一下」:同时查插件本身(对比仓库 main 上的版本)和挂件 exe(对比最新 release) |

挂件设置 → 游戏:

| 项 | 填什么 |
| 截图怎么送 | 每张都说一遍:截一张就发一轮;攒着,说话时一起看:只存着,你说话(或她主动看一眼)时全部带过去 |
| 她主动看一眼 | 每 N 分钟自己开口一次(只在「攒着」那一档生效;「每张都说」时截图本来就叫醒她,再叠一层就是白花钱) |
| 组合键 | 退出游戏模式 / 锁解锁弹幕框,默认 Alt+G / Alt+H,写法 Ctrl+Alt+G、F9 都行 |
| 锁住弹幕框 | 锁上就是真穿透(鼠标穿到游戏里),解锁用右键菜单或这一项 |

语音识别模型怎么选

挂件 设置 → 语音 → 识别模型,三档选一个,装的时候只下选中的那一档:

| 档 | 大小 | 什么样 |
| 小 | 228MB | 默认。省 CPU,平时说话够用 —— 拿不准就选它 |
| 大 | 894MB | 识别最准,也最吃 CPU 和内存;机器一般的话,别的程序会跟着变慢 |
| 最快 | 78MB | 最省,但不出标点,字幕会连成一片 |

- 每档后面标着「已装 / 没装」,下载按钮只下当前选中的那一档;换档不用重下别的档。
- 电话、陪看、按住说话用的是同一档。换完,陪看要点一下「开始听」、电话要挂断重打一次,才用新的。
- 机器上已经有一档装好的,不会被当成「没装」:默认值变了,也还是先用那份能用的。
- 老版本放错地方的模型(models\sensevoice-fp32\、models\ 根上的 model.int8.onnx)第一次启动会自动搬到该在的目录,不用重下。
- 目录约定:models\ 根上是「大」,models\int8\ 是「小」,models\paraformer\ 是「最快」;每档目录里都叫 model.onnx + tokens.txt。

下不动的时候:2026-10-30 凌晨实测,国内镜像 hf-mirror.com 在限流 / 跳转,官方 huggingface.co 直连不通,那一刻确实下不了。下载本身(按档选仓库、按档落目录、断点续传、失败重试)是验过的,网络好了再点一次就行;已经下到一半的部分不会作废。

插件自己攒的截图会自己清

陪看抽的帧、她主动开口那张、按住说话带的那张,插件都在 ~\.dsh\fish-buddy-frames 留一份。
以前只进不出,用久了能堆几十上百 MB —— 现在按两条清:

- 留几天(默认 30)、最多几张(默认 800),在 DSH 设置 → 鱼搭子 → 第一栏里调;填 0 = 那一条不限。
- 插件一起来先清一次,之后每写一张图顺带看一眼(十分钟最多查一次目录,不会一直扫盘)。
- 只删这个目录里的图片(.jpg / .png),别的地方一概不碰;删了会在设置页「最近发生了什么」里记一行。

协议(挂件那边照这个对接)

挂件 → DSH

POST http://127.0.0.1:8777/hands/say {"text": "说了什么"} POST http://127.0.0.1:8777/hands/talk {"text": "说了什么", "图片": "<base64,可省>"} POST http://127.0.0.1:8777/hands/frame {"图片": "<base64>", "立即": 1|0, "存档": 1|0, "来源": "游戏"} POST http://127.0.0.1:8777/hands/mode {"游戏": true|false} POST http://127.0.0.1:8777/hands/subtitle {"字幕": [{"文本": "…", "ts": 1690000000}]} POST http://127.0.0.1:8777/hands/watch {"watch": true|false}

- /hands/talk 会把攒着的截图一起带过去(图片 可省)
- /hands/frame 的 存档=1:只存不叫醒(「攒着」用);立即=1:立刻发一轮
- /hands/say 也可以带 "session": "session-xxx" 指定这一次送进哪间
- 回:{"ok": true, "说": "送进去了"};没绑会话 / 会话没开 / 总开关关着 → 409 + 一句人话

DSH → 挂件

POST <设置页里填的回调地址> {"text": "她那句", "session": "session-xxx"} GET http://127.0.0.1:8778/hands/devices → {"ok": true, "设备": [...], "版本": "<挂件版本>"}

- 只递「挂件叫起来的那一轮」:你自己在 DSH 里聊的,不会往挂件推
- 回调没填就什么都不发(不会报错)

已知边界

- 端口是启动时定死的:改端口要重启 DSH。
- 会话得在 DSH 里打开过一次,否则 agents.get() 找不到它(会回一句「那间会话没开着」)。
- 每送一句话 = 一轮模型请求 = 花额度。上下文越长越贵:同一个上下文每轮都要重读一遍,所以「一小时说了多少次话」直接决定账单(实测:一小时 111 次、每次约 60 万 token 上下文 → 几十块)。
- 游戏截图会制造轮次:「每张都说」一小时能叫醒她几十轮;「攒着」只在你说话 / 主动看一眼时花一次。
攒着的图不删、不重复发,但攒得越多,那一次带过去的图越多、越贵。
- 回话只取那一轮里最后一段文字;纯图轮的没有文字,不递。
- 攒图队列在内存里:DSH 重启就清空。图本身分两处:挂件自己在 %LOCALAPPDATA%\鱼搭子\frames 留最近 20 张,插件收下的在 ~\.dsh\fish-buddy-frames(按天数和张数自己清,见上面那节)。

自测

node tests/宿主半边.mjs # 75 项:真的起一个 http 口子发请求,不碰真实 DSH
node tests/网页半边.mjs # 设置页那半边
node tests/inbound-batching.mjs # 群消息攒批
node tests/inbound-lifecycle.mjs # 收消息生命周期
node tests/inbound-singleflight.mjs

挂件那边:python ball.py --selftest(108 项,含热区、气泡、弹幕、快捷键)。

一起看(字幕白板)

挂件的陪看在放视频/直播时,每出一句定稿字幕就推给插件(POST /hands/subtitle)。
插件按会话留最近 90 秒、最多 40 句,每轮用 systemPrompt.context 现拼一段「【你正在看的】…」(挂在消息尾部,不动系统提示词的前缀,缓存才不掉)——

- 不写进对话历史,所以不会越看越厚;没字幕时是空串,不占上下文;
- 她一眼看完,想说的时候再说,不用每句都应;
- 另外可开「随机搭话」(随机搭话分钟):每隔这么久掷一次骰子,中了就让 DSH 开一轮让她自己说一句。

打游戏

进游戏模式之后:悬浮球收起来,桌面只剩飘的弹幕(它说的话横着飞过去)和弹幕框(攒着最近几句)。

- 弹幕 / 弹幕框 / 气泡都做了「缺字换字体」:主字体(站酷)没有的颜文字、符号自动换系统字体补,不出方块;
- 截图按设定间隔抓,三种送法见上面「挂件设置 → 游戏」(每张都说 / 攒着);
- 主动看一眼:攒着那一档里,隔 N 分钟她自己开口一次,顺带把攒的图带上;
- 锁定:弹幕框锁住后是真穿透,全屏游戏里鼠标不会被它接住;解锁走右键菜单 / 设置 / 组合键;
- 弹幕框可以拖到副屏;弹幕本身只在主屏横飞(跨屏会两边各一半)。

已经能用的

- 插件:接线、回话递回、字幕白板、随机搭话、游戏截图三种送法、主动看一眼、检查更新、设置页
- 挂件:电话(语音识别)、一起看(字幕)、游戏模式(弹幕 + 弹幕框 + 截图)、气泡、多显示器摆位、颜文字混排、组合键、锁定穿透

(各版本改了什么、最新是多少 —— 见 CHANGELOG.md 和 Releases。)

许可

Yuuyuko-uu 插件许可 1.0:允许使用、修改、商用;再分发时要在 README 第一屏注明原仓库和原作者;禁止把本项目说成自己的原创。
这份许可不是 OSI 认证的开源许可,用之前请读一遍全文。
预览分享卡片长什么样 ↓Yuuyuko-uu/dsh-fish-buddy
分享 · DeepSeek Harness Hub
Yuuyuko-uu/dsh-fish-buddy

把桌面鲸鱼挂件的语音和截图接进会话

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部