@deepseek-ai/dsh-experimental-api-speech-to-text 0.1.7-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +78 -0
- package/README.zh.md +78 -0
- package/lib/index.js +218 -0
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +432 -0
- package/lib/typert.remote-client.d.ts +34 -0
- package/lib/typert.remote-client.js +311 -0
- package/lib/types/index.d.ts +63 -0
- package/lib/types/index.js +142 -0
- package/lib/types/types.d.ts +26 -0
- package/lib/types/types.js +2 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
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.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
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/experimental/api-speech-to-text/README.md
|
|
5
|
+
README.md: ecc83c15b4217323c074733ae77259261598803c
|
|
6
|
+
README.zh.md: 46ac6a16c902c32f2effb23a98141b1afbdccd37
|
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Expose bounded transient transcription through the authenticated Web Remote."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-experimental-api-speech-to-text
|
|
7
|
+
|
|
8
|
+
English | [中文](README.zh.md)
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
The `speech` Remote connects browser recordings to `ctx.speechToText`. It exposes provider discovery and one complete-recording transcription call.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
Compose with the speech Service Definition and Typert. `maxAudioBytes` and `maxDurationSeconds` limit accepted recordings. The browser UI mounts this package’s generated `/remote` contribution when enabled.
|
|
29
|
+
|
|
30
|
+
-----
|
|
31
|
+
|
|
32
|
+
<a id="understand-the-implementation"></a>
|
|
33
|
+
## Understand the implementation
|
|
34
|
+
|
|
35
|
+
<details>
|
|
36
|
+
<summary>Maintainer details — click to expand</summary>
|
|
37
|
+
|
|
38
|
+
`catalog()` exposes provider identities, the default selection and recording limits. `transcribe()` validates canonical base64 and 16 kHz mono PCM16 WAV before resolving the selected provider. The existing gateway owns authentication and cancellation transport. Audio is transient, never a Session event or attachment; only the user’s later ordinary submission records recognized text. No runtime invariant companion is published because validation is stateless and preparation belongs to the provider.
|
|
39
|
+
|
|
40
|
+
`follow()` streams complete catalogs, including preparation states and current preferences. `prepare()` starts or joins a Host task; `cancelPreparation()` explicitly cancels it. `configure()` persists the supplied preference fields. A disconnected observer does not cancel preparation.
|
|
41
|
+
|
|
42
|
+
</details>
|
|
43
|
+
|
|
44
|
+
-----
|
|
45
|
+
|
|
46
|
+
<a id="further-exploration"></a>
|
|
47
|
+
## Further Exploration
|
|
48
|
+
|
|
49
|
+
[Voice input subsystem](../../../docs/subsystems/voice-input.md)
|
|
50
|
+
|
|
51
|
+
-----
|
|
52
|
+
|
|
53
|
+
<a id="model-experience"></a>
|
|
54
|
+
## Model Experience
|
|
55
|
+
|
|
56
|
+
None, as recordings and preparation remain outside model requests; ordinary user submission owns any later text.
|
|
57
|
+
|
|
58
|
+
#### KV Cache effect
|
|
59
|
+
|
|
60
|
+
No direct effect; ordinary submission owns the message content.
|
|
61
|
+
|
|
62
|
+
## Known Limitations and Deferred Work
|
|
63
|
+
|
|
64
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
65
|
+
|
|
66
|
+
- No file upload, persistent transcript history or streaming protocol is exposed. Base64 adds transport overhead; recordings remain bounded by the advertised limits.
|
|
67
|
+
|
|
68
|
+
-----
|
|
69
|
+
|
|
70
|
+
<a id="dev-note"></a>
|
|
71
|
+
### Dev Note
|
|
72
|
+
|
|
73
|
+
<details>
|
|
74
|
+
<summary>Maintainer details — click to expand</summary>
|
|
75
|
+
|
|
76
|
+
None.
|
|
77
|
+
|
|
78
|
+
</details>
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "通过带认证的 Web Remote 提供有界临时转写。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-experimental-api-speech-to-text
|
|
7
|
+
|
|
8
|
+
[English](README.md) | 中文
|
|
9
|
+
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
`speech` Remote 将浏览器录音连接至 `ctx.speechToText`,提供 Provider 发现和完整录音转写调用。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用此包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与后续工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## 使用此包
|
|
27
|
+
|
|
28
|
+
与语音服务定义和 Typert 组合。`maxAudioBytes` 与 `maxDurationSeconds` 限制接收的录音。浏览器 UI 启用时挂载本包生成的 `/remote` 贡献。
|
|
29
|
+
|
|
30
|
+
-----
|
|
31
|
+
|
|
32
|
+
<a id="understand-the-implementation"></a>
|
|
33
|
+
## 理解实现
|
|
34
|
+
|
|
35
|
+
<details>
|
|
36
|
+
<summary>维护者信息 — 点击展开</summary>
|
|
37
|
+
|
|
38
|
+
`catalog()` 暴露 Provider 标识、默认选择与录音限制。`transcribe()` 在解析指定 Provider 前校验规范 base64 与 16 kHz 单声道 PCM16 WAV。现有网关负责认证和取消传输。音频是临时数据,不成为 Session 事件或附件;只有用户之后的普通提交才记录识别文字。不发布运行时不变量伴随模块,因为校验无状态,准备属于 Provider。
|
|
39
|
+
|
|
40
|
+
`follow()` 推送包含准备状态和当前偏好的完整目录。`prepare()` 启动或加入 Host 任务;`cancelPreparation()` 显式取消任务。`configure()` 持久化传入的偏好字段。观察连接断开不会取消准备。
|
|
41
|
+
|
|
42
|
+
</details>
|
|
43
|
+
|
|
44
|
+
-----
|
|
45
|
+
|
|
46
|
+
<a id="further-exploration"></a>
|
|
47
|
+
## 进一步探索
|
|
48
|
+
|
|
49
|
+
[语音输入子系统](../../../docs/subsystems/voice-input.zh.md)
|
|
50
|
+
|
|
51
|
+
-----
|
|
52
|
+
|
|
53
|
+
<a id="model-experience"></a>
|
|
54
|
+
## 模型体验
|
|
55
|
+
|
|
56
|
+
无,因为录音与准备不进入模型请求;之后的文字由普通用户提交拥有。
|
|
57
|
+
|
|
58
|
+
#### KV 缓存影响
|
|
59
|
+
|
|
60
|
+
没有直接影响;普通提交拥有消息内容。
|
|
61
|
+
|
|
62
|
+
## 已知限制与后续工作
|
|
63
|
+
|
|
64
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
65
|
+
|
|
66
|
+
- 不提供文件上传、持久化转写历史或流式协议。Base64 会增加传输开销;录音受公布的限制约束。
|
|
67
|
+
|
|
68
|
+
-----
|
|
69
|
+
|
|
70
|
+
<a id="dev-note"></a>
|
|
71
|
+
### 开发备注
|
|
72
|
+
|
|
73
|
+
<details>
|
|
74
|
+
<summary>维护者信息 — 点击展开</summary>
|
|
75
|
+
|
|
76
|
+
无。
|
|
77
|
+
|
|
78
|
+
</details>
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import z from "@deepseek-ai/schemastery";
|
|
2
|
+
import { Remote, RemoteError, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
3
|
+
import { validateWave } from "@deepseek-ai/dsh-experimental-speech-to-text/wave";
|
|
4
|
+
//#region lib/types/index.js
|
|
5
|
+
var __runInitializers = function(thisArg, initializers, value) {
|
|
6
|
+
var useValue = arguments.length > 2;
|
|
7
|
+
for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
8
|
+
return useValue ? value : void 0;
|
|
9
|
+
};
|
|
10
|
+
var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
11
|
+
function accept(f) {
|
|
12
|
+
if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected");
|
|
13
|
+
return f;
|
|
14
|
+
}
|
|
15
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
16
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
17
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
18
|
+
var _, done = false;
|
|
19
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
20
|
+
var context = {};
|
|
21
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
22
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
23
|
+
context.addInitializer = function(f) {
|
|
24
|
+
if (done) throw new TypeError("Cannot add initializers after decoration has completed");
|
|
25
|
+
extraInitializers.push(accept(f || null));
|
|
26
|
+
};
|
|
27
|
+
var result = (0, decorators[i])(kind === "accessor" ? {
|
|
28
|
+
get: descriptor.get,
|
|
29
|
+
set: descriptor.set
|
|
30
|
+
} : descriptor[key], context);
|
|
31
|
+
if (kind === "accessor") {
|
|
32
|
+
if (result === void 0) continue;
|
|
33
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
34
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
35
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
36
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
37
|
+
} else if (_ = accept(result)) if (kind === "field") initializers.unshift(_);
|
|
38
|
+
else descriptor[key] = _;
|
|
39
|
+
}
|
|
40
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
41
|
+
done = true;
|
|
42
|
+
};
|
|
43
|
+
let SpeechController = (() => {
|
|
44
|
+
let _classSuper = TypertRemoteService;
|
|
45
|
+
let _instanceExtraInitializers = [];
|
|
46
|
+
let _catalog_decorators;
|
|
47
|
+
let _follow_decorators;
|
|
48
|
+
let _configure_decorators;
|
|
49
|
+
let _prepare_decorators;
|
|
50
|
+
let _cancelPreparation_decorators;
|
|
51
|
+
let _transcribe_decorators;
|
|
52
|
+
return class SpeechController extends _classSuper {
|
|
53
|
+
static {
|
|
54
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
55
|
+
_catalog_decorators = [Remote];
|
|
56
|
+
_follow_decorators = [Remote({ mode: "stream" })];
|
|
57
|
+
_configure_decorators = [Remote];
|
|
58
|
+
_prepare_decorators = [Remote];
|
|
59
|
+
_cancelPreparation_decorators = [Remote];
|
|
60
|
+
_transcribe_decorators = [Remote];
|
|
61
|
+
__esDecorate(this, null, _catalog_decorators, {
|
|
62
|
+
kind: "method",
|
|
63
|
+
name: "catalog",
|
|
64
|
+
static: false,
|
|
65
|
+
private: false,
|
|
66
|
+
access: {
|
|
67
|
+
has: (obj) => "catalog" in obj,
|
|
68
|
+
get: (obj) => obj.catalog
|
|
69
|
+
},
|
|
70
|
+
metadata: _metadata
|
|
71
|
+
}, null, _instanceExtraInitializers);
|
|
72
|
+
__esDecorate(this, null, _follow_decorators, {
|
|
73
|
+
kind: "method",
|
|
74
|
+
name: "follow",
|
|
75
|
+
static: false,
|
|
76
|
+
private: false,
|
|
77
|
+
access: {
|
|
78
|
+
has: (obj) => "follow" in obj,
|
|
79
|
+
get: (obj) => obj.follow
|
|
80
|
+
},
|
|
81
|
+
metadata: _metadata
|
|
82
|
+
}, null, _instanceExtraInitializers);
|
|
83
|
+
__esDecorate(this, null, _configure_decorators, {
|
|
84
|
+
kind: "method",
|
|
85
|
+
name: "configure",
|
|
86
|
+
static: false,
|
|
87
|
+
private: false,
|
|
88
|
+
access: {
|
|
89
|
+
has: (obj) => "configure" in obj,
|
|
90
|
+
get: (obj) => obj.configure
|
|
91
|
+
},
|
|
92
|
+
metadata: _metadata
|
|
93
|
+
}, null, _instanceExtraInitializers);
|
|
94
|
+
__esDecorate(this, null, _prepare_decorators, {
|
|
95
|
+
kind: "method",
|
|
96
|
+
name: "prepare",
|
|
97
|
+
static: false,
|
|
98
|
+
private: false,
|
|
99
|
+
access: {
|
|
100
|
+
has: (obj) => "prepare" in obj,
|
|
101
|
+
get: (obj) => obj.prepare
|
|
102
|
+
},
|
|
103
|
+
metadata: _metadata
|
|
104
|
+
}, null, _instanceExtraInitializers);
|
|
105
|
+
__esDecorate(this, null, _cancelPreparation_decorators, {
|
|
106
|
+
kind: "method",
|
|
107
|
+
name: "cancelPreparation",
|
|
108
|
+
static: false,
|
|
109
|
+
private: false,
|
|
110
|
+
access: {
|
|
111
|
+
has: (obj) => "cancelPreparation" in obj,
|
|
112
|
+
get: (obj) => obj.cancelPreparation
|
|
113
|
+
},
|
|
114
|
+
metadata: _metadata
|
|
115
|
+
}, null, _instanceExtraInitializers);
|
|
116
|
+
__esDecorate(this, null, _transcribe_decorators, {
|
|
117
|
+
kind: "method",
|
|
118
|
+
name: "transcribe",
|
|
119
|
+
static: false,
|
|
120
|
+
private: false,
|
|
121
|
+
access: {
|
|
122
|
+
has: (obj) => "transcribe" in obj,
|
|
123
|
+
get: (obj) => obj.transcribe
|
|
124
|
+
},
|
|
125
|
+
metadata: _metadata
|
|
126
|
+
}, null, _instanceExtraInitializers);
|
|
127
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, {
|
|
128
|
+
enumerable: true,
|
|
129
|
+
configurable: true,
|
|
130
|
+
writable: true,
|
|
131
|
+
value: _metadata
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
config = __runInitializers(this, _instanceExtraInitializers);
|
|
135
|
+
static inject = ["speechToText", "typert"];
|
|
136
|
+
static Config = z.object({
|
|
137
|
+
maxAudioBytes: z.natural().min(46).default(4 * 1024 * 1024),
|
|
138
|
+
maxDurationSeconds: z.number().min(1).default(120)
|
|
139
|
+
});
|
|
140
|
+
constructor(ctx, config) {
|
|
141
|
+
super(ctx, "speechController", { namespace: "speech" });
|
|
142
|
+
this.config = config;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Read provider choices without preparing a recognizer.
|
|
146
|
+
* @returns available providers, resolved default, and recording limits.
|
|
147
|
+
*/
|
|
148
|
+
catalog() {
|
|
149
|
+
return {
|
|
150
|
+
...this.ctx.speechToText.snapshot(),
|
|
151
|
+
...this.config
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Follow provider readiness independently of Session and preparation lifetimes.
|
|
156
|
+
* @param signal - Client observation lifetime.
|
|
157
|
+
* @returns initial and subsequent complete readiness snapshots.
|
|
158
|
+
*/
|
|
159
|
+
async *follow(signal) {
|
|
160
|
+
for await (const snapshot of this.ctx.speechToText.follow(signal)) yield {
|
|
161
|
+
...snapshot,
|
|
162
|
+
...this.config
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Persist the user's recognition preferences.
|
|
167
|
+
* @param patch - changed preference fields.
|
|
168
|
+
* @returns after preferences are saved.
|
|
169
|
+
*/
|
|
170
|
+
configure(patch) {
|
|
171
|
+
return this.ctx.speechToText.configure(patch);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Start or join one Host-owned preparation task.
|
|
175
|
+
* @param providerId - selected recognizer.
|
|
176
|
+
*/
|
|
177
|
+
prepare(providerId) {
|
|
178
|
+
this.ctx.speechToText.prepare(providerId);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Explicitly cancel resource preparation.
|
|
182
|
+
* @param providerId - selected recognizer.
|
|
183
|
+
* @returns after the preparation task settles.
|
|
184
|
+
*/
|
|
185
|
+
cancelPreparation(providerId) {
|
|
186
|
+
return this.ctx.speechToText.cancelPreparation(providerId);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Validate and transcribe one recording through the explicit provider selection.
|
|
190
|
+
* @param request - canonical WAV encoded as base64, provider id and language hint.
|
|
191
|
+
* @param signal - Client cancellation or Remote contribution disposal.
|
|
192
|
+
* @returns final transcript without adding a Session event.
|
|
193
|
+
*/
|
|
194
|
+
async transcribe(request, signal) {
|
|
195
|
+
signal.throwIfAborted();
|
|
196
|
+
const encoded = request.audioBase64;
|
|
197
|
+
if (encoded.length > Math.ceil(this.config.maxAudioBytes / 3) * 4) throw new RemoteError("speech/invalid-audio", "Audio is invalid or exceeds the configured byte limit", { reason: "encoding-or-size" });
|
|
198
|
+
const audio = Buffer.from(encoded, "base64");
|
|
199
|
+
try {
|
|
200
|
+
if (audio.toString("base64") !== encoded) throw new Error("Audio must use canonical base64 encoding");
|
|
201
|
+
if (audio.length > this.config.maxAudioBytes) throw new Error("Audio exceeds the configured byte limit");
|
|
202
|
+
validateWave(audio, this.config.maxDurationSeconds);
|
|
203
|
+
const spec = this.ctx.speechToText.resolve({
|
|
204
|
+
audio,
|
|
205
|
+
...request.providerId === void 0 ? {} : { providerId: request.providerId },
|
|
206
|
+
...request.language === void 0 ? {} : { language: request.language }
|
|
207
|
+
});
|
|
208
|
+
return await this.ctx.speechToText.transcribe(spec, signal);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
signal.throwIfAborted();
|
|
211
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
212
|
+
throw new RemoteError("speech/transcription-failed", reason, { reason });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
})();
|
|
217
|
+
//#endregion
|
|
218
|
+
export { SpeechController as default };
|