RaspberryPizeroぬいぐるみとおしゃべりする方法(docomoAPI利用)

# ぬいぐるみと対話したい
前回[RaspberryPizeroぬいぐるみの作り方](http://qiita.com/akihiro01051/items/de7b6e708b382fa0f6c7)の続きで

## 作りたいもの
- ぬいぐるみと会話したい
- 対話内容を作成するのは大変

音声認識から音声合成，サーボモータ制御まで行うとRaspberryPizeroではスペックが足りないと思われる
↓
音声認識と会話内容作成はAndroidスマートフォンに任せよう

## docomoAPI(雑談API)
- docomoが開発者に提供しているアセットをAPI
    - 様々なAPIが利用可能
    - 利用には登録が必要
    - [https://dev.smt.docomo.ne.jp/](https://dev.smt.docomo.ne.jp/)

- 今回は雑談対話のAPIを利用
    - サンプルコードにAndroid用のアプリも含まれているのでそれを参考にする


## 作成方法
前回[RaspberryPizeroぬいぐるみの作り方](http://qiita.com/akihiro01051/items/de7b6e708b382fa0f6c7)で作成したBluetoothChatアプリに音声認識とdocomo雑談APIの機能を追加

- 音声認識部分
    - AndroidSDKにある音声認識__SpeechRecognizer__を利用

    ``` Recognizer.java
public class Recognizer {
    private docomolibs docomo;

    private Context context;
    private SpeechRecognizer sr;
    private String RecognizerText="";
    private boolean RecognizerFlag=false;

    public void initListening(Context c) {
        docomo =new docomolibs();
        docomo.startDocomo();
        context=c;
    }

    public void startListening() {
        if (sr == null) {
            sr = SpeechRecognizer.createSpeechRecognizer(context);
            sr.setRecognitionListener(new listener());
        }

        RecognizerFlag=false;
        Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
        sr.startListening(intent);
    }

    protected void stopListening() {
        if (sr != null) sr.destroy();
        sr = null;
    }

    public void restartListeningService() {
        stopListening();
        startListening();
    }

    public boolean getRecognizerFlag() {
        return RecognizerFlag;
    }

    public String getRecognizerText() {
        return RecognizerText;
    }

    public void setRecognizerFlag() {
        RecognizerFlag=false;
    }

    class listener implements RecognitionListener {

        @Override
        public void onReadyForSpeech(Bundle bundle) {

        }

        @Override
        public void onBeginningOfSpeech() {

        }

        @Override
        public void onRmsChanged(float v) {

        }

        @Override
        public void onBufferReceived(byte[] bytes) {

        }

        @Override
        public void onEndOfSpeech() {

        }

        @Override
        public void onError(int i) {
            restartListeningService();
        }

        @Override
        public void onResults(Bundle bundle) {
            ArrayList results_array = bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
            String resultsString = results_array.get(0).toString() ;
            docomo.sendDocomo(resultsString);

            while (true)
            {
                if (docomo.getTextFlag()==true) {
                    RecognizerText = docomo.getText();
                    Random r = new Random();
                    int i=r.nextInt(3);
                    if(i==0)RecognizerText= RecognizerText + ",0";
                    else if(i==1)RecognizerText = RecognizerText + ",1";
                    else  RecognizerText =  RecognizerText + ",2";
                    RecognizerFlag=true;
                    break;
                }
            }
        }

        @Override
        public void onPartialResults(Bundle bundle) {

        }

        @Override
        public void onEvent(int i, Bundle bundle) {

        }
    }
}
```


- docomo雑談API部分
    - docomoAPIのライブラリをインポート
    - 雑談の通信部分を作成

    ``` docomolibs.java
public class docomolibs {

    private DialogueRequestParam param;
    private String Context="";
    private String Text="";
    private boolean TextFlag=false;
    public void startDocomo(){
        AuthApiKey.initializeAuth( "発行されたAPIKey");
        param = new DialogueRequestParam();
        param.setContext(Context);
        param.setNickname("デモ");
        param.setNickname_y("デモ");
        param.setSex("男");
        param.setBloodtype("A");
        param.setBirthdateY(2016);
        param.setBirthdateM(10);
        param.setBirthdateD(9);
        param.setAge(25);
        param.setConstellations("山羊座");
        param.setPlace("東京");
        param.setMode("dialog");
    }

    public void sendDocomo(String text){
        Text="";
        TextFlag=false;
        param.setUtt(text);
        param.setContext(Context);
        AsyncTask<DialogueRequestParam, Void, Void> task = new AsyncTask<DialogueRequestParam, Void, Void>()
        {

            @Override
            protected Void doInBackground(DialogueRequestParam... dialogueRequestParams) {
                DialogueResultData resultData = null;
                DialogueRequestParam req_param = dialogueRequestParams[0];
                //要求処理クラスを作成
                Dialogue dialogue = new Dialogue();
                //要求処理クラスにリクエストデータを渡し、レスポンスデータを取得する
                try {
                    resultData = dialogue.request(req_param);
                } catch (SdkException e) {
                    e.printStackTrace();
                } catch (ServerException e) {
                    e.printStackTrace();
                }
                Text=resultData.getUtt();
                Context=resultData.getContext();
                TextFlag=true;
                return null;
            }
        };
        task.execute(param);
    }

    public String getText(){
        return Text;
    }

    public boolean getTextFlag() {
        return TextFlag;
    }
}

- BluetoothChatで結果を送信
    - タイマー機能で雑談結果をBluetoothで送信するため以下を追加

   ``` BluetoothChatFragment.java
 public class MainTimerTask extends TimerTask {

        @Override
        public void run() {
            mHandler.post( new Runnable() {
                public void run() {
                    if(recognizer.getRecognizerFlag()==true) {
                        sendMessage(recognizer.getRecognizerText());
                        recognizer.setRecognizerFlag();
                        recognizer.restartListeningService();
                    }
                }
            });
        }
    }
```

## 実行
- Bluetoothでぬいぐるみと接続後音声認識が開始される
- 音声認識後，雑談APIと通信を行い対話内容を取得する
- テキストボックスに文字を入力しなくても，雑談APIからの返答が入力されてぬいぐるみがしゃべってくれる

<blockquote class="twitter-video" data-lang="ja"><p lang="ja" dir="ltr">スマホから音声認識→docomo雑談API→bluetooth→RaspberryPizero→OpenJTalk+サーボモーターで、会話っぽいものができた。<br><br>寝る。 <a href="https://t.co/n6WtwxVCTP">pic.twitter.com/n6WtwxVCTP</a></p>&mdash; アキヒロ (@akihiro01051) <a href="https://twitter.com/akihiro01051/status/778264463984041984">2016年9月20日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-video" data-lang="ja"><p lang="ja" dir="ltr">.<a href="https://twitter.com/akihiro01051">@akihiro01051</a> <br>たぶん音声は出てるはず。 <a href="https://t.co/DK5psVUH94">pic.twitter.com/DK5psVUH94</a></p>&mdash; アキヒロ (@akihiro01051) <a href="https://twitter.com/akihiro01051/status/781331438884966400">2016年9月29日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

## 今後の課題
- アプリの画面がサンプルのままでいまいち
- 周りがわさわさしてると音声認識がうまくいかない(しゃべり終わりを認識できない)
- ぬいぐるみ単体とお話したい