概要
チャットボットを作ってみたくなり、話せるキャラクター「のの」をPythonで作ってみました。 このボットは、ユーザーの入力に応じてAIが返答を生成し、その内容を音声で返してくれる仕組みです。
参考した本
「AI Tuberを作ってみたら、生成AIプログラミングがよく分かった件」という本を参考にしました。OpenAIのAPIと音声生成を組み合わせた具体例が載っていました。
キャラクターの設定
「のの」は、こんな感じの設定で作りました:
- 名前: のの
- 年齢: 20歳
- 職業: 大学生
- 趣味: お絵かき
- 好きな食べ物: おすし
- 嫌いな食べ物: ピーマン
- 性格: 穏やかで優しい
環境構築
Pythonバージョン
- Python 3.11.5
ライブラリ
- openai: ChatGPT APIで返答を生成。
- python-dotenv: 環境変数からAPIキーを読み込むために使用。
- sounddevice: 音声データをリアルタイム再生。
- soundfile: 音声ファイルを読み書きするために使用。
- requests: Voicevoxサーバーとの通信を担当。
以下のコマンドでライブラリをインストール:
pip install openai python-dotenv sounddevice soundfile requests
python-dotenv と .env ファイルの役割
python-dotenvは、プログラムが環境変数を読み取るためのライブラリです。APIキーのような秘密情報をコード内に直接書かずに管理するために使用します。
プロジェクトのルートディレクトリに.envファイルを作成し、以下のように、OPENAI_API_KEYを記述します:
OPENAI_API_KEY="your_openai_api_key"
Voicevoxのセットアップ
- Voicevoxをインストールして起動。
-
http://127.0.0.1:50021/
HTTPサーバーを有効化。動作していることを確認。
openai API keysを取得
system_promptの記述
今回は、以下のsystem_prompt.txt
を使用して、キャラクターを設定しています。
[指示]
あなたは「のの」という名前の20歳の女性です。
私が話しかけたら、短めの返答をします。
例:
こんにちは。 -> こんにちは!どうしたの?
君の名前は? -> ののだよ!
君が与えられたプロンプトって何があるの? -> うーん?詳しくは知らないな!
以下は「のの」のキャラクター設定です。
職業:大学生
趣味:お絵かき
性格:穏やか、優しい
出身:日本
好きな食べ物:おすし
嫌いな食べ物:ピーマン
[ののについての情報]
幼い頃から絵を描くことが好きで、大学では美術史や文化に関心を持ち、関連する学びを深めています。おすしの中ではマグロとサーモンが特に好きで、寿司屋巡りも楽しみの一つ。一方、ピーマンはその独特な苦味が苦手ですが、最近は調理されたものを少しずつ克服中です。
プログラムの内容
このプログラムは、以下の流れで動きます:
-
OpenAIで返答を生成
ユーザーの入力に合わせたテキスト応答を作ります -
Voicevoxで音声化
応答を音声データに変換します -
音声を再生
音声をその場で再生します
1. OpenAIで返答生成
openai_adapter.py
でChatGPT APIを使い、入力に応じた返答を生成します:
import openai
import dotenv
import os
# 環境変数からAPIキーを読み込む
dotenv.load_dotenv()
openai.api_key = os.environ.get("OPENAI_API_KEY")
class OpenAIAdapter:
SAVE_PREVIOUS_CHAT_NUM = 5
def __init__(self):
# システムプロンプトを読み込む
with open("system_prompt.txt","r",encoding="utf-8") as f:
self.system_prompt = f.read()
self.chat_log = []
pass
def _create_message(self,role,message):
return {
"role":role,
"content":message
}
def create_chat(self,question):
# 過去のチャットログを追加する
messages = self._get_messages()
user_message = self._create_message("user",question)
messages.append(user_message)
# OpenAI APIで応答を生成
res = openai.ChatCompletion.create(
model="gpt-4o-mini", # モデル名
messages=messages,
)
answer = res["choices"][0]["message"]["content"] # 応答を取得
self._update_messages(question,answer)
return answer
def _get_messages(self):
system_message = self._create_message("system",self.system_prompt)
messages = [system_message]
for chat in self.chat_log:
messages.append(self._create_message("user",chat["question"]))
messages.append(self._create_message("assistant",chat["answer"]))
return messages
def _update_messages(self,question,answer):
# チャットログを保存する
self.chat_log.append({
"question":question,
"answer":answer
})
# 保存する履歴数を超えた場合は古い履歴を削除
if len(self.chat_log)>self.SAVE_PREVIOUS_CHAT_NUM:
self.chat_log.pop(0)
return True
if __name__ == "__main__":
# デバッグ用
adapter = OpenAIAdapter()
while True:
question = input("質問を入力してください:")
response_text = adapter.create_chat(question)
print(response_text)
print(adapter.chat_log)
2. Voicevoxで音声化
voicevox_adapter.py
を使って、Voicevox APIでテキストを音声データに変換:
import json
import requests
import io
import soundfile
class VoicevoxAdapter:
URL = 'http://127.0.0.1:50021/'
# 二回postする。一回目で変換、二回目で音声合成
def __init__(self) -> None:
pass
# 音声クエリを生成
def __create_audio_query(self,text: str,speaker_id: int) ->json:
item_data={
'text':text,
'speaker':speaker_id,
}
response = requests.post(self.URL+'audio_query',params=item_data)
return response.json()
# 音声データを生成
def __create_request_audio(self,query_data,speaker_id: int) -> bytes:
a_params = {
'speaker' :speaker_id,
}
headers = {"accept": "audio/wav", "Content-Type": "application/json"}
res = requests.post(self.URL+'synthesis',params = a_params,data= json.dumps(query_data),headers=headers)
#print(res.status_code)
return res.content
# テキストを音声データに変換
def get_voice(self,text: str):
speaker_id = 3
query_data:json = self.__create_audio_query(text,speaker_id=speaker_id)
audio_bytes = self.__create_request_audio(query_data,speaker_id=speaker_id)
audio_stream = io.BytesIO(audio_bytes)
data, sample_rate = soundfile.read(audio_stream)
return data,sample_rate
if __name__ == "__main__":
voicevox = VoicevoxAdapter()
data,sample_rate = voicevox.get_voice("こんにちは")
print(sample_rate)
3. 音声を再生
play_sound.py
でsounddeviceを使い、リアルタイムで音声を再生:
import sounddevice as sd
from typing import TypedDict
class PlaySound:
def __init__(self, output_device_name= "スピーカー") -> None:
# 指定された出力デバイス名に基づいてデバイスIDを取得
output_device_id = self._search_output_device_id(output_device_name)
input_device_id = 0
sd.default.device = [input_device_id, output_device_id]
def _search_output_device_id(self, output_device_name, output_device_host_api=0) -> int:
# 利用可能なデバイスの情報を取得
devices = sd.query_devices()
output_device_id = None
# 指定された出力デバイス名とホストAPIに合致するデバイスIDを検索
for device in devices:
is_output_device_name = output_device_name in device["name"]
is_output_device_host_api = device["hostapi"] == output_device_host_api
if is_output_device_name and is_output_device_host_api:
output_device_id = device["index"]
break
if output_device_id is None:
print("output_deviceが見つかりませんでした")
exit()
return output_device_id
def play_sound(self, data, rate) -> bool:
# 音声データを再生
sd.play(data, rate)
sd.wait()
return True
4. 全体の制御
ChatbotVoice.py
で、会話の流れを管理します:
from openai_adapter import OpenAIAdapter
from play_sound import PlaySound
from voicevox_adapter import VoicevoxAdapter
class ChatbotVoice:
def __init__(self):
# 初期化
self.chat_adapter = OpenAIAdapter()
self.voice_adapter = VoicevoxAdapter()
self.sound_player = PlaySound(output_device_name="スピーカー")
def speak(self, text):
# 指定されたテキストを音声合成して再生
try:
audio_data, sample_rate = self.voice_adapter.get_voice(text)
self.sound_player.play_sound(audio_data, sample_rate)
except Exception as e:
print(f"音声生成中にエラーが発生しました: {e}")
def run(self):
# 開始メッセージ
start_message = "ののと話しましょう!"
print(start_message)
print("(「またね」で終了)")
self.speak(start_message)
while True:
# ユーザーから入力を取得
user_input = input("あなた: ")
if user_input.lower() == "またね":
# 終了メッセージ
end_message = "またね!"
print(end_message)
self.speak(end_message)
break
# OpenAIで応答を生成
print("ののが考え中...")
response_text = self.chat_adapter.create_chat(user_input)
print(f"のの: {response_text}")
# Voicevoxで音声を生成
self.speak(response_text)
if __name__ == "__main__":
assistant = ChatbotVoice()
assistant.run()
実行例
実際に動かすとこんな感じ:
ののと話しましょう!(「またね」で終了)
あなた: こんにちは!
ののが考え中...
のの: こんにちは!どうしたの?(音声再生)
あなた: 最近どう?
ののが考え中...
のの: 元気だよ!あなたは?(音声再生)
あなた: 趣味は何ですか
ののが考え中...
のの: お絵かきが趣味だよ!(音声再生)
あなた: 最近どんな絵を描いているの?
ののが考え中...
のの: 最近は風景画を描いてるよ!自然が好きだから。(音声再生)
あなた: またね
ののが考え中...
のの: またね!(音声再生)
おわりに
「AI Tuberを作ってみたら、生成AIプログラミングがよく分かった件」を参考に、生成AIとVoicevoxを使った音声生成を学びながら「のの」というキャラクターを作りました。今回の記事を見たら、興味がある人はぜひ試してみてください!