口癖チェッカーを作ろう!Next.jsで簡単に音声認識アプリを開発
概要
この記事の対象者: 発言の癖を改善したい人。
記事の内容: Next.jsを使った特定の言葉をカウントするアプリの作成方法。
記事を読むとわかること: Next.jsとreact-speech-recognitionを使った音声認識アプリの実装方法。
序説
えーっと、最近話すときに「えーっと」と言いすぎているということに悩んでいます。
友達同士とかなら問題ないですが、
人前で話すときに限ってテンパってしまい頻発してしまう性分です。
思い切って相談すると、ある人からはその言葉をカウントしてみてはどうだろうかと。
ある人からカウンターを作ってみてはどうだろうかと言ってくるわけです。
こういう経緯がありまして、えーっと作ってみたわけであります。
成果
早速作ったものですが、Nextjsである特定の言葉をカウントするアプリを作りました。
↑特定の言葉を入れ、スタートを押すと音声認識が始まります。
↑試しに話した言葉が音声認識され、カウントされていることがわかります。
使用ライブラリ
今回使用した音声認識のライブラリはreact-speech-recognition
です。
react-speech-recognition
は、Web Speech API
を利用して、Reactアプリケーションで音声認識機能を簡単に利用できるライブラリです。
Web Speech API
は
W3C (World Wide Web Consortium)によって標準化された
ウェブブラウザが音声認識と音声合成を行う技術です。
つまり、文字起こしや自動音声がブラウザ上でできるというものです。
一方で、各ブラウザの開発者がどのように実装するかは個別に決定しており、
精度や速度はそのブラウザに依存します。
API使用料はかからず、無料で使用することができます。
方法
Next.jsプロジェクトの作成
next.jsのプロジェクトを作成します。
以下のオプションを設定しました。
npx create-next-app@latest etto-counter --typescript --eslint --tailwind --app --import-alias '@/*'
cd etto-counter
パッケージのインストール
Web Speech APIのPolyfillやその他必要なパッケージをインストールします。
npm install react-speech-recognition regenerator-runtime
- react-speech-recognitionはReactで音声認識機能を簡単に利用するためのライブラリ
- regenerator-runtimeは非同期関数を使用するためのランタイム
型定義ファイルの作成
react-speech-recognition
の型定義ファイルが提供されていないため、プロジェクト内に型定義ファイルを作成します。
まず、typesフォルダを作成し、その中にreact-speech-recognition.d.ts
ファイルを作成します。
mkdir types
touch types/react-speech-recognition.d.ts
次に、以下の内容をtypes/react-speech-recognition.d.ts
ファイルに追加します。
declare module 'react-speech-recognition' {
interface SpeechRecognition {
startListening: (options?: { continuous?: boolean; language?: string }) => void;
stopListening: () => void;
abortListening: () => void;
browserSupportsSpeechRecognition: () => boolean;
browserSupportsContinuousListening: () => boolean;
}
const useSpeechRecognition: () => {
transcript: string;
interimTranscript: string;
finalTranscript: string;
resetTranscript: () => void;
listening: boolean;
};
const SpeechRecognition: SpeechRecognition;
export { useSpeechRecognition };
export default SpeechRecognition;
}
polyfills.js ファイルの作成
プロジェクトのルートディレクトリにpolyfills.ts
ファイルを作成し、以下の内容を追加します。
import 'regenerator-runtime/runtime';
フロントエンドの実装
app/page.tsx ファイルを作成し、フロントエンドロジックを実装します。以下のコードを追加します。
"use client";
import '../../polyfills';
import { useState, useEffect } from 'react';
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition';
const Home = () => {
const [isClient, setIsClient] = useState(false); // クライアントサイドのチェック用
const [targetWords, setTargetWords] = useState<string[]>([]); // カウントしたい単語のリスト
const [inputWord, setInputWord] = useState(''); // ユーザーが入力する単語
const [counts, setCounts] = useState<{ [key: string]: number }>({});
const [listening, setListening] = useState(false);
const { transcript, resetTranscript } = useSpeechRecognition();
useEffect(() => {
setIsClient(true); // クライアントサイドでのみtrueに設定
}, []);
useEffect(() => {
if (transcript) {
const words = transcript.split(' ');
const newCounts = targetWords.reduce((acc, word) => {
acc[word] = words.filter(w => w === word).length;
return acc;
}, {} as { [key: string]: number });
setCounts(newCounts);
}
}, [transcript, targetWords]);
const startListening = () => {
SpeechRecognition.startListening({ continuous: true });
setListening(true);
};
const stopListening = () => {
SpeechRecognition.stopListening();
setListening(false);
resetTranscript();
};
const handleWordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputWord(e.target.value);
};
const addTargetWord = () => {
if (inputWord && !targetWords.includes(inputWord)) {
setTargetWords([...targetWords, inputWord]);
setInputWord('');
}
};
if (!isClient) {
return null; // サーバーサイドレンダリング時は何も表示しない
}
if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
return <div>このブラウザはSpeech Recognitionをサポートしていません。</div>;
}
return (
<div className="p-6">
<h1 className="text-2xl font-bold mb-4">Speech Recognition Word Counter</h1>
<div className="mb-4">
<input
type="text"
value={inputWord}
onChange={handleWordChange}
className="px-2 py-1 border border-gray-300 rounded"
placeholder="ターゲットワードを追加"
/>
<button
onClick={addTargetWord}
className="px-4 py-2 bg-green-500 text-white rounded ml-2"
>
追加
</button>
</div>
<div className="mb-4">
{targetWords.length > 0 && (
<ul>
{targetWords.map(word => (
<li key={word} className="mb-2">
{word}: <strong>{counts[word]}</strong>
</li>
))}
</ul>
)}
</div>
{!listening ? (
<button
onClick={startListening}
className="px-4 py-2 bg-blue-500 text-white rounded mr-2"
>
スタート
</button>
) : (
<button
onClick={stopListening}
className="px-4 py-2 bg-red-500 text-white rounded"
>
ストップ
</button>
)}
<p className="mt-4">{transcript}</p>
</div>
);
};
export default Home;
アプリの起動
すべての設定と実装が完了したら、以下のコマンドを実行してアプリを起動します。
npm run dev
これで、ブラウザで http://localhost:3000 にアクセスすると、音声認識を開始して特定の言葉をカウントするアプリが表示されます。
沼ポイント
Node.js versionのエラー
npm run dev
時に以下のエラーが出たとき
Node.js version >= v18.17.0 is required.
nvm use 20
などnodeのバージョンを上げる必要があります!
結言
「えーっと」じゃなくて「Well...」というようにしていきたい
参照
Discussion