@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.
Files changed (68) hide show
  1. package/README.md +89 -0
  2. package/dist/{chunk-S3S2RNO6.js → chunk-BI6SL35K.js} +1 -184
  3. package/dist/chunk-CLF25CZC.js +987 -0
  4. package/dist/chunk-KMSL5PWK.js +540 -0
  5. package/dist/chunk-ME3SIZZU.js +581 -0
  6. package/dist/chunk-TQOBJMEK.js +17 -0
  7. package/dist/{chunk-T3T4EBWY.js → chunk-UH75UVM2.js} +6 -2
  8. package/dist/chunk-UW7VQ3S6.js +148 -0
  9. package/dist/chunk-XE4LLC7Z.js +1067 -0
  10. package/dist/chunk-ZAW6F3YT.js +172 -0
  11. package/dist/index.cjs +735 -25
  12. package/dist/index.d.cts +373 -3
  13. package/dist/index.d.ts +373 -3
  14. package/dist/index.js +59 -3
  15. package/dist/live/client.cjs +173 -0
  16. package/dist/live/client.d.cts +132 -0
  17. package/dist/live/client.d.ts +132 -0
  18. package/dist/live/client.js +9 -0
  19. package/dist/native/index.d.cts +5 -2
  20. package/dist/native/index.d.ts +5 -2
  21. package/dist/native/index.js +15 -11
  22. package/dist/{organicParticlesShaders-DIva0vBO.d.ts → organicParticlesShaders-seZq7jYX.d.cts} +1 -421
  23. package/dist/{organicParticlesShaders-DIva0vBO.d.cts → organicParticlesShaders-seZq7jYX.d.ts} +1 -421
  24. package/dist/particlesConfig-0YbdPOdY.d.cts +223 -0
  25. package/dist/particlesConfig-0YbdPOdY.d.ts +223 -0
  26. package/dist/react/conversation.cjs +789 -0
  27. package/dist/react/conversation.d.cts +134 -0
  28. package/dist/react/conversation.d.ts +134 -0
  29. package/dist/react/conversation.js +13 -0
  30. package/dist/react/index.cjs +374 -36
  31. package/dist/react/index.d.cts +10 -141
  32. package/dist/react/index.d.ts +10 -141
  33. package/dist/react/index.js +23 -770
  34. package/dist/react/visuals.cjs +1048 -0
  35. package/dist/react/visuals.d.cts +70 -0
  36. package/dist/react/visuals.d.ts +70 -0
  37. package/dist/react/visuals.js +10 -0
  38. package/dist/route/agent.cjs +1038 -85
  39. package/dist/route/agent.js +3 -3
  40. package/dist/route/audio-tags.cjs +1038 -85
  41. package/dist/route/audio-tags.js +3 -3
  42. package/dist/route/index.cjs +1042 -85
  43. package/dist/route/index.d.cts +19 -3
  44. package/dist/route/index.d.ts +19 -3
  45. package/dist/route/index.js +3 -3
  46. package/dist/route/music.cjs +1038 -85
  47. package/dist/route/music.js +3 -3
  48. package/dist/route/op.cjs +2118 -0
  49. package/dist/route/op.d.cts +43 -0
  50. package/dist/route/op.d.ts +43 -0
  51. package/dist/route/op.js +27 -0
  52. package/dist/route/signed-url.cjs +1038 -85
  53. package/dist/route/signed-url.js +3 -3
  54. package/dist/route/tts-preview.cjs +1038 -85
  55. package/dist/route/tts-preview.d.cts +6 -4
  56. package/dist/route/tts-preview.d.ts +6 -4
  57. package/dist/route/tts-preview.js +3 -3
  58. package/dist/server.cjs +1038 -85
  59. package/dist/server.d.cts +40 -8
  60. package/dist/server.d.ts +40 -8
  61. package/dist/server.js +2 -2
  62. package/dist/types-Bfhu-aQH.d.cts +199 -0
  63. package/dist/types-Bfhu-aQH.d.ts +199 -0
  64. package/dist/{types-W9y6eMj3.d.ts → types-CadjTXNH.d.cts} +193 -12
  65. package/dist/{types-W9y6eMj3.d.cts → types-CadjTXNH.d.ts} +193 -12
  66. package/package.json +21 -1
  67. package/dist/chunk-B4JC3DK2.js +0 -529
  68. package/dist/chunk-O362EJQR.js +0 -524
@@ -1,3 +1,16 @@
1
+ import {
2
+ appendChatQuery
3
+ } from "../chunk-TQOBJMEK.js";
4
+ import {
5
+ ShogoVoiceProvider,
6
+ useLiveVoiceConversation,
7
+ useVoiceConversation
8
+ } from "../chunk-ME3SIZZU.js";
9
+ import "../chunk-ZAW6F3YT.js";
10
+ import {
11
+ OrganicParticles,
12
+ OrganicSphere
13
+ } from "../chunk-KMSL5PWK.js";
1
14
  import {
2
15
  DEFAULT_ORGANIC_PARTICLES_CONFIG,
3
16
  DEFAULT_ORGANIC_SPHERE_CONFIG,
@@ -6,239 +19,11 @@ import {
6
19
  ORGANIC_SPHERE_FRAGMENT_SHADER,
7
20
  ORGANIC_SPHERE_VERTEX_SHADER,
8
21
  PERLIN_4D,
9
- appendChatQuery,
10
- appendTranscriptLine,
11
- buildSessionPayload,
12
- createMemoryAddTool,
13
- createMemoryContextInjector,
14
- createPostJson,
15
- createTranscriptDisconnectHandler,
16
- fetchSignedUrl,
17
22
  resolveOrganicParticlesConfig,
18
- resolveOrganicSphereConfig,
19
- withProjectQuery
20
- } from "../chunk-S3S2RNO6.js";
23
+ resolveOrganicSphereConfig
24
+ } from "../chunk-BI6SL35K.js";
21
25
  import "../chunk-Q3TJAJ54.js";
22
26
 
23
- // src/react/useVoiceConversation.ts
24
- import { useCallback, useEffect, useRef, useState } from "react";
25
- import { useConversation } from "@elevenlabs/react";
26
- function useVoiceConversation(options) {
27
- const {
28
- characterName,
29
- signedUrlPath = "/api/voice/signed-url",
30
- memoryAddPath = "/api/memory/add",
31
- memoryRetrievePath = "/api/memory/retrieve",
32
- transcriptIngestPath = "/api/memory/ingest",
33
- autoInjectMemory = true,
34
- includeMemoryTool = true,
35
- clientTools = {},
36
- onTranscript,
37
- shogoApiKey,
38
- projectId,
39
- agentName,
40
- fetchCredentials = shogoApiKey ? "omit" : "same-origin",
41
- onError,
42
- onMessage,
43
- conversationId: optionConversationId,
44
- dynamicVariables
45
- } = options;
46
- const authHeaders = useCallback(() => {
47
- return shogoApiKey ? { authorization: `Bearer ${shogoApiKey}` } : {};
48
- }, [shogoApiKey]);
49
- const resolvedSignedUrlPath = withProjectQuery(signedUrlPath, { projectId, agentName });
50
- const transcriptRef = useRef([]);
51
- const lastInjectedRef = useRef("");
52
- const weStartedSessionRef = useRef(false);
53
- const [convaiConversationId, setConvaiConversationId] = useState(null);
54
- const isRestartingRef = useRef(false);
55
- const conversationRef = useRef(null);
56
- const postJson = useCallback(
57
- createPostJson({ authHeaders, fetchCredentials }),
58
- [fetchCredentials, authHeaders]
59
- );
60
- const injectMemoryContext = useCallback(
61
- createMemoryContextInjector({
62
- postJson,
63
- memoryRetrievePath,
64
- conversationRef,
65
- enabled: autoInjectMemory,
66
- lastInjectedRef
67
- }),
68
- [autoInjectMemory, memoryRetrievePath, postJson]
69
- );
70
- const handleTranscriptOnDisconnect = useCallback(
71
- createTranscriptDisconnectHandler({
72
- isRestartingRef,
73
- weStartedSessionRef,
74
- transcriptRef,
75
- onTranscript,
76
- transcriptIngestPath,
77
- postJson
78
- }),
79
- [onTranscript, postJson, transcriptIngestPath]
80
- );
81
- const builtInTools = includeMemoryTool ? { add_memory: createMemoryAddTool({ postJson, memoryAddPath }) } : {};
82
- const mergedClientTools = { ...builtInTools, ...clientTools };
83
- const conversation = useConversation({
84
- clientTools: mergedClientTools,
85
- onConnect: (info) => {
86
- const id = info?.conversationId;
87
- if (typeof id === "string" && id.length > 0) {
88
- setConvaiConversationId(id);
89
- }
90
- if (!isRestartingRef.current) {
91
- transcriptRef.current = [];
92
- lastInjectedRef.current = "";
93
- }
94
- },
95
- onDisconnect: () => {
96
- handleTranscriptOnDisconnect();
97
- if (!isRestartingRef.current) {
98
- setConvaiConversationId(null);
99
- }
100
- },
101
- onError: (e) => {
102
- onError?.(e);
103
- },
104
- onMessage: (m) => {
105
- const msg = m;
106
- if (!msg?.message || !msg?.source) return;
107
- appendTranscriptLine(msg, { transcriptRef, weStartedSessionRef });
108
- onMessage?.({ source: msg.source, message: msg.message });
109
- if (autoInjectMemory && msg.source === "user" && msg.message.trim().length >= 3 && weStartedSessionRef.current) {
110
- void injectMemoryContext(msg.message);
111
- }
112
- }
113
- });
114
- const { status, isSpeaking, isListening, isMuted, setMuted, startSession, endSession } = conversation;
115
- conversationRef.current = conversation;
116
- useEffect(() => {
117
- const onHide = () => {
118
- if (!weStartedSessionRef.current || transcriptRef.current.length === 0) return;
119
- const transcript = transcriptRef.current.join("\n").trim();
120
- transcriptRef.current = [];
121
- if (transcript.length < 20) return;
122
- try {
123
- const blob = new Blob([JSON.stringify({ transcript })], { type: "application/json" });
124
- navigator.sendBeacon(transcriptIngestPath, blob);
125
- } catch {
126
- }
127
- };
128
- window.addEventListener("pagehide", onHide);
129
- return () => window.removeEventListener("pagehide", onHide);
130
- }, [transcriptIngestPath]);
131
- const startInternal = useCallback(
132
- async (opts) => {
133
- if (status === "connected" || status === "connecting") {
134
- try {
135
- endSession();
136
- await new Promise((r) => setTimeout(r, 120));
137
- } catch {
138
- }
139
- }
140
- await navigator.mediaDevices.getUserMedia({ audio: true });
141
- const data = await fetchSignedUrl({
142
- path: resolvedSignedUrlPath,
143
- fetchCredentials,
144
- authHeaders
145
- });
146
- const ctx = data.userContext || "No prior memories yet.";
147
- weStartedSessionRef.current = true;
148
- const sessionPayload = buildSessionPayload({
149
- signedUrl: data.signedUrl,
150
- characterName,
151
- userContext: ctx,
152
- agentPromptOverride: data.agentPromptOverride,
153
- suppressFirstMessage: opts?.suppressFirstMessage,
154
- conversationId: optionConversationId,
155
- dynamicVariables
156
- });
157
- await startSession(sessionPayload);
158
- },
159
- [
160
- status,
161
- endSession,
162
- resolvedSignedUrlPath,
163
- fetchCredentials,
164
- dynamicVariables,
165
- startSession,
166
- characterName,
167
- authHeaders,
168
- optionConversationId
169
- ]
170
- );
171
- const start = useCallback(
172
- async (options2) => {
173
- await startInternal(options2);
174
- },
175
- [startInternal]
176
- );
177
- const end = useCallback(() => {
178
- endSession();
179
- }, [endSession]);
180
- const restart = useCallback(
181
- async (options2) => {
182
- const suppress = options2?.suppressFirstMessage ?? true;
183
- isRestartingRef.current = true;
184
- try {
185
- try {
186
- endSession();
187
- } catch {
188
- }
189
- await new Promise((r) => setTimeout(r, 120));
190
- await startInternal({ suppressFirstMessage: suppress });
191
- } finally {
192
- isRestartingRef.current = false;
193
- }
194
- },
195
- [endSession, startInternal]
196
- );
197
- const sendContextualUpdate = useCallback((text) => {
198
- conversationRef.current?.sendContextualUpdate(text);
199
- }, []);
200
- const sendUserMessage = useCallback((text) => {
201
- const ref = conversationRef.current;
202
- if (!ref) return;
203
- if (typeof ref.sendUserMessage === "function") {
204
- ref.sendUserMessage(text);
205
- return;
206
- }
207
- ref.sendContextualUpdate(text);
208
- try {
209
- ref.sendUserActivity?.();
210
- } catch {
211
- }
212
- }, []);
213
- const sendUserActivity = useCallback(() => {
214
- conversationRef.current?.sendUserActivity?.();
215
- }, []);
216
- const getOutputByteFrequencyData = useCallback(() => {
217
- try {
218
- const fn = conversation.getOutputByteFrequencyData;
219
- return fn ? fn() : null;
220
- } catch {
221
- return null;
222
- }
223
- }, [conversation]);
224
- return {
225
- start,
226
- end,
227
- restart,
228
- status,
229
- isSpeaking,
230
- isListening,
231
- isMuted,
232
- setMuted,
233
- getOutputByteFrequencyData,
234
- sendContextualUpdate,
235
- sendUserMessage,
236
- sendUserActivity,
237
- conversationId: optionConversationId ?? convaiConversationId,
238
- convaiConversationId
239
- };
240
- }
241
-
242
27
  // src/react/useShogoVoice.ts
243
28
  function useShogoVoice(opts = {}) {
244
29
  return useVoiceConversation({
@@ -250,7 +35,7 @@ function useShogoVoice(opts = {}) {
250
35
  }
251
36
 
252
37
  // src/react/useChatConversation.ts
253
- import { useCallback as useCallback2, useMemo, useRef as useRef2 } from "react";
38
+ import { useCallback, useMemo, useRef } from "react";
254
39
  import { useChat } from "@ai-sdk/react";
255
40
  import { DefaultChatTransport } from "ai";
256
41
  var DEFAULT_API_PATH = "/api/chat/turn";
@@ -302,9 +87,9 @@ function useChatConversation(options = {}) {
302
87
  }),
303
88
  [resolvedApi, fetchCredentials, headers, body]
304
89
  );
305
- const toolsRef = useRef2(clientTools);
90
+ const toolsRef = useRef(clientTools);
306
91
  toolsRef.current = clientTools;
307
- const chatRef = useRef2(null);
92
+ const chatRef = useRef(null);
308
93
  const resolvedId = id ?? (conversationId ? `shogo-chat:${conversationId}` : DEFAULT_CHAT_ID);
309
94
  const chat = useChat({
310
95
  id: resolvedId,
@@ -346,17 +131,17 @@ function useChatConversation(options = {}) {
346
131
  }
347
132
  });
348
133
  chatRef.current = chat;
349
- const sendMessage = useCallback2(
134
+ const sendMessage = useCallback(
350
135
  async (text) => {
351
136
  if (!text.trim()) return;
352
137
  await chatRef.current?.sendMessage({ text });
353
138
  },
354
139
  []
355
140
  );
356
- const setMessages = useCallback2((messages) => {
141
+ const setMessages = useCallback((messages) => {
357
142
  chatRef.current?.setMessages?.(messages);
358
143
  }, []);
359
- const appendAssistantMessage = useCallback2((text) => {
144
+ const appendAssistantMessage = useCallback((text) => {
360
145
  const next = {
361
146
  id: syntheticId("synthetic-assistant"),
362
147
  role: "assistant",
@@ -367,7 +152,7 @@ function useChatConversation(options = {}) {
367
152
  const nextList = [...current.messages, next];
368
153
  current.setMessages?.(nextList);
369
154
  }, []);
370
- const appendUserMessage = useCallback2((text) => {
155
+ const appendUserMessage = useCallback((text) => {
371
156
  const next = {
372
157
  id: syntheticId("synthetic-user"),
373
158
  role: "user",
@@ -398,539 +183,6 @@ function useShogoChat(opts = {}) {
398
183
  ...opts
399
184
  });
400
185
  }
401
-
402
- // src/react/ShogoVoiceProvider.tsx
403
- import { ConversationProvider as ElevenLabsConversationProvider } from "@elevenlabs/react";
404
- import { jsx } from "react/jsx-runtime";
405
- function ShogoVoiceProvider(props) {
406
- return /* @__PURE__ */ jsx(ElevenLabsConversationProvider, { children: props.children });
407
- }
408
-
409
- // src/react/OrganicSphere.tsx
410
- import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef3 } from "react";
411
- import * as THREE from "three";
412
- import { jsx as jsx2 } from "react/jsx-runtime";
413
- function seededUnit(seed, salt) {
414
- const s = Math.sin((seed + salt * 7919) * 12.9898 + salt * 78.233) * 43758.5453;
415
- return s - Math.floor(s);
416
- }
417
- function OrganicSphere({
418
- getFrequencyData,
419
- active = true,
420
- config: configProp,
421
- lightAColor,
422
- lightBColor,
423
- rimColor,
424
- rimThreshold,
425
- rimPower,
426
- backgroundColor,
427
- subdivisions,
428
- maxPixelRatio,
429
- className,
430
- style
431
- }) {
432
- const containerRef = useRef3(null);
433
- const resolvedConfig = useMemo2(() => {
434
- const base = resolveOrganicSphereConfig(configProp);
435
- const overrides = {};
436
- if (lightAColor !== void 0) overrides.lightAColor = lightAColor;
437
- if (lightBColor !== void 0) overrides.lightBColor = lightBColor;
438
- if (rimColor !== void 0) overrides.rimColor = rimColor;
439
- if (rimThreshold !== void 0) overrides.rimThreshold = rimThreshold;
440
- if (rimPower !== void 0) overrides.rimPower = rimPower;
441
- if (backgroundColor !== void 0) overrides.backgroundColor = backgroundColor;
442
- if (subdivisions !== void 0) overrides.subdivisions = subdivisions;
443
- if (maxPixelRatio !== void 0) overrides.maxPixelRatio = maxPixelRatio;
444
- return { ...base, ...overrides };
445
- }, [
446
- configProp,
447
- lightAColor,
448
- lightBColor,
449
- rimColor,
450
- rimThreshold,
451
- rimPower,
452
- backgroundColor,
453
- subdivisions,
454
- maxPixelRatio
455
- ]);
456
- const configRef = useRef3(resolvedConfig);
457
- useEffect2(() => {
458
- configRef.current = resolvedConfig;
459
- }, [resolvedConfig]);
460
- const getFrequencyDataRef = useRef3(getFrequencyData);
461
- const activeRef = useRef3(active);
462
- useEffect2(() => {
463
- getFrequencyDataRef.current = getFrequencyData;
464
- }, [getFrequencyData]);
465
- useEffect2(() => {
466
- activeRef.current = active;
467
- }, [active]);
468
- const initSubdivisions = resolvedConfig.subdivisions;
469
- const initMaxPixelRatio = resolvedConfig.maxPixelRatio;
470
- const initBackgroundColor = resolvedConfig.backgroundColor;
471
- useEffect2(() => {
472
- const container = containerRef.current;
473
- if (!container) return;
474
- const cfg0 = configRef.current;
475
- const width = container.clientWidth || 1;
476
- const height = container.clientHeight || 1;
477
- const pixelRatio = Math.min(
478
- initMaxPixelRatio ?? (typeof window !== "undefined" ? window.devicePixelRatio : 1),
479
- 2
480
- );
481
- const scene = new THREE.Scene();
482
- if (initBackgroundColor) scene.background = new THREE.Color(initBackgroundColor);
483
- const camera = new THREE.PerspectiveCamera(cfg0.fov, width / height, 0.1, 100);
484
- camera.position.set(0, 0, cfg0.cameraZ);
485
- scene.add(camera);
486
- const renderer = new THREE.WebGLRenderer({
487
- antialias: true,
488
- alpha: initBackgroundColor === null,
489
- powerPreference: "high-performance"
490
- });
491
- renderer.setSize(width, height, false);
492
- renderer.setPixelRatio(pixelRatio);
493
- renderer.setClearColor(0, initBackgroundColor === null ? 0 : 1);
494
- container.appendChild(renderer.domElement);
495
- renderer.domElement.style.display = "block";
496
- renderer.domElement.style.width = "100%";
497
- renderer.domElement.style.height = "100%";
498
- const geometry = new THREE.SphereGeometry(1, initSubdivisions, initSubdivisions);
499
- geometry.computeTangents();
500
- const lightAPos = new THREE.Vector3().setFromSpherical(
501
- new THREE.Spherical(1, 0.615, 2.049)
502
- );
503
- const lightBPos = new THREE.Vector3().setFromSpherical(
504
- new THREE.Spherical(1, 2.561, -1.844)
505
- );
506
- const lightAColorObj = new THREE.Color(cfg0.lightAColor);
507
- const lightBColorObj = new THREE.Color(cfg0.lightBColor);
508
- const rimColorObj = new THREE.Color(cfg0.rimColor ?? cfg0.lightBColor);
509
- const material = new THREE.ShaderMaterial({
510
- uniforms: {
511
- uLightAColor: { value: lightAColorObj },
512
- uLightAPosition: { value: lightAPos },
513
- uLightAIntensity: { value: cfg0.lightAIntensity },
514
- uLightBColor: { value: lightBColorObj },
515
- uLightBPosition: { value: lightBPos },
516
- uLightBIntensity: { value: cfg0.lightBIntensity },
517
- uSubdivision: {
518
- value: new THREE.Vector2(initSubdivisions, initSubdivisions)
519
- },
520
- uOffset: { value: new THREE.Vector3() },
521
- uDistortionFrequency: { value: cfg0.distortionFrequency },
522
- uDistortionStrength: { value: cfg0.high.idle },
523
- uDisplacementFrequency: { value: cfg0.displacementFrequency },
524
- uDisplacementStrength: { value: cfg0.volume.idle },
525
- uFresnelOffset: { value: cfg0.fresnelOffset },
526
- uFresnelMultiplier: { value: cfg0.medium.idle },
527
- uFresnelPower: { value: cfg0.fresnelPower },
528
- uRimColor: { value: rimColorObj },
529
- uRimThreshold: { value: cfg0.rimThreshold },
530
- uRimPower: { value: cfg0.rimPower },
531
- uTime: { value: 0 }
532
- },
533
- defines: { USE_TANGENT: "" },
534
- vertexShader: ORGANIC_SPHERE_VERTEX_SHADER,
535
- fragmentShader: ORGANIC_SPHERE_FRAGMENT_SHADER
536
- });
537
- const mesh = new THREE.Mesh(geometry, material);
538
- scene.add(mesh);
539
- const seedInitialPhase = (seed) => ({
540
- phi: seededUnit(seed, 1) * Math.PI,
541
- theta: seededUnit(seed, 2) * Math.PI * 2
542
- });
543
- const initialPhase = seedInitialPhase(cfg0.seed);
544
- const offsetSpherical = new THREE.Spherical(1, initialPhase.phi, initialPhase.theta);
545
- const offsetDirection = new THREE.Vector3().setFromSpherical(offsetSpherical);
546
- const variations = {
547
- volume: { target: 0, current: cfg0.volume.idle },
548
- medium: { target: 0, current: cfg0.medium.idle },
549
- high: { target: 0, current: cfg0.high.idle },
550
- low: { target: 0, current: cfg0.low.idle }
551
- };
552
- const resetAnimationState = (cfg) => {
553
- material.uniforms.uTime.value = 0;
554
- material.uniforms.uOffset.value.set(0, 0, 0);
555
- const phase = seedInitialPhase(cfg.seed);
556
- offsetSpherical.radius = 1;
557
- offsetSpherical.phi = phase.phi;
558
- offsetSpherical.theta = phase.theta;
559
- variations.volume.current = cfg.volume.idle;
560
- variations.medium.current = cfg.medium.idle;
561
- variations.high.current = cfg.high.idle;
562
- variations.low.current = cfg.low.idle;
563
- variations.volume.target = cfg.volume.idle;
564
- variations.medium.target = cfg.medium.idle;
565
- variations.high.target = cfg.high.idle;
566
- variations.low.target = cfg.low.idle;
567
- };
568
- const LEVEL_COUNT = 8;
569
- function computeLevels(buf) {
570
- const bins = Math.floor(buf.length / LEVEL_COUNT);
571
- const levels = new Array(LEVEL_COUNT).fill(0);
572
- if (bins <= 0) return levels;
573
- for (let i = 0; i < LEVEL_COUNT; i++) {
574
- let sum = 0;
575
- for (let j = 0; j < bins; j++) sum += buf[i * bins + j];
576
- levels[i] = sum / bins / 256;
577
- }
578
- return levels;
579
- }
580
- function bandTarget(reactivity, levels, sourceLevel) {
581
- if (!levels) return reactivity.idle;
582
- return Math.max(reactivity.floor, reactivity.floor + sourceLevel * reactivity.gain);
583
- }
584
- let rafId = 0;
585
- let lastTs = performance.now();
586
- let disposed = false;
587
- let wasActive = activeRef.current;
588
- let lastSeed = cfg0.seed;
589
- const render = () => {
590
- if (disposed) return;
591
- const now = performance.now();
592
- const delta = Math.min(now - lastTs, 100);
593
- lastTs = now;
594
- const cfg = configRef.current;
595
- lightAColorObj.set(cfg.lightAColor);
596
- lightBColorObj.set(cfg.lightBColor);
597
- rimColorObj.set(cfg.rimColor ?? cfg.lightBColor);
598
- material.uniforms.uLightAIntensity.value = cfg.lightAIntensity;
599
- material.uniforms.uLightBIntensity.value = cfg.lightBIntensity;
600
- material.uniforms.uDistortionFrequency.value = cfg.distortionFrequency;
601
- material.uniforms.uDisplacementFrequency.value = cfg.displacementFrequency;
602
- material.uniforms.uFresnelOffset.value = cfg.fresnelOffset;
603
- material.uniforms.uFresnelPower.value = cfg.fresnelPower;
604
- material.uniforms.uRimThreshold.value = cfg.rimThreshold;
605
- material.uniforms.uRimPower.value = cfg.rimPower;
606
- if (camera.position.z !== cfg.cameraZ) camera.position.z = cfg.cameraZ;
607
- if (camera.fov !== cfg.fov) {
608
- camera.fov = cfg.fov;
609
- camera.updateProjectionMatrix();
610
- }
611
- const isActive = activeRef.current;
612
- if (isActive && !wasActive || cfg.seed !== lastSeed) {
613
- resetAnimationState(cfg);
614
- lastSeed = cfg.seed;
615
- }
616
- wasActive = isActive;
617
- if (isActive) {
618
- let levels = null;
619
- if (getFrequencyDataRef.current) {
620
- try {
621
- const buf = getFrequencyDataRef.current();
622
- if (buf && buf.length > 0) levels = computeLevels(buf);
623
- } catch {
624
- levels = null;
625
- }
626
- }
627
- const l0 = levels ? levels[0] || 0 : 0;
628
- const l1 = levels ? levels[1] || 0 : 0;
629
- const l2 = levels ? levels[2] || 0 : 0;
630
- const loudest = Math.max(l0, l1, l2);
631
- const update = (variation, reactivity, sourceLevel) => {
632
- variation.target = bandTarget(reactivity, levels, sourceLevel);
633
- const easing = variation.target > variation.current ? reactivity.attack : reactivity.decay;
634
- variation.current += (variation.target - variation.current) * easing * delta;
635
- };
636
- update(variations.volume, cfg.volume, loudest);
637
- update(variations.medium, cfg.medium, l1);
638
- update(variations.high, cfg.high, l2);
639
- update(variations.low, cfg.low, l0);
640
- const timeFrequency = variations.low.current;
641
- const elapsed = delta * timeFrequency;
642
- material.uniforms.uDisplacementStrength.value = variations.volume.current;
643
- material.uniforms.uDistortionStrength.value = variations.high.current;
644
- material.uniforms.uFresnelMultiplier.value = variations.medium.current;
645
- const offsetTime = (material.uniforms.uTime.value + elapsed) * 0.3;
646
- offsetSpherical.phi = (Math.sin(offsetTime * 1e-3) * Math.sin(offsetTime * 321e-5) * 0.5 + 0.5) * Math.PI;
647
- offsetSpherical.theta = (Math.sin(offsetTime * 1e-4) * Math.sin(offsetTime * 321e-6) * 0.5 + 0.5) * Math.PI * 2;
648
- offsetDirection.setFromSpherical(offsetSpherical);
649
- offsetDirection.multiplyScalar(timeFrequency * 2);
650
- material.uniforms.uOffset.value.add(offsetDirection);
651
- material.uniforms.uTime.value += elapsed;
652
- }
653
- renderer.render(scene, camera);
654
- rafId = requestAnimationFrame(render);
655
- };
656
- rafId = requestAnimationFrame(render);
657
- const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
658
- const w = container.clientWidth || 1;
659
- const h = container.clientHeight || 1;
660
- camera.aspect = w / h;
661
- camera.updateProjectionMatrix();
662
- renderer.setSize(w, h, false);
663
- }) : null;
664
- resizeObserver?.observe(container);
665
- return () => {
666
- disposed = true;
667
- cancelAnimationFrame(rafId);
668
- resizeObserver?.disconnect();
669
- geometry.dispose();
670
- material.dispose();
671
- renderer.dispose();
672
- if (renderer.domElement.parentNode === container) {
673
- container.removeChild(renderer.domElement);
674
- }
675
- };
676
- }, [initSubdivisions, initMaxPixelRatio, initBackgroundColor]);
677
- return /* @__PURE__ */ jsx2("div", { ref: containerRef, className, style });
678
- }
679
-
680
- // src/react/OrganicParticles.tsx
681
- import { useEffect as useEffect3, useMemo as useMemo3, useRef as useRef4 } from "react";
682
- import * as THREE2 from "three";
683
- import { jsx as jsx3 } from "react/jsx-runtime";
684
- function seededUnit2(seed, salt) {
685
- const s = Math.sin((seed + salt * 7919) * 12.9898 + salt * 78.233) * 43758.5453;
686
- return s - Math.floor(s);
687
- }
688
- function buildParticleAttributes(count, innerRadius, outerRadius, seed) {
689
- const positions = new Float32Array(count * 3);
690
- const seeds = new Float32Array(count);
691
- for (let i = 0; i < count; i++) {
692
- const u = seededUnit2(seed, i * 4 + 1);
693
- const v = seededUnit2(seed, i * 4 + 2);
694
- const w = seededUnit2(seed, i * 4 + 3);
695
- const s = seededUnit2(seed, i * 4 + 4);
696
- const theta = v * Math.PI * 2;
697
- const phi = Math.acos(2 * w - 1);
698
- const r = innerRadius + u * Math.max(0, outerRadius - innerRadius);
699
- const sinPhi = Math.sin(phi);
700
- positions[i * 3 + 0] = r * sinPhi * Math.cos(theta);
701
- positions[i * 3 + 1] = r * sinPhi * Math.sin(theta);
702
- positions[i * 3 + 2] = r * Math.cos(phi);
703
- seeds[i] = s;
704
- }
705
- return { positions, seeds };
706
- }
707
- function OrganicParticles({
708
- getFrequencyData,
709
- active = true,
710
- config: configProp,
711
- className,
712
- style
713
- }) {
714
- const containerRef = useRef4(null);
715
- const resolvedConfig = useMemo3(
716
- () => resolveOrganicParticlesConfig(configProp),
717
- [configProp]
718
- );
719
- const configRef = useRef4(resolvedConfig);
720
- useEffect3(() => {
721
- configRef.current = resolvedConfig;
722
- }, [resolvedConfig]);
723
- const getFrequencyDataRef = useRef4(getFrequencyData);
724
- const activeRef = useRef4(active);
725
- useEffect3(() => {
726
- getFrequencyDataRef.current = getFrequencyData;
727
- }, [getFrequencyData]);
728
- useEffect3(() => {
729
- activeRef.current = active;
730
- }, [active]);
731
- const initCount = resolvedConfig.count;
732
- const initInnerRadius = resolvedConfig.innerRadius;
733
- const initOuterRadius = resolvedConfig.outerRadius;
734
- const initSeed = resolvedConfig.seed;
735
- const initMaxPixelRatio = resolvedConfig.maxPixelRatio;
736
- const initBackgroundColor = resolvedConfig.backgroundColor;
737
- useEffect3(() => {
738
- const container = containerRef.current;
739
- if (!container) return;
740
- const cfg0 = configRef.current;
741
- const width = container.clientWidth || 1;
742
- const height = container.clientHeight || 1;
743
- const pixelRatio = Math.min(
744
- initMaxPixelRatio ?? (typeof window !== "undefined" ? window.devicePixelRatio : 1),
745
- 2
746
- );
747
- const scene = new THREE2.Scene();
748
- if (initBackgroundColor) scene.background = new THREE2.Color(initBackgroundColor);
749
- const camera = new THREE2.PerspectiveCamera(cfg0.fov, width / height, 0.1, 100);
750
- camera.position.set(0, 0, cfg0.cameraZ);
751
- scene.add(camera);
752
- const renderer = new THREE2.WebGLRenderer({
753
- antialias: true,
754
- alpha: initBackgroundColor === null,
755
- powerPreference: "high-performance"
756
- });
757
- renderer.setSize(width, height, false);
758
- renderer.setPixelRatio(pixelRatio);
759
- renderer.setClearColor(0, initBackgroundColor === null ? 0 : 1);
760
- container.appendChild(renderer.domElement);
761
- renderer.domElement.style.display = "block";
762
- renderer.domElement.style.width = "100%";
763
- renderer.domElement.style.height = "100%";
764
- const { positions, seeds } = buildParticleAttributes(
765
- initCount,
766
- initInnerRadius,
767
- initOuterRadius,
768
- initSeed
769
- );
770
- const geometry = new THREE2.BufferGeometry();
771
- geometry.setAttribute("aBasePosition", new THREE2.BufferAttribute(positions, 3));
772
- geometry.setAttribute("aSeed", new THREE2.BufferAttribute(seeds, 1));
773
- geometry.setAttribute("position", new THREE2.BufferAttribute(positions, 3));
774
- const colorCoolObj = new THREE2.Color(cfg0.colorCool);
775
- const colorHotObj = new THREE2.Color(cfg0.colorHot);
776
- const material = new THREE2.ShaderMaterial({
777
- uniforms: {
778
- uTime: { value: 0 },
779
- uNoiseFrequency: { value: cfg0.noiseFrequency },
780
- uNoiseStrength: { value: cfg0.noiseStrength },
781
- uDisplacement: { value: cfg0.volume.idle },
782
- uSwirl: { value: cfg0.high.idle },
783
- uSwirlTimeRate: { value: cfg0.swirlTimeRate },
784
- uSizeBase: { value: cfg0.sizeBase },
785
- uSizeAudio: { value: cfg0.medium.idle },
786
- uPixelRatio: { value: pixelRatio },
787
- uColorCool: { value: colorCoolObj },
788
- uColorHot: { value: colorHotObj },
789
- uOpacity: { value: cfg0.opacity },
790
- uSoftness: { value: cfg0.softness }
791
- },
792
- vertexShader: ORGANIC_PARTICLES_VERTEX_SHADER,
793
- fragmentShader: ORGANIC_PARTICLES_FRAGMENT_SHADER,
794
- transparent: true,
795
- depthWrite: false,
796
- blending: THREE2.AdditiveBlending
797
- });
798
- const points = new THREE2.Points(geometry, material);
799
- scene.add(points);
800
- const variations = {
801
- volume: { target: 0, current: cfg0.volume.idle },
802
- medium: { target: 0, current: cfg0.medium.idle },
803
- high: { target: 0, current: cfg0.high.idle },
804
- low: { target: 0, current: cfg0.low.idle }
805
- };
806
- const LEVEL_COUNT = 8;
807
- function computeLevels(buf) {
808
- const bins = Math.floor(buf.length / LEVEL_COUNT);
809
- const levels = new Array(LEVEL_COUNT).fill(0);
810
- if (bins <= 0) return levels;
811
- for (let i = 0; i < LEVEL_COUNT; i++) {
812
- let sum = 0;
813
- for (let j = 0; j < bins; j++) sum += buf[i * bins + j];
814
- levels[i] = sum / bins / 256;
815
- }
816
- return levels;
817
- }
818
- function bandTarget(reactivity, levels, sourceLevel) {
819
- if (!levels) return reactivity.idle;
820
- return Math.max(
821
- reactivity.floor,
822
- reactivity.floor + sourceLevel * reactivity.gain
823
- );
824
- }
825
- const rotationState = { y: 0 };
826
- const resetAnimationState = (cfg) => {
827
- material.uniforms.uTime.value = 0;
828
- rotationState.y = 0;
829
- points.rotation.set(0, 0, 0);
830
- variations.volume.current = cfg.volume.idle;
831
- variations.medium.current = cfg.medium.idle;
832
- variations.high.current = cfg.high.idle;
833
- variations.low.current = cfg.low.idle;
834
- variations.volume.target = cfg.volume.idle;
835
- variations.medium.target = cfg.medium.idle;
836
- variations.high.target = cfg.high.idle;
837
- variations.low.target = cfg.low.idle;
838
- };
839
- let rafId = 0;
840
- let lastTs = performance.now();
841
- let disposed = false;
842
- let wasActive = activeRef.current;
843
- const render = () => {
844
- if (disposed) return;
845
- const now = performance.now();
846
- const delta = Math.min(now - lastTs, 100);
847
- lastTs = now;
848
- const cfg = configRef.current;
849
- colorCoolObj.set(cfg.colorCool);
850
- colorHotObj.set(cfg.colorHot);
851
- material.uniforms.uNoiseFrequency.value = cfg.noiseFrequency;
852
- material.uniforms.uNoiseStrength.value = cfg.noiseStrength;
853
- material.uniforms.uSwirlTimeRate.value = cfg.swirlTimeRate;
854
- material.uniforms.uSizeBase.value = cfg.sizeBase;
855
- material.uniforms.uOpacity.value = cfg.opacity;
856
- material.uniforms.uSoftness.value = cfg.softness;
857
- if (camera.position.z !== cfg.cameraZ) camera.position.z = cfg.cameraZ;
858
- if (camera.fov !== cfg.fov) {
859
- camera.fov = cfg.fov;
860
- camera.updateProjectionMatrix();
861
- }
862
- const isActive = activeRef.current;
863
- if (isActive && !wasActive) {
864
- resetAnimationState(cfg);
865
- }
866
- wasActive = isActive;
867
- if (isActive) {
868
- let levels = null;
869
- if (getFrequencyDataRef.current) {
870
- try {
871
- const buf = getFrequencyDataRef.current();
872
- if (buf && buf.length > 0) levels = computeLevels(buf);
873
- } catch {
874
- levels = null;
875
- }
876
- }
877
- const l0 = levels ? levels[0] || 0 : 0;
878
- const l1 = levels ? levels[1] || 0 : 0;
879
- const l2 = levels ? levels[2] || 0 : 0;
880
- const loudest = Math.max(l0, l1, l2);
881
- const update = (variation, reactivity, sourceLevel) => {
882
- variation.target = bandTarget(reactivity, levels, sourceLevel);
883
- const easing = variation.target > variation.current ? reactivity.attack : reactivity.decay;
884
- variation.current += (variation.target - variation.current) * easing * delta;
885
- };
886
- update(variations.volume, cfg.volume, loudest);
887
- update(variations.medium, cfg.medium, l1);
888
- update(variations.high, cfg.high, l2);
889
- update(variations.low, cfg.low, l0);
890
- const timeFrequency = variations.low.current;
891
- const elapsed = delta * timeFrequency;
892
- material.uniforms.uDisplacement.value = variations.volume.current;
893
- material.uniforms.uSizeAudio.value = variations.medium.current;
894
- material.uniforms.uSwirl.value = variations.high.current;
895
- material.uniforms.uTime.value += elapsed;
896
- rotationState.y += delta * cfg.rotationBias + variations.high.current * delta * 8e-4;
897
- points.rotation.y = rotationState.y;
898
- } else {
899
- material.uniforms.uTime.value += delta * cfg.idleNoiseRate;
900
- }
901
- renderer.render(scene, camera);
902
- rafId = requestAnimationFrame(render);
903
- };
904
- rafId = requestAnimationFrame(render);
905
- const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
906
- const w = container.clientWidth || 1;
907
- const h = container.clientHeight || 1;
908
- camera.aspect = w / h;
909
- camera.updateProjectionMatrix();
910
- renderer.setSize(w, h, false);
911
- }) : null;
912
- resizeObserver?.observe(container);
913
- return () => {
914
- disposed = true;
915
- cancelAnimationFrame(rafId);
916
- resizeObserver?.disconnect();
917
- geometry.dispose();
918
- material.dispose();
919
- renderer.dispose();
920
- if (renderer.domElement.parentNode === container) {
921
- container.removeChild(renderer.domElement);
922
- }
923
- };
924
- }, [
925
- initCount,
926
- initInnerRadius,
927
- initOuterRadius,
928
- initSeed,
929
- initMaxPixelRatio,
930
- initBackgroundColor
931
- ]);
932
- return /* @__PURE__ */ jsx3("div", { ref: containerRef, className, style });
933
- }
934
186
  export {
935
187
  DEFAULT_ORGANIC_PARTICLES_CONFIG,
936
188
  DEFAULT_ORGANIC_SPHERE_CONFIG,
@@ -945,6 +197,7 @@ export {
945
197
  resolveOrganicParticlesConfig,
946
198
  resolveOrganicSphereConfig,
947
199
  useChatConversation,
200
+ useLiveVoiceConversation,
948
201
  useShogoChat,
949
202
  useShogoVoice,
950
203
  useVoiceConversation