時間がないので端的に質問していただいてもいいですか？ feat. COTOHA API

# はじめに
忙しくて時間がないとき、長ったらしいチャットが来てもなかなか目を通せませんよね。
その中にしれっと質問なんかが紛れ込んでいると見落とす可能性もありますし厄介です。
例えば超絶多忙なとき、次のようなチャットが来たらどうしますか？

```
お疲れ様。昨日は遅くまで残業してもらってごめんね。
娘の誕生日で家に帰らないと行けなかったのを忘れてたんだ。
お客様に見せる資料を作ってもらって助かったよ。
あれはどこに置いてるのかな。
ああ、もちろん今晩の飲みは俺の奢りだよ、本当にありがとう。
```
筆者であれば、__娘の誕生日のくだりでチャットを閉じます。__
でもよく見てください。
その後にお客様向けに作成した資料の在処を聞かれています。
チャットを爆速で閉じた筆者は質問に答えていないためこの後怒られてしまいます。

だったら, 質問文だけを抜き出して他の部分は全て切り捨てましょう。
え？そんなことできるのかって？
できるんです。そう、[COTOHA API](https://api.ce-cotoha.com/contents/index.html) ならね。

<details><summary>サンプルプログラム(雑で申し訳ない)</summary><div>

```python:getQuestion.py
import os
import regex
from dotenv import load_dotenv
import itertools
from cotoha_api import CotohaApi

dotenv_path = '.env'
load_dotenv(dotenv_path)
CLIENT_ID = os.environ.get("CLIENT_ID")
CLIENT_SECRET = os.environ.get("CLIENT_SECRET")
DEVELOPER_API_BASE_URL = os.environ.get("DEVELOPER_API_BASE_URL")
ACCESS_TOKEN_PUBLISH_URL = os.environ.get("ACCESS_TOKEN_PUBLISH_URL")

# COTOHA APIインスタンス生成
cotoha_api = CotohaApi(CLIENT_ID, CLIENT_SECRET, DEVELOPER_API_BASE_URL, ACCESS_TOKEN_PUBLISH_URL)

## 解析対象文
input = "お疲れ様。昨日は遅くまで残業してもらってごめんね。娘の誕生日で家に帰らないと行けなかったのを忘れてたんだ。お客様に見せる資料を代わりに作ってもらって助かったよ。あれはどこに置いてるのかな。回収しておくよ。ああ、もちろん今晩の飲みは俺の奢りだよ、本当にありがとう。"
# 照応解析
result = cotoha_api.coreference(input)
coreference = result['result']['coreference']
tokens = result['result']['tokens']

if len(coreference) != 0:
    for relation in coreference:
        referents = relation['referents']
        sentence_id = referents[1]['sentence_id']
        token_id = referents[1]['token_id_to']
        token = referents[0]['form']
        tokens[sentence_id][token_id] = token            

input = ''.join(list(itertools.chain.from_iterable(tokens)))

sentenceList = regex.split(r'(?<=[。? ! \n])(?!$)', input, flags=regex.VERSION1)

# 文タイプ判定
for sentence in sentenceList:
    sentenceType = cotoha_api.sentenceType(sentence)
    modality = sentenceType['result']['modality']
    if modality == 'interrogative':
        print(sentence)

```
</div></details>

```
$ python3 getQuestion.py 
  # 出力：お客様に見せる資料はどこに置いてるのかな。
```
正しく質問部分を抜き出すことができていますね。
さらに、「あれ」を「お客様に見せる資料」に置き換えることもできています。


# COTOHA APIとは
NTTコミュニケーションズさんが提供している、自然言語処理と音声処理に関するAPIプラットフォームのことです。
無料版 (for Developers) と有料版 (for Enterprise) があり、無料版では1日1000コールまで利用することができます。
簡単な情報さえ登録してしまえばすぐに使うことができるので、とてもおすすめです。
COTOHA APIで提供されているAPIは以下の14種です：

- 構文解析
- 固有表現抽出
- 固有名詞 (企業名) 補正 【for Enterpriseのみ】
- 照応解析
- キーワード抽出
- 類似度算出
- 文タイプ判定
- ユーザ属性推定 (β)
- 言い淀み除去 (β)
- 音声認識誤り検知 (β)
- 感情分析
- 音声認識 【for Enterpriseのみ】
- 音声合成 【for Enterpriseのみ】
- 要約 (β)

ここまで多くの種類のAPIを取り扱っているサービスはそうそう無いと思います。
すごい、NTT。

本記事ではCOTOHA APIの __文タイプ判定__ と __照応解析__ を用いています。

## 文タイプ判定
COTOHA APIが提供しているAPIの1つである __文タイプ判定__ は、挨拶や同意などの発話行為のタイプや叙述文、命令文、質問文などの文タイプを出力します。
詳しくは[文タイプ判定APIリファレンス](https://api.ce-cotoha.com/contents/reference/apireference.html#sentence)をご覧ください。
今回のプログラムでは、入力された文章のうち文タイプが疑問文 (interrogative) のものを抽出するところで使用しています。

## 照応解析
__照応解析__ とは、文中に現れる「あれ」や「それ」、「彼」や「彼女」などの指示語が何を指し示しているかを推定する技術のことです。
COTOHA APIでは照応解析APIも提供されているため、今回は質問文をより詳細に記述するために利用しました。
APIの詳細については[照応解析APIリファレンス](https://api.ce-cotoha.com/contents/reference/apireference.html#correspond)をご覧ください。
また、照応解析APIについては[解析デモ](https://api.ce-cotoha.com/demo)も用意されているため、簡単に試すことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342285/985e45ed-ca1b-356e-d594-12d2818d9ff3.png)

## プログラムの簡単な説明
CotohaApiは[こちらの記事](https://qiita.com/gossy5454/items/83072418fb0c5f3e269f)の```cotoha_api_python3.py```からほぼそのまま拝借しています(一部エンドポイントは最新のものに書き換えています)。

まず、以下の部分で ```.env```に書き込んだ設定を読み込みCotohaApiインスタンスを生成します。

```python
dotenv_path = '.env'
load_dotenv(dotenv_path)
CLIENT_ID = os.environ.get("CLIENT_ID")
CLIENT_SECRET = os.environ.get("CLIENT_SECRET")
DEVELOPER_API_BASE_URL = os.environ.get("DEVELOPER_API_BASE_URL")
ACCESS_TOKEN_PUBLISH_URL = os.environ.get("ACCESS_TOKEN_PUBLISH_URL")

# CotohaApiインスタンス生成
cotoha_api = CotohaApi(CLIENT_ID, CLIENT_SECRET, DEVELOPER_API_BASE_URL, ACCESS_TOKEN_PUBLISH_URL)
```

次に、入力した文章に対して照応解析を行い、指示語部分をそれが指し示す語に置き換えます。

```python
# 照応解析
result = cotoha_api.coreference(input)
coreference = result['result']['coreference']
tokens = result['result']['tokens']

if len(coreference) != 0:
    for relation in coreference:
        referents = relation['referents']
        sentence_id = referents[1]['sentence_id']
        token_id = referents[1]['token_id_to']
        token = referents[0]['form']
        tokens[sentence_id][token_id] = token            

input = ''.join(list(itertools.chain.from_iterable(tokens)))

sentenceList = regex.split(r'(?<=[。? ! \n])(?!$)', input, flags=regex.VERSION1)
```

そして最後に書く文章ごとに文タイプ判定を行い、疑問文を抽出します。

```python
# 文タイプ判定
for sentence in sentenceList:
    sentenceType = cotoha_api.sentenceType(sentence)
    modality = sentenceType['result']['modality']
    if modality == 'interrogative':
        print(sentence)
```
はい、エドテン。
# いろいろやってみた
上記以外にもいくつかの例で疑問文抽出をやってみたので、その結果をつらつらと書いていきます。
## 資料＝ケーキ
```:input
お疲れ様。
昨日は遅くまで残業してもらってごめんね。
娘の誕生日で家に帰らないと行けなかったのを忘れてたんだ。
帰りにケーキを買って帰ったんだけど、嬉しそうに食べてくれて嬉しかったなあ。
あ、そうそう。
お客様に見せる資料を作ってもらって助かったよ。
あれはどこに置いてるのかな。
回収しておくよ。
ああ、もちろん今晩の飲みは俺の奢りだよ、本当にありがとう。
```
```:output
ケーキはどこに置いてるのかな。
```
指示語が「お客様に見せる資料」から「ケーキ」に代わってしまいました。
なんで？？？


## 何の？
```:input
お聞きしたいことがございます。
扶養申請に関する手続きを行いたいのですが、方法が分かりません。
これの手順書はございますでしょうか。
お忙しいところ大変恐れ入りますが、ご回答をよろしくお願いいたします。"
```
```:output
方法の手順書はございますでしょうか。
```
「これ」が示すものが「方法」となってしまいました。
確かにこのあたりは単純な照応解析のみでは厳しいかもしれませんね。
係り受け解析なども用いてみると良いかもしれません。

## どれ？
```:input
ちょっと教えてほしい。
この前さ、APIの仕様書を作ってたよね。
あれって今バージョンいくつなんだっけ？
```

```:output
あれって今バージョンいくつなんだっけ?
```
「あれ」が何の指示語なのかを見つけられなかったようです。
個人的には、これは正しく出力されてほしかった…。

## さいごに
いろいろ試してみましたが、照応解析の精度がやや低く感じました。
for Enterprise 版だともう少し精度が上がったりするのでしょうか？
一方、文タイプ判定では常に疑問文を正しく取得できていましたね。
「？」がついていなくとも疑問文が取得できるのは少し驚きました。

チャットやメールから端的な疑問文が取得できれば、
本記事の冒頭で述べた目的以外にも、例えばチャットボットの学習データに利用できたりしますよね。

今回は単純に照応解析と文タイプ判別のみを用いましたが、
もう少し工夫を凝らして取り組んでみたいと思います。