@unctad-ai/voice-agent-ui 0.1.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/dist/VoiceAgentProvider.d.ts +6 -0
- package/dist/VoiceAgentProvider.d.ts.map +1 -0
- package/dist/VoiceAgentProvider.js +8 -0
- package/dist/VoiceAgentProvider.js.map +1 -0
- package/dist/components/AgentAvatar.d.ts +16 -0
- package/dist/components/AgentAvatar.d.ts.map +1 -0
- package/dist/components/AgentAvatar.js +186 -0
- package/dist/components/AgentAvatar.js.map +1 -0
- package/dist/components/GlassCopilotPanel.d.ts +13 -0
- package/dist/components/GlassCopilotPanel.d.ts.map +1 -0
- package/dist/components/GlassCopilotPanel.js +438 -0
- package/dist/components/GlassCopilotPanel.js.map +1 -0
- package/dist/components/PipelineMetricsBar.d.ts +7 -0
- package/dist/components/PipelineMetricsBar.d.ts.map +1 -0
- package/dist/components/PipelineMetricsBar.js +62 -0
- package/dist/components/PipelineMetricsBar.js.map +1 -0
- package/dist/components/VoiceA11yAnnouncer.d.ts +8 -0
- package/dist/components/VoiceA11yAnnouncer.d.ts.map +1 -0
- package/dist/components/VoiceA11yAnnouncer.js +32 -0
- package/dist/components/VoiceA11yAnnouncer.js.map +1 -0
- package/dist/components/VoiceControls.d.ts +9 -0
- package/dist/components/VoiceControls.d.ts.map +1 -0
- package/dist/components/VoiceControls.js +60 -0
- package/dist/components/VoiceControls.js.map +1 -0
- package/dist/components/VoiceCopilotFAB.d.ts +9 -0
- package/dist/components/VoiceCopilotFAB.d.ts.map +1 -0
- package/dist/components/VoiceCopilotFAB.js +12 -0
- package/dist/components/VoiceCopilotFAB.js.map +1 -0
- package/dist/components/VoiceDotRing.d.ts +9 -0
- package/dist/components/VoiceDotRing.d.ts.map +1 -0
- package/dist/components/VoiceDotRing.js +64 -0
- package/dist/components/VoiceDotRing.js.map +1 -0
- package/dist/components/VoiceErrorBoundary.d.ts +19 -0
- package/dist/components/VoiceErrorBoundary.d.ts.map +1 -0
- package/dist/components/VoiceErrorBoundary.js +24 -0
- package/dist/components/VoiceErrorBoundary.js.map +1 -0
- package/dist/components/VoiceErrorDisplay.d.ts +8 -0
- package/dist/components/VoiceErrorDisplay.d.ts.map +1 -0
- package/dist/components/VoiceErrorDisplay.js +94 -0
- package/dist/components/VoiceErrorDisplay.js.map +1 -0
- package/dist/components/VoiceOnboarding.d.ts +8 -0
- package/dist/components/VoiceOnboarding.d.ts.map +1 -0
- package/dist/components/VoiceOnboarding.js +28 -0
- package/dist/components/VoiceOnboarding.js.map +1 -0
- package/dist/components/VoiceOrb.d.ts +10 -0
- package/dist/components/VoiceOrb.d.ts.map +1 -0
- package/dist/components/VoiceOrb.js +236 -0
- package/dist/components/VoiceOrb.js.map +1 -0
- package/dist/components/VoiceOverlay.d.ts +9 -0
- package/dist/components/VoiceOverlay.d.ts.map +1 -0
- package/dist/components/VoiceOverlay.js +199 -0
- package/dist/components/VoiceOverlay.js.map +1 -0
- package/dist/components/VoiceSettingsView.d.ts +7 -0
- package/dist/components/VoiceSettingsView.d.ts.map +1 -0
- package/dist/components/VoiceSettingsView.js +109 -0
- package/dist/components/VoiceSettingsView.js.map +1 -0
- package/dist/components/VoiceToolCard.d.ts +11 -0
- package/dist/components/VoiceToolCard.d.ts.map +1 -0
- package/dist/components/VoiceToolCard.js +37 -0
- package/dist/components/VoiceToolCard.js.map +1 -0
- package/dist/components/VoiceTranscript.d.ts +13 -0
- package/dist/components/VoiceTranscript.d.ts.map +1 -0
- package/dist/components/VoiceTranscript.js +313 -0
- package/dist/components/VoiceTranscript.js.map +1 -0
- package/dist/components/VoiceWaveformCanvas.d.ts +9 -0
- package/dist/components/VoiceWaveformCanvas.d.ts.map +1 -0
- package/dist/components/VoiceWaveformCanvas.js +91 -0
- package/dist/components/VoiceWaveformCanvas.js.map +1 -0
- package/dist/contexts/VoiceSettingsContext.d.ts +37 -0
- package/dist/contexts/VoiceSettingsContext.d.ts.map +1 -0
- package/dist/contexts/VoiceSettingsContext.js +89 -0
- package/dist/contexts/VoiceSettingsContext.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +6 -0
- package/dist/utils.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { OrbState } from '@unctad-ai/voice-agent-core';
|
|
2
|
+
interface VoiceA11yAnnouncerProps {
|
|
3
|
+
isOpen: boolean;
|
|
4
|
+
orbState: OrbState;
|
|
5
|
+
}
|
|
6
|
+
export default function VoiceA11yAnnouncer({ isOpen, orbState }: VoiceA11yAnnouncerProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=VoiceA11yAnnouncer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceA11yAnnouncer.d.ts","sourceRoot":"","sources":["../../src/components/VoiceA11yAnnouncer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,UAAU,uBAAuB;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAUD,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,uBAAuB,2CA8BvF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
3
|
+
const STATE_ANNOUNCEMENTS = {
|
|
4
|
+
idle: 'Voice assistant ready',
|
|
5
|
+
listening: 'Listening for your question',
|
|
6
|
+
processing: 'Processing your request',
|
|
7
|
+
speaking: 'Assistant is responding',
|
|
8
|
+
error: 'An error occurred',
|
|
9
|
+
};
|
|
10
|
+
export default function VoiceA11yAnnouncer({ isOpen, orbState }) {
|
|
11
|
+
const prevOpen = useRef(isOpen);
|
|
12
|
+
const prevState = useRef(orbState);
|
|
13
|
+
const announceRef = useRef(null);
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (!announceRef.current)
|
|
16
|
+
return;
|
|
17
|
+
if (isOpen && !prevOpen.current) {
|
|
18
|
+
announceRef.current.textContent =
|
|
19
|
+
'Voice assistant opened. Press Escape to close. Use Ctrl+Shift+V to toggle.';
|
|
20
|
+
}
|
|
21
|
+
else if (!isOpen && prevOpen.current) {
|
|
22
|
+
announceRef.current.textContent = 'Voice assistant closed';
|
|
23
|
+
}
|
|
24
|
+
else if (isOpen && orbState !== prevState.current) {
|
|
25
|
+
announceRef.current.textContent = STATE_ANNOUNCEMENTS[orbState];
|
|
26
|
+
}
|
|
27
|
+
prevOpen.current = isOpen;
|
|
28
|
+
prevState.current = orbState;
|
|
29
|
+
}, [isOpen, orbState]);
|
|
30
|
+
return (_jsx("div", { ref: announceRef, "aria-live": "polite", "aria-atomic": "true", className: "sr-only", role: "status" }));
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=VoiceA11yAnnouncer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceA11yAnnouncer.js","sourceRoot":"","sources":["../../src/components/VoiceA11yAnnouncer.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAQ1C,MAAM,mBAAmB,GAA6B;IACpD,IAAI,EAAE,uBAAuB;IAC7B,SAAS,EAAE,6BAA6B;IACxC,UAAU,EAAE,yBAAyB;IACrC,QAAQ,EAAE,yBAAyB;IACnC,KAAK,EAAE,mBAAmB;CAC3B,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAA2B;IACtF,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,WAAW,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAEjD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,WAAW,CAAC,OAAO;YAAE,OAAO;QAEjC,IAAI,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YAChC,WAAW,CAAC,OAAO,CAAC,WAAW;gBAC7B,4EAA4E,CAAC;QACjF,CAAC;aAAM,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACvC,WAAW,CAAC,OAAO,CAAC,WAAW,GAAG,wBAAwB,CAAC;QAC7D,CAAC;aAAM,IAAI,MAAM,IAAI,QAAQ,KAAK,SAAS,CAAC,OAAO,EAAE,CAAC;YACpD,WAAW,CAAC,OAAO,CAAC,WAAW,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAClE,CAAC;QAED,QAAQ,CAAC,OAAO,GAAG,MAAM,CAAC;QAC1B,SAAS,CAAC,OAAO,GAAG,QAAQ,CAAC;IAC/B,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEvB,OAAO,CACL,cACE,GAAG,EAAE,WAAW,eACN,QAAQ,iBACN,MAAM,EAClB,SAAS,EAAC,SAAS,EACnB,IAAI,EAAC,QAAQ,GACb,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { VoiceState } from '@unctad-ai/voice-agent-core';
|
|
2
|
+
interface VoiceControlsProps {
|
|
3
|
+
state: VoiceState;
|
|
4
|
+
onTextSubmit: (text: string) => void;
|
|
5
|
+
isListening: boolean;
|
|
6
|
+
}
|
|
7
|
+
export default function VoiceControls({ state, onTextSubmit, isListening }: VoiceControlsProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=VoiceControls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceControls.d.ts","sourceRoot":"","sources":["../../src/components/VoiceControls.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,UAAU,kBAAkB;IAC1B,KAAK,EAAE,UAAU,CAAC;IAClB,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,WAAW,EAAE,OAAO,CAAC;CACtB;AAmBD,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,kBAAkB,2CA4J7F"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useEffect } from 'react';
|
|
3
|
+
import { motion, AnimatePresence } from 'motion/react';
|
|
4
|
+
import { Keyboard, Send, X } from 'lucide-react';
|
|
5
|
+
import { cn } from '../utils';
|
|
6
|
+
import { useSiteConfig } from '@unctad-ai/voice-agent-core';
|
|
7
|
+
const STATE_LABELS = {
|
|
8
|
+
IDLE: 'How can I help you?',
|
|
9
|
+
LISTENING: "I'm listening...",
|
|
10
|
+
USER_SPEAKING: 'Go ahead...',
|
|
11
|
+
PROCESSING: 'Let me look into that...',
|
|
12
|
+
AI_SPEAKING: "Here's what I found...",
|
|
13
|
+
};
|
|
14
|
+
/** Shared glass-pill style for control buttons */
|
|
15
|
+
const GLASS_PILL_BASE = cn('backdrop-blur-xl rounded-full', 'flex items-center justify-center', 'border border-white/15', 'transition-all duration-200 cursor-pointer', 'hover:border-white/30 hover:shadow-[0_0_16px_rgba(255,255,255,0.08)]');
|
|
16
|
+
export default function VoiceControls({ state, onTextSubmit, isListening }) {
|
|
17
|
+
const { colors } = useSiteConfig();
|
|
18
|
+
const [showTextInput, setShowTextInput] = useState(false);
|
|
19
|
+
const [text, setText] = useState('');
|
|
20
|
+
const inputRef = useRef(null);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (showTextInput)
|
|
23
|
+
inputRef.current?.focus();
|
|
24
|
+
}, [showTextInput]);
|
|
25
|
+
const handleSubmit = () => {
|
|
26
|
+
const trimmed = text.trim();
|
|
27
|
+
if (!trimmed)
|
|
28
|
+
return;
|
|
29
|
+
onTextSubmit(trimmed);
|
|
30
|
+
setText('');
|
|
31
|
+
setShowTextInput(false);
|
|
32
|
+
};
|
|
33
|
+
return (_jsx("div", { className: "w-full max-w-2xl mx-auto mt-auto pb-8 px-4", children: _jsx(AnimatePresence, { mode: "wait", children: showTextInput ? (_jsxs(motion.div, { initial: { opacity: 0, y: 16, scale: 0.95 }, animate: { opacity: 1, y: 0, scale: 1 }, exit: { opacity: 0, y: 16, scale: 0.95 }, transition: { duration: 0.25, ease: [0.22, 1, 0.36, 1] }, className: cn('rounded-full', 'flex items-center gap-4', 'border border-white/20', 'px-8 py-3'), style: {
|
|
34
|
+
backgroundColor: 'rgba(0, 0, 0, 0.4)',
|
|
35
|
+
backdropFilter: 'blur(16px) saturate(1.2)',
|
|
36
|
+
WebkitBackdropFilter: 'blur(16px) saturate(1.2)',
|
|
37
|
+
}, children: [_jsx("input", { ref: inputRef, type: "text", value: text, onChange: (e) => setText(e.target.value), onKeyDown: (e) => e.key === 'Enter' && handleSubmit(), placeholder: "Ask a question...", className: "flex-1 text-sm placeholder:text-white/40 min-w-0", style: {
|
|
38
|
+
color: 'white',
|
|
39
|
+
background: 'none',
|
|
40
|
+
border: 'none',
|
|
41
|
+
outline: 'none',
|
|
42
|
+
boxShadow: 'none',
|
|
43
|
+
WebkitAppearance: 'none',
|
|
44
|
+
padding: 0,
|
|
45
|
+
} }), _jsx(motion.button, { onClick: handleSubmit, whileTap: { scale: 0.9 }, className: "rounded-full p-2 text-white transition-colors cursor-pointer", style: { backgroundColor: colors.primary }, "aria-label": "Send message", children: _jsx(Send, { className: "h-4 w-4" }) }), _jsx("button", { onClick: () => {
|
|
46
|
+
setShowTextInput(false);
|
|
47
|
+
setText('');
|
|
48
|
+
}, className: "rounded-full p-2 text-white/60 hover:text-white hover:bg-white/10 transition-all cursor-pointer", "aria-label": "Cancel text input", children: _jsx(X, { className: "h-4 w-4" }) })] }, "text-input")) : (_jsx(motion.div, { initial: { opacity: 0, y: 16, scale: 0.95 }, animate: { opacity: 1, y: 0, scale: 1 }, exit: { opacity: 0, y: 16, scale: 0.95 }, transition: { duration: 0.25, ease: [0.22, 1, 0.36, 1] }, className: "flex items-center justify-center gap-3", children: _jsxs("div", { className: cn('rounded-full', 'text-white text-sm font-medium', 'flex items-center gap-6', 'border border-white/20', 'pl-8 pr-4 py-1.5'), style: {
|
|
49
|
+
backgroundColor: 'rgba(0, 0, 0, 0.4)',
|
|
50
|
+
backdropFilter: 'blur(16px) saturate(1.2)',
|
|
51
|
+
WebkitBackdropFilter: 'blur(16px) saturate(1.2)',
|
|
52
|
+
color: 'white',
|
|
53
|
+
}, children: [_jsxs("span", { className: "relative flex items-center justify-center w-3 h-3 ml-0.5", children: [isListening && (_jsx("span", { className: "absolute inset-0 rounded-full animate-ping", style: { backgroundColor: `${colors.primary}80` } })), _jsx("span", { className: cn('relative h-2.5 w-2.5 rounded-full transition-colors duration-300'), style: isListening ? {
|
|
54
|
+
backgroundColor: colors.primary,
|
|
55
|
+
boxShadow: `0 0 8px ${colors.primary}99`,
|
|
56
|
+
} : {
|
|
57
|
+
backgroundColor: 'rgba(255,255,255,0.3)',
|
|
58
|
+
} })] }), _jsx(AnimatePresence, { mode: "wait", children: _jsx(motion.span, { initial: { opacity: 0, y: 4 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -4 }, transition: { duration: 0.2 }, className: "pr-1", children: STATE_LABELS[state] }, state) }), _jsx("button", { onClick: () => setShowTextInput(true), className: cn('rounded-full p-2', 'text-white/60 hover:text-white', 'hover:bg-white/10', 'transition-all duration-200 cursor-pointer'), "aria-label": "Type a message", children: _jsx(Keyboard, { className: "h-4 w-4" }) })] }) }, "controls")) }) }));
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=VoiceControls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceControls.js","sourceRoot":"","sources":["../../src/components/VoiceControls.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface VoiceCopilotFABProps {
|
|
2
|
+
onClick: () => void;
|
|
3
|
+
isActive?: boolean;
|
|
4
|
+
isOverlayOpen?: boolean;
|
|
5
|
+
onMouseEnter?: () => void;
|
|
6
|
+
}
|
|
7
|
+
export default function VoiceCopilotFAB({ onClick, isActive, isOverlayOpen, onMouseEnter, }: VoiceCopilotFABProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=VoiceCopilotFAB.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceCopilotFAB.d.ts","sourceRoot":"","sources":["../../src/components/VoiceCopilotFAB.tsx"],"names":[],"mappings":"AAIA,UAAU,oBAAoB;IAC5B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,OAAO,EACP,QAAQ,EACR,aAAa,EACb,YAAY,GACb,EAAE,oBAAoB,2CAwCtB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { motion, AnimatePresence, useReducedMotion } from 'motion/react';
|
|
3
|
+
import { Mic } from 'lucide-react';
|
|
4
|
+
import { useSiteConfig } from '@unctad-ai/voice-agent-core';
|
|
5
|
+
export default function VoiceCopilotFAB({ onClick, isActive, isOverlayOpen, onMouseEnter, }) {
|
|
6
|
+
const prefersReduced = useReducedMotion();
|
|
7
|
+
const { colors } = useSiteConfig();
|
|
8
|
+
return (_jsx(AnimatePresence, { children: !isOverlayOpen && (_jsx(motion.div, { initial: { scale: 0, opacity: 0 }, animate: { scale: 1, opacity: 1 }, exit: { scale: 0, opacity: 0 }, transition: { duration: 0.25, ease: 'easeOut' }, className: "fixed bottom-6 right-6 z-50", children: _jsx(motion.button, { onClick: onClick, onMouseEnter: onMouseEnter, animate: prefersReduced ? {} : { scale: [1, 1.15, 1] }, transition: prefersReduced
|
|
9
|
+
? {}
|
|
10
|
+
: { scale: { duration: 1.5, repeat: Infinity, ease: 'easeInOut' } }, whileHover: { scale: 1.1 }, whileTap: { scale: 0.95 }, className: "relative rounded-full p-3 shadow-lg text-white transition-all cursor-pointer", style: { backgroundColor: colors.primary }, "aria-label": "Open voice assistant", children: isActive ? (_jsx("span", { className: "h-3 w-3 rounded-full bg-white animate-pulse" })) : (_jsx(Mic, { className: "w-6 h-6" })) }) }, "voice-fab-wrapper")) }));
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=VoiceCopilotFAB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceCopilotFAB.js","sourceRoot":"","sources":["../../src/components/VoiceCopilotFAB.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAS5D,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,OAAO,EACP,QAAQ,EACR,aAAa,EACb,YAAY,GACS;IACrB,MAAM,cAAc,GAAG,gBAAgB,EAAE,CAAC;IAC1C,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAC;IAEnC,OAAO,CACL,KAAC,eAAe,cACb,CAAC,aAAa,IAAI,CACjB,KAAC,MAAM,CAAC,GAAG,IAET,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EACjC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EACjC,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAC9B,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAC/C,SAAS,EAAC,6BAA6B,YAEvC,KAAC,MAAM,CAAC,MAAM,IACZ,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EACtD,UAAU,EACR,cAAc;oBACZ,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAEvE,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAC1B,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EACzB,SAAS,EAAC,8EAA8E,EACxF,KAAK,EAAE,EAAE,eAAe,EAAE,MAAM,CAAC,OAAO,EAAE,gBAC/B,sBAAsB,YAEhC,QAAQ,CAAC,CAAC,CAAC,CACV,eAAM,SAAS,EAAC,6CAA6C,GAAG,CACjE,CAAC,CAAC,CAAC,CACF,KAAC,GAAG,IAAC,SAAS,EAAC,SAAS,GAAG,CAC5B,GACa,IA3BZ,mBAAmB,CA4BZ,CACd,GACe,CACnB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { OrbState } from '@unctad-ai/voice-agent-core';
|
|
2
|
+
interface VoiceDotRingProps {
|
|
3
|
+
analyserNode: AnalyserNode | null;
|
|
4
|
+
state: OrbState;
|
|
5
|
+
orbRadius: number;
|
|
6
|
+
}
|
|
7
|
+
export default function VoiceDotRing({ analyserNode, state, orbRadius }: VoiceDotRingProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=VoiceDotRing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceDotRing.d.ts","sourceRoot":"","sources":["../../src/components/VoiceDotRing.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,UAAU,iBAAiB;IACzB,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,KAAK,EAAE,QAAQ,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAUD,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,iBAAiB,2CAuFzF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useEffect, useState } from 'react';
|
|
3
|
+
import { DOT_RING_COUNT, DOT_RING_GAP, DOT_RING_BASE_RADIUS, DOT_RING_PEAK_RADIUS, DOT_RING_SMOOTHING, } from '@unctad-ai/voice-agent-core';
|
|
4
|
+
const STATE_COLORS = {
|
|
5
|
+
idle: 'rgba(59,130,246,0.6)',
|
|
6
|
+
listening: 'rgba(219,33,41,0.8)',
|
|
7
|
+
processing: 'rgba(245,158,11,0.7)',
|
|
8
|
+
speaking: 'rgba(34,197,94,0.7)',
|
|
9
|
+
error: 'rgba(220,38,38,0.6)',
|
|
10
|
+
};
|
|
11
|
+
export default function VoiceDotRing({ analyserNode, state, orbRadius }) {
|
|
12
|
+
const dotsRef = useRef([]);
|
|
13
|
+
const barsRef = useRef(new Float32Array(DOT_RING_COUNT));
|
|
14
|
+
const rafRef = useRef(0);
|
|
15
|
+
const colorRef = useRef(STATE_COLORS.idle);
|
|
16
|
+
const [reducedMotion] = useState(() => window.matchMedia('(prefers-reduced-motion: reduce)').matches);
|
|
17
|
+
const ringRadius = orbRadius + DOT_RING_GAP;
|
|
18
|
+
const svgSize = (ringRadius + DOT_RING_PEAK_RADIUS + 2) * 2;
|
|
19
|
+
const cx = svgSize / 2;
|
|
20
|
+
const cy = svgSize / 2;
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const freqData = analyserNode ? new Uint8Array(analyserNode.frequencyBinCount) : null;
|
|
23
|
+
const tick = () => {
|
|
24
|
+
// Lerp color toward target
|
|
25
|
+
colorRef.current = STATE_COLORS[state];
|
|
26
|
+
if (analyserNode && freqData) {
|
|
27
|
+
analyserNode.getByteFrequencyData(freqData);
|
|
28
|
+
}
|
|
29
|
+
for (let i = 0; i < DOT_RING_COUNT; i++) {
|
|
30
|
+
const dot = dotsRef.current[i];
|
|
31
|
+
if (!dot)
|
|
32
|
+
continue;
|
|
33
|
+
let targetVal = 0;
|
|
34
|
+
if (freqData && freqData.length > 0) {
|
|
35
|
+
const binIndex = Math.floor((i / DOT_RING_COUNT) * freqData.length);
|
|
36
|
+
targetVal = freqData[binIndex] / 255;
|
|
37
|
+
}
|
|
38
|
+
barsRef.current[i] += (targetVal - barsRef.current[i]) * DOT_RING_SMOOTHING;
|
|
39
|
+
const val = reducedMotion ? 0 : barsRef.current[i];
|
|
40
|
+
const r = DOT_RING_BASE_RADIUS + val * (DOT_RING_PEAK_RADIUS - DOT_RING_BASE_RADIUS);
|
|
41
|
+
const opacity = 0.3 + val * 0.5;
|
|
42
|
+
dot.setAttribute('r', String(r));
|
|
43
|
+
dot.setAttribute('opacity', String(opacity));
|
|
44
|
+
dot.setAttribute('fill', colorRef.current);
|
|
45
|
+
}
|
|
46
|
+
rafRef.current = requestAnimationFrame(tick);
|
|
47
|
+
};
|
|
48
|
+
rafRef.current = requestAnimationFrame(tick);
|
|
49
|
+
return () => cancelAnimationFrame(rafRef.current);
|
|
50
|
+
}, [analyserNode, state, reducedMotion, ringRadius]);
|
|
51
|
+
return (_jsx("svg", { width: svgSize, height: svgSize, viewBox: `0 0 ${svgSize} ${svgSize}`, className: "absolute pointer-events-none", style: {
|
|
52
|
+
top: '50%',
|
|
53
|
+
left: '50%',
|
|
54
|
+
transform: 'translate(-50%, -50%)',
|
|
55
|
+
}, "aria-hidden": "true", children: Array.from({ length: DOT_RING_COUNT }, (_, i) => {
|
|
56
|
+
const angle = (i / DOT_RING_COUNT) * Math.PI * 2 - Math.PI / 2;
|
|
57
|
+
const x = cx + Math.cos(angle) * ringRadius;
|
|
58
|
+
const y = cy + Math.sin(angle) * ringRadius;
|
|
59
|
+
return (_jsx("circle", { ref: (el) => {
|
|
60
|
+
dotsRef.current[i] = el;
|
|
61
|
+
}, cx: x, cy: y, r: DOT_RING_BASE_RADIUS, fill: STATE_COLORS.idle, opacity: 0.3 }, i));
|
|
62
|
+
}) }));
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=VoiceDotRing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceDotRing.js","sourceRoot":"","sources":["../../src/components/VoiceDotRing.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Component } from 'react';
|
|
2
|
+
import type { ReactNode, ErrorInfo } from 'react';
|
|
3
|
+
interface Props {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
onReset?: () => void;
|
|
6
|
+
}
|
|
7
|
+
interface State {
|
|
8
|
+
hasError: boolean;
|
|
9
|
+
error: Error | null;
|
|
10
|
+
}
|
|
11
|
+
export default class VoiceErrorBoundary extends Component<Props, State> {
|
|
12
|
+
state: State;
|
|
13
|
+
static getDerivedStateFromError(error: Error): State;
|
|
14
|
+
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
15
|
+
handleReset: () => void;
|
|
16
|
+
render(): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=VoiceErrorBoundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceErrorBoundary.d.ts","sourceRoot":"","sources":["../../src/components/VoiceErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIlD,UAAU,KAAK;IACb,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,UAAU,KAAK;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC;IACrE,KAAK,EAAE,KAAK,CAAoC;IAEhD,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK;IAIpD,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS;IAI/C,WAAW,aAGT;IAEF,MAAM;CA0BP"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Component } from 'react';
|
|
3
|
+
import { cn } from '../utils';
|
|
4
|
+
import { AlertTriangle, RefreshCw } from 'lucide-react';
|
|
5
|
+
export default class VoiceErrorBoundary extends Component {
|
|
6
|
+
state = { hasError: false, error: null };
|
|
7
|
+
static getDerivedStateFromError(error) {
|
|
8
|
+
return { hasError: true, error };
|
|
9
|
+
}
|
|
10
|
+
componentDidCatch(error, info) {
|
|
11
|
+
console.error('Voice component error:', error, info.componentStack);
|
|
12
|
+
}
|
|
13
|
+
handleReset = () => {
|
|
14
|
+
this.setState({ hasError: false, error: null });
|
|
15
|
+
this.props.onReset?.();
|
|
16
|
+
};
|
|
17
|
+
render() {
|
|
18
|
+
if (this.state.hasError) {
|
|
19
|
+
return (_jsxs("div", { className: "flex flex-col items-center justify-center gap-4 p-8 text-center", children: [_jsx(AlertTriangle, { className: "h-10 w-10 text-red-400" }), _jsx("p", { className: "text-white text-lg", children: "Something went wrong with the voice assistant." }), _jsx("p", { className: "text-white/50 text-sm max-w-sm", children: this.state.error?.message || 'An unexpected error occurred.' }), _jsxs("button", { onClick: this.handleReset, className: cn('flex items-center gap-2 px-4 py-2', 'bg-white/10 backdrop-blur-md rounded-full', 'text-white text-sm hover:bg-white/20 transition-colors cursor-pointer'), children: [_jsx(RefreshCw, { className: "h-4 w-4" }), "Try again"] })] }));
|
|
20
|
+
}
|
|
21
|
+
return this.props.children;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=VoiceErrorBoundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceErrorBoundary.js","sourceRoot":"","sources":["../../src/components/VoiceErrorBoundary.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAYxD,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,SAAuB;IACrE,KAAK,GAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAEhD,MAAM,CAAC,wBAAwB,CAAC,KAAY;QAC1C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACnC,CAAC;IAED,iBAAiB,CAAC,KAAY,EAAE,IAAe;QAC7C,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;IACtE,CAAC;IAED,WAAW,GAAG,GAAG,EAAE;QACjB,IAAI,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;IACzB,CAAC,CAAC;IAEF,MAAM;QACJ,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YACxB,OAAO,CACL,eAAK,SAAS,EAAC,iEAAiE,aAC9E,KAAC,aAAa,IAAC,SAAS,EAAC,wBAAwB,GAAG,EACpD,YAAG,SAAS,EAAC,oBAAoB,+DAAmD,EACpF,YAAG,SAAS,EAAC,gCAAgC,YAC1C,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,IAAI,+BAA+B,GAC3D,EACJ,kBACE,OAAO,EAAE,IAAI,CAAC,WAAW,EACzB,SAAS,EAAE,EAAE,CACX,mCAAmC,EACnC,2CAA2C,EAC3C,uEAAuE,CACxE,aAED,KAAC,SAAS,IAAC,SAAS,EAAC,SAAS,GAAG,iBAE1B,IACL,CACP,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;IAC7B,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type VoiceErrorType = 'mic_denied' | 'mic_unavailable' | 'vad_load_failed' | 'stt_failed' | 'tts_failed' | 'network_error' | 'llm_failed' | 'speech_too_short' | 'not_addressed' | 'processing' | null;
|
|
2
|
+
interface VoiceErrorDisplayProps {
|
|
3
|
+
error: VoiceErrorType;
|
|
4
|
+
onDismiss: () => void;
|
|
5
|
+
}
|
|
6
|
+
export default function VoiceErrorDisplay({ error, onDismiss }: VoiceErrorDisplayProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=VoiceErrorDisplay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceErrorDisplay.d.ts","sourceRoot":"","sources":["../../src/components/VoiceErrorDisplay.tsx"],"names":[],"mappings":"AAIA,MAAM,MAAM,cAAc,GACtB,YAAY,GACZ,iBAAiB,GACjB,iBAAiB,GACjB,YAAY,GACZ,YAAY,GACZ,eAAe,GACf,YAAY,GACZ,kBAAkB,GAClB,eAAe,GACf,YAAY,GACZ,IAAI,CAAC;AAET,UAAU,sBAAsB;IAC9B,KAAK,EAAE,cAAc,CAAC;IACtB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAuFD,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,sBAAsB,2CAuCrF"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { motion, AnimatePresence } from 'motion/react';
|
|
3
|
+
import { AlertTriangle, Hourglass, Mic, MicOff, VolumeX, Wifi, WifiOff } from 'lucide-react';
|
|
4
|
+
import { cn } from '../utils';
|
|
5
|
+
const SEVERITY_STYLES = {
|
|
6
|
+
error: {
|
|
7
|
+
bg: 'rgba(220, 38, 38, 0.08)',
|
|
8
|
+
border: 'rgba(220, 38, 38, 0.15)',
|
|
9
|
+
icon: 'text-red-500',
|
|
10
|
+
text: 'text-red-700',
|
|
11
|
+
dismiss: 'text-red-400 hover:text-red-600',
|
|
12
|
+
},
|
|
13
|
+
warning: {
|
|
14
|
+
bg: 'rgba(217, 119, 6, 0.08)',
|
|
15
|
+
border: 'rgba(217, 119, 6, 0.15)',
|
|
16
|
+
icon: 'text-amber-500',
|
|
17
|
+
text: 'text-amber-700',
|
|
18
|
+
dismiss: 'text-amber-400 hover:text-amber-600',
|
|
19
|
+
},
|
|
20
|
+
info: {
|
|
21
|
+
bg: 'rgba(0, 0, 0, 0.04)',
|
|
22
|
+
border: 'rgba(0, 0, 0, 0.08)',
|
|
23
|
+
icon: 'text-neutral-500',
|
|
24
|
+
text: 'text-neutral-600',
|
|
25
|
+
dismiss: 'text-neutral-400 hover:text-neutral-600',
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
const ERROR_CONFIG = {
|
|
29
|
+
mic_denied: {
|
|
30
|
+
icon: MicOff,
|
|
31
|
+
title: 'Microphone access denied',
|
|
32
|
+
severity: 'error',
|
|
33
|
+
},
|
|
34
|
+
mic_unavailable: {
|
|
35
|
+
icon: MicOff,
|
|
36
|
+
title: 'No microphone found',
|
|
37
|
+
severity: 'error',
|
|
38
|
+
},
|
|
39
|
+
vad_load_failed: {
|
|
40
|
+
icon: AlertTriangle,
|
|
41
|
+
title: 'Voice detection unavailable',
|
|
42
|
+
severity: 'warning',
|
|
43
|
+
},
|
|
44
|
+
stt_failed: {
|
|
45
|
+
icon: Mic,
|
|
46
|
+
title: "Didn't catch that",
|
|
47
|
+
severity: 'info',
|
|
48
|
+
},
|
|
49
|
+
tts_failed: {
|
|
50
|
+
icon: AlertTriangle,
|
|
51
|
+
title: 'Voice response unavailable',
|
|
52
|
+
severity: 'warning',
|
|
53
|
+
},
|
|
54
|
+
network_error: {
|
|
55
|
+
icon: WifiOff,
|
|
56
|
+
title: 'Connection lost',
|
|
57
|
+
severity: 'error',
|
|
58
|
+
},
|
|
59
|
+
llm_failed: {
|
|
60
|
+
icon: Wifi,
|
|
61
|
+
title: 'AI service unavailable',
|
|
62
|
+
severity: 'error',
|
|
63
|
+
},
|
|
64
|
+
speech_too_short: {
|
|
65
|
+
icon: Mic,
|
|
66
|
+
title: "Didn't catch that",
|
|
67
|
+
severity: 'info',
|
|
68
|
+
},
|
|
69
|
+
not_addressed: {
|
|
70
|
+
icon: VolumeX,
|
|
71
|
+
title: 'Not addressed to me',
|
|
72
|
+
severity: 'info',
|
|
73
|
+
},
|
|
74
|
+
processing: {
|
|
75
|
+
icon: Hourglass,
|
|
76
|
+
title: 'Still processing...',
|
|
77
|
+
severity: 'info',
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
export default function VoiceErrorDisplay({ error, onDismiss }) {
|
|
81
|
+
return (_jsx(AnimatePresence, { children: error && (_jsx(motion.div, { initial: { opacity: 0, y: 16, scale: 0.95 }, animate: { opacity: 1, y: 0, scale: 1 }, exit: { opacity: 0, y: -8, scale: 0.95 }, transition: { duration: 0.25 }, className: cn('max-w-xs mx-auto', 'rounded-xl', 'px-4 py-2'), style: {
|
|
82
|
+
backgroundColor: SEVERITY_STYLES[ERROR_CONFIG[error].severity].bg,
|
|
83
|
+
border: `1px solid ${SEVERITY_STYLES[ERROR_CONFIG[error].severity].border}`,
|
|
84
|
+
backdropFilter: 'blur(12px)',
|
|
85
|
+
WebkitBackdropFilter: 'blur(12px)',
|
|
86
|
+
pointerEvents: 'auto',
|
|
87
|
+
}, children: (() => {
|
|
88
|
+
const config = ERROR_CONFIG[error];
|
|
89
|
+
const styles = SEVERITY_STYLES[config.severity];
|
|
90
|
+
const Icon = config.icon;
|
|
91
|
+
return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Icon, { className: cn('h-4 w-4 shrink-0', styles.icon) }), _jsx("span", { className: cn('text-xs flex-1', styles.text), children: config.title }), _jsx("button", { onClick: onDismiss, className: cn('text-xs transition-colors cursor-pointer', styles.dismiss), children: "\u00D7" })] }));
|
|
92
|
+
})() })) }));
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=VoiceErrorDisplay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceErrorDisplay.js","sourceRoot":"","sources":["../../src/components/VoiceErrorDisplay.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface VoiceOnboardingProps {
|
|
2
|
+
onTryNow: () => void;
|
|
3
|
+
/** Custom description text shown in the onboarding tooltip */
|
|
4
|
+
description?: string;
|
|
5
|
+
}
|
|
6
|
+
export default function VoiceOnboarding({ onTryNow, description }: VoiceOnboardingProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=VoiceOnboarding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceOnboarding.d.ts","sourceRoot":"","sources":["../../src/components/VoiceOnboarding.tsx"],"names":[],"mappings":"AAOA,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,oBAAoB,2CA0EtF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { motion, AnimatePresence } from 'motion/react';
|
|
4
|
+
import { cn } from '../utils';
|
|
5
|
+
import { useSiteConfig } from '@unctad-ai/voice-agent-core';
|
|
6
|
+
const STORAGE_KEY = 'voice-onboarding-dismissed';
|
|
7
|
+
export default function VoiceOnboarding({ onTryNow, description }) {
|
|
8
|
+
const { colors } = useSiteConfig();
|
|
9
|
+
const [show, setShow] = useState(false);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
const dismissed = localStorage.getItem(STORAGE_KEY);
|
|
12
|
+
if (!dismissed) {
|
|
13
|
+
// Small delay so FAB renders first
|
|
14
|
+
const timer = setTimeout(() => setShow(true), 1500);
|
|
15
|
+
return () => clearTimeout(timer);
|
|
16
|
+
}
|
|
17
|
+
}, []);
|
|
18
|
+
const dismiss = () => {
|
|
19
|
+
setShow(false);
|
|
20
|
+
localStorage.setItem(STORAGE_KEY, 'true');
|
|
21
|
+
};
|
|
22
|
+
const handleTryNow = () => {
|
|
23
|
+
dismiss();
|
|
24
|
+
onTryNow();
|
|
25
|
+
};
|
|
26
|
+
return (_jsx(AnimatePresence, { children: show && (_jsxs(motion.div, { initial: { opacity: 0, y: 8, scale: 0.95 }, animate: { opacity: 1, y: 0, scale: 1 }, exit: { opacity: 0, y: 8, scale: 0.95 }, transition: { duration: 0.25, ease: 'easeOut' }, className: cn('fixed bottom-24 right-6 z-50', 'md:bottom-[104px] md:right-6', 'bg-white rounded-xl shadow-xl', 'border border-neutral-200', 'p-4 max-w-[280px]'), role: "tooltip", children: [_jsx("div", { className: "absolute -bottom-2 right-6 w-4 h-4 bg-white border-b border-r border-neutral-200 rotate-45" }), _jsx("p", { className: "text-sm text-neutral-700 leading-relaxed mb-3", children: description ?? 'Meet your AI assistant. Ask about services, permits, or opportunities.' }), _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { onClick: handleTryNow, className: cn('text-white text-sm font-medium', 'rounded-lg px-3 py-1.5', 'transition-colors cursor-pointer'), style: { backgroundColor: colors.primary }, children: "Try it now" }), _jsx("button", { onClick: dismiss, className: cn('text-neutral-500 text-sm', 'rounded-lg px-3 py-1.5', 'hover:text-neutral-700 hover:bg-neutral-100', 'transition-colors cursor-pointer'), children: "Maybe later" })] })] })) }));
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=VoiceOnboarding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceOnboarding.js","sourceRoot":"","sources":["../../src/components/VoiceOnboarding.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,WAAW,GAAG,4BAA4B,CAAC;AAQjD,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAwB;IACrF,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAExC,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACpD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,mCAAmC;YACnC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;YACpD,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,OAAO,CAAC,KAAK,CAAC,CAAC;QACf,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC5C,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,OAAO,EAAE,CAAC;QACV,QAAQ,EAAE,CAAC;IACb,CAAC,CAAC;IAEF,OAAO,CACL,KAAC,eAAe,cACb,IAAI,IAAI,CACP,MAAC,MAAM,CAAC,GAAG,IACT,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAC1C,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EACvC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EACvC,UAAU,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAC/C,SAAS,EAAE,EAAE,CACX,8BAA8B,EAC9B,8BAA8B,EAC9B,+BAA+B,EAC/B,2BAA2B,EAC3B,mBAAmB,CACpB,EACD,IAAI,EAAC,SAAS,aAGd,cAAK,SAAS,EAAC,4FAA4F,GAAG,EAE9G,YAAG,SAAS,EAAC,+CAA+C,YACzD,WAAW,IAAI,wEAAwE,GACtF,EACJ,eAAK,SAAS,EAAC,YAAY,aACzB,iBACE,OAAO,EAAE,YAAY,EACrB,SAAS,EAAE,EAAE,CACX,gCAAgC,EAChC,wBAAwB,EACxB,kCAAkC,CACnC,EACD,KAAK,EAAE,EAAE,eAAe,EAAE,MAAM,CAAC,OAAO,EAAE,2BAGnC,EACT,iBACE,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,EAAE,CACX,0BAA0B,EAC1B,wBAAwB,EACxB,6CAA6C,EAC7C,kCAAkC,CACnC,4BAGM,IACL,IACK,CACd,GACe,CACnB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { OrbState } from '@unctad-ai/voice-agent-core';
|
|
2
|
+
interface VoiceOrbProps {
|
|
3
|
+
state: OrbState;
|
|
4
|
+
/** Getter function called each animation frame — avoids 60fps React re-renders */
|
|
5
|
+
getAmplitude: () => number;
|
|
6
|
+
size?: number;
|
|
7
|
+
}
|
|
8
|
+
export default function VoiceOrb({ state, getAmplitude, size }: VoiceOrbProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=VoiceOrb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceOrb.d.ts","sourceRoot":"","sources":["../../src/components/VoiceOrb.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,UAAU,aAAa;IACrB,KAAK,EAAE,QAAQ,CAAC;IAChB,kFAAkF;IAClF,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAiHD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,IAAU,EAAE,EAAE,aAAa,2CAyNlF"}
|