bkdragon's log

Web Speech API 본문

React

Web Speech API

bkdragon 2024. 11. 26. 21:44

Web Speech API 는 웹에서 음성 데이터를 인식할 수 있는 API 이다.

주요 개념

SpeechRecognition

인식을 위한 인터페이스이다. 문법 , 언어 중간값 반환등의 옵션을 지정하고 음성 인식을 시작 또는 종료할 수 있다.

speechstart, speechend, result, error 등의 이벤트 리스너를 등록할 수 있다.

const grammar =
  "#JSGF V1.0; grammar colors; public <color> = aqua | azure | beige | bisque | black | blue | brown | chocolate | coral | crimson | cyan | fuchsia | ghostwhite | gold | goldenrod | gray | green | indigo | ivory | khaki | lavender | lime | linen | magenta | maroon | moccasin | navy | olive | orange | orchid | peru | pink | plum | purple | red | salmon | sienna | silver | snow | tan | teal | thistle | tomato | turquoise | violet | white | yellow ;";
const recognition = new SpeechRecognition();
const speechRecognitionList = new SpeechGrammarList();
speechRecognitionList.addFromString(grammar, 1);
recognition.grammars = speechRecognitionList;
recognition.continuous = false;
recognition.lang = "en-US";
recognition.interimResults = false;
recognition.maxAlternatives = 1;

const diagnostic = document.querySelector(".output");
const bg = document.querySelector("html");

document.body.onclick = () => {
  recognition.start();
  console.log("Ready to receive a color command.");
};

recognition.onresult = (event) => {
  const color = event.results[0][0].transcript;
  diagnostic.textContent = `Result received: ${color}`;
  bg.style.backgroundColor = color;
};

MDN 예시 코드

SpeechRecognitionAlternative

인식된 단어를 나타내는 인터페이스 위 예제에서도 볼 수 있는 transcript 를 가지고 있다.

SpeechRecognitionErrorEvent

이름 그대로 에러를 정보를 가지고 있는 인터페이스이다. error, message를 가지고 있다.

const recognition = new SpeechRecognition();

recognition.onerror = (event) => {
  console.log(`Speech recognition error detected: ${event.error}`);
  console.log(`Additional information: ${event.message}`);
};

이정도만 알면 간단하게 음성 인식을 추가하는데는 문제가 없다.

React 에서 사용하기 위한 Hooks

리액트에서 Web Speech API 를 사용하기 위한 hooks를 만들었다.

const useSpeechRecognition = () => {
    const timeoutId = useRef<NodeJS.Timeout | null>(null);

    const [isListening, setIsListening] = useState(false);
    const [result, setResult] = useState<any>({
        text: "",
        error: null,
    });
    const [recognition, setRecognition] = useState<any>(null);

    useEffect(() => {
        const initRecognition = () => {
            //@ts-ignore
            const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;

            if (!SpeechRecognition) {
                console.error("SpeechRecognition이 지원되지 않습니다.");
                return null;
            }

            const newRecognition = new SpeechRecognition();
            newRecognition.lang = "ko-KR";
            newRecognition.interimResults = false;
            newRecognition.maxAlternatives = 1;
            return newRecognition;
        };

        const speechRecognition = initRecognition();
        setRecognition(speechRecognition);
    }, []);

    const startListening = () => {
        if (!recognition) {
            setResult({ text: "", error: "SpeechRecognition이 지원되지 않습니다." });
            return;
        }
        setIsListening(true);
        recognition.addEventListener("result", handleResult);
        recognition.addEventListener("error", handleError);
        recognition.addEventListener("speechend", handleSpeechEnd); // 말을 멈췄을 때
        recognition.start();
    };

    const stopListening = () => {
        if (recognition) {
            recognition.removeEventListener("result", handleResult);
            recognition.removeEventListener("error", handleError);
            recognition.removeEventListener("speechend", handleSpeechEnd);

            recognition.stop();
        }
        setIsListening(false);

        if (timeoutId.current) {
            clearTimeout(timeoutId.current);
            timeoutId.current = null;
        }
    };

    const handleResult = (event: any) => {
        const text = event.results[0][0].transcript;
        setResult({ text, error: null });
        if (timeoutId.current) {
            clearTimeout(timeoutId.current);
            timeoutId.current = null;
        }
    };

    const handleError = (event: any) => {
        setResult({
            text: "",
            error: `SpeechRecognition error: ${event.error}`,
        });
        stopListening();
    };

    const handleSpeechEnd = () => {
        timeoutId.current = setTimeout(() => {
            stopListening();
        }, 3000);
    };

    return [result, startListening, stopListening, isListening];
};

export default useSpeechRecognition;

recognition state에 SpeechRecognition을 담아주고 사용한다. 추가로 음성인식 중인지 여부와 결과를 저장할 상태가 있다.

'React' 카테고리의 다른 글

useImperativeHandle  (0) 2024.11.27
forwardRef  (0) 2024.11.20
Storybook Interactions Portal Component  (0) 2024.11.17
Storybook Interactions  (0) 2024.11.16
children 을 함수해서 동적으로 스타일을 지정하기  (0) 2024.11.14