@navsi.ai/sdk 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,6 +19,9 @@ For **Next.js** projects, ensure `next` is installed (optional peer dependency):
19
19
 
20
20
  ## Quick Start
21
21
 
22
+ > **Zero-config styling** — All widget styles are auto-injected at runtime.
23
+ > You do **not** need to import any CSS file.
24
+
22
25
  ```tsx
23
26
  import { ChatbotProvider, ChatbotWidget } from '@navsi.ai/sdk';
24
27
 
@@ -35,6 +38,89 @@ function App() {
35
38
  }
36
39
  ```
37
40
 
41
+ ### Overriding Default Styles
42
+
43
+ The SDK auto-injects its styles in a `<style>` tag at the top of `<head>`. Any CSS you add in your own stylesheet will automatically take precedence. All widget classes are prefixed `navsi-chatbot-*`.
44
+
45
+ ```css
46
+ /* Example: custom toggle button */
47
+ .navsi-chatbot-toggle {
48
+ background: #e11d48;
49
+ box-shadow: 0 4px 16px rgba(225, 29, 72, 0.4);
50
+ }
51
+
52
+ /* Example: custom chat window size */
53
+ .navsi-chatbot-window {
54
+ width: 420px;
55
+ height: 600px;
56
+ }
57
+ ```
58
+
59
+ #### Available CSS Classes
60
+
61
+ | Class Name | Element |
62
+ | ------------------------------------ | ------------------------------------ |
63
+ | `.navsi-chatbot-container` | Root fixed-position container |
64
+ | `.navsi-chatbot-toggle` | Floating open/close button |
65
+ | `.navsi-chatbot-window` | Chat window panel |
66
+ | `.navsi-chatbot-header` | Window header bar |
67
+ | `.navsi-chatbot-header-left` | Header left section (title + status) |
68
+ | `.navsi-chatbot-title` | Header title text |
69
+ | `.navsi-chatbot-status` | Connection status text |
70
+ | `.navsi-chatbot-clear` | "Clear" chat button |
71
+ | `.navsi-chatbot-mode-toggle` | Ask/Action mode toggle container |
72
+ | `.navsi-chatbot-mode-button` | Individual mode button |
73
+ | `.navsi-chatbot-mode-active` | Active mode button |
74
+ | `.navsi-chatbot-lang-toggle` | Language toggle container |
75
+ | `.navsi-chatbot-lang-button` | Individual language button |
76
+ | `.navsi-chatbot-lang-active` | Active language button |
77
+ | `.navsi-chatbot-messages` | Messages scroll area |
78
+ | `.navsi-chatbot-message` | Individual message wrapper |
79
+ | `.navsi-chatbot-message-user` | User message bubble |
80
+ | `.navsi-chatbot-message-assistant` | Assistant message bubble |
81
+ | `.navsi-chatbot-message-content` | Message content (markdown) |
82
+ | `.navsi-chatbot-message-paragraph` | Paragraph inside assistant message |
83
+ | `.navsi-chatbot-message-list` | Bullet list inside assistant message |
84
+ | `.navsi-chatbot-message-list-item` | List item inside assistant message |
85
+ | `.navsi-chatbot-welcome` | Welcome screen container |
86
+ | `.navsi-chatbot-welcome-icon` | Welcome emoji icon |
87
+ | `.navsi-chatbot-welcome-text` | Welcome message text |
88
+ | `.navsi-chatbot-welcome-hint` | Welcome hint/subtitle |
89
+ | `.navsi-chatbot-input-area` | Input area container |
90
+ | `.navsi-chatbot-input` | Text input field |
91
+ | `.navsi-chatbot-send-button` | Send button |
92
+ | `.navsi-chatbot-voice-button` | Voice input button |
93
+ | `.navsi-chatbot-voice-button-active` | Voice button while recording |
94
+ | `.navsi-chatbot-stop-button` | Stop execution button |
95
+ | `.navsi-chatbot-error` | Error banner |
96
+ | `.navsi-chatbot-error-close` | Error dismiss button |
97
+ | `.navsi-chatbot-voice-error` | Voice error message |
98
+ | `.navsi-chatbot-voice-transcript` | Live voice transcript |
99
+ | `.navsi-chatbot-voice-indicator` | Header voice indicator |
100
+ | `.navsi-chatbot-banner` | Execution status banner |
101
+ | `.navsi-chatbot-pill` | Progress step pill |
102
+ | `.navsi-chatbot-progress-container` | Progress bar wrapper |
103
+ | `.navsi-chatbot-progress-bar` | Progress bar track |
104
+ | `.navsi-chatbot-progress-fill` | Progress bar fill |
105
+ | `.navsi-chatbot-typing` | Typing dots indicator |
106
+
107
+ #### CSS Custom Properties
108
+
109
+ You can also set these CSS variables on `.navsi-chatbot-container` (or let the `theme` config set them automatically):
110
+
111
+ | Variable | Default | Description |
112
+ | ----------------------- | ----------------- | ------------------------------------- |
113
+ | `--navsi-primary` | `#2563eb` | Primary brand colour |
114
+ | `--navsi-primary-hover` | `#1d4ed8` | Primary hover colour |
115
+ | `--navsi-bg` | `#ffffff` | Window background |
116
+ | `--navsi-text` | `#1f2937` | Text colour |
117
+ | `--navsi-font` | System font stack | Font family |
118
+ | `--navsi-radius` | `12px` | Border radius (window, bubbles) |
119
+ | `--navsi-radius-sm` | `6px` | Small border radius (inputs, buttons) |
120
+ | `--navsi-window-width` | `360px` | Chat window width |
121
+ | `--navsi-window-height` | `520px` | Chat window height |
122
+ | `--navsi-button-size` | `56px` | Toggle button size |
123
+
38
124
  ### With Configuration Fetching
39
125
 
40
126
  For a complete setup with widget configuration from your server:
@@ -0,0 +1,2 @@
1
+ import {createContext,useContext,useMemo,useState,useRef,useEffect,useCallback}from'react';var F=createContext(null);function d(){let e=useContext(F);if(!e)throw new Error("useChatbotContext must be used within a ChatbotProvider");return e}function J(){let e=d();return {widgetConfig:e.widgetConfig,voiceLanguage:e.voiceLanguage,setVoiceLanguage:e.setVoiceLanguage,messages:e.messages,sendMessage:e.sendMessage,clearMessages:e.clearMessages,mode:e.mode,setMode:e.setMode,isWidgetOpen:e.isWidgetOpen,setWidgetOpen:e.setWidgetOpen,isConnected:e.isConnected,connect:e.connect,disconnect:e.disconnect,executeAction:e.executeAction,registerServerAction:e.registerServerAction,stopExecution:e.stopExecution,isExecuting:e.isExecuting,error:e.error,clearError:e.clearError}}function X(){let e=d(),l=e.executionState?{current:e.executionState.currentIndex,total:e.executionState.totalCommands,percentage:e.executionState.totalCommands>0?Math.round(e.executionState.currentIndex/e.executionState.totalCommands*100):0,description:e.executionState.description}:null;return {isExecuting:e.isExecuting,executionState:e.executionState,currentCommand:e.executionState?.currentCommand,progress:l}}function ne(){let e=d();return {connectionState:e.connectionState,isConnected:e.connectionState==="connected",isConnecting:e.connectionState==="connecting",isReconnecting:e.connectionState==="reconnecting",connect:e.connect,disconnect:e.disconnect}}function D(){if(typeof window>"u")return null;let e=window;return e.SpeechRecognition??e.webkitSpeechRecognition??null}var H=typeof navigator<"u"&&"brave"in navigator;function Y(e){switch(e){case "network":return typeof navigator<"u"&&!navigator.onLine?"You appear to be offline \u2014 voice needs a network connection.":H?"Brave may block speech services. Disable Shields or try Chrome/Edge.":typeof window<"u"&&window.location.protocol!=="https:"&&!["localhost","127.0.0.1"].includes(window.location.hostname)?"Microphone access requires HTTPS.":"Network error \u2014 check mic permissions and reload.";case "not-allowed":case "service-not-allowed":return "Microphone permission is blocked.";case "no-speech":return "No speech detected \u2014 try again.";case "audio-capture":return "No microphone found.";case "aborted":return "";default:return `Voice error: ${e}`}}function _(e){return e.replace(/\*\*(.*?)\*\*/g,"$1").replace(/[*_~`#]/g,"").replace(/\[([^\]]+)\]\([^)]+\)/g,"$1").replace(/\n{2,}/g,". ").trim()}function re({lang:e,onTranscript:l,silenceMs:R=1200,autoSpeak:E=true}){let g=useMemo(D,[]),[x,p]=useState(false),[L,w]=useState(""),[V,f]=useState(null),[U,h]=useState(false),i=useRef(null),s=useRef(""),S=useRef(null),y=useRef(l),m=useRef(e),M=useRef(false),t=useRef(true);y.current=l,m.current=e,useEffect(()=>{if(M.current||typeof window>"u"||!("speechSynthesis"in window))return;M.current=true;let n=new SpeechSynthesisUtterance("");n.volume=0,window.speechSynthesis.speak(n);},[]);let c=useCallback(()=>{S.current&&(clearTimeout(S.current),S.current=null);},[]),C=useCallback(()=>{let n=s.current.trim();s.current="",t.current&&(w(""),n&&y.current(n));},[]),k=useCallback(()=>{if(!g)return null;if(i.current)return i.current.lang=m.current,i.current;let n=new g;return n.continuous=true,n.interimResults=true,n.maxAlternatives=1,n.lang=m.current,n.onstart=()=>{t.current&&(p(true),f(null),w(""),s.current="",typeof window<"u"&&"speechSynthesis"in window&&window.speechSynthesis.cancel());},n.onresult=r=>{if(!t.current)return;let o="";for(let b=r.resultIndex;b<r.results.length;b++){let A=r.results[b],W=A[0]?.transcript??"";A.isFinal?s.current=(s.current+" "+W).trim():o+=W;}w(s.current?s.current:o.trim()),c(),S.current=setTimeout(()=>{t.current&&(i.current?.stop(),C(),p(false));},R);},n.onerror=r=>{if(!t.current)return;let o=Y(r.error);o&&f(o),["not-allowed","service-not-allowed","audio-capture"].includes(r.error)&&(c(),p(false));},n.onend=()=>{t.current&&(c(),C(),p(false));},i.current=n,n},[g,c,C,R]),O=useCallback(()=>{if(x)return;f(null);let n=k();if(!n){f("Voice input is not supported in this browser.");return}try{n.start();}catch{}},[x,k]),T=useCallback(()=>{c();try{i.current?.stop();}catch{}},[c]),P=useCallback(n=>{if(typeof window>"u"||!("speechSynthesis"in window)||!E)return;let r=_(n);if(!r)return;window.speechSynthesis.cancel();let o=new SpeechSynthesisUtterance(r);o.lang=m.current,o.onstart=()=>{t.current&&h(true);},o.onend=()=>{t.current&&h(false);},o.onerror=()=>{t.current&&h(false);},window.speechSynthesis.speak(o);},[E]),B=useCallback(()=>{typeof window<"u"&&"speechSynthesis"in window&&window.speechSynthesis.cancel(),t.current&&h(false);},[]);return useEffect(()=>(t.current=true,()=>{t.current=false,c(),i.current?.abort(),i.current=null,typeof window<"u"&&"speechSynthesis"in window&&window.speechSynthesis.cancel();}),[c]),{isSupported:!!g,isListening:x,transcript:L,error:V,start:O,stop:T,speak:P,cancelSpeech:B,isSpeaking:U}}export{F as a,d as b,J as c,X as d,ne as e,re as f};//# sourceMappingURL=chunk-BM6443KF.js.map
2
+ //# sourceMappingURL=chunk-BM6443KF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/context/chatbot-context.tsx","../src/hooks/useChatbot.ts","../src/hooks/useActionExecution.ts","../src/hooks/useWebSocket.ts","../src/hooks/useVoice.ts"],"names":["ChatbotContext","createContext","useChatbotContext","context","useContext","useChatbot","useActionExecution","progress","useWebSocket","getRecognitionCtor","w","isBrave","friendlyError","code","stripMarkdown","text","useVoice","lang","onTranscript","silenceMs","autoSpeak","Ctor","useMemo","isListening","setIsListening","useState","transcript","setTranscript","error","setError","isSpeaking","setIsSpeaking","recRef","useRef","finalBuf","silenceTimer","onTranscriptRef","langRef","ttsWarm","mountedRef","useEffect","u","clearSilence","useCallback","flushTranscript","getOrCreateRec","rec","ev","interim","i","seg","msg","start","stop","speak","clean","cancelSpeech"],"mappings":"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","file":"chunk-BM6443KF.js","sourcesContent":["/**\n * Chatbot Context\n * \n * React context for chatbot state and functionality.\n */\n\nimport { createContext, useContext } from 'react';\nimport type {\n Message,\n ChatMode,\n ConnectionState,\n ServerAction,\n ExecutionState,\n WidgetConfig,\n} from '@navsi.ai/shared';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ChatbotContextValue {\n /** Widget styling and copy (from admin / API). Applied by ChatbotWidget. */\n widgetConfig: Partial<WidgetConfig> | null;\n\n // State\n messages: Message[];\n mode: ChatMode;\n connectionState: ConnectionState;\n isExecuting: boolean;\n executionState: ExecutionState | null;\n error: Error | null;\n\n // Widget visibility (persists across navigation)\n isWidgetOpen: boolean;\n setWidgetOpen: (open: boolean) => void;\n\n /** User-selected voice/response language (e.g. 'en-US', 'hi-IN'). Overrides widgetConfig.voiceLanguage when set. */\n voiceLanguage: string | undefined;\n setVoiceLanguage: (lang: string | undefined) => void;\n\n // Actions\n sendMessage: (content: string) => void;\n setMode: (mode: ChatMode) => void;\n executeAction: (actionId: string, params?: Record<string, unknown>) => Promise<unknown>;\n registerServerAction: (action: ServerAction) => void;\n clearMessages: () => void;\n clearError: () => void;\n stopExecution: () => void;\n\n // Connection\n connect: () => void;\n disconnect: () => void;\n isConnected: boolean;\n}\n\n// ============================================================================\n// Context\n// ============================================================================\n\nexport const ChatbotContext = createContext<ChatbotContextValue | null>(null);\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Hook to access chatbot context\n * Must be used within ChatbotProvider\n */\nexport function useChatbotContext(): ChatbotContextValue {\n const context = useContext(ChatbotContext);\n\n if (!context) {\n throw new Error('useChatbotContext must be used within a ChatbotProvider');\n }\n\n return context;\n}\n","/**\n * useChatbot Hook\n * \n * Main hook for accessing chatbot functionality.\n * Provides simplified API for common operations.\n */\n\nimport { useChatbotContext } from '../context/chatbot-context.js';\nimport type { ChatMode, ServerAction, Message, WidgetConfig } from '@navsi.ai/shared';\n\nexport interface UseChatbotReturn {\n /** Widget styling/copy from admin (or options). Use in ChatbotWidget. */\n widgetConfig: Partial<WidgetConfig> | null;\n\n /** Effective voice/response language (user-selected or config). Use for STT/TTS and locale. */\n voiceLanguage: string | undefined;\n setVoiceLanguage: (lang: string | undefined) => void;\n\n // Messages\n messages: Message[];\n sendMessage: (content: string) => void;\n clearMessages: () => void;\n\n // Mode\n mode: ChatMode;\n setMode: (mode: ChatMode) => void;\n\n // Widget visibility (persists across navigation)\n isWidgetOpen: boolean;\n setWidgetOpen: (open: boolean) => void;\n\n // Connection\n isConnected: boolean;\n connect: () => void;\n disconnect: () => void;\n\n // Actions\n executeAction: (actionId: string, params?: Record<string, unknown>) => Promise<unknown>;\n registerServerAction: (action: ServerAction) => void;\n stopExecution: () => void;\n\n // State\n isExecuting: boolean;\n error: Error | null;\n clearError: () => void;\n}\n\n/**\n * Main hook for chatbot functionality\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { \n * messages, \n * sendMessage, \n * isConnected,\n * mode,\n * setMode,\n * } = useChatbot();\n * \n * return (\n * <div>\n * <button onClick={() => sendMessage('Hello!')}>\n * Send\n * </button>\n * <button onClick={() => startVoice()}>\n * Start Voice\n * </button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useChatbot(): UseChatbotReturn {\n const context = useChatbotContext();\n\n return {\n widgetConfig: context.widgetConfig,\n voiceLanguage: context.voiceLanguage,\n setVoiceLanguage: context.setVoiceLanguage,\n // Messages\n messages: context.messages,\n sendMessage: context.sendMessage,\n clearMessages: context.clearMessages,\n\n // Mode\n mode: context.mode,\n setMode: context.setMode,\n\n // Widget visibility\n isWidgetOpen: context.isWidgetOpen,\n setWidgetOpen: context.setWidgetOpen,\n\n // Connection\n isConnected: context.isConnected,\n connect: context.connect,\n disconnect: context.disconnect,\n\n // Actions\n executeAction: context.executeAction,\n registerServerAction: context.registerServerAction,\n stopExecution: context.stopExecution,\n\n // State\n isExecuting: context.isExecuting,\n error: context.error,\n clearError: context.clearError,\n };\n}\n","/**\n * useActionExecution Hook\n * \n * Hook for monitoring action execution state.\n */\n\nimport { useChatbotContext } from '../context/chatbot-context.js';\nimport type { ExecutionState } from '@navsi.ai/shared';\n\nexport interface UseActionExecutionReturn {\n isExecuting: boolean;\n executionState: ExecutionState | null;\n currentCommand: ExecutionState['currentCommand'] | undefined;\n progress: {\n current: number;\n total: number;\n percentage: number;\n /** Optional human-readable description of the current step */\n description?: string;\n } | null;\n}\n\n/**\n * Hook for monitoring action execution\n */\nexport function useActionExecution(): UseActionExecutionReturn {\n const context = useChatbotContext();\n\n const progress = context.executionState\n ? {\n current: context.executionState.currentIndex,\n total: context.executionState.totalCommands,\n percentage: context.executionState.totalCommands > 0\n ? Math.round((context.executionState.currentIndex / context.executionState.totalCommands) * 100)\n : 0,\n description: context.executionState.description,\n }\n : null;\n\n return {\n isExecuting: context.isExecuting,\n executionState: context.executionState,\n currentCommand: context.executionState?.currentCommand,\n progress,\n };\n}\n","/**\n * useWebSocket Hook\n * \n * Hook for managing WebSocket connection state.\n */\n\nimport { useChatbotContext } from '../context/chatbot-context.js';\nimport type { ConnectionState } from '@navsi.ai/shared';\n\nexport interface UseWebSocketReturn {\n connectionState: ConnectionState;\n isConnected: boolean;\n isConnecting: boolean;\n isReconnecting: boolean;\n connect: () => void;\n disconnect: () => void;\n}\n\n/**\n * Hook for WebSocket connection management\n */\nexport function useWebSocket(): UseWebSocketReturn {\n const context = useChatbotContext();\n\n return {\n connectionState: context.connectionState,\n isConnected: context.connectionState === 'connected',\n isConnecting: context.connectionState === 'connecting',\n isReconnecting: context.connectionState === 'reconnecting',\n connect: context.connect,\n disconnect: context.disconnect,\n };\n}\n","/**\n * useVoice Hook — Low-latency STT + TTS for the Navsi chatbot.\n *\n * Design goals:\n * • Fast start: reuses a single SpeechRecognition instance across activations.\n * • Low latency: fires an auto-send after a configurable silence gap so the\n * user doesn't have to wait for the browser's default end-of-speech timeout.\n * • Clean separation: all voice state is encapsulated here; ChatbotWidget\n * only consumes the returned API.\n * • TTS warm-up: a silent utterance is queued once so the first real TTS play\n * doesn't incur a cold-start delay.\n *\n * Only depends on the Web Speech API — no extra packages.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\n// ---------------------------------------------------------------------------\n// Web Speech API type shims (not all TS libs ship these)\n// ---------------------------------------------------------------------------\n\ntype SpeechRecognitionCtor = new () => SpeechRecognitionInstance;\n\ninterface SpeechRecognitionInstance extends EventTarget {\n continuous: boolean;\n interimResults: boolean;\n maxAlternatives: number;\n lang: string;\n onstart: ((ev: Event) => void) | null;\n onend: ((ev: Event) => void) | null;\n onerror: ((ev: SpeechRecognitionErrorEvent) => void) | null;\n onresult: ((ev: SpeechRecognitionResultEvent) => void) | null;\n start: () => void;\n stop: () => void;\n abort: () => void;\n}\n\ninterface SpeechRecognitionErrorEvent extends Event {\n error: string;\n}\n\ninterface SpeechRecognitionResultEvent extends Event {\n resultIndex: number;\n results: SpeechRecognitionResultList;\n}\n\ninterface SpeechRecognitionResultList {\n length: number;\n [index: number]: SpeechRecognitionResultItem;\n}\n\ninterface SpeechRecognitionResultItem {\n isFinal: boolean;\n length: number;\n [index: number]: { transcript: string };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getRecognitionCtor(): SpeechRecognitionCtor | null {\n if (typeof window === 'undefined') return null;\n const w = window as Window & {\n SpeechRecognition?: SpeechRecognitionCtor;\n webkitSpeechRecognition?: SpeechRecognitionCtor;\n };\n return w.SpeechRecognition ?? w.webkitSpeechRecognition ?? null;\n}\n\nconst isBrave = typeof navigator !== 'undefined' && 'brave' in navigator;\n\nfunction friendlyError(code: string): string {\n switch (code) {\n case 'network': {\n if (typeof navigator !== 'undefined' && !navigator.onLine)\n return 'You appear to be offline — voice needs a network connection.';\n if (isBrave)\n return 'Brave may block speech services. Disable Shields or try Chrome/Edge.';\n if (\n typeof window !== 'undefined' &&\n window.location.protocol !== 'https:' &&\n !['localhost', '127.0.0.1'].includes(window.location.hostname)\n )\n return 'Microphone access requires HTTPS.';\n return 'Network error — check mic permissions and reload.';\n }\n case 'not-allowed':\n case 'service-not-allowed':\n return 'Microphone permission is blocked.';\n case 'no-speech':\n return 'No speech detected — try again.';\n case 'audio-capture':\n return 'No microphone found.';\n case 'aborted':\n return ''; // intentional abort — don't show an error\n default:\n return `Voice error: ${code}`;\n }\n}\n\n/** Strip markdown formatting so TTS reads clean text. */\nfunction stripMarkdown(text: string): string {\n return text\n .replace(/\\*\\*(.*?)\\*\\*/g, '$1') // bold\n .replace(/[*_~`#]/g, '') // residual markers\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, '$1') // links → label only\n .replace(/\\n{2,}/g, '. ') // paragraph breaks → pause\n .trim();\n}\n\n// ---------------------------------------------------------------------------\n// Public API types\n// ---------------------------------------------------------------------------\n\nexport interface UseVoiceOptions {\n /** BCP-47 language for STT & TTS (e.g. 'en-US'). */\n lang: string;\n /** Called with the final transcript when the user finishes speaking. */\n onTranscript: (text: string) => void;\n /** Milliseconds of silence before auto-sending (default 1200). */\n silenceMs?: number;\n /** Whether TTS should speak new assistant messages triggered by voice input. */\n autoSpeak?: boolean;\n}\n\nexport interface UseVoiceReturn {\n /** Whether the Web Speech API is available in this browser. */\n isSupported: boolean;\n /** Whether the mic is currently active / recording. */\n isListening: boolean;\n /** Live interim transcript while recording. */\n transcript: string;\n /** Human-readable error, or null. */\n error: string | null;\n /** Start recording. No-op if already listening. */\n start: () => void;\n /** Stop recording (fires onTranscript if there is accumulated text). */\n stop: () => void;\n /** Speak text aloud via TTS. */\n speak: (text: string) => void;\n /** Cancel any ongoing TTS playback. */\n cancelSpeech: () => void;\n /** Whether TTS is currently speaking. */\n isSpeaking: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\nexport function useVoice({\n lang,\n onTranscript,\n silenceMs = 1200,\n autoSpeak = true,\n}: UseVoiceOptions): UseVoiceReturn {\n // ---- constructor (stable across renders) ----\n const Ctor = useMemo(getRecognitionCtor, []);\n\n // ---- state exposed to consumers ----\n const [isListening, setIsListening] = useState(false);\n const [transcript, setTranscript] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [isSpeaking, setIsSpeaking] = useState(false);\n\n // ---- internal refs ----\n const recRef = useRef<SpeechRecognitionInstance | null>(null);\n const finalBuf = useRef(''); // accumulated final fragments\n const silenceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const onTranscriptRef = useRef(onTranscript); // always-current callback\n const langRef = useRef(lang);\n const ttsWarm = useRef(false);\n const mountedRef = useRef(true);\n\n // Keep refs in sync without causing re-renders.\n onTranscriptRef.current = onTranscript;\n langRef.current = lang;\n\n // ---- TTS warm-up (run once after mount) ----\n useEffect(() => {\n if (ttsWarm.current) return;\n if (typeof window === 'undefined' || !('speechSynthesis' in window)) return;\n ttsWarm.current = true;\n // A zero-length utterance warms up the synth engine so the first real\n // utterance plays without the browser's cold-start pause.\n const u = new SpeechSynthesisUtterance('');\n u.volume = 0;\n window.speechSynthesis.speak(u);\n }, []);\n\n // ---- helpers ----\n const clearSilence = useCallback(() => {\n if (silenceTimer.current) {\n clearTimeout(silenceTimer.current);\n silenceTimer.current = null;\n }\n }, []);\n\n const flushTranscript = useCallback(() => {\n const text = finalBuf.current.trim();\n finalBuf.current = '';\n if (!mountedRef.current) return;\n setTranscript('');\n if (text) onTranscriptRef.current(text);\n }, []);\n\n // ---- SpeechRecognition lifecycle ----\n\n /**\n * Lazily create (or reconfigure) a single SpeechRecognition instance.\n * Reusing the same instance avoids the ~300 ms startup cost of calling\n * `new SpeechRecognition()` each time.\n */\n const getOrCreateRec = useCallback((): SpeechRecognitionInstance | null => {\n if (!Ctor) return null;\n if (recRef.current) {\n // Just update the language — all handlers are already attached.\n recRef.current.lang = langRef.current;\n return recRef.current;\n }\n\n const rec = new Ctor();\n rec.continuous = true; // keep listening until explicitly stopped\n rec.interimResults = true;\n rec.maxAlternatives = 1;\n rec.lang = langRef.current;\n\n rec.onstart = () => {\n if (!mountedRef.current) return;\n setIsListening(true);\n setError(null);\n setTranscript('');\n finalBuf.current = '';\n // Cancel any ongoing TTS so the mic doesn't pick it up.\n if (typeof window !== 'undefined' && 'speechSynthesis' in window) {\n window.speechSynthesis.cancel();\n }\n };\n\n rec.onresult = (ev: SpeechRecognitionResultEvent) => {\n if (!mountedRef.current) return;\n let interim = '';\n for (let i = ev.resultIndex; i < ev.results.length; i++) {\n const seg = ev.results[i];\n const text = seg[0]?.transcript ?? '';\n if (seg.isFinal) {\n finalBuf.current = (finalBuf.current + ' ' + text).trim();\n } else {\n interim += text;\n }\n }\n\n // Show the most relevant text to the user immediately.\n setTranscript(finalBuf.current ? finalBuf.current : interim.trim());\n\n // ---- silence-based auto-send ----\n // Every time we get a result reset the silence timer. When no new\n // results arrive for `silenceMs` we automatically flush.\n clearSilence();\n silenceTimer.current = setTimeout(() => {\n if (!mountedRef.current) return;\n // Stop the recognizer — `onend` will fire but with an empty buffer\n // because we already flushed.\n recRef.current?.stop();\n flushTranscript();\n setIsListening(false);\n }, silenceMs);\n };\n\n rec.onerror = (ev: SpeechRecognitionErrorEvent) => {\n if (!mountedRef.current) return;\n const msg = friendlyError(ev.error);\n if (msg) setError(msg);\n // For fatal errors, stop listening.\n if (['not-allowed', 'service-not-allowed', 'audio-capture'].includes(ev.error)) {\n clearSilence();\n setIsListening(false);\n }\n };\n\n rec.onend = () => {\n if (!mountedRef.current) return;\n clearSilence();\n // Flush anything remaining (e.g. the browser decided to stop early).\n flushTranscript();\n setIsListening(false);\n };\n\n recRef.current = rec;\n return rec;\n }, [Ctor, clearSilence, flushTranscript, silenceMs]);\n\n // ---- public: start / stop ----\n\n const start = useCallback(() => {\n if (isListening) return;\n setError(null);\n const rec = getOrCreateRec();\n if (!rec) {\n setError('Voice input is not supported in this browser.');\n return;\n }\n try {\n rec.start();\n } catch {\n // Already started — ignore.\n }\n }, [isListening, getOrCreateRec]);\n\n const stop = useCallback(() => {\n clearSilence();\n try {\n recRef.current?.stop();\n } catch {\n // Already stopped — ignore.\n }\n }, [clearSilence]);\n\n // ---- public: TTS ----\n\n const speak = useCallback(\n (text: string) => {\n if (typeof window === 'undefined' || !('speechSynthesis' in window)) return;\n if (!autoSpeak) return;\n const clean = stripMarkdown(text);\n if (!clean) return;\n window.speechSynthesis.cancel();\n const u = new SpeechSynthesisUtterance(clean);\n u.lang = langRef.current;\n u.onstart = () => { if (mountedRef.current) setIsSpeaking(true); };\n u.onend = () => { if (mountedRef.current) setIsSpeaking(false); };\n u.onerror = () => { if (mountedRef.current) setIsSpeaking(false); };\n window.speechSynthesis.speak(u);\n },\n [autoSpeak],\n );\n\n const cancelSpeech = useCallback(() => {\n if (typeof window !== 'undefined' && 'speechSynthesis' in window) {\n window.speechSynthesis.cancel();\n }\n if (mountedRef.current) setIsSpeaking(false);\n }, []);\n\n // ---- cleanup on unmount ----\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n clearSilence();\n recRef.current?.abort();\n recRef.current = null;\n if (typeof window !== 'undefined' && 'speechSynthesis' in window) {\n window.speechSynthesis.cancel();\n }\n };\n }, [clearSilence]);\n\n return {\n isSupported: !!Ctor,\n isListening,\n transcript,\n error,\n start,\n stop,\n speak,\n cancelSpeech,\n isSpeaking,\n };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ //# sourceMappingURL=chunk-EL7YGOTY.js.map
2
+ //# sourceMappingURL=chunk-EL7YGOTY.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-427NHGTX.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-EL7YGOTY.js"}