全部插件

DSH / BUNDLE / CLIENT-UI

dsh-kitt-voice

v1.0.0kittcat-lab / dsh-kitt-voice1a57fd7de4

可安装组合包UI 与客户端插件社区 · Topic 自动分析Web UI

概览

dsh-kitt-voice

DSH KITT — Spanish-first voice for the DeepSeek Harness web UI: hands-free conversation, push-to-talk (Whisper), read-aloud replies, and a floating overlay window with global hotkeys. · DSH KITT 语音:为 DeepSeek Harness 打造的语音插件——免提对话、按键说话(Whisper)、朗读回复,以及带全局快捷键的悬浮窗;界面支持中文、英文和西班牙语。

README / ZH

插件文档

DSH KITT

DeepSeek Harness 网页界面打造的语音插件——以西班牙语为首选语言,并且在无需注视浏览器的情况下也能使用。

按下一个按键,说出你的需求,智能体会用语音回答。一个小巧的悬浮窗会停留在你正在使用的任何应用之上,告诉你当前的状态。

状态:1.0 版,每天在用。 语音对话、悬浮窗和全局快捷键已完成并每天在使用。界面支持中文、英文和西班牙语。本地 Whisper 尚未实现;见 缺失的功能

为什么还需要一个语音插件

Harness 已有不错的语音插件,但没有一个能做到下面两件事,而其中一件不是靠努力就能做到的:

  • 它们不懂西班牙语。 它们的语音识别是为中文和英语设计的。dsh-kitt-voice 使用 Whisper——真正多语言的识别模型——并用 Piper 朗读,后者拥有优秀的西班牙语语音且完全在本地运行。
  • 浏览器一失焦它们就失效——因为插件活在网页里,而网页听不到别人没有给它的按键,也没法显示在全屏游戏之上。这正是悬浮窗存在的原因。

它能做什么

  • 真正的语音对话,而不是听写。 按一次就开始说。它听到你说完,转写、发送、等待回复并朗读出来,然后继续听。回合之间不需要按任何按钮。
  • 能分辨语音和噪音。 在嘈杂的房间里——电视、音乐、从扬声器传来的引擎声——用音量来判断你说完没有会失败:任何噪音都会被当成说话,而在免提模式下就意味着替你把噪音发给智能体。这里由真正的检测器——Silero——来决定。在本项目中的实测阈值是 0.30:静音 0.04,引擎噪音 0.13,低沉的轰鸣 0.10,哨声 0.16。后三者调大音量后,任何音量计都会被骗过。
  • 按键说话,如果你更喜欢这种方式。 按下麦克风或你的按键,说话,再按一次。文字会进入消息框;由你决定何时发送。
  • 边写边读。 在对话中,回复会一句一句地朗读,而智能体还在继续撰写,这样长回答不会先沉默十五秒。只有句子结束之后才会被朗读出来:半句话加一个停顿听起来像故障。代码块只会被说出名称,不会被逐字朗读。
  • 你可以打断它。 在它朗读时开口,它就会停下。这个门槛不是事先挑的数字:每次回复 开始的前半秒,麦克风会先听,而它听到的就是回声,因为那时还没有人说话。要算作 人声,必须超过这个底线三倍并持续三分之一秒。它在每次回复时重新测量,所以中途戴上 耳机会自动适应,而关门声太短,不足以触发它。
  • 每次回复只用一种声音。 引擎、语音和语速在回复开始时决定,并保持到回复结束。如果所选引擎失败,该回复的其余部分改用系统语音朗读,状态栏会说明;下一次回复会再次尝试该引擎。一次回复绝不会中途换声音。
  • 两个页面,一套按键。 当 Harness 在多个地方打开时,按键只会送到正在使用语音的页面——如果都没有在用,就送到你面前的那个。其他页面保持安静。
  • 值得一听的声音。 104 个神经语音,按语言和国家分组:45 个西班牙语——西班牙和美洲所有西语国家——47 个英语和 12 个中文。它们由微软的朗读服务提供,无需密钥、无需账户,代价说得很清楚:回复的文本会离开你的电脑。 除此之外什么都不会离开。
  • 按你自己的节奏。 朗读速度可以在半速到双倍之间调节,并适用于全部三种引擎:系统语音、Piper 和神经语音。听和读不一样,用别人的节奏听长回复很难跟上。在悬浮窗的菜单里设置即可,无需改任何文件。
  • 对话有铃声。 打开对话时响起升调,挂断时响起降调,让你仅凭声音就知道它正在聆听——而这正是你不看屏幕的时候。
  • 界面支持三种语言。 中文、英文和西班牙语,网页和悬浮窗都是如此。悬浮窗的语言在它自己的菜单里选择,与你说活时所用的语言相互独立。
  • 或者什么都不离开。 指向一个 Piper 语音文件夹,合成就在本机离线完成。就算两者都没有,它也能用系统自带的语音说话。从第一分钟起就能用;更好的语音是改进,不是前提。
  • 在哪里都能用的快捷键。 分配一个全局快捷键,就可以从任何应用——游戏、编辑器、任何东西——里和智能体说话。方向盘按钮映射到该按键同样有效。
  • 自己选择设备。 麦克风和声音输出分开选择,因为好的麦克风和好的扬声器很少是同一个设备。
  • 它总是告诉你正在发生什么——聆听中、转写中、朗读中——而一旦出错,它会说出是哪一部分、为什么。

安装

dsh plugin --profile web add dsh-kitt-voice

该命令会把包安装到 Harness 配置文件中,并自动把插件追加到配置文件的 bundle 列表(声明了 dsh.bundle 的依赖会自动加入层栈)。重启 Harness——彻底停止,而不是简单地重新启动,否则你仍在和旧进程对话。在输入框工具栏会出现麦克风和扬声器按钮。

卸载:

dsh plugin --profile web remove dsh-kitt-voice

同一个命令会同步 bundle 列表,只移除这个插件。旧版建议手动编辑 package.json,那属于旧版 CLI(会重写整个列表)的做法;当前版本按已安装状态同步。

不使用 npm,而是使用本地克隆: 让配置文件指向克隆目录。

dsh plugin --profile web add link:/绝对路径/to/dsh-kitt-voice

如果你的 Harness 使用其他配置文件名,把 web 换成你的名字。

关于包管理器打印的警告

安装时会提到某个依赖的安装脚本未被执行:msedge-tts,它的 preinstallnpx only-allow pnpm

没有缺失任何东西,而且那个脚本不应该被执行。 它不构建任何内容 —— 它是该库用来 强制其自身贡献者使用 pnpm 的一道闩,在任何其他包管理器下都会故意失败。该库发布 的是已编译的 JavaScript,不含原生代码。

在 npm 下这只是一条警告,安装会正常完成。在干净的机器上实测:npm install 以 0 退出,该库列出 322 个语音并返回真实音频,什么都没有构建,也没有安装任何本地语音。

在 pnpm 下 —— 也就是框架配置文件所使用的 —— 它是一个错误,会让整条命令失败:

[ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: msedge-tts@2.0.7

pnpm 会在你配置文件的 pnpm-workspace.yaml 里写下一行请你决定,并且让它保持未决:

allowBuilds:
  msedge-tts: set this to true or false

把它设为 false,然后重新运行命令:

allowBuilds:
  msedge-tts: false

看到就马上处理,因为只要那一行还没有决定,该配置文件里的每一次安装都会失败 —— 包括别人的插件,而那是一种相当令人困惑的发现方式。

配置

除转写密钥外,一切都在 设置 → 插件 → dsh-kitt-voice:识别器、语言、辅助词汇、语音文件夹、语音、麦克风和声音输出。

转写密钥来自 Harness 自己的凭据库——和智能体密钥所在的地方一样。无需创建任何东西,也无需重启:以 GROQ_API_KEY 保存即可,插件会找到它。如果你的密钥存在别的名字下,把 apiKeyRef 指向那个名字。

如果凭据库为空,则使用环境变量 DSH_KITT_API_KEYGROQ_API_KEY

密钥不会显示在设置里,也永远不会到达浏览器。页面只询问是否已配置,通过一个不可能返回值的调用。每次请求都会重新解析,所以更换密钥立即生效。

所有可以修改的设置

设置 作用
speechRate 朗读回复的速度。1 是语音本身的语速;0.5 是一半,2 是两倍。三种引擎都适用,包括系统语音——它由页面朗读而不是服务器。
uiLang 插件自身界面的语言:西班牙语、英语或简体中文。与转写语言相互独立——你可以用西班牙语口述而界面保持英文。
buttonColours 控件各有自己的颜色,或者全部为白色。颜色让人一眼看出每个控件的作用;朴素模式是给觉得那样太吵的人准备的。
overlayAuto 一使用语音就自动打开悬浮窗,并随框架一起关闭。默认关闭:一个自己冒出来的窗口,是没有人要求过的窗口。
micLabel 使用哪个麦克风,按名称。留空表示系统默认。刻意按名称而不按 id:浏览器会给每个来源分配不同的 id 来指代同一个物理设备,所以在悬浮窗里选中的 id 在页面里毫无意义。
outputLabel 回复从哪个扬声器或耳机播放,按名称。

识别器

选项 需要账户 在桌面应用中可用 说明
浏览器(默认) 仅 Chrome 和 Edge;音频经过浏览器厂商
Groq Whisper 精度和速度最佳;需要在凭据库中有密钥

浏览器识别器是默认项,让新用户几秒钟内就能说话。它在 Electron 中不可用——对象存在但识别每次都会失败——所以当 Harness 嵌入桌面应用时,插件会切换到 Groq 并明确告知。

西班牙语中夹杂的英语词

说西班牙语的人会在西语句子中间说出 setupbrake biasundersteer。只告诉 Whisper「西班牙语」,它会把它们按读音写成西语(cetapbreik baias),智能体收到的就是乱码。设置中的辅助词汇会发送给 Whisper,让这些术语保持英语。请按你自己的领域编辑它。

语音检测器

免提对话必须知道你何时说完一句话。那是一个模型——Silero v5——加上它的运行时,一共约十六兆字节。

它们不随本包一起发布。 大多数安装语音插件的人只想按一个按钮说话;让所有人都为可能永远不用的模式背负十六兆字节是不礼貌的。它们按以下两种方式之一到达,顺序如下:

  1. 一个你已有的文件夹,在设置中指定为 vadDir——什么都不下载;
  2. 一次有引导的下载,第一次开启对话时先告知大小。

无论哪种方式,文件都由 Harness 自己回传给页面,浏览器永远不会自行访问互联网,而且固定列表中的六个名字是唯一能成为路径的名字。

是六个文件,不是五个:检测器自己的包不携带推理运行时。它期望页面上已有一个,并且要先加载。

悬浮窗

cd overlay
start.cmd          Windows
./start.sh         macOS 和 Linux

Electron 不随包发布:Harness 是网页应用,大多数人不想要桌面窗口。启动器会使用你已经安装的 Electron——把 DSH_KITT_ELECTRON 指向它——或在这里运行 npm install 获取一个。

一条悬浮在所有东西之上(包括全屏游戏)的横条,横条就是控制区——和 Harness 自带工具栏里的完全相同:同样的图形、同样的颜色、同样的尺寸,因为它们本就是同一组控制,只是出现在两个地方。

  • 左侧的品牌字母 K——KITT 模式:免提连续对话,无需再按任何键。模式开启时它会显示当前状态的颜色——等待时蓝色,聆听时绿色,朗读时红色——思考或朗读时它的光晕会轻轻脉动。两边都可以关闭。旁边的「kittcat.com」文字会打开网站,而且只在空闲时;
  • 红色麦克风——按一次开始,说完再按一次;文字会落在输入框里,由你按 Enter 发送
  • 扬声器——再听一遍最后的回复,或让它停下;
  • 琥珀色带斜线的麦克风——静音。它是真的停止检测器,不是假装。这是为你没有看屏幕的时刻准备的:有人过来跟你说话,或者你要播放视频。静音只是让对话待命,不会挂断;
  • 齿轮——其他一切:麦克风、扬声器、语音、语速、语言和按钮配色;快捷键;停止朗读和外形;
  • ×——不打开菜单直接关闭窗口。关闭不是死路:下次启动语音时插件会重新打开它——但不会在你关掉它的那场对话中途重新打开——Harness 工具栏里的齿轮也随时能打开。

边框承载状态,可以用余光读取:静止时无颜色,聆听时为绿色——并随测得的音量增长——思考时为蓝色并缓慢呼吸,朗读时为红色。 如果出错,会显示闪烁的 ERROR 字样,无需解读任何颜色。

按住即可拖到任何位置,它会记住你留在哪里。

快捷键(在菜单中分配):F8 说话并发送,F9 开始或结束对话,F7 静音麦克风,F10 再次听回复,F11 停止朗读(在对话中同时停止等待回复),F6 打开菜单。想用方向盘按钮,就在方向盘自己的软件里把它映射到这些按键之一——无需任何手柄代码。属于整个系统的按键(Ctrl+C、Alt+F4 等)会被拒绝:全局快捷键会把按键从机器上的所有应用中夺走。

如果你的 Harness 不在 3081 端口,设置 DSH_KITT_PORT。它只接受端口,绝不接受 URL:窗口只能访问 loopback。

结构

lib/          插件
  index.js      服务器端:设置、HTTP 路由、捕获最后一条回复
  client.js     浏览器端:控制、录音、设置卡片
  guard.js      谁可以调用路由
  transcribe.js 语音转文字
  speak.js      使用本地 Piper 语音朗读
  chunk.js      把回复切分成可朗读的片段
  neural.js     神经语音,以及它们会让什么离开你的电脑
  overlay.js    使用语音时打开悬浮窗
  vad.js        语音检测器的文件,以及它们如何到达
  lastfromlog.js 从会话日志恢复最后一条回复
  apikey.js     每次调用解析密钥,从不缓存
  log.js        一行启动信息,以及被拒绝的请求——绝不含密钥
  freshness.js  检测服务器运行的是旧版插件
  paginas.js    多个页面同时打开时由哪一个响应按键
overlay/       悬浮窗(独立的 Electron 应用)
  main.js       窗口、外形和位置
  shortcuts.js  系统级快捷键
  requests.js   窗口可以向 Harness 请求的封闭列表
  textos.js     窗口显示的所有文字,三种语言
  index.html    它绘制的内容
test/          值得保护的部分

两半从不共享内存。它们通过 /dsh-kitt-voice 下的十三条 loopback 路由通信:configsettingsdevicesvoicestranscribespeaklaststatecommandordersvad/statusvad/downloadvad/file。每一条都会检查调用者。状态流向为页面 → 主机 → 悬浮窗;command 流向相反,是浏览器之外的按键到达页面的方式。

安全

  • 每条路由都检查调用者。 Loopback 不是隐私:你访问的任何页面都可以让你的浏览器向 127.0.0.1 发送请求。请求必须来自 loopback,携带 Origin 的请求必须指向这台服务器——相同的 loopback 写法、相同的端口(OriginHost 都由调用者写入,所以永远不信任它们彼此一致)。拒绝不会透露关于这台机器的任何信息。
  • 转写密钥永远不会到达浏览器,也永远不会被记录。页面只知道是否已配置。
  • 语音名不能变成路径。 在拼接到文件夹之前会经过严格校验。
  • 悬浮窗被牢牢锁住:上下文隔离开启、页面中没有 Node、沙箱、无导航、无新窗口、无浏览器权限,并且只能访问 127.0.0.1 上的可配置端口——永远不会接受别人给它的 URL。它的页面完全不发起网络调用:所有请求都由主进程对照 overlay/requests.js 的封闭列表转发,所以即使它自己的代码也无法把它指向别的服务器。
  • 文件名同样不能变成路径。 检测器的文件按固定六项列表按名提供;其他一切在构造路径之前就被拒绝。
  • 关闭窗口时归还全局快捷键。

测试

npm test

88 项测试,使用 node --test 运行,无需构建步骤。它们覆盖出错代价最高的部分:谁可以调用路由、语音名能否逃出它的文件夹、回复切分器承诺了什么、日志回退永远不会在它所服务的路由内部抛错、窗口的请求白名单、朗读句子切分器、交给语音的文本片段、两个页面同时打开时由哪一个响应按键,以及速度档位。

缺失的功能

  • 本地 Whisper。 会消除桌面应用中对密钥的需求。它需要模型管理和音频转换,尚未实现。
  • Windows 以外的一切。 这里没有任何 Windows 专属的东西——语音、窗口和快捷键都有对应方案——但它只在 Windows 上运行过。欢迎报告。

已经付过代价的陷阱

二十四个各花掉一整个下午的问题,连同它们的症状一并写下: 已经付过代价的陷阱。它们全都是在使用中暴露的, 而不是靠读代码发现的,而且没有一个报错。动到哪一部分之前,先读属于它的那一条。

许可证

MIT——见 LICENSE。参考过的既有项目在 NOTICE 中致谢。如何参与:CONTRIBUTING.md。变更记录:CHANGELOG.md

Kitt Cat 开发 · kittcat.com

English: README.md · Español: README.es.md