-
Notifications
You must be signed in to change notification settings - Fork 59
Expand file tree
/
Copy pathPipecatClientProvider.tsx
More file actions
129 lines (110 loc) · 3.34 KB
/
PipecatClientProvider.tsx
File metadata and controls
129 lines (110 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/**
* Copyright (c) 2024, Daily.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
import {
PipecatClient,
RTVIEvent,
RTVIEventHandler,
setAboutClient,
} from "@pipecat-ai/client-js";
import { createStore } from "jotai";
import { Provider as JotaiProvider } from "jotai/react";
import React, { createContext, useCallback, useEffect, useRef } from "react";
import {
name as packageName,
version as packageVersion,
} from "../package.json";
import { PipecatClientParticipantManager } from "./PipecatClientParticipantManager";
import { PipecatClientStateProvider } from "./PipecatClientState";
import { RTVIEventContext } from "./RTVIEventContext";
export interface Props {
client: PipecatClient;
jotaiStore?: React.ComponentProps<typeof JotaiProvider>["store"];
}
const defaultStore = createStore();
export const PipecatClientContext = createContext<{ client?: PipecatClient }>(
{}
);
type EventHandlersMap = {
[E in RTVIEvent]?: Set<RTVIEventHandler<E>>;
};
export const PipecatClientProvider: React.FC<
React.PropsWithChildren<Props>
> = ({ children, client, jotaiStore = defaultStore }) => {
useEffect(() => {
setAboutClient({
library: packageName,
library_version: packageVersion,
});
}, []);
const eventHandlersMap = useRef<EventHandlersMap>({});
useEffect(() => {
if (!client) return;
const allEvents = Object.values(RTVIEvent).filter((value) =>
isNaN(Number(value))
) as RTVIEvent[];
const allHandlers: Partial<
Record<
RTVIEvent,
(
...args: Parameters<Exclude<RTVIEventHandler<RTVIEvent>, undefined>>
) => void
>
> = {};
allEvents.forEach((event) => {
type E = typeof event;
type Handler = Exclude<RTVIEventHandler<E>, undefined>; // Remove undefined
type Payload = Parameters<Handler>; // Will always be a tuple
const handler = (...payload: Payload) => {
const handlers = eventHandlersMap.current[event] as
| Set<Handler>
| undefined;
if (!handlers) return;
handlers.forEach((h) => {
(
h as (
...args: Parameters<Exclude<RTVIEventHandler<E>, undefined>>
) => void
)(...payload);
});
};
allHandlers[event] = handler;
client.on(event, handler);
});
return () => {
allEvents.forEach((event) => {
client.off(event, allHandlers[event]);
});
};
}, [client]);
const on = useCallback(
<E extends RTVIEvent>(event: E, handler: RTVIEventHandler<E>) => {
if (!eventHandlersMap.current[event]) {
eventHandlersMap.current[event] = new Set();
}
eventHandlersMap.current[event]!.add(handler);
},
[]
);
const off = useCallback(
<E extends RTVIEvent>(event: E, handler: RTVIEventHandler<E>) => {
eventHandlersMap.current[event]?.delete(handler);
},
[]
);
return (
<JotaiProvider store={jotaiStore}>
<PipecatClientContext.Provider value={{ client }}>
<RTVIEventContext.Provider value={{ on, off }}>
<PipecatClientStateProvider>
{children}
<PipecatClientParticipantManager />
</PipecatClientStateProvider>
</RTVIEventContext.Provider>
</PipecatClientContext.Provider>
</JotaiProvider>
);
};
PipecatClientProvider.displayName = "PipecatClientProvider";