UNPKG

voicebot-react-native-expo

Version:

This is a voicebot-react-native package of Kipps AI voice bot for React Native Expo

564 lines (563 loc) 22.4 kB
import * as e from "react"; import { C as K, S as re, c as oe, a as ue, M as B, w as le, b as de, T as R, m as G, d as me, e as fe, D as J, f as he, g as H, L as Q, G as pe, P as z, F as ge, h as ve, i as Ee, R as Se, j as ke, k as be, l as Ce, B as we } from "./components-Y1IPllFz.mjs"; import { w as Ie, x as ye, y as x, z as Me, A as X, t as Y, B as Ne, C as Pe } from "./hooks-C6T19zG6.mjs"; import { j as Z, an as Te, ao as De, l as P, ap as Le, a as Ae, aq as Re, ar as Ve, a1 as q, as as Oe, at as $e } from "./contexts-BggYqn0S.mjs"; import { Mutex as Ue, createLocalTracks as _e, Track as y, facingModeFromLocalTrack as Fe, createLocalVideoTrack as Be, VideoPresets as qe, createLocalAudioTrack as xe, RoomEvent as We } from "livekit-client"; import { m as je } from "./room-BeQGUa5w.mjs"; function ee({ messageFormatter: a, messageDecoder: l, messageEncoder: i, channelTopic: c, ...E }) { const p = e.useRef(null), m = e.useRef(null), u = e.useMemo(() => ({ messageDecoder: l, messageEncoder: i, channelTopic: c }), [l, i, c]), { send: d, chatMessages: g, isSending: t } = Ie(u), r = Z(), o = e.useRef(0); async function S(n) { n.preventDefault(), p.current && p.current.value.trim() !== "" && d && (await d(p.current.value), p.current.value = "", p.current.focus()); } return e.useEffect(() => { var n; m && ((n = m.current) == null || n.scrollTo({ top: m.current.scrollHeight })); }, [m, g]), e.useEffect(() => { var s, v, f, b, w; if (!r || g.length === 0) return; if ((s = r.widget.state) != null && s.showChat && g.length > 0 && o.current !== ((v = g[g.length - 1]) == null ? void 0 : v.timestamp)) { o.current = (f = g[g.length - 1]) == null ? void 0 : f.timestamp; return; } const n = g.filter( (L) => !o.current || L.timestamp > o.current ).length, { widget: h } = r; n > 0 && ((b = h.state) == null ? void 0 : b.unreadMessages) !== n && ((w = h.dispatch) == null || w.call(h, { msg: "unread_msg", count: n })); }, [g, r == null ? void 0 : r.widget]), /* @__PURE__ */ e.createElement("div", { ...E, className: "lk-chat" }, /* @__PURE__ */ e.createElement("div", { className: "lk-chat-header" }, "Messages", /* @__PURE__ */ e.createElement(K, { className: "lk-close-button" }, /* @__PURE__ */ e.createElement(re, null))), /* @__PURE__ */ e.createElement("ul", { className: "lk-list lk-chat-messages", ref: m }, E.children ? g.map( (n, h) => oe(E.children, { entry: n, key: n.id ?? h, messageFormatter: a }) ) : g.map((n, h, s) => { const v = h >= 1 && s[h - 1].from === n.from, f = h >= 1 && n.timestamp - s[h - 1].timestamp < 6e4; return /* @__PURE__ */ e.createElement( ue, { key: n.id ?? h, hideName: v, hideTimestamp: v === !1 ? !1 : f, entry: n, messageFormatter: a } ); })), /* @__PURE__ */ e.createElement("form", { className: "lk-chat-form", onSubmit: S }, /* @__PURE__ */ e.createElement( "input", { className: "lk-form-control lk-chat-form-input", disabled: t, ref: p, type: "text", placeholder: "Enter a message...", onInput: (n) => n.stopPropagation(), onKeyDown: (n) => n.stopPropagation(), onKeyUp: (n) => n.stopPropagation() } ), /* @__PURE__ */ e.createElement("button", { type: "submit", className: "lk-button lk-chat-form-button", disabled: t }, "Send"))); } function O({ kind: a, initialSelection: l, onActiveDeviceChange: i, tracks: c, requestPermissions: E = !1, ...p }) { const [m, u] = e.useState(!1), [d, g] = e.useState([]), [t, r] = e.useState(!0), [o, S] = e.useState(E), n = (f, b) => { P.debug("handle device change"), u(!1), i == null || i(f, b); }, h = e.useRef(null), s = e.useRef(null); e.useLayoutEffect(() => { m && S(!0); }, [m]), e.useLayoutEffect(() => { h.current && s.current && (d || t) && Te(h.current, s.current).then(({ x: f, y: b }) => { s.current && Object.assign(s.current.style, { left: `${f}px`, top: `${b}px` }); }), r(!1); }, [h, s, d, t]); const v = e.useCallback( (f) => { s.current && f.target !== h.current && m && De(s.current, f) && u(!1); }, [m, s, h] ); return e.useEffect(() => (document.addEventListener("click", v), window.addEventListener("resize", () => r(!0)), () => { document.removeEventListener("click", v), window.removeEventListener("resize", () => r(!0)); }), [v, r]), /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement( "button", { className: "lk-button lk-button-menu", "aria-pressed": m, ...p, onClick: () => u(!m), ref: h }, p.children ), !p.disabled && /* @__PURE__ */ e.createElement( "div", { className: "lk-device-menu", ref: s, style: { visibility: m ? "visible" : "hidden" } }, a ? /* @__PURE__ */ e.createElement( B, { initialSelection: l, onActiveDeviceChange: (f) => n(a, f), onDeviceListChange: g, kind: a, track: c == null ? void 0 : c[a], requestPermissions: o } ) : /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("div", { className: "lk-device-menu-heading" }, "Audio inputs"), /* @__PURE__ */ e.createElement( B, { kind: "audioinput", onActiveDeviceChange: (f) => n("audioinput", f), onDeviceListChange: g, track: c == null ? void 0 : c.audioinput, requestPermissions: o } ), /* @__PURE__ */ e.createElement("div", { className: "lk-device-menu-heading" }, "Video inputs"), /* @__PURE__ */ e.createElement( B, { kind: "videoinput", onActiveDeviceChange: (f) => n("videoinput", f), onDeviceListChange: g, track: c == null ? void 0 : c.videoinput, requestPermissions: o } )) )); } function W() { e.useEffect(() => { le(); }, []); } function ze(a, l) { const [i, c] = e.useState(), E = e.useMemo(() => new Ue(), []); return e.useEffect(() => { let p = !1, m = []; return E.lock().then(async (u) => { try { (a.audio || a.video) && (m = await _e(a), p ? m.forEach((d) => d.stop()) : c(m)); } catch (d) { l && d instanceof Error ? l(d) : P.error(d); } finally { u(); } }), () => { p = !0, m.forEach((u) => { u.stop(); }); }; }, [JSON.stringify(a), l, E]), i; } function Ze(a, l, i) { const [c, E] = e.useState(null), [p, m] = e.useState(!1), u = ye({ kind: i }), [d, g] = e.useState( void 0 ), [t, r] = e.useState(), [o, S] = e.useState(l); e.useEffect(() => { S(l); }, [l]); const n = async (v, f) => { try { const b = f === "videoinput" ? await Be({ deviceId: v, resolution: qe.h720.resolution }) : await xe({ deviceId: v }), w = await b.getDeviceId(); w && v !== w && (s.current = w, S(w)), r(b); } catch (b) { b instanceof Error && E(b); } }, h = async (v, f) => { await v.setDeviceId(f), s.current = f; }, s = e.useRef(o); return e.useEffect(() => { a && !t && !c && !p && (P.debug("creating track", i), m(!0), n(o, i).finally(() => { m(!1); })); }, [a, t, c, p]), e.useEffect(() => { t && (a ? d != null && d.deviceId && s.current !== (d == null ? void 0 : d.deviceId) ? (P.debug(`switching ${i} device from`, s.current, d.deviceId), h(t, d.deviceId)) : (P.debug(`unmuting local ${i} track`), t.unmute()) : (P.debug(`muting ${i} track`), t.mute().then(() => P.debug(t.mediaStreamTrack)))); }, [t, d, a, i]), e.useEffect(() => () => { t && (P.debug(`stopping local ${i} track`), t.stop(), t.mute()); }, []), e.useEffect(() => { g(u == null ? void 0 : u.find((v) => v.deviceId === o)); }, [o, u]), { selectedDevice: d, localTrack: t, deviceError: c }; } function et({ defaults: a = {}, onValidate: l, onSubmit: i, onError: c, debug: E, joinLabel: p = "Join Room", micLabel: m = "Microphone", camLabel: u = "Camera", userLabel: d = "Username", persistUserChoices: g = !0, ...t }) { const [r, o] = e.useState(Le), S = { ...a.audioDeviceId !== void 0 && { audioDeviceId: a.audioDeviceId }, ...a.videoDeviceId !== void 0 && { videoDeviceId: a.videoDeviceId }, ...a.audioEnabled !== void 0 && { audioEnabled: a.audioEnabled }, ...a.videoEnabled !== void 0 && { videoEnabled: a.videoEnabled }, ...a.username !== void 0 && { username: a.username } }, { userChoices: n, saveAudioInputDeviceId: h, saveAudioInputEnabled: s, saveVideoInputDeviceId: v, saveVideoInputEnabled: f, saveUsername: b } = x({ defaults: S, preventSave: !g, preventLoad: !g }), [w, L] = e.useState(n.audioEnabled), [I, D] = e.useState(n.videoEnabled), [T, $] = e.useState( n.audioDeviceId ), [k, N] = e.useState( n.videoDeviceId ), [V, ae] = e.useState(n.username); e.useEffect(() => { s(w); }, [w, s]), e.useEffect(() => { f(I); }, [I, f]), e.useEffect(() => { h(T); }, [T, h]), e.useEffect(() => { v(k); }, [k, v]), e.useEffect(() => { b(V); }, [V, b]); const A = ze( { audio: w ? { deviceId: n.audioDeviceId } : !1, video: I ? { deviceId: n.videoDeviceId } : !1 }, c ), U = e.useRef(null), M = e.useMemo( () => A == null ? void 0 : A.filter((C) => C.kind === y.Kind.Video)[0], [A] ), ne = e.useMemo(() => { if (M) { const { facingMode: C } = Fe(M); return C; } else return "undefined"; }, [M]), j = e.useMemo( () => A == null ? void 0 : A.filter((C) => C.kind === y.Kind.Audio)[0], [A] ); e.useEffect(() => (U.current && M && (M.unmute(), M.attach(U.current)), () => { M == null || M.detach(); }), [M]); const [ce, se] = e.useState(), _ = e.useCallback( (C) => typeof l == "function" ? l(C) : C.username !== "", [l] ); e.useEffect(() => { const C = { username: V, videoEnabled: I, videoDeviceId: k, audioEnabled: w, audioDeviceId: T }; o(C), se(_(C)); }, [V, I, _, w, T, k]); function ie(C) { C.preventDefault(), _(r) ? typeof i == "function" && i(r) : P.warn("Validation failed with: ", r); } return W(), /* @__PURE__ */ e.createElement("div", { className: "lk-prejoin", ...t }, /* @__PURE__ */ e.createElement("div", { className: "lk-video-container" }, M && /* @__PURE__ */ e.createElement("video", { ref: U, width: "1280", height: "720", "data-lk-facing-mode": ne }), (!M || !I) && /* @__PURE__ */ e.createElement("div", { className: "lk-camera-off-note" }, /* @__PURE__ */ e.createElement(de, null))), /* @__PURE__ */ e.createElement("div", { className: "lk-button-group-container" }, /* @__PURE__ */ e.createElement("div", { className: "lk-button-group audio" }, /* @__PURE__ */ e.createElement( R, { initialState: w, source: y.Source.Microphone, onChange: (C) => L(C) }, m ), /* @__PURE__ */ e.createElement("div", { className: "lk-button-group-menu" }, /* @__PURE__ */ e.createElement( O, { initialSelection: T, kind: "audioinput", disabled: !j, tracks: { audioinput: j }, onActiveDeviceChange: (C, F) => $(F) } ))), /* @__PURE__ */ e.createElement("div", { className: "lk-button-group video" }, /* @__PURE__ */ e.createElement( R, { initialState: I, source: y.Source.Camera, onChange: (C) => D(C) }, u ), /* @__PURE__ */ e.createElement("div", { className: "lk-button-group-menu" }, /* @__PURE__ */ e.createElement( O, { initialSelection: k, kind: "videoinput", disabled: !M, tracks: { videoinput: M }, onActiveDeviceChange: (C, F) => N(F) } )))), /* @__PURE__ */ e.createElement("form", { className: "lk-username-container" }, /* @__PURE__ */ e.createElement( "input", { className: "lk-form-control", id: "username", name: "username", type: "text", defaultValue: V, placeholder: d, onChange: (C) => ae(C.target.value), autoComplete: "off" } ), /* @__PURE__ */ e.createElement( "button", { className: "lk-button lk-join-button", type: "submit", onClick: ie, disabled: !ce }, p )), E && /* @__PURE__ */ e.createElement(e.Fragment, null, /* @__PURE__ */ e.createElement("strong", null, "User Choices:"), /* @__PURE__ */ e.createElement("ul", { className: "lk-list", style: { overflow: "hidden", maxWidth: "15rem" } }, /* @__PURE__ */ e.createElement("li", null, "Username: ", `${r.username}`), /* @__PURE__ */ e.createElement("li", null, "Video Enabled: ", `${r.videoEnabled}`), /* @__PURE__ */ e.createElement("li", null, "Audio Enabled: ", `${r.audioEnabled}`), /* @__PURE__ */ e.createElement("li", null, "Video Device: ", `${r.videoDeviceId}`), /* @__PURE__ */ e.createElement("li", null, "Audio Device: ", `${r.audioDeviceId}`)))); } function Ke({ props: a }) { const { dispatch: l, state: i } = Ae().widget, c = "lk-button lk-settings-toggle"; return { mergedProps: e.useMemo(() => je(a, { className: c, onClick: () => { l && l({ msg: "toggle_settings" }); }, "aria-pressed": i != null && i.showSettings ? "true" : "false" }), [a, c, l, i]) }; } const Ge = /* @__PURE__ */ e.forwardRef( function(l, i) { const { mergedProps: c } = Ke({ props: l }); return /* @__PURE__ */ e.createElement("button", { ref: i, ...c }, l.children); } ); function te({ variation: a, controls: l, saveUserChoices: i = !0, onDeviceError: c, ...E }) { var $; const [p, m] = e.useState(!1), u = Z(); e.useEffect(() => { var k, N; ((k = u == null ? void 0 : u.widget.state) == null ? void 0 : k.showChat) !== void 0 && m((N = u == null ? void 0 : u.widget.state) == null ? void 0 : N.showChat); }, [($ = u == null ? void 0 : u.widget.state) == null ? void 0 : $.showChat]); const g = Me(`(max-width: ${p ? 1e3 : 760}px)`) ? "minimal" : "verbose"; a ?? (a = g); const t = { leave: !0, ...l }, r = X(); r ? (t.camera ?? (t.camera = r.canPublish), t.microphone ?? (t.microphone = r.canPublish), t.screenShare ?? (t.screenShare = r.canPublish), t.chat ?? (t.chat = r.canPublishData && (l == null ? void 0 : l.chat))) : (t.camera = !1, t.chat = !1, t.microphone = !1, t.screenShare = !1); const o = e.useMemo( () => a === "minimal" || a === "verbose", [a] ), S = e.useMemo( () => a === "textOnly" || a === "verbose", [a] ), n = Re(), [h, s] = e.useState(!1), v = e.useCallback( (k) => { s(k); }, [s] ), f = G({ className: "lk-control-bar" }, E), { saveAudioInputEnabled: b, saveVideoInputEnabled: w, saveAudioInputDeviceId: L, saveVideoInputDeviceId: I } = x({ preventSave: !i }), D = e.useCallback( (k, N) => N ? b(k) : null, [b] ), T = e.useCallback( (k, N) => N ? w(k) : null, [w] ); return /* @__PURE__ */ e.createElement("div", { ...f }, t.microphone && /* @__PURE__ */ e.createElement("div", { className: "lk-button-group" }, /* @__PURE__ */ e.createElement( R, { source: y.Source.Microphone, showIcon: o, onChange: D, onDeviceError: (k) => c == null ? void 0 : c({ source: y.Source.Microphone, error: k }) }, S && "Microphone" ), /* @__PURE__ */ e.createElement("div", { className: "lk-button-group-menu" }, /* @__PURE__ */ e.createElement( O, { kind: "audioinput", onActiveDeviceChange: (k, N) => L(N ?? "") } ))), t.camera && /* @__PURE__ */ e.createElement("div", { className: "lk-button-group" }, /* @__PURE__ */ e.createElement( R, { source: y.Source.Camera, showIcon: o, onChange: T, onDeviceError: (k) => c == null ? void 0 : c({ source: y.Source.Camera, error: k }) }, S && "Camera" ), /* @__PURE__ */ e.createElement("div", { className: "lk-button-group-menu" }, /* @__PURE__ */ e.createElement( O, { kind: "videoinput", onActiveDeviceChange: (k, N) => I(N ?? "") } ))), t.screenShare && n && /* @__PURE__ */ e.createElement( R, { source: y.Source.ScreenShare, captureOptions: { audio: !0, selfBrowserSurface: "include" }, showIcon: o, onChange: v, onDeviceError: (k) => c == null ? void 0 : c({ source: y.Source.ScreenShare, error: k }) }, S && (h ? "Stop screen share" : "Share screen") ), t.chat && /* @__PURE__ */ e.createElement(K, null, o && /* @__PURE__ */ e.createElement(me, null), S && "Chat"), t.settings && /* @__PURE__ */ e.createElement(Ge, null, o && /* @__PURE__ */ e.createElement(fe, null), S && "Settings"), t.leave && /* @__PURE__ */ e.createElement(J, null, o && /* @__PURE__ */ e.createElement(he, null), S && "Leave"), /* @__PURE__ */ e.createElement(H, null)); } function tt({ chatMessageFormatter: a, chatMessageDecoder: l, chatMessageEncoder: i, SettingsComponent: c, ...E }) { var n, h; const [p, m] = e.useState({ showChat: !1, unreadMessages: 0, showSettings: !1 }), u = e.useRef(null), d = Y( [ { source: y.Source.Camera, withPlaceholder: !0 }, { source: y.Source.ScreenShare, withPlaceholder: !1 } ], { updateOnlyOn: [We.ActiveSpeakersChanged], onlySubscribed: !1 } ), g = (s) => { P.debug("updating widget state", s), m(s); }, t = Ve(), r = d.filter(q).filter((s) => s.publication.source === y.Source.ScreenShare), o = (n = Ne(t)) == null ? void 0 : n[0], S = d.filter((s) => !Oe(s, o)); return e.useEffect(() => { var s, v, f, b, w, L; if (r.some((I) => I.publication.isSubscribed) && u.current === null ? (P.debug("Auto set screen share focus:", { newScreenShareTrack: r[0] }), (v = (s = t.pin).dispatch) == null || v.call(s, { msg: "set_pin", trackReference: r[0] }), u.current = r[0]) : u.current && !r.some( (I) => { var D, T; return I.publication.trackSid === ((T = (D = u.current) == null ? void 0 : D.publication) == null ? void 0 : T.trackSid); } ) && (P.debug("Auto clearing screen share focus."), (b = (f = t.pin).dispatch) == null || b.call(f, { msg: "clear_pin" }), u.current = null), o && !q(o)) { const I = d.find( (D) => D.participant.identity === o.participant.identity && D.source === o.source ); I !== o && q(I) && ((L = (w = t.pin).dispatch) == null || L.call(w, { msg: "set_pin", trackReference: I })); } }, [ r.map((s) => `${s.publication.trackSid}_${s.publication.isSubscribed}`).join(), (h = o == null ? void 0 : o.publication) == null ? void 0 : h.trackSid, d ]), W(), /* @__PURE__ */ e.createElement("div", { className: "lk-video-conference", ...E }, $e() && /* @__PURE__ */ e.createElement( Q, { value: t, onWidgetChange: g }, /* @__PURE__ */ e.createElement("div", { className: "lk-video-conference-inner" }, o ? /* @__PURE__ */ e.createElement("div", { className: "lk-focus-layout-wrapper" }, /* @__PURE__ */ e.createElement(ge, null, /* @__PURE__ */ e.createElement(ve, { tracks: S }, /* @__PURE__ */ e.createElement(z, null)), o && /* @__PURE__ */ e.createElement(Ee, { trackRef: o }))) : /* @__PURE__ */ e.createElement("div", { className: "lk-grid-layout-wrapper" }, /* @__PURE__ */ e.createElement(pe, { tracks: d }, /* @__PURE__ */ e.createElement(z, null))), /* @__PURE__ */ e.createElement(te, { controls: { chat: !0, settings: !!c } })), /* @__PURE__ */ e.createElement( ee, { style: { display: p.showChat ? "grid" : "none" }, messageFormatter: a, messageEncoder: i, messageDecoder: l } ), c && /* @__PURE__ */ e.createElement( "div", { className: "lk-settings-menu-modal", style: { display: p.showSettings ? "block" : "none" } }, /* @__PURE__ */ e.createElement(c, null) ) ), /* @__PURE__ */ e.createElement(Se, null), /* @__PURE__ */ e.createElement(ke, null)); } function at({ ...a }) { const [l, i] = e.useState({ showChat: !1, unreadMessages: 0 }), c = Y([y.Source.Microphone]); return W(), /* @__PURE__ */ e.createElement(Q, { onWidgetChange: i }, /* @__PURE__ */ e.createElement("div", { className: "lk-audio-conference", ...a }, /* @__PURE__ */ e.createElement("div", { className: "lk-audio-conference-stage" }, /* @__PURE__ */ e.createElement(be, { tracks: c }, /* @__PURE__ */ e.createElement(Ce, null))), /* @__PURE__ */ e.createElement( te, { controls: { microphone: !0, screenShare: !1, camera: !1, chat: !0 } } ), l.showChat && /* @__PURE__ */ e.createElement(ee, null))); } function nt({ controls: a, saveUserChoices: l = !0, onDeviceError: i, ...c }) { const E = { leave: !0, microphone: !0, ...a }, p = X(), { microphoneTrack: m, localParticipant: u } = Pe(), d = e.useMemo(() => ({ participant: u, source: y.Source.Microphone, publication: m }), [u, m]); p ? E.microphone ?? (E.microphone = p.canPublish) : E.microphone = !1; const g = G({ className: "lk-agent-control-bar" }, c), { saveAudioInputEnabled: t, saveAudioInputDeviceId: r } = x({ preventSave: !l }), o = e.useCallback( (S, n) => { n && t(S); }, [t] ); return /* @__PURE__ */ e.createElement("div", { ...g }, E.microphone && /* @__PURE__ */ e.createElement("div", { className: "lk-button-group" }, /* @__PURE__ */ e.createElement( R, { source: y.Source.Microphone, showIcon: !0, onChange: o, onDeviceError: (S) => i == null ? void 0 : i({ source: y.Source.Microphone, error: S }) }, /* @__PURE__ */ e.createElement(we, { trackRef: d, barCount: 7, options: { minHeight: 5 } }) ), /* @__PURE__ */ e.createElement("div", { className: "lk-button-group-menu" }, /* @__PURE__ */ e.createElement( O, { kind: "audioinput", onActiveDeviceChange: (S, n) => r(n ?? "") } ))), E.leave && /* @__PURE__ */ e.createElement(J, null, "Disconnect"), /* @__PURE__ */ e.createElement(H, null)); } export { at as AudioConference, ee as Chat, te as ControlBar, O as MediaDeviceMenu, et as PreJoin, tt as VideoConference, nt as VoiceAssistantControlBar, Ze as usePreviewDevice, ze as usePreviewTracks }; //# sourceMappingURL=prefabs.mjs.map