LoginSignup
3
1

More than 1 year has passed since last update.

ReactHookで簡単に音声認識

Last updated at Posted at 2023-03-18

はじめに

ChatGPTの影響で音声認識をさくっと使いたいとき、
あると思います。
さくっと入れられるようにコンポネント化しました。

実行結果

recog2.gif

ソースコード

音声認識コンポネント

import { useEffect, useRef, useState } from "react";

interface ISpeechRecognitionEvent {
  isTrusted?: boolean;
  resultIndex: number;
  results: {
    isFinal: boolean;
    [key: number]:
    | undefined
    | {
      transcript: string;
    };
  }[];
}

interface ISpeechRecognition extends EventTarget {
  grammars: string;
  lang: string;
  continuous: boolean;
  interimResults: boolean;
  maxAlternatives: number;
  serviceURI: string;
  onaudiostart: () => void;
  onaudioend: () => void;
  onend: () => void;
  onerror: () => void;
  onnomatch: () => void;
  onresult: (event: ISpeechRecognitionEvent) => void;
  onsoundstart: () => void;
  onsoundend: () => void;
  onspeechstart: () => void;
  onspeechend: () => void;
  onstart: () => void;
  abort(): void;
  start(): void;
  stop(): void;
}

declare global {
  interface Window {
    SpeechRecognition: any | { webkitSpeechRecognition: any };
  }
}
declare var webkitSpeechRecognition: any;

interface IUseSpeechRecognition {
  enabled: boolean;
  lang: "ja" | "en";
  continuous: boolean; // 連続的に音声認識
  interimResults: boolean; // 途中結果の出力
}

interface ISpeechRecognitionResult {
  finishText: string;
  interimText: string;
}

/**
 * 音声認識ReactHook
 * @param props 
 * @returns 
 */
export const useSpeechRecognition = (props: IUseSpeechRecognition): ISpeechRecognitionResult => {
  const ref = useRef<ISpeechRecognitionResult>({
    finishText: '',
    interimText: ''
  });
  const [text, setText] = useState<string>();
  window.SpeechRecognition = window.SpeechRecognition || webkitSpeechRecognition;
  var recognition: ISpeechRecognition = new webkitSpeechRecognition();
  recognition.lang = props.lang;
  recognition.interimResults = props.interimResults;
  recognition.continuous = props.continuous;

  recognition.onresult = (event: ISpeechRecognitionEvent) => {
    if (props.enabled) {
      let interimTranscript = '';
      let finalTranscript = '';

      for (let i = event.resultIndex; i < event.results.length; ++i) {
        const transcript = event.results[i][0].transcript;
        if (event.results[i].isFinal) {
          finalTranscript += transcript;
          ref.current.finishText = finalTranscript;
        } else {
          interimTranscript += transcript;
          ref.current.interimText = interimTranscript;
        }
      }
    }
    else {
      ref.current.interimText = "";
      ref.current.finishText = "";
    }
  };

  const startRecognition = () => {
    navigator.mediaDevices.getUserMedia({ audio: true })
      .then(() => {
        recognition.start();
      })
      .catch(error => {
        console.error(error);
      });
  }

  const stopRecognition = () => {
    recognition.stop();
  };

  useEffect(() => {
    if (props.enabled) {
      startRecognition();
    }
    else {
      stopRecognition();
    }
  }, [props.enabled]);

  return ref.current;
}

呼び出すとき

const speechText = useSpeechRecognition({ 
  enabled: true, 
  lang: "ja", 
  continuous: true, 
  interimResults: true 
});

const getNowText = () => {
  console.log("音声認識(途中): " + speechText.interimText);
  console.log("音声認識(結果): " + speechText.finishText);
}
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1