@voiceloop/web-sdk 0.2.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/dist/index.cjs +642 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +312 -0
- package/dist/index.d.ts +312 -0
- package/dist/index.js +604 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.cjs +681 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +180 -0
- package/dist/react/index.d.ts +180 -0
- package/dist/react/index.js +659 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +44 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
type LogLevel = "info" | "warn" | "error";
|
|
2
|
+
type LogEntry = {
|
|
3
|
+
id: number;
|
|
4
|
+
ts: number;
|
|
5
|
+
level: LogLevel;
|
|
6
|
+
tag: string;
|
|
7
|
+
msg: string;
|
|
8
|
+
detail?: string;
|
|
9
|
+
};
|
|
10
|
+
declare function log(tag: string, msg: string, detail?: string, level?: LogLevel): void;
|
|
11
|
+
declare function warn(tag: string, msg: string, detail?: string): void;
|
|
12
|
+
declare function logError(tag: string, msg: string, detail?: string): void;
|
|
13
|
+
declare function getEntries(): readonly LogEntry[];
|
|
14
|
+
declare function clearLog(): void;
|
|
15
|
+
declare function subscribe(fn: () => void): () => void;
|
|
16
|
+
declare function formatForCopy(): string;
|
|
17
|
+
|
|
18
|
+
declare const MIC_SAMPLE_RATE = 16000;
|
|
19
|
+
declare const TTS_SAMPLE_RATE = 24000;
|
|
20
|
+
type AudioCaptureHandle = {
|
|
21
|
+
stop: () => void;
|
|
22
|
+
getVolume: () => number;
|
|
23
|
+
};
|
|
24
|
+
declare function startMicCapture(onPcm: (chunk: ArrayBuffer) => void): Promise<AudioCaptureHandle>;
|
|
25
|
+
type PcmPlayerHandle = {
|
|
26
|
+
enqueue: (pcm: Uint8Array) => void;
|
|
27
|
+
flush: () => void;
|
|
28
|
+
resume: () => void;
|
|
29
|
+
};
|
|
30
|
+
declare function createPcmPlayer(): PcmPlayerHandle;
|
|
31
|
+
|
|
32
|
+
type SessionConfig = {
|
|
33
|
+
type: "session.config";
|
|
34
|
+
session_id: string;
|
|
35
|
+
audio_format: "pcm";
|
|
36
|
+
sample_rate: number;
|
|
37
|
+
brain_mode: "server" | "client";
|
|
38
|
+
turn_policy: {
|
|
39
|
+
vad_stop_secs: number;
|
|
40
|
+
vad_start_secs: number;
|
|
41
|
+
allow_interruptions: boolean;
|
|
42
|
+
eot_strategy: "vad" | "smart";
|
|
43
|
+
};
|
|
44
|
+
capabilities: {
|
|
45
|
+
server_vad: boolean;
|
|
46
|
+
client_barge: boolean;
|
|
47
|
+
client_turn_end: boolean;
|
|
48
|
+
client_say: boolean;
|
|
49
|
+
smart_eot: boolean;
|
|
50
|
+
filler: boolean;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
type FillerStartedEvent = {
|
|
54
|
+
type: "filler.started";
|
|
55
|
+
id: string;
|
|
56
|
+
text: string;
|
|
57
|
+
category?: string | null;
|
|
58
|
+
duration_ms: number;
|
|
59
|
+
};
|
|
60
|
+
type FillerStoppedEvent = {
|
|
61
|
+
type: "filler.stopped";
|
|
62
|
+
id: string;
|
|
63
|
+
};
|
|
64
|
+
type FillerSkippedEvent = {
|
|
65
|
+
type: "filler.skipped";
|
|
66
|
+
reason: "tts_fast";
|
|
67
|
+
wait_ms: number;
|
|
68
|
+
};
|
|
69
|
+
type BrainRequestEvent = {
|
|
70
|
+
type: "brain.request";
|
|
71
|
+
transcript: string;
|
|
72
|
+
history: Array<{
|
|
73
|
+
role: string;
|
|
74
|
+
content: string;
|
|
75
|
+
}>;
|
|
76
|
+
generation_id: string;
|
|
77
|
+
session_id: string;
|
|
78
|
+
/** Original filler phrase already spoken to the user (optional). */
|
|
79
|
+
filler_prefix?: string;
|
|
80
|
+
/** Server-built prompt append; concatenate to your system prompt. */
|
|
81
|
+
system_append?: string;
|
|
82
|
+
};
|
|
83
|
+
type AsrPartialEvent = {
|
|
84
|
+
type: "transcript.partial";
|
|
85
|
+
text: string;
|
|
86
|
+
};
|
|
87
|
+
type AsrFinalEvent = {
|
|
88
|
+
type: "transcript.final";
|
|
89
|
+
text: string;
|
|
90
|
+
};
|
|
91
|
+
type AsrIncompleteEvent = {
|
|
92
|
+
type: "transcript.incomplete";
|
|
93
|
+
text: string;
|
|
94
|
+
wait_ms?: number;
|
|
95
|
+
};
|
|
96
|
+
type AsrTimingEvent = {
|
|
97
|
+
type: "transcript.timing";
|
|
98
|
+
wait_ms: number;
|
|
99
|
+
};
|
|
100
|
+
type TurnStartedEvent = {
|
|
101
|
+
type: "turn.started";
|
|
102
|
+
};
|
|
103
|
+
type TurnEndedEvent = {
|
|
104
|
+
type: "turn.ended";
|
|
105
|
+
transcript?: string;
|
|
106
|
+
};
|
|
107
|
+
type AssistantDelta = {
|
|
108
|
+
type: "assistant.delta";
|
|
109
|
+
text: string;
|
|
110
|
+
phase?: "main";
|
|
111
|
+
generationId?: string;
|
|
112
|
+
generation_id?: string;
|
|
113
|
+
};
|
|
114
|
+
type TtsStartedEvent = {
|
|
115
|
+
type: "tts.started";
|
|
116
|
+
};
|
|
117
|
+
type TtsStoppedEvent = {
|
|
118
|
+
type: "tts.stopped";
|
|
119
|
+
reason: "completed" | "interrupted";
|
|
120
|
+
};
|
|
121
|
+
type AssistantDoneEvent = {
|
|
122
|
+
type: "assistant.done";
|
|
123
|
+
};
|
|
124
|
+
type InterruptedEvent = {
|
|
125
|
+
type: "interrupted";
|
|
126
|
+
};
|
|
127
|
+
type ErrorEvent = {
|
|
128
|
+
type: "error";
|
|
129
|
+
code?: number;
|
|
130
|
+
message: string;
|
|
131
|
+
};
|
|
132
|
+
type FtlMetrics = {
|
|
133
|
+
total_ms: number;
|
|
134
|
+
asr_tail_ms: number | null;
|
|
135
|
+
svad_infer_ms: number | null;
|
|
136
|
+
svad_wait_ms: number | null;
|
|
137
|
+
lftl_ms: number | null;
|
|
138
|
+
tfal_ms: number | null;
|
|
139
|
+
};
|
|
140
|
+
type IlMetrics = {
|
|
141
|
+
total_ms: number | null;
|
|
142
|
+
vsl_ms: number;
|
|
143
|
+
aftl_ms: number | null;
|
|
144
|
+
};
|
|
145
|
+
type TurnMetricsEvent = {
|
|
146
|
+
type: "turn.metrics";
|
|
147
|
+
turn_id: string;
|
|
148
|
+
ftl: FtlMetrics | null;
|
|
149
|
+
il: IlMetrics | null;
|
|
150
|
+
};
|
|
151
|
+
type ServerEvent = AssistantDoneEvent | TurnMetricsEvent | SessionConfig | AsrPartialEvent | AsrFinalEvent | AsrIncompleteEvent | AsrTimingEvent | TurnStartedEvent | TurnEndedEvent | AssistantDelta | FillerStartedEvent | FillerStoppedEvent | FillerSkippedEvent | TtsStartedEvent | TtsStoppedEvent | InterruptedEvent | ErrorEvent | BrainRequestEvent;
|
|
152
|
+
type BargeFrame = {
|
|
153
|
+
type: "barge";
|
|
154
|
+
};
|
|
155
|
+
type TurnEndFrame = {
|
|
156
|
+
type: "turn.end";
|
|
157
|
+
transcript?: string;
|
|
158
|
+
};
|
|
159
|
+
type SayFrame = {
|
|
160
|
+
type: "say";
|
|
161
|
+
text: string;
|
|
162
|
+
voice?: string;
|
|
163
|
+
};
|
|
164
|
+
type ClientControlFrame = BargeFrame | TurnEndFrame | SayFrame;
|
|
165
|
+
type SessionState = "idle" | "listening" | "thinking" | "speaking" | "interrupted";
|
|
166
|
+
type ConnectionState = "disconnected" | "connecting" | "connected" | "reconnecting";
|
|
167
|
+
type BrainDeltaFrame = {
|
|
168
|
+
type: "brain.delta";
|
|
169
|
+
text: string;
|
|
170
|
+
generation_id: string;
|
|
171
|
+
};
|
|
172
|
+
type BrainDoneFrame = {
|
|
173
|
+
type: "brain.done";
|
|
174
|
+
generation_id: string;
|
|
175
|
+
};
|
|
176
|
+
type BrainErrorFrame = {
|
|
177
|
+
type: "brain.error";
|
|
178
|
+
message: string;
|
|
179
|
+
generation_id: string;
|
|
180
|
+
};
|
|
181
|
+
type TtsOptions = {
|
|
182
|
+
/** 音色 ID,例如 "zh_male_yuanboxiaoshu_uranus_bigtts" */
|
|
183
|
+
speaker?: string;
|
|
184
|
+
/** 语速,范围 -50~100(100 = 2倍速,-50 = 0.5倍速) */
|
|
185
|
+
speech_rate?: number;
|
|
186
|
+
/** 音量,范围 -50~100(100 = 2倍音量,-50 = 0.5倍音量) */
|
|
187
|
+
loudness_rate?: number;
|
|
188
|
+
/**
|
|
189
|
+
* 方言。目前仅 zh_female_vv_uranus_bigtts 音色支持,可选值:
|
|
190
|
+
* - "dongbei" 东北话
|
|
191
|
+
* - "shaanxi" 陕西话
|
|
192
|
+
* - "sichuan" 四川话
|
|
193
|
+
*/
|
|
194
|
+
explicit_dialect?: "dongbei" | "shaanxi" | "sichuan";
|
|
195
|
+
/**
|
|
196
|
+
* 语音指令/情绪引导,传入参考文本让模型按指定风格合成,
|
|
197
|
+
* 例如 ["用特别特别痛心的语气说话"]
|
|
198
|
+
*/
|
|
199
|
+
context_texts?: string[];
|
|
200
|
+
};
|
|
201
|
+
type TurnPolicy = {
|
|
202
|
+
/** 连接后立即播报的欢迎语,传空字符串可禁用服务端默认欢迎语 */
|
|
203
|
+
welcome_text?: string;
|
|
204
|
+
/** 是否启用垫词,默认 true(仅 doubao TTS 后端生效) */
|
|
205
|
+
filler_enabled?: boolean;
|
|
206
|
+
tts_options?: TtsOptions;
|
|
207
|
+
};
|
|
208
|
+
type CreateSessionRequest = {
|
|
209
|
+
turn_policy?: TurnPolicy;
|
|
210
|
+
app_context?: Record<string, unknown>;
|
|
211
|
+
brain_mode?: "server" | "client";
|
|
212
|
+
};
|
|
213
|
+
type CreateSessionResponse = {
|
|
214
|
+
session_id: string;
|
|
215
|
+
session_token: string;
|
|
216
|
+
policy_profile: Record<string, unknown>;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
type Utterance = {
|
|
220
|
+
role: "user" | "assistant";
|
|
221
|
+
text: string;
|
|
222
|
+
partial?: boolean;
|
|
223
|
+
incomplete?: boolean;
|
|
224
|
+
fillerPrefix?: string;
|
|
225
|
+
waitTimes?: number[];
|
|
226
|
+
};
|
|
227
|
+
type TurnMetricsSummary = {
|
|
228
|
+
turn_id: string;
|
|
229
|
+
ftl: FtlMetrics | null;
|
|
230
|
+
il: IlMetrics | null;
|
|
231
|
+
ts: number;
|
|
232
|
+
};
|
|
233
|
+
type VoiceSessionState = {
|
|
234
|
+
connection: ConnectionState;
|
|
235
|
+
session: SessionState;
|
|
236
|
+
utterances: Utterance[];
|
|
237
|
+
volume: number;
|
|
238
|
+
error: string | null;
|
|
239
|
+
latency: {
|
|
240
|
+
current: TurnMetricsSummary | null;
|
|
241
|
+
history: TurnMetricsSummary[];
|
|
242
|
+
};
|
|
243
|
+
};
|
|
244
|
+
declare function createInitialState(): VoiceSessionState;
|
|
245
|
+
|
|
246
|
+
type EventMap = {
|
|
247
|
+
state: (s: VoiceSessionState) => void;
|
|
248
|
+
log: (e: LogEntry) => void;
|
|
249
|
+
};
|
|
250
|
+
declare class TypedEmitter {
|
|
251
|
+
private _listeners;
|
|
252
|
+
on<K extends keyof EventMap>(event: K, fn: EventMap[K]): this;
|
|
253
|
+
off<K extends keyof EventMap>(event: K, fn: EventMap[K]): this;
|
|
254
|
+
protected emit<K extends keyof EventMap>(event: K, ...args: Parameters<EventMap[K]>): void;
|
|
255
|
+
}
|
|
256
|
+
type BrainSendFrame = (frame: BrainDeltaFrame | BrainDoneFrame | BrainErrorFrame) => void;
|
|
257
|
+
type VoiceLoopClientOptions = {
|
|
258
|
+
serverUrl?: string;
|
|
259
|
+
apiKey?: string;
|
|
260
|
+
/** 话轮策略与 TTS 参数,含垫词、打断、EoT、音色、语速等。 */
|
|
261
|
+
turnPolicy?: TurnPolicy;
|
|
262
|
+
/** Called when the server delegates an LLM request to the client. */
|
|
263
|
+
onBrainRequest?: (evt: BrainRequestEvent, sendFrame: BrainSendFrame) => void | Promise<void>;
|
|
264
|
+
/** Inject custom microphone capture (useful for testing). */
|
|
265
|
+
micCapture?: (onPcm: (chunk: ArrayBuffer) => void) => Promise<AudioCaptureHandle>;
|
|
266
|
+
/** Inject custom PCM player factory (useful for testing). */
|
|
267
|
+
playerFactory?: () => PcmPlayerHandle;
|
|
268
|
+
};
|
|
269
|
+
declare class VoiceLoopClient extends TypedEmitter {
|
|
270
|
+
private _state;
|
|
271
|
+
private _ctx;
|
|
272
|
+
private _ws;
|
|
273
|
+
private _mic;
|
|
274
|
+
private _player;
|
|
275
|
+
private _volTimer;
|
|
276
|
+
private readonly _serverUrl;
|
|
277
|
+
private readonly _apiKey;
|
|
278
|
+
private readonly _turnPolicy;
|
|
279
|
+
private readonly _onBrainRequest;
|
|
280
|
+
private readonly _micCapture;
|
|
281
|
+
constructor(opts?: VoiceLoopClientOptions);
|
|
282
|
+
get state(): VoiceSessionState;
|
|
283
|
+
connect(): Promise<void>;
|
|
284
|
+
disconnect(): void;
|
|
285
|
+
barge(): void;
|
|
286
|
+
endTurn(transcript?: string): void;
|
|
287
|
+
say(text: string, voice?: string): void;
|
|
288
|
+
private _send;
|
|
289
|
+
private _handleEvent;
|
|
290
|
+
private _applyPatch;
|
|
291
|
+
private _cleanup;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
type StateMachineContext = {
|
|
295
|
+
assistantBubbleOpen: boolean;
|
|
296
|
+
userTurnActive: boolean;
|
|
297
|
+
incompleteAccum: string;
|
|
298
|
+
hasIncompleteUserTurn: boolean;
|
|
299
|
+
preLLMText: string;
|
|
300
|
+
};
|
|
301
|
+
declare function createStateMachineContext(): StateMachineContext;
|
|
302
|
+
type SideEffect = {
|
|
303
|
+
kind: "flush_player";
|
|
304
|
+
};
|
|
305
|
+
type ReduceResult = {
|
|
306
|
+
state: VoiceSessionState;
|
|
307
|
+
ctx: StateMachineContext;
|
|
308
|
+
effects: SideEffect[];
|
|
309
|
+
};
|
|
310
|
+
declare function reduceServerEvent(state: VoiceSessionState, ctx: StateMachineContext, evt: ServerEvent): ReduceResult;
|
|
311
|
+
|
|
312
|
+
export { type AsrFinalEvent, type AsrIncompleteEvent, type AsrPartialEvent, type AsrTimingEvent, type AssistantDelta, type AssistantDoneEvent, type AudioCaptureHandle, type BargeFrame, type BrainDeltaFrame, type BrainDoneFrame, type BrainErrorFrame, type BrainRequestEvent, type BrainSendFrame, type ClientControlFrame, type ConnectionState, type CreateSessionRequest, type CreateSessionResponse, type ErrorEvent, type FillerSkippedEvent, type FillerStartedEvent, type FillerStoppedEvent, type FtlMetrics, type IlMetrics, type InterruptedEvent, type LogEntry, type LogLevel, MIC_SAMPLE_RATE, type PcmPlayerHandle, type ReduceResult, type SayFrame, type ServerEvent, type SessionConfig, type SessionState, type SideEffect, type StateMachineContext, TTS_SAMPLE_RATE, type TtsOptions, type TtsStartedEvent, type TtsStoppedEvent, type TurnEndFrame, type TurnEndedEvent, type TurnMetricsEvent, type TurnMetricsSummary, type TurnPolicy, type TurnStartedEvent, type Utterance, VoiceLoopClient, type VoiceLoopClientOptions, type VoiceSessionState, clearLog, createInitialState, createPcmPlayer, createStateMachineContext, formatForCopy, getEntries, log, logError, reduceServerEvent, startMicCapture, subscribe, warn };
|