読者です 読者をやめる 読者になる 読者になる

RaspberryPiのマイクで会話してみる【ヒミツのクマちゃん 完結編】

RaspberryPiのマイクで会話してみる【ヒミツのクマちゃん 完結編】

これまでのエントリの内容に最後に「今日会った出来事を教えてね」感じで会話するようにします。

uepon.hatenadiary.com

uepon.hatenadiary.com

uepon.hatenadiary.com

uepon.hatenadiary.com

uepon.hatenadiary.com

動作の概要は以下のような感じになります。

f:id:ueponx:20161226015507j:plain

これまでのソースファイルに音声認識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をどういう風に隠すか、マイクをどのようにするかなど考えればきりがないのですが。 それも含めて工作や工夫の醍醐味のあるテーマだったかなと思います。