Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

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

お疲れ様。昨日は遅くまで残業してもらってごめんね。
娘の誕生日で家に帰らないと行けなかったのを忘れてたんだ。
お客様に見せる資料を作ってもらって助かったよ。
あれはどこに置いてるのかな。
ああ、もちろん今晩の飲みは俺の奢りだよ、本当にありがとう。

筆者であれば、娘の誕生日のくだりでチャットを閉じます。
でもよく見てください。
その後にお客様向けに作成した資料の在処を聞かれています。
チャットを爆速で閉じた筆者は質問に答えていないためこの後怒られてしまいます。

だったら, 質問文だけを抜き出して他の部分は全て切り捨てましょう。
え?そんなことできるのかって?
できるんです。そう、COTOHA API ならね。

サンプルプログラム(雑で申し訳ない)
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)

$ 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リファレンスをご覧ください。
今回のプログラムでは、入力された文章のうち文タイプが疑問文 (interrogative) のものを抽出するところで使用しています。

照応解析

照応解析 とは、文中に現れる「あれ」や「それ」、「彼」や「彼女」などの指示語が何を指し示しているかを推定する技術のことです。
COTOHA APIでは照応解析APIも提供されているため、今回は質問文をより詳細に記述するために利用しました。
APIの詳細については照応解析APIリファレンスをご覧ください。
また、照応解析APIについては解析デモも用意されているため、簡単に試すことができます。

image.png

プログラムの簡単な説明

CotohaApiはこちらの記事cotoha_api_python3.pyからほぼそのまま拝借しています(一部エンドポイントは最新のものに書き換えています)。

まず、以下の部分で .envに書き込んだ設定を読み込み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")

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

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

# 照応解析
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)

はい、エドテン。

いろいろやってみた

上記以外にもいくつかの例で疑問文抽出をやってみたので、その結果をつらつらと書いていきます。

資料=ケーキ

input
お疲れ様。
昨日は遅くまで残業してもらってごめんね。
娘の誕生日で家に帰らないと行けなかったのを忘れてたんだ。
帰りにケーキを買って帰ったんだけど、嬉しそうに食べてくれて嬉しかったなあ。
あ、そうそう。
お客様に見せる資料を作ってもらって助かったよ。
あれはどこに置いてるのかな。
回収しておくよ。
ああ、もちろん今晩の飲みは俺の奢りだよ、本当にありがとう。
output
ケーキはどこに置いてるのかな。

指示語が「お客様に見せる資料」から「ケーキ」に代わってしまいました。
なんで???

何の?

input
お聞きしたいことがございます。
扶養申請に関する手続きを行いたいのですが、方法が分かりません。
これの手順書はございますでしょうか。
お忙しいところ大変恐れ入りますが、ご回答をよろしくお願いいたします。"
output
方法の手順書はございますでしょうか。

「これ」が示すものが「方法」となってしまいました。
確かにこのあたりは単純な照応解析のみでは厳しいかもしれませんね。
係り受け解析なども用いてみると良いかもしれません。

どれ?

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

「あれ」が何の指示語なのかを見つけられなかったようです。
個人的には、これは正しく出力されてほしかった…。

さいごに

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

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

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

NegeLon
おじさんは すうれつが だいすきだぞ!
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away