@solo3li/client-react 1.0.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.d.ts +12 -0
- package/dist/index.js +61 -0
- package/dist/useAiAgent.d.ts +13 -0
- package/dist/useAiAgent.js +41 -0
- package/package.json +21 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface OmniAgentOptions {
|
|
2
|
+
token: string;
|
|
3
|
+
livekitUrl: string;
|
|
4
|
+
onAgentConnected?: () => void;
|
|
5
|
+
onAgentDisconnected?: () => void;
|
|
6
|
+
onAgentSpeaking?: (isSpeaking: boolean) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare const useOmniAgent: (options: OmniAgentOptions) => {
|
|
9
|
+
isConnected: boolean;
|
|
10
|
+
isAgentSpeaking: boolean;
|
|
11
|
+
disconnect: () => void;
|
|
12
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { Room, RoomEvent, Track } from 'livekit-client';
|
|
3
|
+
export const useOmniAgent = (options) => {
|
|
4
|
+
const [room, setRoom] = useState(null);
|
|
5
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
6
|
+
const [isAgentSpeaking, setIsAgentSpeaking] = useState(false);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (!options.token || !options.livekitUrl)
|
|
9
|
+
return;
|
|
10
|
+
const newRoom = new Room({
|
|
11
|
+
adaptiveStream: true,
|
|
12
|
+
dynacast: true,
|
|
13
|
+
});
|
|
14
|
+
newRoom.on(RoomEvent.Connected, () => {
|
|
15
|
+
setIsConnected(true);
|
|
16
|
+
options.onAgentConnected?.();
|
|
17
|
+
});
|
|
18
|
+
newRoom.on(RoomEvent.Disconnected, () => {
|
|
19
|
+
setIsConnected(false);
|
|
20
|
+
options.onAgentDisconnected?.();
|
|
21
|
+
});
|
|
22
|
+
newRoom.on(RoomEvent.ActiveSpeakersChanged, (speakers) => {
|
|
23
|
+
const agentSpeaking = speakers.some(s => s.identity === 'ai-agent');
|
|
24
|
+
setIsAgentSpeaking(agentSpeaking);
|
|
25
|
+
options.onAgentSpeaking?.(agentSpeaking);
|
|
26
|
+
});
|
|
27
|
+
newRoom.on(RoomEvent.TrackSubscribed, (track, publication, participant) => {
|
|
28
|
+
if (track.kind === Track.Kind.Audio) {
|
|
29
|
+
const element = track.attach();
|
|
30
|
+
document.body.appendChild(element);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const connect = async () => {
|
|
34
|
+
try {
|
|
35
|
+
await newRoom.connect(options.livekitUrl, options.token);
|
|
36
|
+
// Publish microphone
|
|
37
|
+
await newRoom.localParticipant.enableCameraAndMicrophone();
|
|
38
|
+
setRoom(newRoom);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.error('Failed to connect to OmniAgent:', error);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
connect();
|
|
45
|
+
return () => {
|
|
46
|
+
newRoom.disconnect();
|
|
47
|
+
};
|
|
48
|
+
}, [options.token, options.livekitUrl]);
|
|
49
|
+
const disconnect = () => {
|
|
50
|
+
if (room) {
|
|
51
|
+
room.disconnect();
|
|
52
|
+
setRoom(null);
|
|
53
|
+
setIsConnected(false);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
isConnected,
|
|
58
|
+
isAgentSpeaking,
|
|
59
|
+
disconnect
|
|
60
|
+
};
|
|
61
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Room } from 'livekit-client';
|
|
2
|
+
export interface UseAiAgentOptions {
|
|
3
|
+
wsUrl: string;
|
|
4
|
+
token: string;
|
|
5
|
+
autoConnect?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function useAiAgent({ wsUrl, token, autoConnect }: UseAiAgentOptions): {
|
|
8
|
+
isConnected: boolean;
|
|
9
|
+
isAgentSpeaking: boolean;
|
|
10
|
+
connect: () => Promise<void>;
|
|
11
|
+
disconnect: () => void;
|
|
12
|
+
room: Room | null;
|
|
13
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useState, useCallback, useEffect } from 'react';
|
|
2
|
+
import { Room, RoomEvent } from 'livekit-client';
|
|
3
|
+
export function useAiAgent({ wsUrl, token, autoConnect = false }) {
|
|
4
|
+
const [room, setRoom] = useState(null);
|
|
5
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
6
|
+
const [isAgentSpeaking, setIsAgentSpeaking] = useState(false);
|
|
7
|
+
const connect = useCallback(async () => {
|
|
8
|
+
const newRoom = new Room();
|
|
9
|
+
newRoom.on(RoomEvent.Connected, () => setIsConnected(true));
|
|
10
|
+
newRoom.on(RoomEvent.Disconnected, () => setIsConnected(false));
|
|
11
|
+
newRoom.on(RoomEvent.ActiveSpeakersChanged, (speakers) => {
|
|
12
|
+
// Check if AI agent is speaking
|
|
13
|
+
setIsAgentSpeaking(speakers.some(s => !s.isLocal));
|
|
14
|
+
});
|
|
15
|
+
await newRoom.connect(wsUrl, token);
|
|
16
|
+
// Automatically publish microphone
|
|
17
|
+
await newRoom.localParticipant.setMicrophoneEnabled(true);
|
|
18
|
+
setRoom(newRoom);
|
|
19
|
+
}, [wsUrl, token]);
|
|
20
|
+
const disconnect = useCallback(() => {
|
|
21
|
+
if (room) {
|
|
22
|
+
room.disconnect();
|
|
23
|
+
setRoom(null);
|
|
24
|
+
}
|
|
25
|
+
}, [room]);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (autoConnect) {
|
|
28
|
+
connect();
|
|
29
|
+
}
|
|
30
|
+
return () => {
|
|
31
|
+
disconnect();
|
|
32
|
+
};
|
|
33
|
+
}, [autoConnect, connect, disconnect]);
|
|
34
|
+
return {
|
|
35
|
+
isConnected,
|
|
36
|
+
isAgentSpeaking,
|
|
37
|
+
connect,
|
|
38
|
+
disconnect,
|
|
39
|
+
room
|
|
40
|
+
};
|
|
41
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@solo3li/client-react",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "React hooks and components for Voice AI CPaaS",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc"
|
|
12
|
+
},
|
|
13
|
+
"peerDependencies": {
|
|
14
|
+
"react": "^18.0.0",
|
|
15
|
+
"livekit-client": "^2.1.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "^5.0.0",
|
|
19
|
+
"@types/react": "^18.0.0"
|
|
20
|
+
}
|
|
21
|
+
}
|