56 lines
1.5 KiB
TypeScript
56 lines
1.5 KiB
TypeScript
import { useState, useCallback, useRef } from "react";
|
|
import {
|
|
ExpoSpeechRecognitionModule,
|
|
useSpeechRecognitionEvent,
|
|
} from "expo-speech-recognition";
|
|
|
|
export type VoiceState = "idle" | "listening" | "processing" | "error";
|
|
|
|
export function useVoice() {
|
|
const [state, setState] = useState<VoiceState>("idle");
|
|
const [transcript, setTranscript] = useState("");
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useSpeechRecognitionEvent("start", () => setState("listening"));
|
|
|
|
useSpeechRecognitionEvent("end", () => {
|
|
setState((s) => (s === "listening" ? "processing" : s));
|
|
});
|
|
|
|
useSpeechRecognitionEvent("result", (event) => {
|
|
const best = event.results[0]?.transcript ?? "";
|
|
setTranscript(best);
|
|
if (event.isFinal) setState("idle");
|
|
});
|
|
|
|
useSpeechRecognitionEvent("error", (event) => {
|
|
setError(event.error ?? "Voice recognition failed");
|
|
setState("error");
|
|
});
|
|
|
|
const start = useCallback(async (lang = "fr-FR") => {
|
|
setError(null);
|
|
setTranscript("");
|
|
const { granted } =
|
|
await ExpoSpeechRecognitionModule.requestPermissionsAsync();
|
|
if (!granted) {
|
|
setError("Microphone permission denied");
|
|
setState("error");
|
|
return;
|
|
}
|
|
ExpoSpeechRecognitionModule.start({ lang, interimResults: true });
|
|
}, []);
|
|
|
|
const stop = useCallback(() => {
|
|
ExpoSpeechRecognitionModule.stop();
|
|
}, []);
|
|
|
|
const reset = useCallback(() => {
|
|
setTranscript("");
|
|
setError(null);
|
|
setState("idle");
|
|
}, []);
|
|
|
|
return { state, transcript, error, start, stop, reset };
|
|
}
|