import React, { useState, useRef, useEffect } from 'react'; import { Button } from '../ui/button'; const FreeTextToSpeech = () => { // State management const [text, setText] = useState(''); const [voices, setVoices] = useState([]); const [selectedVoice, setSelectedVoice] = useState(''); const [pitch, setPitch] = useState(1); const [rate, setRate] = useState(1); const [volume, setVolume] = useState(1); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [status, setStatus] = useState('Enter text to convert to speech'); const [isSpeaking, setIsSpeaking] = useState(false); const [isPaused, setIsPaused] = useState(false); const [copied, setCopied] = useState(false); const [debugLogs, setDebugLogs] = useState([]); const [showDebug, setShowDebug] = useState(false); // Refs const synthRef = useRef(null); const utteranceRef = useRef(null); const audioRef = useRef(null); const textareaRef = useRef(null); // Debug logging const addDebugLog = (message) => { const timestamp = new Date().toISOString().split('T')[1].split('.')[0]; const logMessage = `${timestamp}: ${message}`; setDebugLogs(prev => [...prev.slice(-100), logMessage]); console.debug(logMessage); }; // Initialize speech synthesis useEffect(() => { if (typeof window !== 'undefined') { synthRef.current = window.speechSynthesis; const loadVoices = () => { const availableVoices = synthRef.current.getVoices(); setVoices(availableVoices); if (availableVoices.length > 0) { setSelectedVoice(availableVoices[0].name); } addDebugLog(`Loaded ${availableVoices.length} voices`); }; // Chrome loads voices asynchronously synthRef.current.onvoiceschanged = loadVoices; loadVoices(); return () => { if (synthRef.current) { synthRef.current.onvoiceschanged = null; } }; } }, []); // Handle speaking const handleSpeak = () => { if (!text.trim()) { setError('Please enter some text to speak'); setStatus('Please enter some text to speak'); addDebugLog('No text provided for speech'); return; } if (!synthRef.current) { setError('Speech synthesis not supported in this browser'); setStatus('Speech synthesis not supported'); addDebugLog('Speech synthesis API not available'); return; } if (isPaused) { synthRef.current.resume(); setIsPaused(false); setIsSpeaking(true); setStatus('Resumed speaking'); addDebugLog('Resumed speech playback'); return; } // Cancel any current speech synthRef.current.cancel(); // Create a new utterance const utterance = new SpeechSynthesisUtterance(text); utteranceRef.current = utterance; // Set utterance properties const selectedVoiceObj = voices.find(v => v.name === selectedVoice); if (selectedVoiceObj) { utterance.voice = selectedVoiceObj; addDebugLog(`Using voice: ${selectedVoiceObj.name} (${selectedVoiceObj.lang})`); } utterance.pitch = pitch; utterance.rate = rate; utterance.volume = volume; // Event handlers utterance.onstart = () => { setIsSpeaking(true); setIsPaused(false); setStatus('Speaking...'); addDebugLog('Speech started'); }; utterance.onend = () => { setIsSpeaking(false); setIsPaused(false); setStatus('Finished speaking'); addDebugLog('Speech completed'); }; utterance.onerror = (event) => { setIsSpeaking(false); setIsPaused(false); setStatus(`Error occurred: ${event.error}`); addDebugLog(`Speech error: ${event.error}`); }; // Speak the utterance synthRef.current.speak(utterance); setStatus('Started speaking...'); addDebugLog('Initiated speech synthesis'); }; const handlePause = () => { if (isSpeaking && !isPaused && synthRef.current) { synthRef.current.pause(); setIsPaused(true); setIsSpeaking(false); setStatus('Paused'); addDebugLog('Speech paused'); } }; const handleStop = () => { if (synthRef.current) { synthRef.current.cancel(); setIsSpeaking(false); setIsPaused(false); setStatus('Stopped speaking'); addDebugLog('Speech stopped'); } }; const handleDownload = () => { setStatus('Download requires a TTS API service'); setError('Download functionality requires a TTS API service'); addDebugLog('Download attempted (not implemented)'); }; // Copy text to clipboard const copyToClipboard = () => { if (!text) return; navigator.clipboard.writeText(text).then(() => { setCopied(true); setTimeout(() => setCopied(false), 2000); addDebugLog('Text copied to clipboard'); }).catch(err => { const errorMsg = 'Failed to copy text to clipboard'; addDebugLog(`${errorMsg}: ${err.message}`); setError(errorMsg); }); }; // Clear all inputs and states const clearAll = () => { setText(''); setError(null); setStatus('Enter text to convert to speech'); if (synthRef.current) { synthRef.current.cancel(); } setIsSpeaking(false); setIsPaused(false); addDebugLog('All inputs and states cleared'); }; // Helper functions const clearDebugLogs = () => { setDebugLogs([]); addDebugLog('Debug logs cleared'); }; const toggleDebug = () => { setShowDebug(!showDebug); addDebugLog(`Debug panel ${showDebug ? 'hidden' : 'shown'}`); }; return (

Text to Speech (Using Google)

{/* Text Input Section */}