use-stt
Version:
React hook for speech-to-text using multiple STT providers
1 lines • 39.6 kB
Source Map (JSON)
{"version":3,"sources":["../src/hooks/useSTT.ts","../src/audio/recorder.ts","../src/adapters/baseAdapter.ts","../src/utils/audioConverter.ts","../src/adapters/whisperAdapter.ts","../src/hooks/useFFmpeg.ts"],"sourcesContent":["import { useState, useCallback, useRef, useEffect } from 'react';\nimport { STTOptions, STTResult } from '../types';\nimport { BaseError } from '../adapters/baseAdapter';\nimport { WhisperAdapter } from '../adapters/whisperAdapter';\nimport { useFFmpeg } from './useFFmpeg';\n\ninterface UseSTTResult {\n transcript: string;\n isRecording: boolean;\n isProcessing: boolean;\n error: Error | null;\n isInitialized: boolean;\n isStopping: boolean;\n startRecording: () => Promise<void>;\n stopRecording: () => Promise<void>;\n pauseRecording: () => void;\n resumeRecording: () => void;\n}\n\nconst isDev = process.env.NODE_ENV === 'development';\n\nexport function useSTT(options: STTOptions): UseSTTResult {\n const { disabled = false } = options;\n const [isRecording, setIsRecording] = useState(false);\n const [isProcessing, setIsProcessing] = useState(false);\n const [transcript, setTranscript] = useState('');\n const [error, setError] = useState<Error | null>(null);\n const [isInitialized, setIsInitialized] = useState(false);\n const [isStopping, setIsStopping] = useState(false);\n const adapterRef = useRef<WhisperAdapter | null>(null);\n const optionsRef = useRef(options);\n\n useEffect(() => {\n optionsRef.current = options;\n }, [options]);\n\n const { ffmpeg, loaded, loading, error: ffmpegError, load: loadFFmpeg } = useFFmpeg();\n\n useEffect(() => {\n if (disabled) {\n if (isDev) console.log('useSTT is disabled. Cleaning up adapter.');\n if (adapterRef.current) {\n adapterRef.current.abort();\n adapterRef.current = null;\n }\n setIsRecording(false);\n setIsStopping(false);\n setIsInitialized(false);\n } else if (loaded && ffmpeg && !adapterRef.current && !isInitialized) {\n if (isDev) console.log('useSTT is re-enabled. Will attempt to initialize adapter if not already initializing.');\n }\n }, [disabled, loaded, ffmpeg, isInitialized]);\n\n useEffect(() => {\n let isMounted = true;\n\n const initializeAdapter = async () => {\n if (disabled || !loaded || !ffmpeg) {\n if (ffmpegError && isMounted && !disabled) {\n setError(ffmpegError);\n }\n return;\n }\n\n if (adapterRef.current && isInitialized) return;\n \n if (isDev) console.log('useSTT: Initializing adapter.');\n try {\n console.log('Creating new WhisperAdapter instance');\n const adapter = new WhisperAdapter({\n ...optionsRef.current,\n ffmpeg,\n onResult: (result: STTResult) => {\n if (!isMounted || optionsRef.current.disabled) return;\n setTranscript(result.transcript);\n if (result.isFinal) {\n setIsProcessing(false);\n }\n },\n onError: (err: Error) => {\n if (!isMounted || optionsRef.current.disabled) return;\n setError(err);\n setIsProcessing(false);\n setIsRecording(false);\n },\n onStart: () => {\n if (!isMounted || optionsRef.current.disabled) return;\n setError(null);\n setIsRecording(true);\n setIsProcessing(true);\n },\n onEnd: () => {\n if (!isMounted || optionsRef.current.disabled) return;\n setIsRecording(false);\n setIsStopping(false);\n }\n });\n\n adapterRef.current = adapter;\n if (isMounted) {\n setIsInitialized(true);\n setError(null);\n }\n } catch (err) {\n console.error('Error initializing adapter:', err);\n if (isMounted && !optionsRef.current.disabled) {\n setError(err instanceof Error ? err : new BaseError('Failed to initialize adapter'));\n setIsInitialized(false);\n }\n }\n };\n\n initializeAdapter();\n\n return () => {\n isMounted = false;\n if (adapterRef.current && !optionsRef.current.disabled) {\n if (isDev) console.log('useSTT: Unmounting, aborting adapter.');\n adapterRef.current.abort();\n adapterRef.current = null;\n } else if (adapterRef.current && optionsRef.current.disabled) {\n adapterRef.current = null;\n }\n };\n }, [loaded, ffmpeg, ffmpegError, disabled, isInitialized]);\n\n useEffect(() => {\n if (disabled) {\n if (isDev) console.log('useSTT is disabled. FFmpeg load call skipped.');\n return;\n }\n if (!loaded && !loading && !ffmpegError) {\n if (isDev) console.log('useSTT: loadFFmpeg called.');\n loadFFmpeg();\n }\n }, [loadFFmpeg, disabled, loaded, loading, ffmpegError]);\n\n const startRecording = useCallback(async () => {\n // Priority 1: Check if disabled\n if (optionsRef.current.disabled) {\n if (isDev) console.log('useSTT: startRecording aborted (STT is disabled).');\n throw new Error('STT is disabled.');\n }\n\n // Priority 2: Check for FFmpeg loading errors directly\n // This error should be surfaced regardless of initialization state if an attempt to record is made.\n if (ffmpegError) {\n if (isDev) console.log('useSTT: startRecording aborted (FFmpeg error).');\n throw ffmpegError; \n }\n \n // Priority 3: Check if FFmpeg is actually loaded (should be redundant if ffmpegError is null, but good safeguard)\n if (!loaded || !ffmpeg) {\n if (isDev) console.log('useSTT: startRecording aborted (FFmpeg not loaded).');\n throw new Error('FFmpeg not loaded');\n }\n\n // Priority 4: Check if adapter is initialized\n if (!isInitialized || !adapterRef.current) {\n if (isDev) console.log('useSTT: startRecording aborted (adapter not initialized or no adapter).');\n throw new Error('STT adapter not initialized.');\n }\n\n // If all checks pass, proceed with starting the adapter\n try {\n await adapterRef.current.start();\n } catch (err) {\n // Error during adapter.start() call\n if (!optionsRef.current.disabled) { // Only set component error state if not disabled\n setIsRecording(false);\n setIsProcessing(false);\n setError(err instanceof Error ? err : new BaseError('Failed to start recording'));\n }\n throw err; // Re-throw to allow parent to catch\n }\n }, [loaded, ffmpeg, ffmpegError, isInitialized]); // optionsRef.current.disabled is checked inside\n\n const stopRecording = useCallback(async () => {\n if (!adapterRef.current) {\n if (isDev) console.log('useSTT: stopRecording aborted (no adapter).');\n return;\n }\n if (isDev) console.log('useSTT: stopRecording called.');\n try {\n setIsStopping(true);\n await adapterRef.current.stop();\n if (optionsRef.current.disabled) {\n setIsStopping(false);\n setIsRecording(false);\n setIsProcessing(false);\n }\n } catch (err) {\n if (!optionsRef.current.disabled) {\n setError(err instanceof Error ? err : new BaseError('Failed to stop recording'));\n }\n setIsStopping(false);\n setIsProcessing(false);\n throw err;\n }\n }, []);\n\n const pauseRecording = useCallback(() => {\n if (optionsRef.current.disabled || !adapterRef.current) {\n if (isDev) console.log('useSTT: pauseRecording aborted (disabled or no adapter).');\n return;\n }\n if (isDev) console.log('useSTT: pauseRecording called.');\n adapterRef.current.pause();\n }, []);\n\n const resumeRecording = useCallback(() => {\n if (optionsRef.current.disabled || !adapterRef.current) {\n if (isDev) console.log('useSTT: resumeRecording aborted (disabled or no adapter).');\n return;\n }\n if (isDev) console.log('useSTT: resumeRecording called.');\n adapterRef.current.resume();\n }, []);\n\n return {\n transcript,\n isRecording,\n isProcessing: isProcessing || loading,\n error: error || ffmpegError,\n isInitialized,\n isStopping,\n startRecording,\n stopRecording,\n pauseRecording,\n resumeRecording,\n };\n}\n","export interface AudioRecorderOptions {\n onDataAvailable?: (data: Blob) => void;\n onError?: (error: Error) => void;\n mimeType?: string;\n}\n\nexport class AudioRecorder {\n private mediaRecorder: MediaRecorder | null = null;\n private stream: MediaStream | null = null;\n private options: AudioRecorderOptions;\n\n constructor(options: AudioRecorderOptions) {\n this.options = options;\n }\n\n private getSupportedMimeType(): string {\n const mimeTypes = [\n 'audio/webm',\n 'audio/mp4',\n 'audio/ogg',\n 'audio/wav'\n ];\n\n if (this.options.mimeType && MediaRecorder.isTypeSupported(this.options.mimeType)) {\n return this.options.mimeType;\n }\n\n const supportedType = mimeTypes.find(type => MediaRecorder.isTypeSupported(type));\n if (!supportedType) {\n throw new Error('No supported audio MIME types found');\n }\n\n return supportedType;\n }\n\n async start(): Promise<void> {\n try {\n if (this.mediaRecorder?.state === 'recording') {\n throw new Error('Recording already in progress');\n }\n\n const stream = await navigator.mediaDevices.getUserMedia({ \n audio: {\n channelCount: 1,\n sampleRate: 16000,\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true\n } \n });\n\n const mimeType = this.getSupportedMimeType();\n console.log('Creating MediaRecorder with options:', {\n mimeType,\n platform: typeof window !== 'undefined' ? window.navigator.platform : 'unknown',\n userAgent: typeof window !== 'undefined' ? window.navigator.userAgent : 'unknown'\n });\n\n this.stream = stream;\n this.mediaRecorder = new MediaRecorder(stream, { mimeType });\n \n this.mediaRecorder.ondataavailable = (event) => {\n if (event.data.size > 0 && this.options.onDataAvailable) {\n console.log('MediaRecorder data available:', {\n size: event.data.size,\n type: event.data.type\n });\n this.options.onDataAvailable(event.data);\n }\n };\n\n this.mediaRecorder.onerror = (event) => {\n const error = event.error || new Error('MediaRecorder error');\n if (this.options.onError) {\n this.options.onError(error);\n }\n };\n\n this.mediaRecorder.start();\n console.log('MediaRecorder started');\n } catch (error) {\n console.error('Error starting MediaRecorder:', error);\n if (this.options.onError) {\n this.options.onError(error as Error);\n }\n throw error;\n }\n }\n\n async stop(): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.mediaRecorder) {\n reject(new Error('MediaRecorder not initialized'));\n return;\n }\n\n console.log('Stopping MediaRecorder');\n \n const handleStop = () => {\n this.cleanup();\n resolve();\n };\n\n const handleError = (event: Event) => {\n this.cleanup();\n reject(new Error('MediaRecorder error'));\n };\n\n this.mediaRecorder.onstop = handleStop;\n this.mediaRecorder.onerror = handleError;\n \n this.mediaRecorder.stop();\n });\n }\n\n pause(): void {\n if (this.mediaRecorder?.state === 'recording') {\n this.mediaRecorder.pause();\n }\n }\n\n resume(): void {\n if (this.mediaRecorder?.state === 'paused') {\n this.mediaRecorder.resume();\n }\n }\n\n private cleanup(): void {\n if (this.stream) {\n this.stream.getTracks().forEach(track => track.stop());\n this.stream = null;\n }\n this.mediaRecorder = null;\n }\n} ","import { STTOptions, STTResult } from '../types';\nimport { AudioRecorder } from '../audio/recorder';\n\nexport class BaseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'BaseError';\n }\n}\n\nexport abstract class BaseAdapter {\n protected options: STTOptions;\n protected recorder: AudioRecorder | null = null;\n \n // Callbacks\n protected resultCallback?: (result: STTResult) => void;\n protected errorCallback?: (error: Error) => void;\n protected startCallback?: () => void;\n protected endCallback?: () => void;\n \n constructor(options: STTOptions) {\n console.log('Initializing BaseAdapter');\n this.options = options;\n // Initialize callbacks from options\n if (options.onResult) this.resultCallback = options.onResult;\n if (options.onError) this.errorCallback = options.onError;\n if (options.onStart) this.startCallback = options.onStart;\n if (options.onEnd) this.endCallback = options.onEnd;\n }\n\n protected handleError(error: unknown) {\n const err = error instanceof Error ? error : new BaseError('Unknown error');\n // Call error callback first to set error state\n this.errorCallback?.(err);\n // Then call end callback to reset processing/recording states\n this.endCallback?.();\n // Clean up recorder if it exists\n if (this.recorder) {\n this.recorder.stop().catch(console.error);\n this.recorder = null;\n }\n throw err; // Re-throw to propagate to caller\n }\n\n // Core method that derived classes must implement - this is where provider-specific logic goes\n protected abstract processAudio(audioBlob: Blob): Promise<STTResult>;\n \n async start(): Promise<void> {\n try { \n console.log('Starting adapter...');\n \n // Initialize recorder first\n this.recorder = new AudioRecorder({\n mimeType: 'audio/webm',\n onDataAvailable: async (data) => {\n try {\n console.log('Processing complete recording:', {\n size: data.size,\n type: data.type\n });\n const result = await this.processAudio(data);\n this.resultCallback?.(result);\n this.endCallback?.(); // Call end callback after successful processing\n } catch (error) {\n console.error('Error processing audio:', error);\n this.handleError(error);\n }\n },\n onError: (error) => this.handleError(error)\n });\n\n // Call startCallback before starting recording to ensure state is set\n this.startCallback?.();\n\n // Wait for the recorder to start before proceeding\n await this.recorder.start();\n } catch (error) {\n console.error('Error in start():', error);\n this.handleError(error);\n }\n }\n\n async stop(): Promise<void> {\n try {\n if (!this.recorder) return;\n console.log('Stopping recording...');\n const currentRecorder = this.recorder;\n await currentRecorder.stop();\n this.recorder = null;\n } catch (error) {\n console.error('Error in stop():', error);\n this.handleError(error);\n }\n }\n\n pause(): void {\n if (this.recorder) {\n this.recorder.pause();\n }\n }\n\n resume(): void {\n if (this.recorder) {\n this.recorder.resume();\n }\n }\n\n async abort(): Promise<void> {\n console.log('Cleaning up adapter...');\n if (this.recorder) {\n try {\n await this.recorder.stop();\n this.recorder = null;\n } catch (error) {\n console.error('Error in abort():', error);\n }\n }\n }\n\n // Callback setters\n onResult(callback: (result: STTResult) => void): void {\n this.resultCallback = callback;\n }\n\n onError(callback: (error: Error) => void): void {\n this.errorCallback = callback;\n }\n\n onStart(callback: () => void): void {\n this.startCallback = callback;\n }\n\n onEnd(callback: () => void): void {\n this.endCallback = callback;\n }\n}\n","import { FFmpeg } from '@ffmpeg/ffmpeg';\nimport { fetchFile } from '@ffmpeg/util';\nimport type { FFmpegConfig, AudioMetadata } from '../types';\n\nconst SUPPORTED_INPUT_FORMATS = [\n 'audio/webm',\n 'audio/mp4',\n 'audio/wav',\n 'audio/ogg',\n 'audio/mpeg'\n];\n\nfunction validateAudioFormat(blob: Blob) {\n // Extract main MIME type without codecs\n const mainType = blob.type.split(';')[0];\n if (!SUPPORTED_INPUT_FORMATS.includes(mainType)) {\n throw new Error(`Unsupported audio format: ${blob.type}. Supported formats are: ${SUPPORTED_INPUT_FORMATS.join(', ')}`);\n }\n}\n\nexport async function convertAudioToWebM(ffmpeg: FFmpeg, file: File | Blob, config: FFmpegConfig = {}): Promise<Blob> {\n console.log('Starting audio conversion to WebM...', {\n fileType: file.type,\n fileSize: file.size,\n config\n });\n validateAudioFormat(file);\n \n try {\n console.log('Writing input file...');\n const fileData = await fetchFile(file);\n await ffmpeg.writeFile('input', fileData);\n console.log('Input file written successfully');\n\n console.log('Converting to WebM...');\n const args = [\n '-i', 'input',\n '-ar', `${config.outputSampleRate || 16000}`, // Sample rate\n '-ac', `${config.outputChannels || 1}`, // Channels\n ];\n\n // Add filters\n const filters: string[] = [];\n \n // Noise reduction if requested\n if (config.denoise) {\n filters.push('anlmdn'); // Noise reduction filter\n }\n\n // Normalization if requested\n if (config.normalize) {\n filters.push(`loudnorm=I=${config.normalizationLevel || -16}`);\n }\n\n // Voice Activity Detection if requested\n if (config.vad) {\n filters.push(`silenceremove=start_periods=1:start_duration=1:start_threshold=${config.vadLevel || 1}:detection=peak`);\n }\n\n // Add any custom filters\n if (config.filters && config.filters.length > 0) {\n filters.push(...config.filters);\n }\n\n // Apply all filters if any\n if (filters.length > 0) {\n args.push('-af', filters.join(','));\n }\n\n // Add codec and compression settings\n args.push(\n '-c:a', 'libopus',\n '-b:a', config.bitrate || '24k',\n '-compression_level', `${config.compressionLevel || 10}`\n );\n\n args.push('output.webm');\n \n console.log('FFmpeg conversion args:', args);\n await ffmpeg.exec(args);\n console.log('FFmpeg conversion completed');\n\n const data = await ffmpeg.readFile('output.webm');\n \n // Clean up\n await ffmpeg.deleteFile('input');\n await ffmpeg.deleteFile('output.webm');\n\n const blob = new Blob([data], { type: 'audio/webm;codecs=opus' });\n console.log('Conversion complete:', {\n inputSize: file.size,\n outputSize: blob.size,\n outputType: blob.type,\n appliedFilters: filters\n });\n return blob;\n } catch (error) {\n console.error('Audio conversion failed:', {\n error,\n message: error instanceof Error ? error.message : 'Unknown error',\n stack: error instanceof Error ? error.stack : undefined\n });\n throw error;\n }\n}\n\n// Keep the original convertAudioToMono as a fallback\nexport async function convertAudioToMono(ffmpeg: FFmpeg, file: File | Blob): Promise<Blob> {\n return convertAudioToWebM(ffmpeg, file);\n}\n\nexport async function convertWithFFmpeg(\n ffmpeg: FFmpeg,\n file: File | Blob, \n config: FFmpegConfig = {}\n): Promise<Blob> {\n console.log('Starting FFmpeg conversion with config:', config);\n \n try {\n // Write input file\n console.log('Writing input file...');\n await ffmpeg.writeFile('input', await fetchFile(file));\n\n // Build FFmpeg arguments\n const args = [\n '-i', 'input',\n '-ar', `${config.outputSampleRate || 16000}`,\n '-ac', `${config.outputChannels || 1}`,\n ];\n\n // Add normalization if requested\n if (config.normalize) {\n args.push('-filter:a', 'loudnorm');\n }\n\n // Add codec\n args.push('-c:a', config.codec || 'pcm_s16le');\n\n // Add output file\n const outputFile = `output.${config.outputFormat || 'wav'}`;\n args.push(outputFile);\n\n // Execute FFmpeg command\n console.log('Executing FFmpeg command with args:', args);\n await ffmpeg.exec(args);\n\n // Read the output file\n console.log('Reading converted file...');\n const data = await ffmpeg.readFile(outputFile);\n \n // Clean up\n console.log('Cleaning up...');\n await ffmpeg.deleteFile('input');\n await ffmpeg.deleteFile(outputFile);\n\n // Convert to Blob\n const blob = new Blob([data], { \n type: `audio/${config.outputFormat || 'wav'}`\n });\n console.log('Conversion complete. Output size:', blob.size);\n return blob;\n } catch (error) {\n console.error('FFmpeg conversion error:', error);\n throw new Error('Audio conversion failed: ' + (error instanceof Error ? error.message : 'Unknown error'));\n }\n}\n\nexport async function getAudioMetadata(ffmpeg: FFmpeg, file: File | Blob): Promise<AudioMetadata> {\n console.log('Getting audio metadata...');\n \n try {\n // Write input file\n console.log('Writing input file...');\n await ffmpeg.writeFile('input', await fetchFile(file));\n\n // Get file information using FFprobe\n console.log('Getting file information...');\n await ffmpeg.exec([\n '-i', 'input',\n '-f', 'null', '-'\n ]);\n\n // Clean up\n console.log('Cleaning up...');\n await ffmpeg.deleteFile('input');\n\n // Parse FFprobe output (this is a simplified example)\n // In reality, you'd want to parse the FFprobe output more carefully\n const metadata = {\n duration: 0, // You'd get this from FFprobe output\n sampleRate: 16000,\n channels: 1,\n format: file.type as any,\n size: file.size\n };\n console.log('Metadata extracted:', metadata);\n return metadata;\n } catch (error) {\n console.error('FFmpeg metadata error:', error);\n throw new Error('Failed to get audio metadata: ' + (error instanceof Error ? error.message : 'Unknown error'));\n }\n} ","import { BaseAdapter, BaseError } from './baseAdapter';\nimport { STTOptions, STTResult } from '../types';\nimport { convertAudioToMono } from '../utils/audioConverter';\nimport { FFmpeg } from '@ffmpeg/ffmpeg';\n\ninterface WhisperAdapterOptions extends STTOptions {\n ffmpeg: FFmpeg;\n onResult?: (result: STTResult) => void;\n onError?: (error: Error) => void;\n onStart?: () => void;\n onEnd?: () => void;\n}\n\nexport class WhisperAdapter extends BaseAdapter {\n private ffmpeg: FFmpeg;\n\n constructor(options: WhisperAdapterOptions) {\n super(options);\n console.log('Initializing WhisperAdapter');\n this.ffmpeg = options.ffmpeg;\n }\n\n protected async processAudio(audioBlob: Blob): Promise<STTResult> {\n try {\n if (audioBlob.size === 0) {\n return {\n transcript: '',\n isFinal: true,\n confidence: 1\n };\n }\n\n // Check if we already have WebM format\n const isWebM = audioBlob.type.includes('webm');\n \n let processedBlob = audioBlob;\n if (!isWebM) {\n // Convert non-WebM formats to WebM with Opus codec\n console.log('Converting audio to WebM format...', {\n originalFormat: audioBlob.type,\n originalSize: audioBlob.size\n });\n processedBlob = await convertAudioToMono(this.ffmpeg, audioBlob);\n console.log('Conversion complete:', {\n newFormat: processedBlob.type,\n newSize: processedBlob.size\n });\n } else {\n console.log('Audio already in WebM format, skipping conversion:', {\n format: audioBlob.type,\n size: audioBlob.size\n });\n }\n\n console.log('Processing audio with transcribe function...');\n const result = await this.options.transcribe(processedBlob);\n \n return {\n transcript: result.transcript,\n isFinal: true,\n confidence: result.confidence ?? 0.95\n };\n } catch (error) {\n console.error('Error in processAudio:', error);\n const baseError = new BaseError(error instanceof Error ? error.message : 'Transcription failed');\n baseError.cause = error; // Preserve original error as cause\n throw baseError;\n }\n }\n}\n","import { useState, useRef, useCallback } from 'react';\nimport { FFmpeg } from '@ffmpeg/ffmpeg';\nimport { toBlobURL } from '@ffmpeg/util';\n\ninterface UseFFmpegResult {\n ffmpeg: FFmpeg | null;\n loaded: boolean;\n loading: boolean;\n error: Error | null;\n load: () => Promise<void>;\n}\n\nexport function useFFmpeg(): UseFFmpegResult {\n const [loaded, setLoaded] = useState(false);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const ffmpegRef = useRef<FFmpeg | null>(null);\n\n const load = useCallback(async () => {\n try {\n setLoading(true);\n setError(null);\n\n // Create new FFmpeg instance if not exists\n if (!ffmpegRef.current) {\n ffmpegRef.current = new FFmpeg();\n }\n\n const ffmpeg = ffmpegRef.current;\n\n // Add logging handler\n ffmpeg.on('log', ({ message }) => {\n console.log('FFmpeg:', message);\n });\n\n // Load FFmpeg core files\n const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.10/dist/umd';\n await ffmpeg.load({\n coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),\n wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'),\n });\n\n setLoaded(true);\n } catch (err) {\n console.error('Failed to load FFmpeg:', err);\n setError(err instanceof Error ? err : new Error('Failed to load FFmpeg'));\n } finally {\n setLoading(false);\n }\n }, []);\n\n return {\n ffmpeg: ffmpegRef.current,\n loaded,\n loading,\n error,\n load\n };\n} "],"mappings":"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","names":["useState","useCallback","useRef","useState","useRef","useCallback"]}