docomoの知識Q&A APIで賢いslackbotを作ってみる(前編)

# はじめに
[docomoの知識理解Q&A](https://dev.smt.docomo.ne.jp/?p=docs.api.page&api_name=knowledge_qa&p_name=api_reference)　というものがあるので，それを使って疑問に思ったことを解決してくれるslackbotを開発しようと思ったことが始まり．

![スクリーンショット 2018-03-01 18.48.23.png](https://qiita-image-store.s3.amazonaws.com/0/163680/1eee2751-7e0c-26e2-f18d-f47266a6ffa1.png)
こんな会話をslack上でして見たい．

次の記事はこちら
[docomoの知識Q&A APIで賢いslackbotを作ってみる(後編)](https://qiita.com/sey323/items/4c81ec43730883c8fc26)

# データ形式
質問に対する解答例はjson形式で返される．

「面白い映画は？」に対する回答は以下の通り．

```json:json
{
    "answers": [
        {
            "answerText": "スチュアート・リトル",
            "linkText": "先日「レミーのおいしいレストラン」を見てとても面白かったのですが、そんなわたしにネズミが主人公の面白い映画を教えてください。アニメ映画以外でも構いません。宜...",
            "linkUrl": "https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12131637827",
            "rank": "1"
        },
        {
            "answerText": "レミーのおいしいレストラン",
            "linkText": "先日「レミーのおいしいレストラン」を見てとても面白かったのですが、そんなわたしにネズミが主人公の面白い映画を教えてください。アニメ映画以外でも構いません。宜...",
            "linkUrl": "https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12131637827",
            "rank": "2"
        },
        {
            "answerText": "アメリカ映画",
            "linkText": "なにか面白い映画・ドラマが知りたいです",
            "linkUrl": "https://oshiete.goo.ne.jp/qa/5671418.html",
            "rank": "3"
        },
        {
            "answerText": "ギャラクシー・クエスト",
            "linkText": "普通に面白い映画",
            "linkUrl": "https://oshiete.goo.ne.jp/qa/9038865.html",
            "rank": "4"
        },
        {
            "answerText": "ミセスダウト",
            "linkText": "明るい感じで面白い映画教えて下さい",
            "linkUrl": "https://oshiete.goo.ne.jp/qa/5019998.html",
            "rank": "5"
        }
    ],
    "code": "S020010",
    "message": {
        "textForDisplay": "インターネットで調べたところ、もしかするとスチュアート・リトルです。",
        "textForSpeech": "インターネットで調べたところ、もしかするとスチュアートリトルです。"
    }
}
```

- `answers` 検索していくつかのリンクが出てきた場合，優先度が高い順に表示してくれるらしい．
 - `rank`回答の順位，重要度の高いものほど上に出るらしい．
 - `answerText` 単純な返答
 - `linkText` 引用元のテキスト
 - `linkURL` 引用元のURL
- `message` ユーザに返信するメッセージ
 - `testForDisplay` 結果を良い感じに文章に変換してくれたもの
 - `testForSpeech` 読み上げる時に難しい漢字をひらがなにしてくれるらしい(例：未→ひつじ)

なんでも答えられるわけでなく，わからない時は以下のように返ってくる．

```json:json
{
    "answers": [],
    "code": "E020010",
    "message": {
        "textForDisplay": "わかりませんでした。",
        "textForSpeech": "わかりませんでした。"
    }
}
```

単純に会話させるだけなら，`testForDisplay`の内容だけ表示すれば良さそうだが，今回は情報はできるだけ全てほしいということで，answersの要素も出力するようにした．

# ソースコード

`DdialogueDriver`というクラスを作成し，`lesten("質問内容")`で会話を聞かせ，`speak()`で話させるようにした．

APIKEYのところは[こちら](https://dev.smt.docomo.ne.jp/?p=docs.api.page&api_name=knowledge_qa&p_name=api_reference)で取得したapiキーを引数として渡せばOK

```python:docomo_dialogue.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys ,os
sys.path.append( os.pardir )
import requests
import json
import types

class DdialogueDriver:

    def __init__( self , _api_key = None ):
        self._data = None
        self._token = _api_key

        #エンドポイントの設定
        self._endpoint_qa = 'https://api.apigw.smt.docomo.ne.jp/knowledgeQA/v1/ask'

        self._response = ''


    def listen( self , talk ):
        self._response = ''
        self.listen_qa(talk)
        # Q&Aのリクエストを受け取ったとき
        if self._data['message']['textForDisplay'] not in 'わかりませんでした。':
            self._response += str(self._data['message']['textForDisplay'])
            if self._data['answers'] is not None:
                for answer in self._data['answers']:
                    self._response += '\n'
                    self._response += 'rank:' + answer['rank'] + answer['answerText'] + answer['linkText'] + '\n URL: ' + answer['linkUrl']
        else:
            self._response = self._data['message']['textForDisplay']

    # Q&AにAPIリクエストを飛ばす
    def listen_qa( self , talk ):
        params = {'q': talk , 'APIKEY': self._token }
        #送信
        r = requests.get(self._endpoint_qa , params )
        self._data = r.json()

    def speak( self ):
        return self._response

if __name__ == '__main__':
    dd = DdialogueDriver("APIKEY")


    #1回目の会話の入力
    utt_content = input('>>')

    dd.listen(utt_content)
    #表示
    print("response: %s" %(dd.speak()))

    #2回目以降の会話(Ctrl+Cで終了)
    while True:
        utt_content = input('>>')
        dd.listen(utt_content)

        print("response: %s" %(dd.speak()))

```

# 実行結果
`python docomo_dialogue.py`
で実行．色々適当に質問して見た．

```
>>日本で一番高い山は？
response: 日本で一番高い山は富士山です。
rank:1富士山wikipedia「富士山」より
 URL: http://ja.wikipedia.org/wiki/富士山
>>面白い映画
response: インターネットで調べたところ、もしかするとスチュアート・リトルです。
rank:1スチュアート・リトル先日「レミーのおいしいレストラン」を見てとても面白かったのですが、そんなわたしにネズミが主人
の面白い映画を教えてください。アニメ映画以外でも構いません。宜...
 URL: https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12131637827
rank:2レミーのおいしいレストラン先日「レミーのおいしいレストラン」を見てとても面白かったのですが、そんなわたしにネズミ
主人公の面白い映画を教えてください。アニメ映画以外でも構いません。宜...
 URL: https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12131637827
rank:3アメリカ映画なにか面白い映画・ドラマが知りたいです
 URL: https://oshiete.goo.ne.jp/qa/5671418.html
rank:4ギャラクシー・クエスト普通に面白い映画
 URL: https://oshiete.goo.ne.jp/qa/9038865.html
rank:5ミセスダウト明るい感じで面白い映画教えて下さい
 URL: https://oshiete.goo.ne.jp/qa/5019998.html
>>世界で最も強い人間は？
response: インターネットで調べたところ、一位は、トランプです。
rank:1トランプトランプ氏の“参謀"バノン氏「アジア歴訪は素晴らしかった」、「覇権広げる」と中国批判 東京で講演
 URL: http://blog.goo.ne.jp/7317907/e/8f42f741a6f6aa215266ada901b46d58
rank:2バノントランプ氏の“参謀"バノン氏「アジア歴訪は素晴らしかった」、「覇権広げる」と中国批判 東京で講演
 URL: http://blog.goo.ne.jp/7317907/e/8f42f741a6f6aa215266ada901b46d58
rank:3ジョン人の言うことは気にしない
 URL: https://ameblo.jp/nijiokun/entry-12339384284.html
rank:4エルモ20171205アルファゼロ将棋文献をweblio翻訳(前半)
 URL: https://ameblo.jp/nyankichi69/entry-12335197467.html
rank:5八幡和郎世界28ヶ国の王家の中では、天皇家が世界一の格上ですか?
 URL: https://oshiete.goo.ne.jp/qa/4094668.html
```
世界でい最も強い人間はトランプらしい...

次はこれをbot化する．
また後日．

# 参考
[docomoの 知識Q&A デモ。WebAPI に JSON で聞いてみる](http://ailaby.com/docomo_qa/)