Ashgen12's picture
Recruitment Copilot
14fdc5e verified
Raw
History Blame Contribute Delete
2.2 kB
"use client";
import { ReactNode, useState } from "react";
type RecognitionInstance = {
continuous: boolean;
interimResults: boolean;
lang: string;
onresult: ((event: any) => void) | null;
onerror: ((event: any) => void) | null;
onend: (() => void) | null;
start: () => void;
stop: () => void;
};
type RecognitionConstructor = new () => RecognitionInstance;
declare global {
interface Window {
SpeechRecognition?: RecognitionConstructor;
webkitSpeechRecognition?: RecognitionConstructor;
}
}
type VoiceInputProps = {
onTranscript: (text: string) => void;
disabled?: boolean;
className?: string;
idleLabel?: string;
listeningLabel?: string;
title?: string;
children?: ReactNode;
listeningContent?: ReactNode;
};
export function VoiceInput({
onTranscript,
disabled = false,
className,
idleLabel = "Voice",
listeningLabel = "Listening...",
title,
children,
listeningContent
}: VoiceInputProps) {
const [isListening, setIsListening] = useState(false);
const toggleListen = () => {
const Constructor = window.SpeechRecognition ?? window.webkitSpeechRecognition;
if (!Constructor) {
alert("Speech recognition is not supported in this browser.");
return;
}
const recognition = new Constructor();
recognition.lang = "en-US";
recognition.continuous = false;
recognition.interimResults = false;
recognition.onresult = (event) => {
const transcript = event?.results?.[0]?.[0]?.transcript;
if (typeof transcript === "string" && transcript.trim()) {
onTranscript(transcript.trim());
}
};
recognition.onerror = () => {
setIsListening(false);
};
recognition.onend = () => {
setIsListening(false);
};
setIsListening(true);
recognition.start();
};
return (
<button
type="button"
onClick={toggleListen}
disabled={disabled || isListening}
className={className}
title={title}
>
{isListening
? (listeningContent ?? listeningLabel)
: (children ?? idleLabel)}
</button>
);
}