Botが雑談に応えられるようにするWEB APIを公開してみた話【個人開発】

# 追記
本記事で紹介する「Chaplus雑談対話API」の後継となるAPIを公開しました。下記の記事で紹介をしているので、合わせてこちらもご覧ください。
https://qiita.com/maKunugi/items/14f1b82a2c0b6fa5c202
本記事で紹介するAPIよりも精度が向上している他、文脈を考慮した会話ができるようになっています。

# 対象読者
- チャットボット等を初めとする「対話型」のサービスに興味がある方
- チャットボット等の開発に興味がある方
- チャットボットに雑談を話させたい方
- 対話システムと人間の対話に興味がある方

# チャットボットに必要な「雑談力」

こんにちは、[maKunugi](https://twitter.com/maKunugi)です。
チャットボットを初めとする「対話型」のサービスが様々な場面で活用されている昨今ですが、対話型サービスの開発で非常に厄介なのが、「**ユーザからの問いかけに応答するためのセリフを用意しきれない**」問題です。ある程度シチュエーションや用途が限られる場合や、サービス提供者が会話の選択肢を与えるなどしない限り、対話型サービスは無数のユーザ発話を想定して開発をしなければなりません。とりわけ、ユーザがチャットボットに対して行う「雑談」はこの際たる例です。無数にある雑談のバリエーションに対応するには非常に大きいコストがかかりますが、対応をしないと下記の例のように「**すみません、違った言い方で話しかけてみてください**」のような応答を繰り返す味気ない対話型サービスになってしまいます。

```
Chatbot: 「他に何かできることはありますか？」
User: 「今日は疲れたなー」
Chatbot: 「すみません、よくわかりませんでした。違った言い方で話しかけてみてください」
User: 「今日は疲れました」
Chatbot: 「すみません、よくわかりませんでした。違った言い方で話しかけてみてください」
User: 「orz....」
Chatbot: 「すみません、よくわかりませんでした。違った言い方で話しかけてみてください」
```


そんな問題に対処するべく、ユーザの雑談に対する応答の候補を提供するWEB APIを公開しました。公開したWEB APIが少しでも対話型サービス開発の役に立てればと思い、この記事ではAPIの概要と使い方について紹介したいと思います。

※尚、この記事は個人の活動について紹介をしたものであり、所属する組織の活動とは一切関係はありません。

# 公開したWEB API

![](https://i.imgur.com/4ufWaaC.png)

「[Chaplus API](https://www.chaplus.jp)」というWEB APIを公開しました。(現在はβ版　もちろん無料です)
上記ページで登録を行うことでAPI KEYが取得できます。
後ほど、利用方法についてこの記事でも触れますが、API仕様は[こちら](https://k-masashi.github.io/chaplus-api-doc/)にまとめています。

※**本APIは応答の精度や内容の検証・改善中であることも考慮し、β版として提供しています。** 場合によっては不適切と感じられる応答を行う可能性もございます。ご利用いただく場合、利用規約をご確認の上APIの登録を行なってください。

「Chaplus」はAPIを公開するにあたって作った造語です。(「Chat + Plus = Chaplus」)
上述した問題を解決するために作ったWEB APIで、チャットボット等を初めとした対話型サービスに、雑談機能を手軽に実装することができます。

【※追記】
利用方法の例として、Chaplus APIを利用して雑談Slackボットを短時間で構築する方法を下記記事で紹介しました！
[たった10分で雑談ができる脱力系Slack Botを作成する方法(セリフや口調のカスタマイズも簡単)](https://qiita.com/maKunugi/items/6a6abf83ca27716541df)

個人開発で音声アシスタントや対話システムといった近しい領域の開発を行なっていたこともあり、本APIの開発に取り組みました。本APIはGo言語で実装しています。

類似サービスとしては、下記のようなサービスがあります。
- [かたらい](https://www.katar.ai/)
- [TalkAPI A3RT](https://a3rt.recruit-tech.co.jp/product/talkAPI/)

# APIが提供する機能

Chaplus APIは主に下記の5つの機能を提供しています。

- ユーザの発話に対する応答候補を取得する機能
- ユーザが次に言うセリフのサジェスト機能
- 応答するセリフをサービス提供者がカスタマイズする機能
- 応答してはいけないNGワードを設定する機能
- 応答をする「エージェント」のプロフィールを設定する機能

本APIは雑談に対する応答を返すだけでなく、サービス提供者が手軽に応答のカスタマイズができる仕組みも提供しています。

## Chaplus APIが返す応答の候補(例)
```
例:
ユーザ発話: 「仕事終わりのビールは最高」

応答候補

1位(Score: 0.8846)　適量でね
2位(Score: 0.8846) 今日も1日おつかれさま
3位(Score: 0.8846) カンパーイ！
4位(Score: 0.8462) 今日１日<#USERNAME>さんががんばった証拠ですね。
5位(Score: 0.4038) 発熱でいきましょう
6位(Score: 0.4038) 偉い
6位(Score: 0.3888) 牛乳派です
```
本APIはユーザ発話に対する応答の候補をScore付きで複数提供します。本APIに利用している対話システムは、WEB上の情報や個人で運営をしている対話型サービスで蓄積したデータやコンテンツをもとに応答を生成しており、幅広い話題の発話や雑談に対応しています。

Scoreは0~1の範囲の数値で、ユーザ発話に対する応答としてどれだけ自然かを示す数値です。この応答候補を利用することで、サービス提供者はセリフを用意することなくユーザの発話に対する応答を返すことができます。

### ユーザが次に言うセリフのサジェスト機能
本APIは応答の候補と共に、次にユーザが行う発話のサジェストを返します。
![](https://i.imgur.com/lzgS0ad.png)
サジェストには下記の３種類があります。

### 時間帯に応じたサジェスト
時間帯に応じて発話候補を表示します。
    
### 応答に応じたサジェスト
直近の応答に対しての発話候補を表示します。
    
### カスタマイズしたサジェスト
API利用者はサジェストを独自に設定することできます。


## 応答のカスタマイズ
本APIはリクエストに「発話ペア」を付与することができます。
利用者の対話用データの用意が不要なことが本APIの強みですが、本APIの応答に加えて新たな応答を登録しておくことができます。

本APIでは、ユーザの問いかけとそれに対する応答を「発話ペア(utterance pair)」と呼んでおり、APIのリクエストには下記のような発話ペアのリストを付与できます。

```json
"utterancePairs":[
    {
        "utterance":"おはよう！",
        "response":"今日も1日頑張って！"
    },
    {
        "utterance":"調子はどう？",
        "response":"すごくいいよ！"
    }
]
```

付与された発話ペアは、他の応答と同様のアルゴリズムで処理され、Score付きの応答候補として返されます。登録する発話ペアは、必ずしもその通りの発話(全文一致)に対して応答が返されるわけでなく、ある程度の表記揺れや類似表現も考慮します。

## NGワードの登録

本APIは幅広い話題の発話や慣用表現についての応答を行いますが、APIを使いたいサービスによっては、内容にマッチしない応答を返してしまう可能性があります。そういった応答が見受けられる場合は、APIのリクエストで「NGワード」を指定しておくことができます。
(指定したNGワードが含まれる応答はAPIから返却されなくなります）

## 「エージェント」のプロフィールを設定する機能

本APIでは、APIの応答者を「エージェント」と呼んでいます。
本APIでは、リクエストの中でエージェントの情報を設定します。
2020年3月9日現在、設定が可能なのは下記の項目です。
- エージェントの名前
- ユーザの名前(エージェントがユーザを何と呼ぶか)
- エージェントの年齢
- エージェントの口調

エージェントの口調は下記の４項目
    - 標準
    - 関西弁風
    - 甲州弁風
    - 赤ちゃん言葉風

口調を設定することで、応答の口調が変化します。

以上、APIの機能を説明しましたが、これらの機能はDEMOサイトから試すことができます。
![](https://i.imgur.com/HJDe0pb.jpg)

[DEMOサイト](https://www.chaplus.jp/demo)

# 使い方

## 1. 登録
[こちら](https://www.chaplus.jp/#contact)からAPIを利用するための登録を行います。(事前に登録フォームに記載の利用規約をご確認ください。)

## 2. APIにリクエストを送る

### エンドポイント
https://www.chaplus.jp/v1/chat?apikey=APIKEY 

上記のエンドポイントを利用します。
API登録時に取得したAPIKEYをクエリパラメータに付与します。


### METHOD
POST

### リクエストヘッダー

|  Key  |  Value  |
| ---- | ---- |
|  Content-Type  |  application/json  |

### リクエストボディ
Jsonでリクエストを記述します。

|  パラメータ  |  説明  |  型  |  必須  |
| ---- | ---- | ---- | ---- |
|  utterance  |  ユーザの発話  | String | ◯ |
|  username  |  ユーザの名前(呼び名)  | String |  |
|  agentState  |  エージェントの情報  | agentStateオブジェクト |  |
|  addition  |  追加情報  | additionオブジェクト |  |
 
utteranceにはユーザの発話を設定します。
エージェントの情報を細かく設定する場合は、下記のAgentStateオブジェクトを設定します。


|  AgentState  |  説明  | 置き換え記号 | 型 |
| ---- | ---- | ---- | ---- |
|  agentName  |  エージェントの名前  | <#NAME> | String |
|  tone  |  エージェントの口調(normal, kansai, koshu, dechu)  |  | String |
|  age  |  エージェントの年齢  | <#AGE> | String |

置き換え記号は、応答として返される際、AgentStateに設定された値に変換される文字列を指します。例えば、応答として「私の名前は<#NAME>です。」と返される場合、AgentStateのagentNameに設定された名前と<#NAME>が置き換わります。発話ペアのカスタマイズでも、この置き換え記号を利用することが可能です。

toneにはエージェントの口調が設定できます。

```
normal: 標準(default)
kansai: 関西弁風
koshu: 甲州弁風
dechu: 赤ちゃん言葉風
```

エージェントの応答をカスタマイズしたい場合はAdditionオブジェクトを設定します。

|  Addition  |  説明  | 型 |
| ---- | ---- | ---- |
|  options  |  ユーザに示す発話候補  | String配列 |
|  utterancePairs  |  発話ペアの配列  | utterancePairオブジェクトの配列 |
|  ngwords  |  NGワードのリスト  | String配列 |

optionsには先述した発話候補のサジェストに表示したい文字列を追加できます。

エージェントに応答をさせたい発話ペアを追加したい場合は、UtterancePairオブジェクトを利用します。

|  UtterancePair  |  説明  | 型 |
| ---- | ---- | ---- |
|  utterance  |  ユーザの発話  | String |
|  response  |  ユーザの発話に対する応答  | String |

UtterancePairで指定された発話ペアは、先述した通りChaplus APIが行う応答と同じロジックで処理されます。登録された発話と近しい表現の発話がリクエストされた際、応答としてresponseに設定された文字列を洗濯します。(表記揺れの考慮あり)

ここまで紹介したリクエストの内容をJsonの形にすると下記のようになります。

サンプル

```json
{
    "utterance": "調子はどう？",
    "username": "太郎",
    "agentState":{
        "agentName": "エージェント",
        "tone": "kansai",
        "age": "14歳"
    }
    "addition" {
        "options":[
            "疲れた",
            "肩凝った"
        ]
        "ngwords" [
            "ため息",
            "やめてしまえ"
        ]
        "utterancePairs" [
            {
                "utterance": "肩凝った",
                "response":"適度に運動しないとね"
            },
        ]
    }
}
```

curl サンプル

上記のサンプルの送信はCurlコマンドでお試しください。末尾に取得したAPIキーを入力する必要があります。

```
curl -v -H "Content-Type: application/json" -X POST -d '{"utterance":"調子はどう？","username":"太郎","agentState":{"agentName":"エージェント","tone":"kansai", "age":"20歳"},"addition":{"options":["疲れた","肩凝った"],"utterancePairs":[{"utterance":"肩凝った","response":"適度に運動しないとね"}]}}' https://www.chaplus.jp/v1/chat\?apikey\=<APIKEY>
```


### レスポンス

APIのレスポンスについても説明をしていきます。

#### ステータス
まずはステータスです。本APIは下記のステータスが状況に応じて返却されます。


|  ステータス  |  説明  |
| ---- | ---- |
|  200  |  リクエスト成功  |
|  400 Bad Request  |  リクエストに問題  |
|  401 Unauthorized  |  認証エラー  |
|  404 Not Found  |  存在しないエンドポイント  |
|  500 Internal Server Error  |  サーバーのエラー  |

200以外のステータスが返される場合、下記のようなエラーレスポンスがjson形式で返されます。


```json
{
    "status": "Unauthorized Error",
    "message": "invalid key"
}
```

本API(β版)は1APIキーのリクエスト1日のリクエスト上限を1000に設定しています。上限を超えた場合も上記のエラーが返却されます。(β版につきリクエスト上限の値も再考していきます。)


### レスポンスJson

|  Key  |  説明  |  型  |
| ---- | ---- | ---- |
|  bestResponse  |  ユーザ発話に対する最もScoreの高い応答  |  responseオブジェクト  |
|  responses  |  ユーザ発話に対する応答候補  |  responseオブジェクトの配列  |
|  tokenized  |  分かち書きの結果 |  String配列  |
|  options  |  次の発話候補 |  String配列  |

上記のようなレスポンスが返されます。
bestResponseにはユーザの発話に対してもっとも自然と判断された応答(Scoreがもっとも高い応答)が格納されます。他の応答を考慮せずに１つだけ応答を返したい場合はbestResponseをユーザに対する応答として採用することをお勧めします。

responsesには、bestResponseを含めたScoreが高かった応答の候補が返されます。
responsesはresponseオブジェクトの配列で以下の要素を含みます。

|  response  |  説明  |  型  |
| ---- | ---- | ---- |
|  utterance  |  応答の発話文  |  String  |
|  score  |  応答のScore(どれだけ自然な応答か)  | Float  |
|  url  |  応答と対応するURL(Defaultは空) |  String配列  |

Scoreは0~1の範囲で、表現され、応答がどれだけ自然かを表しています。
応答によって精度はまちまちなため、あくまで参考程度ですが、下記が目安です。

```
Score
1.0 : かなり自然
0.8以上 : 自然
0.6以上 : 自然とは言えないが、的を得ている場合が多い
0.4以上 : 自然ではないが関連性がある程度認められている
0.4未満 : 自然でない (とんちんかんな発話な可能性)
```

※本APIではまだ未実装ですが、Chaplus APIは静的Webページ(HTML)から会話の応答生成を行うことにも挑戦をしています。そのためのパラメータとして、responseオブジェクトには「url」パラメータが存在しています。現段階では必ず空文字が返ってきます。



optionsには、次にユーザが発話する際の参考になる「発話候補」が返されます。
optionsの内容は、ユーザ発話やAPIの応答によって決まる内容と、時間帯によって決まる内容、APIリクエストでカスタマイズした内容の３種類が含まれます。


ここまで紹介したレスポンスの内容は実際に下記のようなjsonで返されます。

サンプル

```json
{
    "utterance": "仕事終わりのビールは最高",
    "bestResponse": {
        "utterance": "適量でね",
        "score": 1,
        "url": ""
    },
    "responses": [
        {
            "utterance": "適量でね",
            "score": 1,
            "url": ""
        },
        {
            "utterance": "今日も1日おつかれさま",
            "score": 1,
            "url": ""
        },
        {
            "utterance": "今日１日太郎はんががんばった証拠やね。",
            "score": 0.7083,
            "url": ""
        },
        {
            "utterance": "カンパーイ！",
            "score": 0.7083,
            "url": ""
        },
        {
            "utterance": "牛乳派です",
            "score": 0.3333,
            "url": ""
        },
        {
            "utterance": "偉い",
            "score": 0.3333,
            "url": ""
        }
    ],
    "tokenized": [
        "名詞,サ変接続,*,*,*,*,仕事,シゴト,シゴト",
        "動詞,自立,*,*,五段・ラ行,連用形,終わる,オワリ,オワリ",
        "助詞,連体化,*,*,*,*,の,ノ,ノ",
        "名詞,一般,*,*,*,*,ビール,ビール,ビール",
        "助詞,係助詞,*,*,*,*,は,ハ,ワ",
        "名詞,一般,*,*,*,*,最高,サイコウ,サイコー"
    ],
    "options": [
        "疲れた",
        "肩凝った",
        "会社の人間関係は家まで持ち込みたくないですね",
        "今日は大変な１日だったなー",
        "明日はいい朝を迎えたいね",
        "ヒーリング音楽流すと安らぎますよね"
    ]
}
```

本APIでは、発話の分かち書きに下記ライブラリを利用させていただいています。
[Kagome](https://github.com/ikawaha/kagome)
[Qiita記事: Pure Go で辞書同梱な形態素解析器 kagome を公開してみました](https://qiita.com/ikawaha/items/ff27ac03e22b7f36811b)

```
Kagome is licensed under the Apache License v2.0 and uses the MeCab-IPADIC, UniDic dictionary/statistical model. See NOTICE.txt for license details.
```
分かち書きの結果は、jsonレスポンスの「tokenized」に格納されています。

以上、リクエストとレスポンスに関しての使用を紹介させていただきました。
具体的なサンプル等も今後用意していけたらなと思っています。

## まとめ
個人開発で公開をした雑談対話API「Chaplus API」の紹介をさせていただきました。
本APIがチャットボット開発などのお役に少しでも立てれば幸いです。今後需要があれば、精度向上や新機能追加を進めていこうと思っています。使ってみたFBやご要望をいただけると開発に励みになりますので、何かありましたらぜひ[Twitterアカウント](https://twitter.com/maKunugi)までお寄せいただけると助かります。

最後までお読みいただきありがとうございました。