@thattobi/narrator-avatar 1.1.10
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/LICENSE +21 -0
- package/PUBLISHING.md +62 -0
- package/README.md +352 -0
- package/THIRD_PARTY_NOTICES.md +27 -0
- package/dist/NarratorAvatarFull-DhBLV6kE.js +37063 -0
- package/dist/NarratorAvatarFull-DhBLV6kE.js.map +1 -0
- package/dist/index-xRyAk0sW.js +734 -0
- package/dist/index-xRyAk0sW.js.map +1 -0
- package/dist/index.d.ts +72 -0
- package/dist/narrator-avatar.js +6 -0
- package/dist/narrator-avatar.js.map +1 -0
- package/dist/narrator-avatar.umd.cjs +4071 -0
- package/dist/narrator-avatar.umd.cjs.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-xRyAk0sW.js","sources":["../src/deepgram-endpoint.js","../src/VoiceOnlyNarrator.jsx","../src/NarratorAvatar.jsx"],"sourcesContent":["/** A same-origin proxy can authenticate the caller and hold the provider key. */\nexport function canRequestDeepgram(apiKey, endpoint) {\n if (apiKey) return true;\n if (typeof endpoint !== 'string' || !endpoint.trim()) return false;\n if (endpoint.startsWith('/') && !endpoint.startsWith('//')) return true;\n if (typeof window === 'undefined') return false;\n try {\n const url = new URL(endpoint, window.location.href);\n return url.origin === window.location.origin && /^https?:$/.test(url.protocol);\n } catch (_) {\n return false;\n }\n}\n","/**\n * Mobile / voice-only narrator: Deepgram TTS + captions, NO GLB / WebGL / TalkingHead.\n * Same imperative API surface as NarratorAvatar for speak / pause / resume / stop / preload.\n */\nimport React, {\n useRef,\n useEffect,\n useCallback,\n useImperativeHandle,\n forwardRef,\n useState,\n} from 'react';\nimport { canRequestDeepgram } from './deepgram-endpoint.js';\n\nconst DEEPGRAM_SPEAK_URL = 'https://api.deepgram.com/v1/speak';\nconst DEEPGRAM_FAST_RESPONSE_PARAMS = 'encoding=linear16&container=wav&sample_rate=24000';\nconst WAV_HEADER_SIZE = 44;\nconst TTS_FETCH_RETRIES = 3;\nconst TTS_FETCH_RETRY_MS = 280;\nconst HUMAN_PHRASE_GAP_BASE_MS = 560;\n\nfunction getDeepgramApiKey(value) {\n return typeof value === 'string' ? value.trim() : '';\n}\n\nfunction usesExternalAudioService(service) {\n return service === 'deepgram';\n}\n\nconst sleep = (ms) => new Promise((r) => setTimeout(r, ms));\n\nfunction splitIntoPhrases(text) {\n const t = text.trim();\n if (!t) return [];\n return t.split(/(?<=[.!?])\\s+/).map((p) => p.trim()).filter(Boolean);\n}\n\nfunction coalesceSpeechPhrases(phrases, {\n tinyMaxWords = 4,\n tinyMaxChars = 48,\n maxChars = 280,\n} = {}) {\n if (!phrases?.length) return [];\n const out = [];\n let buf = '';\n const wordsIn = (s) => s.trim().split(/\\s+/).filter(Boolean).length;\n const isTiny = (s) => {\n const t = (s || '').trim();\n return !!t && wordsIn(t) <= tinyMaxWords && t.length <= tinyMaxChars;\n };\n const isSentence = (s) => /[.!?…][\"')\\]]*\\s*$/.test((s || '').trim());\n\n for (const phrase of phrases) {\n if (!buf) {\n buf = phrase;\n continue;\n }\n const combined = `${buf} ${phrase}`;\n const canAbsorbTiny = (isTiny(buf) || isTiny(phrase)) && combined.length <= maxChars;\n const canMergeFragment = !isSentence(buf) && combined.length <= maxChars;\n if (canAbsorbTiny || canMergeFragment) buf = combined;\n else {\n out.push(buf);\n buf = phrase;\n }\n }\n if (buf) out.push(buf);\n return out;\n}\n\nfunction speechUnitsFromText(text) {\n return coalesceSpeechPhrases(splitIntoPhrases(text));\n}\n\nfunction humanPhraseGapMs(phrase, baseMs = HUMAN_PHRASE_GAP_BASE_MS) {\n const t = (phrase || '').trim();\n let gap = Math.max(320, Number(baseMs) || HUMAN_PHRASE_GAP_BASE_MS);\n if (/\\?\\s*$/.test(t)) gap += 220;\n else if (/!\\s*$/.test(t)) gap += 160;\n else if (/(?:\\.\\.\\.|…)\\s*$/.test(t)) gap += 240;\n else if (/\\.\\s*$/.test(t)) gap += 120;\n const words = t.split(/\\s+/).filter(Boolean).length;\n if (words >= 24) gap += 120;\n else if (words >= 14) gap += 60;\n gap += Math.floor(Math.random() * 100) - 30;\n return Math.max(380, Math.min(1100, Math.round(gap)));\n}\n\nasync function sleepPhraseGap(ms, isActive, pausedRef) {\n const end = Date.now() + Math.max(0, ms);\n while (Date.now() < end) {\n if (!isActive()) return;\n while (pausedRef?.current && isActive()) await sleep(80);\n if (!isActive()) return;\n await sleep(Math.min(60, end - Date.now()));\n }\n}\n\nfunction normalizeSubtitleChunk(chunk) {\n if (chunk == null) return '';\n if (Array.isArray(chunk)) return chunk.join('').replace(/\\s+/g, ' ').trim();\n if (typeof chunk === 'string') return chunk.replace(/\\s+/g, ' ').trim();\n return String(chunk).replace(/\\s+/g, ' ').trim();\n}\n\nfunction createFollowSubtitleHandler(onSubtitle, initialText = '', maxWords = 0) {\n let line = (initialText || '').trim();\n const emit = () => {\n if (!onSubtitle) return;\n const limit = Number(maxWords) || 0;\n if (limit <= 0) {\n onSubtitle(line);\n return;\n }\n const words = line.split(/\\s+/).filter(Boolean);\n onSubtitle(words.length <= limit ? line : words.slice(-limit).join(' '));\n };\n if (line) emit();\n return (chunk) => {\n const word = normalizeSubtitleChunk(chunk);\n if (!word) return;\n if (!line) line = word;\n else if (word.startsWith(line) && word.length > line.length) line = word;\n else if (line === word || line.endsWith(` ${word}`) || line.endsWith(word)) {\n /* duplicate */\n } else line = `${line} ${word}`;\n emit();\n };\n}\n\nfunction spokenPrefixBeforeOffset(prepared, offsetMs) {\n if (!prepared?.words?.length || offsetMs <= 0) return '';\n const parts = [];\n for (let i = 0; i < prepared.words.length; i++) {\n const start = prepared.wtimes[i];\n const end = start + prepared.wdurations[i];\n if (end <= offsetMs + 1 || start < offsetMs) parts.push(prepared.words[i]);\n else break;\n }\n return parts.join(' ');\n}\n\nfunction wavToAudioBuffer(audioCtx, wavArrayBuffer) {\n if (wavArrayBuffer.byteLength < WAV_HEADER_SIZE) return null;\n const view = new DataView(wavArrayBuffer);\n const sampleRate = view.getUint32(24, true);\n const numChannels = Math.max(1, view.getUint16(22, true));\n const totalBytes = wavArrayBuffer.byteLength - WAV_HEADER_SIZE;\n const numSamplesPerChannel = totalBytes / (2 * numChannels);\n const audioBuffer = audioCtx.createBuffer(numChannels, numSamplesPerChannel, sampleRate);\n const int16 = new Int16Array(wavArrayBuffer, WAV_HEADER_SIZE, (totalBytes / 2) | 0);\n for (let ch = 0; ch < numChannels; ch++) {\n const channel = audioBuffer.getChannelData(ch);\n for (let i = 0; i < numSamplesPerChannel; i++) {\n channel[i] = int16[i * numChannels + ch] / 32768;\n }\n }\n return audioBuffer;\n}\n\nfunction wordTimingWeight(word) {\n const spoken = word.replace(/[^\\p{L}\\p{N}'’-]/gu, '');\n const letters = spoken.replace(/[^\\p{L}]/gu, '');\n const vowels = (letters.match(/[aeiouy]/gi) || []).length;\n return Math.max(1, letters.length + vowels * 0.65 + (spoken.length - letters.length) * 0.45);\n}\n\nfunction punctuationPauseMs(word) {\n if (/[.?!…][\"')\\]}]*$/.test(word)) return 175;\n if (/[;:][\"')\\]}]*$/.test(word)) return 115;\n if (/[,—-][\"')\\]}]*$/.test(word)) return 75;\n return 0;\n}\n\nfunction wordTimingsForDuration(text, durationMs) {\n const words = text.trim().split(/\\s+/).filter(Boolean);\n const safeDuration = Math.max(0, Number(durationMs) || 0);\n const pauseMs = words.map(punctuationPauseMs);\n const requestedPauses = pauseMs.reduce((sum, value) => sum + value, 0);\n const pauseScale = requestedPauses > 0\n ? Math.min(1, (safeDuration * 0.28) / requestedPauses)\n : 0;\n const allocatedPauseMs = requestedPauses * pauseScale;\n const spokenMs = Math.max(0, safeDuration - allocatedPauseMs);\n const weights = words.map(wordTimingWeight);\n const totalWeight = weights.reduce((sum, value) => sum + value, 0) || 1;\n const wtimes = [];\n const wdurations = [];\n let t = 0;\n for (let i = 0; i < words.length; i++) {\n wtimes.push(t);\n const dur = (weights[i] / totalWeight) * spokenMs;\n wdurations.push(dur);\n t += dur + pauseMs[i] * pauseScale;\n }\n if (!wtimes.length) {\n words.push(text || ' ');\n wtimes.push(0);\n wdurations.push(safeDuration);\n }\n return { words, wtimes, wdurations };\n}\n\nasync function fetchExternalTtsWav(apiKey, model, phrase, signal, endpoint = DEEPGRAM_SPEAK_URL, speechRate = 1) {\n const separator = endpoint.includes('?') ? '&' : '?';\n const speed = Math.max(0.7, Math.min(1.5, Number(speechRate) || 1));\n const url = `${endpoint}${separator}model=${encodeURIComponent(model)}&speed=${speed}&${DEEPGRAM_FAST_RESPONSE_PARAMS}`;\n let lastErr;\n for (let attempt = 0; attempt < TTS_FETCH_RETRIES; attempt++) {\n try {\n const headers = { 'Content-Type': 'application/json', Accept: 'audio/wav' };\n if (apiKey) headers.Authorization = `Token ${apiKey}`;\n const res = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify({ text: phrase }),\n signal,\n });\n if (!res.ok) {\n const detail = (await res.text()).slice(0, 500);\n throw new Error(\n `Deepgram TTS error: ${res.status} ${res.statusText}${detail ? ` — ${detail}` : ''}`\n );\n }\n const arrayBuffer = await res.arrayBuffer();\n if (!arrayBuffer?.byteLength) throw new Error('Deepgram TTS returned empty audio');\n return arrayBuffer;\n } catch (err) {\n lastErr = err;\n if (err?.name === 'AbortError' || signal?.aborted) throw err;\n if (attempt < TTS_FETCH_RETRIES - 1) await sleep(TTS_FETCH_RETRY_MS * (attempt + 1));\n }\n }\n if (lastErr instanceof TypeError && /failed to fetch/i.test(lastErr.message)) {\n throw new Error(\n 'Deepgram TTS request could not reach the API. Check the configured same-origin proxy/service and browser network policy.'\n );\n }\n throw lastErr || new Error('Deepgram TTS failed');\n}\n\nasync function preparePhraseAudio(audioCtx, apiKey, model, phrase, signal, speechRate = 1, endpoint) {\n const wav = await fetchExternalTtsWav(apiKey, model, phrase, signal, endpoint, speechRate);\n let audioBuffer = wavToAudioBuffer(audioCtx, wav);\n if (!audioBuffer) throw new Error('Failed to prepare audio');\n const durationMs = audioBuffer.duration * 1000;\n const { words, wtimes, wdurations } = wordTimingsForDuration(phrase, durationMs);\n return { phrase, audioBuffer, durationMs, words, wtimes, wdurations };\n}\n\nfunction ttsCacheKey(model, speechRate, phrase, endpoint = '') {\n const rate = Math.max(0.7, Math.min(1.5, Number(speechRate) || 1));\n return `deepgram|${endpoint}|${model}|${rate}|${phrase}`;\n}\n\nfunction getOrPreparePhraseAudio(cache, audioCtx, apiKey, model, phrase, _signalIgnored, speechRate = 1, endpoint) {\n const key = ttsCacheKey(model, speechRate, phrase, endpoint);\n const existing = cache.get(key);\n if (existing) {\n return Promise.resolve(existing).then(\n (value) => value,\n () => {\n cache.delete(key);\n return getOrPreparePhraseAudio(cache, audioCtx, apiKey, model, phrase, null, speechRate, endpoint);\n }\n );\n }\n const pending = preparePhraseAudio(audioCtx, apiKey, model, phrase, null, speechRate, endpoint).catch((err) => {\n cache.delete(key);\n throw err;\n });\n cache.set(key, pending);\n return pending;\n}\n\nfunction trimTtsCache(cache, maxEntries) {\n if (!cache || cache.size <= maxEntries) return;\n const keys = [...cache.keys()];\n for (const k of keys.slice(0, cache.size - maxEntries)) cache.delete(k);\n}\n\nfunction sliceAudioBufferFromOffset(audioCtx, buffer, offsetMs) {\n if (!buffer || !audioCtx) return null;\n const sr = buffer.sampleRate;\n let start = Math.floor((Math.max(0, offsetMs) / 1000) * sr);\n if (start < 0) start = 0;\n if (start >= buffer.length - 32) return null;\n const len = buffer.length - start;\n const out = audioCtx.createBuffer(buffer.numberOfChannels, len, sr);\n for (let ch = 0; ch < buffer.numberOfChannels; ch++) {\n out.getChannelData(ch).set(buffer.getChannelData(ch).subarray(start));\n }\n return out;\n}\n\nfunction shiftWordTimings(words, wtimes, wdurations, offsetMs) {\n const outW = [];\n const outT = [];\n const outD = [];\n for (let i = 0; i < words.length; i++) {\n const start = wtimes[i];\n const dur = wdurations[i];\n const end = start + dur;\n if (end <= offsetMs + 1) continue;\n if (start < offsetMs) {\n outW.push(words[i]);\n outT.push(0);\n outD.push(end - offsetMs);\n } else {\n outW.push(words[i]);\n outT.push(start - offsetMs);\n outD.push(dur);\n }\n }\n if (!outW.length) {\n outW.push(' ');\n outT.push(0);\n outD.push(120);\n }\n return { words: outW, wtimes: outT, wdurations: outD };\n}\n\nfunction segmentFromPrepared(audioCtx, prepared, offsetMs) {\n const audio = sliceAudioBufferFromOffset(audioCtx, prepared.audioBuffer, offsetMs);\n if (!audio) return null;\n const { words, wtimes, wdurations } = shiftWordTimings(\n prepared.words,\n prepared.wtimes,\n prepared.wdurations,\n offsetMs\n );\n return { audio, words, wtimes, wdurations, durationMs: audio.duration * 1000 };\n}\n\nasync function ensureAudioContextRunning(audioCtx) {\n if (!audioCtx || audioCtx.state === 'closed') return false;\n if (audioCtx.state === 'running') return true;\n try {\n await Promise.race([\n audioCtx.resume(),\n new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), 1500)),\n ]);\n } catch (_) {\n try {\n await audioCtx.resume();\n } catch (__) {\n return false;\n }\n }\n return audioCtx.state === 'running';\n}\n\n/**\n * Play one AudioBuffer segment; drives word-follow captions via timeouts.\n * Returns 'done' | 'paused' | 'aborted' | 'blocked' (AudioContext not running).\n */\nfunction playSegment(player, segment, {\n onWord,\n abortedRef,\n pausedRef,\n sessionRef,\n sessionId,\n playbackState,\n}) {\n return new Promise((resolve) => {\n const audioCtx = player.audioCtx;\n let watch = null;\n let settled = false;\n\n const finish = (status) => {\n if (settled) return;\n settled = true;\n if (watch != null) {\n clearInterval(watch);\n watch = null;\n }\n for (const t of player.wordTimers || []) clearTimeout(t);\n player.wordTimers = [];\n player.isAudioPlaying = false;\n if (player.source) {\n try {\n player.source.onended = null;\n } catch (_) {}\n }\n if (status !== 'paused') player.isSpeaking = false;\n resolve(status);\n };\n\n void (async () => {\n if (!audioCtx || !segment?.audio) {\n finish('aborted');\n return;\n }\n const ok = await ensureAudioContextRunning(audioCtx);\n if (!ok) {\n finish('blocked');\n return;\n }\n if (abortedRef.current || sessionRef.current !== sessionId) {\n finish('aborted');\n return;\n }\n if (pausedRef.current) {\n finish('paused');\n return;\n }\n\n try {\n player.source?.stop?.();\n } catch (_) {}\n player.source = null;\n for (const t of player.wordTimers || []) clearTimeout(t);\n player.wordTimers = [];\n\n const source = audioCtx.createBufferSource();\n source.buffer = segment.audio;\n source.connect(player.gain);\n player.source = source;\n player.isSpeaking = true;\n player.isAudioPlaying = true;\n playbackState.segmentStartedCtxTime = audioCtx.currentTime;\n\n if (typeof onWord === 'function' && segment.words?.length) {\n for (let i = 0; i < segment.words.length; i++) {\n const delay = Math.max(0, segment.wtimes[i]);\n const word = segment.words[i];\n const timer = setTimeout(() => {\n if (abortedRef.current || pausedRef.current || sessionRef.current !== sessionId) return;\n onWord(word);\n }, delay);\n player.wordTimers.push(timer);\n }\n }\n\n source.onended = () => {\n // Intentionally stopped for pause → watch/pauseSpeaking owns 'paused'\n if (pausedRef.current) {\n finish('paused');\n return;\n }\n if (abortedRef.current || sessionRef.current !== sessionId) finish('aborted');\n else finish('done');\n };\n\n watch = setInterval(() => {\n if (settled) return;\n if (abortedRef.current || sessionRef.current !== sessionId) {\n try {\n source.stop();\n } catch (_) {}\n finish('aborted');\n return;\n }\n if (pausedRef.current) {\n try {\n const elapsed = (audioCtx.currentTime - playbackState.segmentStartedCtxTime) * 1000;\n playbackState.resumeOffsetMs =\n (playbackState.segmentOffsetMs || 0) + Math.max(0, elapsed);\n source.stop();\n } catch (_) {}\n finish('paused');\n }\n }, 40);\n\n try {\n source.start(0);\n } catch (_) {\n finish('aborted');\n }\n })();\n });\n}\n\nconst VoiceOnlyNarrator = forwardRef(function VoiceOnlyNarrator({\n ttsApiKey = null,\n deepgramEndpoint = DEEPGRAM_SPEAK_URL,\n ttsVoice = 'aura-2-thalia-en',\n ttsService = 'deepgram',\n speechRate = 1,\n phraseGapMs = HUMAN_PHRASE_GAP_BASE_MS,\n preloadText = null,\n onPreloadReady = null,\n pauseWhenHidden = true,\n subtitleMaxWords = 16,\n onReady = () => {},\n onError = () => {},\n onSpeechStart = () => {},\n onSpeechEnd = () => {},\n onSubtitle = null,\n className = '',\n style = {},\n}, ref) {\n const [isReady, setIsReady] = useState(false);\n const playerRef = useRef(null);\n const ttsCacheRef = useRef(new Map());\n const speechSessionIdRef = useRef(0);\n const speechAbortedRef = useRef(false);\n const speechPausedRef = useRef(false);\n const autoPausedForHideRef = useRef(false);\n const phrasePlaybackRef = useRef({\n segmentOffsetMs: 0,\n segmentStartedCtxTime: null,\n durationMs: 0,\n resumeOffsetMs: 0,\n });\n const preloadGenRef = useRef(0);\n const speakingRef = useRef(false);\n\n const ttsApiKeyRef = useRef(ttsApiKey);\n const deepgramEndpointRef = useRef(deepgramEndpoint);\n const ttsVoiceRef = useRef(ttsVoice);\n const speechRateRef = useRef(speechRate);\n const phraseGapMsRef = useRef(phraseGapMs);\n const preloadTextRef = useRef(preloadText);\n const onPreloadReadyRef = useRef(onPreloadReady);\n const onReadyRef = useRef(onReady);\n const onErrorRef = useRef(onError);\n const onSpeechStartRef = useRef(onSpeechStart);\n const onSpeechEndRef = useRef(onSpeechEnd);\n const onSubtitleRef = useRef(onSubtitle);\n const subtitleMaxWordsRef = useRef(subtitleMaxWords);\n const pauseWhenHiddenRef = useRef(pauseWhenHidden);\n const pauseSpeakingRef = useRef(() => {});\n const resumeSpeakingRef = useRef(async () => {});\n const cancelRef = useRef(() => {});\n\n useEffect(() => {\n ttsApiKeyRef.current = ttsApiKey;\n deepgramEndpointRef.current = deepgramEndpoint || DEEPGRAM_SPEAK_URL;\n ttsVoiceRef.current = ttsVoice;\n speechRateRef.current = Math.max(0.6, Math.min(1.2, Number(speechRate) || 1));\n const gap = Number(phraseGapMs);\n phraseGapMsRef.current = Number.isFinite(gap) && gap >= 0 ? gap : HUMAN_PHRASE_GAP_BASE_MS;\n preloadTextRef.current = preloadText;\n onPreloadReadyRef.current = onPreloadReady;\n onReadyRef.current = onReady;\n onErrorRef.current = onError;\n onSpeechStartRef.current = onSpeechStart;\n onSpeechEndRef.current = onSpeechEnd;\n onSubtitleRef.current = onSubtitle;\n subtitleMaxWordsRef.current = Number(subtitleMaxWords) > 0 ? Number(subtitleMaxWords) : 16;\n pauseWhenHiddenRef.current = pauseWhenHidden;\n });\n\n useEffect(() => {\n if (!usesExternalAudioService(ttsService)) {\n setIsReady(true);\n onReadyRef.current?.();\n return undefined;\n }\n const AudioCtx = window.AudioContext || window.webkitAudioContext;\n const audioCtx = new AudioCtx();\n const gain = audioCtx.createGain();\n gain.connect(audioCtx.destination);\n playerRef.current = {\n audioCtx,\n gain,\n source: null,\n wordTimers: [],\n isSpeaking: false,\n isAudioPlaying: false,\n };\n setIsReady(true);\n onReadyRef.current?.();\n\n return () => {\n cancelRef.current?.(true);\n try {\n playerRef.current?.source?.stop?.();\n } catch (_) {}\n try {\n audioCtx.close();\n } catch (_) {}\n playerRef.current = null;\n ttsCacheRef.current.clear();\n };\n }, [ttsService]);\n\n useEffect(() => {\n const hide = () => {\n if (!pauseWhenHiddenRef.current) return;\n const p = playerRef.current;\n if (p && (p.isSpeaking || p.isAudioPlaying) && !speechPausedRef.current) {\n autoPausedForHideRef.current = true;\n pauseSpeakingRef.current?.();\n }\n try {\n if (p?.audioCtx?.state === 'running') void p.audioCtx.suspend();\n } catch (_) {}\n };\n const show = async () => {\n const p = playerRef.current;\n if (!p) return;\n const ok = await ensureAudioContextRunning(p.audioCtx);\n if (!ok) return;\n if (autoPausedForHideRef.current) {\n autoPausedForHideRef.current = false;\n await resumeSpeakingRef.current?.();\n }\n };\n const onVis = () => {\n if (document.hidden) hide();\n else void show();\n };\n const onPageHide = () => hide();\n const onPointer = () => {\n if (autoPausedForHideRef.current) void show();\n else void ensureAudioContextRunning(playerRef.current?.audioCtx);\n };\n const onPageShow = () => {\n void show();\n };\n document.addEventListener('visibilitychange', onVis);\n window.addEventListener('pagehide', onPageHide);\n window.addEventListener('pageshow', onPageShow);\n window.addEventListener('pointerdown', onPointer, { passive: true });\n window.addEventListener('touchstart', onPointer, { passive: true });\n return () => {\n document.removeEventListener('visibilitychange', onVis);\n window.removeEventListener('pagehide', onPageHide);\n window.removeEventListener('pageshow', onPageShow);\n window.removeEventListener('pointerdown', onPointer);\n window.removeEventListener('touchstart', onPointer);\n };\n }, []);\n\n const cancelActiveSpeechSession = useCallback((bump = true) => {\n speechAbortedRef.current = true;\n speechPausedRef.current = false;\n speakingRef.current = false;\n if (bump) speechSessionIdRef.current += 1;\n const p = playerRef.current;\n if (p) {\n for (const t of p.wordTimers || []) clearTimeout(t);\n p.wordTimers = [];\n try {\n p.source?.stop?.();\n } catch (_) {}\n p.source = null;\n p.isSpeaking = false;\n p.isAudioPlaying = false;\n }\n try {\n onSubtitleRef.current?.('');\n } catch (_) {}\n }, []);\n\n cancelRef.current = cancelActiveSpeechSession;\n\n const preloadSpeech = useCallback((text) => {\n const p = playerRef.current;\n if (!p?.audioCtx || !text?.trim() || !usesExternalAudioService(ttsService)) return;\n const apiKey = getDeepgramApiKey(\n ttsService === 'deepgram'\n ? (ttsApiKeyRef.current || import.meta.env?.VITE_DEEPGRAM_API_KEY)\n : ttsApiKeyRef.current,\n );\n if (ttsService === 'deepgram' && !canRequestDeepgram(apiKey, deepgramEndpointRef.current)) return;\n const model = ttsVoiceRef.current || 'aura-2-thalia-en';\n const rate = speechRateRef.current;\n const list = speechUnitsFromText(text);\n const phrases = list.length ? list : [text.trim()];\n const gen = ++preloadGenRef.current;\n const kick = (i) =>\n getOrPreparePhraseAudio(\n ttsCacheRef.current,\n p.audioCtx,\n apiKey,\n model,\n phrases[i],\n null,\n rate,\n deepgramEndpointRef.current,\n );\n\n void (async () => {\n try {\n await kick(0);\n if (gen !== preloadGenRef.current) return;\n onPreloadReadyRef.current?.();\n } catch (err) {\n console.warn('[VoiceOnlyNarrator] Preload failed:', err);\n return;\n }\n if (gen !== preloadGenRef.current) return;\n if (phrases[1]) void kick(1);\n trimTtsCache(ttsCacheRef.current, 8);\n })();\n }, [ttsService]);\n\n useEffect(() => {\n if (!isReady || !preloadText) return undefined;\n preloadSpeech(preloadText);\n return undefined;\n }, [isReady, preloadText, preloadSpeech]);\n\n const speakLesson = useCallback(async (text, sessionId) => {\n const player = playerRef.current;\n if (!player?.audioCtx) return;\n const apiKey = getDeepgramApiKey(\n ttsService === 'deepgram'\n ? (ttsApiKeyRef.current || import.meta.env?.VITE_DEEPGRAM_API_KEY)\n : ttsApiKeyRef.current,\n );\n if (ttsService === 'deepgram' && !canRequestDeepgram(apiKey, deepgramEndpointRef.current)) {\n throw new Error('Deepgram requires an API key or a same-origin proxy endpoint');\n }\n const model = ttsVoiceRef.current || 'aura-2-thalia-en';\n const rate = speechRateRef.current;\n const phraseList = speechUnitsFromText(text);\n const list = phraseList.length ? phraseList : [text.trim() || ' '];\n\n const isActive = () =>\n !speechAbortedRef.current && speechSessionIdRef.current === sessionId;\n\n const prefetch = new Map();\n const enqueue = (i) => {\n if (i < 0 || i >= list.length || prefetch.has(i)) return;\n prefetch.set(\n i,\n getOrPreparePhraseAudio(\n ttsCacheRef.current,\n player.audioCtx,\n apiKey,\n model,\n list[i],\n null,\n rate,\n deepgramEndpointRef.current,\n )\n );\n };\n\n enqueue(0);\n const audioOk = await ensureAudioContextRunning(player.audioCtx);\n if (!audioOk) {\n throw new Error('AudioContext blocked — tap Speak / Continue Learning to unlock audio');\n }\n await prefetch.get(0);\n if (!isActive()) return;\n enqueue(1);\n\n let playedAny = false;\n let blocked = false;\n for (let i = 0; i < list.length; i++) {\n if (!isActive()) break;\n while (speechPausedRef.current && isActive()) await sleep(80);\n if (!isActive()) break;\n\n enqueue(i);\n enqueue(i + 1);\n\n let prepared;\n try {\n prepared = await prefetch.get(i);\n } catch (err) {\n onErrorRef.current?.(err);\n prefetch.delete(i);\n continue;\n }\n prefetch.delete(i);\n if (!prepared || !isActive()) break;\n\n onSubtitleRef.current?.('');\n let offsetMs = 0;\n let phraseComplete = false;\n\n while (!phraseComplete && isActive()) {\n while (speechPausedRef.current && isActive()) await sleep(80);\n if (!isActive()) break;\n if (offsetMs >= prepared.durationMs - 60) {\n phraseComplete = true;\n break;\n }\n const segment = segmentFromPrepared(player.audioCtx, prepared, offsetMs);\n if (!segment) {\n phraseComplete = true;\n break;\n }\n\n phrasePlaybackRef.current = {\n segmentOffsetMs: offsetMs,\n segmentStartedCtxTime: null,\n durationMs: prepared.durationMs,\n resumeOffsetMs: offsetMs,\n };\n\n const follow = createFollowSubtitleHandler(\n (line) => onSubtitleRef.current?.(line),\n spokenPrefixBeforeOffset(prepared, offsetMs),\n subtitleMaxWordsRef.current\n );\n\n speakingRef.current = true;\n const status = await playSegment(player, segment, {\n onWord: follow,\n abortedRef: speechAbortedRef,\n pausedRef: speechPausedRef,\n sessionRef: speechSessionIdRef,\n sessionId,\n playbackState: phrasePlaybackRef.current,\n });\n\n if (status === 'blocked') {\n blocked = true;\n break;\n }\n if (status === 'paused') {\n offsetMs = phrasePlaybackRef.current.resumeOffsetMs || offsetMs;\n continue;\n }\n if (status === 'aborted') break;\n playedAny = true;\n phraseComplete = true;\n }\n\n if (blocked) break;\n\n try {\n ttsCacheRef.current.delete(ttsCacheKey(\n model,\n rate,\n prepared.phrase,\n deepgramEndpointRef.current,\n ));\n } catch (_) {}\n trimTtsCache(ttsCacheRef.current, 8);\n\n if (isActive() && phraseComplete && i < list.length - 1) {\n await sleepPhraseGap(\n humanPhraseGapMs(prepared.phrase, phraseGapMsRef.current),\n isActive,\n speechPausedRef\n );\n }\n }\n\n speakingRef.current = false;\n if (blocked && isActive()) {\n throw new Error('AudioContext blocked — tap Speak / Continue Learning to unlock audio');\n }\n if (isActive() && playedAny) onSpeechEndRef.current?.();\n else if (isActive() && !playedAny) {\n throw new Error('No audio could be played');\n }\n }, []);\n\n const speakText = useCallback((text) => {\n if (!usesExternalAudioService(ttsService)) {\n onErrorRef.current?.(new Error('Voice-only mode requires ttsService=\"deepgram\"'));\n return;\n }\n if (!playerRef.current || !text?.trim()) return;\n const apiKey = getDeepgramApiKey(\n ttsService === 'deepgram'\n ? (ttsApiKeyRef.current || import.meta.env?.VITE_DEEPGRAM_API_KEY)\n : ttsApiKeyRef.current,\n );\n if (ttsService !== 'deepgram' || canRequestDeepgram(apiKey, deepgramEndpointRef.current)) {\n const phrases = speechUnitsFromText(text);\n const first = phrases[0] || text.trim();\n if (first) {\n void getOrPreparePhraseAudio(\n ttsCacheRef.current,\n playerRef.current.audioCtx,\n apiKey,\n ttsVoiceRef.current || 'aura-2-thalia-en',\n first,\n null,\n speechRateRef.current,\n deepgramEndpointRef.current,\n );\n }\n }\n cancelActiveSpeechSession(true);\n autoPausedForHideRef.current = false;\n speechAbortedRef.current = false;\n speechPausedRef.current = false;\n const sessionId = speechSessionIdRef.current;\n void ensureAudioContextRunning(playerRef.current.audioCtx);\n onSpeechStartRef.current?.(text);\n onSubtitleRef.current?.('');\n speakLesson(text, sessionId).catch((err) => {\n if (speechSessionIdRef.current !== sessionId || speechAbortedRef.current) return;\n console.error('[VoiceOnlyNarrator] Speech failed:', err);\n speakingRef.current = false;\n onSpeechEndRef.current?.();\n onErrorRef.current?.(err);\n });\n }, [cancelActiveSpeechSession, speakLesson, ttsService]);\n\n const pauseSpeaking = useCallback(() => {\n const p = playerRef.current;\n if (!p) return;\n if (p.isAudioPlaying && phrasePlaybackRef.current.segmentStartedCtxTime != null) {\n const elapsed =\n (p.audioCtx.currentTime - phrasePlaybackRef.current.segmentStartedCtxTime) * 1000;\n phrasePlaybackRef.current.resumeOffsetMs =\n (phrasePlaybackRef.current.segmentOffsetMs || 0) + Math.max(0, elapsed);\n }\n speechPausedRef.current = true;\n try {\n p.source?.stop?.();\n } catch (_) {}\n p.isAudioPlaying = false;\n }, []);\n\n const resumeSpeaking = useCallback(async () => {\n if (!speechPausedRef.current) return;\n await ensureAudioContextRunning(playerRef.current?.audioCtx);\n speechPausedRef.current = false;\n }, []);\n\n const stopSpeaking = useCallback(() => {\n autoPausedForHideRef.current = false;\n cancelActiveSpeechSession(true);\n onSpeechEndRef.current?.();\n }, [cancelActiveSpeechSession]);\n\n pauseSpeakingRef.current = pauseSpeaking;\n resumeSpeakingRef.current = resumeSpeaking;\n\n useImperativeHandle(ref, () => ({\n speakText,\n preloadSpeech,\n pauseSpeaking,\n resumeSpeaking,\n stopSpeaking,\n makeEyeContact: () => {},\n setMood: () => {},\n setLighting: () => {},\n setView: () => {},\n playGesture: () => {},\n playTeachingGesture: () => false,\n playAnimation: () => {},\n playPose: () => {},\n stopAnimation: () => {},\n stopPose: () => {},\n setMixerGain: () => {},\n playBackgroundAudio: () => {},\n stopBackgroundAudio: () => {},\n isReady,\n get isSpeaking() {\n return speakingRef.current || !!playerRef.current?.isSpeaking;\n },\n get talkingHead() {\n return null;\n },\n get avatarMode() {\n return 'voice';\n },\n }), [speakText, preloadSpeech, pauseSpeaking, resumeSpeaking, stopSpeaking, isReady]);\n\n return (\n <div\n className={`narrator-avatar-container narrator-avatar-voice-only ${className}`}\n style={{\n position: 'relative',\n minHeight: 0,\n height: 0,\n overflow: 'hidden',\n pointerEvents: 'none',\n ...style,\n // Force zero footprint — host should not reserve avatar layout on mobile\n width: style?.width ?? '100%',\n maxHeight: 0,\n }}\n data-avatar-mode=\"voice\"\n aria-hidden=\"true\"\n />\n );\n});\n\nVoiceOnlyNarrator.displayName = 'VoiceOnlyNarrator';\n\nexport default VoiceOnlyNarrator;\n","/**\n * Public NarratorAvatar entry — routes mobile to voice-only (no GLB/THREE)\n * and lazily loads the full 3D avatar only when needed.\n */\nimport React, { forwardRef, useEffect, useState, Suspense, lazy } from 'react';\nimport VoiceOnlyNarrator from './VoiceOnlyNarrator.jsx';\n\nconst NarratorAvatarFullLazy = lazy(() => import('./NarratorAvatarFull.jsx'));\n\nfunction isMobileLikeDevice() {\n if (typeof window === 'undefined') return false;\n const ua = typeof navigator !== 'undefined' ? navigator.userAgent || '' : '';\n if (/iPhone|iPod|Android.*Mobile|webOS|BlackBerry|IEMobile|Opera Mini/i.test(ua)) return true;\n if (/iPad/i.test(ua) || (/Android/i.test(ua) && !/Mobile/i.test(ua))) return true;\n if (\n /Macintosh/i.test(ua) &&\n (navigator.maxTouchPoints || 0) > 1 &&\n window.matchMedia?.('(pointer: coarse)')?.matches\n ) {\n return true;\n }\n if (window.matchMedia?.('(max-width: 768px)')?.matches) return true;\n if (window.innerWidth <= 768) return true;\n return false;\n}\n\nfunction resolveAvatarMode(avatarMode, ttsService) {\n if (avatarMode === 'voice' || avatarMode === true) return 'voice';\n if (avatarMode === 'full' || avatarMode === false) return 'full';\n return isMobileLikeDevice() && ttsService === 'deepgram' ? 'voice' : 'full';\n}\n\n/**\n * @param {'auto'|'full'|'voice'|boolean} [avatarMode='auto']\n * `auto`: phones/tablets → voice only (no GLB); desktop → full 3D (lazy-loaded).\n */\nconst NarratorAvatar = forwardRef(function NarratorAvatar(props, ref) {\n const { avatarMode = 'auto', ...rest } = props;\n const [mode, setMode] = useState(() => {\n if (avatarMode === 'voice' || avatarMode === true) return 'voice';\n if (avatarMode === 'full' || avatarMode === false) return 'full';\n return null;\n });\n\n useEffect(() => {\n setMode(resolveAvatarMode(avatarMode, rest.ttsService || 'google'));\n }, [avatarMode, rest.ttsService]);\n\n if (mode === null) {\n return (\n <div\n className={`narrator-avatar-container ${rest.className || ''}`}\n style={{ position: 'relative', minHeight: 0, ...rest.style }}\n data-avatar-mode=\"resolving\"\n aria-hidden=\"true\"\n />\n );\n }\n\n if (mode === 'voice') {\n return <VoiceOnlyNarrator ref={ref} {...rest} />;\n }\n\n return (\n <Suspense\n fallback={\n <div\n className={`narrator-avatar-container ${rest.className || ''}`}\n style={{\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: rest.style?.minHeight || 400,\n ...rest.style,\n }}\n >\n Loading 3D avatar…\n </div>\n }\n >\n <NarratorAvatarFullLazy ref={ref} {...rest} />\n </Suspense>\n );\n});\n\nNarratorAvatar.displayName = 'NarratorAvatar';\n\nexport default NarratorAvatar;\n"],"names":["canRequestDeepgram","apiKey","endpoint","url","DEEPGRAM_SPEAK_URL","DEEPGRAM_FAST_RESPONSE_PARAMS","WAV_HEADER_SIZE","TTS_FETCH_RETRIES","TTS_FETCH_RETRY_MS","HUMAN_PHRASE_GAP_BASE_MS","getDeepgramApiKey","value","usesExternalAudioService","service","sleep","ms","splitIntoPhrases","text","t","p","coalesceSpeechPhrases","phrases","tinyMaxWords","tinyMaxChars","maxChars","out","buf","wordsIn","s","isTiny","isSentence","phrase","combined","canAbsorbTiny","canMergeFragment","speechUnitsFromText","humanPhraseGapMs","baseMs","gap","words","sleepPhraseGap","isActive","pausedRef","end","normalizeSubtitleChunk","chunk","createFollowSubtitleHandler","onSubtitle","initialText","maxWords","line","emit","limit","word","spokenPrefixBeforeOffset","prepared","offsetMs","_a","parts","i","start","wavToAudioBuffer","audioCtx","wavArrayBuffer","view","sampleRate","numChannels","totalBytes","numSamplesPerChannel","audioBuffer","int16","ch","channel","wordTimingWeight","spoken","letters","vowels","punctuationPauseMs","wordTimingsForDuration","durationMs","safeDuration","pauseMs","requestedPauses","sum","pauseScale","allocatedPauseMs","spokenMs","weights","totalWeight","wtimes","wdurations","dur","fetchExternalTtsWav","model","signal","speechRate","separator","speed","lastErr","attempt","headers","res","detail","arrayBuffer","err","preparePhraseAudio","wav","ttsCacheKey","rate","getOrPreparePhraseAudio","cache","_signalIgnored","key","existing","pending","trimTtsCache","maxEntries","keys","k","sliceAudioBufferFromOffset","buffer","sr","len","shiftWordTimings","outW","outT","outD","segmentFromPrepared","audio","ensureAudioContextRunning","_","rej","playSegment","player","segment","onWord","abortedRef","sessionRef","sessionId","playbackState","resolve","watch","settled","finish","status","_b","source","_c","delay","timer","elapsed","VoiceOnlyNarrator","forwardRef","ttsApiKey","deepgramEndpoint","ttsVoice","ttsService","phraseGapMs","preloadText","onPreloadReady","pauseWhenHidden","subtitleMaxWords","onReady","onError","onSpeechStart","onSpeechEnd","className","style","ref","isReady","setIsReady","useState","playerRef","useRef","ttsCacheRef","speechSessionIdRef","speechAbortedRef","speechPausedRef","autoPausedForHideRef","phrasePlaybackRef","preloadGenRef","speakingRef","ttsApiKeyRef","deepgramEndpointRef","ttsVoiceRef","speechRateRef","phraseGapMsRef","preloadTextRef","onPreloadReadyRef","onReadyRef","onErrorRef","onSpeechStartRef","onSpeechEndRef","onSubtitleRef","subtitleMaxWordsRef","pauseWhenHiddenRef","pauseSpeakingRef","resumeSpeakingRef","cancelRef","useEffect","AudioCtx","gain","_d","hide","show","onVis","onPageHide","onPointer","onPageShow","cancelActiveSpeechSession","useCallback","bump","preloadSpeech","__vite_import_meta_env__","list","gen","kick","speakLesson","phraseList","prefetch","enqueue","playedAny","blocked","phraseComplete","follow","speakText","first","pauseSpeaking","resumeSpeaking","stopSpeaking","useImperativeHandle","jsx","NarratorAvatarFullLazy","lazy","isMobileLikeDevice","ua","resolveAvatarMode","avatarMode","NarratorAvatar","props","rest","mode","setMode","Suspense"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { CSSProperties, ForwardRefExoticComponent, RefAttributes } from 'react';
|
|
2
|
+
|
|
3
|
+
export type AvatarMode = 'auto' | 'full' | 'voice';
|
|
4
|
+
export type TtsService = 'deepgram' | 'google';
|
|
5
|
+
export type TeachingGestureName =
|
|
6
|
+
| 'greet' | 'invite' | 'explain' | 'count' | 'emphasize' | 'celebrate'
|
|
7
|
+
| 'encourage' | 'think' | 'caution' | 'thanks' | 'recap' | 'transition'
|
|
8
|
+
| 'wave' | 'bow' | 'nod' | 'disagree' | 'present' | 'whiteboard'
|
|
9
|
+
| 'welcomeSequence' | 'boardExplainSequence' | 'guidedQuestionSequence'
|
|
10
|
+
| 'celebrateSequence' | 'gentleCorrectionSequence' | 'recapSequence'
|
|
11
|
+
| 'goodbyeSequence';
|
|
12
|
+
|
|
13
|
+
export interface NarratorAvatarRef {
|
|
14
|
+
speakText(text: string, options?: Record<string, unknown>): void;
|
|
15
|
+
preloadSpeech(text: string): void;
|
|
16
|
+
pauseSpeaking(): void;
|
|
17
|
+
resumeSpeaking(): Promise<void> | void;
|
|
18
|
+
stopSpeaking(): void;
|
|
19
|
+
makeEyeContact(durationMs?: number): void;
|
|
20
|
+
setMood(mood: string): void;
|
|
21
|
+
setLighting(options: Record<string, unknown>): void;
|
|
22
|
+
setView(view: string, options?: Record<string, unknown>): void;
|
|
23
|
+
playGesture(name: string, dur?: number, mirror?: boolean, ms?: number): void;
|
|
24
|
+
playTeachingGesture(name: TeachingGestureName, options?: { dur?: number; mirror?: boolean; blendMs?: number }): boolean;
|
|
25
|
+
playAnimation(url: string, onprogress?: (event: ProgressEvent) => void, dur?: number, ndx?: number, scale?: number): void;
|
|
26
|
+
playPose(url: string, onprogress?: (event: ProgressEvent) => void, dur?: number, ndx?: number, scale?: number): void;
|
|
27
|
+
stopAnimation(): void;
|
|
28
|
+
stopPose(): void;
|
|
29
|
+
readonly isReady: boolean;
|
|
30
|
+
readonly isSpeaking: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface NarratorAvatarProps {
|
|
34
|
+
avatarUrl?: string;
|
|
35
|
+
avatarMode?: AvatarMode;
|
|
36
|
+
avatarBody?: 'M' | 'F';
|
|
37
|
+
cameraView?: 'full' | 'mid' | 'upper' | 'head';
|
|
38
|
+
/** Offset from the selected view's built-in camera distance. */
|
|
39
|
+
cameraDistance?: number;
|
|
40
|
+
/** Vertical camera framing offset. */
|
|
41
|
+
cameraY?: number;
|
|
42
|
+
ttsService?: TtsService;
|
|
43
|
+
ttsVoice?: string;
|
|
44
|
+
/** Use a backend proxy; browser-exposed provider keys are unsafe. */
|
|
45
|
+
ttsApiKey?: string | null;
|
|
46
|
+
/** Same-origin endpoint implemented by your server and authorized to call Deepgram. */
|
|
47
|
+
deepgramEndpoint?: string;
|
|
48
|
+
ttsEndpoint?: string;
|
|
49
|
+
lipsyncLang?: string;
|
|
50
|
+
visualQuality?: 'auto' | 'ultra' | 'balanced' | 'performance';
|
|
51
|
+
lazyMount?: boolean | 'auto';
|
|
52
|
+
speechRate?: number;
|
|
53
|
+
phraseGapMs?: number;
|
|
54
|
+
accurateLipSync?: boolean;
|
|
55
|
+
/** Drive Deepgram visemes from the audible waveform when AudioWorklet is available. */
|
|
56
|
+
audioDrivenLipSync?: boolean;
|
|
57
|
+
speechGestures?: boolean;
|
|
58
|
+
/** Optional full-body FBX URLs keyed by a `playTeachingGesture` semantic name. */
|
|
59
|
+
teachingAnimations?: Partial<Record<TeachingGestureName, string>>;
|
|
60
|
+
preloadText?: string | null;
|
|
61
|
+
onReady?: () => void;
|
|
62
|
+
onError?: (error: Error) => void;
|
|
63
|
+
onSpeechStart?: (text: string) => void;
|
|
64
|
+
onSpeechEnd?: () => void;
|
|
65
|
+
onSubtitle?: (text: string) => void;
|
|
66
|
+
className?: string;
|
|
67
|
+
style?: CSSProperties;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
declare const NarratorAvatar: ForwardRefExoticComponent<NarratorAvatarProps & RefAttributes<NarratorAvatarRef>>;
|
|
71
|
+
export { NarratorAvatar };
|
|
72
|
+
export default NarratorAvatar;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"narrator-avatar.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|