diff --git a/src/components/SpeakerButton/SpeakerButton.tsx b/src/components/SpeakerButton/SpeakerButton.tsx index 4f7cf6e..25abfdb 100644 --- a/src/components/SpeakerButton/SpeakerButton.tsx +++ b/src/components/SpeakerButton/SpeakerButton.tsx @@ -5,179 +5,103 @@ interface SpeakerButtonProps { text: string; } -// Liste bekannter männlicher Stimmen -const MALE_VOICE_NAMES = [ - 'deutsch male', 'german male', - 'markus', 'hans', 'stefan', 'klaus', - 'microsoft stefan', 'microsoft markus', - 'google deutsch männlich' -]; +// Liste von bekannten männlichen Stimmen +const MALE_VOICE_KEYWORDS = ['male', 'männlich', 'stefan', 'hans', 'michael', 'klaus']; export const SpeakerButton = ({ text }: SpeakerButtonProps) => { const [isPlaying, setIsPlaying] = useState(false); const [germanVoice, setGermanVoice] = useState(null); - const [isSupported, setIsSupported] = useState(false); const utteranceRef = useRef(null); useEffect(() => { - // Prüfe ob Speech Synthesis unterstützt wird - if (typeof window !== 'undefined' && 'speechSynthesis' in window && 'SpeechSynthesisUtterance' in window) { - setIsSupported(true); + // Funktion zum Laden der deutschen Männerstimme + const loadGermanVoice = () => { + const voices = window.speechSynthesis.getVoices(); + const germanVoices = voices.filter(voice => voice.lang.startsWith('de')); - const loadGermanVoice = () => { - try { - const voices = window.speechSynthesis.getVoices(); - - // Filter für deutsche Stimmen - const germanVoices = voices.filter(voice => - voice.lang.startsWith('de') || - voice.lang.startsWith('de-DE') - ); - - if (germanVoices.length > 0) { - // Suche nach männlicher Stimme - const maleVoice = germanVoices.find(voice => - MALE_VOICE_NAMES.some(name => - voice.name.toLowerCase().includes(name.toLowerCase()) - ) - ); - - // Versuche die beste Stimme zu finden - const selectedVoice = maleVoice || - // Fallback: Versuche eine Stimme mit "Deutsch" im Namen zu finden - germanVoices.find(voice => voice.name.toLowerCase().includes('deutsch')) || - // Sonst nimm die erste deutsche Stimme - germanVoices[0]; - - console.log('Verfügbare deutsche Stimmen:', germanVoices.map(v => v.name).join(', ')); - console.log('Gewählte Stimme:', selectedVoice.name); - - setGermanVoice(selectedVoice); - } else { - console.log('Keine deutsche Stimme gefunden'); - } - } catch (error) { - console.error('Fehler beim Laden der Stimmen:', error); - } - }; - - // Versuche Stimmen sofort zu laden - loadGermanVoice(); - - // Registriere Event-Listener für das Laden der Stimmen - if (window.speechSynthesis.onvoiceschanged !== undefined) { - window.speechSynthesis.onvoiceschanged = loadGermanVoice; + if (germanVoices.length > 0) { + // Suche nach männlicher Stimme + const maleVoice = germanVoices.find(voice => + MALE_VOICE_KEYWORDS.some(keyword => + voice.name.toLowerCase().includes(keyword) + ) + ); + + // Wenn keine explizit männliche Stimme gefunden wurde, + // bevorzuge Microsoft oder Google Stimmen + const selectedVoice = maleVoice || germanVoices.find( + voice => voice.name.includes('Microsoft') || voice.name.includes('Google') + ) || germanVoices[0]; + + setGermanVoice(selectedVoice); + console.log('Selected German voice:', selectedVoice.name); } + }; - return () => { - try { - window.speechSynthesis.cancel(); - if (window.speechSynthesis.onvoiceschanged !== undefined) { - window.speechSynthesis.onvoiceschanged = null; - } - } catch (error) { - console.error('Fehler beim Cleanup:', error); - } - }; - } else { - console.log('Speech Synthesis wird nicht unterstützt'); - } + // Lade Stimmen initial und wenn sie sich ändern + loadGermanVoice(); + window.speechSynthesis.onvoiceschanged = loadGermanVoice; + + // Cleanup + return () => { + window.speechSynthesis.cancel(); + window.speechSynthesis.onvoiceschanged = null; + }; }, []); - const handlePlay = () => { - if (!isSupported || !germanVoice) { - setIsPlaying(!isPlaying); - setTimeout(() => setIsPlaying(false), 500); + const speak = () => { + if (!window.speechSynthesis) { + console.error('Speech synthesis not supported'); return; } - try { - // Stoppe vorherige Wiedergabe - if (isPlaying) { - window.speechSynthesis.cancel(); - setIsPlaying(false); - return; - } - - // Text in Sätze aufteilen für natürlichere Pausen - const sentences = text.match(/[^.!?]+[.!?]+/g) || [text]; - let currentSentence = 0; - - const speakSentence = (sentence: string) => { - try { - const utterance = new SpeechSynthesisUtterance(sentence.trim()); - utterance.voice = germanVoice; - - // Optimierte Einstellungen für männlichere Stimme - utterance.rate = 0.85; // Etwas langsamer - utterance.pitch = 0.8; // Tiefere Stimme - utterance.volume = 1.0; // Volle Lautstärke - - utterance.onstart = () => setIsPlaying(true); - utterance.onend = () => { - currentSentence++; - if (currentSentence < sentences.length) { - // Kurze Pause zwischen Sätzen - setTimeout(() => { - speakSentence(sentences[currentSentence]); - }, 300); - } else { - setIsPlaying(false); - } - }; + // Stoppe vorherige Sprachausgabe + window.speechSynthesis.cancel(); + + const utterance = new SpeechSynthesisUtterance(text); + utterance.lang = 'de-DE'; + utterance.rate = 0.9; // 10% langsamer für bessere Verständlichkeit + utterance.pitch = 0.6; // Leicht tiefere Stimme (0-2, normal ist 1.0) + utterance.volume = 1.0; // Maximale Lautstärke + + if (germanVoice) { + utterance.voice = germanVoice; + } - utterance.onerror = (event) => { - console.error('Fehler bei der Sprachausgabe:', event); - setIsPlaying(false); - }; + utterance.onstart = () => setIsPlaying(true); + utterance.onend = () => setIsPlaying(false); + utterance.onerror = (event) => { + console.error('Speech synthesis error:', event); + setIsPlaying(false); + }; - utteranceRef.current = utterance; - window.speechSynthesis.speak(utterance); - } catch (error) { - console.error('Fehler beim Sprechen eines Satzes:', error); - setIsPlaying(false); - } - }; + utteranceRef.current = utterance; + window.speechSynthesis.speak(utterance); + }; - speakSentence(sentences[0]); - } catch (error) { - console.error('Fehler beim Starten der Sprachausgabe:', error); - setIsPlaying(false); - } + const stopSpeaking = () => { + window.speechSynthesis.cancel(); + setIsPlaying(false); }; return (
); -}; +}; \ No newline at end of file