💬

ずんだもんでしゃべるローカルLLMで遊びたい

2024/10/25に公開

最近、Pythonをちょこっと始めました。
Pythonといえば生成AIですが、自分にはハードルが高いなぁと思っていたところ、ローカルLLMが簡単に扱える環境があることを知り、せっかくだからずんだもんの声で喋るようにさせてみたいと思い、挑戦してみました。

当方の環境は、

  • Macbook Pro 16inch 2021
  • メモリ32GB
  • Mac OS 14.7

ローカルLLMを準備する

Ollamaをインストールします。
https://ollama.com

モデルをインストール

言語モデルをインストールします。今回は、llama3-elyza-jp-8bを利用しました。
https://ollama.com/dsasai/llama3-elyza-jp-8b

ollama pull dsasai/llama3-elyza-jp-8b

ちょっと時間がかかります。

声を準備する

Voicevox Coreをインストール

声の要、Voicevox CoreのWheelパッケージをインストールします。
https://github.com/VOICEVOX/voicevox_core/tree/main/example/python

pip install https://github.com/VOICEVOX/voicevox_core/releases/download/0.15.4/voicevox_core-0.15.4+cpu-cp38-abi3-macosx_11_0_arm64.whl

バージョンやOSなどは、以下を参考に書き換えてください。
https://github.com/VOICEVOX/voicevox_core/releases/tag/0.15.4

Open Jtalkの辞書ファイルをダウンロード

作業ディレクトリーに辞書ファイルをダウンロード、展開します。
https://sourceforge.net/projects/open-jtalk/files/Dictionary/open_jtalk_dic-1.11/open_jtalk_dic_utf_8-1.11.tar.gz/download

Simpleaudioをインストール

音声データ再生のため、Simpleaudioパッケージをインストールします。
https://simpleaudio.readthedocs.io/en/latest/installation.html#installation-ref

pip install simpleaudio

動作スクリプト

https://github.com/kadoyan/Python_Playground/tree/main/voicevox_core_playground
とりあえず、喋るずんだもんAIが動きました。
talk ontalk offで、声のありなしを設定できます。
でも、いざやってみると、AIと何を会話したらいいかわかりませんでした。コミニュケーション強者は、AIともうまく会話できるのかなぁ…。

talk_with_llm.py

talk = True
TALK_ON = "talk on"
TALK_OFF = "talk off"

# コアファイルの設定
open_jtalk_dict_dir=Path("open_jtalk_dic_utf_8-1.11")
core = VoicevoxCore(open_jtalk_dict_dir=open_jtalk_dict_dir)

# ずんだもんの声ID
speaker_id = 3
# モデルデータの読み込み
if not core.is_model_loaded(speaker_id):
    core.load_model(speaker_id)

client = OpenAI(
    base_url = 'http://localhost:11434/v1',
    api_key='ollama',
)

MODEL = "dsasai/llama3-elyza-jp-8b:latest"

# 保存するファイル名
history_file = "conversation_history.json"

# 履歴の読み込み
if Path(history_file).exists():
    with open(history_file, 'r') as file:
        messages = json.load(file)
else:
    messages = []

while True:
    role = "user"
    message = input("?")

    # トークモードの状態
    if message.strip().lower() in (TALK_OFF.lower(), TALK_ON.lower()):
        talk = message.strip().lower() == TALK_ON.lower()
        print(f"トークモードは{'オン' if talk else 'オフ'}です")
        continue # 次のループへ
    
    # ユーザーのメッセージを履歴に追加
    messages.append({"role": role, "content": message})
    
    # LLMへのリクエスト
    response = client.chat.completions.create(
        model = MODEL,
        messages = messages  # 全履歴を送信
        # messages=messages[-10:]  # 最新の10メッセージのみ送信
    )
    
    if talk:
        llm_response = response.choices[0].message.content
        messages.append({"role": "assistant", "content": llm_response})
    
        if talk:
            wave_bytes = core.tts(llm_response, speaker_id)

            # バイナリーデータをバイトストリームとして読み込む
            audio_stream = io.BytesIO(wave_bytes)
            # バイトストリームを再生可能なオブジェクトに変換
            wave_read = wave.open(audio_stream, 'rb')
            wave_obj = sa.WaveObject.from_wave_read(wave_read)
            
            # 再生
            play_obj = wave_obj.play()
            # play_obj.wait_done()  # 再生が完了するまで待機
        
        # 履歴の保存
        with open(history_file, 'w') as file:
            json.dump(messages, file, ensure_ascii=False, indent=4)
        
        #レスポンスを文字で表示
        print(llm_response)

Discussion