@flowingspring/dsh-voco 0.3.11 → 0.3.13
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.
- package/README.en.md +156 -0
- package/README.md +93 -45
- package/cordis.patch.yml +26 -26
- package/lib/client.js +46 -46
- package/lib/index.js +1 -1
- package/lib/invariant.js +1 -1
- package/lib/plugins/llm-tool-call-compat.js +1 -1
- package/lib/plugins/voice-assistant.js +20 -20
- package/lib/plugins/voice-local.js +5 -5
- package/lib/plugins/voice-web.js +3 -3
- package/lib/plugins/voice.js +2 -2
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +4 -0
- package/lib/types/index.js.map +1 -0
- package/lib/types/invariant.d.ts.map +1 -0
- package/lib/types/invariant.js +7 -0
- package/lib/types/invariant.js.map +1 -0
- package/package.json +53 -77
- package/README.i18n.yaml +0 -6
- package/README.zh.md +0 -108
package/README.en.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# dsh-voco
|
|
2
|
+
|
|
3
|
+
English | [中文](README.md)
|
|
4
|
+
|
|
5
|
+
`dsh-voco` is a voice conversation plugin for the DeepSeek Harness (DSH) Web UI. Speak a request naturally and work that needs project tools is delegated to a background Agent. The complete task report stays in the DSH task UI while Voice speaks a concise result.
|
|
6
|
+
|
|
7
|
+
The plugin uses SiliconFlow cloud speech recognition and Edge TTS. It is not a standalone browser extension and does not require a separate background service.
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
- Node.js 22.19 or newer (used by the DSH CLI).
|
|
12
|
+
- A DSH Web profile that can start successfully.
|
|
13
|
+
- A SiliconFlow API key. Voco uses the currently free [`XingChenAGI/XingChenASR-V3.2-Ultra`](https://cloud.siliconflow.cn/models?target=XingChenAGI/XingChenASR-V3.2-Ultra) speech-to-text model, but every user still needs their own key. Current availability and pricing are governed by the SiliconFlow model page.
|
|
14
|
+
- A modern browser with microphone support.
|
|
15
|
+
|
|
16
|
+
Install the DSH CLI first if it is not already available:
|
|
17
|
+
|
|
18
|
+
```powershell
|
|
19
|
+
npm install -g @deepseek-ai/dsh
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Option 1: Install from npm (recommended)
|
|
23
|
+
|
|
24
|
+
This is the intended path for regular users. It installs the one public plugin package without downloading or editing this repository:
|
|
25
|
+
|
|
26
|
+
```powershell
|
|
27
|
+
dsh plugin --profile web add @flowingspring/dsh-voco
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Start the DSH Web UI:
|
|
31
|
+
|
|
32
|
+
```powershell
|
|
33
|
+
dsh web
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Open the local URL printed by DSH, click the microphone in a session, and allow microphone access in the browser.
|
|
37
|
+
|
|
38
|
+
## Option 2: Install from a GitHub Release
|
|
39
|
+
|
|
40
|
+
GitHub Releases provide the same prebuilt plugin package as npm. No source checkout or pnpm development environment is required:
|
|
41
|
+
|
|
42
|
+
```powershell
|
|
43
|
+
dsh plugin --profile web add https://github.com/lgquan/dsh-voco/releases/download/v0.3.13/flowingspring-dsh-voco-0.3.13.tgz
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Release page: [v0.3.13](https://github.com/lgquan/dsh-voco/releases/tag/v0.3.13)
|
|
47
|
+
|
|
48
|
+
Whichever installation method you choose, start the Web UI through DSH:
|
|
49
|
+
|
|
50
|
+
```powershell
|
|
51
|
+
dsh web
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Configure the SiliconFlow API key
|
|
55
|
+
|
|
56
|
+
The only required secret is `SILICONFLOW_API_KEY`. Get your own key from the [SiliconFlow console](https://siliconflow.cn/). Speech-to-text uses SiliconFlow's currently free [`XingChenAGI/XingChenASR-V3.2-Ultra`](https://cloud.siliconflow.cn/models?target=XingChenAGI/XingChenASR-V3.2-Ultra) model; current availability and pricing are governed by the model page. Never put a real key in source code, commit it to GitHub, or share it with other users.
|
|
57
|
+
|
|
58
|
+
### Recommended: DSH settings
|
|
59
|
+
|
|
60
|
+
After starting DSH, open **Settings → Plugins → Plugin configuration**, expand **Voice Assistant (Voco)**, enter the API key, and save. The key is written to the DSH credentials store rather than the regular settings file, and the UI never reads the secret back. Start or reconnect Voice after saving.
|
|
61
|
+
|
|
62
|
+
Environment variables and `.env` remain supported for automation and existing deployments.
|
|
63
|
+
|
|
64
|
+
### Temporary: current PowerShell session
|
|
65
|
+
|
|
66
|
+
Set the variable in the same terminal that starts DSH:
|
|
67
|
+
|
|
68
|
+
```powershell
|
|
69
|
+
$env:SILICONFLOW_API_KEY = "sk-your-api-key"
|
|
70
|
+
dsh web
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The value disappears when that terminal closes.
|
|
74
|
+
|
|
75
|
+
### Persistent: DSH user environment file
|
|
76
|
+
|
|
77
|
+
Create `.env` in the DSH user directory. On Windows the default path is `%USERPROFILE%\.dsh\.env` (or `$DSH_HOME/.env` when `DSH_HOME` is set):
|
|
78
|
+
|
|
79
|
+
```dotenv
|
|
80
|
+
SILICONFLOW_API_KEY=sk-your-api-key
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
You may also create `.env` in the directory from which you run `dsh web`. The DSH credentials service reads these environment layers, and the plugin resolves `SILICONFLOW_API_KEY` through that service for each new voice connection. Do not enter the npm installation directory or edit files under `node_modules`.
|
|
84
|
+
|
|
85
|
+
An already inherited environment variable takes precedence, followed by the DSH credentials store and then `.env` fallbacks. Restart `dsh web` after changing `.env`, because the environment is loaded once per process.
|
|
86
|
+
|
|
87
|
+
## After installation
|
|
88
|
+
|
|
89
|
+
1. Run `dsh web` and open the DSH Web UI.
|
|
90
|
+
2. Create or select a session.
|
|
91
|
+
3. Click the microphone and grant browser permission.
|
|
92
|
+
4. Speak naturally. About 1.5 seconds of continuous silence ends an utterance and sends it to cloud recognition. You can also hold the microphone for about 400 ms to use push-to-talk; release it to submit only that utterance. A disconnected session stays muted after a push-to-talk submission so its spoken reply can arrive.
|
|
93
|
+
5. Ordinary conversation is handled in the frontend; work that needs project files, Shell, or other tools is delegated to the background Agent.
|
|
94
|
+
|
|
95
|
+
Voice sessions support interruption, reconnects, and history restoration. Each Voice Session keeps its own background Agent Session binding. When the context rotation threshold is reached, Voco creates a new child session for later tasks while keeping it under the same Voice Session.
|
|
96
|
+
|
|
97
|
+
## Update
|
|
98
|
+
|
|
99
|
+
Update from npm:
|
|
100
|
+
|
|
101
|
+
```powershell
|
|
102
|
+
dsh plugin --profile web add @flowingspring/dsh-voco
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
You can also install a specific GitHub Release `.tgz` URL. Restart `dsh web` after updating.
|
|
106
|
+
|
|
107
|
+
## Uninstall
|
|
108
|
+
|
|
109
|
+
```powershell
|
|
110
|
+
dsh plugin --profile web remove @flowingspring/dsh-voco
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Uninstalling the plugin does not remove a saved API key. To remove it completely, delete `SILICONFLOW_API_KEY` from `refs` in `%USERPROFILE%\.dsh\.credentials.yaml` (or `$DSH_HOME/.credentials.yaml` when configured), and remove the same name from the process environment or any `.env` file.
|
|
114
|
+
|
|
115
|
+
Uninstalling the plugin does not delete existing DSH sessions or Voice history. Confirm the relevant data directory before removing any stored data manually.
|
|
116
|
+
|
|
117
|
+
## Highlights
|
|
118
|
+
|
|
119
|
+
- SiliconFlow's free [`XingChenAGI/XingChenASR-V3.2-Ultra`](https://cloud.siliconflow.cn/models?target=XingChenAGI/XingChenASR-V3.2-Ultra) cloud speech-to-text model.
|
|
120
|
+
- Edge TTS `zh-CN-XiaoxiaoNeural` voice output.
|
|
121
|
+
- Voice, typed messages, and background Agent tasks in one DSH session.
|
|
122
|
+
- Immediate acknowledgement before delegation; full reports remain in the task UI.
|
|
123
|
+
- Voice binding survives navigation, reconnects, and DSH restarts.
|
|
124
|
+
- Optional integration with `@flowingspring/dsh-workspace-memory` for Workspace memory.
|
|
125
|
+
|
|
126
|
+
## Troubleshooting
|
|
127
|
+
|
|
128
|
+
### Missing API key when clicking the microphone
|
|
129
|
+
|
|
130
|
+
Make sure the DSH process can read `SILICONFLOW_API_KEY`. After creating or changing `.env`, stop the old DSH process and run `dsh web` again.
|
|
131
|
+
|
|
132
|
+
### No microphone or audio output
|
|
133
|
+
|
|
134
|
+
Check browser microphone permission and the system input device. Use the page served by `dsh web`; do not open an HTML file directly.
|
|
135
|
+
|
|
136
|
+
### Recognition fails or takes a long time
|
|
137
|
+
|
|
138
|
+
Speech recognition needs network access to SiliconFlow. Check connectivity, key validity, account quota, and the latency of the selected model and provider.
|
|
139
|
+
|
|
140
|
+
### Tuning silence detection
|
|
141
|
+
|
|
142
|
+
Advanced settings live in the plugin profile's `cordis.patch.yml`, including `silenceDurationMs`, `speechThreshold`, `minSpeechDurationMs`, and `maxUtteranceMs`. Most users can keep the defaults.
|
|
143
|
+
|
|
144
|
+
## Optional Workspace Memory
|
|
145
|
+
|
|
146
|
+
Workspace Memory is not required by Voco. Install `@flowingspring/dsh-workspace-memory` separately when needed; Voco also works by itself. See that project's documentation for its own installation and configuration.
|
|
147
|
+
|
|
148
|
+
## Development and support
|
|
149
|
+
|
|
150
|
+
- Source and issues: [GitHub](https://github.com/lgquan/dsh-voco)
|
|
151
|
+
- npm package: [`@flowingspring/dsh-voco`](https://www.npmjs.com/package/@flowingspring/dsh-voco)
|
|
152
|
+
- Architecture notes: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)
|
|
153
|
+
|
|
154
|
+
## License
|
|
155
|
+
|
|
156
|
+
[MIT](LICENSE)
|
package/README.md
CHANGED
|
@@ -1,108 +1,156 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-voco
|
|
2
2
|
|
|
3
|
-
[
|
|
4
|
-
[](https://github.com/lgquan/dsh-voco/blob/master/LICENSE)
|
|
3
|
+
[English](README.en.md) | 中文
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
`dsh-voco` 是面向 DeepSeek Harness(DSH)Web UI 的语音对话插件。它让你用自然语言说出需求,并将需要项目工具的工作委派给后台 Agent;完整任务报告仍保留在 DSH 会话中,语音只播报简洁结果。
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
插件使用硅基流动云端语音识别和 Edge TTS。它不是独立的浏览器扩展,也不需要单独运行一个后台服务。
|
|
9
8
|
|
|
10
|
-
##
|
|
9
|
+
## 安装前准备
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
- Node.js 22.19 或更高版本(安装 DSH CLI 时使用)。
|
|
12
|
+
- 一个已经可以运行的 DSH Web profile。
|
|
13
|
+
- 一个硅基流动 API Key。插件使用当前免费的语音转文字模型 [`XingChenAGI/XingChenASR-V3.2-Ultra`](https://cloud.siliconflow.cn/models?target=XingChenAGI/XingChenASR-V3.2-Ultra),但仍需用户自行申请 Key;免费状态和使用规则以硅基流动模型页面为准。
|
|
14
|
+
- 支持麦克风的现代浏览器。
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
如果还没有 DSH CLI,先安装:
|
|
15
17
|
|
|
16
18
|
```powershell
|
|
17
19
|
npm install -g @deepseek-ai/dsh
|
|
18
20
|
```
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
## 方式一:从 npm 安装(推荐)
|
|
23
|
+
|
|
24
|
+
这是普通用户最简单的安装方式。只安装公开的单一插件包,不需要下载或修改本仓库源码:
|
|
21
25
|
|
|
22
26
|
```powershell
|
|
23
27
|
dsh plugin --profile web add @flowingspring/dsh-voco
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
安装完成后启动 DSH Web:
|
|
31
|
+
|
|
32
|
+
```powershell
|
|
24
33
|
dsh web
|
|
25
34
|
```
|
|
26
35
|
|
|
27
|
-
|
|
36
|
+
打开终端显示的本地地址,在会话中点击麦克风并允许浏览器使用麦克风即可。
|
|
37
|
+
|
|
38
|
+
## 方式二:通过 GitHub Release 安装
|
|
28
39
|
|
|
29
|
-
GitHub
|
|
40
|
+
GitHub Release 提供和 npm 相同的预构建插件包,不需要 clone 源码或准备 pnpm 开发环境:
|
|
30
41
|
|
|
31
42
|
```powershell
|
|
32
|
-
dsh plugin --profile web add https://github.com/lgquan/dsh-voco/releases/download/v0.3.
|
|
43
|
+
dsh plugin --profile web add https://github.com/lgquan/dsh-voco/releases/download/v0.3.13/flowingspring-dsh-voco-0.3.13.tgz
|
|
33
44
|
```
|
|
34
45
|
|
|
35
|
-
Release
|
|
46
|
+
Release 页面:[v0.3.13](https://github.com/lgquan/dsh-voco/releases/tag/v0.3.13)
|
|
47
|
+
|
|
48
|
+
无论选择哪种安装方式,最后都通过 DSH 启动 Web UI:
|
|
49
|
+
|
|
50
|
+
```powershell
|
|
51
|
+
dsh web
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 配置硅基流动 API Key
|
|
55
|
+
|
|
56
|
+
插件只需要一个密钥:`SILICONFLOW_API_KEY`。请先在[硅基流动控制台](https://siliconflow.cn/)申请自己的 API Key。语音转文字使用硅基流动当前免费的 [`XingChenAGI/XingChenASR-V3.2-Ultra`](https://cloud.siliconflow.cn/models?target=XingChenAGI/XingChenASR-V3.2-Ultra);免费状态和使用规则以后续模型页面为准。不要把真实密钥写进源码、提交到 GitHub,或发送给其他人。
|
|
36
57
|
|
|
37
|
-
|
|
58
|
+
### 推荐配置:DSH 设置页面
|
|
38
59
|
|
|
39
|
-
|
|
60
|
+
启动 DSH 后打开“设置 → 插件 → 插件配置”,展开“语音助手(Voco)”,填写 API Key 并保存。密钥写入 DSH 的凭据库,不会写进普通设置文件,界面也不会读回密钥明文。保存后重新开启或重连语音即可生效。
|
|
40
61
|
|
|
41
|
-
|
|
62
|
+
下面的环境变量和 `.env` 方式继续保留,适合自动化或已有部署。
|
|
42
63
|
|
|
43
|
-
|
|
64
|
+
### 临时配置:当前 PowerShell 会话
|
|
44
65
|
|
|
45
|
-
|
|
66
|
+
在启动 DSH 的同一个终端中设置:
|
|
46
67
|
|
|
47
68
|
```powershell
|
|
48
69
|
$env:SILICONFLOW_API_KEY = "sk-your-api-key"
|
|
49
70
|
dsh web
|
|
50
71
|
```
|
|
51
72
|
|
|
52
|
-
|
|
73
|
+
关闭该终端后,变量会失效。
|
|
74
|
+
|
|
75
|
+
### 持久配置:DSH 用户环境文件
|
|
76
|
+
|
|
77
|
+
可以创建 DSH 用户目录下的 `.env`。默认位置是 Windows 的 `%USERPROFILE%\.dsh\.env`(如果设置了 `DSH_HOME`,则使用 `$DSH_HOME/.env`):
|
|
53
78
|
|
|
54
79
|
```dotenv
|
|
55
80
|
SILICONFLOW_API_KEY=sk-your-api-key
|
|
56
81
|
```
|
|
57
82
|
|
|
58
|
-
|
|
83
|
+
也可以在执行 `dsh web` 的当前目录创建 `.env`。DSH 凭据服务会读取这些环境层,插件在每次新建语音连接时通过凭据服务解析 `SILICONFLOW_API_KEY`。无需进入 npm 安装目录,也不要修改 `node_modules` 中的文件。
|
|
84
|
+
|
|
85
|
+
如果同时设置了系统环境变量、DSH 凭据库和 `.env`,已经继承的环境变量优先,其次是 DSH 凭据库。修改 `.env` 后请重启 `dsh web`,因为环境在进程启动时读取一次。
|
|
86
|
+
|
|
87
|
+
## 安装后怎么使用
|
|
59
88
|
|
|
60
|
-
|
|
89
|
+
1. 运行 `dsh web` 并打开 DSH Web UI。
|
|
90
|
+
2. 新建或选择一个会话。
|
|
91
|
+
3. 点击麦克风按钮并允许浏览器权限。
|
|
92
|
+
4. 直接说话;连续静音约 1.5 秒后,当前语句会提交给云端识别。也可以长按麦克风约 400 毫秒按住说话,松手后只提交这一段;未连接时长按会在提交后保持静音,以便接收语音回复。
|
|
93
|
+
5. 普通聊天由前台处理,需要读写项目或运行工具的工作会交给后台 Agent。
|
|
61
94
|
|
|
62
|
-
|
|
63
|
-
2. Create or select a session, click the microphone, and grant browser permission.
|
|
64
|
-
3. Speak naturally. About 1.5 seconds of continuous silence submits an utterance.
|
|
65
|
-
4. Ordinary conversation is answered in the frontend; work that needs project tools is delegated to the background Agent.
|
|
95
|
+
语音会话可以被打断、断线重连和恢复历史。每个语音会话会持续绑定自己的后台 Agent Session;上下文达到轮换阈值时,插件会为后续任务创建新的子会话,但仍归属于同一语音会话。
|
|
66
96
|
|
|
67
|
-
|
|
97
|
+
## 更新
|
|
68
98
|
|
|
69
|
-
|
|
99
|
+
使用 npm 更新到最新版本:
|
|
70
100
|
|
|
71
101
|
```powershell
|
|
72
102
|
dsh plugin --profile web add @flowingspring/dsh-voco
|
|
73
103
|
```
|
|
74
104
|
|
|
75
|
-
|
|
105
|
+
也可以改用指定的 GitHub Release `.tgz` 地址。更新后重启 `dsh web`。
|
|
76
106
|
|
|
77
|
-
##
|
|
107
|
+
## 卸载
|
|
78
108
|
|
|
79
109
|
```powershell
|
|
80
110
|
dsh plugin --profile web remove @flowingspring/dsh-voco
|
|
81
111
|
```
|
|
82
112
|
|
|
83
|
-
|
|
113
|
+
卸载插件不会自动删除已经保存的 API Key。需要彻底清除时,从 `%USERPROFILE%\.dsh\.credentials.yaml`(设置了 `DSH_HOME` 时为 `$DSH_HOME/.credentials.yaml`)的 `refs` 下删除 `SILICONFLOW_API_KEY`,并同时清理系统环境变量或 `.env` 中的同名配置。
|
|
114
|
+
|
|
115
|
+
卸载插件不会删除已经保存的 DSH 会话和语音历史;如需清理数据,请先确认对应数据目录后再手动处理。
|
|
116
|
+
|
|
117
|
+
## 主要能力
|
|
118
|
+
|
|
119
|
+
- SiliconFlow 免费模型 [`XingChenAGI/XingChenASR-V3.2-Ultra`](https://cloud.siliconflow.cn/models?target=XingChenAGI/XingChenASR-V3.2-Ultra) 云端语音转文字。
|
|
120
|
+
- Edge TTS `zh-CN-XiaoxiaoNeural` 中文语音回复。
|
|
121
|
+
- 语音、文字和后台 Agent 任务可以在同一 DSH 会话中协作。
|
|
122
|
+
- 委派前即时播报确认语,完整报告保留在任务界面。
|
|
123
|
+
- 页面切换、断线重连和 DSH 重启后恢复语音会话绑定。
|
|
124
|
+
- 可选接入 `@flowingspring/dsh-workspace-memory`;语音主会话和每个完成的委派子任务都会进入同一个 Workspace 长期记忆范围。
|
|
125
|
+
|
|
126
|
+
## 常见问题
|
|
127
|
+
|
|
128
|
+
### 点击麦克风提示缺少 API Key
|
|
129
|
+
|
|
130
|
+
确认启动 DSH 的进程能读到 `SILICONFLOW_API_KEY`。如果刚创建或修改了 `.env`,先停止旧的 DSH 进程,再重新运行 `dsh web`。
|
|
131
|
+
|
|
132
|
+
### 浏览器没有声音或无法录音
|
|
133
|
+
|
|
134
|
+
检查当前页面是否获得麦克风权限、系统输入设备是否正常,并确认使用的是 `dsh web` 提供的页面,而不是直接打开 HTML 文件。
|
|
135
|
+
|
|
136
|
+
### 识别失败或等待时间较长
|
|
84
137
|
|
|
85
|
-
|
|
138
|
+
语音识别需要访问硅基流动网络服务。请检查网络、API Key 有效期、账户额度,以及所选模型和 Provider 的响应延迟。
|
|
86
139
|
|
|
87
|
-
|
|
140
|
+
### 想调整静音和起音阈值
|
|
88
141
|
|
|
89
|
-
|
|
90
|
-
- Edge TTS `zh-CN-XiaoxiaoNeural` voice responses.
|
|
91
|
-
- Interruption, navigation, reconnects, and restored history.
|
|
92
|
-
- Immediate acknowledgement before delegation; full reports remain in the DSH task UI.
|
|
93
|
-
- Optional `@flowingspring/dsh-workspace-memory` integration for both the source Voice Session and every completed delegated child task.
|
|
142
|
+
高级参数位于插件 profile 的 `cordis.patch.yml`,包括 `silenceDurationMs`、`speechThreshold`、`minSpeechDurationMs` 和 `maxUtteranceMs`。普通用户通常不需要修改这些参数。
|
|
94
143
|
|
|
95
|
-
##
|
|
144
|
+
## 可选 Workspace Memory
|
|
96
145
|
|
|
97
|
-
|
|
98
|
-
- **Microphone unavailable**: check browser permission and the system input device, and make sure the page is served by `dsh web`.
|
|
99
|
-
- **Recognition fails or is slow**: check network access, key validity, SiliconFlow quota, and model/provider latency.
|
|
146
|
+
长期记忆不是 Voco 的必需依赖。需要时另外安装 `@flowingspring/dsh-workspace-memory`;只安装 Voco 也可以独立使用。安装 Memory 后,完成的委派任务会提交用户原始请求和最终可见结果,不会提交 reasoning、工具日志或注入上下文。Memory 插件的安装和配置请参阅其项目文档。
|
|
100
147
|
|
|
101
|
-
##
|
|
148
|
+
## 开发与反馈
|
|
102
149
|
|
|
103
|
-
- [GitHub
|
|
104
|
-
-
|
|
150
|
+
- 源码与问题反馈:[GitHub](https://github.com/lgquan/dsh-voco)
|
|
151
|
+
- npm 包:[`@flowingspring/dsh-voco`](https://www.npmjs.com/package/@flowingspring/dsh-voco)
|
|
152
|
+
- 架构说明:[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)
|
|
105
153
|
|
|
106
|
-
##
|
|
154
|
+
## 许可证
|
|
107
155
|
|
|
108
156
|
[MIT](LICENSE)
|
package/cordis.patch.yml
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
# Voice interaction mode layered after dsh-base and dsh-web-app.
|
|
2
|
-
- insert:
|
|
1
|
+
# Voice interaction mode layered after dsh-base and dsh-web-app.
|
|
2
|
+
- insert:
|
|
3
3
|
- id: llm-tool-call-compat
|
|
4
4
|
name: '@flowingspring/dsh-voco/llm-tool-call-compat'
|
|
5
5
|
|
|
6
6
|
- id: voice
|
|
7
7
|
name: '@flowingspring/dsh-voco/voice'
|
|
8
|
-
config:
|
|
9
|
-
provider: local
|
|
10
|
-
|
|
8
|
+
config:
|
|
9
|
+
provider: local
|
|
10
|
+
|
|
11
11
|
- id: voice-local
|
|
12
12
|
name: '@flowingspring/dsh-voco/voice-local'
|
|
13
|
-
config:
|
|
14
|
-
interactionMode: frontend-agent
|
|
15
|
-
inputSampleRate: 16000
|
|
16
|
-
outputSampleRate: 48000
|
|
17
|
-
ttsRate: '+20%'
|
|
18
|
-
silenceDurationMs: 1500
|
|
19
|
-
speechThreshold: 0.015
|
|
20
|
-
minSpeechDurationMs: 250
|
|
21
|
-
maxUtteranceMs: 60000
|
|
22
|
-
|
|
13
|
+
config:
|
|
14
|
+
interactionMode: frontend-agent
|
|
15
|
+
inputSampleRate: 16000
|
|
16
|
+
outputSampleRate: 48000
|
|
17
|
+
ttsRate: '+20%'
|
|
18
|
+
silenceDurationMs: 1500
|
|
19
|
+
speechThreshold: 0.015
|
|
20
|
+
minSpeechDurationMs: 250
|
|
21
|
+
maxUtteranceMs: 60000
|
|
22
|
+
|
|
23
23
|
- id: voice-assistant
|
|
24
24
|
name: '@flowingspring/dsh-voco/voice-assistant'
|
|
25
|
-
config:
|
|
26
|
-
maxPendingObservations: 64
|
|
25
|
+
config:
|
|
26
|
+
maxPendingObservations: 64
|
|
27
27
|
restoreConversation: true
|
|
28
28
|
memoryRecallTimeoutMs: 250
|
|
29
29
|
maxRestoredUtterances: 24
|
|
@@ -32,16 +32,16 @@
|
|
|
32
32
|
taskSessionRotationReserveTokens: 2048
|
|
33
33
|
taskSessionHandoffMaxChars: 12000
|
|
34
34
|
completedAnnouncement: 任务已完成。
|
|
35
|
-
failedAnnouncement: 任务失败了,请查看屏幕上的错误信息。
|
|
36
|
-
cancelledAnnouncement: 任务已取消。
|
|
37
|
-
interruptedAnnouncement: 上次任务因服务关闭而中断,没有自动重放。你可以告诉我是否继续。
|
|
38
|
-
|
|
35
|
+
failedAnnouncement: 任务失败了,请查看屏幕上的错误信息。
|
|
36
|
+
cancelledAnnouncement: 任务已取消。
|
|
37
|
+
interruptedAnnouncement: 上次任务因服务关闭而中断,没有自动重放。你可以告诉我是否继续。
|
|
38
|
+
|
|
39
39
|
- id: voice-web
|
|
40
40
|
name: '@flowingspring/dsh-voco/voice-web'
|
|
41
|
-
inject: [webRuntime]
|
|
42
|
-
config:
|
|
43
|
-
trustedHosts: !!js ctx.webRuntime.trustedHosts
|
|
44
|
-
maxAudioFrameBytes: 65536
|
|
45
|
-
|
|
41
|
+
inject: [webRuntime]
|
|
42
|
+
config:
|
|
43
|
+
trustedHosts: !!js ctx.webRuntime.trustedHosts
|
|
44
|
+
maxAudioFrameBytes: 65536
|
|
45
|
+
|
|
46
46
|
- id: ui-voice
|
|
47
47
|
name: '@flowingspring/dsh-voco'
|
package/lib/client.js
CHANGED
|
@@ -21,12 +21,12 @@ window.__ModuleLoader__.load({
|
|
|
21
21
|
var VoiceControl_module_css_default = {
|
|
22
22
|
"voice-pulse": "TFZsua_voice-pulse",
|
|
23
23
|
"active": "TFZsua_active",
|
|
24
|
-
"
|
|
24
|
+
"interruptButton": "TFZsua_interruptButton",
|
|
25
25
|
"button": "TFZsua_button",
|
|
26
|
-
"
|
|
26
|
+
"controls": "TFZsua_controls"
|
|
27
27
|
};
|
|
28
28
|
//#endregion
|
|
29
|
-
//#region
|
|
29
|
+
//#region packages/ui-voice/src/client/VoiceControl.tsx
|
|
30
30
|
/** Start a fresh Voice Session from this Session's location or control the active connection. */
|
|
31
31
|
function VoiceControl({ sessionId, useVoice, startVoice, retryVoice, beginPushToTalk, endPushToTalk, setVoiceMuted, t, interruptResponse }) {
|
|
32
32
|
const state = useVoice((snapshot) => snapshot.state);
|
|
@@ -191,7 +191,7 @@ window.__ModuleLoader__.load({
|
|
|
191
191
|
});
|
|
192
192
|
}
|
|
193
193
|
//#endregion
|
|
194
|
-
//#region
|
|
194
|
+
//#region packages/ui-voice/src/client/session-archive.ts
|
|
195
195
|
/**
|
|
196
196
|
* Returns whether a session is archived itself or inherits archive state from
|
|
197
197
|
* any known ancestor. The optional fallback resolves a parent when the
|
|
@@ -222,26 +222,26 @@ window.__ModuleLoader__.load({
|
|
|
222
222
|
document.head.appendChild(tag);
|
|
223
223
|
}
|
|
224
224
|
var VoiceNodeViews_module_css_default = {
|
|
225
|
-
"taskDetails": "Kt2smW_taskDetails",
|
|
226
|
-
"taskUpdate": "Kt2smW_taskUpdate",
|
|
227
|
-
"utterance": "Kt2smW_utterance",
|
|
228
225
|
"miniWave": "Kt2smW_miniWave",
|
|
229
226
|
"voiceBadge": "Kt2smW_voiceBadge",
|
|
230
|
-
"taskCard": "Kt2smW_taskCard",
|
|
231
|
-
"taskTitle": "Kt2smW_taskTitle",
|
|
232
|
-
"taskChevron": "Kt2smW_taskChevron",
|
|
233
|
-
"bubble": "Kt2smW_bubble",
|
|
234
|
-
"taskDot": "Kt2smW_taskDot",
|
|
235
|
-
"taskInput": "Kt2smW_taskInput",
|
|
236
|
-
"taskStatus": "Kt2smW_taskStatus",
|
|
237
227
|
"taskSummary": "Kt2smW_taskSummary",
|
|
228
|
+
"taskStatus": "Kt2smW_taskStatus",
|
|
229
|
+
"taskDot": "Kt2smW_taskDot",
|
|
230
|
+
"taskCancel": "Kt2smW_taskCancel",
|
|
231
|
+
"bubble": "Kt2smW_bubble",
|
|
232
|
+
"taskDetails": "Kt2smW_taskDetails",
|
|
238
233
|
"taskLink": "Kt2smW_taskLink",
|
|
234
|
+
"taskUpdate": "Kt2smW_taskUpdate",
|
|
235
|
+
"taskActions": "Kt2smW_taskActions",
|
|
236
|
+
"taskChevron": "Kt2smW_taskChevron",
|
|
237
|
+
"taskInput": "Kt2smW_taskInput",
|
|
238
|
+
"taskTitle": "Kt2smW_taskTitle",
|
|
239
|
+
"utterance": "Kt2smW_utterance",
|
|
239
240
|
"meta": "Kt2smW_meta",
|
|
240
|
-
"
|
|
241
|
-
"taskActions": "Kt2smW_taskActions"
|
|
241
|
+
"taskCard": "Kt2smW_taskCard"
|
|
242
242
|
};
|
|
243
243
|
//#endregion
|
|
244
|
-
//#region
|
|
244
|
+
//#region packages/ui-voice/src/client/VoiceNodeViews.tsx
|
|
245
245
|
/** Render a durable Voice utterance while replacing its unsettled text with live WebSocket deltas. */
|
|
246
246
|
function VoiceUtteranceView({ node, sessionId, useVoice, t }) {
|
|
247
247
|
const liveText = useVoice((snapshot) => snapshot.sessionId === sessionId ? snapshot.textById[String(node.data.utteranceId)]?.text : void 0);
|
|
@@ -377,13 +377,13 @@ window.__ModuleLoader__.load({
|
|
|
377
377
|
}
|
|
378
378
|
var VoiceOverlay_module_css_default = {
|
|
379
379
|
"root": "GPPB2G_root",
|
|
380
|
-
"status": "GPPB2G_status",
|
|
381
380
|
"wave": "GPPB2G_wave",
|
|
382
381
|
"voice-wave": "GPPB2G_voice-wave",
|
|
383
|
-
"stop": "GPPB2G_stop"
|
|
382
|
+
"stop": "GPPB2G_stop",
|
|
383
|
+
"status": "GPPB2G_status"
|
|
384
384
|
};
|
|
385
385
|
//#endregion
|
|
386
|
-
//#region
|
|
386
|
+
//#region packages/ui-voice/src/client/VoiceOverlay.tsx
|
|
387
387
|
const STATE_KEYS = {
|
|
388
388
|
connecting: "overlay.connecting",
|
|
389
389
|
listening: "overlay.listening",
|
|
@@ -439,11 +439,11 @@ window.__ModuleLoader__.load({
|
|
|
439
439
|
document.head.appendChild(tag);
|
|
440
440
|
}
|
|
441
441
|
var VoiceSessionMarkers_module_css_default = {
|
|
442
|
-
"
|
|
443
|
-
"
|
|
442
|
+
"slot": "_0brRca_slot",
|
|
443
|
+
"marker": "_0brRca_marker"
|
|
444
444
|
};
|
|
445
445
|
//#endregion
|
|
446
|
-
//#region
|
|
446
|
+
//#region packages/ui-voice/src/client/VoiceSessionMarkers.tsx
|
|
447
447
|
/**
|
|
448
448
|
* The workspace package owns the session-row renderer and filters addressed
|
|
449
449
|
* subagent children from its top-level list. This decorator only adds the
|
|
@@ -550,33 +550,33 @@ window.__ModuleLoader__.load({
|
|
|
550
550
|
document.head.appendChild(tag);
|
|
551
551
|
}
|
|
552
552
|
var VocoSettingsCard_module_css_default = {
|
|
553
|
-
"
|
|
554
|
-
"body": "G5LlXq_body",
|
|
553
|
+
"cardOpen": "G5LlXq_cardOpen",
|
|
555
554
|
"fieldHead": "G5LlXq_fieldHead",
|
|
555
|
+
"providerDetail": "G5LlXq_providerDetail",
|
|
556
|
+
"card": "G5LlXq_card",
|
|
556
557
|
"failed": "G5LlXq_failed",
|
|
557
|
-
"chevron": "G5LlXq_chevron",
|
|
558
|
-
"pending": "G5LlXq_pending",
|
|
559
|
-
"discard": "G5LlXq_discard",
|
|
560
|
-
"name": "G5LlXq_name",
|
|
561
|
-
"footer": "G5LlXq_footer",
|
|
562
|
-
"cardOpen": "G5LlXq_cardOpen",
|
|
563
|
-
"save": "G5LlXq_save",
|
|
564
558
|
"headText": "G5LlXq_headText",
|
|
565
559
|
"chevronOpen": "G5LlXq_chevronOpen",
|
|
566
|
-
"header": "G5LlXq_header",
|
|
567
|
-
"badgeMuted": "G5LlXq_badgeMuted",
|
|
568
|
-
"hint": "G5LlXq_hint",
|
|
569
|
-
"providerDetail": "G5LlXq_providerDetail",
|
|
570
560
|
"badge": "G5LlXq_badge",
|
|
571
|
-
"
|
|
561
|
+
"save": "G5LlXq_save",
|
|
562
|
+
"pending": "G5LlXq_pending",
|
|
563
|
+
"badgeMuted": "G5LlXq_badgeMuted",
|
|
572
564
|
"providerDetails": "G5LlXq_providerDetails",
|
|
565
|
+
"discard": "G5LlXq_discard",
|
|
566
|
+
"header": "G5LlXq_header",
|
|
567
|
+
"body": "G5LlXq_body",
|
|
568
|
+
"readOnly": "G5LlXq_readOnly",
|
|
569
|
+
"input": "G5LlXq_input",
|
|
570
|
+
"hint": "G5LlXq_hint",
|
|
571
|
+
"name": "G5LlXq_name",
|
|
572
|
+
"footer": "G5LlXq_footer",
|
|
573
573
|
"field": "G5LlXq_field",
|
|
574
|
-
"
|
|
574
|
+
"chevron": "G5LlXq_chevron",
|
|
575
575
|
"description": "G5LlXq_description",
|
|
576
576
|
"label": "G5LlXq_label"
|
|
577
577
|
};
|
|
578
578
|
//#endregion
|
|
579
|
-
//#region
|
|
579
|
+
//#region packages/ui-voice/src/client/VocoSettingsCard.tsx
|
|
580
580
|
/** Official plugin-settings slot contribution for the Voco credential. */
|
|
581
581
|
function VocoSettingsCard({ useVocoSettings, editApiKey, save, discard, t }) {
|
|
582
582
|
const [open, setOpen] = (0, react.useState)(false);
|
|
@@ -690,7 +690,7 @@ window.__ModuleLoader__.load({
|
|
|
690
690
|
});
|
|
691
691
|
}
|
|
692
692
|
//#endregion
|
|
693
|
-
//#region
|
|
693
|
+
//#region packages/ui-voice/src/client/voice-controller.ts
|
|
694
694
|
const INITIAL_SNAPSHOT = {
|
|
695
695
|
state: "off",
|
|
696
696
|
inputMuted: false,
|
|
@@ -1506,7 +1506,7 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1506
1506
|
node.start(start);
|
|
1507
1507
|
}
|
|
1508
1508
|
//#endregion
|
|
1509
|
-
//#region
|
|
1509
|
+
//#region packages/ui-voice/src/client/voice-history.ts
|
|
1510
1510
|
const STORAGE_KEY = "dsh.voice.history.v1";
|
|
1511
1511
|
function parseEntry(input) {
|
|
1512
1512
|
if (typeof input !== "object" || input === null) return void 0;
|
|
@@ -1637,7 +1637,7 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1637
1637
|
}
|
|
1638
1638
|
};
|
|
1639
1639
|
//#endregion
|
|
1640
|
-
//#region
|
|
1640
|
+
//#region packages/ui-voice/src/client/voice-text-submit.ts
|
|
1641
1641
|
/** Routes the native composer through Voice while preserving its ordinary offline submission. */
|
|
1642
1642
|
var VoiceTextSubmitBridge = class {
|
|
1643
1643
|
voice;
|
|
@@ -1683,7 +1683,7 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1683
1683
|
}
|
|
1684
1684
|
};
|
|
1685
1685
|
//#endregion
|
|
1686
|
-
//#region
|
|
1686
|
+
//#region packages/ui-voice/src/client/voice-definitions.ts
|
|
1687
1687
|
/** Fold one streamed utterance into a stable Chat node. */
|
|
1688
1688
|
const voiceUtteranceDefinition = {
|
|
1689
1689
|
kind: "voice-utterance",
|
|
@@ -1781,7 +1781,7 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1781
1781
|
}
|
|
1782
1782
|
};
|
|
1783
1783
|
//#endregion
|
|
1784
|
-
//#region
|
|
1784
|
+
//#region packages/ui-voice/src/client/locales.ts
|
|
1785
1785
|
/** `voice` namespace dictionaries. */
|
|
1786
1786
|
/** Dictionary namespace owned by this plugin. */
|
|
1787
1787
|
const NS = "voice";
|
|
@@ -1886,7 +1886,7 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1886
1886
|
"settings.saveFailed": "The key could not be saved and was kept for you to retry."
|
|
1887
1887
|
};
|
|
1888
1888
|
//#endregion
|
|
1889
|
-
//#region
|
|
1889
|
+
//#region packages/ui-voice/src/client/voco-settings-controller.ts
|
|
1890
1890
|
const VOCO_SETTINGS_NAMESPACE = "voice-local";
|
|
1891
1891
|
const SILICONFLOW_API_KEY_REF = "SILICONFLOW_API_KEY";
|
|
1892
1892
|
/** Bridges the voice-local namespace and the write-only DSH credentials API. */
|
|
@@ -1988,7 +1988,7 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1988
1988
|
}
|
|
1989
1989
|
};
|
|
1990
1990
|
//#endregion
|
|
1991
|
-
//#region
|
|
1991
|
+
//#region packages/ui-voice/src/client/index.ts
|
|
1992
1992
|
const inject = [
|
|
1993
1993
|
"conversation",
|
|
1994
1994
|
"conversationEvents",
|
package/lib/index.js
CHANGED
package/lib/invariant.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region
|
|
1
|
+
//#region packages/llm-tool-call-compat/src/index.ts
|
|
2
2
|
/** Restore metadata omitted as empty strings by some OpenAI-compatible gateways. */
|
|
3
3
|
function normalizeToolCallSseEvent(event, states) {
|
|
4
4
|
if (!event.startsWith("data: ")) return event;
|
|
@@ -10,7 +10,7 @@ import { ReasoningEffortId, createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
|
10
10
|
import { resolveSessionPreset } from "@deepseek-ai/dsh-agent-presets";
|
|
11
11
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
12
12
|
import { KNOWN_SESSION_EVENT_TYPES, SessionId, foldRequestHeader, snapshotJsonValue } from "@deepseek-ai/dsh-session";
|
|
13
|
-
//#region
|
|
13
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.js
|
|
14
14
|
var _a$1;
|
|
15
15
|
function $constructor(name, initializer, params) {
|
|
16
16
|
function init(inst, def) {
|
|
@@ -69,7 +69,7 @@ function config(newConfig) {
|
|
|
69
69
|
return globalConfig;
|
|
70
70
|
}
|
|
71
71
|
//#endregion
|
|
72
|
-
//#region
|
|
72
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/util.js
|
|
73
73
|
function getEnumValues(entries) {
|
|
74
74
|
const numericValues = Object.values(entries).filter((v) => typeof v === "number");
|
|
75
75
|
return Object.entries(entries).filter(([k, _]) => numericValues.indexOf(+k) === -1).map(([_, v]) => v);
|
|
@@ -383,7 +383,7 @@ function issue(...args) {
|
|
|
383
383
|
return { ...iss };
|
|
384
384
|
}
|
|
385
385
|
//#endregion
|
|
386
|
-
//#region
|
|
386
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/errors.js
|
|
387
387
|
const initializer$1 = (inst, def) => {
|
|
388
388
|
inst.name = "$ZodError";
|
|
389
389
|
Object.defineProperty(inst, "_zod", {
|
|
@@ -443,7 +443,7 @@ function formatError(error, mapper = (issue) => issue.message) {
|
|
|
443
443
|
return fieldErrors;
|
|
444
444
|
}
|
|
445
445
|
//#endregion
|
|
446
|
-
//#region
|
|
446
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/parse.js
|
|
447
447
|
const _parse = (_Err) => (schema, value, _ctx, _params) => {
|
|
448
448
|
const ctx = _ctx ? {
|
|
449
449
|
..._ctx,
|
|
@@ -557,7 +557,7 @@ const _safeDecodeAsync = (_Err) => async (schema, value, _ctx) => {
|
|
|
557
557
|
return _safeParseAsync(_Err)(schema, value, _ctx);
|
|
558
558
|
};
|
|
559
559
|
//#endregion
|
|
560
|
-
//#region
|
|
560
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/regexes.js
|
|
561
561
|
/**
|
|
562
562
|
* @deprecated CUID v1 is deprecated by its authors due to information leakage
|
|
563
563
|
* (timestamps embedded in the id). Use {@link cuid2} instead.
|
|
@@ -621,7 +621,7 @@ const boolean$1 = /^(?:true|false)$/i;
|
|
|
621
621
|
const lowercase = /^[^A-Z]*$/;
|
|
622
622
|
const uppercase = /^[^a-z]*$/;
|
|
623
623
|
//#endregion
|
|
624
|
-
//#region
|
|
624
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/checks.js
|
|
625
625
|
const $ZodCheck = /*@__PURE__*/ $constructor("$ZodCheck", (inst, def) => {
|
|
626
626
|
var _a;
|
|
627
627
|
inst._zod ?? (inst._zod = {});
|
|
@@ -983,7 +983,7 @@ const $ZodCheckOverwrite = /*@__PURE__*/ $constructor("$ZodCheckOverwrite", (ins
|
|
|
983
983
|
};
|
|
984
984
|
});
|
|
985
985
|
//#endregion
|
|
986
|
-
//#region
|
|
986
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/doc.js
|
|
987
987
|
var Doc = class {
|
|
988
988
|
constructor(args = []) {
|
|
989
989
|
this.content = [];
|
|
@@ -1014,14 +1014,14 @@ var Doc = class {
|
|
|
1014
1014
|
}
|
|
1015
1015
|
};
|
|
1016
1016
|
//#endregion
|
|
1017
|
-
//#region
|
|
1017
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/versions.js
|
|
1018
1018
|
const version = {
|
|
1019
1019
|
major: 4,
|
|
1020
1020
|
minor: 4,
|
|
1021
1021
|
patch: 3
|
|
1022
1022
|
};
|
|
1023
1023
|
//#endregion
|
|
1024
|
-
//#region
|
|
1024
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/schemas.js
|
|
1025
1025
|
const $ZodType = /*@__PURE__*/ $constructor("$ZodType", (inst, def) => {
|
|
1026
1026
|
var _a;
|
|
1027
1027
|
inst ?? (inst = {});
|
|
@@ -2198,7 +2198,7 @@ function handleRefineResult(result, payload, input, inst) {
|
|
|
2198
2198
|
}
|
|
2199
2199
|
}
|
|
2200
2200
|
//#endregion
|
|
2201
|
-
//#region
|
|
2201
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/registries.js
|
|
2202
2202
|
var _a;
|
|
2203
2203
|
var $ZodRegistry = class {
|
|
2204
2204
|
constructor() {
|
|
@@ -2245,7 +2245,7 @@ function registry() {
|
|
|
2245
2245
|
(_a = globalThis).__zod_globalRegistry ?? (_a.__zod_globalRegistry = registry());
|
|
2246
2246
|
const globalRegistry = globalThis.__zod_globalRegistry;
|
|
2247
2247
|
//#endregion
|
|
2248
|
-
//#region
|
|
2248
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/api.js
|
|
2249
2249
|
// @__NO_SIDE_EFFECTS__
|
|
2250
2250
|
function _string(Class, params) {
|
|
2251
2251
|
return new Class({
|
|
@@ -2750,7 +2750,7 @@ function _check(fn, params) {
|
|
|
2750
2750
|
return ch;
|
|
2751
2751
|
}
|
|
2752
2752
|
//#endregion
|
|
2753
|
-
//#region
|
|
2753
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/to-json-schema.js
|
|
2754
2754
|
function initializeContext(params) {
|
|
2755
2755
|
let target = params?.target ?? "draft-2020-12";
|
|
2756
2756
|
if (target === "draft-4") target = "draft-04";
|
|
@@ -3045,7 +3045,7 @@ const createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params)
|
|
|
3045
3045
|
return finalize(ctx, schema);
|
|
3046
3046
|
};
|
|
3047
3047
|
//#endregion
|
|
3048
|
-
//#region
|
|
3048
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/json-schema-processors.js
|
|
3049
3049
|
const formatMap = {
|
|
3050
3050
|
guid: "uuid",
|
|
3051
3051
|
url: "uri",
|
|
@@ -3277,7 +3277,7 @@ const optionalProcessor = (schema, ctx, _json, params) => {
|
|
|
3277
3277
|
seen.ref = def.innerType;
|
|
3278
3278
|
};
|
|
3279
3279
|
//#endregion
|
|
3280
|
-
//#region
|
|
3280
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/iso.js
|
|
3281
3281
|
const ZodISODateTime = /*@__PURE__*/ $constructor("ZodISODateTime", (inst, def) => {
|
|
3282
3282
|
$ZodISODateTime.init(inst, def);
|
|
3283
3283
|
ZodStringFormat.init(inst, def);
|
|
@@ -3307,7 +3307,7 @@ function duration(params) {
|
|
|
3307
3307
|
return /* @__PURE__ */ _isoDuration(ZodISODuration, params);
|
|
3308
3308
|
}
|
|
3309
3309
|
//#endregion
|
|
3310
|
-
//#region
|
|
3310
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/errors.js
|
|
3311
3311
|
const initializer = (inst, issues) => {
|
|
3312
3312
|
$ZodError.init(inst, issues);
|
|
3313
3313
|
inst.name = "ZodError";
|
|
@@ -3329,7 +3329,7 @@ const initializer = (inst, issues) => {
|
|
|
3329
3329
|
};
|
|
3330
3330
|
const ZodRealError = /*@__PURE__*/ $constructor("ZodError", initializer, { Parent: Error });
|
|
3331
3331
|
//#endregion
|
|
3332
|
-
//#region
|
|
3332
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/parse.js
|
|
3333
3333
|
const parse = /* @__PURE__ */ _parse(ZodRealError);
|
|
3334
3334
|
const parseAsync = /* @__PURE__ */ _parseAsync(ZodRealError);
|
|
3335
3335
|
const safeParse = /* @__PURE__ */ _safeParse(ZodRealError);
|
|
@@ -3343,7 +3343,7 @@ const safeDecode = /* @__PURE__ */ _safeDecode(ZodRealError);
|
|
|
3343
3343
|
const safeEncodeAsync = /* @__PURE__ */ _safeEncodeAsync(ZodRealError);
|
|
3344
3344
|
const safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync(ZodRealError);
|
|
3345
3345
|
//#endregion
|
|
3346
|
-
//#region
|
|
3346
|
+
//#region node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js
|
|
3347
3347
|
const _installedGroups = /* @__PURE__ */ new WeakMap();
|
|
3348
3348
|
function _installLazyMethods(inst, group, methods) {
|
|
3349
3349
|
const proto = Object.getPrototypeOf(inst);
|
|
@@ -4129,7 +4129,7 @@ function superRefine(fn, params) {
|
|
|
4129
4129
|
return /* @__PURE__ */ _superRefine(fn, params);
|
|
4130
4130
|
}
|
|
4131
4131
|
//#endregion
|
|
4132
|
-
//#region
|
|
4132
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-subagent@0_333a83db5ad7aba5051480205ed90428/node_modules/@deepseek-ai/dsh-subagent/lib/index.js
|
|
4133
4133
|
const DESCRIPTOR_BASE_KEYS = [
|
|
4134
4134
|
"version",
|
|
4135
4135
|
"mode",
|
|
@@ -4298,7 +4298,7 @@ Object.freeze({
|
|
|
4298
4298
|
persona: false
|
|
4299
4299
|
});
|
|
4300
4300
|
//#endregion
|
|
4301
|
-
//#region
|
|
4301
|
+
//#region packages/voice-assistant/src/tool.ts
|
|
4302
4302
|
const VOICE_MESSAGE_SECTION_ORDER = 118;
|
|
4303
4303
|
/**
|
|
4304
4304
|
* Install `send_voice_message` and its guidance into one delegated task Agent scope.
|
|
@@ -4401,7 +4401,7 @@ function installVoiceMessageTool(agentCtx, send, resolveDelegationId) {
|
|
|
4401
4401
|
};
|
|
4402
4402
|
}
|
|
4403
4403
|
//#endregion
|
|
4404
|
-
//#region
|
|
4404
|
+
//#region packages/voice-assistant/src/index.ts
|
|
4405
4405
|
/** Voice-to-Agent driver using ordinary followup, steer and cancel operations. @module @flowingspring/dsh-voice-assistant */
|
|
4406
4406
|
const name = "voice-assistant";
|
|
4407
4407
|
const inject = [
|
|
@@ -10,7 +10,7 @@ import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-sett
|
|
|
10
10
|
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
11
11
|
import { tmpdir } from "node:os";
|
|
12
12
|
import { EdgeTTS } from "node-edge-tts";
|
|
13
|
-
//#region
|
|
13
|
+
//#region packages/voice-local/src/edge-tts.ts
|
|
14
14
|
const EDGE_TTS_VOICE = "zh-CN-XiaoxiaoNeural";
|
|
15
15
|
const DEFAULT_EDGE_TTS_RATE = "+20%";
|
|
16
16
|
/** Edge TTS adapter. Returns the service's MP3 bytes for browser decoding. */
|
|
@@ -47,7 +47,7 @@ function splitSpeechText(text) {
|
|
|
47
47
|
return (normalized.match(/[^。!?!?;;::\n]+[。!?!?;;::]?|[^。!?!?;;::\n]+$/g) ?? [normalized]).map((part) => part.trim()).filter(Boolean);
|
|
48
48
|
}
|
|
49
49
|
//#endregion
|
|
50
|
-
//#region
|
|
50
|
+
//#region packages/voice-local/src/session.ts
|
|
51
51
|
/** Provider session translating local speech events to the shared voice seam. */
|
|
52
52
|
var LocalSession = class {
|
|
53
53
|
backend;
|
|
@@ -246,7 +246,7 @@ function isTerminalTaskStatus(status) {
|
|
|
246
246
|
return status === "completed" || status === "failed" || status === "cancelled" || status === "interrupted";
|
|
247
247
|
}
|
|
248
248
|
//#endregion
|
|
249
|
-
//#region
|
|
249
|
+
//#region packages/voice-local/src/siliconflow-asr.ts
|
|
250
250
|
const WAV_HEADER_BYTES = 44;
|
|
251
251
|
/** Upload one completed PCM utterance to SiliconFlow and return its final transcript. */
|
|
252
252
|
var SiliconFlowAsr = class {
|
|
@@ -306,7 +306,7 @@ function isRecord(value) {
|
|
|
306
306
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
307
307
|
}
|
|
308
308
|
//#endregion
|
|
309
|
-
//#region
|
|
309
|
+
//#region packages/voice-local/src/node-backend.ts
|
|
310
310
|
const INPUT_SAMPLE_RATE = 16e3;
|
|
311
311
|
/** Lightweight PCM silence detector plus SiliconFlow cloud ASR and Edge TTS. */
|
|
312
312
|
var NodeSpeechBackend = class {
|
|
@@ -557,7 +557,7 @@ function errorMessage(error) {
|
|
|
557
557
|
return error instanceof Error ? error.message : String(error);
|
|
558
558
|
}
|
|
559
559
|
//#endregion
|
|
560
|
-
//#region
|
|
560
|
+
//#region packages/voice-local/src/index.ts
|
|
561
561
|
/** Silence-gated SiliconFlow cloud ASR with Edge TTS. */
|
|
562
562
|
const name = "voice-local";
|
|
563
563
|
const inject = ["voice"];
|
package/lib/plugins/voice-web.js
CHANGED
|
@@ -3,7 +3,7 @@ import { randomUUID } from "node:crypto";
|
|
|
3
3
|
import z from "@deepseek-ai/schemastery";
|
|
4
4
|
import { SessionId } from "@deepseek-ai/dsh-session";
|
|
5
5
|
import WebSocket, { WebSocketServer } from "ws";
|
|
6
|
-
//#region
|
|
6
|
+
//#region packages/voice-web/src/loopback-hostname.ts
|
|
7
7
|
/**
|
|
8
8
|
* Browser-safe, zero-dependency loopback classification shared by the `/api`
|
|
9
9
|
* Host fence and the package's `ctx.connection` state. The predicate stays
|
|
@@ -20,7 +20,7 @@ function isLoopbackHostname(hostname) {
|
|
|
20
20
|
return parts.length === 4 && parts[0] === "127" && parts.every((part) => /^\d{1,3}$/.test(part) && Number(part) <= 255);
|
|
21
21
|
}
|
|
22
22
|
//#endregion
|
|
23
|
-
//#region
|
|
23
|
+
//#region packages/voice-web/src/api-request-trust.ts
|
|
24
24
|
function header(headers, name) {
|
|
25
25
|
if (headers instanceof Headers) return headers.get(name) ?? void 0;
|
|
26
26
|
const value = headers[name];
|
|
@@ -100,7 +100,7 @@ function isTrustedApiRequest(request, trustedHosts) {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
//#endregion
|
|
103
|
-
//#region
|
|
103
|
+
//#region packages/voice-web/src/index.ts
|
|
104
104
|
/** Dedicated browser WebSocket carrier for realtime voice audio and events. @module @flowingspring/dsh-voice-web */
|
|
105
105
|
const name = "voice-web";
|
|
106
106
|
const inject = ["voice", "webServer"];
|
package/lib/plugins/voice.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { Service } from "@deepseek-ai/cordis";
|
|
3
3
|
import z from "@deepseek-ai/schemastery";
|
|
4
|
-
//#region
|
|
4
|
+
//#region packages/voice/src/types.ts
|
|
5
5
|
/**
|
|
6
6
|
* Brand a raw id as a voice-session identity.
|
|
7
7
|
* @param value - raw identity.
|
|
@@ -51,7 +51,7 @@ function VoiceTaskMessageId(value) {
|
|
|
51
51
|
return value;
|
|
52
52
|
}
|
|
53
53
|
//#endregion
|
|
54
|
-
//#region
|
|
54
|
+
//#region packages/voice/src/index.ts
|
|
55
55
|
/** Provider-neutral realtime voice session capability seam. @module @flowingspring/dsh-voice */
|
|
56
56
|
/** Provider registry and connected-session coordinator. */
|
|
57
57
|
var VoiceRuntime = class extends Service {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,mEAAmE;AACnE,wBAAgB,KAAK,IAAI,IAAI,CAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,mEAAmE;AACnE,MAAM,UAAU,KAAK,KAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariant.d.ts","sourceRoot":"","sources":["../../src/invariant.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,eAAO,MAAM,IAAI,mBAAmB,CAAA;AACpC,eAAO,MAAM,MAAM,UAAiB,CAAA;AAGpC,qFAAqF;AACrF,eAAO,MAAM,KAAK,GAAI,KAAK,OAAO,KAAG,OAAO,CAAC,MAAM,IAAI,CAAiF,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const name = 'voco-invariant';
|
|
2
|
+
export const inject = ['invariants'];
|
|
3
|
+
/** No runtime invariant: this package is a static patch-list carrier. */
|
|
4
|
+
const install = () => { };
|
|
5
|
+
/** Register invariant ownership. @param ctx - runtime context. @returns disposer. */
|
|
6
|
+
export const apply = (ctx) => Promise.resolve(ctx.invariants.register('@flowingspring/dsh-voco', install));
|
|
7
|
+
//# sourceMappingURL=invariant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariant.js","sourceRoot":"","sources":["../../src/invariant.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,IAAI,GAAG,gBAAgB,CAAA;AACpC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,YAAY,CAAC,CAAA;AACpC,yEAAyE;AACzE,MAAM,OAAO,GAAuB,GAAG,EAAE,GAAE,CAAC,CAAA;AAC5C,qFAAqF;AACrF,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,GAAY,EAAuB,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,yBAAyB,EAAE,OAAO,CAAC,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
2
|
"name": "@flowingspring/dsh-voco",
|
|
3
3
|
"description": "Persistent voice conversations for DSH with cloud speech recognition, Edge TTS, and background Agent delegation",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.13",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
7
7
|
"dsh",
|
|
@@ -15,18 +15,17 @@
|
|
|
15
15
|
"bugs": {
|
|
16
16
|
"url": "https://github.com/lgquan/dsh-voco/issues"
|
|
17
17
|
},
|
|
18
|
-
"publishConfig": {
|
|
19
|
-
"access": "public"
|
|
20
|
-
},
|
|
21
|
-
"repository": {
|
|
22
|
-
"type": "git",
|
|
23
|
-
"url": "git+https://github.com/lgquan/dsh-voco.git"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"exports": {
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/lgquan/dsh-voco.git"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "lib/index.js",
|
|
27
|
+
"types": "lib/types/index.d.ts",
|
|
28
|
+
"exports": {
|
|
30
29
|
".": {
|
|
31
30
|
"types": "./lib/types/index.d.ts",
|
|
32
31
|
"default": "./lib/index.js"
|
|
@@ -45,35 +44,21 @@
|
|
|
45
44
|
"./voice-web": "./lib/plugins/voice-web.js",
|
|
46
45
|
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
47
46
|
"./package.json": "./package.json"
|
|
48
|
-
},
|
|
49
|
-
"files": [
|
|
50
|
-
"lib/index.js",
|
|
51
|
-
"lib/invariant.js",
|
|
52
|
-
"lib/client.js",
|
|
53
|
-
"lib/client.js.map",
|
|
54
|
-
"lib/plugins/*.js",
|
|
55
|
-
"cordis.patch.yml",
|
|
56
|
-
"lib/types/**/*.d.ts"
|
|
57
|
-
],
|
|
58
|
-
"license": "MIT",
|
|
59
|
-
"dsh": {
|
|
60
|
-
"bundle": {
|
|
61
|
-
"patch": "./cordis.patch.yml"
|
|
62
|
-
},
|
|
63
|
-
"client": {
|
|
64
|
-
"inject": [
|
|
65
|
-
"@deepseek-ai/dsh-client-connection",
|
|
66
|
-
"@deepseek-ai/dsh-client-locale",
|
|
67
|
-
"@deepseek-ai/dsh-client-runtime",
|
|
68
|
-
"@deepseek-ai/dsh-client-ui-settings",
|
|
69
|
-
"@deepseek-ai/dsh-client-ui-settings-plugins",
|
|
70
|
-
"@deepseek-ai/dsh-client-ui-conversation",
|
|
71
|
-
"@deepseek-ai/dsh-client-ui-layout",
|
|
72
|
-
"@deepseek-ai/dsh-client-ui-sidebar"
|
|
73
|
-
],
|
|
74
|
-
"platform": "web"
|
|
75
|
-
}
|
|
76
47
|
},
|
|
48
|
+
"packageManager": "pnpm@11.7.0",
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "tsc -b && node scripts/copy-types.mjs && tsdown",
|
|
54
|
+
"prepare": "pnpm run build",
|
|
55
|
+
"test": "vitest run",
|
|
56
|
+
"typecheck": "tsc -b"
|
|
57
|
+
},
|
|
58
|
+
"files": [
|
|
59
|
+
"cordis.patch.yml",
|
|
60
|
+
"lib"
|
|
61
|
+
],
|
|
77
62
|
"dependencies": {
|
|
78
63
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
79
64
|
"node-edge-tts": "1.2.10",
|
|
@@ -107,39 +92,30 @@
|
|
|
107
92
|
"react": "^18.2.0"
|
|
108
93
|
},
|
|
109
94
|
"devDependencies": {
|
|
110
|
-
"@
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
"
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
"
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
"@flowingspring/dsh-voice": "workspace:*",
|
|
137
|
-
"@flowingspring/dsh-voice-assistant": "workspace:*",
|
|
138
|
-
"@flowingspring/dsh-voice-local": "workspace:*",
|
|
139
|
-
"@flowingspring/dsh-voice-web": "workspace:*",
|
|
140
|
-
"@types/react": "~18.3.1",
|
|
141
|
-
"@types/ws": "^8.18.1",
|
|
142
|
-
"react": "^18.2.0",
|
|
143
|
-
"react-dom": "^18.2.0"
|
|
144
|
-
}
|
|
95
|
+
"@types/node": "^22.20.0",
|
|
96
|
+
"jsdom": "^30.0.1",
|
|
97
|
+
"lightningcss": "^1.32.0",
|
|
98
|
+
"tsdown": "^0.22.2",
|
|
99
|
+
"typescript": "^6.0.3",
|
|
100
|
+
"vitest": "^4.1.11"
|
|
101
|
+
},
|
|
102
|
+
"dsh": {
|
|
103
|
+
"bundle": {
|
|
104
|
+
"patch": "./cordis.patch.yml"
|
|
105
|
+
},
|
|
106
|
+
"client": {
|
|
107
|
+
"inject": [
|
|
108
|
+
"@deepseek-ai/dsh-client-connection",
|
|
109
|
+
"@deepseek-ai/dsh-client-locale",
|
|
110
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
111
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
112
|
+
"@deepseek-ai/dsh-client-ui-settings-plugins",
|
|
113
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
114
|
+
"@deepseek-ai/dsh-client-ui-layout",
|
|
115
|
+
"@deepseek-ai/dsh-client-ui-sidebar"
|
|
116
|
+
],
|
|
117
|
+
"platform": "web"
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"license": "MIT"
|
|
145
121
|
}
|
package/README.i18n.yaml
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
-
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
-
# after editing either side, bring the other along and re-record with:
|
|
4
|
-
# pnpm run verify-translation-pairing --write packages/bundle/voice-app/README.md
|
|
5
|
-
README.md: 3582129953c75938c6c08caa11526d5179f0631f
|
|
6
|
-
README.zh.md: f7253637cf50cf5b9677bee512e45fdadd8cc712
|
package/README.zh.md
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
# `@flowingspring/dsh-voco`
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/@flowingspring/dsh-voco)
|
|
4
|
-
[](https://github.com/lgquan/dsh-voco/blob/master/LICENSE)
|
|
5
|
-
|
|
6
|
-
[English](README.md) | 中文
|
|
7
|
-
|
|
8
|
-
面向 DeepSeek Harness(DSH)Web UI 的可恢复、可打断语音对话插件。它使用硅基流动云端语音识别和 Edge TTS,并把需要工具的工作委派给后台 Agent。
|
|
9
|
-
|
|
10
|
-
## 安装
|
|
11
|
-
|
|
12
|
-
### npm 安装(推荐)
|
|
13
|
-
|
|
14
|
-
先安装 DSH CLI:
|
|
15
|
-
|
|
16
|
-
```powershell
|
|
17
|
-
npm install -g @deepseek-ai/dsh
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
将插件加入 Web profile 并启动:
|
|
21
|
-
|
|
22
|
-
```powershell
|
|
23
|
-
dsh plugin --profile web add @flowingspring/dsh-voco
|
|
24
|
-
dsh web
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### GitHub Release 安装
|
|
28
|
-
|
|
29
|
-
GitHub Release 提供已经构建好的插件包,不需要下载源码或安装 pnpm:
|
|
30
|
-
|
|
31
|
-
```powershell
|
|
32
|
-
dsh plugin --profile web add https://github.com/lgquan/dsh-voco/releases/download/v0.3.11/flowingspring-dsh-voco-0.3.11.tgz
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Release 页面:[v0.3.11](https://github.com/lgquan/dsh-voco/releases/tag/v0.3.11)
|
|
36
|
-
|
|
37
|
-
## 配置 API Key
|
|
38
|
-
|
|
39
|
-
语音识别需要你自己的[硅基流动 API Key](https://siliconflow.cn/),配置名只有一个:`SILICONFLOW_API_KEY`。语音转文字使用硅基流动当前免费的 [`XingChenAGI/XingChenASR-V3.2-Ultra`](https://cloud.siliconflow.cn/models?target=XingChenAGI/XingChenASR-V3.2-Ultra);免费状态和使用规则以模型页面为准。Edge TTS 不需要 API Key。
|
|
40
|
-
|
|
41
|
-
推荐在 DSH 中打开“设置 → 插件 → 插件配置”,展开“语音助手(Voco)”,填写 API Key 并保存。密钥保存在 DSH 凭据库中,不写入普通设置文件;保存后重新开启或重连语音即可生效。
|
|
42
|
-
|
|
43
|
-
环境变量和 `.env` 仍作为兼容与自动化配置方式保留。
|
|
44
|
-
|
|
45
|
-
在启动 DSH 的同一个 PowerShell 中临时设置:
|
|
46
|
-
|
|
47
|
-
```powershell
|
|
48
|
-
$env:SILICONFLOW_API_KEY = "sk-your-api-key"
|
|
49
|
-
dsh web
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
要持久保存,可创建 DSH 用户环境文件 `%USERPROFILE%\.dsh\.env`(设置了 `DSH_HOME` 时使用 `$DSH_HOME/.env`):
|
|
53
|
-
|
|
54
|
-
```dotenv
|
|
55
|
-
SILICONFLOW_API_KEY=sk-your-api-key
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
也可在运行 `dsh web` 的当前目录放置 `.env`。修改后重启 DSH;不要修改 npm 安装目录或 `node_modules` 中的文件,也不要把真实密钥提交到 GitHub。
|
|
59
|
-
|
|
60
|
-
## 首次使用
|
|
61
|
-
|
|
62
|
-
1. 运行 `dsh web` 并打开 DSH Web UI。
|
|
63
|
-
2. 新建或选择会话,点击麦克风并允许浏览器权限。
|
|
64
|
-
3. 直接说话,连续静音约 1.5 秒后提交一句话;也可以长按麦克风约 400 毫秒按住说话,松手后提交这一段。
|
|
65
|
-
4. 普通聊天由前台回答,需要项目工具的工作会委派给后台 Agent。
|
|
66
|
-
|
|
67
|
-
每个语音会话持续绑定自己的后台 Agent Session。上下文达到轮换阈值后,后续任务会自动进入新的子会话,但仍与原语音会话绑定。
|
|
68
|
-
|
|
69
|
-
## 更新
|
|
70
|
-
|
|
71
|
-
```powershell
|
|
72
|
-
dsh plugin --profile web add @flowingspring/dsh-voco
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
也可以安装指定的 GitHub Release。更新后重启 `dsh web`。
|
|
76
|
-
|
|
77
|
-
## 卸载
|
|
78
|
-
|
|
79
|
-
```powershell
|
|
80
|
-
dsh plugin --profile web remove @flowingspring/dsh-voco
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
卸载不会自动删除 DSH 会话或语音历史。
|
|
84
|
-
|
|
85
|
-
卸载也不会删除已经保存的 API Key。需要彻底清除时,从 `%USERPROFILE%\.dsh\.credentials.yaml`(设置了 `DSH_HOME` 时为 `$DSH_HOME/.credentials.yaml`)的 `refs` 下删除 `SILICONFLOW_API_KEY`,并同时清理系统环境变量或 `.env` 中的同名配置。
|
|
86
|
-
|
|
87
|
-
## 功能
|
|
88
|
-
|
|
89
|
-
- SiliconFlow 免费模型 [`XingChenAGI/XingChenASR-V3.2-Ultra`](https://cloud.siliconflow.cn/models?target=XingChenAGI/XingChenASR-V3.2-Ultra) 云端语音转文字。
|
|
90
|
-
- Edge TTS `zh-CN-XiaoxiaoNeural` 语音回复。
|
|
91
|
-
- 语音打断、页面切换、断线重连和历史恢复。
|
|
92
|
-
- 委派前即时确认,完整报告保留在 DSH 任务界面。
|
|
93
|
-
- 可选接入 `@flowingspring/dsh-workspace-memory`,让语音主会话和每个完成的委派子任务共享同一 Workspace 长期记忆范围。
|
|
94
|
-
|
|
95
|
-
## 排查
|
|
96
|
-
|
|
97
|
-
- **缺少 API Key**:确认 `SILICONFLOW_API_KEY` 在启动 DSH 的进程中可见;修改 `.env` 后重启 `dsh web`。
|
|
98
|
-
- **无法录音**:检查浏览器麦克风权限和系统输入设备,并确认页面来自 `dsh web`。
|
|
99
|
-
- **识别失败或较慢**:检查网络、Key 有效期、硅基流动账户额度及模型/Provider 延迟。
|
|
100
|
-
|
|
101
|
-
## 链接
|
|
102
|
-
|
|
103
|
-
- [GitHub 源码与问题反馈](https://github.com/lgquan/dsh-voco)
|
|
104
|
-
- [npm 包](https://www.npmjs.com/package/@flowingspring/dsh-voco)
|
|
105
|
-
|
|
106
|
-
## 许可证
|
|
107
|
-
|
|
108
|
-
[MIT](LICENSE)
|