@autoark-ai/eva-client-sdk-ts 1.0.3 → 1.0.5
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 +111 -209
- package/dist/browser.d.ts +20 -11
- package/dist/browser.js +23 -12
- package/dist/index.d.ts +96 -61
- package/dist/index.js +4 -4
- package/dist/spi.d.ts +5 -4
- package/package.json +20 -4
package/README.md
CHANGED
|
@@ -20,7 +20,8 @@ npm install @autoark-ai/eva-client-sdk-ts
|
|
|
20
20
|
|
|
21
21
|
## 版本与 Gateway
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
公网正式版本使用普通 SemVer `X.Y.Z`。SDK 使用内置的固定 EVA Gateway;Gateway 地址不能通过
|
|
24
|
+
Agent 配置或任意 URL 改写。
|
|
24
25
|
|
|
25
26
|
包只提供三个入口:
|
|
26
27
|
|
|
@@ -64,7 +65,6 @@ import type { MediaTransportsConfig } from "@autoark-ai/eva-client-sdk-ts/spi";
|
|
|
64
65
|
import {
|
|
65
66
|
createBrowserAudioInputSource,
|
|
66
67
|
createBrowserAudioOutputSink,
|
|
67
|
-
createBrowserCameraSnapshotSource,
|
|
68
68
|
createPassthroughAecProcessor,
|
|
69
69
|
} from "@autoark-ai/eva-client-sdk-ts/browser";
|
|
70
70
|
|
|
@@ -77,44 +77,27 @@ const transports: MediaTransportsConfig = {
|
|
|
77
77
|
}),
|
|
78
78
|
output: createBrowserAudioOutputSink(),
|
|
79
79
|
aec: createPassthroughAecProcessor(),
|
|
80
|
-
camera: createBrowserCameraSnapshotSource({
|
|
81
|
-
video: { facingMode: { ideal: "environment" } },
|
|
82
|
-
mimeType: "image/png",
|
|
83
|
-
}),
|
|
84
80
|
};
|
|
85
81
|
|
|
86
82
|
const agent = createEvaVoiceDialogueAgent({
|
|
87
83
|
apiKey: applicationManagedApiKey,
|
|
88
84
|
asr: {
|
|
89
|
-
model: "
|
|
90
|
-
sampleRate:
|
|
85
|
+
model: "ark-asr-plus",
|
|
86
|
+
sampleRate: 16_000,
|
|
91
87
|
},
|
|
92
88
|
llm: {
|
|
93
|
-
model: "doubao-seed-2
|
|
89
|
+
model: "volcengine-doubao-seed-2.0-lite",
|
|
94
90
|
},
|
|
95
91
|
tts: {
|
|
96
|
-
model: "
|
|
97
|
-
voice: "
|
|
98
|
-
sampleRate:
|
|
92
|
+
model: "ark-tts-flash",
|
|
93
|
+
voice: "zh_en_male_evan",
|
|
94
|
+
sampleRate: 44100,
|
|
99
95
|
},
|
|
100
96
|
vad: {
|
|
101
97
|
sensitivity: 0.6,
|
|
102
98
|
silenceThresholdMs: 400,
|
|
103
99
|
},
|
|
104
|
-
bargeIn: {
|
|
105
|
-
initialPlaybackGuardMs: 3000, // 单位:ms(毫秒);3000 ms = 3 秒
|
|
106
|
-
},
|
|
107
100
|
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
101
|
});
|
|
119
102
|
|
|
120
103
|
const unsubscribe = agent.onEvent((event: AgentEvent) => {
|
|
@@ -125,8 +108,6 @@ const unsubscribe = agent.onEvent((event: AgentEvent) => {
|
|
|
125
108
|
|
|
126
109
|
await agent.start();
|
|
127
110
|
await agent.setAudioInputEnabled(true);
|
|
128
|
-
// 摄像头默认关闭;需要时显式开启,开启期间持续持有一个 session。
|
|
129
|
-
await agent.setCameraCaptureEnabled(true);
|
|
130
111
|
await agent.submitText("你好");
|
|
131
112
|
|
|
132
113
|
console.log(agent.getMessages());
|
|
@@ -136,6 +117,24 @@ await agent.stop();
|
|
|
136
117
|
unsubscribe();
|
|
137
118
|
```
|
|
138
119
|
|
|
120
|
+
## 可选:增加摄像头
|
|
121
|
+
|
|
122
|
+
需要图片输入时,在上例的 `transports` 中增加 browser camera source:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { createBrowserCameraSnapshotSource } from "@autoark-ai/eva-client-sdk-ts/browser";
|
|
126
|
+
|
|
127
|
+
const cameraTransports: MediaTransportsConfig = {
|
|
128
|
+
...transports,
|
|
129
|
+
camera: createBrowserCameraSnapshotSource(),
|
|
130
|
+
};
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
创建 Agent 时使用 `cameraTransports`。摄像头默认关闭;调用
|
|
134
|
+
`await agent.setCameraCaptureEnabled(true)` 后才会申请权限并持有 camera session,关闭后释放。
|
|
135
|
+
启用期间,每个 speech turn 至多采集一张图片供当前 LLM 请求使用;不开启或不提供 camera source
|
|
136
|
+
都不影响语音和文本对话。
|
|
137
|
+
|
|
139
138
|
## Agent Facade
|
|
140
139
|
|
|
141
140
|
`createEvaVoiceDialogueAgent(config)` 返回的 `EvaVoiceDialogueAgent` 只有八个方法:
|
|
@@ -168,218 +167,126 @@ Agent 一旦开始停止,就不再接受新的 turn 或事件订阅。需要
|
|
|
168
167
|
|
|
169
168
|
## 配置
|
|
170
169
|
|
|
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`。
|
|
170
|
+
README 只介绍顶层配置及其用途。字段级的必填性、默认值、范围、单位、调节方向、代价和校验规则,
|
|
171
|
+
请查看对应 TypeScript declaration 的双语 JSDoc(IDE hover 或随包 `.d.ts`)。
|
|
172
|
+
|
|
173
|
+
| 顶层配置 / 入口 | 控制什么 |
|
|
174
|
+
| ----------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
175
|
+
| `createEvaVoiceDialogueAgent(config)` | 创建一个 Agent;`config` 在 provider 工作前完成校验和快照。 |
|
|
176
|
+
| `EvaVoiceDialogueAgentConfig.apiKey` | 控制 Agent 以哪个 Gateway 凭证访问 ASR、LLM 和 TTS。 |
|
|
177
|
+
| `EvaVoiceDialogueAgentConfig.asr` | 控制语音转写使用的 model 和目标 PCM 采样率。 |
|
|
178
|
+
| `EvaVoiceDialogueAgentConfig.llm` | 控制回复生成使用的 model 及其生成参数。 |
|
|
179
|
+
| `EvaVoiceDialogueAgentConfig.tts` | 控制语音合成使用的 model、音色及合成参数。 |
|
|
180
|
+
| `EvaVoiceDialogueAgentConfig.vad` | 控制本地语音起止检测。 |
|
|
181
|
+
| `EvaVoiceDialogueAgentConfig.systemPrompt` | 控制每次 LLM 请求使用的 system instruction。 |
|
|
182
|
+
| `EvaVoiceDialogueAgentConfig.greeting` | 控制 Agent 启动时是否问候,以及问候如何生成。 |
|
|
183
|
+
| `EvaVoiceDialogueAgentConfig.history` | 控制后续 LLM 请求是否携带历史问答,以及最多携带多少轮。 |
|
|
184
|
+
| `EvaVoiceDialogueAgentConfig.camera` | 控制单次图片采集的等待时限;不会自动启用摄像头。 |
|
|
185
|
+
| `EvaVoiceDialogueAgentConfig.emotion` | 控制是否为用户输入执行情绪识别,以及分类目录和输入上限。 |
|
|
186
|
+
| `EvaVoiceDialogueAgentConfig.bargeIn` | 控制播放期间何时允许新语音进入打断判定。 |
|
|
187
|
+
| `EvaVoiceDialogueAgentConfig.commands` | 控制 Agent 可调用的 command 及每个 turn 的调用预算。 |
|
|
188
|
+
| `EvaVoiceDialogueAgentConfig.metadata` | 控制附加到 Agent 事件和消息的稳定业务 metadata。 |
|
|
189
|
+
| `EvaVoiceDialogueAgentConfig.transports` | 控制 Agent 使用哪些 audio、AEC 和 camera media roles;省略时为 text-only。 |
|
|
190
|
+
| `SubmitTextOptions` | 控制一次手动文本 turn 的 identity 和 metadata。 |
|
|
191
|
+
| `MediaTransportsConfig` | 定义注入 Agent 的完整 media role 集合。 |
|
|
192
|
+
| `AecProcessorConfiguration` | 保留 AEC processor 的配置入口;当前版本没有可设置字段。 |
|
|
193
|
+
| `BrowserAudioInputOptions` / `createBrowserAudioInputSource(options)` | 控制默认浏览器麦克风 source 的采集约束和缓冲。 |
|
|
194
|
+
| `BrowserCameraSnapshotOptions` / `createBrowserCameraSnapshotSource(options)` | 控制默认浏览器 camera source 的设备约束和图片编码。 |
|
|
204
195
|
|
|
205
196
|
`llm.extraParameters` 用于 SDK 尚未预定义的模型参数。例如:
|
|
206
197
|
|
|
207
198
|
```ts
|
|
208
199
|
const agent = createEvaVoiceDialogueAgent({
|
|
209
200
|
apiKey: applicationManagedApiKey,
|
|
210
|
-
asr: { model: "
|
|
201
|
+
asr: { model: "ark-asr-plus", sampleRate: 16_000 },
|
|
211
202
|
llm: {
|
|
212
203
|
model: "volcengine-doubao-seed-2.0-lite",
|
|
213
204
|
extraParameters: {
|
|
214
|
-
thinking: {
|
|
215
|
-
|
|
205
|
+
thinking: {
|
|
206
|
+
type: "disabled",
|
|
207
|
+
},
|
|
216
208
|
},
|
|
217
209
|
},
|
|
218
|
-
tts: {
|
|
210
|
+
tts: {
|
|
211
|
+
model: "ark-tts-flash",
|
|
212
|
+
voice: "zh_en_male_evan",
|
|
213
|
+
sampleRate: 44100,
|
|
214
|
+
},
|
|
219
215
|
});
|
|
220
216
|
```
|
|
221
217
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
参数的值域;具体支持情况由 Gateway 和所选模型裁定。省略 `extraParameters` 或传 `{}` 不会
|
|
225
|
-
增加任何字段,也不会补模型默认值。
|
|
218
|
+
`extraParameters` 中的字段会直接添加到 LLM request body 顶层,且不能覆盖 SDK 管理的请求字段;
|
|
219
|
+
具体 model 参数见下方外部配置参考。
|
|
226
220
|
|
|
227
|
-
|
|
228
|
-
`messages`、`temperature`、`max_tokens`、`tools`、`tool_choice`。这些 key 或非 JSON-compatible
|
|
229
|
-
值会在 Agent 构造期报 `EvaSdkError`;检查区分大小写且不递归,因此顶层 `Model` 和嵌套
|
|
230
|
-
`model` 仍是普通扩展字段。构造后修改调用方原对象不会改变请求快照。若 Gateway 拒绝合法未知
|
|
231
|
-
参数,错误沿既有 `GatewayAccessError` 浮现,SDK 不会删除该参数重试。
|
|
221
|
+
## 外部配置参考 / External configuration references
|
|
232
222
|
|
|
233
|
-
|
|
223
|
+
- 用户可在 [控制台](https://eva.autoarkai.com/console/api-keys) 创建并获取 API Key,格式如
|
|
224
|
+
`ak-xxxxxxxx...`;也可使用 [EVA Skill](https://eva-dev.autoarkai.com/api-docs/guide/eva-skill),
|
|
225
|
+
或参考 [EVA CLI 文档](https://eva-dev.autoarkai.com/api-docs/guide/eva-cli)获取 API Key。
|
|
234
226
|
|
|
235
|
-
|
|
227
|
+
ASR、LLM、TTS model、TTS voice,以及采样率和模型参数的支持范围、准确值与默认值见
|
|
228
|
+
[EVA Models](https://eva.autoarkai.com/api-docs/guide/gateway-model-list.md)。选择 model 时,相关采样率、voice、生成参数与
|
|
229
|
+
model-specific 参数必须配套使用。`temperature`、token 上限等可选调音参数可以省略,由 Gateway
|
|
230
|
+
或 model 使用默认行为;带 SDK 默认值的字段仍以对应 JSDoc 为准。SDK 只校验字段形状和基础
|
|
231
|
+
数值,不维护动态 model 兼容矩阵。
|
|
236
232
|
|
|
237
|
-
|
|
233
|
+
当前 SDK 使用 Chat Completions(`/llm/v1/chat/completions`)。查看 EVA Models 的 LLM 参数时,
|
|
234
|
+
请使用 **Chat Completions** 部分。
|
|
235
|
+
|
|
236
|
+
当前 SDK 的托管 ASR 和 TTS 链路只支持 PCM(`pcm_s16le`):ASR model 必须支持 PCM 输入,
|
|
237
|
+
TTS model 必须支持 PCM 输出。不支持 PCM 的 model 无法用于当前 SDK。
|
|
238
|
+
|
|
239
|
+
## Emotion
|
|
240
|
+
|
|
241
|
+
通过 `emotion.enabled` 开启情绪识别后,SDK 会同时处理麦克风转写和 `submitText()` 提交的用户文本,
|
|
242
|
+
并通过 `emotion.detected` 事件返回分类结果。例如:
|
|
238
243
|
|
|
239
244
|
```ts
|
|
240
245
|
const emotion: EmotionConfig = {
|
|
241
246
|
enabled: true,
|
|
242
247
|
labels: ["happy", "sad"],
|
|
243
248
|
instructions: "这是儿童陪伴场景,重点区分害怕、难过和开心。",
|
|
244
|
-
maxInputChars: 2000,
|
|
245
249
|
};
|
|
246
250
|
```
|
|
247
251
|
|
|
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 已提交到外部系统的业务副作用;跨进程幂等或补偿仍由接入方负责。
|
|
253
|
-
|
|
254
|
-
`maxCallsPerTurn` 统计 Gateway 已聚合完成的 raw tool call,默认 `3`。`executable`、`rejected`、`replay` 与 `conflict` 都各消耗一次额度,尚未收全的 arguments fragment 不计。同一 turn 内 id、name 与原始 `argumentsJson` 字节完全一致的 replay 会复用已收束 result,不重复调用 handler 或发 command lifecycle event;相同 id 但内容不同属于 conflict。未知 command、非法 JSON 或 schema 不匹配等 rejection 不调用 handler,也不产生 command lifecycle/error event,而是把安全失败 result 回填给模型。最后一个 result 后只允许一次不带 tools 的 closing completion;如果模型仍返回 tool call,当前 turn 按 LLM failure 结束,不再执行或请求。
|
|
255
|
-
|
|
256
|
-
handler 返回 `ok: false`、throw/reject 或返回运行时无效值都会规整为脱敏的 `command.failed`;原始异常、cause、AK 与 provider raw body 不会进入公共事件或 tool result。成功或失败 result 都会回填给模型,用于生成后续自然语言回复。
|
|
252
|
+
`emotionCode` 默认来自 `DEFAULT_EMOTION_CODES`;custom `labels` 会完整替换默认业务标签,SDK
|
|
253
|
+
仍会保留 `unknown`。`confidence` 是模型自报的可选信心度,不是经过统计校准的概率;
|
|
254
|
+
`source`、`textPreview` 和 `latencyMs` 分别表示输入来源、用户内容预览和分类耗时,记录事件时应按
|
|
255
|
+
应用的隐私规则处理 `textPreview`。
|
|
257
256
|
|
|
258
|
-
|
|
257
|
+
情绪识别与正常回复并发,不改写 reply、history、messages 或 TTS,也不保证相对
|
|
258
|
+
`reply.final` 的到达顺序。分类请求失败会发出非致命 `error`,但不会中断正常回复;
|
|
259
|
+
`instructions` 只补充业务语境,不需要自定义分类时可以省略。字段默认值和校验规则见
|
|
260
|
+
`EmotionConfig` JSDoc。
|
|
259
261
|
|
|
260
|
-
|
|
261
|
-
import type { CommandRegistration } from "@autoark-ai/eva-client-sdk-ts";
|
|
262
|
-
|
|
263
|
-
export interface ShowCurrentTimeCommandOptions {
|
|
264
|
-
readonly clock?: () => Date;
|
|
265
|
-
readonly showAlert?: (message: string) => void;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
export function createShowCurrentTimeCommand(
|
|
269
|
-
options: ShowCurrentTimeCommandOptions = {},
|
|
270
|
-
): CommandRegistration {
|
|
271
|
-
const clock = options.clock ?? (() => new Date());
|
|
272
|
-
const showAlert = options.showAlert ?? ((message: string) => window.alert(message));
|
|
273
|
-
return {
|
|
274
|
-
definition: {
|
|
275
|
-
name: "show_current_time",
|
|
276
|
-
description: "在当前页面弹窗展示用户本地时间。",
|
|
277
|
-
},
|
|
278
|
-
handler(_call, context) {
|
|
279
|
-
if (context.signal.aborted) {
|
|
280
|
-
return { ok: false, message: "Command cancelled" };
|
|
281
|
-
}
|
|
282
|
-
const now = clock();
|
|
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
|
-
};
|
|
338
|
-
},
|
|
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 -->
|
|
262
|
+
## Command
|
|
355
263
|
|
|
356
|
-
|
|
264
|
+
Command 通过 `commands.registrations` 在 Agent 构造时注册。每项同时包含提供给模型的
|
|
265
|
+
`definition` 和执行具体业务的 `handler`:
|
|
357
266
|
|
|
358
267
|
```ts
|
|
359
|
-
import {
|
|
268
|
+
import type { CommandsConfig } from "@autoark-ai/eva-client-sdk-ts";
|
|
360
269
|
|
|
361
270
|
const commandConfig: CommandsConfig = {
|
|
362
|
-
registrations: [
|
|
363
|
-
|
|
271
|
+
registrations: [
|
|
272
|
+
{
|
|
273
|
+
definition: {
|
|
274
|
+
name: "get_current_time",
|
|
275
|
+
description: "获取当前时间。",
|
|
276
|
+
},
|
|
277
|
+
handler(_call, context) {
|
|
278
|
+
if (context.signal.aborted) {
|
|
279
|
+
return { ok: false, message: "Command cancelled" };
|
|
280
|
+
}
|
|
281
|
+
return { ok: true, data: { isoTime: new Date().toISOString() } };
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
],
|
|
364
285
|
};
|
|
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
286
|
```
|
|
382
287
|
|
|
288
|
+
将 `commandConfig` 传给 Agent config 的 `commands` 字段。完整字段和行为说明请查看对应 JSDoc。
|
|
289
|
+
|
|
383
290
|
## 消息
|
|
384
291
|
|
|
385
292
|
`getMessages()` 同步返回按提交顺序排列的只读快照。每条 `ConversationMessage` 包含:
|
|
@@ -427,10 +334,6 @@ user 与 assistant 的最终文本才会进入消息列表。同一轮的两条
|
|
|
427
334
|
|
|
428
335
|
所有事件都有 `streamId`、`partial`、`final` 和只读 `metadata`;除无法定位 turn 的错误外都有 `turnId`。还可能包含 `sequence`、`timestamp` 和 `frameId`。
|
|
429
336
|
|
|
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
337
|
建议用穷尽 switch 消费事件:
|
|
435
338
|
|
|
436
339
|
```ts
|
|
@@ -573,18 +476,17 @@ const softwareAecTransports: MediaTransportsConfig = {
|
|
|
573
476
|
| 输入 | `createBrowserAudioInputSource()` | 使用浏览器麦克风采集音频 |
|
|
574
477
|
| 输出 | `createBrowserAudioOutputSink()` | 使用 Web Audio 播放 TTS 音频 |
|
|
575
478
|
| AEC | `createPassthroughAecProcessor()` | 不做软件回声处理,由浏览器和操作系统负责 AEC |
|
|
576
|
-
| 摄像头 | `createBrowserCameraSnapshotSource()` |
|
|
479
|
+
| 摄像头 | `createBrowserCameraSnapshotSource()` | 提供可选的浏览器静态图片采集 |
|
|
577
480
|
|
|
578
481
|
```ts
|
|
579
482
|
const defaultTransports: MediaTransportsConfig = {
|
|
580
483
|
input: createBrowserAudioInputSource({ echoCancellation: true }),
|
|
581
484
|
output: createBrowserAudioOutputSink(),
|
|
582
485
|
aec: createPassthroughAecProcessor(),
|
|
583
|
-
camera: createBrowserCameraSnapshotSource(),
|
|
584
486
|
};
|
|
585
487
|
```
|
|
586
488
|
|
|
587
|
-
|
|
489
|
+
摄像头按前文的可选小节加入,不会由 agent factory 自动补齐。
|
|
588
490
|
|
|
589
491
|
默认组合开启浏览器 input 的 `echoCancellation`,同时使用 passthrough AEC。如果接入自己的软件 AEC,应将 `echoCancellation` 设为 `false`,避免平台 AEC 与软件 AEC 重复处理。
|
|
590
492
|
|
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
|
};
|