Skip to content

Instantly share code, notes, and snippets.

@roflsunriz
Last active May 8, 2025 13:15
Show Gist options
  • Select an option

  • Save roflsunriz/5a2b611133e2c596203d1d0b42912fcc to your computer and use it in GitHub Desktop.

Select an option

Save roflsunriz/5a2b611133e2c596203d1d0b42912fcc to your computer and use it in GitHub Desktop.
speech_recognition_app : 日本語と英語対応の音声認識アプリ,Cursorのプロンプト入力用
import os
import sys
import subprocess
import tkinter as tk
from tkinter import messagebox
import datetime
# フォルダパスの設定
ASSETS_DIR = os.path.join("misc", "assets")
OUTPUT_DIR = os.path.join("misc", "output")
# 必須ライブラリのリスト
REQUIRED_LIBRARIES = [
("speech_recognition", "speechrecognition"),
("pyperclip", "pyperclip"),
("pyaudio", "pyaudio")
]
def create_directories():
"""必要なディレクトリを作成する"""
os.makedirs(ASSETS_DIR, exist_ok=True)
os.makedirs(OUTPUT_DIR, exist_ok=True)
def check_and_install_libraries():
"""必須ライブラリの確認とインストールを行う"""
for import_name, package_name in REQUIRED_LIBRARIES:
try:
__import__(import_name)
except ImportError:
print(f"{package_name} がインストールされていません。インストールを開始します...")
try:
subprocess.check_call([sys.executable, "-m", "pip", "install", package_name])
print(f"{package_name} のインストールが完了しました。")
except subprocess.CalledProcessError as e:
print(f"{package_name} のインストールに失敗しました: {str(e)}")
messagebox.showerror("エラー", f"{package_name} のインストールに失敗しました。手動でインストールしてください。")
sys.exit(1)
# ディレクトリ作成
create_directories()
# ライブラリの確認とインストールを実行
check_and_install_libraries()
# 必要なライブラリをインポート
import speech_recognition as sr
import pyperclip
class SpeechRecognitionApp:
def __init__(self, root):
self.root = root
self.root.title("音声認識アプリ")
self.recognizer = sr.Recognizer()
self.setup_ui()
def setup_ui(self):
# メインフレーム
main_frame = tk.Frame(self.root, padx=10, pady=10)
main_frame.pack(fill=tk.BOTH, expand=True)
# 操作ボタンエリア
button_frame = tk.Frame(main_frame)
button_frame.pack(fill=tk.X, pady=5)
# マイクボタン(美しいボタンにする)
self.mic_icon = tk.PhotoImage(file=os.path.join(ASSETS_DIR, "mic_icon.png")).subsample(4, 4)
self.mic_button = tk.Button(button_frame, image=self.mic_icon,
command=self.start_recognition,
bd=0, highlightthickness=0, relief=tk.FLAT)
self.mic_button.pack(side=tk.LEFT, padx=5)
# キャンセルボタン(美しいボタンにする)
self.cancel_icon = tk.PhotoImage(file=os.path.join(ASSETS_DIR, "cancel_icon.png")).subsample(4, 4)
self.cancel_button = tk.Button(button_frame, image=self.cancel_icon,
command=self.stop_recognition,
bd=0, highlightthickness=0, relief=tk.FLAT)
self.cancel_button.pack(side=tk.LEFT, padx=5)
# 言語選択
lang_frame = tk.Frame(main_frame)
lang_frame.pack(fill=tk.X, pady=5)
self.lang_var = tk.StringVar(value="ja-JP")
tk.Radiobutton(lang_frame, text="日本語", variable=self.lang_var, value="ja-JP").pack(side=tk.LEFT)
tk.Radiobutton(lang_frame, text="英語", variable=self.lang_var, value="en-US").pack(side=tk.LEFT)
# 追加言語
tk.Radiobutton(lang_frame, text="中国語", variable=self.lang_var, value="zh-CN").pack(side=tk.LEFT)
tk.Radiobutton(lang_frame, text="スペイン語", variable=self.lang_var, value="es-ES").pack(side=tk.LEFT)
tk.Radiobutton(lang_frame, text="ヒンディー語", variable=self.lang_var, value="hi-IN").pack(side=tk.LEFT)
tk.Radiobutton(lang_frame, text="アラビア語", variable=self.lang_var, value="ar-SA").pack(side=tk.LEFT)
tk.Radiobutton(lang_frame, text="ポルトガル語", variable=self.lang_var, value="pt-BR").pack(side=tk.LEFT)
tk.Radiobutton(lang_frame, text="ロシア語", variable=self.lang_var, value="ru-RU").pack(side=tk.LEFT)
tk.Radiobutton(lang_frame, text="フランス語", variable=self.lang_var, value="fr-FR").pack(side=tk.LEFT)
# テキスト表示エリア
self.text_area = tk.Text(main_frame, height=10, wrap=tk.WORD)
self.text_area.pack(fill=tk.BOTH, expand=True, pady=5)
# ログ表示エリア
self.log_area = tk.Text(main_frame, height=5, wrap=tk.WORD, state=tk.DISABLED)
self.log_area.pack(fill=tk.BOTH, expand=True, pady=5)
# 下部ボタンエリア
bottom_frame = tk.Frame(main_frame)
bottom_frame.pack(fill=tk.X, pady=5)
# クリアボタン
self.clear_text_button = tk.Button(bottom_frame, text="テキストをクリア",
command=self.clear_text)
self.clear_text_button.pack(side=tk.LEFT, padx=5)
self.clear_log_button = tk.Button(bottom_frame, text="ログをクリア",
command=self.clear_log)
self.clear_log_button.pack(side=tk.LEFT, padx=5)
# コピーボタン
self.copy_button = tk.Button(bottom_frame, text="クリップボードにコピー", command=self.copy_to_clipboard)
self.copy_button.pack(side=tk.LEFT, padx=5)
# 保存ボタン
self.save_button = tk.Button(bottom_frame, text="ファイルに保存", command=self.save_to_file)
self.save_button.pack(side=tk.LEFT, padx=5)
# 終了ボタン
self.exit_button = tk.Button(bottom_frame, text="終了", command=self.exit_app)
self.exit_button.pack(side=tk.RIGHT)
def start_recognition(self):
# 別スレッドで音声認識を開始
import threading
threading.Thread(target=self._recognition_thread, daemon=True).start()
def _recognition_thread(self):
self.update_log("音声認識を開始しました")
self.mic_button.config(state=tk.DISABLED) # ボタンを無効化
try:
with sr.Microphone() as source:
self.recognizer.adjust_for_ambient_noise(source)
self.update_log("ノイズ調整完了。話してください...")
# 音声認識の設定を調整
self.recognizer.pause_threshold = 3 # 3秒の沈黙で終了
self.recognizer.phrase_time_limit = 90 # 最大90秒間の音声認識
audio = self.recognizer.listen(source)
self.update_log("音声を認識中...")
selected_lang = self.lang_var.get()
text = self.recognizer.recognize_google(audio, language=selected_lang)
self.text_area.insert(tk.END, text + "\n")
self.update_log(f"認識結果: {text}")
pyperclip.copy(text)
self.update_log("クリップボードにコピーしました")
except sr.WaitTimeoutError:
self.update_log("タイムアウト: 音声が検出されませんでした")
except sr.UnknownValueError:
self.update_log("エラー: 音声を認識できませんでした")
except sr.RequestError as e:
self.update_log(f"エラー: 音声認識サービスに接続できませんでした - {str(e)}")
except Exception as e:
self.update_log(f"予期せぬエラーが発生しました: {str(e)}")
finally:
self.mic_button.config(state=tk.NORMAL) # ボタンを有効化
def stop_recognition(self):
self.update_log("音声認識を停止しました")
# ここに音声認識を停止する処理を追加
# (現状のspeech_recognitionライブラリでは強制停止機能がないため、
# 主にユーザーへのフィードバックとして使用)
def update_log(self, message):
# ログエリアにメッセージを追加
self.log_area.config(state=tk.NORMAL)
self.log_area.insert(tk.END, f"[{datetime.datetime.now().strftime('%H:%M:%S')}] {message}\n")
self.log_area.config(state=tk.DISABLED)
self.log_area.see(tk.END) # 最新のログを表示
def copy_to_clipboard(self):
# テキストエリアの内容を取得
text = self.text_area.get("1.0", tk.END).strip()
if text:
# クリップボードにコピー
pyperclip.copy(text)
self.update_log("クリップボードにコピーしました")
messagebox.showinfo("成功", "クリップボードにコピーしました")
else:
self.update_log("コピーするテキストがありません")
messagebox.showwarning("警告", "コピーするテキストがありません")
def save_to_file(self):
# テキストエリアの内容を取得
text = self.text_area.get("1.0", tk.END).strip()
if text:
try:
# ファイル名をタイムスタンプで生成
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
filename = os.path.join(OUTPUT_DIR, f"speech_output_{timestamp}.txt")
# ファイルに保存
with open(filename, "w", encoding="utf-8") as f:
f.write(text)
self.update_log(f"ファイルに保存しました: {filename}")
messagebox.showinfo("成功", f"ファイルに保存しました: {filename}")
except Exception as e:
self.update_log(f"ファイル保存エラー: {str(e)}")
messagebox.showerror("エラー", f"ファイル保存に失敗しました: {str(e)}")
else:
self.update_log("保存するテキストがありません")
messagebox.showwarning("警告", "保存するテキストがありません")
def exit_app(self):
# 終了確認
if messagebox.askokcancel("終了", "本当に終了しますか?"):
self.root.quit()
def clear_text(self):
self.text_area.delete("1.0", tk.END)
self.update_log("テキストをクリアしました")
def clear_log(self):
self.log_area.config(state=tk.NORMAL)
self.log_area.delete("1.0", tk.END)
self.log_area.config(state=tk.DISABLED)
self.update_log("ログをクリアしました")
if __name__ == "__main__":
root = tk.Tk()
app = SpeechRecognitionApp(root)
root.mainloop()

音声認識プログラム 実装仕様書

概要

本プログラムは、Pythonを用いてマイクからの音声をリアルタイムで認識し、テキストに変換するGUIアプリケーションです。英語と日本語の音声認識に対応し、認識結果をテキストフィールドに表示、クリップボードへのコピー、プレーンテキストファイルへの保存が可能です。ユーザビリティを向上させるため、直感的なアイコンボタンや動作ログ表示を備えます。

開発環境

  • 言語: Python 3.x
  • ライブラリ:
    • speech_recognition: 音声認識
    • pyperclip: クリップボード操作
    • pyaudio: マイク入力
    • tkinter: GUI構築
  • 依存: インターネット接続(Google Speech Recognition API使用)

機能要件

1. GUI構成

  • マイクアイコンボタン: 音声認識の開始を指示。
  • バツアイコンボタン: 音声認識のキャンセルを指示。
  • テキストフィールド: 認識した音声をリアルタイムで表示。
  • 動作ログフィールド: プログラムの動作状況(開始、終了、エラーなど)を表示。
  • クリップボードコピーボタン: 認識結果をワンクリックでクリップボードにコピー。
  • 保存ボタン: 認識結果をプレーンテキストファイルに保存。
  • 終了ボタン: プログラムを終了。
  • 言語選択: 英語(en-US)と日本語(ja-JP)のラジオボタン。

2. 音声認識の動作

  • 開始: マイクアイコンボタン押下で開始。
  • 終了条件:
    • バツアイコンボタン押下で手動キャンセル。
    • 5秒間の沈黙で自動終了。
  • リアルタイム表示: 認識中の音声を逐次テキストフィールドに反映。
  • クリップボードコピー:
    • 認識終了後、自動でクリップボードにコピー。
    • クリップボードコピーボタンで手動コピーも可能。

3. ログ表示

  • 動作ログフィールドに以下の情報を表示:
    • 認識開始時: "音声認識を開始しました"
    • 認識中: "認識中..."
    • 認識成功: "認識結果: [テキスト]"
    • 認識失敗: "音声を認識できませんでした"
    • エラー: "エラー: [詳細]"

4. ファイル保存

  • 保存ボタン押下で、認識結果をプレーンテキストファイル(例: output.txt)に保存。
  • 保存先はプログラム実行ディレクトリ。

5. 終了

  • 終了ボタン押下でプログラムを正常終了。

動作フロー

  1. プログラム起動時、GUIが表示される。
  2. ユーザーが言語を選択し、マイクアイコンボタンを押す。
  3. マイクがアクティブになり、音声認識が開始。動作ログに状況を表示。
  4. 音声が認識されると、テキストフィールドにリアルタイムで表示。
  5. 5秒沈黙またはキャンセルボタン押下で認識終了。
  6. 認識終了後、自動でクリップボードにコピー。
  7. ユーザーが必要に応じてクリップボードコピーボタンまたは保存ボタンを使用。
  8. 終了ボタンでプログラム終了。

設計仕様

GUIレイアウト

+-----------------------------+
| [マイク] [バツ] |
| 言語: [英語] [日本語] |
| +-----------------------+ |
| | テキストフィールド | |
| +-----------------------+ |
| +-----------------------+ |
| | 動作ログフィールド | |
| +-----------------------+ |
| [コピー] [保存] [終了] |
+-----------------------------+

音声認識設定

  • タイムアウト: 5秒(沈黙検出用)。
  • ノイズ調整: 開始時に1秒間の周囲ノイズを調整。

ファイル保存形式

  • 形式: プレーンテキスト(.txt
  • ファイル名: speech_output_[タイムスタンプ].txt(例: speech_output_20250310_123456.txt

注意点

  • マイクが接続されていない場合、エラーメッセージを表示。
  • インターネット接続がない場合、Google APIが利用できないためエラー表示。
  • 日本語認識の精度は発音や環境に依存。

拡張性

  • 将来的に他の音声認識エンジン(例: DeepSpeech)の統合を検討可能。
  • ログをファイルに保存するオプションを追加可能。

スケジュール

  • 設計: 1日
  • 実装: 2日
  • テスト: 1日
@roflsunriz
Copy link
Author

mic_icon.pngとcancel_icon.pngが必要。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment