@autoark-ai/eva-client-sdk-ts 1.0.3 → 1.0.4
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.md +98 -202
- package/dist/browser.d.ts +20 -11
- package/dist/browser.js +23 -12
- package/dist/index.d.ts +94 -61
- package/dist/index.js +1 -1
- package/dist/spi.d.ts +5 -4
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -64,7 +64,6 @@ import type { MediaTransportsConfig } from "@autoark-ai/eva-client-sdk-ts/spi";
|
|
|
64
64
|
import {
|
|
65
65
|
createBrowserAudioInputSource,
|
|
66
66
|
createBrowserAudioOutputSink,
|
|
67
|
-
createBrowserCameraSnapshotSource,
|
|
68
67
|
createPassthroughAecProcessor,
|
|
69
68
|
} from "@autoark-ai/eva-client-sdk-ts/browser";
|
|
70
69
|
|
|
@@ -77,44 +76,27 @@ const transports: MediaTransportsConfig = {
|
|
|
77
76
|
}),
|
|
78
77
|
output: createBrowserAudioOutputSink(),
|
|
79
78
|
aec: createPassthroughAecProcessor(),
|
|
80
|
-
camera: createBrowserCameraSnapshotSource({
|
|
81
|
-
video: { facingMode: { ideal: "environment" } },
|
|
82
|
-
mimeType: "image/png",
|
|
83
|
-
}),
|
|
84
79
|
};
|
|
85
80
|
|
|
86
81
|
const agent = createEvaVoiceDialogueAgent({
|
|
87
82
|
apiKey: applicationManagedApiKey,
|
|
88
83
|
asr: {
|
|
89
|
-
model: "
|
|
90
|
-
sampleRate:
|
|
84
|
+
model: "ark-asr-plus",
|
|
85
|
+
sampleRate: 16_000,
|
|
91
86
|
},
|
|
92
87
|
llm: {
|
|
93
|
-
model: "doubao-seed-2
|
|
88
|
+
model: "volcengine-doubao-seed-2.0-lite",
|
|
94
89
|
},
|
|
95
90
|
tts: {
|
|
96
|
-
model: "
|
|
97
|
-
voice: "
|
|
98
|
-
sampleRate:
|
|
91
|
+
model: "ark-tts-flash",
|
|
92
|
+
voice: "zh_en_male_evan",
|
|
93
|
+
sampleRate: 44100,
|
|
99
94
|
},
|
|
100
95
|
vad: {
|
|
101
96
|
sensitivity: 0.6,
|
|
102
97
|
silenceThresholdMs: 400,
|
|
103
98
|
},
|
|
104
|
-
bargeIn: {
|
|
105
|
-
initialPlaybackGuardMs: 3000, // 单位:ms(毫秒);3000 ms = 3 秒
|
|
106
|
-
},
|
|
107
99
|
transports,
|
|
108
|
-
history: { maxTurns: 10 },
|
|
109
|
-
camera: { captureTimeoutMs: 1500 },
|
|
110
|
-
emotion: {
|
|
111
|
-
enabled: true,
|
|
112
|
-
// custom labels 会完整替换默认业务标签;SDK 会自动补一个 unknown。
|
|
113
|
-
labels: ["happy", "sad"],
|
|
114
|
-
// 这里只填业务补充说明,不是完整提示词,也不能替换 SDK 内置规则。
|
|
115
|
-
instructions: "这是儿童陪伴场景,重点区分害怕、难过和开心。",
|
|
116
|
-
maxInputChars: 2000,
|
|
117
|
-
},
|
|
118
100
|
});
|
|
119
101
|
|
|
120
102
|
const unsubscribe = agent.onEvent((event: AgentEvent) => {
|
|
@@ -125,8 +107,6 @@ const unsubscribe = agent.onEvent((event: AgentEvent) => {
|
|
|
125
107
|
|
|
126
108
|
await agent.start();
|
|
127
109
|
await agent.setAudioInputEnabled(true);
|
|
128
|
-
// 摄像头默认关闭;需要时显式开启,开启期间持续持有一个 session。
|
|
129
|
-
await agent.setCameraCaptureEnabled(true);
|
|
130
110
|
await agent.submitText("你好");
|
|
131
111
|
|
|
132
112
|
console.log(agent.getMessages());
|
|
@@ -136,6 +116,24 @@ await agent.stop();
|
|
|
136
116
|
unsubscribe();
|
|
137
117
|
```
|
|
138
118
|
|
|
119
|
+
## 可选:增加摄像头
|
|
120
|
+
|
|
121
|
+
需要图片输入时,在上例的 `transports` 中增加 browser camera source:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { createBrowserCameraSnapshotSource } from "@autoark-ai/eva-client-sdk-ts/browser";
|
|
125
|
+
|
|
126
|
+
const cameraTransports: MediaTransportsConfig = {
|
|
127
|
+
...transports,
|
|
128
|
+
camera: createBrowserCameraSnapshotSource(),
|
|
129
|
+
};
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
创建 Agent 时使用 `cameraTransports`。摄像头默认关闭;调用
|
|
133
|
+
`await agent.setCameraCaptureEnabled(true)` 后才会申请权限并持有 camera session,关闭后释放。
|
|
134
|
+
启用期间,每个 speech turn 至多采集一张图片供当前 LLM 请求使用;不开启或不提供 camera source
|
|
135
|
+
都不影响语音和文本对话。
|
|
136
|
+
|
|
139
137
|
## Agent Facade
|
|
140
138
|
|
|
141
139
|
`createEvaVoiceDialogueAgent(config)` 返回的 `EvaVoiceDialogueAgent` 只有八个方法:
|
|
@@ -168,218 +166,121 @@ Agent 一旦开始停止,就不再接受新的 turn 或事件订阅。需要
|
|
|
168
166
|
|
|
169
167
|
## 配置
|
|
170
168
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
|
175
|
-
|
|
|
176
|
-
| `
|
|
177
|
-
| `
|
|
178
|
-
| `
|
|
179
|
-
| `llm
|
|
180
|
-
| `
|
|
181
|
-
| `
|
|
182
|
-
| `
|
|
183
|
-
| `
|
|
184
|
-
| `
|
|
185
|
-
| `
|
|
186
|
-
| `
|
|
187
|
-
| `
|
|
188
|
-
| `
|
|
189
|
-
| `
|
|
190
|
-
| `
|
|
191
|
-
| `
|
|
192
|
-
| `
|
|
193
|
-
| `
|
|
194
|
-
| `
|
|
195
|
-
| `
|
|
196
|
-
| `emotion.instructions` | 否 | 给内置分类 prompt 的业务补充说明,不是完整提示词 |
|
|
197
|
-
| `emotion.maxInputChars` | 否 | 送入 emotion 分类的 utterance 上限,默认 `2000` 个 Unicode code point |
|
|
198
|
-
| `commands.registrations` | 否 | 构造期成对注册的 command definition + handler;空数组等同关闭 |
|
|
199
|
-
| `commands.maxCallsPerTurn` | 否 | 单 turn 完整 raw tool-call 回合上限,默认 `3` |
|
|
200
|
-
| `metadata` | 否 | JSON-compatible Agent metadata |
|
|
201
|
-
| `transports` | 否 | 完整的 `input`、`output`、`aec` 与可选 `camera` 组合;省略时为纯文本 Agent |
|
|
202
|
-
|
|
203
|
-
当配置 `transports.input` 时,应同时提供 `vad`。`submitText()` 可通过 `SubmitTextOptions` 指定 `turnId` 和当前 turn 的 `metadata`。
|
|
169
|
+
README 只介绍顶层配置及其用途。字段级的必填性、默认值、范围、单位、调节方向、代价和校验规则,
|
|
170
|
+
请查看对应 TypeScript declaration 的双语 JSDoc(IDE hover 或随包 `.d.ts`)。
|
|
171
|
+
|
|
172
|
+
| 顶层配置 / 入口 | 控制什么 |
|
|
173
|
+
| --- | --- |
|
|
174
|
+
| `createEvaVoiceDialogueAgent(config)` | 创建一个 Agent;`config` 在 provider 工作前完成校验和快照。 |
|
|
175
|
+
| `EvaVoiceDialogueAgentConfig.apiKey` | 控制 Agent 以哪个 Gateway 凭证访问 ASR、LLM 和 TTS。 |
|
|
176
|
+
| `EvaVoiceDialogueAgentConfig.asr` | 控制语音转写使用的 model 和目标 PCM 采样率。 |
|
|
177
|
+
| `EvaVoiceDialogueAgentConfig.llm` | 控制回复生成使用的 model 及其生成参数。 |
|
|
178
|
+
| `EvaVoiceDialogueAgentConfig.tts` | 控制语音合成使用的 model、音色及合成参数。 |
|
|
179
|
+
| `EvaVoiceDialogueAgentConfig.vad` | 控制本地语音起止检测。 |
|
|
180
|
+
| `EvaVoiceDialogueAgentConfig.systemPrompt` | 控制每次 LLM 请求使用的 system instruction。 |
|
|
181
|
+
| `EvaVoiceDialogueAgentConfig.greeting` | 控制 Agent 启动时是否问候,以及问候如何生成。 |
|
|
182
|
+
| `EvaVoiceDialogueAgentConfig.history` | 控制后续 LLM 请求是否携带历史问答,以及最多携带多少轮。 |
|
|
183
|
+
| `EvaVoiceDialogueAgentConfig.camera` | 控制单次图片采集的等待时限;不会自动启用摄像头。 |
|
|
184
|
+
| `EvaVoiceDialogueAgentConfig.emotion` | 控制是否为用户输入执行情绪识别,以及分类目录和输入上限。 |
|
|
185
|
+
| `EvaVoiceDialogueAgentConfig.bargeIn` | 控制播放期间何时允许新语音进入打断判定。 |
|
|
186
|
+
| `EvaVoiceDialogueAgentConfig.commands` | 控制 Agent 可调用的 command 及每个 turn 的调用预算。 |
|
|
187
|
+
| `EvaVoiceDialogueAgentConfig.metadata` | 控制附加到 Agent 事件和消息的稳定业务 metadata。 |
|
|
188
|
+
| `EvaVoiceDialogueAgentConfig.transports` | 控制 Agent 使用哪些 audio、AEC 和 camera media roles;省略时为 text-only。 |
|
|
189
|
+
| `SubmitTextOptions` | 控制一次手动文本 turn 的 identity 和 metadata。 |
|
|
190
|
+
| `MediaTransportsConfig` | 定义注入 Agent 的完整 media role 集合。 |
|
|
191
|
+
| `AecProcessorConfiguration` | 保留 AEC processor 的配置入口;当前版本没有可设置字段。 |
|
|
192
|
+
| `BrowserAudioInputOptions` / `createBrowserAudioInputSource(options)` | 控制默认浏览器麦克风 source 的采集约束和缓冲。 |
|
|
193
|
+
| `BrowserCameraSnapshotOptions` / `createBrowserCameraSnapshotSource(options)` | 控制默认浏览器 camera source 的设备约束和图片编码。 |
|
|
204
194
|
|
|
205
195
|
`llm.extraParameters` 用于 SDK 尚未预定义的模型参数。例如:
|
|
206
196
|
|
|
207
197
|
```ts
|
|
208
198
|
const agent = createEvaVoiceDialogueAgent({
|
|
209
199
|
apiKey: applicationManagedApiKey,
|
|
210
|
-
asr: { model: "
|
|
200
|
+
asr: { model: "ark-asr-plus", sampleRate: 16_000 },
|
|
211
201
|
llm: {
|
|
212
202
|
model: "volcengine-doubao-seed-2.0-lite",
|
|
213
203
|
extraParameters: {
|
|
214
|
-
thinking: {
|
|
215
|
-
|
|
204
|
+
thinking: {
|
|
205
|
+
type: "disabled",
|
|
206
|
+
},
|
|
216
207
|
},
|
|
217
208
|
},
|
|
218
|
-
tts: {
|
|
209
|
+
tts: {
|
|
210
|
+
model: "ark-tts-flash",
|
|
211
|
+
voice: "zh_en_male_evan",
|
|
212
|
+
sampleRate: 44100,
|
|
213
|
+
},
|
|
219
214
|
});
|
|
220
215
|
```
|
|
221
216
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
217
|
+
`extraParameters` 中的字段会直接添加到 LLM request body 顶层,且不能覆盖 SDK 管理的请求字段;
|
|
218
|
+
具体 model 参数见下方外部配置参考。
|
|
219
|
+
|
|
220
|
+
## 外部配置参考 / External configuration references
|
|
226
221
|
|
|
227
|
-
|
|
228
|
-
`
|
|
229
|
-
|
|
230
|
-
`model` 仍是普通扩展字段。构造后修改调用方原对象不会改变请求快照。若 Gateway 拒绝合法未知
|
|
231
|
-
参数,错误沿既有 `GatewayAccessError` 浮现,SDK 不会删除该参数重试。
|
|
222
|
+
- 用户可在 [控制台](https://eva.autoarkai.com/console/api-keys) 创建并获取 API Key,格式如
|
|
223
|
+
`ak-xxxxxxxx...`;也可使用 [EVA Skill](https://eva-dev.autoarkai.com/api-docs/guide/eva-skill),
|
|
224
|
+
或参考 [EVA CLI 文档](https://eva-dev.autoarkai.com/api-docs/guide/eva-cli)获取 API Key。
|
|
232
225
|
|
|
233
|
-
|
|
226
|
+
ASR、LLM、TTS model、TTS voice,以及采样率和模型参数的支持范围、准确值与默认值见
|
|
227
|
+
[EVA Models](https://eva.autoarkai.com/api-docs/guide/gateway-model-list.md)。选择 model 时,相关采样率、voice、生成参数与
|
|
228
|
+
model-specific 参数必须配套使用。`temperature`、token 上限等可选调音参数可以省略,由 Gateway
|
|
229
|
+
或 model 使用默认行为;带 SDK 默认值的字段仍以对应 JSDoc 为准。SDK 只校验字段形状和基础
|
|
230
|
+
数值,不维护动态 model 兼容矩阵。
|
|
234
231
|
|
|
235
|
-
|
|
232
|
+
当前 SDK 的托管 ASR 和 TTS 链路只支持 PCM(`pcm_s16le`):ASR model 必须支持 PCM 输入,
|
|
233
|
+
TTS model 必须支持 PCM 输出。不支持 PCM 的 model 无法用于当前 SDK。
|
|
236
234
|
|
|
237
|
-
|
|
235
|
+
## Emotion
|
|
236
|
+
|
|
237
|
+
通过 `emotion.enabled` 开启情绪识别后,SDK 会同时处理麦克风转写和 `submitText()` 提交的用户文本,
|
|
238
|
+
并通过 `emotion.detected` 事件返回分类结果。例如:
|
|
238
239
|
|
|
239
240
|
```ts
|
|
240
241
|
const emotion: EmotionConfig = {
|
|
241
242
|
enabled: true,
|
|
242
243
|
labels: ["happy", "sad"],
|
|
243
244
|
instructions: "这是儿童陪伴场景,重点区分害怕、难过和开心。",
|
|
244
|
-
maxInputChars: 2000,
|
|
245
245
|
};
|
|
246
246
|
```
|
|
247
247
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
`CommandCall.id` 是 Gateway/model 给出的不透明标识,只用于同一 turn 内关联结果与 SDK 幂等;下一 turn 可以再次出现相同 id。handler 应尽快响应 `CommandContext.signal`。`command.called` 一旦可见,handler 已承诺入场一次,因此同步 listener 立即打断时 handler 仍可能以预取消 signal 入场。SDK 会抑制取消后的事件、result回填、LLM与媒体输出,但不能撤回 handler 已提交到外部系统的业务副作用;跨进程幂等或补偿仍由接入方负责。
|
|
248
|
+
`emotionCode` 默认来自 `DEFAULT_EMOTION_CODES`;custom `labels` 会完整替换默认业务标签,SDK
|
|
249
|
+
仍会保留 `unknown`。`confidence` 是模型自报的可选信心度,不是经过统计校准的概率;
|
|
250
|
+
`source`、`textPreview` 和 `latencyMs` 分别表示输入来源、用户内容预览和分类耗时,记录事件时应按
|
|
251
|
+
应用的隐私规则处理 `textPreview`。
|
|
253
252
|
|
|
254
|
-
|
|
253
|
+
情绪识别与正常回复并发,不改写 reply、history、messages 或 TTS,也不保证相对
|
|
254
|
+
`reply.final` 的到达顺序。分类请求失败会发出非致命 `error`,但不会中断正常回复;
|
|
255
|
+
`instructions` 只补充业务语境,不需要自定义分类时可以省略。字段默认值和校验规则见
|
|
256
|
+
`EmotionConfig` JSDoc。
|
|
255
257
|
|
|
256
|
-
|
|
258
|
+
## Command
|
|
257
259
|
|
|
258
|
-
|
|
260
|
+
Command 通过 `commands.registrations` 在 Agent 构造时注册。每项同时包含提供给模型的
|
|
261
|
+
`definition` 和执行具体业务的 `handler`:
|
|
259
262
|
|
|
260
263
|
```ts
|
|
261
|
-
import type {
|
|
262
|
-
|
|
263
|
-
export interface ShowCurrentTimeCommandOptions {
|
|
264
|
-
readonly clock?: () => Date;
|
|
265
|
-
readonly showAlert?: (message: string) => void;
|
|
266
|
-
}
|
|
264
|
+
import type { CommandsConfig } from "@autoark-ai/eva-client-sdk-ts";
|
|
267
265
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
): CommandRegistration {
|
|
271
|
-
const clock = options.clock ?? (() => new Date());
|
|
272
|
-
const showAlert = options.showAlert ?? ((message: string) => window.alert(message));
|
|
273
|
-
return {
|
|
266
|
+
const commandConfig: CommandsConfig = {
|
|
267
|
+
registrations: [{
|
|
274
268
|
definition: {
|
|
275
|
-
name: "
|
|
276
|
-
description: "
|
|
269
|
+
name: "get_current_time",
|
|
270
|
+
description: "获取当前时间。",
|
|
277
271
|
},
|
|
278
272
|
handler(_call, context) {
|
|
279
273
|
if (context.signal.aborted) {
|
|
280
274
|
return { ok: false, message: "Command cancelled" };
|
|
281
275
|
}
|
|
282
|
-
|
|
283
|
-
showAlert(`当前时间:${now.toLocaleTimeString()}`);
|
|
284
|
-
return {
|
|
285
|
-
ok: true,
|
|
286
|
-
message: "已显示当前时间",
|
|
287
|
-
data: { isoTime: now.toISOString() },
|
|
288
|
-
};
|
|
289
|
-
},
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
<!-- command-example:show-current-time:end -->
|
|
295
|
-
|
|
296
|
-
<!-- command-example:set-page-theme:start -->
|
|
297
|
-
|
|
298
|
-
```ts
|
|
299
|
-
import type { CommandRegistration } from "@autoark-ai/eva-client-sdk-ts";
|
|
300
|
-
|
|
301
|
-
export type PageTheme = "light" | "dark";
|
|
302
|
-
|
|
303
|
-
export interface SetPageThemeCommandOptions {
|
|
304
|
-
readonly applyTheme?: (theme: PageTheme) => void;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
export function createSetPageThemeCommand(
|
|
308
|
-
options: SetPageThemeCommandOptions = {},
|
|
309
|
-
): CommandRegistration {
|
|
310
|
-
const applyTheme = options.applyTheme ?? applyPageTheme;
|
|
311
|
-
return {
|
|
312
|
-
definition: {
|
|
313
|
-
name: "set_page_theme",
|
|
314
|
-
description: "切换当前浏览器页面的明暗主题。",
|
|
315
|
-
parameters: [{
|
|
316
|
-
name: "theme",
|
|
317
|
-
description: "要应用的页面主题。",
|
|
318
|
-
type: "string",
|
|
319
|
-
required: true,
|
|
320
|
-
enum: ["light", "dark"],
|
|
321
|
-
example: "dark",
|
|
322
|
-
}],
|
|
323
|
-
},
|
|
324
|
-
handler(call, context) {
|
|
325
|
-
if (context.signal.aborted) {
|
|
326
|
-
return { ok: false, message: "Command cancelled" };
|
|
327
|
-
}
|
|
328
|
-
const theme = call.arguments.theme;
|
|
329
|
-
if (theme !== "light" && theme !== "dark") {
|
|
330
|
-
return { ok: false, message: "Unsupported page theme" };
|
|
331
|
-
}
|
|
332
|
-
applyTheme(theme);
|
|
333
|
-
return {
|
|
334
|
-
ok: true,
|
|
335
|
-
message: `页面主题已切换为 ${theme}`,
|
|
336
|
-
data: { theme },
|
|
337
|
-
};
|
|
276
|
+
return { ok: true, data: { isoTime: new Date().toISOString() } };
|
|
338
277
|
},
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
function applyPageTheme(theme: PageTheme): void {
|
|
343
|
-
const root = document.documentElement;
|
|
344
|
-
const dark = theme === "dark";
|
|
345
|
-
root.dataset.theme = theme;
|
|
346
|
-
root.style.colorScheme = theme;
|
|
347
|
-
root.style.backgroundColor = dark ? "#171717" : "#ffffff";
|
|
348
|
-
root.style.color = dark ? "#f5f5f5" : "#171717";
|
|
349
|
-
document.body.style.backgroundColor = root.style.backgroundColor;
|
|
350
|
-
document.body.style.color = root.style.color;
|
|
351
|
-
}
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
<!-- command-example:set-page-theme:end -->
|
|
355
|
-
|
|
356
|
-
把两份完整 registration 放入一个 `CommandsConfig`,再作为 Agent config 的 `commands` 字段传入:
|
|
357
|
-
|
|
358
|
-
```ts
|
|
359
|
-
import { createEvaVoiceDialogueAgent, type CommandsConfig } from "@autoark-ai/eva-client-sdk-ts";
|
|
360
|
-
|
|
361
|
-
const commandConfig: CommandsConfig = {
|
|
362
|
-
registrations: [createShowCurrentTimeCommand(), createSetPageThemeCommand()],
|
|
363
|
-
maxCallsPerTurn: 3,
|
|
278
|
+
}],
|
|
364
279
|
};
|
|
365
|
-
|
|
366
|
-
const agent = createEvaVoiceDialogueAgent({
|
|
367
|
-
apiKey: applicationManagedApiKey,
|
|
368
|
-
asr: {
|
|
369
|
-
model: "fun_asr",
|
|
370
|
-
sampleRate: 48_000,
|
|
371
|
-
},
|
|
372
|
-
llm: {
|
|
373
|
-
model: "doubao-seed-2-0-mini-nothink",
|
|
374
|
-
},
|
|
375
|
-
tts: {
|
|
376
|
-
model: "cosyvoice_tts",
|
|
377
|
-
voice: "longjielidou_v3",
|
|
378
|
-
},
|
|
379
|
-
commands: commandConfig,
|
|
380
|
-
});
|
|
381
280
|
```
|
|
382
281
|
|
|
282
|
+
将 `commandConfig` 传给 Agent config 的 `commands` 字段。完整字段和行为说明请查看对应 JSDoc。
|
|
283
|
+
|
|
383
284
|
## 消息
|
|
384
285
|
|
|
385
286
|
`getMessages()` 同步返回按提交顺序排列的只读快照。每条 `ConversationMessage` 包含:
|
|
@@ -427,10 +328,6 @@ user 与 assistant 的最终文本才会进入消息列表。同一轮的两条
|
|
|
427
328
|
|
|
428
329
|
所有事件都有 `streamId`、`partial`、`final` 和只读 `metadata`;除无法定位 turn 的错误外都有 `turnId`。还可能包含 `sequence`、`timestamp` 和 `frameId`。
|
|
429
330
|
|
|
430
|
-
`emotion.detected` 是只上报的旁路结果,不参与 reply、history、messages 或 TTS 控制。`emotionCode` 一定在当前有效 code 空间内,无法解析或越界时为 `unknown`。`confidence` 若存在,会被归一化到 `[0,1]`;它只是模型自报值,不是经过校准的概率或准确率承诺。`textPreview` 含用户内容:不超过 100 个 Unicode code point 时保留原文,超过时取前 100 个后追加 ASCII `...`,应用仍应按自身隐私策略处理事件和日志。
|
|
431
|
-
|
|
432
|
-
分类复用当前 Agent 的 LLM stage,但不会接收正常 reply 的 system prompt、history 或 camera。分类请求失败时,同 turn 发出 `fatal: false` 的脱敏 `error`,不伪造 `unknown` 结果;新输入或 `stop()` 取消的分类不会发出 emotion 事件或错误。分类可能晚于 `reply.final` 到达。
|
|
433
|
-
|
|
434
331
|
建议用穷尽 switch 消费事件:
|
|
435
332
|
|
|
436
333
|
```ts
|
|
@@ -573,18 +470,17 @@ const softwareAecTransports: MediaTransportsConfig = {
|
|
|
573
470
|
| 输入 | `createBrowserAudioInputSource()` | 使用浏览器麦克风采集音频 |
|
|
574
471
|
| 输出 | `createBrowserAudioOutputSink()` | 使用 Web Audio 播放 TTS 音频 |
|
|
575
472
|
| AEC | `createPassthroughAecProcessor()` | 不做软件回声处理,由浏览器和操作系统负责 AEC |
|
|
576
|
-
| 摄像头 | `createBrowserCameraSnapshotSource()` |
|
|
473
|
+
| 摄像头 | `createBrowserCameraSnapshotSource()` | 提供可选的浏览器静态图片采集 |
|
|
577
474
|
|
|
578
475
|
```ts
|
|
579
476
|
const defaultTransports: MediaTransportsConfig = {
|
|
580
477
|
input: createBrowserAudioInputSource({ echoCancellation: true }),
|
|
581
478
|
output: createBrowserAudioOutputSink(),
|
|
582
479
|
aec: createPassthroughAecProcessor(),
|
|
583
|
-
camera: createBrowserCameraSnapshotSource(),
|
|
584
480
|
};
|
|
585
481
|
```
|
|
586
482
|
|
|
587
|
-
|
|
483
|
+
摄像头按前文的可选小节加入,不会由 agent factory 自动补齐。
|
|
588
484
|
|
|
589
485
|
默认组合开启浏览器 input 的 `echoCancellation`,同时使用 passthrough AEC。如果接入自己的软件 AEC,应将 `echoCancellation` 设为 `false`,避免平台 AEC 与软件 AEC 重复处理。
|
|
590
486
|
|
package/dist/browser.d.ts
CHANGED
|
@@ -2,33 +2,39 @@ import type { AecProcessor, AudioInputSource, AudioOutputSink, CameraSnapshotSou
|
|
|
2
2
|
/** Options for the SDK-provided browser microphone input. */
|
|
3
3
|
export interface BrowserAudioInputOptions {
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* 当前 capture session 失败前最多缓冲的已编码音频块数;必须为正整数,越大越能吸收短暂消费抖动,但占用更多内存并可能增加排队延迟。
|
|
6
|
+
* English: Maximum encoded chunks buffered before capture fails; it must be a positive integer, and larger values absorb brief consumer stalls at the cost of memory and queueing latency.
|
|
6
7
|
* @defaultValue 128
|
|
7
8
|
* @remarks Must be a positive integer.
|
|
8
9
|
*/
|
|
9
10
|
maxBufferedChunks?: number;
|
|
10
11
|
/**
|
|
11
|
-
*
|
|
12
|
+
* 通过 `getUserMedia` 请求平台 echo cancellation;启用通常降低扬声器回声,但与 active software AEC 同开可能重复处理。
|
|
13
|
+
* English: Requests platform echo cancellation through `getUserMedia`; it usually reduces speaker echo but may double-process audio with active software AEC.
|
|
12
14
|
* @defaultValue true
|
|
13
15
|
* @remarks The browser or device may ignore this constraint. Disable it when using active software AEC.
|
|
14
16
|
*/
|
|
15
17
|
echoCancellation?: boolean;
|
|
16
18
|
/**
|
|
17
|
-
*
|
|
19
|
+
* 通过 `getUserMedia` 请求平台 noise suppression;启用通常降低背景噪声,但可能改变音色,且平台可忽略该 constraint。
|
|
20
|
+
* English: Requests platform noise suppression through `getUserMedia`; it usually reduces background noise but may color speech, and the platform may ignore it.
|
|
18
21
|
* @defaultValue true
|
|
19
22
|
* @remarks The browser or device may ignore this constraint.
|
|
20
23
|
*/
|
|
21
24
|
noiseSuppression?: boolean;
|
|
22
25
|
/**
|
|
23
|
-
*
|
|
26
|
+
* 通过 `getUserMedia` 请求平台 automatic gain control;启用通常均衡响度,但可能放大底噪,且平台可忽略该 constraint。
|
|
27
|
+
* English: Requests platform automatic gain control through `getUserMedia`; it usually evens loudness but may amplify noise, and the platform may ignore it.
|
|
24
28
|
* @defaultValue true
|
|
25
29
|
* @remarks The browser or device may ignore this constraint.
|
|
26
30
|
*/
|
|
27
31
|
autoGainControl?: boolean;
|
|
28
32
|
}
|
|
29
33
|
/**
|
|
30
|
-
*
|
|
34
|
+
* 创建 SDK 提供的 browser microphone `AudioInputSource`;factory 本身不采集,start 后资源由 agent lifecycle 独占。
|
|
35
|
+
* English: Creates the SDK-provided browser microphone `AudioInputSource`; the factory does not capture immediately, and the agent owns resources after start.
|
|
31
36
|
* The dialogue runtime owns `start()` / `frames()` / `stop()` after agent construction.
|
|
37
|
+
* @param options - 可选的 queue 与平台 audio constraints;省略时使用已记录默认值。 English: Optional queue and platform audio constraints; omission uses the documented defaults.
|
|
32
38
|
*/
|
|
33
39
|
export declare function createBrowserAudioInputSource(options?: BrowserAudioInputOptions): AudioInputSource;
|
|
34
40
|
/**
|
|
@@ -39,24 +45,28 @@ export declare function createBrowserAudioOutputSink(): AudioOutputSink;
|
|
|
39
45
|
/** Options for the SDK-provided browser still-camera source. */
|
|
40
46
|
export interface BrowserCameraSnapshotOptions {
|
|
41
47
|
/**
|
|
42
|
-
*
|
|
48
|
+
* 传给 `getUserMedia` 的原生 video track constraints;更严格的 constraints 可能提高画面要求,也更容易被设备拒绝或适配。
|
|
49
|
+
* English: Native video-track constraints passed to `getUserMedia`; stricter constraints may request better capture but are more likely to be adapted or rejected.
|
|
43
50
|
* @defaultValue `true`
|
|
44
51
|
* @remarks The browser may adapt or ignore individual ideal constraints.
|
|
45
52
|
*/
|
|
46
53
|
video?: MediaTrackConstraints;
|
|
47
54
|
/**
|
|
48
|
-
*
|
|
55
|
+
* 请求的静态图片编码;PNG 通常无损但字节更大,JPEG 通常更小但有损。
|
|
56
|
+
* English: Requested still-image encoding; PNG is usually lossless and larger, while JPEG is usually smaller and lossy.
|
|
49
57
|
* @defaultValue `image/png`
|
|
50
58
|
*/
|
|
51
59
|
mimeType?: "image/png" | "image/jpeg";
|
|
52
60
|
/**
|
|
53
|
-
* JPEG encoder
|
|
61
|
+
* JPEG encoder质量范围 `0-1`;值越大通常细节更多、文件也更大。
|
|
62
|
+
* English: JPEG encoder quality in `0-1`; larger values usually preserve more detail and produce larger files.
|
|
54
63
|
* @remarks Used only when `mimeType` is `image/jpeg`. Omit to use the browser default.
|
|
55
64
|
*/
|
|
56
65
|
jpegQuality?: number;
|
|
57
66
|
}
|
|
58
67
|
/**
|
|
59
|
-
*
|
|
68
|
+
* 创建 SDK 提供的 browser `CameraSnapshotSource`,不在 factory 调用时申请权限。
|
|
69
|
+
* English: Creates the SDK-provided browser `CameraSnapshotSource` without requesting permission at factory call time.
|
|
60
70
|
*
|
|
61
71
|
* @remarks
|
|
62
72
|
* The factory does not request permission. After composition, the runtime exclusively owns
|
|
@@ -71,8 +81,7 @@ export interface BrowserCameraSnapshotOptions {
|
|
|
71
81
|
* faults the camera role and later camera controls reject deterministically. A successful `stop`
|
|
72
82
|
* permits a later sequential restart.
|
|
73
83
|
*
|
|
74
|
-
* @param options - Browser video constraints and still-image encoding preferences
|
|
75
|
-
* the default video device and PNG encoding at the captured frame's native dimensions.
|
|
84
|
+
* @param options - Browser video constraints 与静态图片编码选项;省略时使用默认 video device、原始尺寸和 PNG。 English: Browser video constraints and still-image encoding preferences; omit for the default device, native dimensions, and PNG.
|
|
76
85
|
* @returns A reusable `CameraSnapshotSource` to pass as `MediaTransportsConfig.camera`.
|
|
77
86
|
*/
|
|
78
87
|
export declare function createBrowserCameraSnapshotSource(options?: BrowserCameraSnapshotOptions): CameraSnapshotSource;
|
package/dist/browser.js
CHANGED
|
@@ -498,7 +498,10 @@ function workletNodeOf(dependencies, context) {
|
|
|
498
498
|
if (dependencies.audioWorkletNodeFactory !== void 0) {
|
|
499
499
|
return dependencies.audioWorkletNodeFactory(context, WORKLET_NAME);
|
|
500
500
|
}
|
|
501
|
-
return new AudioWorkletNode(
|
|
501
|
+
return new AudioWorkletNode(
|
|
502
|
+
context,
|
|
503
|
+
WORKLET_NAME
|
|
504
|
+
);
|
|
502
505
|
}
|
|
503
506
|
function objectUrlOf(dependencies) {
|
|
504
507
|
return dependencies.objectUrl ?? {
|
|
@@ -685,7 +688,9 @@ var DefaultBrowserCameraSnapshotSource = class {
|
|
|
685
688
|
start(signal) {
|
|
686
689
|
if (signal.aborted) return Promise.reject(abortError());
|
|
687
690
|
if (this.active !== void 0 || this.pendingStart !== void 0 || this.teardownPromise !== void 0) {
|
|
688
|
-
return Promise.reject(
|
|
691
|
+
return Promise.reject(
|
|
692
|
+
new EvaSdkError("Browser camera session already exists", { fatal: true })
|
|
693
|
+
);
|
|
689
694
|
}
|
|
690
695
|
const generation = ++this.generation;
|
|
691
696
|
const cancellation = cancellable();
|
|
@@ -716,9 +721,11 @@ var DefaultBrowserCameraSnapshotSource = class {
|
|
|
716
721
|
return Promise.reject(new EvaSdkError("Browser camera is not started", { fatal: true }));
|
|
717
722
|
}
|
|
718
723
|
if (this.pendingCapture !== void 0) {
|
|
719
|
-
return Promise.reject(
|
|
720
|
-
|
|
721
|
-
|
|
724
|
+
return Promise.reject(
|
|
725
|
+
new EvaSdkError("Browser camera capture is already in progress", {
|
|
726
|
+
fatal: true
|
|
727
|
+
})
|
|
728
|
+
);
|
|
722
729
|
}
|
|
723
730
|
const cancellation = cancellable();
|
|
724
731
|
const pending = {
|
|
@@ -880,13 +887,17 @@ function createCanvasOf(dependencies) {
|
|
|
880
887
|
},
|
|
881
888
|
encode(type, quality) {
|
|
882
889
|
return new Promise((resolve, reject) => {
|
|
883
|
-
canvas.toBlob(
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
+
canvas.toBlob(
|
|
891
|
+
(blob) => {
|
|
892
|
+
if (blob === null) {
|
|
893
|
+
reject(new EvaSdkError("Browser camera image encoding failed", { fatal: true }));
|
|
894
|
+
} else {
|
|
895
|
+
resolve(blob);
|
|
896
|
+
}
|
|
897
|
+
},
|
|
898
|
+
type,
|
|
899
|
+
quality
|
|
900
|
+
);
|
|
890
901
|
});
|
|
891
902
|
}
|
|
892
903
|
};
|