Pythonの音声認識モジュール「SpeechRecognition」を試す
ここでマイクからの音声データ取得方法を色々試してる中で見つけた。
ちらほら見かける程度で触ったことがなかったけど、コードを見る限りはシンプルに書けそうで、PoCなんかでお手軽に使えそうということで、試してみる。
GitHubレポジトリ
SpeechRecognition
複数のエンジンやAPIをサポートし、オンライン・オフラインの音声認識を実行するためのライブラリ。
対応している音声認識エンジン/API:
- CMU Sphinx(オフライン対応)
- Google Speech Recognition
- Google Cloud Speech API
- Wit.ai
- Microsoft Azure Speech
- Microsoft Bing Voice Recognition(非推奨)
- Houndify API
- IBM Speech to Text
- Snowboy Hotword Detection(オフライン対応)
- TensorFlow
- Vosk API(オフライン対応)
- OpenAI Whisper(オフライン対応)
- OpenAI Whisper API
- Groq Whisper API
クイックスタート
以下のコマンドでインストールできます:
pip install SpeechRecognition
詳細については「インストール」セクションを参照してください。
インストール後、すぐに試すには以下のコマンドを実行してください:
python -m speech_recognition
インストール
作業ディレクトリを作成
mkdir speechrecognition-work && cd speechrecognition-work
Python仮想環境を作成。最近uvを使っている。
uv venv -p 3.12.8
パッケージインストール
uv pip install SpeechRecognition
+ speechrecognition==3.14.1
+ typing-extensions==4.12.2
Quickstartのコマンドを実行してみる。
uv run python -m speech_recognition
AttributeError: Could not find PyAudio; check installation
pyaudioが必要なので追加
uv pip install pyaudio
+ pyaudio==0.2.14
再度実行
uv run python -m speech_recognition
"Say something!"と表示されたら適当に喋ってみる。
A moment of silence, please...
Set minimum energy threshold to 100.66832351676527
Say something!
「おはよう、おはよう」と喋ってみた。
Got it! Now to recognize it...
You said Ohio Ohio
英語で認識してるけど、とりあえず動いてみるみたい。
あと、Requirementsのところに使いたいSTT ライブラリ/APIごとの要件が書いてあるので、extrasを指定してインストールする。
STTはとりあえずOpenAI Whisper APIで試してみる。
uv pip install SpeechRecognition[openai]
+ annotated-types==0.7.0
+ anyio==4.8.0
+ certifi==2025.1.31
+ distro==1.9.0
+ h11==0.14.0
+ httpcore==1.0.7
+ httpx==0.27.2
+ idna==3.10
+ jiter==0.8.2
+ openai==1.61.1
+ pydantic==2.10.6
+ pydantic-core==2.27.2
+ sniffio==1.3.1
+ tqdm==4.67.1
APIキーを環境変数にセット
export OPENAI_API_KEY="XXXXXXXXXX"
使い方
ドキュメントはないので、サンプルコードを見るのが良さそう
リポジトリのルートにある
examples/
ディレクトリ に、使用例が掲載されています:
- マイクからの音声入力を認識する
- 音声ファイルを文字起こしする
- 音声データをオーディオファイルとして保存する
- 拡張された認識結果を表示する
- 周囲のノイズレベルに合わせて認識器のエネルギー閾値を調整する
(詳細はrecognizer_instance.energy_threshold
を参照)- バックグラウンドでマイクをリスニングする
- その他の便利な認識機能
のだが、ちょっと読みにくいコードに感じるので、エッセンス部分だけを拾い上げてみる。
音声ファイルの文字起こし
サンプル音声として、自分が開催した勉強会のYouTube動画から冒頭1分程度の音声を抜き出したオーディオファイルを用意した。
import speech_recognition as sr
# 音声ファイル
AUDIO_FILE = "./sample.wav"
# Recognizerのインスタンスを作成
r = sr.Recognizer()
# 音声ファイルを読み込む
with sr.AudioFile(AUDIO_FILE) as source:
audio = r.record(source) # 音声ファイル全体を読み取る
# OpenAI API を使用して文字起こし
try:
print(r.recognize_openai(audio))
except sr.UnknownValueError:
print("エラー: APIが音声を認識できませんでした。")
except sr.RequestError as e:
print(f"エラー: APIへのリクエストに失敗しました; {e}")
実行
uv run transcribe_from_file.py
結果
はい じゃあ始めます ちょっとまだ 来られていない方もいらっしゃるん ですけど ボイスランチでAP始めます 皆さん 日曜日にお集まりいただき まして ありがとうございます 今日は 久しぶりにオフラインということで 今日はスペシャルなゲストをお二人 来ていただいております ということ で 今日 ちょっとトピックに回ります けれども ボイスローのCEOである レデン・リムさんと セールスフォース のカムセジョナルデザインのディレクター であるグレイク・ベネスさんに来て いただいてます ということで 日本 に来ていただいて ありがとうございました 今日は このお二人にまた後でいろいろ と聞こうというコーナーがあります ので そこでまたいろいろと聞き たいと思います 今日のアジェンダ なんですけども ちょっと時間過ぎ ちゃいましたが まず最初にボイスランチ JPEについてということ あと 改造 のとこですね 少し
マイクからの音声入力
マイクか等の入力を音声ファイルに書き込む場合
import speech_recognition as sr
# Recognizerのインスタンスを作成
r = sr.Recognizer()
# 注: Microphoneクラスを使用するにはPyAudioが必要
with sr.Microphone() as source:
print("Say something!")
audio = r.listen(source)
# 音声データをRAWファイルに書き込む
with open("microphone-results.raw", "wb") as f:
f.write(audio.get_raw_data())
# 音声データをWAVファイルに書き込む
with open("microphone-results.wav", "wb") as f:
f.write(audio.get_wav_data())
# 音声データをAIFFファイルに書き込む
with open("microphone-results.aiff", "wb") as f:
f.write(audio.get_aiff_data())
# 音声データをFLACファイルに書き込む
with open("microphone-results.flac", "wb") as f:
f.write(audio.get_flac_data())
実行
uv run mic_to_file.py
以下のように出力されたら適当に話す。
Say something!
しばらくすると終了する。発話がなくなると終了するみたいなので、VAD的な処理が一応組み込まれているのかもしれない。
以下のようにファイルに出力されている。raw以外はafplay等で再生確認してみると良い。
-rw-r--r--@ 1 kun432 staff 88416 2 6 16:28 microphone-results.flac
-rw-r--r--@ 1 kun432 staff 202838 2 6 16:28 microphone-results.aiff
-rw-r--r--@ 1 kun432 staff 202796 2 6 16:28 microphone-results.wav
-rw-r--r--@ 1 kun432 staff 202752 2 6 16:28 microphone-results.raw
次にSTTに渡してみる。
import speech_recognition as sr
# Recognizerのインスタンスを作成
r = sr.Recognizer()
# マイクから音声を取得
with sr.Microphone() as source:
print("Say something!")
audio = r.listen(source)
# OpenAI API を使用して文字起こし
try:
print(r.recognize_openai(audio))
except sr.UnknownValueError:
print("エラー: APIが音声を認識できませんでした。")
except sr.RequestError as e:
print(f"エラー: APIへのリクエストに失敗しました; {e}")
実行
uv run mic_to_stt.py
こんな感じで文字起こしされる
Say something!
おはようございます。今日は少し暖かいですね。
詳細情報の取得
一部のSTTでは、文字起こしされたテキスト以外の情報も取得できる。OpenAI Whisper APIの場合はどうやらこれに対応していないようなので、Google Cloud Speech-to-Text APIを使う。
uv pip install SpeechRecognition[google-cloud]
+ cachetools==5.5.1
+ charset-normalizer==3.4.1
+ google-api-core==2.24.1
+ google-auth==2.38.0
+ google-cloud-speech==2.30.0
+ googleapis-common-protos==1.66.0
+ grpcio==1.70.0
+ grpcio-status==1.70.0
+ proto-plus==1.26.0
+ protobuf==5.29.3
+ pyasn1==0.6.1
+ pyasn1-modules==0.4.1
+ requests==2.32.3
+ rsa==4.9
+ urllib3==2.3.0
import speech_recognition as sr
# Recognizerのインスタンスを作成
r = sr.Recognizer()
# マイクから音声を取得
with sr.Microphone() as source:
print("Say something!")
audio = r.listen(source)
# OpenAI API を使用して文字起こし
try:
# show_all=True を追加すると詳細表示
# Google Cloud Speech-to-Text APIの場合は`language_code`で言語を指定できる
print(r.recognize_google_cloud(audio, language_code="ja-JP", show_all=True))
except sr.UnknownValueError:
print("エラー: APIが音声を認識できませんでした。")
except sr.RequestError as e:
print(f"エラー: APIへのリクエストに失敗しました; {e}")
実行
uv run mic_to_stt_detail.py
Say something!
results {
alternatives {
transcript: "おはようございます 今日は少し暖かいですね"
confidence: 0.962515473
words {
start_time {
nanos: 700000000
}
end_time {
seconds: 1
nanos: 600000000
}
word: "おはよう"
}
words {
start_time {
seconds: 1
nanos: 600000000
}
end_time {
seconds: 1
nanos: 700000000
}
word: "ござい"
}
words {
start_time {
seconds: 1
nanos: 700000000
}
end_time {
seconds: 2
nanos: 200000000
}
word: "ます"
}
words {
start_time {
seconds: 2
nanos: 200000000
}
end_time {
seconds: 2
nanos: 500000000
}
word: "今日"
}
words {
start_time {
seconds: 2
nanos: 500000000
}
end_time {
seconds: 2
nanos: 800000000
}
word: "は"
}
words {
start_time {
seconds: 2
nanos: 800000000
}
end_time {
seconds: 3
nanos: 100000000
}
word: "少し"
}
words {
start_time {
seconds: 3
nanos: 100000000
}
end_time {
seconds: 3
nanos: 800000000
}
word: "暖かい"
}
words {
start_time {
seconds: 3
nanos: 800000000
}
end_time {
seconds: 4
nanos: 100000000
}
word: "です"
}
words {
start_time {
seconds: 4
nanos: 100000000
}
end_time {
seconds: 4
nanos: 200000000
}
word: "ね"
}
}
result_end_time {
seconds: 4
nanos: 730000000
}
language_code: "ja-jp"
}
total_billed_time {
seconds: 5
}
request_id: 4881858918251460415
上記のように細かく出力される。
なお、STTの言語についてはTroubleshootingに記載がある。
認識エンジンが私の特定の言語/方言を理解できません。
認識言語をあなたの言語/方言に設定してみてください。これを行うには、
recognizer_instance.recognize_sphinx
、recognizer_instance.recognize_google
、recognizer_instance.recognize_wit
、recognizer_instance.recognize_bing
、recognizer_instance.recognize_api
、recognizer_instance.recognize_houndify
、およびrecognizer_instance.recognize_ibm
のドキュメントを参照してください。例えば、あなたの言語/方言が「イギリス英語」である場合、
en-US
ではなくen-GB
を言語として使用する方が適切です。
上記に記載のあるモジュールだと概ねlanguage
で指定できるようなのだが、Google Cloudは含まれていなくて、コードを見てみると指定の仕方ががやや違った次第。
言語だけでなく、OpenAI Whisper向けのモジュールが詳細表示オプションに対応していないことや、おそらくこのオプションの出力形式などもSTTごとに異なるのではないかと推測するので、使用するSTTごとに確認したほうがいいと思う。
音声認識感度の調整
上の方で
しばらくすると終了する。発話がなくなると終了するみたいなので、VAD的な処理が一応組み込まれているのかもしれない。
と書いたが、これはrecognizer_instance.energy_threshold
というプロパティで設定できるらしい。これもTroubleshootingに記載されている。
私が話していないときや、話し終わった後でも、音声認識機能が音声を認識しようとします。
recognizer_instance.energy_threshold
プロパティの値を大きくしてみてください。これは、音声認識機能が音声の認識を開始する感度を調整するものです。値が大きいほど感度が低くなり、騒がしい部屋で使用する際に便利です。この値は、マイクまたはオーディオデータによって異なります。万能な値というものはありませんが、通常は50から4000の範囲の値が適しています。
また、マイクの音量設定も確認してください。感度が高すぎる場合、マイクが周囲の雑音を多く拾っている可能性があります。感度が低すぎる場合、マイクが音声を雑音として排除している可能性があります。
あと、recognizer_instance.adjust_for_ambient_noise
というのもある。
音声認識機能は、初めて音声を聞き取ろうとした直後は、音声を認識できません。
おそらく、
recognizer_instance.energy_threshold
プロパティが、最初から高すぎる値に設定されており、動的エネルギー閾値調整によって自動的に低く調整されていると思われます。適切なレベルになるまでは、エネルギー閾値が高すぎるため、音声は周囲の雑音とみなされます。解決策は、この閾値を下げるか、事前に
recognizer_instance.adjust_for_ambient_noise
を呼び出すことです。これにより、閾値が自動的に適切な値に設定されます。
なるほど、こちらを使えば自動調整できる様子。
import speech_recognition as sr
# Recognizerのインスタンスを作成
r = sr.Recognizer()
# マイクから音声を取得
with sr.Microphone() as source:
print("現在のエネルギー閾値:", r.energy_threshold)
print("背景音にあわせてしきい値を調整中(1秒間)...")
r.adjust_for_ambient_noise(source)
print("調整後のエネルギー閾値:", r.energy_threshold)
print("Say something!")
audio = r.listen(source)
# OpenAI API を使用して文字起こし
try:
print(r.recognize_openai(audio))
except sr.UnknownValueError:
print("エラー: APIが音声を認識できませんでした。")
except sr.RequestError as e:
print(f"エラー: APIへのリクエストに失敗しました; {e}")
実行
uv run from_mic_to_tts_with_automatic_energy_threshold.py
現在のエネルギー閾値: 300
背景音にあわせてしきい値を調整中(1秒間)...
調整後のエネルギー閾値: 128.87971059150533
Say something!
おはようございまーす
なるほど、デフォルトは300っぽい。少し静かな部屋でやってみたら閾値はやや低くなった。確かに反応が良くなったような気もする。
バックグラウンドでマイクからの音声を取得する
バックグラウンドスレッドで非同期かつ継続的に音声を取得しつつ、メインスレッドで別の処理を行うというユースケース。リアルタイムで処理したい場合に良さそう。
import time
import speech_recognition as sr
# バックグラウンドスレッドから呼び出されるコールバック関数
def callback(recognizer, audio):
# 音声データを受け取ったら、OpenAI API を使って認識
try:
print(r.recognize_openai(audio))
except sr.UnknownValueError:
print("エラー: APIが音声を認識できませんでした。")
except sr.RequestError as e:
print(f"エラー: APIへのリクエストに失敗しました; {e}")
# Recognizerのインスタンスを作成
r = sr.Recognizer()
# マイクのインスタンスを作成
m = sr.Microphone()
with m as source:
# 背景の環境音に合わせた閾値の調整
r.adjust_for_ambient_noise(source)
# Recognizer.listen_in_backgroundメソッドは、音声取得を停止するための関数を返し、
# バックグラウンドでの音声聞き取りを開始する(`with`の中で実行する必要はない)
stop_listening = r.listen_in_background(m, callback)
# メインスレッドで別の処理をしている間も、音声認識は継続される
# ここでは5秒間、関係のない処理を実行する
for _ in range(50):
print("バックグラウンドで音声の聞き取りを継続しています...")
time.sleep(0.1)
# Recognizer.listen_in_backgroundが返した関数を呼び出すと、
# バックグラウンドの音声聞き取りを停止するリクエストが送信される
stop_listening(wait_for_stop=False)
# さらに別の処理を実行
# 聞き取りはすでに停止しているが、バックグラウンドスレッドは後処理のために数秒間動作する場合がある
while True: time.sleep(0.1)
実行
uv run background_mic_to_tts
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
おはようございます
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
バックグラウンドで音声の聞き取りを継続しています...
^C
特定の発話で終了するとかができそうな気がする。もうちょっといろいろ試してみたい。
その他
他にも以下のようなサンプルが用意されている。
特定のフレーズを、信頼度、文法ファイルで判定したり、認識しやすくしたり、するような例かな?
特定のコマンドフレーズのTensorflowモデルを使ったコマンド認識の例かな
バックグラウンドスレッドで音声認識を非同期に処理して、メインスレッドで音声収集をするサンプル。
まとめ
シンプルにマイクからSTTできて楽ちん。一応VADっぽいこともできるし、リアルタイム処理的なサンプルも参考になるので、ちょっとした音声入力アプリのPoCとかにはたしかに便利な気がした。