@unctad-ai/voice-agent-ui 0.1.8 → 1.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unctad-ai/voice-agent-ui",
3
- "version": "0.1.8",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -19,8 +19,8 @@
19
19
  "dependencies": {
20
20
  "clsx": "^2.1.0",
21
21
  "tailwind-merge": "^2.0.0",
22
- "@unctad-ai/voice-agent-core": "0.1.8",
23
- "@unctad-ai/voice-agent-registries": "0.1.8"
22
+ "@unctad-ai/voice-agent-core": "1.0.1",
23
+ "@unctad-ai/voice-agent-registries": "1.0.1"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "lucide-react": "*",
@@ -1,7 +0,0 @@
1
- import {
2
- VoiceSettingsView
3
- } from "./chunk-MUFUZ3TH.js";
4
- export {
5
- VoiceSettingsView as default
6
- };
7
- //# sourceMappingURL=VoiceSettingsView-RP5CUCKI.js.map
@@ -1,582 +0,0 @@
1
- // src/components/VoiceSettingsView.tsx
2
- import { motion } from "motion/react";
3
- import {
4
- ArrowLeft,
5
- RotateCcw,
6
- Volume2,
7
- Gauge,
8
- AudioLines,
9
- Sparkles,
10
- Mic,
11
- Timer,
12
- MessageSquare,
13
- Activity,
14
- EyeOff,
15
- Info,
16
- Ear,
17
- Clock,
18
- Zap,
19
- Minimize2,
20
- Signal
21
- } from "lucide-react";
22
-
23
- // src/contexts/VoiceSettingsContext.tsx
24
- import { createContext, useContext, useState, useRef, useCallback } from "react";
25
- import {
26
- DEFAULT_VOLUME,
27
- DEFAULT_PLAYBACK_SPEED,
28
- DEFAULT_TTS_ENABLED,
29
- DEFAULT_AUTO_LISTEN,
30
- DEFAULT_IDLE_TIMEOUT_MS,
31
- DEFAULT_EXPRESSIVENESS,
32
- DEFAULT_RESPONSE_LENGTH,
33
- DEFAULT_SHOW_PIPELINE_METRICS,
34
- DEFAULT_PIPELINE_METRICS_AUTO_HIDE_MS,
35
- DEFAULT_SPEECH_THRESHOLD,
36
- DEFAULT_PAUSE_TOLERANCE_MS,
37
- DEFAULT_BARGE_IN_THRESHOLD,
38
- DEFAULT_PANEL_COLLAPSE_TIMEOUT_MS,
39
- DEFAULT_STT_TIMEOUT_MS,
40
- DEFAULT_TTS_TIMEOUT_MS,
41
- DEFAULT_LLM_TIMEOUT_MS,
42
- DEFAULT_MIN_AUDIO_RMS
43
- } from "@unctad-ai/voice-agent-core";
44
- import { jsx } from "react/jsx-runtime";
45
- var DEFAULTS = {
46
- volume: DEFAULT_VOLUME,
47
- playbackSpeed: DEFAULT_PLAYBACK_SPEED,
48
- ttsEnabled: DEFAULT_TTS_ENABLED,
49
- autoListen: DEFAULT_AUTO_LISTEN,
50
- idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS,
51
- expressiveness: DEFAULT_EXPRESSIVENESS,
52
- responseLength: DEFAULT_RESPONSE_LENGTH,
53
- showPipelineMetrics: DEFAULT_SHOW_PIPELINE_METRICS,
54
- pipelineMetricsAutoHideMs: DEFAULT_PIPELINE_METRICS_AUTO_HIDE_MS,
55
- speechThreshold: DEFAULT_SPEECH_THRESHOLD,
56
- pauseToleranceMs: DEFAULT_PAUSE_TOLERANCE_MS,
57
- bargeInThreshold: DEFAULT_BARGE_IN_THRESHOLD,
58
- panelCollapseTimeoutMs: DEFAULT_PANEL_COLLAPSE_TIMEOUT_MS,
59
- sttTimeoutMs: DEFAULT_STT_TIMEOUT_MS,
60
- ttsTimeoutMs: DEFAULT_TTS_TIMEOUT_MS,
61
- llmTimeoutMs: DEFAULT_LLM_TIMEOUT_MS,
62
- minAudioRms: DEFAULT_MIN_AUDIO_RMS
63
- };
64
- var STORAGE_KEY = "voice-settings";
65
- function loadSettings() {
66
- try {
67
- const raw = localStorage.getItem(STORAGE_KEY);
68
- if (!raw) return { ...DEFAULTS };
69
- const parsed = JSON.parse(raw);
70
- return { ...DEFAULTS, ...parsed };
71
- } catch {
72
- return { ...DEFAULTS };
73
- }
74
- }
75
- function persistSettings(settings) {
76
- try {
77
- localStorage.setItem(STORAGE_KEY, JSON.stringify(settings));
78
- } catch {
79
- }
80
- }
81
- var VoiceSettingsContext = createContext(void 0);
82
- function VoiceSettingsProvider({ children }) {
83
- const [settings, setSettings] = useState(loadSettings);
84
- const volumeRef = useRef(settings.volume);
85
- const speedRef = useRef(settings.playbackSpeed);
86
- const updateSetting = useCallback(
87
- (key, value) => {
88
- setSettings((prev) => {
89
- const next = { ...prev, [key]: value };
90
- persistSettings(next);
91
- if (key === "volume") volumeRef.current = value;
92
- if (key === "playbackSpeed") speedRef.current = value;
93
- return next;
94
- });
95
- },
96
- []
97
- );
98
- const resetSettings = useCallback(() => {
99
- const defaults = { ...DEFAULTS };
100
- setSettings(defaults);
101
- persistSettings(defaults);
102
- volumeRef.current = defaults.volume;
103
- speedRef.current = defaults.playbackSpeed;
104
- }, []);
105
- return /* @__PURE__ */ jsx(
106
- VoiceSettingsContext.Provider,
107
- {
108
- value: { settings, volumeRef, speedRef, updateSetting, resetSettings },
109
- children
110
- }
111
- );
112
- }
113
- function useVoiceSettings() {
114
- const context = useContext(VoiceSettingsContext);
115
- if (context) return context;
116
- return {
117
- settings: DEFAULTS,
118
- volumeRef: { current: DEFAULTS.volume },
119
- speedRef: { current: DEFAULTS.playbackSpeed },
120
- updateSetting: () => {
121
- },
122
- resetSettings: () => {
123
- }
124
- };
125
- }
126
-
127
- // src/components/VoiceSettingsView.tsx
128
- import { VAD, useSiteConfig } from "@unctad-ai/voice-agent-core";
129
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
130
- function expressivenessLabel(v) {
131
- if (v <= 0.15) return "Low";
132
- if (v <= 0.4) return "Medium";
133
- return "High";
134
- }
135
- function speechThresholdLabel(v) {
136
- if (v >= 0.75) return "Strict";
137
- if (v >= 0.5) return "Balanced";
138
- return "Sensitive";
139
- }
140
- function bargeInLabel(v) {
141
- if (v >= 0.8) return "Hard";
142
- if (v >= 0.6) return "Normal";
143
- return "Easy";
144
- }
145
- function SliderSetting({
146
- icon,
147
- label,
148
- value,
149
- displayValue,
150
- min,
151
- max,
152
- step,
153
- onChange
154
- }) {
155
- return /* @__PURE__ */ jsxs("div", { className: "py-3 space-y-2.5", children: [
156
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
157
- icon,
158
- /* @__PURE__ */ jsx2("span", { className: "flex-1 text-sm font-medium text-neutral-900", children: label }),
159
- /* @__PURE__ */ jsx2("span", { className: "text-xs font-medium tabular-nums", style: { color: "var(--voice-settings-accent, #DB2129)" }, children: displayValue })
160
- ] }),
161
- /* @__PURE__ */ jsx2(
162
- "input",
163
- {
164
- type: "range",
165
- value,
166
- min,
167
- max,
168
- step,
169
- onChange: (e) => onChange(Number(e.target.value)),
170
- className: "w-full",
171
- style: { accentColor: "var(--voice-settings-accent, #DB2129)" }
172
- }
173
- )
174
- ] });
175
- }
176
- function ToggleSetting({
177
- icon,
178
- label,
179
- description,
180
- checked,
181
- onChange
182
- }) {
183
- return /* @__PURE__ */ jsxs("label", { className: "py-3 flex items-center gap-3 cursor-pointer", children: [
184
- icon,
185
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
186
- /* @__PURE__ */ jsx2("div", { className: "text-sm font-medium text-neutral-900", children: label }),
187
- /* @__PURE__ */ jsx2("div", { className: "text-xs text-neutral-500", children: description })
188
- ] }),
189
- /* @__PURE__ */ jsx2(
190
- "button",
191
- {
192
- role: "switch",
193
- "aria-checked": checked,
194
- onClick: () => onChange(!checked),
195
- className: "relative inline-flex h-6 w-11 items-center rounded-full transition-colors cursor-pointer",
196
- style: { backgroundColor: checked ? "var(--voice-settings-accent, #DB2129)" : "#d1d5db" },
197
- children: /* @__PURE__ */ jsx2(
198
- "span",
199
- {
200
- className: "inline-block h-5 w-5 rounded-full bg-white shadow transition-transform",
201
- style: { transform: checked ? "translateX(22px)" : "translateX(2px)" }
202
- }
203
- )
204
- }
205
- )
206
- ] });
207
- }
208
- function SelectSetting({
209
- icon,
210
- label,
211
- value,
212
- onChange,
213
- options
214
- }) {
215
- return /* @__PURE__ */ jsxs("div", { className: "py-3 flex items-center gap-3", children: [
216
- icon,
217
- /* @__PURE__ */ jsx2("span", { className: "flex-1 text-sm font-medium text-neutral-900", children: label }),
218
- /* @__PURE__ */ jsx2(
219
- "select",
220
- {
221
- value,
222
- onChange: (e) => onChange(e.target.value),
223
- className: "h-8 text-xs font-medium text-neutral-700 rounded-full border border-neutral-200 bg-neutral-50 pl-3 pr-7 outline-none appearance-none cursor-pointer hover:border-neutral-300 hover:bg-neutral-100 focus:border-neutral-400 transition-colors",
224
- style: {
225
- backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")`,
226
- backgroundRepeat: "no-repeat",
227
- backgroundPosition: "right 8px center"
228
- },
229
- children: options.map((opt) => /* @__PURE__ */ jsx2("option", { value: opt.value, children: opt.label }, opt.value))
230
- }
231
- )
232
- ] });
233
- }
234
- function VoiceSettingsView({ onBack, onVolumeChange }) {
235
- const { settings, updateSetting, resetSettings } = useVoiceSettings();
236
- const { colors } = useSiteConfig();
237
- const iconClass = "w-4 h-4 shrink-0";
238
- const iconStyle = { color: colors.primary };
239
- return /* @__PURE__ */ jsxs(
240
- motion.div,
241
- {
242
- initial: { opacity: 0, x: 20 },
243
- animate: { opacity: 1, x: 0 },
244
- exit: { opacity: 0, x: 20 },
245
- transition: { duration: 0.2, ease: [0.22, 1, 0.36, 1] },
246
- className: "voice-settings absolute inset-0 flex flex-col z-10",
247
- style: { borderRadius: "inherit", backgroundColor: "#f9fafb", "--voice-settings-accent": colors.primary },
248
- children: [
249
- /* @__PURE__ */ jsxs(
250
- "div",
251
- {
252
- className: "flex items-center gap-2.5 shrink-0 px-4",
253
- style: { height: 56, borderBottom: "1px solid #e5e7eb" },
254
- children: [
255
- /* @__PURE__ */ jsx2(
256
- "button",
257
- {
258
- onClick: onBack,
259
- className: "w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors",
260
- style: { color: "#6b7280" },
261
- onMouseEnter: (e) => {
262
- e.currentTarget.style.color = "#111827";
263
- },
264
- onMouseLeave: (e) => {
265
- e.currentTarget.style.color = "#6b7280";
266
- },
267
- "aria-label": "Back to conversation",
268
- children: /* @__PURE__ */ jsx2(ArrowLeft, { className: "w-4 h-4" })
269
- }
270
- ),
271
- /* @__PURE__ */ jsx2("span", { className: "flex-1 text-sm font-semibold", style: { color: "#111827" }, children: "Settings" }),
272
- /* @__PURE__ */ jsx2(
273
- "button",
274
- {
275
- onClick: resetSettings,
276
- className: "w-8 h-8 rounded-full flex items-center justify-center cursor-pointer transition-colors",
277
- style: { color: "#9ca3af" },
278
- onMouseEnter: (e) => {
279
- e.currentTarget.style.color = colors.primary;
280
- },
281
- onMouseLeave: (e) => {
282
- e.currentTarget.style.color = "#9ca3af";
283
- },
284
- "aria-label": "Reset all settings",
285
- title: "Reset to defaults",
286
- children: /* @__PURE__ */ jsx2(RotateCcw, { className: "w-3.5 h-3.5" })
287
- }
288
- )
289
- ]
290
- }
291
- ),
292
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-h-0 overflow-y-auto", children: [
293
- /* @__PURE__ */ jsxs(SettingsSection, { title: "Voice Input", children: [
294
- /* @__PURE__ */ jsx2(
295
- ToggleSetting,
296
- {
297
- icon: /* @__PURE__ */ jsx2(Mic, { className: iconClass, style: iconStyle }),
298
- label: "Auto-listen",
299
- description: "Start mic when panel opens",
300
- checked: settings.autoListen,
301
- onChange: (v) => updateSetting("autoListen", v)
302
- }
303
- ),
304
- /* @__PURE__ */ jsx2(Divider, {}),
305
- /* @__PURE__ */ jsx2(
306
- SelectSetting,
307
- {
308
- icon: /* @__PURE__ */ jsx2(Timer, { className: iconClass, style: iconStyle }),
309
- label: "Idle timeout",
310
- value: String(settings.idleTimeoutMs),
311
- onChange: (v) => updateSetting("idleTimeoutMs", Number(v)),
312
- options: [
313
- { value: "30000", label: "30s" },
314
- { value: "60000", label: "1 min" },
315
- { value: "120000", label: "2 min" },
316
- { value: "300000", label: "5 min" }
317
- ]
318
- }
319
- ),
320
- /* @__PURE__ */ jsx2(Divider, {}),
321
- /* @__PURE__ */ jsx2(
322
- SliderSetting,
323
- {
324
- icon: /* @__PURE__ */ jsx2(Ear, { className: iconClass, style: iconStyle }),
325
- label: "Speech threshold",
326
- value: settings.speechThreshold * 100,
327
- displayValue: speechThresholdLabel(settings.speechThreshold),
328
- min: 30,
329
- max: 90,
330
- step: 5,
331
- onChange: (v) => updateSetting("speechThreshold", v / 100)
332
- }
333
- ),
334
- /* @__PURE__ */ jsx2(Divider, {}),
335
- /* @__PURE__ */ jsx2(
336
- SelectSetting,
337
- {
338
- icon: /* @__PURE__ */ jsx2(Clock, { className: iconClass, style: iconStyle }),
339
- label: "Pause tolerance",
340
- value: String(settings.pauseToleranceMs),
341
- onChange: (v) => updateSetting("pauseToleranceMs", Number(v)),
342
- options: [
343
- { value: "400", label: "Fast" },
344
- { value: "600", label: "Default" },
345
- { value: "800", label: "Relaxed" },
346
- { value: "1000", label: "Patient" }
347
- ]
348
- }
349
- ),
350
- /* @__PURE__ */ jsx2(Divider, {}),
351
- /* @__PURE__ */ jsx2(
352
- SliderSetting,
353
- {
354
- icon: /* @__PURE__ */ jsx2(Zap, { className: iconClass, style: iconStyle }),
355
- label: "Barge-in threshold",
356
- value: settings.bargeInThreshold * 100,
357
- displayValue: bargeInLabel(settings.bargeInThreshold),
358
- min: 40,
359
- max: 90,
360
- step: 5,
361
- onChange: (v) => updateSetting("bargeInThreshold", v / 100)
362
- }
363
- ),
364
- /* @__PURE__ */ jsx2(Divider, {}),
365
- /* @__PURE__ */ jsx2(
366
- SelectSetting,
367
- {
368
- icon: /* @__PURE__ */ jsx2(Minimize2, { className: iconClass, style: iconStyle }),
369
- label: "Auto-collapse",
370
- value: String(settings.panelCollapseTimeoutMs),
371
- onChange: (v) => updateSetting("panelCollapseTimeoutMs", Number(v)),
372
- options: [
373
- { value: "120000", label: "2 min" },
374
- { value: "300000", label: "5 min" },
375
- { value: "600000", label: "10 min" },
376
- { value: "0", label: "Never" }
377
- ]
378
- }
379
- )
380
- ] }),
381
- /* @__PURE__ */ jsxs(SettingsSection, { title: "Voice Output", children: [
382
- /* @__PURE__ */ jsx2(
383
- ToggleSetting,
384
- {
385
- icon: /* @__PURE__ */ jsx2(AudioLines, { className: iconClass, style: iconStyle }),
386
- label: "Text-to-speech",
387
- description: "Speak responses aloud",
388
- checked: settings.ttsEnabled,
389
- onChange: (v) => updateSetting("ttsEnabled", v)
390
- }
391
- ),
392
- /* @__PURE__ */ jsx2(Divider, {}),
393
- /* @__PURE__ */ jsx2(
394
- SliderSetting,
395
- {
396
- icon: /* @__PURE__ */ jsx2(Volume2, { className: iconClass, style: iconStyle }),
397
- label: "Volume",
398
- value: settings.volume * 100,
399
- displayValue: `${Math.round(settings.volume * 100)}%`,
400
- min: 0,
401
- max: 100,
402
- step: 1,
403
- onChange: (v) => {
404
- updateSetting("volume", v / 100);
405
- onVolumeChange?.(v / 100);
406
- }
407
- }
408
- ),
409
- /* @__PURE__ */ jsx2(Divider, {}),
410
- /* @__PURE__ */ jsx2(
411
- SliderSetting,
412
- {
413
- icon: /* @__PURE__ */ jsx2(Gauge, { className: iconClass, style: iconStyle }),
414
- label: "Speed",
415
- value: settings.playbackSpeed * 100,
416
- displayValue: `${settings.playbackSpeed.toFixed(2)}x`,
417
- min: 75,
418
- max: 150,
419
- step: 5,
420
- onChange: (v) => updateSetting("playbackSpeed", v / 100)
421
- }
422
- ),
423
- /* @__PURE__ */ jsx2(Divider, {}),
424
- /* @__PURE__ */ jsx2(
425
- SliderSetting,
426
- {
427
- icon: /* @__PURE__ */ jsx2(Sparkles, { className: iconClass, style: iconStyle }),
428
- label: "Expressiveness",
429
- value: settings.expressiveness * 100,
430
- displayValue: expressivenessLabel(settings.expressiveness),
431
- min: 10,
432
- max: 60,
433
- step: 5,
434
- onChange: (v) => updateSetting("expressiveness", v / 100)
435
- }
436
- ),
437
- /* @__PURE__ */ jsx2(Divider, {}),
438
- /* @__PURE__ */ jsx2(
439
- SelectSetting,
440
- {
441
- icon: /* @__PURE__ */ jsx2(MessageSquare, { className: iconClass, style: iconStyle }),
442
- label: "Response length",
443
- value: String(settings.responseLength),
444
- onChange: (v) => updateSetting("responseLength", Number(v)),
445
- options: [
446
- { value: "30", label: "Brief" },
447
- { value: "60", label: "Normal" },
448
- { value: "100", label: "Detailed" }
449
- ]
450
- }
451
- )
452
- ] }),
453
- /* @__PURE__ */ jsxs(SettingsSection, { title: "Developer", children: [
454
- /* @__PURE__ */ jsx2(
455
- ToggleSetting,
456
- {
457
- icon: /* @__PURE__ */ jsx2(Activity, { className: iconClass, style: iconStyle }),
458
- label: "Pipeline metrics",
459
- description: "Show STT / LLM / TTS timings",
460
- checked: settings.showPipelineMetrics,
461
- onChange: (v) => updateSetting("showPipelineMetrics", v)
462
- }
463
- ),
464
- /* @__PURE__ */ jsx2(Divider, {}),
465
- /* @__PURE__ */ jsx2(
466
- SelectSetting,
467
- {
468
- icon: /* @__PURE__ */ jsx2(EyeOff, { className: iconClass, style: iconStyle }),
469
- label: "Auto-hide metrics",
470
- value: String(settings.pipelineMetricsAutoHideMs),
471
- onChange: (v) => updateSetting("pipelineMetricsAutoHideMs", Number(v)),
472
- options: [
473
- { value: "5000", label: "5s" },
474
- { value: "8000", label: "8s" },
475
- { value: "15000", label: "15s" },
476
- { value: "0", label: "Never" }
477
- ]
478
- }
479
- ),
480
- /* @__PURE__ */ jsx2(Divider, {}),
481
- /* @__PURE__ */ jsx2(
482
- SelectSetting,
483
- {
484
- icon: /* @__PURE__ */ jsx2(Mic, { className: iconClass, style: iconStyle }),
485
- label: "STT timeout",
486
- value: String(settings.sttTimeoutMs),
487
- onChange: (v) => updateSetting("sttTimeoutMs", Number(v)),
488
- options: [
489
- { value: "10000", label: "10s" },
490
- { value: "15000", label: "15s" },
491
- { value: "30000", label: "30s" }
492
- ]
493
- }
494
- ),
495
- /* @__PURE__ */ jsx2(Divider, {}),
496
- /* @__PURE__ */ jsx2(
497
- SelectSetting,
498
- {
499
- icon: /* @__PURE__ */ jsx2(AudioLines, { className: iconClass, style: iconStyle }),
500
- label: "TTS timeout",
501
- value: String(settings.ttsTimeoutMs),
502
- onChange: (v) => updateSetting("ttsTimeoutMs", Number(v)),
503
- options: [
504
- { value: "30000", label: "30s" },
505
- { value: "55000", label: "55s" },
506
- { value: "90000", label: "90s" }
507
- ]
508
- }
509
- ),
510
- /* @__PURE__ */ jsx2(Divider, {}),
511
- /* @__PURE__ */ jsx2(
512
- SelectSetting,
513
- {
514
- icon: /* @__PURE__ */ jsx2(Sparkles, { className: iconClass, style: iconStyle }),
515
- label: "LLM timeout",
516
- value: String(settings.llmTimeoutMs),
517
- onChange: (v) => updateSetting("llmTimeoutMs", Number(v)),
518
- options: [
519
- { value: "10000", label: "10s" },
520
- { value: "20000", label: "20s" },
521
- { value: "30000", label: "30s" },
522
- { value: "60000", label: "60s" }
523
- ]
524
- }
525
- ),
526
- /* @__PURE__ */ jsx2(Divider, {}),
527
- /* @__PURE__ */ jsx2(
528
- SelectSetting,
529
- {
530
- icon: /* @__PURE__ */ jsx2(Signal, { className: iconClass, style: iconStyle }),
531
- label: "Min audio level",
532
- value: String(settings.minAudioRms),
533
- onChange: (v) => updateSetting("minAudioRms", Number(v)),
534
- options: [
535
- { value: "0.01", label: "Sensitive" },
536
- { value: "0.02", label: "Default" },
537
- { value: "0.035", label: "Moderate" },
538
- { value: "0.05", label: "Strict" }
539
- ]
540
- }
541
- )
542
- ] }),
543
- /* @__PURE__ */ jsx2(SettingsSection, { title: "Info", last: true, children: /* @__PURE__ */ jsxs("div", { className: "py-3 flex items-start gap-3", children: [
544
- /* @__PURE__ */ jsx2(Info, { className: iconClass, style: { ...iconStyle, marginTop: 2 } }),
545
- /* @__PURE__ */ jsx2("div", { className: "space-y-1 text-xs text-neutral-500", children: /* @__PURE__ */ jsxs("div", { children: [
546
- "VAD Threshold:",
547
- " ",
548
- /* @__PURE__ */ jsx2("span", { className: "font-medium text-neutral-700", children: VAD.positiveSpeechThreshold })
549
- ] }) })
550
- ] }) })
551
- ] })
552
- ]
553
- }
554
- );
555
- }
556
- function SettingsSection({
557
- title,
558
- children,
559
- last
560
- }) {
561
- return /* @__PURE__ */ jsxs("div", { style: { borderBottom: last ? "none" : "1px solid #e5e7eb" }, children: [
562
- /* @__PURE__ */ jsx2(
563
- "div",
564
- {
565
- className: "px-4 pt-4 pb-1 text-[11px] font-semibold uppercase tracking-wider",
566
- style: { color: "#9ca3af" },
567
- children: title
568
- }
569
- ),
570
- /* @__PURE__ */ jsx2("div", { className: "px-4", children })
571
- ] });
572
- }
573
- function Divider() {
574
- return /* @__PURE__ */ jsx2("div", { style: { height: 1, backgroundColor: "#f3f4f6" } });
575
- }
576
-
577
- export {
578
- VoiceSettingsProvider,
579
- useVoiceSettings,
580
- VoiceSettingsView
581
- };
582
- //# sourceMappingURL=chunk-MUFUZ3TH.js.map