@shogo-ai/voice 1.10.0 → 2.4.1
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 +89 -0
- package/dist/{chunk-S3S2RNO6.js → chunk-BI6SL35K.js} +1 -184
- package/dist/chunk-CLF25CZC.js +987 -0
- package/dist/chunk-KMSL5PWK.js +540 -0
- package/dist/chunk-ME3SIZZU.js +581 -0
- package/dist/chunk-TQOBJMEK.js +17 -0
- package/dist/{chunk-T3T4EBWY.js → chunk-UH75UVM2.js} +6 -2
- package/dist/chunk-UW7VQ3S6.js +148 -0
- package/dist/chunk-XE4LLC7Z.js +1067 -0
- package/dist/chunk-ZAW6F3YT.js +172 -0
- package/dist/index.cjs +735 -25
- package/dist/index.d.cts +373 -3
- package/dist/index.d.ts +373 -3
- package/dist/index.js +59 -3
- package/dist/live/client.cjs +173 -0
- package/dist/live/client.d.cts +132 -0
- package/dist/live/client.d.ts +132 -0
- package/dist/live/client.js +9 -0
- package/dist/native/index.d.cts +5 -2
- package/dist/native/index.d.ts +5 -2
- package/dist/native/index.js +15 -11
- package/dist/{organicParticlesShaders-DIva0vBO.d.ts → organicParticlesShaders-seZq7jYX.d.cts} +1 -421
- package/dist/{organicParticlesShaders-DIva0vBO.d.cts → organicParticlesShaders-seZq7jYX.d.ts} +1 -421
- package/dist/particlesConfig-0YbdPOdY.d.cts +223 -0
- package/dist/particlesConfig-0YbdPOdY.d.ts +223 -0
- package/dist/react/conversation.cjs +789 -0
- package/dist/react/conversation.d.cts +134 -0
- package/dist/react/conversation.d.ts +134 -0
- package/dist/react/conversation.js +13 -0
- package/dist/react/index.cjs +374 -36
- package/dist/react/index.d.cts +10 -141
- package/dist/react/index.d.ts +10 -141
- package/dist/react/index.js +23 -770
- package/dist/react/visuals.cjs +1048 -0
- package/dist/react/visuals.d.cts +70 -0
- package/dist/react/visuals.d.ts +70 -0
- package/dist/react/visuals.js +10 -0
- package/dist/route/agent.cjs +1038 -85
- package/dist/route/agent.js +3 -3
- package/dist/route/audio-tags.cjs +1038 -85
- package/dist/route/audio-tags.js +3 -3
- package/dist/route/index.cjs +1042 -85
- package/dist/route/index.d.cts +19 -3
- package/dist/route/index.d.ts +19 -3
- package/dist/route/index.js +3 -3
- package/dist/route/music.cjs +1038 -85
- package/dist/route/music.js +3 -3
- package/dist/route/op.cjs +2118 -0
- package/dist/route/op.d.cts +43 -0
- package/dist/route/op.d.ts +43 -0
- package/dist/route/op.js +27 -0
- package/dist/route/signed-url.cjs +1038 -85
- package/dist/route/signed-url.js +3 -3
- package/dist/route/tts-preview.cjs +1038 -85
- package/dist/route/tts-preview.d.cts +6 -4
- package/dist/route/tts-preview.d.ts +6 -4
- package/dist/route/tts-preview.js +3 -3
- package/dist/server.cjs +1038 -85
- package/dist/server.d.cts +40 -8
- package/dist/server.d.ts +40 -8
- package/dist/server.js +2 -2
- package/dist/types-Bfhu-aQH.d.cts +199 -0
- package/dist/types-Bfhu-aQH.d.ts +199 -0
- package/dist/{types-W9y6eMj3.d.ts → types-CadjTXNH.d.cts} +193 -12
- package/dist/{types-W9y6eMj3.d.cts → types-CadjTXNH.d.ts} +193 -12
- package/package.json +21 -1
- package/dist/chunk-B4JC3DK2.js +0 -529
- package/dist/chunk-O362EJQR.js +0 -524
package/dist/react/index.cjs
CHANGED
|
@@ -43,6 +43,7 @@ __export(react_exports, {
|
|
|
43
43
|
resolveOrganicParticlesConfig: () => resolveOrganicParticlesConfig,
|
|
44
44
|
resolveOrganicSphereConfig: () => resolveOrganicSphereConfig,
|
|
45
45
|
useChatConversation: () => useChatConversation,
|
|
46
|
+
useLiveVoiceConversation: () => useLiveVoiceConversation,
|
|
46
47
|
useShogoChat: () => useShogoChat,
|
|
47
48
|
useShogoVoice: () => useShogoVoice,
|
|
48
49
|
useVoiceConversation: () => useVoiceConversation
|
|
@@ -244,6 +245,25 @@ function withProjectQuery(signedUrlPath, params) {
|
|
|
244
245
|
return `${signedUrlPath}${sep}${tail.join("&")}`;
|
|
245
246
|
}
|
|
246
247
|
|
|
248
|
+
// src/react/mic-access.ts
|
|
249
|
+
var MIC_BLOCKED_MESSAGE = "Microphone access is blocked. Allow it in your system or browser settings (on macOS: System Settings > Privacy & Security > Microphone), then try again.";
|
|
250
|
+
var MIC_NOT_FOUND_MESSAGE = "No microphone was found. Connect one and try again.";
|
|
251
|
+
async function requestMicStream(constraints = { audio: true }) {
|
|
252
|
+
const desktop = globalThis.shogoDesktop;
|
|
253
|
+
if (desktop?.isDesktop && desktop.ensureMicAccess) {
|
|
254
|
+
const access = await desktop.ensureMicAccess().catch(() => "granted");
|
|
255
|
+
if (access !== "granted") throw new Error(MIC_BLOCKED_MESSAGE);
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
return await navigator.mediaDevices.getUserMedia(constraints);
|
|
259
|
+
} catch (err) {
|
|
260
|
+
const name = err?.name;
|
|
261
|
+
if (name === "NotAllowedError" || name === "SecurityError") throw new Error(MIC_BLOCKED_MESSAGE);
|
|
262
|
+
if (name === "NotFoundError" || name === "OverconstrainedError") throw new Error(MIC_NOT_FOUND_MESSAGE);
|
|
263
|
+
throw err;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
247
267
|
// src/react/useVoiceConversation.ts
|
|
248
268
|
function useVoiceConversation(options) {
|
|
249
269
|
const {
|
|
@@ -359,7 +379,8 @@ function useVoiceConversation(options) {
|
|
|
359
379
|
} catch {
|
|
360
380
|
}
|
|
361
381
|
}
|
|
362
|
-
await
|
|
382
|
+
const micStream = await requestMicStream({ audio: true });
|
|
383
|
+
micStream.getTracks().forEach((track) => track.stop());
|
|
363
384
|
const data = await fetchSignedUrl({
|
|
364
385
|
path: resolvedSignedUrlPath,
|
|
365
386
|
fetchCredentials,
|
|
@@ -461,6 +482,322 @@ function useVoiceConversation(options) {
|
|
|
461
482
|
};
|
|
462
483
|
}
|
|
463
484
|
|
|
485
|
+
// src/react/useLiveVoiceConversation.ts
|
|
486
|
+
var import_react3 = require("react");
|
|
487
|
+
function parseEvent(data) {
|
|
488
|
+
try {
|
|
489
|
+
const text = typeof data === "string" ? data : String(data);
|
|
490
|
+
const event = JSON.parse(text);
|
|
491
|
+
return event && typeof event === "object" ? event : null;
|
|
492
|
+
} catch {
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
function waitForIceGathering(pc) {
|
|
497
|
+
if (pc.iceGatheringState === "complete") return Promise.resolve();
|
|
498
|
+
return new Promise((resolve) => {
|
|
499
|
+
const onStateChange = () => {
|
|
500
|
+
if (pc.iceGatheringState === "complete") {
|
|
501
|
+
pc.removeEventListener("icegatheringstatechange", onStateChange);
|
|
502
|
+
resolve();
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
pc.addEventListener("icegatheringstatechange", onStateChange);
|
|
506
|
+
window.setTimeout(() => {
|
|
507
|
+
pc.removeEventListener("icegatheringstatechange", onStateChange);
|
|
508
|
+
resolve();
|
|
509
|
+
}, 2e3);
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
function splitContext(text) {
|
|
513
|
+
const chunks = [];
|
|
514
|
+
for (let offset = 0; offset < text.length; offset += 1800) {
|
|
515
|
+
chunks.push(text.slice(offset, offset + 1800));
|
|
516
|
+
}
|
|
517
|
+
return chunks.length ? chunks : [""];
|
|
518
|
+
}
|
|
519
|
+
var TRANSCRIPT_HISTORY_MAX = 30;
|
|
520
|
+
function useLiveVoiceConversation(options) {
|
|
521
|
+
const { mintSession } = options;
|
|
522
|
+
const [status, setStatus] = (0, import_react3.useState)("disconnected");
|
|
523
|
+
const [isSpeaking, setIsSpeaking] = (0, import_react3.useState)(false);
|
|
524
|
+
const [isListening, setIsListening] = (0, import_react3.useState)(false);
|
|
525
|
+
const [isMuted, setIsMuted] = (0, import_react3.useState)(false);
|
|
526
|
+
const [sessionId, setSessionId] = (0, import_react3.useState)(null);
|
|
527
|
+
const optionsRef = (0, import_react3.useRef)(options);
|
|
528
|
+
optionsRef.current = options;
|
|
529
|
+
const pcRef = (0, import_react3.useRef)(null);
|
|
530
|
+
const dataChannelRef = (0, import_react3.useRef)(null);
|
|
531
|
+
const mediaStreamRef = (0, import_react3.useRef)(null);
|
|
532
|
+
const audioRef = (0, import_react3.useRef)(null);
|
|
533
|
+
const analyserRef = (0, import_react3.useRef)(null);
|
|
534
|
+
const frequencyRef = (0, import_react3.useRef)(null);
|
|
535
|
+
const audioContextRef = (0, import_react3.useRef)(null);
|
|
536
|
+
const speakingFrameRef = (0, import_react3.useRef)(null);
|
|
537
|
+
const inputTranscriptRef = (0, import_react3.useRef)("");
|
|
538
|
+
const outputTranscriptRef = (0, import_react3.useRef)("");
|
|
539
|
+
const historyRef = (0, import_react3.useRef)([]);
|
|
540
|
+
const closingRef = (0, import_react3.useRef)(false);
|
|
541
|
+
const mutedRef = (0, import_react3.useRef)(false);
|
|
542
|
+
const emit = (0, import_react3.useCallback)((source, message) => {
|
|
543
|
+
const text = message.trim();
|
|
544
|
+
if (!text) return;
|
|
545
|
+
const history = historyRef.current;
|
|
546
|
+
history.push({ role: source === "user" ? "user" : "assistant", text });
|
|
547
|
+
if (history.length > TRANSCRIPT_HISTORY_MAX) history.splice(0, history.length - TRANSCRIPT_HISTORY_MAX);
|
|
548
|
+
optionsRef.current.onMessage?.({ source, message: text });
|
|
549
|
+
}, []);
|
|
550
|
+
const flushTranscripts = (0, import_react3.useCallback)(() => {
|
|
551
|
+
const input = inputTranscriptRef.current.trim();
|
|
552
|
+
const output = outputTranscriptRef.current.trim();
|
|
553
|
+
inputTranscriptRef.current = "";
|
|
554
|
+
outputTranscriptRef.current = "";
|
|
555
|
+
if (input) emit("user", input);
|
|
556
|
+
if (output) emit("agent", output);
|
|
557
|
+
}, [emit]);
|
|
558
|
+
const sendEvent = (0, import_react3.useCallback)((event) => {
|
|
559
|
+
const channel = dataChannelRef.current;
|
|
560
|
+
if (channel?.readyState === "open") channel.send(JSON.stringify(event));
|
|
561
|
+
}, []);
|
|
562
|
+
const updateSpeaking = (0, import_react3.useCallback)(() => {
|
|
563
|
+
const analyser = analyserRef.current;
|
|
564
|
+
if (analyser) {
|
|
565
|
+
const data = frequencyRef.current ?? new Uint8Array(analyser.frequencyBinCount);
|
|
566
|
+
frequencyRef.current = data;
|
|
567
|
+
analyser.getByteFrequencyData(data);
|
|
568
|
+
let sum = 0;
|
|
569
|
+
for (const value of data) sum += value;
|
|
570
|
+
setIsSpeaking(data.length > 0 && sum / data.length > 8);
|
|
571
|
+
}
|
|
572
|
+
if (pcRef.current) speakingFrameRef.current = requestAnimationFrame(updateSpeaking);
|
|
573
|
+
}, []);
|
|
574
|
+
const handleEvent = (0, import_react3.useCallback)(async (event) => {
|
|
575
|
+
const nested = event.type === "response.event" && event.event ? event.event : event;
|
|
576
|
+
const type = nested.type ?? "";
|
|
577
|
+
if (type === "session.started" || type === "session.created") {
|
|
578
|
+
setStatus("connected");
|
|
579
|
+
setIsListening(!mutedRef.current);
|
|
580
|
+
const id = typeof nested.session?.id === "string" ? nested.session.id : null;
|
|
581
|
+
if (id) setSessionId(id);
|
|
582
|
+
}
|
|
583
|
+
if (type === "session.closed") {
|
|
584
|
+
flushTranscripts();
|
|
585
|
+
setStatus("disconnected");
|
|
586
|
+
setIsListening(false);
|
|
587
|
+
}
|
|
588
|
+
if (type === "error") {
|
|
589
|
+
optionsRef.current.onError?.(new Error(event.error?.message || "GPT-Live error"));
|
|
590
|
+
}
|
|
591
|
+
if (type === "session.input_transcript.delta" || type === "input_audio_transcription.delta") {
|
|
592
|
+
inputTranscriptRef.current += event.delta ?? "";
|
|
593
|
+
}
|
|
594
|
+
if (type === "session.output_transcript.delta" || type === "response.audio_transcript.delta") {
|
|
595
|
+
outputTranscriptRef.current += event.delta ?? "";
|
|
596
|
+
}
|
|
597
|
+
if (type === "session.input_transcript.done" || type === "input_audio_transcription.completed" || type === "session.output_transcript.done" || type === "response.audio_transcript.done" || type === "response.done" || type === "response.completed") {
|
|
598
|
+
flushTranscripts();
|
|
599
|
+
}
|
|
600
|
+
if (type === "session.delegation.created" && nested.delegation?.target !== "responses" && typeof nested.delegation?.id === "string") {
|
|
601
|
+
const onDelegation = optionsRef.current.onDelegation;
|
|
602
|
+
if (!onDelegation) return;
|
|
603
|
+
const delegationId = nested.delegation.id;
|
|
604
|
+
flushTranscripts();
|
|
605
|
+
let result;
|
|
606
|
+
try {
|
|
607
|
+
result = await onDelegation({ delegationId, transcript: [...historyRef.current] });
|
|
608
|
+
} catch (error) {
|
|
609
|
+
optionsRef.current.onError?.(error);
|
|
610
|
+
result = "That request failed before it could finish. Nothing was confirmed.";
|
|
611
|
+
}
|
|
612
|
+
const text = typeof result === "string" ? result.trim() : "";
|
|
613
|
+
if (!text) return;
|
|
614
|
+
for (const content of splitContext(text)) {
|
|
615
|
+
sendEvent({
|
|
616
|
+
type: "session.commentary.append",
|
|
617
|
+
delegation_id: delegationId,
|
|
618
|
+
content
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
const item = nested.item;
|
|
624
|
+
if (type === "response.output_item.done" && item?.type === "function_call") {
|
|
625
|
+
const tool = optionsRef.current.clientTools?.[item.name ?? ""];
|
|
626
|
+
if (!tool || !item.call_id) return;
|
|
627
|
+
let args = {};
|
|
628
|
+
try {
|
|
629
|
+
const parsed = JSON.parse(item.arguments || "{}");
|
|
630
|
+
if (parsed && typeof parsed === "object") args = parsed;
|
|
631
|
+
} catch {
|
|
632
|
+
}
|
|
633
|
+
let output;
|
|
634
|
+
try {
|
|
635
|
+
output = String(await tool(args));
|
|
636
|
+
} catch (error) {
|
|
637
|
+
output = `Tool failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
638
|
+
}
|
|
639
|
+
sendEvent({
|
|
640
|
+
type: "response.item.create",
|
|
641
|
+
item: {
|
|
642
|
+
type: "function_call_output",
|
|
643
|
+
call_id: item.call_id,
|
|
644
|
+
output
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
sendEvent({ type: "response.create" });
|
|
648
|
+
}
|
|
649
|
+
}, [flushTranscripts, sendEvent]);
|
|
650
|
+
const end = (0, import_react3.useCallback)(() => {
|
|
651
|
+
closingRef.current = true;
|
|
652
|
+
flushTranscripts();
|
|
653
|
+
sendEvent({ type: "session.close" });
|
|
654
|
+
dataChannelRef.current?.close();
|
|
655
|
+
pcRef.current?.close();
|
|
656
|
+
mediaStreamRef.current?.getTracks().forEach((track) => track.stop());
|
|
657
|
+
audioRef.current?.pause();
|
|
658
|
+
if (speakingFrameRef.current !== null) cancelAnimationFrame(speakingFrameRef.current);
|
|
659
|
+
speakingFrameRef.current = null;
|
|
660
|
+
pcRef.current = null;
|
|
661
|
+
dataChannelRef.current = null;
|
|
662
|
+
mediaStreamRef.current = null;
|
|
663
|
+
analyserRef.current = null;
|
|
664
|
+
frequencyRef.current = null;
|
|
665
|
+
audioContextRef.current?.close().catch(() => {
|
|
666
|
+
});
|
|
667
|
+
audioContextRef.current = null;
|
|
668
|
+
setIsSpeaking(false);
|
|
669
|
+
setIsListening(false);
|
|
670
|
+
setSessionId(null);
|
|
671
|
+
setStatus("disconnected");
|
|
672
|
+
}, [flushTranscripts, sendEvent]);
|
|
673
|
+
const startInternal = (0, import_react3.useCallback)(async () => {
|
|
674
|
+
if (status === "connected" || status === "connecting") end();
|
|
675
|
+
closingRef.current = false;
|
|
676
|
+
setStatus("connecting");
|
|
677
|
+
try {
|
|
678
|
+
const stream = await requestMicStream({ audio: true });
|
|
679
|
+
mediaStreamRef.current = stream;
|
|
680
|
+
const pc = new RTCPeerConnection();
|
|
681
|
+
pcRef.current = pc;
|
|
682
|
+
stream.getTracks().forEach((track) => pc.addTrack(track, stream));
|
|
683
|
+
const channel = pc.createDataChannel("oai-events");
|
|
684
|
+
dataChannelRef.current = channel;
|
|
685
|
+
channel.onopen = () => {
|
|
686
|
+
if (!closingRef.current) setIsListening(!mutedRef.current);
|
|
687
|
+
};
|
|
688
|
+
channel.onmessage = (message) => {
|
|
689
|
+
const event = parseEvent(message.data);
|
|
690
|
+
if (event) void handleEvent(event);
|
|
691
|
+
};
|
|
692
|
+
channel.onerror = (event) => optionsRef.current.onError?.(event);
|
|
693
|
+
pc.ontrack = (event) => {
|
|
694
|
+
const remoteStream = event.streams[0];
|
|
695
|
+
if (!remoteStream) return;
|
|
696
|
+
const audio = new Audio();
|
|
697
|
+
audio.autoplay = true;
|
|
698
|
+
audio.srcObject = remoteStream;
|
|
699
|
+
audioRef.current = audio;
|
|
700
|
+
void audio.play().catch(() => {
|
|
701
|
+
});
|
|
702
|
+
try {
|
|
703
|
+
const AudioContextImpl = window.AudioContext || window.webkitAudioContext;
|
|
704
|
+
if (AudioContextImpl) {
|
|
705
|
+
const context = new AudioContextImpl();
|
|
706
|
+
const source = context.createMediaStreamSource(remoteStream);
|
|
707
|
+
const analyser = context.createAnalyser();
|
|
708
|
+
analyser.fftSize = 256;
|
|
709
|
+
source.connect(analyser);
|
|
710
|
+
audioContextRef.current = context;
|
|
711
|
+
analyserRef.current = analyser;
|
|
712
|
+
frequencyRef.current = new Uint8Array(analyser.frequencyBinCount);
|
|
713
|
+
if (speakingFrameRef.current === null) {
|
|
714
|
+
speakingFrameRef.current = requestAnimationFrame(updateSpeaking);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
} catch {
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
pc.onconnectionstatechange = () => {
|
|
721
|
+
if (["failed", "disconnected", "closed"].includes(pc.connectionState) && !closingRef.current) {
|
|
722
|
+
optionsRef.current.onError?.(new Error(`GPT-Live connection ${pc.connectionState}`));
|
|
723
|
+
end();
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
const offer = await pc.createOffer();
|
|
727
|
+
await pc.setLocalDescription(offer);
|
|
728
|
+
await waitForIceGathering(pc);
|
|
729
|
+
const localSdp = pc.localDescription?.sdp;
|
|
730
|
+
if (!localSdp) throw new Error("Failed to create a WebRTC offer");
|
|
731
|
+
const answer = await mintSession(localSdp);
|
|
732
|
+
await pc.setRemoteDescription({ type: "answer", sdp: answer.sdp });
|
|
733
|
+
setSessionId(answer.sessionId);
|
|
734
|
+
setStatus("connected");
|
|
735
|
+
} catch (error) {
|
|
736
|
+
end();
|
|
737
|
+
optionsRef.current.onError?.(error);
|
|
738
|
+
throw error;
|
|
739
|
+
}
|
|
740
|
+
}, [end, handleEvent, mintSession, status, updateSpeaking]);
|
|
741
|
+
const start = (0, import_react3.useCallback)(async () => {
|
|
742
|
+
await startInternal();
|
|
743
|
+
}, [startInternal]);
|
|
744
|
+
const restart = (0, import_react3.useCallback)(async () => {
|
|
745
|
+
end();
|
|
746
|
+
await new Promise((resolve) => window.setTimeout(resolve, 120));
|
|
747
|
+
await startInternal();
|
|
748
|
+
}, [end, startInternal]);
|
|
749
|
+
const setMuted = (0, import_react3.useCallback)((muted) => {
|
|
750
|
+
mutedRef.current = muted;
|
|
751
|
+
mediaStreamRef.current?.getAudioTracks().forEach((track) => {
|
|
752
|
+
track.enabled = !muted;
|
|
753
|
+
});
|
|
754
|
+
sendEvent({ type: muted ? "session.input_audio.mute" : "session.input_audio.unmute" });
|
|
755
|
+
setIsMuted(muted);
|
|
756
|
+
setIsListening(!muted && status === "connected");
|
|
757
|
+
}, [sendEvent, status]);
|
|
758
|
+
const sendContextualUpdate = (0, import_react3.useCallback)((text) => {
|
|
759
|
+
for (const content of splitContext(text)) {
|
|
760
|
+
sendEvent({
|
|
761
|
+
type: "session.thinking.append",
|
|
762
|
+
delegation_id: null,
|
|
763
|
+
content
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
}, [sendEvent]);
|
|
767
|
+
const sendUserMessage = (0, import_react3.useCallback)((text) => {
|
|
768
|
+
sendEvent({
|
|
769
|
+
type: "session.commentary.append",
|
|
770
|
+
delegation_id: null,
|
|
771
|
+
content: text
|
|
772
|
+
});
|
|
773
|
+
}, [sendEvent]);
|
|
774
|
+
const sendUserActivity = (0, import_react3.useCallback)(() => {
|
|
775
|
+
sendEvent({ type: "session.input_audio.commit" });
|
|
776
|
+
}, [sendEvent]);
|
|
777
|
+
const getOutputByteFrequencyData = (0, import_react3.useCallback)(() => {
|
|
778
|
+
return frequencyRef.current;
|
|
779
|
+
}, []);
|
|
780
|
+
const getTranscript = (0, import_react3.useCallback)(() => [...historyRef.current], []);
|
|
781
|
+
(0, import_react3.useEffect)(() => () => end(), [end]);
|
|
782
|
+
return {
|
|
783
|
+
start,
|
|
784
|
+
end,
|
|
785
|
+
restart,
|
|
786
|
+
status,
|
|
787
|
+
isSpeaking,
|
|
788
|
+
isListening,
|
|
789
|
+
isMuted,
|
|
790
|
+
setMuted,
|
|
791
|
+
getOutputByteFrequencyData,
|
|
792
|
+
sendContextualUpdate,
|
|
793
|
+
sendUserMessage,
|
|
794
|
+
sendUserActivity,
|
|
795
|
+
getTranscript,
|
|
796
|
+
conversationId: sessionId,
|
|
797
|
+
convaiConversationId: sessionId
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
|
|
464
801
|
// src/react/useShogoVoice.ts
|
|
465
802
|
function useShogoVoice(opts = {}) {
|
|
466
803
|
return useVoiceConversation({
|
|
@@ -472,8 +809,8 @@ function useShogoVoice(opts = {}) {
|
|
|
472
809
|
}
|
|
473
810
|
|
|
474
811
|
// src/react/useChatConversation.ts
|
|
475
|
-
var
|
|
476
|
-
var
|
|
812
|
+
var import_react4 = require("react");
|
|
813
|
+
var import_react5 = require("@ai-sdk/react");
|
|
477
814
|
var import_ai = require("ai");
|
|
478
815
|
|
|
479
816
|
// src/shared/chatUrl.ts
|
|
@@ -510,16 +847,16 @@ function useChatConversation(options = {}) {
|
|
|
510
847
|
onError,
|
|
511
848
|
dynamicVariables
|
|
512
849
|
} = options;
|
|
513
|
-
const resolvedApi = (0,
|
|
850
|
+
const resolvedApi = (0, import_react4.useMemo)(
|
|
514
851
|
() => appendChatQuery(api, { projectId, conversationId, agentName }),
|
|
515
852
|
[api, projectId, conversationId, agentName]
|
|
516
853
|
);
|
|
517
|
-
const headers = (0,
|
|
854
|
+
const headers = (0, import_react4.useMemo)(() => {
|
|
518
855
|
const h = {};
|
|
519
856
|
if (shogoApiKey) h.authorization = `Bearer ${shogoApiKey}`;
|
|
520
857
|
return h;
|
|
521
858
|
}, [shogoApiKey]);
|
|
522
|
-
const body = (0,
|
|
859
|
+
const body = (0, import_react4.useMemo)(() => {
|
|
523
860
|
const b = {};
|
|
524
861
|
if (projectId) b.projectId = projectId;
|
|
525
862
|
if (agentName) b.agentName = agentName;
|
|
@@ -530,7 +867,7 @@ function useChatConversation(options = {}) {
|
|
|
530
867
|
}
|
|
531
868
|
return b;
|
|
532
869
|
}, [projectId, agentName, conversationId, tools, dynamicVariables]);
|
|
533
|
-
const transport = (0,
|
|
870
|
+
const transport = (0, import_react4.useMemo)(
|
|
534
871
|
() => new import_ai.DefaultChatTransport({
|
|
535
872
|
api: resolvedApi,
|
|
536
873
|
credentials: fetchCredentials,
|
|
@@ -539,11 +876,11 @@ function useChatConversation(options = {}) {
|
|
|
539
876
|
}),
|
|
540
877
|
[resolvedApi, fetchCredentials, headers, body]
|
|
541
878
|
);
|
|
542
|
-
const toolsRef = (0,
|
|
879
|
+
const toolsRef = (0, import_react4.useRef)(clientTools);
|
|
543
880
|
toolsRef.current = clientTools;
|
|
544
|
-
const chatRef = (0,
|
|
881
|
+
const chatRef = (0, import_react4.useRef)(null);
|
|
545
882
|
const resolvedId = id ?? (conversationId ? `shogo-chat:${conversationId}` : DEFAULT_CHAT_ID);
|
|
546
|
-
const chat = (0,
|
|
883
|
+
const chat = (0, import_react5.useChat)({
|
|
547
884
|
id: resolvedId,
|
|
548
885
|
transport,
|
|
549
886
|
messages: initialMessages,
|
|
@@ -583,17 +920,17 @@ function useChatConversation(options = {}) {
|
|
|
583
920
|
}
|
|
584
921
|
});
|
|
585
922
|
chatRef.current = chat;
|
|
586
|
-
const sendMessage = (0,
|
|
923
|
+
const sendMessage = (0, import_react4.useCallback)(
|
|
587
924
|
async (text) => {
|
|
588
925
|
if (!text.trim()) return;
|
|
589
926
|
await chatRef.current?.sendMessage({ text });
|
|
590
927
|
},
|
|
591
928
|
[]
|
|
592
929
|
);
|
|
593
|
-
const setMessages = (0,
|
|
930
|
+
const setMessages = (0, import_react4.useCallback)((messages) => {
|
|
594
931
|
chatRef.current?.setMessages?.(messages);
|
|
595
932
|
}, []);
|
|
596
|
-
const appendAssistantMessage = (0,
|
|
933
|
+
const appendAssistantMessage = (0, import_react4.useCallback)((text) => {
|
|
597
934
|
const next = {
|
|
598
935
|
id: syntheticId("synthetic-assistant"),
|
|
599
936
|
role: "assistant",
|
|
@@ -604,7 +941,7 @@ function useChatConversation(options = {}) {
|
|
|
604
941
|
const nextList = [...current.messages, next];
|
|
605
942
|
current.setMessages?.(nextList);
|
|
606
943
|
}, []);
|
|
607
|
-
const appendUserMessage = (0,
|
|
944
|
+
const appendUserMessage = (0, import_react4.useCallback)((text) => {
|
|
608
945
|
const next = {
|
|
609
946
|
id: syntheticId("synthetic-user"),
|
|
610
947
|
role: "user",
|
|
@@ -637,14 +974,14 @@ function useShogoChat(opts = {}) {
|
|
|
637
974
|
}
|
|
638
975
|
|
|
639
976
|
// src/react/ShogoVoiceProvider.tsx
|
|
640
|
-
var
|
|
977
|
+
var import_react6 = require("@elevenlabs/react");
|
|
641
978
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
642
979
|
function ShogoVoiceProvider(props) {
|
|
643
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
980
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react6.ConversationProvider, { children: props.children });
|
|
644
981
|
}
|
|
645
982
|
|
|
646
983
|
// src/react/OrganicSphere.tsx
|
|
647
|
-
var
|
|
984
|
+
var import_react7 = require("react");
|
|
648
985
|
var THREE = __toESM(require("three"), 1);
|
|
649
986
|
|
|
650
987
|
// src/react/shaders/organicSphereShaders.ts
|
|
@@ -964,8 +1301,8 @@ function OrganicSphere({
|
|
|
964
1301
|
className,
|
|
965
1302
|
style
|
|
966
1303
|
}) {
|
|
967
|
-
const containerRef = (0,
|
|
968
|
-
const resolvedConfig = (0,
|
|
1304
|
+
const containerRef = (0, import_react7.useRef)(null);
|
|
1305
|
+
const resolvedConfig = (0, import_react7.useMemo)(() => {
|
|
969
1306
|
const base = resolveOrganicSphereConfig(configProp);
|
|
970
1307
|
const overrides = {};
|
|
971
1308
|
if (lightAColor !== void 0) overrides.lightAColor = lightAColor;
|
|
@@ -988,22 +1325,22 @@ function OrganicSphere({
|
|
|
988
1325
|
subdivisions,
|
|
989
1326
|
maxPixelRatio
|
|
990
1327
|
]);
|
|
991
|
-
const configRef = (0,
|
|
992
|
-
(0,
|
|
1328
|
+
const configRef = (0, import_react7.useRef)(resolvedConfig);
|
|
1329
|
+
(0, import_react7.useEffect)(() => {
|
|
993
1330
|
configRef.current = resolvedConfig;
|
|
994
1331
|
}, [resolvedConfig]);
|
|
995
|
-
const getFrequencyDataRef = (0,
|
|
996
|
-
const activeRef = (0,
|
|
997
|
-
(0,
|
|
1332
|
+
const getFrequencyDataRef = (0, import_react7.useRef)(getFrequencyData);
|
|
1333
|
+
const activeRef = (0, import_react7.useRef)(active);
|
|
1334
|
+
(0, import_react7.useEffect)(() => {
|
|
998
1335
|
getFrequencyDataRef.current = getFrequencyData;
|
|
999
1336
|
}, [getFrequencyData]);
|
|
1000
|
-
(0,
|
|
1337
|
+
(0, import_react7.useEffect)(() => {
|
|
1001
1338
|
activeRef.current = active;
|
|
1002
1339
|
}, [active]);
|
|
1003
1340
|
const initSubdivisions = resolvedConfig.subdivisions;
|
|
1004
1341
|
const initMaxPixelRatio = resolvedConfig.maxPixelRatio;
|
|
1005
1342
|
const initBackgroundColor = resolvedConfig.backgroundColor;
|
|
1006
|
-
(0,
|
|
1343
|
+
(0, import_react7.useEffect)(() => {
|
|
1007
1344
|
const container = containerRef.current;
|
|
1008
1345
|
if (!container) return;
|
|
1009
1346
|
const cfg0 = configRef.current;
|
|
@@ -1213,7 +1550,7 @@ function OrganicSphere({
|
|
|
1213
1550
|
}
|
|
1214
1551
|
|
|
1215
1552
|
// src/react/OrganicParticles.tsx
|
|
1216
|
-
var
|
|
1553
|
+
var import_react8 = require("react");
|
|
1217
1554
|
var THREE2 = __toESM(require("three"), 1);
|
|
1218
1555
|
|
|
1219
1556
|
// src/react/shaders/organicParticlesShaders.ts
|
|
@@ -1428,21 +1765,21 @@ function OrganicParticles({
|
|
|
1428
1765
|
className,
|
|
1429
1766
|
style
|
|
1430
1767
|
}) {
|
|
1431
|
-
const containerRef = (0,
|
|
1432
|
-
const resolvedConfig = (0,
|
|
1768
|
+
const containerRef = (0, import_react8.useRef)(null);
|
|
1769
|
+
const resolvedConfig = (0, import_react8.useMemo)(
|
|
1433
1770
|
() => resolveOrganicParticlesConfig(configProp),
|
|
1434
1771
|
[configProp]
|
|
1435
1772
|
);
|
|
1436
|
-
const configRef = (0,
|
|
1437
|
-
(0,
|
|
1773
|
+
const configRef = (0, import_react8.useRef)(resolvedConfig);
|
|
1774
|
+
(0, import_react8.useEffect)(() => {
|
|
1438
1775
|
configRef.current = resolvedConfig;
|
|
1439
1776
|
}, [resolvedConfig]);
|
|
1440
|
-
const getFrequencyDataRef = (0,
|
|
1441
|
-
const activeRef = (0,
|
|
1442
|
-
(0,
|
|
1777
|
+
const getFrequencyDataRef = (0, import_react8.useRef)(getFrequencyData);
|
|
1778
|
+
const activeRef = (0, import_react8.useRef)(active);
|
|
1779
|
+
(0, import_react8.useEffect)(() => {
|
|
1443
1780
|
getFrequencyDataRef.current = getFrequencyData;
|
|
1444
1781
|
}, [getFrequencyData]);
|
|
1445
|
-
(0,
|
|
1782
|
+
(0, import_react8.useEffect)(() => {
|
|
1446
1783
|
activeRef.current = active;
|
|
1447
1784
|
}, [active]);
|
|
1448
1785
|
const initCount = resolvedConfig.count;
|
|
@@ -1451,7 +1788,7 @@ function OrganicParticles({
|
|
|
1451
1788
|
const initSeed = resolvedConfig.seed;
|
|
1452
1789
|
const initMaxPixelRatio = resolvedConfig.maxPixelRatio;
|
|
1453
1790
|
const initBackgroundColor = resolvedConfig.backgroundColor;
|
|
1454
|
-
(0,
|
|
1791
|
+
(0, import_react8.useEffect)(() => {
|
|
1455
1792
|
const container = containerRef.current;
|
|
1456
1793
|
if (!container) return;
|
|
1457
1794
|
const cfg0 = configRef.current;
|
|
@@ -1663,6 +2000,7 @@ function OrganicParticles({
|
|
|
1663
2000
|
resolveOrganicParticlesConfig,
|
|
1664
2001
|
resolveOrganicSphereConfig,
|
|
1665
2002
|
useChatConversation,
|
|
2003
|
+
useLiveVoiceConversation,
|
|
1666
2004
|
useShogoChat,
|
|
1667
2005
|
useShogoVoice,
|
|
1668
2006
|
useVoiceConversation
|