@keyframelabs/elements 0.0.8 → 0.1.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 +2 -2
- package/dist/PersonaEmbed.d.ts +1 -1
- package/dist/PersonaView.d.ts +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +35 -25
- package/dist/types.d.ts +2 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -125,7 +125,7 @@ Currently, only the ElevenLabs agent emits emotion events.
|
|
|
125
125
|
| `apiBaseUrl` | `string` | `'https://api.keyframelabs.com'` | Base URL for the Keyframe API. |
|
|
126
126
|
| `videoFit` | `'cover' \| 'contain'` | `'cover'` | Video scaling mode (`object-fit`). |
|
|
127
127
|
| `onStateChange` | `(status: EmbedStatus) => void` | — | Fired when connection status changes. |
|
|
128
|
-
| `onAgentStateChange` | `(state: AgentState) => void` | — | Fired when
|
|
128
|
+
| `onAgentStateChange` | `(state: AgentState) => void` | — | Fired when avatar playback state changes. Signaled by the GPU node via RPC, not the voice agent. |
|
|
129
129
|
| `onDisconnect` | `() => void` | — | Fired when the session disconnects. |
|
|
130
130
|
| `onError` | `(err: Error) => void` | — | Fired on fatal errors. |
|
|
131
131
|
|
|
@@ -142,7 +142,7 @@ Currently, only the ElevenLabs agent emits emotion events.
|
|
|
142
142
|
| Property | Type | Description |
|
|
143
143
|
| -------------- | ------------------ | -------------------------------------------------------------------------------------- |
|
|
144
144
|
| `status` | `EmbedStatus` | Current connection status: `'connecting' \| 'connected' \| 'disconnected' \| 'error'`. |
|
|
145
|
-
| `agentState` | `AgentState` |
|
|
145
|
+
| `agentState` | `AgentState` | Avatar playback state: `'listening' \| 'speaking'`. Set by the GPU node, not the voice agent. |
|
|
146
146
|
| `isMuted` | `boolean` | Whether the microphone is currently muted. |
|
|
147
147
|
| `videoElement` | `HTMLVideoElement` | The underlying video element used for rendering. |
|
|
148
148
|
| `audioElement` | `HTMLAudioElement` | The underlying audio element used for playback. |
|
package/dist/PersonaEmbed.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AgentState } from '
|
|
1
|
+
import { AgentState } from '@keyframelabs/sdk';
|
|
2
2
|
import { EmbedStatus, VideoFit, BaseCallbacks } from './types';
|
|
3
3
|
export type { EmbedStatus, VideoFit } from './types';
|
|
4
4
|
export interface PersonaEmbedOptions extends BaseCallbacks {
|
package/dist/PersonaView.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AgentState } from '
|
|
1
|
+
import { AgentState } from '@keyframelabs/sdk';
|
|
2
2
|
import { EmbedStatus, VideoFit, VoiceAgentDetails, SessionDetails, BaseCallbacks } from './types';
|
|
3
3
|
export interface PersonaViewOptions extends BaseCallbacks {
|
|
4
4
|
/** Target container element */
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ export { PersonaView } from './PersonaView';
|
|
|
4
4
|
export type { PersonaViewOptions } from './PersonaView';
|
|
5
5
|
export type { EmbedStatus, VideoFit, VoiceAgentDetails, SessionDetails, BaseCallbacks, } from './types';
|
|
6
6
|
export { createAgent, GeminiLiveAgent, ElevenLabsAgent, CartesiaAgent, BaseAgent, AGENT_REGISTRY, getAgentInfo, } from './agents';
|
|
7
|
-
export type { AgentType,
|
|
7
|
+
export type { AgentType, AgentConfig, AgentEventMap, Agent, AnyAgent, AgentTypeInfo, GeminiLiveConfig, ElevenLabsConfig, CartesiaConfig, } from './agents';
|
|
8
|
+
export type { AgentState } from '@keyframelabs/sdk';
|
|
8
9
|
export { floatTo16BitPCM, resamplePcm, base64ToBytes, bytesToBase64, SAMPLE_RATE, createEventEmitter, } from './agents';
|
|
9
10
|
export { ApiError as KeyframeApiError } from './ApiError';
|
|
10
11
|
export type { ApiErrorPayload as KeyframeApiErrorPayload } from './ApiError';
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { createClient as
|
|
1
|
+
import { createClient as f } from "@keyframelabs/sdk";
|
|
2
2
|
const l = 24e3;
|
|
3
|
-
function
|
|
3
|
+
function g(i) {
|
|
4
4
|
const e = atob(i), t = new Uint8Array(e.length);
|
|
5
5
|
for (let s = 0; s < e.length; s++)
|
|
6
6
|
t[s] = e.charCodeAt(s);
|
|
7
7
|
return t;
|
|
8
8
|
}
|
|
9
|
-
function
|
|
9
|
+
function m(i) {
|
|
10
10
|
let e = "";
|
|
11
11
|
for (let t = 0; t < i.length; t++)
|
|
12
12
|
e += String.fromCharCode(i[t]);
|
|
@@ -41,7 +41,7 @@ function E() {
|
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
-
function
|
|
44
|
+
function w(i) {
|
|
45
45
|
const e = new Int16Array(i.length);
|
|
46
46
|
for (let t = 0; t < i.length; t++) {
|
|
47
47
|
const s = Math.max(-1, Math.min(1, i[t]));
|
|
@@ -113,7 +113,7 @@ class u {
|
|
|
113
113
|
this.events.emit("closed", { code: e, reason: t });
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
const
|
|
116
|
+
const A = "gemini-2.5-flash-native-audio-preview-12-2025", C = "wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent", k = "wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContentConstrained";
|
|
117
117
|
class R extends u {
|
|
118
118
|
agentName = "GeminiLive";
|
|
119
119
|
async connect(e) {
|
|
@@ -122,7 +122,7 @@ class R extends u {
|
|
|
122
122
|
if (!e.apiKey)
|
|
123
123
|
throw new Error("Gemini API key is required");
|
|
124
124
|
e.inputSampleRate && (this.inputSampleRate = e.inputSampleRate);
|
|
125
|
-
const t = e.model ??
|
|
125
|
+
const t = e.model ?? A, n = (e.authType ?? "api_key") === "ephemeral_token" ? `${k}?access_token=${encodeURIComponent(e.apiKey)}` : `${C}?key=${encodeURIComponent(e.apiKey)}`;
|
|
126
126
|
return new Promise((a, r) => {
|
|
127
127
|
this.ws = new WebSocket(n), this.ws.onopen = () => {
|
|
128
128
|
const o = {
|
|
@@ -159,7 +159,7 @@ class R extends u {
|
|
|
159
159
|
this._state !== "speaking" && (this.events.emit("turnStart", void 0), this.setState("speaking"));
|
|
160
160
|
for (const n of s.modelTurn.parts) {
|
|
161
161
|
if (n.inlineData?.data) {
|
|
162
|
-
const a =
|
|
162
|
+
const a = g(n.inlineData.data);
|
|
163
163
|
this.events.emit("audio", a);
|
|
164
164
|
}
|
|
165
165
|
n.text && this.events.emit("transcript", {
|
|
@@ -181,7 +181,7 @@ class R extends u {
|
|
|
181
181
|
mediaChunks: [
|
|
182
182
|
{
|
|
183
183
|
mimeType: `audio/pcm;rate=${this.inputSampleRate}`,
|
|
184
|
-
data:
|
|
184
|
+
data: m(e)
|
|
185
185
|
}
|
|
186
186
|
]
|
|
187
187
|
}
|
|
@@ -282,7 +282,7 @@ class S extends u {
|
|
|
282
282
|
M.includes(o) && (this.events.emit("emotion", o), this.emotionEmittedForEventId = s);
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
|
-
let n =
|
|
285
|
+
let n = g(t.audio_base_64);
|
|
286
286
|
this.outputSampleRate !== l && (n = c(n, this.outputSampleRate, l)), this.events.emit("audio", n);
|
|
287
287
|
}
|
|
288
288
|
handleUserTranscript(e) {
|
|
@@ -295,11 +295,11 @@ class S extends u {
|
|
|
295
295
|
}
|
|
296
296
|
handleAgentResponse(e) {
|
|
297
297
|
const t = e.agent_response_event;
|
|
298
|
-
t?.agent_response && this.events.emit("transcript", {
|
|
298
|
+
t?.agent_response && (this.events.emit("turnEnd", void 0), this.setState("listening"), this.events.emit("transcript", {
|
|
299
299
|
role: "assistant",
|
|
300
300
|
text: t.agent_response,
|
|
301
301
|
isFinal: !0
|
|
302
|
-
});
|
|
302
|
+
}));
|
|
303
303
|
}
|
|
304
304
|
handleInterruption(e) {
|
|
305
305
|
const t = e.interruption_event;
|
|
@@ -310,7 +310,7 @@ class S extends u {
|
|
|
310
310
|
return;
|
|
311
311
|
let t = e;
|
|
312
312
|
this.sourceInputSampleRate !== this.expectedInputSampleRate && (t = c(e, this.sourceInputSampleRate, this.expectedInputSampleRate)), this.ws.send(JSON.stringify({
|
|
313
|
-
user_audio_chunk:
|
|
313
|
+
user_audio_chunk: m(t)
|
|
314
314
|
}));
|
|
315
315
|
}
|
|
316
316
|
/**
|
|
@@ -425,7 +425,7 @@ class O extends u {
|
|
|
425
425
|
handleMediaOutput(e) {
|
|
426
426
|
if (!e.media?.payload) return;
|
|
427
427
|
this._state !== "speaking" && (this.events.emit("turnStart", void 0), this.setState("speaking"));
|
|
428
|
-
let t =
|
|
428
|
+
let t = g(e.media.payload);
|
|
429
429
|
this.cartesiaOutputRate !== l && (t = c(t, this.cartesiaOutputRate, l)), this.events.emit("audio", t);
|
|
430
430
|
}
|
|
431
431
|
handleClear() {
|
|
@@ -440,7 +440,7 @@ class O extends u {
|
|
|
440
440
|
event: "media_input",
|
|
441
441
|
stream_id: this.streamId,
|
|
442
442
|
media: {
|
|
443
|
-
payload:
|
|
443
|
+
payload: m(t)
|
|
444
444
|
}
|
|
445
445
|
}));
|
|
446
446
|
}
|
|
@@ -574,7 +574,7 @@ class K {
|
|
|
574
574
|
stream = null;
|
|
575
575
|
abortController = null;
|
|
576
576
|
_status = "disconnected";
|
|
577
|
-
_agentState = "
|
|
577
|
+
_agentState = "listening";
|
|
578
578
|
_isMuted = !1;
|
|
579
579
|
mounted = !0;
|
|
580
580
|
constructor(e) {
|
|
@@ -666,7 +666,7 @@ class K {
|
|
|
666
666
|
return t.json();
|
|
667
667
|
}
|
|
668
668
|
async initSession(e) {
|
|
669
|
-
this.session =
|
|
669
|
+
this.session = f({
|
|
670
670
|
serverUrl: e.session_details.server_url,
|
|
671
671
|
participantToken: e.session_details.participant_token,
|
|
672
672
|
agentIdentity: e.session_details.agent_identity,
|
|
@@ -680,13 +680,18 @@ class K {
|
|
|
680
680
|
onStateChange: (t) => {
|
|
681
681
|
this.mounted && t === "disconnected" && (this.setStatus("disconnected"), this.callbacks.onDisconnect?.());
|
|
682
682
|
},
|
|
683
|
+
onAgentStateChange: (t) => {
|
|
684
|
+
this.mounted && this.setAgentState(t);
|
|
685
|
+
},
|
|
683
686
|
onError: (t) => {
|
|
684
687
|
this.mounted && this.callbacks.onError?.(t);
|
|
685
688
|
},
|
|
686
689
|
onClose: () => {
|
|
687
690
|
this.mounted && this.callbacks.onDisconnect?.();
|
|
688
691
|
}
|
|
689
|
-
}), this.agent = y(e.voice_agent_details.type), this.agent.on("audio", (t) => this.session?.sendAudio(t)), this.agent.on("
|
|
692
|
+
}), this.agent = y(e.voice_agent_details.type), this.agent.on("audio", (t) => this.session?.sendAudio(t)), this.agent.on("turnEnd", () => this.session?.endAudioTurn()), this.agent.on("interrupted", () => {
|
|
693
|
+
this.session?.endAudioTurn(), this.session?.interrupt();
|
|
694
|
+
}), this.agent.on("closed", () => {
|
|
690
695
|
this.mounted && this.callbacks.onDisconnect?.();
|
|
691
696
|
}), this.agent instanceof S && this.agent.on("emotion", (t) => this.session?.setEmotion(t)), await this.session.connect();
|
|
692
697
|
}
|
|
@@ -697,7 +702,7 @@ class K {
|
|
|
697
702
|
const e = this.audioContext.createMediaStreamSource(this.stream);
|
|
698
703
|
this.processor = this.audioContext.createScriptProcessor(4096, 1, 1), this.processor.onaudioprocess = (t) => {
|
|
699
704
|
if (!this._isMuted) {
|
|
700
|
-
const s =
|
|
705
|
+
const s = w(t.inputBuffer.getChannelData(0));
|
|
701
706
|
this.agent?.sendAudio(s);
|
|
702
707
|
}
|
|
703
708
|
}, e.connect(this.processor), this.processor.connect(this.audioContext.destination);
|
|
@@ -742,7 +747,7 @@ class B {
|
|
|
742
747
|
processor = null;
|
|
743
748
|
stream = null;
|
|
744
749
|
_status = "disconnected";
|
|
745
|
-
_agentState = "
|
|
750
|
+
_agentState = "listening";
|
|
746
751
|
_isMuted = !1;
|
|
747
752
|
mounted = !0;
|
|
748
753
|
constructor(e) {
|
|
@@ -801,7 +806,7 @@ class B {
|
|
|
801
806
|
this._agentState !== e && (this._agentState = e, this.callbacks.onAgentStateChange?.(e));
|
|
802
807
|
}
|
|
803
808
|
async initSession() {
|
|
804
|
-
this.session =
|
|
809
|
+
this.session = f({
|
|
805
810
|
serverUrl: this.sessionDetails.server_url,
|
|
806
811
|
participantToken: this.sessionDetails.participant_token,
|
|
807
812
|
agentIdentity: this.sessionDetails.agent_identity,
|
|
@@ -815,13 +820,18 @@ class B {
|
|
|
815
820
|
onStateChange: (e) => {
|
|
816
821
|
this.mounted && e === "disconnected" && (this.setStatus("disconnected"), this.callbacks.onDisconnect?.());
|
|
817
822
|
},
|
|
823
|
+
onAgentStateChange: (e) => {
|
|
824
|
+
this.mounted && this.setAgentState(e);
|
|
825
|
+
},
|
|
818
826
|
onError: (e) => {
|
|
819
827
|
this.mounted && this.callbacks.onError?.(e);
|
|
820
828
|
},
|
|
821
829
|
onClose: () => {
|
|
822
830
|
this.mounted && this.callbacks.onDisconnect?.();
|
|
823
831
|
}
|
|
824
|
-
}), this.agent = y(this.voiceAgentDetails.type), this.agent.on("audio", (e) => this.session?.sendAudio(e)), this.agent.on("
|
|
832
|
+
}), this.agent = y(this.voiceAgentDetails.type), this.agent.on("audio", (e) => this.session?.sendAudio(e)), this.agent.on("turnEnd", () => this.session?.endAudioTurn()), this.agent.on("interrupted", () => {
|
|
833
|
+
this.session?.endAudioTurn(), this.session?.interrupt();
|
|
834
|
+
}), this.agent.on("closed", () => {
|
|
825
835
|
this.mounted && this.callbacks.onDisconnect?.();
|
|
826
836
|
}), this.agent instanceof S && this.agent.on("emotion", (e) => this.session?.setEmotion(e)), await this.session.connect();
|
|
827
837
|
}
|
|
@@ -832,7 +842,7 @@ class B {
|
|
|
832
842
|
const e = this.audioContext.createMediaStreamSource(this.stream);
|
|
833
843
|
this.processor = this.audioContext.createScriptProcessor(4096, 1, 1), this.processor.onaudioprocess = (t) => {
|
|
834
844
|
if (!this._isMuted) {
|
|
835
|
-
const s =
|
|
845
|
+
const s = w(t.inputBuffer.getChannelData(0));
|
|
836
846
|
this.agent?.sendAudio(s);
|
|
837
847
|
}
|
|
838
848
|
}, e.connect(this.processor), this.processor.connect(this.audioContext.destination);
|
|
@@ -871,11 +881,11 @@ export {
|
|
|
871
881
|
K as PersonaEmbed,
|
|
872
882
|
B as PersonaView,
|
|
873
883
|
l as SAMPLE_RATE,
|
|
874
|
-
|
|
875
|
-
|
|
884
|
+
g as base64ToBytes,
|
|
885
|
+
m as bytesToBase64,
|
|
876
886
|
y as createAgent,
|
|
877
887
|
E as createEventEmitter,
|
|
878
|
-
|
|
888
|
+
w as floatTo16BitPCM,
|
|
879
889
|
F as getAgentInfo,
|
|
880
890
|
c as resamplePcm
|
|
881
891
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { AgentType
|
|
1
|
+
import { AgentType } from './agents';
|
|
2
|
+
import { AgentState } from '@keyframelabs/sdk';
|
|
2
3
|
export type EmbedStatus = 'connecting' | 'connected' | 'error' | 'disconnected';
|
|
3
4
|
export type VideoFit = 'cover' | 'contain';
|
|
4
5
|
export type VoiceAgentDetails = {
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.0
|
|
7
|
+
"version": "0.1.0",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "./dist/index.js",
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
],
|
|
20
20
|
"sideEffects": false,
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@keyframelabs/sdk": "0.1.
|
|
22
|
+
"@keyframelabs/sdk": "0.1.8"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^25.0.9",
|