'use client'; import { useEffect, useRef, useState, useCallback } from 'react'; import { Loader2, Mic, Square } from 'lucide-react'; import { cn } from '@/lib/utils'; export interface SpeechRecorderProps { onTranscript: (text: string) => void; disabled?: boolean; className?: string; } export function SpeechRecorder({ onTranscript, disabled = false, className }: SpeechRecorderProps) { const mediaRecorderRef = useRef(null); const chunksRef = useRef([]); const [isRecording, setIsRecording] = useState(false); const [isUploading, setIsUploading] = useState(false); const [error, setError] = useState(null); const [permissionDenied, setPermissionDenied] = useState(false); useEffect(() => { return () => { mediaRecorderRef.current?.stream.getTracks().forEach((track) => track.stop()); }; }, []); const stopStream = () => { mediaRecorderRef.current?.stream.getTracks().forEach((track) => track.stop()); mediaRecorderRef.current = null; }; const handleStop = useCallback(async () => { setIsRecording(false); const chunks = chunksRef.current; chunksRef.current = []; stopStream(); if (chunks.length === 0) return; const blob = new Blob(chunks, { type: 'audio/webm' }); const formData = new FormData(); formData.append('file', blob, 'recording.webm'); try { setIsUploading(true); setError(null); const response = await fetch('/api/deepgram/transcribe', { method: 'POST', body: formData, }); if (!response.ok) { const data = await response.json().catch(() => ({})); throw new Error(data.error || 'Transcriptie mislukt'); } const data = await response.json(); if (data.transcript) { onTranscript(data.transcript as string); } } catch (err) { console.error(err); setError(err instanceof Error ? err.message : 'Onbekende fout'); } finally { setIsUploading(false); } }, [onTranscript]); const startRecording = async () => { if (disabled || isUploading) return; try { setError(null); setPermissionDenied(false); const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' }); mediaRecorderRef.current = mediaRecorder; chunksRef.current = []; mediaRecorder.ondataavailable = (event) => { if (event.data.size > 0) { chunksRef.current.push(event.data); } }; mediaRecorder.onstop = handleStop; mediaRecorder.start(); setIsRecording(true); } catch (err) { console.error(err); setPermissionDenied(true); setError('Toegang tot microfoon geweigerd of niet beschikbaar.'); } }; const stopRecording = () => { if (mediaRecorderRef.current && mediaRecorderRef.current.state !== 'inactive') { mediaRecorderRef.current.stop(); } }; const isBusy = isRecording || isUploading; return (

Spraak-naar-tekst

{isRecording ? 'Opname loopt…' : 'Neem een fragment op en laat Deepgram transcriberen.'}

{isUploading && (

Transcriptie bezig…

)} {permissionDenied &&

Microfoontoegang nodig om op te nemen.

} {error && !permissionDenied &&

{error}

}
); }