昨夜の会話アプリ完成したと思っていたけど、会話しているとき会話履歴がもう一度出てくるのが気に入らないので、会話履歴をそれ用のファイルに保管しつつ、それを発言するのを禁止したら、すごくよくなったので記事にしようと思う。
使っている技術はこれまでとあまり変わらないので簡単に説明します。
以下のコードにはバグがありました。
バグフィックス版と説明を以下の参考に書いたのでコードは参考を見てください。
【参考】
・【会話入門】会話しつつ学習するアプリが進化した♪II正規表現の使い方(バグフィックス版)
以下にコード全体を置きました
・something2speak/auto_conversation.py
コード解説
特に工夫ないけど、追加したのは以下の部分
まず、最初の部分は不要な気もするが一応前のアプリで前3回で同じ文章をつぶやかないようにline1,line2,line3を導入しています。
今回さらにsave_questions(line)により、会話履歴を保存して、conv_new=read_conv(mecab)で読込むことにより、会話履歴が生成した文章と同じであることを禁止しています。
会話履歴は、ここではコンピュータの会話履歴と話している人の会話履歴と両方共保存するしようとしています。
※ここは会話だとオウム返しがいいという話もあるので会話相手の会話は禁止しないこともいいかも知れません
def conversation(questions,vecs,mecab):
line = input("> ")
line1=line
line2=line
line3=line
with open('conversation_.csv', 'a', newline='') as f: #a+ #w
writer = csv.writer(f)
while True:
writer.writerow({line}) #会話相手の会話のみ保存
sims = cosine_similarity(vectorizer.transform([mecab.parse(line)]), vecs)
index = np.argsort(sims[0])
line3=line2
line2=line1
line1=line
while True:
index_= index[-np.random.randint(1,10)] #ランキング1-10までを乱数で選択
line = questions[index_]
if line1==line or line2==line or line3==line:
continue
else:
break
conv_new=read_conv(mecab) #会話履歴取得
s=1
ss=1
for j in range(0,len(conv_new),1):
if line==conv_new[j]:
s=0
else:
s=1
ss *= s
#print(ss,s)
if ss == 0:
continue
else:
break
save_questions(line) #生成line会話履歴保存
print("({:.2f}): {}".format(sims[0][index_],questions[index_]))
text2speak(questions[index_])
time.sleep(2)
line = input("> ")
save_questions(line) #会話相手の会話履歴保存
if not line:
break
会話全履歴の保存と読込みは以下のとおり
def save_questions(line):
with open('conversation_new.csv', 'a', newline='') as f:
writer = csv.writer(f)
writer.writerow({line})
def read_conv(mecab):
conv_new = []
with open('conversation_new.csv') as f:
cols = f.read().strip().split('\n')
for i in range(len(cols)):
conv_new.append(mecab.parse(cols[i]).strip())
return conv_new
結果
会話例はおまけに掲載した
まとめ
・会話履歴を発言できないようにしたら、少し賢くなったように見える
・単なるTFIDFなのに回答はインテリジェンスを感じる
・まだまだ工夫の余地があるのでAlexaは超えられそうな気がする
・Doc2vec等でも同じようなものを作成できるのでやってみたいと思う
おまけ
以下が会話例です。
(0.83): 何 が だめ な の ,
という風に(0.83):
がついているのがコンピュータの会話文で>だめ
みたいなのがウワンが記入しているテキストです。
※それなりな回答してくれるのでもっと教育すると面白くなりそう
現在、650センテンス位
>python auto_conversation.py -d C:\PROGRA~1\mecab\dic\ipadic conversation_.csv -s stop_words.txt
> だめ
(0.83): 何 が だめ な の ,
> うん、なんとなく風邪気味なんだけど
(0.28): なんとなく 一 日 が 過ぎ て い ます ,
> そういう人はいいなあ、調子悪いんだよ
(0.24): いい 感じ だ よ ,
> うらやましいなぁ
(0.57): 軽井沢 が いい なぁ ,
> 軽井沢行きたいの
(0.68): どこ 行き たい ,
> 草津に行きたいな
(0.58): ドライブ 行き たい の
> ドライブいいね
(0.43): いい 天気 です ね ,
> そうだね
(0.72): そう だ よ ,
> じゃ、明日は草津温泉までドライブして温泉入って来ようか
(0.39): 行こ う よ 、 温泉 が いい なぁ ,
> そうだね
(0.61): そう だ ね 、 体 動かさ ない と ね ,
> ドライブって体動かすかな
(0.34): 草津 に ドライブ って 決め た ん だ よ
> そうだったね
(0.39): そう だ ね 、 どこ 行く の
> 草津でしょ
(0.62): でも 草津 に ドライブ 行く ん でしょ
>
> 食事は何食べたい
(0.71): 何 食べ たい ,
> 草津は山だからお蕎麦食べたいな
(0.50): 草津 に 行き たい な
> だから、何か食べたいものある
(0.57): おいしい もの 食べ たい な ,
> 何が好きなの
(0.31): そう な の ,
> 食べ物は何が好きなの
(0.85): ドライブ 好き な の ,
> 天丼とかさ、カレーライスとか
(0.23): 天丼 が いい なぁ ,
> 天丼好きなんだ
(0.47): 天丼 食べ たい な ,
> 天丼って、好きなのは海老天なのかな
(0.51): ラーメン 好き な ん だ ね ,
> あれ、やっぱりラーメン好きなの
(0.36): ラーメン で も いい よ ,
> でもって、なんだよ
(0.48): どこ でも いい の
> 行くのは草津温泉だよ
(0.66): 草津 に ドライブ に 行く ん だ よ
> 軽井沢はどうなったんだっけ
(0.33): これ 、 どう ,
> いやいや草津と軽井沢どっちに行きたい
(0.46): どこ 行き たい ,
> そうだな、ドライブならどこでもいいけど
(0.42): ドライブ いい ね
> 一応、草津行くんなら朝早く出ないとね
(0.29): 草津 も いい ね ,
> 明日の朝は何時に出る
(0.50): 明日 は 朝 早い よ
> 何時ごろ出る
(0.33): 何 時 に 出よ う か ,
> じゃ、6時に出ようか
(0.52): 6 時 は 早く ない
> お、じゃ何時がいいと思う
(0.35): おいしい もの は 何 だ と 思う ,
> 今は、明日の出る時間決めようよ
(0.25): ちょうど いい ね 、 明日 行こ う よ
> だから、何時に出る
(0.33): だから 暇 だ よ ,
> そういう話じゃなくて、何時にドライブ出発するかだけど
(0.43): そう 、 ドライブ だ から ね 。 自転車 じゃ なく て 車 だ よ
> 明日は6時頃出たいな
(0.39): 6 時 に 起き られる かい ,
> 少し早いね、温泉は朝は入れないよ
(0.32): 温泉 は 一泊 し ない と 行け ない よ ,
> そうだね、一泊するのがいいね
(0.43): いい 夜 だ ね ,
> 二人きりで一泊してもいいの
(0.36): 温泉 は 一泊 し ない と 行け ない よ ,
>
> 二人で一泊旅行してもいいの
(0.41): 二 人 だ と 、 ドライブ でき ない よ
> そうだね、免許証持っているけど、最近運転してないからね
(0.41): そう だ ね
> じゃ、どうしよう
(0.38): じゃ 、 行こ う か ,
> 誰か、一緒に行く人を探そうよ
(0.33): 僕 も 一 人 誘う から 誰 か 誘っ て よ