RaspberryPiのマイクで会話してみる【ヒミツのクマちゃん 完結編】
これまでのエントリの内容に最後に「今日会った出来事を教えてね」感じで会話するようにします。
動作の概要は以下のような感じになります。
これまでのソースファイルに音声認識APIへのアクセスをいれ、そのあとにNobyAPIに送信することで 会話を行うことになります。少しアレンジした点は音声認識の開始と終了に効果音をいれたところになります。
# pygame pygame.mixer.music.load("./Q.mp3") pygame.mixer.music.play() time.sleep(1) pygame.mixer.music.stop()
このように音声認識開始と終了の部分に短い効果音をいれると話す人の戸惑いが少ないと思います。(ペッパーなどでも入れてますね。) 他のロボットと違い、目などの色で話している人にロボットがどのような状態かを知らせる手段がないので こういう工夫が必要だと思います。
#!/usr/bin/env python # -*- coding: utf-8 -*- import requests import json import types import time import picamera import os import sys import pyaudio import pygame.mixer import wave # MSEmotionAPIのwait SHORTSLEEP = 10 LONGSLEEP = 60 # 音声録音のパラメータ chunk = 1024*2 FORMAT = pyaudio.paInt16 CHANNELS = 1 #サンプリングレート、マイク性能に依存 RATE = 16000 #録音時間 RECORD_SECONDS = 5 # pygame pygame.mixer.init() try: while True: # MS Emotion APIで顔の認識を行う with picamera.PiCamera() as camera: camera.start_preview() camera.hflip = True camera.vflip = True time.sleep(2) #カメラ初期化 camera.capture('foo.jpg') url = 'https://api.projectoxford.ai/emotion/v1.0/recognize' MS_APIKEY = '【Microsoft Emotion APIのキー】' headers = {'Content-type': 'application/octet-stream', 'Ocp-Apim-Subscription-Key': MS_APIKEY} payload = open('./foo.jpg', 'rb').read() r = requests.post(url, data=payload, headers=headers) data = r.json() ninshiki = len(data) # 顔認識が出来たらNoby APIにアクセスしておみくじを引く if ninshiki > 0: dict = data[0]['scores'] max_key = max(dict, key=(lambda x: dict[x])) print "key: %s,\t value:%f" %(max_key, dict[max_key]) ENDPOINT = 'https://www.cotogoto.ai/webapi/noby.json' NOBY_APIKEY = '【NobyのAPIキー】' payload = {'text': 'おみくじ引きたいな。', 'app_key': NOBY_APIKEY} r = requests.get(ENDPOINT, params=payload) data = r.json() response = data['text'] # print "response: %s" %(response) uranai = response.split("\r\n")[1] print uranai # おみくじのフレーズを話す voice1 = 'こんにちは、今日は来てくれてありがとう。今日の運勢を占うね。' # shを呼び出す。 cmdtext = './jtalk2.sh ' + uranai # print cmdtext os.system('./jtalk2.sh ' + voice1) #成功すると0 # import os os.system(cmdtext.encode('utf-8')) #成功すると0 # import os os.system('./jtalk2.sh ' + '最近あったできごとを教えて?') print 'マイクに5秒間話しかけてください >>>' # pygame pygame.mixer.music.load("./Q.mp3") pygame.mixer.music.play() time.sleep(1) pygame.mixer.music.stop() # pyaudio p = pyaudio.PyAudio() #マイク0番からの入力を5秒間録音し、ファイル名:voice.wavで保存する。 #マイク0番を設定 input_device_index = 0 #マイクからデータ取得 stream = p.open(format = FORMAT, channels = CHANNELS, rate = RATE, input = True, frames_per_buffer = chunk) all = [] for i in range(0, RATE / chunk * RECORD_SECONDS): data = stream.read(chunk) all.append(data) stream.close() data = ''.join(all) out = wave.open('voice.wav','w') out.setnchannels(1) #mono out.setsampwidth(2) #16bits out.setframerate(RATE) out.writeframes(data) out.close() p.terminate() print '<<< 録音完了' pygame.mixer.music.load("./OK.mp3") pygame.mixer.music.play() time.sleep(1) pygame.mixer.music.stop() path = 'voice.wav' DOCOMO_APIKEY = '【docomo音声認識APIのキー】' url = "https://api.apigw.smt.docomo.ne.jp/amiVoice/v1/recognize?APIKEY={}".format(DOCOMO_APIKEY) files = {"a": open(path, 'rb'), "v":"on"} r = requests.post(url, files=files) print r.json()['text'] payload = {'text': r.json()['text'], 'app_key': NOBY_APIKEY} r = requests.get(ENDPOINT, params=payload) print r.json()['text'] cmdtext = './jtalk2.sh ' + r.json()['text'] os.system(cmdtext.encode('utf-8')) #成功すると0 # import os os.system('./jtalk2.sh ' + '教えてくれてありがとう。また会いにきてね!') print 'LONG_SLEEP_MODE' time.sleep(LONGSLEEP) else: print 'SHORT_SLEEP_MODE' time.sleep(SHORTSLEEP) except KeyboardInterrupt: sys.exit()
もう少し関数とかクラスとかを使用するときれいにまとまりますが、それは今後の自分のpythonスキルの向上のために今後修正していこうと思います。 また、音声認識に関しては非常にネットワークAPIとの相性が良くない(特にリアルタイムのレスポンスを求めるものは難しい)のでスレッドなどを使用したりなどのイライラさせない工夫がカギになってくると思います。
まとめ
やっと音声関係というか「ヒミツのクマちゃん」を使ったもので完結編になりました。 軽い気持ちで購入したヒミツのクマちゃんですが、ちゃんとした会話のできるロボットになってくれました。 ぬいぐるみの出来がよいので、最終的にはRaspberryPiをどういう風に隠すか、マイクをどのようにするかなど考えればきりがないのですが。 それも含めて工作や工夫の醍醐味のあるテーマだったかなと思います。