import React, { useState, useEffect, useRef } from 'react'; import MicIcon from '@mui/icons-material/Mic'; import StopIcon from '@mui/icons-material/Stop'; import styles from './page.module.css'; import useSpeechRecognition from './hooks/useSpeechRecognition'; import useAudioManager from './hooks/useAudioManager'; const getMimeType = (): string | null => { const types = ["audio/webm", "audio/mp4", "audio/ogg", "audio/wav", "audio/aac"]; for (let type of types) { if (MediaRecorder.isTypeSupported(type)) { return type; } } return null; }; interface VoiceInputFormProps { handleSubmit: any; input: string; setInput: React.Dispatch>; } const VoiceInputForm: React.FC = ({ handleSubmit, input, setInput }) => { const [isRecording, setIsRecording] = useState(false); const { startListening, stopListening, recognizedText } = useSpeechRecognition(); const { setAudioFromRecording } = useAudioManager(); const mediaRecorderRef = useRef(null); const audioChunksRef = useRef([]); useEffect(() => { if (recognizedText) { setInput(recognizedText); } }, [recognizedText, setInput]); const startRecording = async () => { try { const mimeType = getMimeType(); const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); mediaRecorderRef.current = new MediaRecorder(stream, { mimeType: mimeType ?? undefined }); audioChunksRef.current = []; mediaRecorderRef.current.ondataavailable = (event: BlobEvent) => { audioChunksRef.current.push(event.data); }; mediaRecorderRef.current.start(); } catch (err) { console.error("Error accessing media devices:", err); } }; const stopRecording = async (): Promise => { return new Promise((resolve, reject) => { const recorder = mediaRecorderRef.current; if (recorder && recorder.state === "recording") { recorder.onstop = () => { const audioBlob = new Blob(audioChunksRef.current, { 'type': recorder.mimeType }); audioChunksRef.current = []; resolve(audioBlob); }; recorder.stop(); } else { reject(new Error("MediaRecorder is not recording")); } }); }; const handleRecording = async () => { if (isRecording) { stopListening(); const recordedBlob = await stopRecording(); setAudioFromRecording(recordedBlob); const audioBuffer = await convertBlobToAudioBuffer(recordedBlob); startListening(audioBuffer); } else { startRecording(); } setIsRecording(!isRecording); }; return (
setInput(e.target.value)} placeholder="Speak or type..." />
); }; const convertBlobToAudioBuffer = async (blob: Blob): Promise => { const audioContext = new AudioContext(); const arrayBuffer = await blob.arrayBuffer(); return await audioContext.decodeAudioData(arrayBuffer); }; export default VoiceInputForm;