🎙️

React × Web Speech API で音声入力UIを作る!話すだけで文字入力できるマイク機能

に公開

はじめに

「音声で文字入力できたら便利そうだけど、Reactでどう作るの?」

そんな人に向けて、マイクで話した言葉をテキストに変換する、とてもシンプルな音声入力コンポーネントをReactで作ってみましょう!


想定する読者

  • 音声入力や音声認証機能を初めて実装する人
  • Reactでユーザーインターフェースの拡張を目指す人
  • Web Speech APIに興味がある方

Web Speech APIとは?

  • Web Speech APIは、ブラウザ上で「話す」「聞く」といった音声操作を実現するためのWeb APIです。
  • 今回のように「マイクから音声を取得し、テキストに変換する(音声認識)」だけでなく、逆にテキストを音声として読み上げる(音声合成) こともできます。
    ※ 本記事ではこのうち「音声認識」機能を使用します。

今回のゴール

  • ブラウザの音声認識API(Web Speech API) を使ってマイク入力を取得
  • ReactのuseState / useRef を活用した音声入力UIの構築
  • 話した内容がすぐにテキストボックスに表示されるデモの作成

完成イメージ

以下のようなシンプルなUIを作ります:

1.「マイクをON」ボタンをクリック
2. マイクに向かって話すと...
3. 入力欄に文字として自動で反映!


使用技術

  • React:UI構築用のライブラリ
  • Web Speech API:ブラウザの音声認識機能(※Chrome対応)

使用コード解説

① 必要なReactフックの準備

// Reactの基本機能「useState」「useRef」をインポート
import React, { useState, useRef } from 'react';

useState はマイクのON/OFF状態や取得したテキストを管理するために、
useRef は音声認識インスタンスを保持するために使います。

② 音声入力コンポーネントの定義とステート管理

// コンポーネント本体を定義(関数コンポーネント
const VoiceInput = () => {
const [text, setText] = useState('');
const [isListening, setIsListening] = useState(false);
const recognitionRef = useRef(null); // 音声認識を保持

ここでは、音声認識の状態(オン・オフ)と、認識結果のテキストを管理しています。
recognitionRef は、SpeechRecognition のインスタンスを一度だけ作成して再利用するために使用します。

③ マイクボタンがクリックされたときの処理

  // マイクのON/OFFを制御する関数
  const handleMicClick = () => {
    const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
    if (!SpeechRecognition) {
      alert('このブラウザは音声認識に対応していません(Chromeを使ってください)');
      return;
    }

まず、ブラウザが SpeechRecognition に対応しているかをチェックします。対応していなければアラートを出して終了します。

④ 音声認識のインスタンス作成とイベント定義

    // 初回のみ音声認識インスタンスを作成
    if (!recognitionRef.current) {
      const recognition = new SpeechRecognition();
      recognition.lang = 'ja-JP'; // 日本語を認識
      recognition.interimResults = false; // 途中経過は使わない
      recognition.continuous = false; // 単発で聞き取る

ここでは音声認識インスタンスを初回だけ作成します。
日本語(ja-JP)を対象にし、認識は1回限り、途中経過は無視します。

      // 音声が認識されたとき
      recognition.onresult = (event) => {
        const transcript = event.results[0][0].transcript;
        setText(transcript);
      };

ここで、実際に認識されたテキストをステートに保存します。

      // エラーが起きたとき
      recognition.onerror = (event) => {
        alert(`音声認識エラー: ${event.error}`);
      };

      // 話し終わったとき
      recognition.onend = () => {
        setIsListening(false);
      };
      recognitionRef.current = recognition;
    }

エラー発生時や認識終了時の処理もここで定義します。

⑤ 音声認識の開始・停止を切り替える処理

    if (isListening) {
      recognitionRef.current.stop();
    } else {
      recognitionRef.current.start();
    }

    setIsListening((prev) => !prev);
  };

現在の状態に応じて、start() または stop() を実行して切り替えます。

⑥ JSXによるUI構築

  // UI部分
  return (
    <div style={{ padding: '1rem', fontFamily: 'sans-serif' }}>
      <h2>音声入力デモ</h2>
      <input
        // 音声で認識されたテキストを表示
        type="text"
        value={text}
        placeholder="ここに音声が表示されます"
        readOnly
        style={{ width: '80%', padding: '0.5rem', fontSize: '1rem' }}
      />
      <br /><br />
      <button onClick={handleMicClick} style={{ padding: '0.5rem 1rem', fontSize: '1rem' }}>
        {isListening ? ' 話してください...' : 'マイクをON'}
      </button>
    </div>
  );
};

export default VoiceInput;

入力欄とマイクボタンの見た目を整えつつ、状態によってボタン表示を切り替えています。

コード全体

import React, { useState, useRef } from 'react';

const VoiceInput = () => {
  const [text, setText] = useState('');
  const [isListening, setIsListening] = useState(false);
  const recognitionRef = useRef(null);

  const handleMicClick = () => {
    const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;

    if (!SpeechRecognition) {
      alert('このブラウザは音声認識に対応していません(Chromeを使ってください)');
      return;
    }

    if (!recognitionRef.current) {
      const recognition = new SpeechRecognition();
      recognition.lang = 'ja-JP';
      recognition.interimResults = false;
      recognition.continuous = false;

      recognition.onresult = (event) => {
        const transcript = event.results[0][0].transcript;
        setText(transcript);
      };

      recognition.onerror = (event) => {
        alert(`音声認識エラー: ${event.error}`);
      };

      recognition.onend = () => {
        setIsListening(false);
      };

      recognitionRef.current = recognition;
    }

    if (isListening) {
      recognitionRef.current.stop();
    } else {
      recognitionRef.current.start();
    }

    setIsListening((prev) => !prev);
  };

  return (
    <div style={{ padding: '1rem', fontFamily: 'sans-serif' }}>
      <h2>音声入力デモ</h2>
      <input
        // 音声で認識されたテキストを表示
        type="text"
        value={text}
        placeholder="ここに音声が表示されます"
        readOnly
        style={{ width: '80%', padding: '0.5rem', fontSize: '1rem' }}
      />
      <br /><br />
      <button onClick={handleMicClick} style={{ padding: '0.5rem 1rem', fontSize: '1rem' }}>
        {isListening ? '話してください...' : 'マイクをON'}
      </button>
    </div>
  );
};

export default VoiceInput;

結果

1.音声入力画面


2.ボタンをクリック "あー"と話す


3.結果


注意点

1. 対応ブラウザが限定的だが....

  • Web Speech APIの音声認識は、主にChromeやEdge(Chromium系)で安定して動作します。
  • FirefoxやSafariは公式対応が不完全、もしくは未対応とされてきました。
  • ただし、iOS 16.6.1のSafari(iPhone 13)でReact+webkitSpeechRecognitionを使った実装が動作しました。
  • とはいえ、この動作はWebKitの仕様変更やiOSアップデートで今後変わる可能性があるため、現状の“動くかもしれない”情報として参考にしてください。
  • モバイルブラウザでの利用はChrome系がより安定しており、iOSのSafariは対応が限定的である点は注意が必要です。

2. HTTPSでの利用が必須

  • セキュリティの関係で、HTTPS環境でしか動作しません。
  • ローカル環境ではlocalhostはOKですが、httpのままのサイトでは音声認識機能は使えません。

3. ユーザーの許可が必要

  • マイクの利用はプライバシーに関わるため、ユーザーからマイク使用の許可を必ず求められます。
  • 許可しない場合は音声入力はできません。

4. 認識精度や安定性のばらつき

  • 環境(雑音レベル、マイク性能、話し方)によって認識結果が左右されます。
  • Web Speech APIはブラウザ依存で、認識精度もブラウザの音声エンジンに依存しています。

5. 制限や仕様の違い

  • continuousモード(連続認識)が不完全なブラウザもあります。
  • 多くは単発認識の繰り返し動作になります。
  • interimResults(途中結果)を使ってリアルタイムで文字起こしを表示する機能もブラウザごとに挙動が異なります。

6. 言語対応に注意

  • 対応言語はブラウザによって異なり、日本語対応はあるものの方言や専門用語には弱いです。
  • recognition.langで言語コードを指定しますが、正しく認識されない場合もあります。

7. 利用制限がある場合も

  • 連続利用や長時間の音声認識は制限されることが多いです。
  • 大量に使うサービスの場合、API制限やブラウザ側の制限で使いづらいケースがあります。

8. UI/UXの配慮が必要

  • ユーザーに認識中であることを明確に伝えたり、誤認識時の修正操作を用意したりすると良いです。
  • マイクのON/OFFや状態遷移が分かりやすいボタン設計が求められます。

まとめ

今回は、ReactとWeb Speech APIを使って、簡単に音声入力を組み込めることがわかりました。
この音声入力を活かして、勤怠打刻にも応用できそうです!

ここまでご覧いただきありがとうございました。

ネイバーズ東京

Discussion