質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

4751閲覧

python を使った会話AIの実現

masaroad612

総合スコア14

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2018/01/15 10:38

編集2018/01/17 11:36

#前提・実現したいこと
前提
docomo apiからRepl-AIに変更し、1度返事を得ることができた。

実現したいこと
連続した会話をしたい。

※初心者で的を射ない質問で大変申し訳ありません。
どうしても明日中に会話をさせるAIを完成させたく質問させていただきました。

#発生している問題・エラーメッセージ
1.repl-AIからの返答を音声で話してくれない
speakの戻り値に問題があるのでしょうか?
2.テキストでの返答はあるが、連続した会話にならない
ここがよくわかりません

Traceback (most recent call last):
File "/home/pi/ai/ai/ai-dialoguereplret.py", line 175, in <module>
speak(reply)
File "/home/pi/ai/ai/ai-dialoguereplret.py", line 112, in speak
print(commands.getoutput(cmdline))
File "/usr/lib/python2.7/commands.py", line 50, in getoutput
return getstatusoutput(cmd)[1]
File "/usr/lib/python2.7/commands.py", line 59, in getstatusoutput
pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 7-15: ordinal not in range(128)

#使用言語
python

#!/usr/bin/env python # -*- coding: utf-8 -*- import requests import json import os import commands import time GOOGLE_APIKEY = 'AIzaSyCcd2JFQt_1D6cBgFOHcJv53Wn1QmfM-_4' DOCOMO_APIKEY = '6b57447369556f3432332e5a73453553776d64624d7a4a447235314530477767476b393975313748765234' LISTEN_SECONDS = 7 VOICE_IN_PATH = '/home/pi/tmp.flac' VOICE_OUT_PATH = '/home/pi/tmp.wav' REPLAI_API_KEY = "tIbYtdhqLp4GFArA93Np791lpiBM1f7M6pUAns61"; REPLAI_API_BOTID = "sample"; REPLAI_API_URLBASE = "https://api.repl-ai.jp/v1/"; REPLAI_API_TOPICID = "docomoapi" # 録音 def listen(seconds): print 'lestening...' cmdline = 'AUDIODEV=hw:1 rec -c 1 -r 17000 ' + VOICE_IN_PATH + \ ' trim 0 ' + str(seconds) os.system(cmdline) return os.path.getsize(VOICE_IN_PATH) # 音声認識 def recognize(): print('recognizing...') f = open(VOICE_IN_PATH, 'rb') voice = f.read() f.close() url = 'https://www.google.com/speech-api/v2/recognize?xjerr=1&client=chromium&'\ 'lang=ja-JP&maxresults=10&pfilter=0&xjerr=1&key=' + GOOGLE_APIKEY hds = {'Content-type': 'audio/x-flac; rate=17000'} try: reply = requests.post(url, data=voice, headers=hds).text except IOError: return '#CONN_ERR' except: return '#ERROR' print 'results:', reply objs = reply.split(os.linesep) for obj in objs: if not obj: continue alternatives = json.loads(obj)['result'] if len(alternatives) == 0: continue return alternatives[0]['alternative'][0]['transcript'] return "" # 対話 def request_replai_api(url, params): print(url) headers = {} headers['content-type'] = 'application/json' headers['x-api-key'] = REPLAI_API_KEY r = requests.post(url, headers=headers, json=params) return r.json() def registration(): url = requests.compat.urljoin(REPLAI_API_URLBASE, 'registration') params = {} params['botId'] = REPLAI_API_BOTID return request_replai_api(url, params)['appUserId'] # 初回の発話(initialize=True)時は tipic_id を設定する def dialogue(app_id, message, initialize=False, topic_id=None): url = requests.compat.urljoin(REPLAI_API_URLBASE, 'dialogue') params = {} params['appUserId'] = app_id params['botId'] = REPLAI_API_BOTID params['voiceText'] = message if initialize and topic_id: params['initTalkingFlag'] = True params['initTopicId'] = topic_id else: params['initTalkingFlag'] = False return request_replai_api(url, params)['systemText']['utterance'] # 動作確認 app_id = registration() first_time = True while True: if first_time: ret = dialogue(app_id, 'こんにちは', True, REPLAI_API_TOPICID) print(ret) first_time = False else: ret = dialogue(app_id, 'さようなら') print(ret) break time.sleep(10) # 読み上げ def speak(message): print('speaking...' + message) JDIC_DIR='/var/lib/mecab/dic/open-jtalk/naist-jdic/' VOICE_DATA='/home/pi/ai/ai/mei/mei_happy.htsvoice' cmdline = 'echo ' + message + ' | open_jtalk -x ' + JDIC_DIR + \ ' -m ' + VOICE_DATA + ' -ow ' + VOICE_OUT_PATH + \ ' -s 17000 -p 100 -a 0.03' print(commands.getoutput(cmdline)) os.system('play ' + VOICE_OUT_PATH) def current_milli_time(): return int(round(time.time() * 1000)) if __name__ == '__main__': #first time record will be failed. listen(1) speak('こんにちは、今日の調子はどうですか?') no_word = 0 wifi_err = 0 try: while True: # 録音 t0 = current_milli_time() size = listen(LISTEN_SECONDS) t = current_milli_time() - t0 if (t < 2000): print 'USB microphone not available' speak('マイクロホンを確認してください。') time.sleep(10) continue print 'listened:' + str(t) + 'ms' print 'voice data size=' + str(size) # 音声認識 t0 = current_milli_time() message = recognize().encode('utf-8') print 'recognized:' + str(current_milli_time() - t0) + 'ms' if (message == '#CONN_ERR'): print 'internet not available' speak('イーターネット接続を確認してください。') time.sleep(10) continue elif (message == '#ERROR'): print 'voice recognize failed' speak('音声認識サービスを確認してください。') time.sleep(10) continue # あいさつ if (len(message) <= 1): no_word = no_word + 1 if (no_word >= 5): speak('こんにちは、ラズパイです。') no_word = 0 continue # 対話 speak('') t0 = current_milli_time() reply = dialogue(app_id, message, initialize=False, topic_id=None) print 'replied:' + str(current_milli_time() - t0) + 'ms' if (reply == '#ERROR'): print 'dialogue failed' speak('雑談会話サービスを確認してください。') time.sleep(10) continue # 読み上げ t0 = current_milli_time() speak(reply) print 'talked:' + str(current_milli_time() - t0) + 'ms' except KeyboardInterrupt: pass

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

namnium1125

2018/01/15 12:54 編集

<code>(または</>)をクリックして現れる```内にコードを書くか、コードを```で囲んだ方が回答がつきやすくなると思いますよ。
masaroad612

2018/01/16 08:50

アドバイスありがとうございます。以降の質問から気をつけたいです
guest

回答1

0

ベストアンサー

とりあえず、システムに組み込む前にRepl.AI単体で動作確認を行ったほうが良いかと思います。

で、Repl.AIの会話APIが動作しない原因ですが、

1つ目として、
https://repl-ai.jp/docs/references/dialogue
を見る限り、dialogure APIRequest URL"https://api.repl-ai.jp/v1/dialogue" となっておりますので

Python

1url = 'REPLAI_API_URL'\ 2'REPLAI_API_KEY={}'.format(REPLAI_API_KEY)

は明らかな間違いです。

2つ目は、初回発話時は、Request BodyにてinitTalkingFlagTrueにする必要があり、その際に initTopicId にてシナリオIDを指定する必要がありますので、この処理を追加する必要があります。

initTopicId の項目に 【initTalkingFlagがtrueの際は必須。】の記述があります

最後に3つ目として、dialogue API では Request Bodyutt パラメータが不要となります。

以上の修正で、とりあえず動くのではないでしょうか。

以下に私がAPIの動作確認したコードを挙げておきます(エラー処理の類は一切入っておりません)
appUserIdTopicID を取り回すにはクラス化したほうが楽かと思います。

Python

1""" 2import requests 3import time 4 5REPLAI_API_KEY = "********************************************" 6REPLAI_API_BOTID = "sample" 7REPLAI_API_URLBASE = "https://api.repl-ai.jp/v1/" 8REPLAI_API_TOPICID = "docomoapi" 9 10def request_replai_api(url, params): 11 print(url) 12 headers = {} 13 headers['content-type'] = 'application/json' 14 headers['x-api-key'] = REPLAI_API_KEY 15 16 r = requests.post(url, headers=headers, json=params) 17 return r.json() 18 19def registration(): 20 url = requests.compat.urljoin(REPLAI_API_URLBASE, 'registration') 21 params = {} 22 params['botId'] = REPLAI_API_BOTID 23 return request_replai_api(url, params)['appUserId'] 24 25# 初回の発話(initialize=True)時は tipic_id を設定する 26def dialogue(app_id, message, initialize=False, topic_id=None): 27 url = requests.compat.urljoin(REPLAI_API_URLBASE, 'dialogue') 28 params = {} 29 params['appUserId'] = app_id 30 params['botId'] = REPLAI_API_BOTID 31 params['voiceText'] = message 32 if initialize and topic_id: 33 params['initTalkingFlag'] = True 34 params['initTopicId'] = topic_id 35 else: 36 params['initTalkingFlag'] = False 37 return request_replai_api(url, params)['systemText']['expression'] 38 39 40# 動作確認 41app_id = registration() 42first_time = True 43while True: 44 if first_time: 45 ret = dialogue(app_id, 'こんにちは', True, REPLAI_API_TOPICID) 46 print(ret) 47 first_time = False 48 else: 49 ret = dialogue(app_id, 'さようなら') 50 print(ret) 51 break 52 time.sleep(10)

投稿2018/01/16 06:39

編集2018/01/16 10:48
magichan

総合スコア15898

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

masaroad612

2018/01/16 11:15

ご丁寧にありがとうございました。 プログラミング初心者なので非常に助かります。 直していただいたプログラムを動かして見たところ動作確認ができました。 本体のプログラムに組み込んで見たところ、音声認識までは動きました。 def dialogueの中にあるmessageを def speakの中にあるmessageへ送ることができると会話ができるのかと思いますが、解決方法がわからないでおります。 御教授いただければと思います。
magichan

2018/01/16 12:08

Repl-AIからの返答を音声出力したいということでしょうか?
magichan

2018/01/16 23:32

それでしたら、コレまでのコード同様、dialogureの戻り値を speak()に渡すと良いのではないですか reply = dialogue(app_id, 'さようなら') speak(reply)
magichan

2018/01/16 23:36

それから APIリファレンスによると dialogure APIの戻り値は expression: システムからの返答。 utterance: 音声合成用テキスト。 となってますので、 request_replai_api(url, params)['systemText']['expression'] を request_replai_api(url, params)['systemText']['utterance'] としたほうが良いかもしれませんね
masaroad612

2018/01/17 11:39

いつも回答ありがとうございます。 非常に勉強になりますが、ピントのずれた回答や、回答の意図を理解していない部分が多々あるもしれません。 お許しください。
masaroad612

2018/01/18 04:28

docomo apiからRepl-AIに変更し、1度返事を得ることができたましたが、それ以降プラグラムが作動しないため質問を追記しました、よろしくお願いします。
magichan

2018/01/19 02:11

回等にも書いておりますが dialogue API は初回だけ 'initTalkingFlag':True 'initTopicId' : トピックID を送る必用があります。 私のコードの場合は 初回は replay = dialogue(app_id, message, True, トピックID) の形式で実行し、2回目以降は replay = dialogue(app_id, message) の形式で実行するようになっておりますので、そのように実装するとよいかと思います。 私のサンプルコードの場合は first_time というフラグ変数を作成し、ループ内で初回かどうかを判定しております。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問