opencode-voice2text 0.1.0
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/LICENSE +21 -0
- package/README.md +228 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +706 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# opencode-voice2text
|
|
2
|
+
|
|
3
|
+
Streaming voice input for the OpenCode TUI using Volcengine ASR.
|
|
4
|
+
|
|
5
|
+
Press a shortcut once to start recognition, speak naturally while audio streams to Volcengine, and press the shortcut again to stop. Stable text is appended into the current OpenCode prompt while you are still speaking.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- True start/stop streaming with a single shortcut
|
|
10
|
+
- Stable utterances appear in the prompt before the session ends
|
|
11
|
+
- Prompt-right status indicator while recording or finalizing
|
|
12
|
+
- Works on macOS and Linux
|
|
13
|
+
- Keeps credentials out of the plugin repo
|
|
14
|
+
|
|
15
|
+
## Behavior
|
|
16
|
+
|
|
17
|
+
- First `Ctrl+S`: start microphone capture and streaming recognition
|
|
18
|
+
- While speaking: stable recognized text is appended to the current prompt
|
|
19
|
+
- Second `Ctrl+S`: stop capture, flush the final ASR result, append the remaining tail text
|
|
20
|
+
- Idle state shows no persistent status UI
|
|
21
|
+
|
|
22
|
+
## Why this is toggle-based
|
|
23
|
+
|
|
24
|
+
OpenCode's current TUI plugin API exposes keybind matching, but not key release events. That means true press-and-hold / release-to-stop behavior is not reliable in a plugin today.
|
|
25
|
+
|
|
26
|
+
## Requirements
|
|
27
|
+
|
|
28
|
+
- OpenCode with TUI plugin support
|
|
29
|
+
- Volcengine ASR credentials
|
|
30
|
+
- `rec` from Sox installed locally
|
|
31
|
+
|
|
32
|
+
macOS:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
brew install sox
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Ubuntu/Debian:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
sudo apt install sox
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
Preferred install command:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
opencode plugin opencode-voice2text@latest --global
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This is the same style used by `opencode-dynamic-context-pruning`. The OpenCode CLI installs the npm package and updates your OpenCode plugin config for you.
|
|
53
|
+
|
|
54
|
+
If you only want it in the current project instead of globally, omit `--global`:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
opencode plugin opencode-voice2text@latest
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## TUI config
|
|
61
|
+
|
|
62
|
+
OpenCode's plugin installer manages the server/plugin registration, but this plugin still needs a TUI keybind, so keep this in:
|
|
63
|
+
|
|
64
|
+
`~/.config/opencode/tui.json`
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"$schema": "https://opencode.ai/tui.json",
|
|
69
|
+
"keybinds": {
|
|
70
|
+
"terminal_suspend": "none"
|
|
71
|
+
},
|
|
72
|
+
"plugin": [
|
|
73
|
+
[
|
|
74
|
+
"opencode-voice2text",
|
|
75
|
+
{
|
|
76
|
+
"commandKeybind": "ctrl+s"
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
If you choose a different shortcut, make sure it does not conflict with an existing TUI keybind.
|
|
84
|
+
|
|
85
|
+
## Restart OpenCode
|
|
86
|
+
|
|
87
|
+
If OpenCode is already running, restart it so the plugin and dependency tree are loaded again.
|
|
88
|
+
|
|
89
|
+
## Credentials
|
|
90
|
+
|
|
91
|
+
Create a local config file on the target machine:
|
|
92
|
+
|
|
93
|
+
`~/.config/opencode/voice2text.local.json`
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"appId": "your-volcengine-app-id",
|
|
98
|
+
"accessToken": "your-volcengine-access-token",
|
|
99
|
+
"resourceId": "volc.seedasr.sauc.duration",
|
|
100
|
+
"endpoint": "wss://openspeech.bytedance.com/api/v3/sauc/bigmodel_async",
|
|
101
|
+
"language": "zh-CN",
|
|
102
|
+
"chunkMs": 200,
|
|
103
|
+
"endWindowSize": 800,
|
|
104
|
+
"maxDurationSeconds": 180,
|
|
105
|
+
"appendTrailingSpace": true,
|
|
106
|
+
"rate": 16000,
|
|
107
|
+
"bits": 16,
|
|
108
|
+
"channels": 1
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
An example template also lives in `examples/voice2text.local.example.json`.
|
|
113
|
+
|
|
114
|
+
You can override the config path with:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
export OPENCODE_VOICE2TEXT_LOCAL_CONFIG=/path/to/voice2text.local.json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Environment variables
|
|
121
|
+
|
|
122
|
+
These can override or replace values from the local config file:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
export OPENCODE_VOICE2TEXT_APP_ID=...
|
|
126
|
+
export OPENCODE_VOICE2TEXT_ACCESS_TOKEN=...
|
|
127
|
+
export OPENCODE_VOICE2TEXT_RESOURCE_ID=volc.seedasr.sauc.duration
|
|
128
|
+
export OPENCODE_VOICE2TEXT_ENDPOINT=wss://openspeech.bytedance.com/api/v3/sauc/bigmodel_async
|
|
129
|
+
export OPENCODE_VOICE2TEXT_LANGUAGE=zh-CN
|
|
130
|
+
export OPENCODE_VOICE2TEXT_CHUNK_MS=200
|
|
131
|
+
export OPENCODE_VOICE2TEXT_END_WINDOW_SIZE=800
|
|
132
|
+
export OPENCODE_VOICE2TEXT_MAX_DURATION_SECONDS=180
|
|
133
|
+
export OPENCODE_VOICE2TEXT_APPEND_TRAILING_SPACE=true
|
|
134
|
+
export OPENCODE_VOICE2TEXT_SAMPLE_RATE=16000
|
|
135
|
+
export OPENCODE_VOICE2TEXT_BITS=16
|
|
136
|
+
export OPENCODE_VOICE2TEXT_CHANNELS=1
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Plugin options
|
|
140
|
+
|
|
141
|
+
You can pass the same runtime options through `tui.json`:
|
|
142
|
+
|
|
143
|
+
- `commandKeybind`
|
|
144
|
+
- `endpoint`
|
|
145
|
+
- `appId`
|
|
146
|
+
- `accessToken`
|
|
147
|
+
- `resourceId`
|
|
148
|
+
- `language`
|
|
149
|
+
- `chunkMs`
|
|
150
|
+
- `endWindowSize`
|
|
151
|
+
- `maxDurationSeconds`
|
|
152
|
+
- `appendTrailingSpace`
|
|
153
|
+
- `rate`
|
|
154
|
+
- `bits`
|
|
155
|
+
- `channels`
|
|
156
|
+
|
|
157
|
+
In practice, credentials are best kept in the local config file or environment variables rather than in `tui.json`.
|
|
158
|
+
|
|
159
|
+
## Development
|
|
160
|
+
|
|
161
|
+
Install dependencies and build:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
npm install
|
|
165
|
+
npm run build
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Type-check only:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
npm run typecheck
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Publishing
|
|
175
|
+
|
|
176
|
+
### Automatic publish from GitHub Actions
|
|
177
|
+
|
|
178
|
+
This repository now includes `.github/workflows/publish.yml`.
|
|
179
|
+
|
|
180
|
+
Behavior:
|
|
181
|
+
|
|
182
|
+
- every push to `master` runs typecheck and build
|
|
183
|
+
- the workflow checks whether `package.json`'s current `name@version` already exists on npm
|
|
184
|
+
- if that version is not published yet, it runs `npm publish`
|
|
185
|
+
- if that version already exists, the workflow exits cleanly without failing
|
|
186
|
+
|
|
187
|
+
Required GitHub secret:
|
|
188
|
+
|
|
189
|
+
- `NPM_TOKEN`
|
|
190
|
+
|
|
191
|
+
Create an npm automation token, then add it in GitHub:
|
|
192
|
+
|
|
193
|
+
- repository `Settings`
|
|
194
|
+
- `Secrets and variables`
|
|
195
|
+
- `Actions`
|
|
196
|
+
- `New repository secret`
|
|
197
|
+
- name: `NPM_TOKEN`
|
|
198
|
+
|
|
199
|
+
Important release rule:
|
|
200
|
+
|
|
201
|
+
- before pushing to `master`, bump `package.json` version if you want a new npm release
|
|
202
|
+
- if you push code without changing the version, CI will skip publishing because npm versions are immutable
|
|
203
|
+
|
|
204
|
+
Version bump examples:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
npm version patch
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
or:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
npm version minor
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Manual publish
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
npm publish
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
`prepublishOnly` runs the build automatically.
|
|
223
|
+
|
|
224
|
+
## Notes
|
|
225
|
+
|
|
226
|
+
- The plugin uses Volcengine's websocket ASR protocol directly.
|
|
227
|
+
- Success toasts are intentionally not shown; ongoing state is visible near the prompt instead.
|
|
228
|
+
- Errors still surface as OpenCode toasts.
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,706 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@opentui/solid/jsx-runtime";
|
|
2
|
+
/** @jsxImportSource @opentui/solid */
|
|
3
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import tls from "node:tls";
|
|
8
|
+
import zlib from "node:zlib";
|
|
9
|
+
import { promises as fs } from "node:fs";
|
|
10
|
+
import { Show, createMemo } from "solid-js";
|
|
11
|
+
const WS_OPCODE_BINARY = 0x2;
|
|
12
|
+
const WS_OPCODE_CLOSE = 0x8;
|
|
13
|
+
const WS_OPCODE_PING = 0x9;
|
|
14
|
+
const WS_OPCODE_PONG = 0xA;
|
|
15
|
+
const HEADER_VERSION = 0x1;
|
|
16
|
+
const HEADER_SIZE = 0x1;
|
|
17
|
+
const MESSAGE_TYPE_FULL_CLIENT_REQUEST = 0x1;
|
|
18
|
+
const MESSAGE_TYPE_AUDIO_ONLY_REQUEST = 0x2;
|
|
19
|
+
const MESSAGE_TYPE_ERROR = 0xF;
|
|
20
|
+
const SERIALIZATION_NONE = 0x0;
|
|
21
|
+
const SERIALIZATION_JSON = 0x1;
|
|
22
|
+
const COMPRESSION_GZIP = 0x1;
|
|
23
|
+
const DEFAULT_CONFIG_PATH = path.join(os.homedir(), ".config/opencode/voice2text.local.json");
|
|
24
|
+
const DEFAULT_ENDPOINT = "wss://openspeech.bytedance.com/api/v3/sauc/bigmodel_async";
|
|
25
|
+
const DEFAULT_RESOURCE_ID = "volc.seedasr.sauc.duration";
|
|
26
|
+
const DEFAULT_CHUNK_MS = 200;
|
|
27
|
+
const DEFAULT_RATE = 16000;
|
|
28
|
+
const DEFAULT_BITS = 16;
|
|
29
|
+
const DEFAULT_CHANNELS = 1;
|
|
30
|
+
const DEFAULT_END_WINDOW_SIZE = 800;
|
|
31
|
+
const STATUS_KEY = "opencode_voice2text.status";
|
|
32
|
+
const STATUS_MESSAGE_KEY = "opencode_voice2text.status_message";
|
|
33
|
+
function str(value, fallback = "") {
|
|
34
|
+
return typeof value === "string" && value.trim() ? value.trim() : fallback;
|
|
35
|
+
}
|
|
36
|
+
function num(value, fallback) {
|
|
37
|
+
const parsed = Number(value);
|
|
38
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
39
|
+
}
|
|
40
|
+
function bool(value, fallback) {
|
|
41
|
+
if (typeof value === "boolean")
|
|
42
|
+
return value;
|
|
43
|
+
if (value === "true")
|
|
44
|
+
return true;
|
|
45
|
+
if (value === "false")
|
|
46
|
+
return false;
|
|
47
|
+
return fallback;
|
|
48
|
+
}
|
|
49
|
+
function appendableText(text) {
|
|
50
|
+
return typeof text === "string" ? text.trim() : "";
|
|
51
|
+
}
|
|
52
|
+
function diffSuffix(previous, next) {
|
|
53
|
+
if (!next)
|
|
54
|
+
return "";
|
|
55
|
+
if (!previous)
|
|
56
|
+
return next;
|
|
57
|
+
if (next.startsWith(previous))
|
|
58
|
+
return next.slice(previous.length).trim();
|
|
59
|
+
return "";
|
|
60
|
+
}
|
|
61
|
+
function platformLabel() {
|
|
62
|
+
if (process.platform === "darwin")
|
|
63
|
+
return "macOS";
|
|
64
|
+
if (process.platform === "linux")
|
|
65
|
+
return "Linux";
|
|
66
|
+
return process.platform;
|
|
67
|
+
}
|
|
68
|
+
function installHint() {
|
|
69
|
+
if (process.platform === "darwin")
|
|
70
|
+
return "Missing recorder 'rec'. Install Sox with: brew install sox";
|
|
71
|
+
if (process.platform === "linux")
|
|
72
|
+
return "Missing recorder 'rec'. Install Sox with: sudo apt install sox";
|
|
73
|
+
return "Missing recorder 'rec'. Install Sox before using voice input.";
|
|
74
|
+
}
|
|
75
|
+
function gzip(buffer) {
|
|
76
|
+
return zlib.gzipSync(buffer);
|
|
77
|
+
}
|
|
78
|
+
function buildProtocolHeader(messageType, flags, serialization, compression) {
|
|
79
|
+
return Buffer.from([
|
|
80
|
+
(HEADER_VERSION << 4) | HEADER_SIZE,
|
|
81
|
+
(messageType << 4) | flags,
|
|
82
|
+
(serialization << 4) | compression,
|
|
83
|
+
0x00,
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
function buildClientMessage(messageType, flags, payload, serialization) {
|
|
87
|
+
const compressedPayload = gzip(payload);
|
|
88
|
+
const header = buildProtocolHeader(messageType, flags, serialization, COMPRESSION_GZIP);
|
|
89
|
+
const size = Buffer.alloc(4);
|
|
90
|
+
size.writeUInt32BE(compressedPayload.length, 0);
|
|
91
|
+
return Buffer.concat([header, size, compressedPayload]);
|
|
92
|
+
}
|
|
93
|
+
function buildEmptyLastAudioMessage() {
|
|
94
|
+
const compressedPayload = gzip(Buffer.alloc(0));
|
|
95
|
+
const header = buildProtocolHeader(MESSAGE_TYPE_AUDIO_ONLY_REQUEST, 0x2, SERIALIZATION_NONE, COMPRESSION_GZIP);
|
|
96
|
+
const size = Buffer.alloc(4);
|
|
97
|
+
size.writeUInt32BE(compressedPayload.length, 0);
|
|
98
|
+
return Buffer.concat([header, size, compressedPayload]);
|
|
99
|
+
}
|
|
100
|
+
function parseServerMessage(message) {
|
|
101
|
+
if (message.length < 8)
|
|
102
|
+
throw new Error("Invalid Volcengine response frame");
|
|
103
|
+
const headerSize = (message[0] & 0x0f) * 4;
|
|
104
|
+
const messageType = message[1] >> 4;
|
|
105
|
+
const flags = message[1] & 0x0f;
|
|
106
|
+
const serialization = message[2] >> 4;
|
|
107
|
+
const compression = message[2] & 0x0f;
|
|
108
|
+
let offset = headerSize;
|
|
109
|
+
if (messageType === MESSAGE_TYPE_ERROR) {
|
|
110
|
+
const code = message.readUInt32BE(offset);
|
|
111
|
+
offset += 4;
|
|
112
|
+
const payloadSize = message.readUInt32BE(offset);
|
|
113
|
+
offset += 4;
|
|
114
|
+
const payload = message.subarray(offset, offset + payloadSize);
|
|
115
|
+
const text = compression === COMPRESSION_GZIP ? zlib.gunzipSync(payload).toString("utf8") : payload.toString("utf8");
|
|
116
|
+
throw new Error(`Volcengine ASR error ${code}: ${text}`);
|
|
117
|
+
}
|
|
118
|
+
if (flags === 0x1 || flags === 0x3)
|
|
119
|
+
offset += 4;
|
|
120
|
+
const payloadSize = message.readUInt32BE(offset);
|
|
121
|
+
offset += 4;
|
|
122
|
+
const payload = message.subarray(offset, offset + payloadSize);
|
|
123
|
+
const body = compression === COMPRESSION_GZIP ? zlib.gunzipSync(payload) : payload;
|
|
124
|
+
return {
|
|
125
|
+
flags,
|
|
126
|
+
data: serialization === SERIALIZATION_JSON ? JSON.parse(body.toString("utf8")) : body,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function createMaskedFrame(opcode, payload) {
|
|
130
|
+
const mask = randomBytes(4);
|
|
131
|
+
const chunks = [Buffer.from([0x80 | opcode])];
|
|
132
|
+
const length = payload.length;
|
|
133
|
+
if (length < 126) {
|
|
134
|
+
chunks.push(Buffer.from([0x80 | length]));
|
|
135
|
+
}
|
|
136
|
+
else if (length <= 0xffff) {
|
|
137
|
+
const extended = Buffer.alloc(3);
|
|
138
|
+
extended[0] = 0x80 | 126;
|
|
139
|
+
extended.writeUInt16BE(length, 1);
|
|
140
|
+
chunks.push(extended);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
const extended = Buffer.alloc(9);
|
|
144
|
+
extended[0] = 0x80 | 127;
|
|
145
|
+
extended.writeBigUInt64BE(BigInt(length), 1);
|
|
146
|
+
chunks.push(extended);
|
|
147
|
+
}
|
|
148
|
+
const masked = Buffer.alloc(length);
|
|
149
|
+
for (let index = 0; index < length; index += 1) {
|
|
150
|
+
masked[index] = payload[index] ^ mask[index % 4];
|
|
151
|
+
}
|
|
152
|
+
chunks.push(mask, masked);
|
|
153
|
+
return Buffer.concat(chunks);
|
|
154
|
+
}
|
|
155
|
+
class WebSocketBinaryClient {
|
|
156
|
+
url;
|
|
157
|
+
headers;
|
|
158
|
+
socket;
|
|
159
|
+
buffer = Buffer.alloc(0);
|
|
160
|
+
pendingFrames = [];
|
|
161
|
+
waiters = [];
|
|
162
|
+
constructor(url, headers) {
|
|
163
|
+
this.url = new URL(url);
|
|
164
|
+
this.headers = headers;
|
|
165
|
+
}
|
|
166
|
+
async connect() {
|
|
167
|
+
if (this.url.protocol !== "wss:") {
|
|
168
|
+
throw new Error(`Unsupported websocket protocol: ${this.url.protocol}`);
|
|
169
|
+
}
|
|
170
|
+
const key = randomBytes(16).toString("base64");
|
|
171
|
+
const headerLines = [
|
|
172
|
+
`GET ${this.url.pathname}${this.url.search} HTTP/1.1`,
|
|
173
|
+
`Host: ${this.url.host}`,
|
|
174
|
+
"Upgrade: websocket",
|
|
175
|
+
"Connection: Upgrade",
|
|
176
|
+
`Sec-WebSocket-Key: ${key}`,
|
|
177
|
+
"Sec-WebSocket-Version: 13",
|
|
178
|
+
];
|
|
179
|
+
for (const [name, value] of Object.entries(this.headers)) {
|
|
180
|
+
headerLines.push(`${name}: ${value}`);
|
|
181
|
+
}
|
|
182
|
+
headerLines.push("\r\n");
|
|
183
|
+
const socket = await new Promise((resolve, reject) => {
|
|
184
|
+
const next = tls.connect({
|
|
185
|
+
host: this.url.hostname,
|
|
186
|
+
port: Number(this.url.port || 443),
|
|
187
|
+
servername: this.url.hostname,
|
|
188
|
+
});
|
|
189
|
+
next.once("secureConnect", () => resolve(next));
|
|
190
|
+
next.once("error", reject);
|
|
191
|
+
});
|
|
192
|
+
this.socket = socket;
|
|
193
|
+
socket.setNoDelay(true);
|
|
194
|
+
socket.write(headerLines.join("\r\n"));
|
|
195
|
+
const handshake = await new Promise((resolve, reject) => {
|
|
196
|
+
let chunkBuffer = Buffer.alloc(0);
|
|
197
|
+
const onData = (chunk) => {
|
|
198
|
+
chunkBuffer = Buffer.concat([chunkBuffer, chunk]);
|
|
199
|
+
const separator = chunkBuffer.indexOf("\r\n\r\n");
|
|
200
|
+
if (separator === -1)
|
|
201
|
+
return;
|
|
202
|
+
socket.off("data", onData);
|
|
203
|
+
resolve({
|
|
204
|
+
headerPart: chunkBuffer.subarray(0, separator).toString("utf8"),
|
|
205
|
+
rest: chunkBuffer.subarray(separator + 4),
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
socket.on("data", onData);
|
|
209
|
+
socket.once("error", reject);
|
|
210
|
+
});
|
|
211
|
+
const lines = handshake.headerPart.split("\r\n");
|
|
212
|
+
if (!(lines[0] || "").includes("101")) {
|
|
213
|
+
throw new Error(`WebSocket handshake failed: ${lines[0] || "unknown"}`);
|
|
214
|
+
}
|
|
215
|
+
const responseHeaders = {};
|
|
216
|
+
for (const line of lines.slice(1)) {
|
|
217
|
+
const index = line.indexOf(":");
|
|
218
|
+
if (index === -1)
|
|
219
|
+
continue;
|
|
220
|
+
responseHeaders[line.slice(0, index).trim().toLowerCase()] = line.slice(index + 1).trim();
|
|
221
|
+
}
|
|
222
|
+
socket.on("data", (chunk) => this.onData(chunk));
|
|
223
|
+
socket.on("close", () => this.flushWaiters(new Error("WebSocket closed")));
|
|
224
|
+
socket.on("error", (error) => this.flushWaiters(error));
|
|
225
|
+
if (handshake.rest.length > 0)
|
|
226
|
+
this.onData(handshake.rest);
|
|
227
|
+
return responseHeaders;
|
|
228
|
+
}
|
|
229
|
+
onData(chunk) {
|
|
230
|
+
this.buffer = Buffer.concat([this.buffer, chunk]);
|
|
231
|
+
while (this.buffer.length >= 2) {
|
|
232
|
+
const first = this.buffer[0];
|
|
233
|
+
const second = this.buffer[1];
|
|
234
|
+
const opcode = first & 0x0f;
|
|
235
|
+
const masked = (second & 0x80) !== 0;
|
|
236
|
+
let offset = 2;
|
|
237
|
+
let payloadLength = second & 0x7f;
|
|
238
|
+
if (payloadLength === 126) {
|
|
239
|
+
if (this.buffer.length < offset + 2)
|
|
240
|
+
return;
|
|
241
|
+
payloadLength = this.buffer.readUInt16BE(offset);
|
|
242
|
+
offset += 2;
|
|
243
|
+
}
|
|
244
|
+
else if (payloadLength === 127) {
|
|
245
|
+
if (this.buffer.length < offset + 8)
|
|
246
|
+
return;
|
|
247
|
+
payloadLength = Number(this.buffer.readBigUInt64BE(offset));
|
|
248
|
+
offset += 8;
|
|
249
|
+
}
|
|
250
|
+
let mask;
|
|
251
|
+
if (masked) {
|
|
252
|
+
if (this.buffer.length < offset + 4)
|
|
253
|
+
return;
|
|
254
|
+
mask = this.buffer.subarray(offset, offset + 4);
|
|
255
|
+
offset += 4;
|
|
256
|
+
}
|
|
257
|
+
if (this.buffer.length < offset + payloadLength)
|
|
258
|
+
return;
|
|
259
|
+
let payload = this.buffer.subarray(offset, offset + payloadLength);
|
|
260
|
+
this.buffer = this.buffer.subarray(offset + payloadLength);
|
|
261
|
+
if (masked && mask) {
|
|
262
|
+
const unmasked = Buffer.alloc(payload.length);
|
|
263
|
+
for (let index = 0; index < payload.length; index += 1) {
|
|
264
|
+
unmasked[index] = payload[index] ^ mask[index % 4];
|
|
265
|
+
}
|
|
266
|
+
payload = unmasked;
|
|
267
|
+
}
|
|
268
|
+
if (opcode === WS_OPCODE_PING) {
|
|
269
|
+
this.sendRaw(WS_OPCODE_PONG, payload);
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
if (opcode === WS_OPCODE_CLOSE) {
|
|
273
|
+
this.flushWaiters(new Error("WebSocket closed by server"));
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (opcode !== WS_OPCODE_BINARY)
|
|
277
|
+
continue;
|
|
278
|
+
const waiter = this.waiters.shift();
|
|
279
|
+
if (waiter)
|
|
280
|
+
waiter.resolve(payload);
|
|
281
|
+
else
|
|
282
|
+
this.pendingFrames.push(payload);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
flushWaiters(error) {
|
|
286
|
+
while (this.waiters.length > 0) {
|
|
287
|
+
this.waiters.shift()?.reject(error);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
sendRaw(opcode, payload) {
|
|
291
|
+
if (!this.socket)
|
|
292
|
+
throw new Error("WebSocket is not connected");
|
|
293
|
+
this.socket.write(createMaskedFrame(opcode, payload));
|
|
294
|
+
}
|
|
295
|
+
sendBinary(payload) {
|
|
296
|
+
this.sendRaw(WS_OPCODE_BINARY, payload);
|
|
297
|
+
}
|
|
298
|
+
async receiveBinary(timeoutMs = 30000) {
|
|
299
|
+
if (this.pendingFrames.length > 0) {
|
|
300
|
+
return this.pendingFrames.shift();
|
|
301
|
+
}
|
|
302
|
+
return new Promise((resolve, reject) => {
|
|
303
|
+
const waiter = {
|
|
304
|
+
resolve: (value) => {
|
|
305
|
+
clearTimeout(timer);
|
|
306
|
+
resolve(value);
|
|
307
|
+
},
|
|
308
|
+
reject: (error) => {
|
|
309
|
+
clearTimeout(timer);
|
|
310
|
+
reject(error);
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
const timer = setTimeout(() => {
|
|
314
|
+
this.waiters = this.waiters.filter((item) => item !== waiter);
|
|
315
|
+
reject(new Error("Timed out waiting for Volcengine ASR response"));
|
|
316
|
+
}, timeoutMs);
|
|
317
|
+
this.waiters.push(waiter);
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
async close() {
|
|
321
|
+
if (!this.socket)
|
|
322
|
+
return;
|
|
323
|
+
try {
|
|
324
|
+
this.sendRaw(WS_OPCODE_CLOSE, Buffer.alloc(0));
|
|
325
|
+
}
|
|
326
|
+
catch {
|
|
327
|
+
// Ignore close send failure.
|
|
328
|
+
}
|
|
329
|
+
const socket = this.socket;
|
|
330
|
+
await new Promise((resolve) => {
|
|
331
|
+
socket.end(() => resolve());
|
|
332
|
+
setTimeout(() => resolve(), 200);
|
|
333
|
+
});
|
|
334
|
+
this.socket = undefined;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
async function commandExists(command) {
|
|
338
|
+
return new Promise((resolve) => {
|
|
339
|
+
const child = spawn("which", [command], { stdio: "ignore" });
|
|
340
|
+
child.on("close", (code) => resolve(code === 0));
|
|
341
|
+
child.on("error", () => resolve(false));
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
async function ensureRuntimeSupport() {
|
|
345
|
+
if (process.platform !== "darwin" && process.platform !== "linux") {
|
|
346
|
+
throw new Error(`opencode-voice2text currently supports macOS and Linux. Current platform: ${platformLabel()}`);
|
|
347
|
+
}
|
|
348
|
+
if (!(await commandExists("rec"))) {
|
|
349
|
+
throw new Error(installHint());
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
async function readLocalConfig() {
|
|
353
|
+
const configPath = process.env.OPENCODE_VOICE2TEXT_LOCAL_CONFIG || DEFAULT_CONFIG_PATH;
|
|
354
|
+
try {
|
|
355
|
+
return JSON.parse(await fs.readFile(configPath, "utf8"));
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
if (error?.code === "ENOENT")
|
|
359
|
+
return {};
|
|
360
|
+
throw error;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
async function loadConfig(options = {}) {
|
|
364
|
+
const local = await readLocalConfig();
|
|
365
|
+
const env = process.env;
|
|
366
|
+
const merged = { ...local, ...options };
|
|
367
|
+
const config = {
|
|
368
|
+
commandKeybind: str(merged.commandKeybind, "ctrl+s"),
|
|
369
|
+
endpoint: str(merged.endpoint ?? env.OPENCODE_VOICE2TEXT_ENDPOINT, DEFAULT_ENDPOINT),
|
|
370
|
+
appId: str(merged.appId ?? env.OPENCODE_VOICE2TEXT_APP_ID),
|
|
371
|
+
accessToken: str(merged.accessToken ?? env.OPENCODE_VOICE2TEXT_ACCESS_TOKEN),
|
|
372
|
+
resourceId: str(merged.resourceId ?? env.OPENCODE_VOICE2TEXT_RESOURCE_ID, DEFAULT_RESOURCE_ID),
|
|
373
|
+
language: str(merged.language ?? env.OPENCODE_VOICE2TEXT_LANGUAGE),
|
|
374
|
+
chunkMs: num(merged.chunkMs ?? env.OPENCODE_VOICE2TEXT_CHUNK_MS, DEFAULT_CHUNK_MS),
|
|
375
|
+
endWindowSize: num(merged.endWindowSize ?? env.OPENCODE_VOICE2TEXT_END_WINDOW_SIZE, DEFAULT_END_WINDOW_SIZE),
|
|
376
|
+
maxDurationSeconds: num(merged.maxDurationSeconds ?? env.OPENCODE_VOICE2TEXT_MAX_DURATION_SECONDS, 180),
|
|
377
|
+
appendTrailingSpace: bool(merged.appendTrailingSpace ?? env.OPENCODE_VOICE2TEXT_APPEND_TRAILING_SPACE, true),
|
|
378
|
+
rate: num(merged.rate ?? env.OPENCODE_VOICE2TEXT_SAMPLE_RATE, DEFAULT_RATE),
|
|
379
|
+
bits: num(merged.bits ?? env.OPENCODE_VOICE2TEXT_BITS, DEFAULT_BITS),
|
|
380
|
+
channels: num(merged.channels ?? env.OPENCODE_VOICE2TEXT_CHANNELS, DEFAULT_CHANNELS),
|
|
381
|
+
};
|
|
382
|
+
if (!config.appId || !config.accessToken || !config.resourceId) {
|
|
383
|
+
const configPath = process.env.OPENCODE_VOICE2TEXT_LOCAL_CONFIG || DEFAULT_CONFIG_PATH;
|
|
384
|
+
throw new Error(`Volcengine ASR config is incomplete. Fill ${configPath} first.`);
|
|
385
|
+
}
|
|
386
|
+
return config;
|
|
387
|
+
}
|
|
388
|
+
function buildVolcengineRequest(config) {
|
|
389
|
+
const audio = {
|
|
390
|
+
format: "pcm",
|
|
391
|
+
codec: "raw",
|
|
392
|
+
rate: config.rate,
|
|
393
|
+
bits: config.bits,
|
|
394
|
+
channel: config.channels,
|
|
395
|
+
};
|
|
396
|
+
if (config.language) {
|
|
397
|
+
audio.language = config.language;
|
|
398
|
+
}
|
|
399
|
+
return {
|
|
400
|
+
user: {
|
|
401
|
+
uid: os.userInfo().username,
|
|
402
|
+
did: os.hostname(),
|
|
403
|
+
platform: process.platform === "darwin" ? "macOS" : process.platform,
|
|
404
|
+
sdk_version: "opencode-plugin",
|
|
405
|
+
app_version: "opencode-voice2text",
|
|
406
|
+
},
|
|
407
|
+
audio,
|
|
408
|
+
request: {
|
|
409
|
+
model_name: "bigmodel",
|
|
410
|
+
enable_itn: true,
|
|
411
|
+
enable_punc: true,
|
|
412
|
+
enable_ddc: false,
|
|
413
|
+
result_type: "full",
|
|
414
|
+
show_utterances: true,
|
|
415
|
+
end_window_size: config.endWindowSize,
|
|
416
|
+
},
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
function getStableText(data) {
|
|
420
|
+
const utterances = Array.isArray(data?.result?.utterances) ? data.result.utterances : [];
|
|
421
|
+
return utterances
|
|
422
|
+
.filter((item) => item && item.definite && typeof item.text === "string" && item.text.trim())
|
|
423
|
+
.map((item) => item.text)
|
|
424
|
+
.join("")
|
|
425
|
+
.trim();
|
|
426
|
+
}
|
|
427
|
+
function createRecorder(config, onChunk) {
|
|
428
|
+
const child = spawn("rec", [
|
|
429
|
+
"-q",
|
|
430
|
+
"-t",
|
|
431
|
+
"raw",
|
|
432
|
+
"-r",
|
|
433
|
+
String(config.rate),
|
|
434
|
+
"-c",
|
|
435
|
+
String(config.channels),
|
|
436
|
+
"-b",
|
|
437
|
+
String(config.bits),
|
|
438
|
+
"-e",
|
|
439
|
+
"signed-integer",
|
|
440
|
+
"-",
|
|
441
|
+
], { stdio: ["ignore", "pipe", "pipe"] });
|
|
442
|
+
let stderr = "";
|
|
443
|
+
let stopRequested = false;
|
|
444
|
+
let finished = false;
|
|
445
|
+
let streamError;
|
|
446
|
+
let writeChain = Promise.resolve();
|
|
447
|
+
child.stdout?.on("data", (chunk) => {
|
|
448
|
+
writeChain = writeChain.then(async () => {
|
|
449
|
+
if (streamError)
|
|
450
|
+
return;
|
|
451
|
+
try {
|
|
452
|
+
await onChunk(chunk);
|
|
453
|
+
}
|
|
454
|
+
catch (error) {
|
|
455
|
+
streamError = error instanceof Error ? error : new Error(String(error));
|
|
456
|
+
stopRequested = true;
|
|
457
|
+
child.kill("SIGINT");
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
});
|
|
461
|
+
child.stderr?.on("data", (chunk) => {
|
|
462
|
+
stderr += chunk.toString();
|
|
463
|
+
});
|
|
464
|
+
const timer = setTimeout(() => {
|
|
465
|
+
stopRequested = true;
|
|
466
|
+
child.kill("SIGINT");
|
|
467
|
+
}, config.maxDurationSeconds * 1000);
|
|
468
|
+
const done = new Promise((resolve, reject) => {
|
|
469
|
+
child.on("error", (error) => {
|
|
470
|
+
clearTimeout(timer);
|
|
471
|
+
finished = true;
|
|
472
|
+
reject(error?.code === "ENOENT" ? new Error(installHint()) : error);
|
|
473
|
+
});
|
|
474
|
+
child.on("close", async (code, signal) => {
|
|
475
|
+
clearTimeout(timer);
|
|
476
|
+
finished = true;
|
|
477
|
+
await writeChain;
|
|
478
|
+
if (streamError) {
|
|
479
|
+
reject(streamError);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
if (code === 0 || signal === "SIGINT" || stopRequested) {
|
|
483
|
+
resolve();
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
reject(new Error(stderr.trim() || `Recording failed with code ${code ?? "unknown"}`));
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
return {
|
|
490
|
+
done,
|
|
491
|
+
stop() {
|
|
492
|
+
if (finished || child.killed)
|
|
493
|
+
return;
|
|
494
|
+
stopRequested = true;
|
|
495
|
+
child.kill("SIGINT");
|
|
496
|
+
},
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
async function createStreamingRecognition(config, callbacks) {
|
|
500
|
+
const client = new WebSocketBinaryClient(config.endpoint, {
|
|
501
|
+
"X-Api-App-Key": config.appId,
|
|
502
|
+
"X-Api-Access-Key": config.accessToken,
|
|
503
|
+
"X-Api-Resource-Id": config.resourceId,
|
|
504
|
+
"X-Api-Connect-Id": randomUUID(),
|
|
505
|
+
});
|
|
506
|
+
let lastText = "";
|
|
507
|
+
let stableText = "";
|
|
508
|
+
let closed = false;
|
|
509
|
+
const responseHeaders = await client.connect();
|
|
510
|
+
const requestPayload = Buffer.from(JSON.stringify(buildVolcengineRequest(config)), "utf8");
|
|
511
|
+
client.sendBinary(buildClientMessage(MESSAGE_TYPE_FULL_CLIENT_REQUEST, 0x0, requestPayload, SERIALIZATION_JSON));
|
|
512
|
+
parseServerMessage(await client.receiveBinary());
|
|
513
|
+
const receiveLoop = (async () => {
|
|
514
|
+
while (true) {
|
|
515
|
+
const response = parseServerMessage(await client.receiveBinary(30000));
|
|
516
|
+
const nextText = appendableText(response.data?.result?.text);
|
|
517
|
+
if (nextText)
|
|
518
|
+
lastText = nextText;
|
|
519
|
+
const nextStableText = appendableText(getStableText(response.data));
|
|
520
|
+
const stableDelta = diffSuffix(stableText, nextStableText);
|
|
521
|
+
if (stableDelta) {
|
|
522
|
+
stableText = nextStableText;
|
|
523
|
+
await callbacks.onStableText?.(stableDelta);
|
|
524
|
+
}
|
|
525
|
+
if (response.flags === 0x3) {
|
|
526
|
+
return {
|
|
527
|
+
text: lastText,
|
|
528
|
+
stableText,
|
|
529
|
+
logId: responseHeaders["x-tt-logid"] || "",
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
})();
|
|
534
|
+
let sendChain = Promise.resolve();
|
|
535
|
+
return {
|
|
536
|
+
write(chunk) {
|
|
537
|
+
if (closed || chunk.length === 0)
|
|
538
|
+
return;
|
|
539
|
+
sendChain = sendChain.then(() => {
|
|
540
|
+
client.sendBinary(buildClientMessage(MESSAGE_TYPE_AUDIO_ONLY_REQUEST, 0x0, chunk, SERIALIZATION_NONE));
|
|
541
|
+
});
|
|
542
|
+
},
|
|
543
|
+
async finish(finalChunk) {
|
|
544
|
+
if (closed)
|
|
545
|
+
return receiveLoop;
|
|
546
|
+
closed = true;
|
|
547
|
+
if (finalChunk && finalChunk.length > 0) {
|
|
548
|
+
sendChain = sendChain.then(() => {
|
|
549
|
+
client.sendBinary(buildClientMessage(MESSAGE_TYPE_AUDIO_ONLY_REQUEST, 0x0, finalChunk, SERIALIZATION_NONE));
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
await sendChain;
|
|
553
|
+
client.sendBinary(buildEmptyLastAudioMessage());
|
|
554
|
+
try {
|
|
555
|
+
return await receiveLoop;
|
|
556
|
+
}
|
|
557
|
+
finally {
|
|
558
|
+
await client.close();
|
|
559
|
+
}
|
|
560
|
+
},
|
|
561
|
+
async abort() {
|
|
562
|
+
if (closed)
|
|
563
|
+
return;
|
|
564
|
+
closed = true;
|
|
565
|
+
await client.close();
|
|
566
|
+
},
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
async function appendTranscript(api, config, text) {
|
|
570
|
+
const nextText = config.appendTrailingSpace ? `${text} ` : text;
|
|
571
|
+
await api.client.tui.appendPrompt({ text: nextText });
|
|
572
|
+
}
|
|
573
|
+
function setStatus(api, status, message) {
|
|
574
|
+
api.kv.set(STATUS_KEY, status);
|
|
575
|
+
api.kv.set(STATUS_MESSAGE_KEY, message);
|
|
576
|
+
}
|
|
577
|
+
function statusView(api) {
|
|
578
|
+
return () => {
|
|
579
|
+
const status = createMemo(() => api.kv.get(STATUS_KEY, "idle"));
|
|
580
|
+
const message = createMemo(() => api.kv.get(STATUS_MESSAGE_KEY, ""));
|
|
581
|
+
const tone = createMemo(() => {
|
|
582
|
+
if (status() === "recording")
|
|
583
|
+
return api.theme.current.warning;
|
|
584
|
+
if (status() === "transcribing")
|
|
585
|
+
return api.theme.current.accent;
|
|
586
|
+
return api.theme.current.textMuted;
|
|
587
|
+
});
|
|
588
|
+
const label = createMemo(() => (status() === "recording" ? "REC" : "ASR"));
|
|
589
|
+
return (_jsx(Show, { when: status() !== "idle", children: _jsxs("box", { flexDirection: "row", gap: 1, children: [_jsx("text", { fg: tone(), children: _jsx("b", { children: label() }) }), _jsx(Show, { when: message(), children: _jsx("text", { fg: api.theme.current.textMuted, children: message() }) })] }) }));
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
const tui = async (api, options) => {
|
|
593
|
+
await ensureRuntimeSupport();
|
|
594
|
+
const config = await loadConfig((options ?? {}));
|
|
595
|
+
let phase = "idle";
|
|
596
|
+
let active;
|
|
597
|
+
setStatus(api, "idle", "");
|
|
598
|
+
api.slots.register({
|
|
599
|
+
order: 50,
|
|
600
|
+
slots: {
|
|
601
|
+
home_prompt_right: statusView(api),
|
|
602
|
+
session_prompt_right: statusView(api),
|
|
603
|
+
},
|
|
604
|
+
});
|
|
605
|
+
const toast = (message, variant = "info") => {
|
|
606
|
+
api.ui.toast({ title: "Voice2Text", message, variant, duration: 2500 });
|
|
607
|
+
};
|
|
608
|
+
const startRecording = async () => {
|
|
609
|
+
if (phase !== "idle")
|
|
610
|
+
return;
|
|
611
|
+
phase = "recording";
|
|
612
|
+
setStatus(api, "recording", `listening... press ${config.commandKeybind} to stop`);
|
|
613
|
+
try {
|
|
614
|
+
const stream = await createStreamingRecognition(config, {
|
|
615
|
+
onStableText: async (text) => {
|
|
616
|
+
const next = appendableText(text);
|
|
617
|
+
if (!next)
|
|
618
|
+
return;
|
|
619
|
+
await appendTranscript(api, config, next);
|
|
620
|
+
},
|
|
621
|
+
});
|
|
622
|
+
const session = {
|
|
623
|
+
stream,
|
|
624
|
+
pending: Buffer.alloc(0),
|
|
625
|
+
chunkBytes: Math.max(1, Math.floor((config.rate * config.channels * (config.bits / 8) * config.chunkMs) / 1000)),
|
|
626
|
+
recorder: undefined,
|
|
627
|
+
};
|
|
628
|
+
const flushPending = async () => {
|
|
629
|
+
while (session.pending.length >= session.chunkBytes) {
|
|
630
|
+
const chunk = session.pending.subarray(0, session.chunkBytes);
|
|
631
|
+
session.pending = session.pending.subarray(session.chunkBytes);
|
|
632
|
+
session.stream.write(chunk);
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
session.recorder = createRecorder(config, async (chunk) => {
|
|
636
|
+
session.pending = Buffer.concat([session.pending, chunk]);
|
|
637
|
+
await flushPending();
|
|
638
|
+
});
|
|
639
|
+
active = session;
|
|
640
|
+
}
|
|
641
|
+
catch (error) {
|
|
642
|
+
phase = "idle";
|
|
643
|
+
setStatus(api, "idle", "");
|
|
644
|
+
toast(error instanceof Error ? error.message : String(error), "error");
|
|
645
|
+
}
|
|
646
|
+
};
|
|
647
|
+
const stopRecording = async () => {
|
|
648
|
+
if (phase !== "recording" || !active)
|
|
649
|
+
return;
|
|
650
|
+
const current = active;
|
|
651
|
+
active = undefined;
|
|
652
|
+
phase = "transcribing";
|
|
653
|
+
setStatus(api, "transcribing", "stopping...");
|
|
654
|
+
try {
|
|
655
|
+
current.recorder.stop();
|
|
656
|
+
await current.recorder.done;
|
|
657
|
+
const finalChunk = current.pending.length > 0 ? current.pending : undefined;
|
|
658
|
+
const result = await current.stream.finish(finalChunk);
|
|
659
|
+
const tail = diffSuffix(result.stableText, appendableText(result.text));
|
|
660
|
+
if (tail) {
|
|
661
|
+
await appendTranscript(api, config, tail);
|
|
662
|
+
}
|
|
663
|
+
void result.logId;
|
|
664
|
+
}
|
|
665
|
+
catch (error) {
|
|
666
|
+
await current.stream.abort().catch(() => undefined);
|
|
667
|
+
toast(error instanceof Error ? error.message : String(error), "error");
|
|
668
|
+
}
|
|
669
|
+
finally {
|
|
670
|
+
phase = "idle";
|
|
671
|
+
setStatus(api, "idle", "");
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
api.command.register(() => [
|
|
675
|
+
{
|
|
676
|
+
title: "Toggle voice input",
|
|
677
|
+
value: "voice2text.toggle",
|
|
678
|
+
description: "Stream microphone audio to Volcengine ASR and append recognized text to the prompt",
|
|
679
|
+
keybind: config.commandKeybind,
|
|
680
|
+
slash: { name: "voice2text", aliases: ["voice"] },
|
|
681
|
+
hidden: true,
|
|
682
|
+
onSelect: () => {
|
|
683
|
+
if (phase === "transcribing") {
|
|
684
|
+
toast("Still transcribing the previous recording.", "warning");
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
if (phase === "recording") {
|
|
688
|
+
void stopRecording();
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
void startRecording();
|
|
692
|
+
},
|
|
693
|
+
},
|
|
694
|
+
]);
|
|
695
|
+
api.lifecycle.onDispose(() => {
|
|
696
|
+
active?.recorder.stop();
|
|
697
|
+
void active?.stream.abort().catch(() => undefined);
|
|
698
|
+
setStatus(api, "idle", "");
|
|
699
|
+
});
|
|
700
|
+
};
|
|
701
|
+
const plugin = {
|
|
702
|
+
id: "opencode.voice2text",
|
|
703
|
+
tui,
|
|
704
|
+
};
|
|
705
|
+
export default plugin;
|
|
706
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-voice2text",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Streaming Volcengine speech-to-text plugin for the OpenCode TUI",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/chenxuan520/opencode-voice2text.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/chenxuan520/opencode-voice2text#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/chenxuan520/opencode-voice2text/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"opencode",
|
|
17
|
+
"plugin",
|
|
18
|
+
"speech-to-text",
|
|
19
|
+
"voice",
|
|
20
|
+
"volcengine",
|
|
21
|
+
"asr"
|
|
22
|
+
],
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"README.md",
|
|
26
|
+
"LICENSE"
|
|
27
|
+
],
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -p tsconfig.json",
|
|
36
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
37
|
+
"prepublishOnly": "npm run build"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@opencode-ai/plugin": "^1.4.3",
|
|
41
|
+
"@opentui/solid": "^0.1.97",
|
|
42
|
+
"solid-js": "^1.9.9"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.13.9",
|
|
46
|
+
"typescript": "^5.8.2"
|
|
47
|
+
}
|
|
48
|
+
}
|