@ariaflowagents/livekit-plugin 0.9.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/README.md +155 -0
- package/dist/agent/AriaFlowAgent.d.ts +11 -0
- package/dist/agent/AriaFlowAgent.d.ts.map +1 -0
- package/dist/agent/AriaFlowAgent.js +22 -0
- package/dist/agent/AriaFlowAgent.js.map +1 -0
- package/dist/audio_byte_stream.d.ts +29 -0
- package/dist/audio_byte_stream.d.ts.map +1 -0
- package/dist/audio_byte_stream.js +62 -0
- package/dist/audio_byte_stream.js.map +1 -0
- package/dist/audio_frame.d.ts +2 -0
- package/dist/audio_frame.d.ts.map +1 -0
- package/dist/audio_frame.js +6 -0
- package/dist/audio_frame.js.map +1 -0
- package/dist/codec/g711.d.ts +14 -0
- package/dist/codec/g711.d.ts.map +1 -0
- package/dist/codec/g711.js +51 -0
- package/dist/codec/g711.js.map +1 -0
- package/dist/errors.d.ts +14 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +27 -0
- package/dist/errors.js.map +1 -0
- package/dist/filler/FillerCoordinator.d.ts +7 -0
- package/dist/filler/FillerCoordinator.d.ts.map +1 -0
- package/dist/filler/FillerCoordinator.js +29 -0
- package/dist/filler/FillerCoordinator.js.map +1 -0
- package/dist/gemini/filler.d.ts +14 -0
- package/dist/gemini/filler.d.ts.map +1 -0
- package/dist/gemini/filler.js +48 -0
- package/dist/gemini/filler.js.map +1 -0
- package/dist/gemini/index.d.ts +4 -0
- package/dist/gemini/index.d.ts.map +1 -0
- package/dist/gemini/index.js +4 -0
- package/dist/gemini/index.js.map +1 -0
- package/dist/gemini/stt.d.ts +106 -0
- package/dist/gemini/stt.d.ts.map +1 -0
- package/dist/gemini/stt.js +528 -0
- package/dist/gemini/stt.js.map +1 -0
- package/dist/gemini/tts.d.ts +57 -0
- package/dist/gemini/tts.d.ts.map +1 -0
- package/dist/gemini/tts.js +529 -0
- package/dist/gemini/tts.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/livekit_io.d.ts +44 -0
- package/dist/livekit_io.d.ts.map +1 -0
- package/dist/livekit_io.js +101 -0
- package/dist/livekit_io.js.map +1 -0
- package/dist/llm/AriaRuntimeLLMAdapter.d.ts +65 -0
- package/dist/llm/AriaRuntimeLLMAdapter.d.ts.map +1 -0
- package/dist/llm/AriaRuntimeLLMAdapter.js +296 -0
- package/dist/llm/AriaRuntimeLLMAdapter.js.map +1 -0
- package/dist/llm/LiveKitRealtimeAdapter.d.ts +99 -0
- package/dist/llm/LiveKitRealtimeAdapter.d.ts.map +1 -0
- package/dist/llm/LiveKitRealtimeAdapter.js +206 -0
- package/dist/llm/LiveKitRealtimeAdapter.js.map +1 -0
- package/dist/metrics/bridge.d.ts +35 -0
- package/dist/metrics/bridge.d.ts.map +1 -0
- package/dist/metrics/bridge.js +89 -0
- package/dist/metrics/bridge.js.map +1 -0
- package/dist/metrics/index.d.ts +3 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +2 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/types.d.ts +84 -0
- package/dist/metrics/types.d.ts.map +1 -0
- package/dist/metrics/types.js +22 -0
- package/dist/metrics/types.js.map +1 -0
- package/dist/recording/index.d.ts +4 -0
- package/dist/recording/index.d.ts.map +1 -0
- package/dist/recording/index.js +3 -0
- package/dist/recording/index.js.map +1 -0
- package/dist/recording/manager.d.ts +14 -0
- package/dist/recording/manager.d.ts.map +1 -0
- package/dist/recording/manager.js +80 -0
- package/dist/recording/manager.js.map +1 -0
- package/dist/recording/s3_adapter.d.ts +26 -0
- package/dist/recording/s3_adapter.d.ts.map +1 -0
- package/dist/recording/s3_adapter.js +120 -0
- package/dist/recording/s3_adapter.js.map +1 -0
- package/dist/recording/storage.d.ts +19 -0
- package/dist/recording/storage.d.ts.map +1 -0
- package/dist/recording/storage.js +2 -0
- package/dist/recording/storage.js.map +1 -0
- package/dist/session/AriaFlowLivekitSession.d.ts +50 -0
- package/dist/session/AriaFlowLivekitSession.d.ts.map +1 -0
- package/dist/session/AriaFlowLivekitSession.js +85 -0
- package/dist/session/AriaFlowLivekitSession.js.map +1 -0
- package/dist/session/AriaFlowVoiceSession.d.ts +71 -0
- package/dist/session/AriaFlowVoiceSession.d.ts.map +1 -0
- package/dist/session/AriaFlowVoiceSession.js +105 -0
- package/dist/session/AriaFlowVoiceSession.js.map +1 -0
- package/dist/session/createAriaFlowSession.d.ts +21 -0
- package/dist/session/createAriaFlowSession.d.ts.map +1 -0
- package/dist/session/createAriaFlowSession.js +8 -0
- package/dist/session/createAriaFlowSession.js.map +1 -0
- package/dist/session/createAriaVoicePipeline.d.ts +29 -0
- package/dist/session/createAriaVoicePipeline.d.ts.map +1 -0
- package/dist/session/createAriaVoicePipeline.js +28 -0
- package/dist/session/createAriaVoicePipeline.js.map +1 -0
- package/dist/session/voice_defaults.d.ts +34 -0
- package/dist/session/voice_defaults.d.ts.map +1 -0
- package/dist/session/voice_defaults.js +42 -0
- package/dist/session/voice_defaults.js.map +1 -0
- package/dist/session_manager.d.ts +42 -0
- package/dist/session_manager.d.ts.map +1 -0
- package/dist/session_manager.js +97 -0
- package/dist/session_manager.js.map +1 -0
- package/dist/transport_adapter.d.ts +19 -0
- package/dist/transport_adapter.d.ts.map +1 -0
- package/dist/transport_adapter.js +10 -0
- package/dist/transport_adapter.js.map +1 -0
- package/dist/turn_detection/eou_detector.d.ts +93 -0
- package/dist/turn_detection/eou_detector.d.ts.map +1 -0
- package/dist/turn_detection/eou_detector.js +190 -0
- package/dist/turn_detection/eou_detector.js.map +1 -0
- package/dist/turn_detection/eou_text_normalizer.d.ts +9 -0
- package/dist/turn_detection/eou_text_normalizer.d.ts.map +1 -0
- package/dist/turn_detection/eou_text_normalizer.js +17 -0
- package/dist/turn_detection/eou_text_normalizer.js.map +1 -0
- package/dist/turn_detection/eou_turn_detector_adapter.d.ts +40 -0
- package/dist/turn_detection/eou_turn_detector_adapter.d.ts.map +1 -0
- package/dist/turn_detection/eou_turn_detector_adapter.js +54 -0
- package/dist/turn_detection/eou_turn_detector_adapter.js.map +1 -0
- package/dist/turn_detection/index.d.ts +7 -0
- package/dist/turn_detection/index.d.ts.map +1 -0
- package/dist/turn_detection/index.js +8 -0
- package/dist/turn_detection/index.js.map +1 -0
- package/dist/turn_detection/llm_turn_marker_prompt.d.ts +13 -0
- package/dist/turn_detection/llm_turn_marker_prompt.d.ts.map +1 -0
- package/dist/turn_detection/llm_turn_marker_prompt.js +39 -0
- package/dist/turn_detection/llm_turn_marker_prompt.js.map +1 -0
- package/dist/turn_detection/llm_turn_markers.d.ts +57 -0
- package/dist/turn_detection/llm_turn_markers.d.ts.map +1 -0
- package/dist/turn_detection/llm_turn_markers.js +79 -0
- package/dist/turn_detection/llm_turn_markers.js.map +1 -0
- package/dist/turn_detection/turn_detector.d.ts +72 -0
- package/dist/turn_detection/turn_detector.d.ts.map +1 -0
- package/dist/turn_detection/turn_detector.js +84 -0
- package/dist/turn_detection/turn_detector.js.map +1 -0
- package/dist/turn_detection/vad_loader.d.ts +13 -0
- package/dist/turn_detection/vad_loader.d.ts.map +1 -0
- package/dist/turn_detection/vad_loader.js +34 -0
- package/dist/turn_detection/vad_loader.js.map +1 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/resample.d.ts +26 -0
- package/dist/utils/resample.d.ts.map +1 -0
- package/dist/utils/resample.js +48 -0
- package/dist/utils/resample.js.map +1 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# @ariaflow/livekit-plugin
|
|
2
|
+
|
|
3
|
+
AriaFlow plugin for [LiveKit Agents](https://docs.livekit.io/agents/) — connects AriaFlow Runtime to LiveKit's voice infrastructure for building production voice agents.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Runtime Adapter** — wraps AriaFlow Runtime as a LiveKit LLM provider (`AriaRuntimeLLMAdapter`)
|
|
8
|
+
- **Voice Sessions** — `AriaFlowVoiceSession` (WebSocket) and `AriaFlowLivekitSession` (LiveKit rooms)
|
|
9
|
+
- **Two-Layer Turn Detection** — Silero VAD + EOU text model + LLM turn markers
|
|
10
|
+
- **Gemini STT/TTS** — Google Gemini Live speech-to-text and text-to-speech
|
|
11
|
+
- **Filler Coordinator** — audio filler management during tool execution
|
|
12
|
+
- **Recording** — session recording with pluggable storage adapters
|
|
13
|
+
- **Codec Utilities** — G.711 (PCMU/PCMA) encode/decode, resampling
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bun add @ariaflow/livekit-plugin
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Peer dependencies:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
bun add @livekit/agents @livekit/rtc-node @ariaflowagents/core
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { WebSocketAgentServer } from '@ariaflow/livekit-plugin-transport-ws';
|
|
31
|
+
import { AriaFlowVoiceSession, TurnDetector } from '@ariaflow/livekit-plugin';
|
|
32
|
+
import { GeminiLiveSTT, GeminiLiveTTS } from '@ariaflow/livekit-plugin/gemini';
|
|
33
|
+
import { Runtime } from '@ariaflowagents/core';
|
|
34
|
+
import { openai } from '@ai-sdk/openai';
|
|
35
|
+
|
|
36
|
+
const runtime = new Runtime({
|
|
37
|
+
agents: [{
|
|
38
|
+
id: 'assistant',
|
|
39
|
+
name: 'Voice Assistant',
|
|
40
|
+
model: openai('gpt-4o-mini'),
|
|
41
|
+
prompt: 'You are a helpful voice assistant.',
|
|
42
|
+
}],
|
|
43
|
+
defaultAgentId: 'assistant',
|
|
44
|
+
defaultModel: openai('gpt-4o-mini'),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Load turn detection models once at startup
|
|
48
|
+
const detector = new TurnDetector();
|
|
49
|
+
await detector.initialize();
|
|
50
|
+
|
|
51
|
+
const server = new WebSocketAgentServer({ port: 8080 });
|
|
52
|
+
|
|
53
|
+
server.onConnection(async (transport) => {
|
|
54
|
+
const voiceSession = new AriaFlowVoiceSession({
|
|
55
|
+
runtime,
|
|
56
|
+
stt: new GeminiLiveSTT(),
|
|
57
|
+
tts: new GeminiLiveTTS(),
|
|
58
|
+
vad: detector.vad ?? undefined,
|
|
59
|
+
turnDetection: detector.eouTurnDetector ?? undefined,
|
|
60
|
+
turnMarkerConfig: detector.turnMarkerConfig,
|
|
61
|
+
greeting: 'Hello! How can I help you?',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
await server.startSession(transport, voiceSession);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
await server.listen();
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Turn Detection
|
|
71
|
+
|
|
72
|
+
The plugin implements a two-layer turn detection system:
|
|
73
|
+
|
|
74
|
+
**Layer 1: VAD + EOU text model**
|
|
75
|
+
- Silero VAD detects speech boundaries (start/end of speech)
|
|
76
|
+
- EOU (End-of-Utterance) ONNX model predicts whether the transcript looks like a complete turn
|
|
77
|
+
- These run at the audio/STT level inside LiveKit's `AgentSession`
|
|
78
|
+
|
|
79
|
+
**Layer 2: LLM turn markers**
|
|
80
|
+
- The LLM is instructed to prefix responses with a Unicode marker indicating turn completeness
|
|
81
|
+
- `✓` — user's turn is complete, respond normally
|
|
82
|
+
- `○` — user will likely continue shortly, suppress response
|
|
83
|
+
- `◐` — user needs more time to think, suppress and wait longer
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
const detector = new TurnDetector({
|
|
87
|
+
// Disable individual layers:
|
|
88
|
+
// disableVAD: true,
|
|
89
|
+
// disableEOU: true,
|
|
90
|
+
|
|
91
|
+
// Custom marker config:
|
|
92
|
+
turnMarkerConfig: {
|
|
93
|
+
enabled: true,
|
|
94
|
+
incompleteShortWaitMs: 5000,
|
|
95
|
+
incompleteLongWaitMs: 10000,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
await detector.initialize();
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Exports
|
|
102
|
+
|
|
103
|
+
| Export Path | Contents |
|
|
104
|
+
|-------------|----------|
|
|
105
|
+
| `@ariaflow/livekit-plugin` | Core: sessions, LLM adapter, turn detection, transport, codecs |
|
|
106
|
+
| `@ariaflow/livekit-plugin/gemini` | Gemini Live STT/TTS |
|
|
107
|
+
| `@ariaflow/livekit-plugin/recording` | Recording manager and storage adapters |
|
|
108
|
+
| `@ariaflow/livekit-plugin/codec/g711` | G.711 PCMU/PCMA encode/decode |
|
|
109
|
+
| `@ariaflow/livekit-plugin/utils/resample` | Audio resampling utilities |
|
|
110
|
+
|
|
111
|
+
## Examples
|
|
112
|
+
|
|
113
|
+
See [`examples/`](./examples/) for runnable examples:
|
|
114
|
+
|
|
115
|
+
- **basic_voice_agent.ts** — minimal agent with a tool
|
|
116
|
+
- **multi_agent_handoff.ts** — router + game agent handoff
|
|
117
|
+
- **restaurant_agent.ts** — 4-agent restaurant system
|
|
118
|
+
- **turn_detection_demo.ts** — turn detection configuration
|
|
119
|
+
- **livekit_room_agent.ts** — LiveKit room (WebRTC) agent
|
|
120
|
+
- **livekit_room_with_tools.ts** — room agent with tools
|
|
121
|
+
|
|
122
|
+
## Changelog
|
|
123
|
+
|
|
124
|
+
### 0.1.0
|
|
125
|
+
|
|
126
|
+
**Turn Detection** (RFC-011, RFC-012)
|
|
127
|
+
- Added two-layer turn detection system (`src/turn_detection/`)
|
|
128
|
+
- `TurnDetector` — orchestrator that loads VAD and EOU models in parallel
|
|
129
|
+
- `loadSileroVAD()` — process-level singleton loader for Silero VAD with concurrent-call deduplication
|
|
130
|
+
- `EOUDetector` — standalone port of LiveKit's EOU ONNX model, no `getJobContext()` dependency
|
|
131
|
+
- `EOUTurnDetectorAdapter` — bridges `EOUDetector` to LiveKit's `_TurnDetector` interface
|
|
132
|
+
- `detectTurnMarker()` / `stripMarker()` — LLM turn marker detection and stripping
|
|
133
|
+
- `TURN_MARKER_SYSTEM_PROMPT` — system prompt fragment for LLM marker compliance
|
|
134
|
+
- Modified `AriaRuntimeLLMAdapter` to intercept turn markers in LLM responses when configured
|
|
135
|
+
- Modified `AriaFlowVoiceSession` to accept `turnMarkerConfig` option
|
|
136
|
+
- Modified `AriaFlowLivekitSession` to accept `turnMarkerConfig` option
|
|
137
|
+
- Added dependencies: `@livekit/agents-plugin-silero`, `onnxruntime-node`, `@huggingface/hub`, `@huggingface/transformers`
|
|
138
|
+
|
|
139
|
+
**Examples**
|
|
140
|
+
- Added `basic_voice_agent.ts` — minimal voice agent with turn detection
|
|
141
|
+
- Added `multi_agent_handoff.ts` — multi-agent routing demo
|
|
142
|
+
- Added `restaurant_agent.ts` — 4-agent restaurant system
|
|
143
|
+
- Added `turn_detection_demo.ts` — turn detection configuration demo
|
|
144
|
+
- Added `livekit_room_with_tools.ts` — room-based agent with tools
|
|
145
|
+
- Updated `livekit_room_agent.ts` — added turn detection, migrated to `ServerOptions`/`defineAgent` API
|
|
146
|
+
|
|
147
|
+
**Initial Release**
|
|
148
|
+
- `AriaRuntimeLLMAdapter` — wraps AriaFlow Runtime as a LiveKit LLM provider
|
|
149
|
+
- `AriaFlowVoiceSession` — WebSocket-based voice session
|
|
150
|
+
- `AriaFlowLivekitSession` — LiveKit room-based voice session
|
|
151
|
+
- `FillerCoordinator` — audio filler management during tool execution
|
|
152
|
+
- Gemini Live STT/TTS integration
|
|
153
|
+
- Recording with pluggable storage adapters (S3)
|
|
154
|
+
- G.711 codec utilities (PCMU/PCMA)
|
|
155
|
+
- Audio resampling utilities
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { voice } from '@livekit/agents';
|
|
2
|
+
import type { AriaRuntimeLLMAdapter } from '../llm/AriaRuntimeLLMAdapter.js';
|
|
3
|
+
export interface AriaFlowAgentOptions {
|
|
4
|
+
greeting?: string | null;
|
|
5
|
+
}
|
|
6
|
+
export declare class AriaFlowAgent extends voice.Agent {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(ariaLlm: AriaRuntimeLLMAdapter, opts?: AriaFlowAgentOptions);
|
|
9
|
+
onEnter(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=AriaFlowAgent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AriaFlowAgent.d.ts","sourceRoot":"","sources":["../../src/agent/AriaFlowAgent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAE7E,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,qBAAa,aAAc,SAAQ,KAAK,CAAC,KAAK;;gBAGhC,OAAO,EAAE,qBAAqB,EAAE,IAAI,GAAE,oBAAyB;IASrE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAW/B"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { voice } from '@livekit/agents';
|
|
2
|
+
export class AriaFlowAgent extends voice.Agent {
|
|
3
|
+
#opts;
|
|
4
|
+
constructor(ariaLlm, opts = {}) {
|
|
5
|
+
super({
|
|
6
|
+
instructions: 'AriaFlow-managed voice agent',
|
|
7
|
+
llm: ariaLlm,
|
|
8
|
+
});
|
|
9
|
+
this.#opts = opts;
|
|
10
|
+
}
|
|
11
|
+
async onEnter() {
|
|
12
|
+
if (this.#opts.greeting === null) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const greeting = this.#opts.greeting ?? "Hello! I'm your AI assistant. How can I help?";
|
|
16
|
+
this.session.say(greeting, {
|
|
17
|
+
allowInterruptions: true,
|
|
18
|
+
addToChatCtx: false,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=AriaFlowAgent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AriaFlowAgent.js","sourceRoot":"","sources":["../../src/agent/AriaFlowAgent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAOxC,MAAM,OAAO,aAAc,SAAQ,KAAK,CAAC,KAAK;IAC5C,KAAK,CAAuB;IAE5B,YAAY,OAA8B,EAAE,OAA6B,EAAE;QACzE,KAAK,CAAC;YACJ,YAAY,EAAE,8BAA8B;YAC5C,GAAG,EAAE,OAAO;SACb,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YACjC,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,+CAA+C,CAAC;QACxF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE;YACzB,kBAAkB,EAAE,IAAI;YACxB,YAAY,EAAE,KAAK;SACpB,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { AudioFrame } from './audio_frame.js';
|
|
2
|
+
/**
|
|
3
|
+
* Accumulates raw PCM bytes and produces AudioFrame objects when enough
|
|
4
|
+
* data has been buffered for a complete frame.
|
|
5
|
+
*
|
|
6
|
+
* This is the primary utility for transport adapters that receive audio
|
|
7
|
+
* as a continuous byte stream (WebSocket binary messages, RTP packets,
|
|
8
|
+
* HTTP chunked transfer, etc.).
|
|
9
|
+
*
|
|
10
|
+
* The default frame size is 100ms of audio (sampleRate / 10 samples).
|
|
11
|
+
*/
|
|
12
|
+
export declare class AudioByteStream {
|
|
13
|
+
private sampleRate;
|
|
14
|
+
private numChannels;
|
|
15
|
+
private bytesPerFrame;
|
|
16
|
+
private buf;
|
|
17
|
+
constructor(sampleRate: number, numChannels: number, samplesPerChannel?: number | null);
|
|
18
|
+
/**
|
|
19
|
+
* Write raw PCM bytes. Returns zero or more complete AudioFrame objects.
|
|
20
|
+
* Incomplete data is buffered internally.
|
|
21
|
+
*/
|
|
22
|
+
write(data: ArrayBuffer): AudioFrame[];
|
|
23
|
+
/**
|
|
24
|
+
* Flush remaining buffered data as a final (potentially short) frame.
|
|
25
|
+
* Returns empty array if remaining buffer is not sample-aligned.
|
|
26
|
+
*/
|
|
27
|
+
flush(): AudioFrame[];
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=audio_byte_stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio_byte_stream.d.ts","sourceRoot":"","sources":["../src/audio_byte_stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;;;;;;;;GASG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,GAAG,CAAY;gBAGrB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,iBAAiB,GAAE,MAAM,GAAG,IAAW;IAazC;;;OAGG;IACH,KAAK,CAAC,IAAI,EAAE,WAAW,GAAG,UAAU,EAAE;IAyBtC;;;OAGG;IACH,KAAK,IAAI,UAAU,EAAE;CAqBtB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { AudioFrame } from './audio_frame.js';
|
|
2
|
+
/**
|
|
3
|
+
* Accumulates raw PCM bytes and produces AudioFrame objects when enough
|
|
4
|
+
* data has been buffered for a complete frame.
|
|
5
|
+
*
|
|
6
|
+
* This is the primary utility for transport adapters that receive audio
|
|
7
|
+
* as a continuous byte stream (WebSocket binary messages, RTP packets,
|
|
8
|
+
* HTTP chunked transfer, etc.).
|
|
9
|
+
*
|
|
10
|
+
* The default frame size is 100ms of audio (sampleRate / 10 samples).
|
|
11
|
+
*/
|
|
12
|
+
export class AudioByteStream {
|
|
13
|
+
sampleRate;
|
|
14
|
+
numChannels;
|
|
15
|
+
bytesPerFrame;
|
|
16
|
+
buf;
|
|
17
|
+
constructor(sampleRate, numChannels, samplesPerChannel = null) {
|
|
18
|
+
this.sampleRate = sampleRate;
|
|
19
|
+
this.numChannels = numChannels;
|
|
20
|
+
if (samplesPerChannel === null) {
|
|
21
|
+
samplesPerChannel = Math.floor(sampleRate / 10);
|
|
22
|
+
}
|
|
23
|
+
this.bytesPerFrame = numChannels * samplesPerChannel * 2;
|
|
24
|
+
this.buf = new Int8Array();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Write raw PCM bytes. Returns zero or more complete AudioFrame objects.
|
|
28
|
+
* Incomplete data is buffered internally.
|
|
29
|
+
*/
|
|
30
|
+
write(data) {
|
|
31
|
+
const incoming = new Int8Array(data);
|
|
32
|
+
const next = new Int8Array(this.buf.length + incoming.length);
|
|
33
|
+
next.set(this.buf, 0);
|
|
34
|
+
next.set(incoming, this.buf.length);
|
|
35
|
+
this.buf = next;
|
|
36
|
+
const frames = [];
|
|
37
|
+
while (this.buf.length >= this.bytesPerFrame) {
|
|
38
|
+
const frameData = this.buf.slice(0, this.bytesPerFrame);
|
|
39
|
+
this.buf = this.buf.slice(this.bytesPerFrame);
|
|
40
|
+
frames.push(new AudioFrame(new Int16Array(frameData.buffer), this.sampleRate, this.numChannels, frameData.length / (2 * this.numChannels)));
|
|
41
|
+
}
|
|
42
|
+
return frames;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Flush remaining buffered data as a final (potentially short) frame.
|
|
46
|
+
* Returns empty array if remaining buffer is not sample-aligned.
|
|
47
|
+
*/
|
|
48
|
+
flush() {
|
|
49
|
+
if (this.buf.length === 0) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
if (this.buf.length % (2 * this.numChannels) !== 0) {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
const frames = [
|
|
56
|
+
new AudioFrame(new Int16Array(this.buf.buffer), this.sampleRate, this.numChannels, this.buf.length / (2 * this.numChannels)),
|
|
57
|
+
];
|
|
58
|
+
this.buf = new Int8Array();
|
|
59
|
+
return frames;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=audio_byte_stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio_byte_stream.js","sourceRoot":"","sources":["../src/audio_byte_stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;;;;;;;;GASG;AACH,MAAM,OAAO,eAAe;IAClB,UAAU,CAAS;IACnB,WAAW,CAAS;IACpB,aAAa,CAAS;IACtB,GAAG,CAAY;IAEvB,YACE,UAAkB,EAClB,WAAmB,EACnB,oBAAmC,IAAI;QAEvC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAE/B,IAAI,iBAAiB,KAAK,IAAI,EAAE,CAAC;YAC/B,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,CAAC,aAAa,GAAG,WAAW,GAAG,iBAAiB,GAAG,CAAC,CAAC;QACzD,IAAI,CAAC,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAiB;QACrB,MAAM,QAAQ,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC9D,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;QAEhB,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;YACxD,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAE9C,MAAM,CAAC,IAAI,CACT,IAAI,UAAU,CACZ,IAAI,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,EAChC,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,WAAW,EAChB,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAC1C,CACF,CAAC;QACJ,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,KAAK;QACH,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YACnD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAG;YACb,IAAI,UAAU,CACZ,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAC/B,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CACzC;SACF,CAAC;QAEF,IAAI,CAAC,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC;QAC3B,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio_frame.d.ts","sourceRoot":"","sources":["../src/audio_frame.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Re-export AudioFrame from @livekit/rtc-node.
|
|
2
|
+
// This single indirection point isolates all downstream packages from the
|
|
3
|
+
// native dependency. When a pure-JS AudioFrame shim is available, only
|
|
4
|
+
// this file needs to change.
|
|
5
|
+
export { AudioFrame } from '@livekit/rtc-node';
|
|
6
|
+
//# sourceMappingURL=audio_frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio_frame.js","sourceRoot":"","sources":["../src/audio_frame.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,0EAA0E;AAC1E,uEAAuE;AACvE,6BAA6B;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface Codec {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly payloadType: number;
|
|
4
|
+
readonly sampleRate: number;
|
|
5
|
+
readonly channels: number;
|
|
6
|
+
decode(input: Uint8Array): Int16Array;
|
|
7
|
+
encode(input: Int16Array): Uint8Array;
|
|
8
|
+
}
|
|
9
|
+
export declare const PCMU: Codec;
|
|
10
|
+
export declare const PCMA: Codec;
|
|
11
|
+
/** Convenience wrappers matching the Twilio transport API surface. */
|
|
12
|
+
export declare function mulawEncodeArray(pcm: Int16Array): Uint8Array;
|
|
13
|
+
export declare function mulawDecodeArray(mulawBytes: Uint8Array): Int16Array;
|
|
14
|
+
//# sourceMappingURL=g711.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"g711.d.ts","sourceRoot":"","sources":["../../src/codec/g711.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAAC;IACtC,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAAC;CACvC;AAED,eAAO,MAAM,IAAI,EAAE,KAWlB,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,KAWlB,CAAC;AAEF,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAE5D;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,CAEnE"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* G.711 mu-law and A-law codec (CCITT/ITU-T compliant).
|
|
3
|
+
*
|
|
4
|
+
* Delegates to the `alawmulaw` npm package which implements the standard
|
|
5
|
+
* CCITT G.711 algorithm with BIAS=0x84 (132). This matches the Sun
|
|
6
|
+
* Microsystems / Columbia University reference implementation exactly
|
|
7
|
+
* across all 65536 Int16 input values.
|
|
8
|
+
*
|
|
9
|
+
* Previous implementation used BIAS=33 (the 14-bit variant mistakenly
|
|
10
|
+
* applied in 16-bit context), producing 16503 encode mismatches and
|
|
11
|
+
* 50x worse roundtrip error vs the CCITT reference. See LIBRARY-RESEARCH.md.
|
|
12
|
+
*/
|
|
13
|
+
// `alawmulaw` publishes a CJS/UMD `main` entry and an ESM `module` entry.
|
|
14
|
+
// Node's ESM resolver ignores `module`, so importing from the package root
|
|
15
|
+
// resolves to the CJS bundle and breaks named imports under `tsx`.
|
|
16
|
+
// Import the ESM submodules directly to keep this codec usable in both Node
|
|
17
|
+
// ESM test runners and the existing Bun workspace.
|
|
18
|
+
import * as mulaw from 'alawmulaw/lib/mulaw.js';
|
|
19
|
+
import * as alaw from 'alawmulaw/lib/alaw.js';
|
|
20
|
+
export const PCMU = {
|
|
21
|
+
name: 'PCMU',
|
|
22
|
+
payloadType: 0,
|
|
23
|
+
sampleRate: 8000,
|
|
24
|
+
channels: 1,
|
|
25
|
+
decode(input) {
|
|
26
|
+
return mulaw.decode(input);
|
|
27
|
+
},
|
|
28
|
+
encode(input) {
|
|
29
|
+
return mulaw.encode(input);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
export const PCMA = {
|
|
33
|
+
name: 'PCMA',
|
|
34
|
+
payloadType: 8,
|
|
35
|
+
sampleRate: 8000,
|
|
36
|
+
channels: 1,
|
|
37
|
+
decode(input) {
|
|
38
|
+
return alaw.decode(input);
|
|
39
|
+
},
|
|
40
|
+
encode(input) {
|
|
41
|
+
return alaw.encode(input);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
/** Convenience wrappers matching the Twilio transport API surface. */
|
|
45
|
+
export function mulawEncodeArray(pcm) {
|
|
46
|
+
return PCMU.encode(pcm);
|
|
47
|
+
}
|
|
48
|
+
export function mulawDecodeArray(mulawBytes) {
|
|
49
|
+
return PCMU.decode(mulawBytes);
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=g711.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"g711.js","sourceRoot":"","sources":["../../src/codec/g711.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,0EAA0E;AAC1E,2EAA2E;AAC3E,mEAAmE;AACnE,4EAA4E;AAC5E,mDAAmD;AACnD,OAAO,KAAK,KAAK,MAAM,wBAAwB,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAW9C,MAAM,CAAC,MAAM,IAAI,GAAU;IACzB,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,CAAC;IACd,UAAU,EAAE,IAAI;IAChB,QAAQ,EAAE,CAAC;IACX,MAAM,CAAC,KAAiB;QACtB,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,CAAC,KAAiB;QACtB,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAU;IACzB,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,CAAC;IACd,UAAU,EAAE,IAAI;IAChB,QAAQ,EAAE,CAAC;IACX,MAAM,CAAC,KAAiB;QACtB,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,CAAC,KAAiB;QACtB,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;CACF,CAAC;AAEF,sEAAsE;AACtE,MAAM,UAAU,gBAAgB,CAAC,GAAe;IAC9C,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,UAAsB;IACrD,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AACjC,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare class TransportError extends Error {
|
|
2
|
+
readonly cause?: Error | undefined;
|
|
3
|
+
constructor(message: string, cause?: Error | undefined);
|
|
4
|
+
}
|
|
5
|
+
export declare class TransportDisconnectedError extends TransportError {
|
|
6
|
+
constructor(message?: string, cause?: Error);
|
|
7
|
+
}
|
|
8
|
+
export declare class TransportProtocolError extends TransportError {
|
|
9
|
+
constructor(message: string, cause?: Error);
|
|
10
|
+
}
|
|
11
|
+
export declare class AudioConfigError extends TransportError {
|
|
12
|
+
constructor(message: string, cause?: Error);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,cAAe,SAAQ,KAAK;aAGrB,KAAK,CAAC,EAAE,KAAK;gBAD7B,OAAO,EAAE,MAAM,EACC,KAAK,CAAC,EAAE,KAAK,YAAA;CAKhC;AAED,qBAAa,0BAA2B,SAAQ,cAAc;gBAChD,OAAO,GAAE,MAAsC,EAAE,KAAK,CAAC,EAAE,KAAK;CAI3E;AAED,qBAAa,sBAAuB,SAAQ,cAAc;gBAC5C,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAI3C;AAED,qBAAa,gBAAiB,SAAQ,cAAc;gBACtC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAI3C"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export class TransportError extends Error {
|
|
2
|
+
cause;
|
|
3
|
+
constructor(message, cause) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.cause = cause;
|
|
6
|
+
this.name = 'TransportError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class TransportDisconnectedError extends TransportError {
|
|
10
|
+
constructor(message = 'Transport connection closed', cause) {
|
|
11
|
+
super(message, cause);
|
|
12
|
+
this.name = 'TransportDisconnectedError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class TransportProtocolError extends TransportError {
|
|
16
|
+
constructor(message, cause) {
|
|
17
|
+
super(message, cause);
|
|
18
|
+
this.name = 'TransportProtocolError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class AudioConfigError extends TransportError {
|
|
22
|
+
constructor(message, cause) {
|
|
23
|
+
super(message, cause);
|
|
24
|
+
this.name = 'AudioConfigError';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,cAAe,SAAQ,KAAK;IAGrB;IAFlB,YACE,OAAe,EACC,KAAa;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,UAAK,GAAL,KAAK,CAAQ;QAG7B,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,0BAA2B,SAAQ,cAAc;IAC5D,YAAY,UAAkB,6BAA6B,EAAE,KAAa;QACxE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;CACF;AAED,MAAM,OAAO,sBAAuB,SAAQ,cAAc;IACxD,YAAY,OAAe,EAAE,KAAa;QACxC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AAED,MAAM,OAAO,gBAAiB,SAAQ,cAAc;IAClD,YAAY,OAAe,EAAE,KAAa;QACxC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { voice } from '@livekit/agents';
|
|
2
|
+
export declare class FillerCoordinator {
|
|
3
|
+
#private;
|
|
4
|
+
speakFiller(session: voice.AgentSession, filler: string): Promise<void>;
|
|
5
|
+
waitForActiveFillers(): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=FillerCoordinator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FillerCoordinator.d.ts","sourceRoot":"","sources":["../../src/filler/FillerCoordinator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAE7C,qBAAa,iBAAiB;;IAGtB,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBvE,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;CAO5C"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export class FillerCoordinator {
|
|
2
|
+
#activeFillers = new Set();
|
|
3
|
+
async speakFiller(session, filler) {
|
|
4
|
+
const text = filler.trim();
|
|
5
|
+
if (!text) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const handle = session.say(text, {
|
|
9
|
+
allowInterruptions: true,
|
|
10
|
+
addToChatCtx: false,
|
|
11
|
+
});
|
|
12
|
+
const playout = handle
|
|
13
|
+
.waitForPlayout()
|
|
14
|
+
.catch(() => {
|
|
15
|
+
// Barge-in interruptions are expected and should not fail the pipeline.
|
|
16
|
+
})
|
|
17
|
+
.finally(() => {
|
|
18
|
+
this.#activeFillers.delete(playout);
|
|
19
|
+
});
|
|
20
|
+
this.#activeFillers.add(playout);
|
|
21
|
+
}
|
|
22
|
+
async waitForActiveFillers() {
|
|
23
|
+
if (this.#activeFillers.size === 0) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
await Promise.allSettled([...this.#activeFillers]);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=FillerCoordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FillerCoordinator.js","sourceRoot":"","sources":["../../src/filler/FillerCoordinator.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,iBAAiB;IAC5B,cAAc,GAAuB,IAAI,GAAG,EAAE,CAAC;IAE/C,KAAK,CAAC,WAAW,CAAC,OAA2B,EAAE,MAAc;QAC3D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE;YAC/B,kBAAkB,EAAE,IAAI;YACxB,YAAY,EAAE,KAAK;SACpB,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,MAAM;aACnB,cAAc,EAAE;aAChB,KAAK,CAAC,GAAG,EAAE;YACV,wEAAwE;QAC1E,CAAC,CAAC;aACD,OAAO,CAAC,GAAG,EAAE;YACZ,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEL,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,oBAAoB;QACxB,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACnC,OAAO;QACT,CAAC;QAED,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IACrD,CAAC;CACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ParsedFillerResponse {
|
|
2
|
+
transcript: string;
|
|
3
|
+
filler: string;
|
|
4
|
+
parsedAsJson: boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface BuildFillerInstructionOptions {
|
|
7
|
+
baseInstruction?: string;
|
|
8
|
+
fillerPrompt?: string;
|
|
9
|
+
fillerMinTranscriptLength: number;
|
|
10
|
+
}
|
|
11
|
+
export declare const DEFAULT_FILLER_PROMPT: string;
|
|
12
|
+
export declare function buildFillerInstruction(opts: BuildFillerInstructionOptions): string;
|
|
13
|
+
export declare function parseFillerResponse(raw: string): ParsedFillerResponse;
|
|
14
|
+
//# sourceMappingURL=filler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filler.d.ts","sourceRoot":"","sources":["../../src/gemini/filler.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,6BAA6B;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED,eAAO,MAAM,qBAAqB,QAStB,CAAC;AAEb,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,6BAA6B,GAAG,MAAM,CAWlF;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CA2BrE"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export const DEFAULT_FILLER_PROMPT = [
|
|
2
|
+
'You are a speech transcription service for a voice assistant.',
|
|
3
|
+
'Return STRICT JSON only in this schema:',
|
|
4
|
+
'{"transcript":"<exact user speech>","filler":"<short natural acknowledgement>"}',
|
|
5
|
+
'Rules for filler:',
|
|
6
|
+
'- Keep it to one short sentence.',
|
|
7
|
+
'- Do not invent facts or outcomes.',
|
|
8
|
+
'- Use empty string for very short replies (yes/no/okay).',
|
|
9
|
+
'- Keep tone conversational and neutral.',
|
|
10
|
+
].join('\n');
|
|
11
|
+
export function buildFillerInstruction(opts) {
|
|
12
|
+
const prefix = opts.baseInstruction?.trim();
|
|
13
|
+
const prompt = (opts.fillerPrompt?.trim() || DEFAULT_FILLER_PROMPT).trim();
|
|
14
|
+
return [
|
|
15
|
+
prefix,
|
|
16
|
+
prompt,
|
|
17
|
+
`Emit empty filler when transcript length is below ${opts.fillerMinTranscriptLength} characters.`,
|
|
18
|
+
]
|
|
19
|
+
.filter(Boolean)
|
|
20
|
+
.join('\n\n');
|
|
21
|
+
}
|
|
22
|
+
export function parseFillerResponse(raw) {
|
|
23
|
+
const text = raw.trim();
|
|
24
|
+
if (!text) {
|
|
25
|
+
return { transcript: '', filler: '', parsedAsJson: false };
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(text);
|
|
29
|
+
const transcript = typeof parsed.transcript === 'string' ? parsed.transcript.trim() : '';
|
|
30
|
+
const filler = typeof parsed.filler === 'string' ? parsed.filler.trim() : '';
|
|
31
|
+
if (!transcript) {
|
|
32
|
+
return { transcript: text, filler: '', parsedAsJson: false };
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
transcript,
|
|
36
|
+
filler,
|
|
37
|
+
parsedAsJson: true,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return {
|
|
42
|
+
transcript: text,
|
|
43
|
+
filler: '',
|
|
44
|
+
parsedAsJson: false,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=filler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filler.js","sourceRoot":"","sources":["../../src/gemini/filler.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,+DAA+D;IAC/D,yCAAyC;IACzC,iFAAiF;IACjF,mBAAmB;IACnB,kCAAkC;IAClC,oCAAoC;IACpC,0DAA0D;IAC1D,yCAAyC;CAC1C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,UAAU,sBAAsB,CAAC,IAAmC;IACxE,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,qBAAqB,CAAC,CAAC,IAAI,EAAE,CAAC;IAE3E,OAAO;QACL,MAAM;QACN,MAAM;QACN,qDAAqD,IAAI,CAAC,yBAAyB,cAAc;KAClG;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACxB,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IAC7D,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA+C,CAAC;QAC9E,MAAM,UAAU,GAAG,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzF,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAE7E,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;QAC/D,CAAC;QAED,OAAO;YACL,UAAU;YACV,MAAM;YACN,YAAY,EAAE,IAAI;SACnB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,UAAU,EAAE,IAAI;YAChB,MAAM,EAAE,EAAE;YACV,YAAY,EAAE,KAAK;SACpB,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { GeminiLiveSTT, GeminiLiveSpeechStream, type GeminiLiveSTTOptions, type GeminiFillerEvent, type GeminiFillerPayload, type GeminiLiveClient, type GeminiLiveSession, } from './stt.js';
|
|
2
|
+
export { GeminiLiveTTS, GeminiLiveSynthesizeStream, GeminiLiveChunkedStream, type GeminiLiveTTSOptions, type GeminiVoice, } from './tts.js';
|
|
3
|
+
export { DEFAULT_FILLER_PROMPT, buildFillerInstruction, parseFillerResponse, type ParsedFillerResponse, type BuildFillerInstructionOptions, } from './filler.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gemini/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,GACvB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,aAAa,EACb,0BAA0B,EAC1B,uBAAuB,EACvB,KAAK,oBAAoB,EACzB,KAAK,WAAW,GACjB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,KAAK,6BAA6B,GACnC,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { GeminiLiveSTT, GeminiLiveSpeechStream, } from './stt.js';
|
|
2
|
+
export { GeminiLiveTTS, GeminiLiveSynthesizeStream, GeminiLiveChunkedStream, } from './tts.js';
|
|
3
|
+
export { DEFAULT_FILLER_PROMPT, buildFillerInstruction, parseFillerResponse, } from './filler.js';
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gemini/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,sBAAsB,GAMvB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,aAAa,EACb,0BAA0B,EAC1B,uBAAuB,GAGxB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,GAGpB,MAAM,aAAa,CAAC"}
|