MENU

AITuber開発日誌 2-1 声のテスト!

この記事の最後まで進めると、コードをコピペするだけで
テキストと、それを読み上げる音声ファイルを作成
してくれるプログラムができます!

作成した音声

目次

さあ、開発の時間だ!

つくる人

環境設定は完了したから、次は声のテストになるのかな?
教えてLM!

AITuber 開用LMの回答

はい、その通りです!環境構築お疲れ様でした。 次は**「PythonからVOICEVOXを操作して、音声ファイルを生成できるか」**を確認する「声のテスト」を行いましょう。
これが成功すれば、AITuberの「口(発声機能)」が完成したことになります。
Cursorの**Composer機能Ctrl + I)**を使って、以下の手順でコードを実装・実行していきましょう。

Cursorでコードを書いてもらおう!

STEP
VOICEVOXアプリの起動

まず、VOICEVOXアプリを起動しておいてください。 (これが起動していないと、Pythonが接続しようとしてもエラーになります)

VOICEVOX起動画面
STEP
音声合成モジュールの実装

Cursorのエディタで Ctrl + I(Macは Cmd + I)を押してComposerを開き、以下のプロンプトを入力して「送信」してください。

Composerへの指示(プロンプト)
modules/expression/voicevox.py に、VOICEVOXを操作するクラス VoiceVoxClient を実装してください。

【要件】
1. 非同期処理 (aiohttp) を使用すること。
2. コンストラクタで base_url (デフォルト: http://localhost:50021) と speaker_id を受け取る。
3. 以下のメソッドを実装する:
   - create_audio_query(text): /audio_query エンドポイントを使用
   - synthesis(query, speaker): /synthesis エンドポイントを使用
   - generate_voice(text): 上記2つを組み合わせて、音声データ(bytes)を返す
4. config/settings.py が未実装なら、pydantic-settingsを使って .env を読み込むクラスも作成してください。

Cursorがコードを生成したら、「Accept(適用)」または「Save All」をクリックしてファイルを保存します。

STEP
テスト用スクリプトの作成と実行

次に、正しく動くか確認するための小さなテストファイルを作ります。 ルートディレクトリ(main.pyがある場所)に test_voice.py というファイルを新規作成し、以下のコードを貼り付けてください。

コピペするコード
import asyncio
from modules.expression.voicevox import VoiceVoxClient
# 設定ファイルから読み込む形が理想ですが、まずは直接指定でテストします
from config.settings import settings

async def main():
    print("🤖 音声合成テストを開始します...")
    
    # クライアントの初期化 (設定ファイルの値を使用)
    # もしエラーが出る場合は url="http://127.0.0.1:50021", speaker_id=3 など直接指定してください
    client = VoiceVoxClient(
        base_url=settings.VOICEVOX_URL, 
        speaker_id=settings.VOICEVOX_SPEAKER_ID
    )
    
    text = "こんにちは。これはAITuberの声のテストです。"
    
    try:
        # 音声データの生成
        audio_data = await client.generate_voice(text)
        
        # ファイルとして保存
        with open("test_voice.wav", "wb") as f:
            f.write(audio_data)
            
        print("✅ 成功! 'test_voice.wav' が作成されました。再生して確認してください。")
        
    except Exception as e:
        print(f"❌ エラーが発生しました: {e}")
        print("ヒント: VOICEVOXアプリは起動していますか?")

if __name__ == "__main__":
    asyncio.run(main())

CursorのAI

作業ログ

まずプロジェクト構成と既存コードを確認し、modules/expression/voicevox.py と config/settings.py の有無・内容を見ます。その上で VoiceVoxClient をaiohttpで実装し、未実装なら設定クラスも追加します。

ファイルを作り始めるCursorさん

実装内容

modules/expression/voicevox.py に VoiceVoxClient を要件どおり実装しました。

class VoiceVoxClient:VOICEVOXクライアント
VOICEVOX エンジンの HTTP API を非同期で呼び出します。
"""

def __init__(self, base_url: str = "http://localhost:50021", speaker_id: int = 1):
    ...
    self.base_url = base_url.rstrip("/")
    self.speaker_id = speaker_id
    ...

async def create_audio_query(self, text: str, speaker: Optional[int] = None) -> Optional[Dict[str, Any]]:
    """`/audio_query` エンドポイントを呼び出して音声クエリを生成します。"""
    ...

async def synthesis(self, query: Dict[str, Any], speaker: Optional[int] = None) -> Optional[bytes]:
    """`/synthesis` エンドポイントを呼び出して音声データを生成します。"""
    ...

async def generate_voice(self, text: str) -> Optional[bytes]:
    """テキストから音声データ(bytes)を生成します。"""
    ...

仕様との対応

  • 非同期処理: 全メソッドで aiohttp.ClientSession を使用した async 実装。
  • コンストラクタ: __init__(base_url: str = “http://localhost:50021”, speaker_id: int = 1) に変更。
  • メソッド
    • create_audio_query(text): /audio_query を POST、クエリ JSON を返却。
    • synthesis(query, speaker): /synthesis を POST、音声 bytes を返却。
    • generate_voice(text): 上記 2 メソッドを組み合わせて bytes を返却(失敗時は None)。
  • config/settings.py について
    • すでに pydantic-settings を用いて .env を読む Settings クラス (settings = Settings()) が実装済みのため、新規実装は行っていません。
STEP
実行

Cursorの下部にあるターミナルで、以下のコマンドを実行します。

python test_voice.py

成功すると。。。

フォルダ内に test_voice.wav というファイルが生成されます。これを再生して、ずんだもん(設定したキャラ)の声が聞こえれば「声のテスト」は完了です!

実行結果

実行したらエラーがでた。
つくる人

エラーが出たよ?なんでLM

エラー原因を特定!&修正!

ターミナルの結果とSTEP3の実装内容をコピペしてLMに聞いてみます。

AITuber 開用LMの回答

エラーが出た原因は、実行しようとした test_voice.py というファイルが、まだフォルダの中に保存されていないから です。

PowerShellの画面で can't open file ... [Errno 2] No such file or directory と表示されるのは、「そのファイルが見つからないよ」という意味です。

Cursorのエディタ上で、以下の 2つのファイル が正しい場所に作成・保存されているか確認し、なければ作成してください。

解決方法
手順1:音声合成モジュールの作成

あなたが貼り付けてくれた class VoiceVoxClient... のコードは、ここに保存します。

  • ファイル名: modules/expression/voicevox.py
    • modules フォルダの中の expression フォルダの中に作ります。

以下のコードをコピーして貼り付けてください(import文なども含めた完全版です)。

中身のコード
import aiohttp
import json
from typing import Optional, Dict, Any

class VoiceVoxClient:
    """
    VOICEVOXエンジンと通信するクライアントクラス
    """
    def __init__(self, base_url: str = "http://127.0.0.1:50021", speaker_id: int = 1):
        self.base_url = base_url.rstrip("/")
        self.speaker_id = speaker_id

    async def create_audio_query(self, text: str, speaker: Optional[int] = None) -> Optional[Dict[str, Any]]:
        """音声合成用のクエリを作成します (/audio_query)"""
        speaker_id = speaker if speaker is not None else self.speaker_id
        params = {"text": text, "speaker": speaker_id}
        
        async with aiohttp.ClientSession() as session:
            try:
                async with session.post(f"{self.base_url}/audio_query", params=params) as response:
                    response.raise_for_status()
                    return await response.json()
            except Exception as e:
                print(f"Error creating audio query: {e}")
                return None

    async def synthesis(self, query: Dict[str, Any], speaker: Optional[int] = None) -> Optional[bytes]:
        """音声を合成してバイナリデータを返します (/synthesis)"""
        speaker_id = speaker if speaker is not None else self.speaker_id
        params = {"speaker": speaker_id}
        
        async with aiohttp.ClientSession() as session:
            try:
                headers = {"Content-Type": "application/json"}
                async with session.post(
                    f"{self.base_url}/synthesis", 
                    params=params, 
                    json=query,
                    headers=headers
                ) as response:
                    response.raise_for_status()
                    return await response.read()
            except Exception as e:
                print(f"Error synthesizing audio: {e}")
                return None

    async def generate_voice(self, text: str) -> Optional[bytes]:
        """テキストから音声を生成する一連の流れを実行します"""
        query = await self.create_audio_query(text)
        if query is None:
            return None
        return await self.synthesis(query)
ファイルは既に作成されていた。
つくる人

既にファイルがあるんだけど
これに追記する形でいいの?

LMの回答

結論から言うと、追記も上書きも不要です。そのままで完璧です!

あなたが持っている modules/expression/voicevox.py のコードは、必要な機能(音声合成、クエリ作成)が全て実装されており、さらにプロジェクト固有の core.logger(ログ出力機能)も組み込まれている完成度の高い状態です。

ここにコードを追記すると、クラスの定義が重複してエラーになったり、逆にバグの原因になったりします。そのファイルの内容は変更せず、そのまま保存してください。

つくる人

OK!こちらは何もせずに次!

手順2:テスト用実行ファイルの作成

先ほどエラーになった「実行しようとしていたファイル」を、プロジェクトの一番上の階層(ルート)に作成します。

  • ファイル名: test_voice.py
    • main.py.env と同じ場所に作ってください。
ファイルが追加されます
中身のコード
import asyncio
import os
from modules.expression.voicevox import VoiceVoxClient
from dotenv import load_dotenv

# .envファイルを読み込む
load_dotenv()

async def main():
    print("🤖 音声合成テストを開始します...")
    
    # 環境変数から設定を読み込む(なければデフォルト値)
    voicevox_url = os.getenv("VOICEVOX_URL", "http://127.0.0.1:50021")
    speaker_id = int(os.getenv("VOICEVOX_SPEAKER_ID", "1"))
    
    # クライアントの初期化
    client = VoiceVoxClient(base_url=voicevox_url, speaker_id=speaker_id)
    
    text = "こんにちは。聞こえていますか?これはテストです。"
    print(f"生成するテキスト: 「{text}」")
    
    # 音声生成
    audio_data = await client.generate_voice(text)
    
    if audio_data:
        # ファイルに保存
        filename = "test_output.wav"
        with open(filename, "wb") as f:
            f.write(audio_data)
        print(f"✅ 成功! '{filename}' が作成されました。")
    else:
        print("❌ 失敗しました。VOICEVOXが起動しているか確認してください。")

if __name__ == "__main__":
    asyncio.run(main())
コピペして完了!
手順3:もう一度実行する

2つのファイルを保存(Ctrl + S)したら、もう一度ターミナルで以下のコマンドを実行してください。
python test_voice.py

これで「✅ 成功!」と表示されればOKです!

つくる人

いざ、実行!

手順3までやったらこれがでた

こうなった
つくる人

これって、うまくいったの????
教えてLM!

コードをコピペして「上手くいったの?」と聞きました。

AITuber 開用LMの回答

惜しい!あと少しです。

エラーが出てしまったので、まだ成功していません。
原因は、プログラムの中で使っている「部品(ライブラリ)」である aiohttp が、あなたのパソコンにまだ入っていないからです。

以下の手順で、必要な部品をまとめてインストールしてしまいましょう。

1. 必要な部品をインストールする

PowerShell(黒い画面)で、以下のコマンドをコピーして貼り付け、Enterキーを押してください。これで今回必要なものが全て入ります。

pip install aiohttp python-dotenv

PowerShell(黒い画面)で、以下のコマンドをコピーして貼り付け、Enterキーを押してください。これで今回必要なものが全て入ります。

実行していっぱいコード出ますが、最後にこれがでたらOK
2. もう一度テストを実行する

インストールが終わって文字の動きが止まったら、さきほどと同じコマンドでもう一度テストを実行してください。

python test_voice.py
いってみよー!

実行結果はまたエラー

コードをのみを貼り付けてLMに聞いてみます。

AITuber 開用LMの回答

まだ成功していません!
エラーメッセージ ModuleNotFoundError: No module named 'loguru' は、「loguru(ログル)」というライブラリが入っていない という意味です。

このプロジェクトでは、ログ(実行履歴)をきれいに表示するために loguru という外部ライブラリを使っているようです。

以下の手順でインストールして、もう一度実行してください。

1. 不足しているライブラリをインストール

PowerShell(黒い画面)で以下のコマンドを実行してください。

pip install loguru

PowerShell(黒い画面)で、以下のコマンドをコピーして貼り付け、Enterキーを押してください。これで今回必要なものが全て入ります。

最後の部分の表示は先ほど一緒!
2. もう一度テストを実行

インストールが終わったら、さきほどと同じコマンドを実行します。

python test_voice.py
こっちも同じだね。いってみよー!

この感動。やヴぁい

これは成功か!?
つくる人

これ上手くいったよね!!!
どうするの!? このあとどうすればいいの!?

AITuber 開用LMの回答

おめでとうございます!大成功です! 🤖🎉
ログを見ると、VOICEVOX(ずんだもん)への接続、音声データの生成、そしてファイル保存まで完璧に動作しています。

test_output.wav を再生して、実際に「こんにちは」という声が聞こえるか確認してみてください。これでAITuberの「声(Voice)」の部分は完成です。

つくる人

心なしかLMさんも浮かれている様だ
ありがとう。LMさん!

再生だな。ファイルを選んで再生だな!

作:ChatGPT5.2

テスト音声が出来ました!。次は何をするのかな!?楽しみです。

よかったらシェアしてね!
  • URLをコピーしました!
目次