speak_qt_async.py 技術ドキュメント

プログラムの動作

speak_qt_async.py は、PySide6フレームワークで構築されたグラフィカルユーザーインターフェース(GUI)アプリケーションです。このプログラムは、指定されたテキストファイル(Markdownまたはプレーンテキスト)を読み込み、ユーザー定義の置換ルールを適用し、複数のText-to-Speech(TTS)エンジン(pyttsx3、Voicevox、OpenAI、AquesTalkPlayer)を使用して音声を生成および再生します。音声生成は非同期で実行されるため、処理中でもGUIは応答性を保ちます。

主な機能は以下の通りです。

  • テキストファイル読み込みとスライド分割: 指定された入力ファイルの内容を読み込み、Markdownの見出しや特定のマーカーに基づいて「スライド」または「ページ」として分割表示します。

  • テキスト置換: 2つのINIファイルから正規表現ベースの置換ルールを読み込み、元のテキストに適用して変換されたテキストを表示します。

  • 多様なTTSエンジン対応: pyttsx3、Voicevox、OpenAI、AquesTalkPlayerの中から利用可能なTTSエンジンを選択して音声生成を行えます。

  • 音声パラメータ調整: 話速、ピッチ、ボイス名、OpenAIの指示文などのTTSパラメータをGUIで設定できます。

  • 非同期音声生成と再生: 音声生成はバックグラウンドスレッドで実行され、GUIのフリーズを防ぎます。生成された音声はアプリケーション内で直接再生できます。

  • 音声ファイルの保存: 生成された音声を指定したファイル(.wav など)に保存するか、一時ファイルとしてのみ使用するかを選択できます。

  • 再生コントロール: 再生、一時停止、停止、再生位置のシークといった基本的なメディア操作を提供します。

  • 設定の永続化: ウィンドウのサイズや位置、各種パス設定、入力/出力ファイルパスなどのGUI状態をINIファイルに自動で保存・読み込みます。

  • 一時ファイルの自動クリーンアップ: アプリケーション終了時に、生成された一時音声ファイルを自動的に削除し、使用された一時ディレクトリも空であれば削除します。

原理

本プログラムは、主にPySide6とtkttsライブラリを組み合わせて動作します。

  1. GUI構築とイベント処理: PySide6のウィジェット(QWidget, QTextEdit, QPushButton, QSliderなど)を使用してGUIを構築します。ユーザーの操作(ボタンクリック、テキスト変更など)はシグナル・スロットメカニズムによって処理されます。

  2. 非同期音声生成: 音声生成は時間がかかる処理であるため、GUIがフリーズしないよう QThread を継承した MyTTSWorker クラスで別スレッドで実行されます。

    • MyTTSWorkertktts ライブラリの内部ロジックを直接利用し、指定されたTTSエンジンとパラメータ(テキスト、話速、ピッチ、ボイス名など)で音声ファイルを生成します。

    • 生成中には progress シグナルを発行してGUIのプログレスバーを更新します。

    • 音声生成が完了すると finished シグナルを発行して生成されたファイルのパスをGUIに通知し、エラーが発生した場合は error シグナルを発行します。

  3. TTSエンジン統合 (tktts): プログラムは tktts ライブラリを介して複数のTTSエンジンと連携します。tktts.get_tts() 関数で選択されたエンジン(pyttsx3, voicevox, openai, aquestalkplayer)のインスタンスを取得し、その speak_dialogue() メソッドを呼び出して音声生成を行います。

    • pyttsx3: ローカルにインストールされたTTSエンジンを利用します。

    • voicevox: 指定されたVoicevoxのエンドポイント(通常はローカルで動作するVoicevoxエンジン)にHTTPリクエストを送信して音声を生成します。

    • openai: OpenAIのAPIを利用して音声を生成します。

    • aquestalkplayer: AquesTalkPlayer.exe(Windows用商用ソフト)を外部プロセスとして呼び出して音声を生成します。

  4. テキスト処理と置換:

    • 文字コード検出: chardet ライブラリを使用して、入力ファイルの文字コードを自動的に判定し、適切にファイルを読み込みます。

    • スライド分割: 入力テキストファイルは、行頭に # Slide または *数字 (例: *1) が含まれる行を区切りとして、複数の「スライド」または「ページ」に分割されます。これにより、プレゼンテーション資料のようにページごとに読み上げ内容を管理できます。

    • 正規表現置換: load_replace_dict 関数は、TOML風の簡易INIファイルから キー=値 の形式で置換ルールを読み込みます。キーは正規表現パターン、値は置換文字列です。ファイルのタイムスタンプをチェックし、変更がなければキャッシュされた辞書を使用することで効率化しています。 apply_replacements 関数は、読み込まれた置換辞書を使って入力テキストに対して re.sub を適用します。この際、re.IGNORECASE(大文字小文字を区別しない)と re.MULTILINE(複数行モード)フラグが使用され、より柔軟な置換が可能です。また、スライド区切りマーカー(# Slide...*N)は、変換後に完全に削除されます。

  5. 音声ファイル結合と再生:

    • tktts が生成する複数の音声セグメントは、pydub.AudioSegment を使用して結合されます。この際、tinterval パラメータで指定された無音区間が各セグメント間に挿入され、自然な間隔を再現します。

    • 結合された音声ファイルは、PySide6の QMediaPlayer および QAudioOutput を使用して再生されます。QMediaPlayer は再生状態、再生位置、合計時間などの情報をシグナルで提供し、GUIはこれらのシグナルを捕らえてプログレスバーやステータスラベルを更新します。

  6. 設定の永続化: アプリケーションの終了時、現在のウィンドウの位置・サイズ、各種パス(一時ディレクトリ、AquesTalkパスなど)、入力/出力ファイルパスが、プログラム名に基づいたINIファイル(例: speak_qt_async.ini)に保存されます。次回起動時にこれらの設定が自動的にロードされます。

必要な非標準ライブラリとインストール方法

このプログラムを実行するには、以下のPythonライブラリが必要です。

  • chardet: ファイルの文字コードを検出するために使用します。

  • tktts: 複数のTTSエンジンを統合するためのライブラリです。

  • pydub: 音声ファイルを結合・操作するために使用します。

  • PySide6: GUIを構築するためのQtバインディングです。

これらのライブラリは、以下の pip コマンドでインストールできます。

pip install chardet tktts pydub PySide6

注記:

  • tktts ライブラリは、PyPIに公開されている必要があります。もしインストールエラーが発生する場合は、開発元の指示に従ってください。

  • AquesTalkPlayerエンジンを使用する場合、別途 AquesTalk Player の実行ファイル(AquesTalkPlayer.exe)が必要です。これは有償のソフトウェアであり、プログラムが動作する環境にインストールし、GUIでパスを指定する必要があります。

  • Voicevoxエンジンを使用する場合、別途 VOICEVOX アプリケーションまたはVoicevoxエンジンのAPIサーバーが動作している必要があります。

  • OpenAIエンジンを使用する場合、別途OpenAI APIキーが環境変数等で設定されている必要があります。(speak_qt_async.py 自体にはAPIキーの設定UIはありませんが、tktts ライブラリがそれを処理します。)

必要な入力ファイル

speak_qt_async.py は、以下の種類の入力ファイルを扱います。

  1. 読み上げテキストファイル

    • 期待されるファイル形式: .txt または .md (Markdown)

    • データ構造: 読み上げたいテキストが含まれます。 テキスト内の特定の行を「スライド」の区切りとして認識し、GUIのプルダウンでページ選択が可能です。

      • スライドの区切りは、以下のいずれかのパターンで始まる行です。

        • # Slide (例: # Slide 1: Introduction)

        • *数字 (例: *1, *2 など)

      • 例:

        # Slide 1: はじめに
        これは最初のスライドのテキストです。
        Pythonを使ったTTSアプリケーションの紹介を行います。
        
        *2
        主な機能は、テキストの読み込みと音声合成です。
        非同期処理で快適な操作性を提供します。
        
        # Slide 3: 応用例
        プレゼンテーション資料の読み上げや、
        オーディオブックの作成に活用できます。
        
    • GUIでの指定: メインタブの「Input File (infile):」欄で指定します。

  2. 置換ルールINIファイル

    • 期待されるファイル形式: .ini

    • データ構造: キー=値 の形式で、正規表現によるテキスト置換ルールを記述します。

      • # で始まる行はコメントとして扱われます。

      • キーと値は、必要に応じてシングルクォート ' またはダブルクォート " で囲むことができます。

      • キーは正規表現パターンとして解釈されます。

      • 例:

        # デフォルトの置換ルール例
        
        # 特定の記号を全角スペースに置換
        "\[\]"= 
        "()"= 
        # 特定の略語を展開
        "TTS"="テキストトゥスピーチ"
        "AI"="エーアイ"
        # 漢字をひらがなに置換 (例)
        "今日"="きょう"
        
    • GUIでの指定: メインタブの「Replace INI (Default):」および「Replace INI (User):」欄で指定します。2つのファイルが指定された場合、ユーザー設定ファイルの内容がデフォルト設定ファイルの内容に優先して適用されます。

生成される出力ファイル

speak_qt_async.py は、以下のファイルを生成します。

  1. 音声ファイル

    • 形式: デフォルトは .wav 形式です。OpenAIエンジンを使用する場合は .mp3 形式で生成されることがあります。

    • ファイル名:

      • GUIの「出力ファイル (wav):」欄にパスが指定された場合、そのパスでファイルが保存されます。

      • パスが指定されなかった場合、一時ディレクトリ(デフォルトは tts_temp_wavs)内に _tktts_tmp_xxxx_merged.wav の形式で一時ファイルとして生成されます。ここで xxxx はランダムなハッシュ値です。

    • 内容: 「読み上げテキスト (Converted)」エリアに表示されているテキストを、選択されたTTSエンジンと設定で合成した音声データです。複数の短い音声セグメントが無音区間と共に結合されたものとなります。

    • ライフサイクル: 一時ファイルとして生成されたものは、アプリケーション終了時に自動的に削除されます。明示的に出力ファイルパスを指定した場合は、ファイルは永続的に保存されます。

  2. 設定ファイル

    • 形式: .ini

    • ファイル名: プログラム名と同じディレクトリに speak_qt_async.ini という名前で自動生成されます。

    • 内容: 以下の情報がTOML風のINI形式で保存されます。

      • [window] セクション: アプリケーションウィンドウのX座標、Y座標、幅、高さ。

      • [tts_paths] セクション: 一時ディレクトリのパス、AquesTalkPlayer.exeのパス、VoicevoxエンドポイントのURL、入力ファイルパス、デフォルト置換INIファイルパス、ユーザー置換INIファイルパス、出力ファイルパス。

    • ライフサイクル: アプリケーションの終了時に更新され、次回の起動時に読み込まれてGUIの状態を復元します。

コマンドラインでの使用例 (Usage)

speak_qt_async.py はGUIアプリケーションであるため、通常、コマンドライン引数は必要ありません。

基本的な実行コマンドは以下の通りです。

python speak_qt_async.py

ヘルプオプションを指定することも可能ですが、このプログラムは現在のところヘルプメッセージを出力しません。

python speak_qt_async.py --help

コマンドラインでの具体的な使用例

speak_qt_async.py はGUIアプリケーションとして操作されます。以下に、一般的な使用シナリオと操作手順を示します。

  1. プログラムの起動: ターミナルまたはコマンドプロンプトを開き、プログラムが保存されているディレクトリに移動して以下のコマンドを実行します。

    python speak_qt_async.py
    

    これにより、「統合TTS GUI (コンパクト・リサイズ可能)」というタイトルのウィンドウが表示されます。

  2. 入力ファイルの読み込み:

    • メインタブの「Input File (infile):」の横にある「Path」ボタンをクリックします。

    • ファイル選択ダイアログが表示されるので、読み上げたいテキストファイル(例: my_presentation.md)を選択します。

    • ファイルが読み込まれると、「読み上げテキスト (Original):」エリアにその内容が表示され、スライド区切りに基づいて「Slide Page:」プルダウンメニューが更新されます。

    • プルダウンメニューから特定のスライド(例: 1. Slide 1)を選択すると、そのスライドの内容が「読み上げテキスト (Original):」に表示されます。

  3. 置換ルールの適用:

    • デフォルトの置換ルールファイル(例: replace.ini)やユーザー定義の置換ルールファイル(例: user_replace.ini)を「Replace INI (Default):」および「Replace INI (User):」の横にある「Path」ボタンから選択します。

    • 「⚙️ Convert (Apply Rules)」ボタンをクリックします。

    • 置換ルールが適用され、その結果が「読み上げテキスト (Converted):」エリアに表示されます。ステータスバーに「Status: Conversion complete. Ready to Play.」と表示されます。

  4. TTSエンジンの設定:

    • メインタブまたはConfigタブで、以下の設定を行います。

      • 「Engine:」プルダウンから使用したいTTSエンジン(例: voicevox)を選択します。

      • 「Voice:」プルダウンから利用可能なボイス(例: ずんだもん)を選択します。

      • 「Speed (fspeak_rate):」と「Pitch (ピッチ):」のスピンボックスで話速とピッチを調整します。

      • VoicevoxやAquesTalkPlayerを使用する場合は、Configタブで「Voicevox Endpoint:」や「AquesTalk Path:」が正しく設定されていることを確認してください。

  5. 音声の生成と再生:

    • 「読み上げテキスト (Converted):」エリアに表示されているテキストを読み上げるには、「▶ Play/Generate」ボタンをクリックします。

    • 設定が変更されている場合や、まだ音声が生成されていない場合は、まず音声生成が開始されます。プログレスバーが進行し、ステータスバーに「Status: 音声生成を開始しました...」と表示されます。

    • 音声生成が完了すると、自動的に再生が開始されます。

    • 「▶ Play/Generate」ボタンは、音声が既に生成されていて設定が変更されていない場合は「▶ Play (Existing)」に変わり、生成済みの音声を即座に再生します。

    • 「⚡ Generate (Force)」ボタンをクリックすると、設定が変更されていない場合でも強制的に音声を再生成します。

    • 再生中に「⏸ Pause」ボタンで一時停止、「■ Stop」ボタンで停止できます。

  6. 出力ファイルの保存(オプション):

    • 生成された音声をファイルとして保存したい場合は、メインタブの「出力ファイル (wav):」欄に保存先のパスとファイル名(例: output_audio.wav)を入力するか、「Path」ボタンで選択します。

    • この設定をした状態で「▶ Play/Generate」または「⚡ Generate (Force)」を実行すると、音声が指定されたファイルに保存されます。

  7. アプリケーションの終了: ウィンドウを閉じるか、メニューから終了を選択すると、一時ファイルがクリーンアップされ、現在の設定が自動的に speak_qt_async.ini に保存されます。