feat: add voice-to-text input using Web Speech API

This commit is contained in:
Christian Vidal Wolf
2026-04-11 11:34:57 +02:00
parent 5104dfd59d
commit 0e797e06bb
2 changed files with 116 additions and 3 deletions
+74
View File
@@ -0,0 +1,74 @@
import { useState, useCallback, useRef, useEffect } from 'react';
interface UseSpeechRecognitionOptions {
onResult: (transcript: string) => void;
lang?: string;
}
interface UseSpeechRecognitionReturn {
isListening: boolean;
start: () => void;
stop: () => void;
isSupported: boolean;
}
export function useSpeechRecognition({ onResult, lang = 'en-US' }: UseSpeechRecognitionOptions): UseSpeechRecognitionReturn {
const [isListening, setIsListening] = useState(false);
const recognitionRef = useRef<any>(null);
const isSupported = typeof window !== 'undefined' && ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window);
useEffect(() => {
if (!isSupported) return;
const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;
const recognition = new SpeechRecognition();
recognition.continuous = true;
recognition.interimResults = true;
recognition.lang = lang;
recognition.onresult = (event: any) => {
let transcript = '';
for (let i = event.resultIndex; i < event.results.length; i++) {
transcript += event.results[i][0].transcript;
}
if (event.results[event.resultIndex].isFinal) {
onResult(transcript);
}
};
recognition.onerror = () => {
setIsListening(false);
};
recognition.onend = () => {
setIsListening(false);
};
recognitionRef.current = recognition;
return () => {
try {
recognition.stop();
} catch (e) {}
};
}, [isSupported, lang, onResult]);
const start = useCallback(() => {
if (!recognitionRef.current || isListening) return;
try {
recognitionRef.current.start();
setIsListening(true);
} catch (e) {}
}, [isListening]);
const stop = useCallback(() => {
if (!recognitionRef.current || !isListening) return;
try {
recognitionRef.current.stop();
setIsListening(false);
} catch (e) {}
}, [isListening]);
return { isListening, start, stop, isSupported };
}