transformersの日本語特化学習済み事前言語処理モデルJapanese-GPT-1bと音声合成APIのVoiceVoxを組み合わせて、しゃべるチャットボットを作成してみました。
環境構築(1) VoiceVox
VoiceVoxのAPIはVoiceVoxエンジンをインストールし、起動することで、ローカルのwebAPIとして動作させることが可能です。環境構築方法はこちらのまとめ記事をご参考ください。
VOICEVOXエンジンを使ったPythonでの「高」品質音声合成API
インストールさせたあと、起動して、APIをスタンバイ状態にします。
CPUで起動する場合(VoiceVoxの「run.py」ファイルがあるディレクトリで実行)
> python run.py --voicevox_dir="./engines/windows-cpu"
GPUで起動する場合(VoiceVoxの「run.py」ファイルがあるディレクトリで実行)
> python run.py --voicevox_dir=".\engines\windows-nvidia" --use_gpu
環境構築(2) GPU+Pytorch+Transformers環境の構築
Windowsネイティブ環境にTransformersの環境を構築します。環境構築については、以前の記事もご参考ください。ここでは、venv仮想環境にcuda+pytorch+transformersの環境を作成します。あらかじめ、cudaの環境は準備してください。(参考記事:WindowsへのNVIDIA CUDAのGPU環境構築)cpu環境でもできますが、チャットの生成に時間が掛かってしまうので、できればGPUの環境をお使いください。
> mkdir chatbot
> cd chatbot
> py -3.9 -m venv venv
> .\venv\Scripts\Activate.ps1
(venv)> python -m pip install -U pip setuptools
(venv)> pip3 install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu117
(venv)> pip install transformers
(venv)> pip install sentencepiece
(venv)> pip install pyaudio
環境構築(3) Japanese-GPT-1bとチャットボット
続いて、ChatBotのエンジンをテストします。ChatBotの詳しい説明はUbuntu環境に作成した、下の記事をご覧ください。
日本語特化GPT言語モデルJapanese-GPT-1bで簡単チャットボット
今回は上のリンクのコードを改造してwavファイルの生成と再生を実装します。wavファイルとの連動とかを考えて、Windowsネイティブ環境で完結するようにしています。生成したwavファイルをtmpフォルダに生成して、再生しています。speakerのパラメータには好きな声のspeaker idを設定することで好みの声で出力できます。urlのパラメータには、VoiceVoxのAPIのアドレスを入力します。私のPCでは少し声の生成にタイムラグはありますが、ちゃんとチャットでしゃべることができました。
import torch
from transformers import T5Tokenizer, AutoModelForCausalLM
import requests
import json
import datetime
import pyaudio
import wave
import os
import time
# VoiceVoxのspeaker idを入れる
speaker = 2
# 会話文を入れる
def my_turn():
while True:
s = input("話してください?")
if s == "":
exit()
elif len(s)<=40:
break
return s
# bot生成
class ChatBot:
def __init__(self, bot_chara):
self.bot_chara = bot_chara
def conv_generate(self, prompt, tokenizer, model):
token_ids = tokenizer.encode(prompt, add_special_tokens=False, return_tensors="pt")
prompt_length = len(prompt)
with torch.no_grad():
output_ids = model.generate(
token_ids.to(model.device),
max_length=100,
min_length=100,
do_sample=True,
num_beams=20,
early_stopping=True,
no_repeat_ngram_size=1,
remove_invalid_values=True,
temperature=0.8,
pad_token_id=tokenizer.pad_token_id,
bos_token_id=tokenizer.bos_token_id,
eos_token_id=tokenizer.eos_token_id,
)
output = tokenizer.decode(output_ids.tolist()[0])
res = output[prompt_length:]
if "」" in res:
res = res.split("」")[0]
voice_gen(res, speaker)
print(self.bot_chara+":「"+res+"」")
return output[0:(prompt_length+len(res))]
# promptの字数を調整
def reducer(prompt):
if len(prompt) >= 100:
return prompt[-100:]
return prompt
# キャラクター選択
def select_chara():
print("誰と話しますか?")
chara_list = ["フリー入力","正統派美少女", "しっかり者の女性", "理系女子","もの知りのおばあちゃん", "電話のオペレーターのおねえさん"]
for i in range(len(chara_list)):
print(i+1, ": "+chara_list[i])
chara_no = int(input("キャラクタを選んでください(番号で選択)?"))
if chara_no == 1:
return input("話したい人を入れてください(フリーで入力)?")
elif chara_no>=2 and chara_no<=len(chara_list):
return chara_list[chara_no-1]
else:
exit()
def voice_gen(text, speaker):
# urlはVOICEVOXのAPIのURLを入れる
url = 'http://127.0.0.1:50021/audio_query'
# 音声合成クエリの作成
res1 = requests.post(url,params = {'text': text, 'speaker': speaker})
# 音声合成データの作成
res2 = requests.post(url,params = {'speaker': speaker},data=json.dumps(res1.json()))
# wavデータの生成
now = datetime.datetime.now()
file_name = './tmp/'+now.strftime('%y%m%d_%H%M%S')+'.wav'
with open(file_name, mode='wb') as f:
f.write(res2.content)
wav_loader(file_name)
return
# 発声部
def wav_loader(file_name):
while not os.path.exists(file_name):
time.sleep(0.2)
CHUNK = 1024
wf = wave.open(file_name, 'rb')
p = pyaudio.PyAudio()
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
output=True)
data = wf.readframes(CHUNK)
while len(data) > 0:
stream.write(data)
data = wf.readframes(CHUNK)
stream.stop_stream()
stream.close()
p.terminate()
return
# 実行部
def main():
bot_chara = select_chara()
print(bot_chara+"ですね。")
print()
tokenizer = T5Tokenizer.from_pretrained("rinna/japanese-gpt-1b")
model = AutoModelForCausalLM.from_pretrained("rinna/japanese-gpt-1b")
if torch.cuda.is_available():
model = model.to("cuda")
chatbot = ChatBot(bot_chara)
voice_gen("楽しいお話をしましょう。", speaker)
initial_prompt = chatbot.bot_chara+":「楽しいお話をしましょう。」"
print(initial_prompt)
text = initial_prompt
while True:
text = text + "私:「"+my_turn()+"」"+chatbot.bot_chara+":「"
text = reducer(text)
text = chatbot.conv_generate(text, tokenizer, model)
if __name__ == "__main__":
main()
コメント