ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • todo-list 음성인식으로 리스트 추가하기(feat.react-speech-recognition)
    프로젝트/개인프로젝트 2024. 1. 24. 11:32
    728x90
    전에 구현해봤던 todo-list에 음성인식 기능을 추가해서 키보드와, 음성인식을 통해 입력창에 입력할수있도록 구현해보기로했다.

     


    useSpeechToText

    import SpeechRecognition, {
      useSpeechRecognition,
    } from "react-speech-recognition";
    
    const useSpeechToText = () => {
      const { transcript, listening, resetTranscript } = useSpeechRecognition();
    
      const toggleListening = () => {
        if (listening) {
          SpeechRecognition.stopListening();
          resetTranscript(); // 음성 인식을 중지할 때 transcript를 초기화
        } else {
          SpeechRecognition.startListening({ language: "ko-KR", continuous: true });
        }
      };
    
      return { transcript, listening, toggleListening, resetTranscript };
    };
    
    export default useSpeechToText;

     

    transcript : 음성인식을 통해 텍스트로 변환된 값

    listening : 음성인식의 상태 음성인식중 or 음성인식중지

    resetTranscript : 음성인식 텍스트값을 초기화시켜준다.

     

    toggleListening :
    - listening의 상태에 따라 listening중일때 toggle 함수가 발생했다면, 음성인식을 중지시키고, transcript값을 초기화시켜준다
    - listening의 상태에 따라 listening중지상태일때 toggle함수가 발생했다면 음성인식을 시작해준다.
    이때, 옵션으로는 한국어, continuous:true로 사용자가 말을 멈출 때 까지 음성인식을 할지말지 여부를 설정해준다.

     

    마지막으로 return에  결과값, 음성인식 상태값, toggle함수, 결과값초기화함수를 내보내준다.

     

     

    Todo-List

    import React, { useEffect, useState } from "react";
    
    import List from "../components/list.js";
    
    import Myheader from "../components/Myheader.js";
    import MyButton from "../components/MyButton.js";
    import { useNavigate } from "react-router-dom";
    
    import useSpeechToText from "../functions/usespeechtotext.js";
    
    function TodoList() {
      const { transcript, listening, toggleListening, resetTranscript } =
        useSpeechToText();
      const [micOn, setMicOn] = useState(false);
      const [inputValue, setInputValue] = useState("");
      const [list, setList] = useState([]);
      const navigate = useNavigate();
    
      //추가
      const handleAddClick = () => {
        const newList = [...list, { text: inputValue, checked: false }];
        setList(newList);
        localStorage.setItem("list", JSON.stringify(newList));
        setInputValue("");
        console.log("inputvalue 는 :", inputValue);
        toggleListening(); // 음성인식 중지
        resetTranscript(); //transcript 초기화
      };
    
      //삭제
      const handleDeleteClick = (item) => {
        const newList = list.filter((i) => i !== item);
        setList(newList);
        localStorage.setItem("list", JSON.stringify(newList));
      };
    
      //todo list클릭시 스타일변화
      const handleCheckClick = (item) => {
        const newList = list.map((i) =>
          i === item ? { ...i, checked: !i.checked } : i
        );
        setList(newList);
        localStorage.setItem("list", JSON.stringify(newList));
      };
    
      //마이크 클릭상태
      const micClickHandler = () => {
        //마이크가 켜져있을때 : 음성인식종료
        if (micOn) {
          toggleListening();
          //마이크가 꺼져있을때 : 마이크상태를 on으로 바꾸고 음성인식시작
        } else {
          setMicOn(true);
          toggleListening();
        }
      };
    
      useEffect(() => {
        //음성인식 종료되면 transcript값을 초기화하고 마이크상태변경
        if (!listening) {
          resetTranscript();
          setMicOn(false);
        }
      }, [listening, resetTranscript]);
    
      useEffect(() => {
        setInputValue(transcript);
      }, [transcript]);
    
      //로컬스토리지
    
      //앱이 마운트 될 때 실행
      useEffect(() => {
        const savedList = JSON.parse(localStorage.getItem("list")) || [];
        setList(savedList);
      }, []);
    
      const env = process.env;
      env.PUBLIC_URL = env.PUBLIC_URL || "";
    
      return (
        <div className="todolist">
          <Myheader
            headText={"Todo-List"}
            leftChild={
              <MyButton
                text={"뒤로가기"}
                onClick={() => {
                  navigate(-1);
                }}
              />
            }
          />
          <h1>Talk To Me</h1>
          <div className="todo-input-wrapper">
            <input
              className="todo-input"
              type="text"
              placeholder="내용을 입력하세요"
              value={inputValue}
              onChange={(e) => {
                setInputValue(e.target.value);
              }}
            ></input>
            <div className="button-wrapper">
              <button
                onClick={() => {
                  handleAddClick();
                }}
              >
                <img
                  className="add-image"
                  src={process.env.PUBLIC_URL + `assets/add.png`}
                  alt="addimage"
                />
              </button>
              <button onClick={micClickHandler}>
                {listening ? (
                  <img
                    className="mic-image"
                    src={process.env.PUBLIC_URL + `assets/onmic.png`}
                    alt="micimage"
                  />
                ) : (
                  <img
                    className="mic-image"
                    src={process.env.PUBLIC_URL + `assets/offmic.png`}
                    alt="micimage"
                  />
                )}
              </button>
            </div>
          </div>
          <div className="todo-content">
            {list.map((item, index) => (
              <List
                item={item}
                key={index}
                handleDeleteClick={() => {
                  handleDeleteClick(item);
                }}
                handleCheckClick={handleCheckClick}
              />
            ))}
          </div>
        </div>
      );
    }
    
    export default React.memo(TodoList);

     

    1. useSpeechToText함수를 import해준다.

    2. useSpeechToText에서 return해주었던,

    const { transcript, listening, toggleListening, resetTranscript } =
    useSpeechToText();

     

    을 가져온다.

     

    3. 음성인식을통해 가져온값을 add버튼을 클릭했을 때 handleAddClick함수가 실행되고,
    새로운 값을 로컬스토리지에 저장 후 toggleListening()함수를 실행해 음성인식을 중지,
    reSetTranscript()함수를 실행하여 transcript값을 초기화시켜준다.

     

    4. 또한 listening상태에따라, 마이크이미지 버튼이 달라지고, 마이크버튼을 클릭 했을 때

    micClickHandler함수를 통해 micOn의 상태를 if문으로 확인하여

    마이크가 켜져있을때와 꺼져있을때 toggleListening()함수를 통해 조절해준다.

     

    5.useEffect를 통해 listening과 resetTranscript가 호출될때 !listening 즉 음성인식 중지상태라면
    if문이 실행되어 resetTransript로 음성인식 결과값을 리셋해주고, setMicOn(false)로 변경시켜
    사용자에눈에 마이크 이미지가 꺼지도록 해준다.


     

    결과물

     

     

    마이크가 작동 될 때는 url 우측에 마이크표시와 브라우저 타이틀 옆에 빨간원으로 표시되는것을 볼 수 있다.

     


     

    이분의 블로그를 통해 구현할수있었다..!!

    출처

     

    React - Web Speech API

    Web Speech API 문서 홈페이지 :https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API웹 페이지나 웹 앱에서 음성 데이터를 인식하고 합성하는 기능

    velog.io

     

    728x90

    댓글

Designed by Tistory.