Google colab上でCotohaを超手軽に使うためのPyPIパッケージ

## 2020/04/10 PyPIパッケージ公開しました！
詳しくは[こちら](https://github.com/TOOOOOOMY/Cotoha_at_python)（スター頂けるととっても嬉しいです！）

手早く使いたい方は下コードを参照してください

```py
$ pip install cotoha_at_python

from cotohacall.main  import cotoha_call
import os

os.environ['CLIENT_ID'] = 'Your ID'
os.environ['CLIENT_SECRET'] = 'Ypur Secret'

sentence = '日本語の高精度な自然言語解析を実現するAPIサービス。NTTグループの40年以上の研究成果を活かした自然言語解析技術をCOTOHA APIでお手軽にご利用いただけます。'
cotoha_call('keyword', sentence)

# Return
"""
[{'form': '高精度', 'score': 20.0},
 {'form': '実現', 'score': 16.8278},
 {'form': 'お手軽', 'score': 10.8133},
 {'form': '研究成果', 'score': 10.0},
 {'form': 'cotoha api', 'score': 10.0}]
"""
```

##前書き
COTOHAの使い方については既に超わかりやすい解説（[自然言語処理を簡単に扱えると噂のCOTOHA APIをPythonで使ってみた](https://qiita.com/gossy5454/items/83072418fb0c5f3e269f) や [「メントスと囲碁の思い出」をCOTOHAさんに要約してもらった結果。COTOHA最速チュートリアル付き](https://qiita.com/youwht/items/16e67f4ada666e679875)）があるのですが、

[【Qiita x COTOHA APIプレゼント企画】](https://zine.qiita.com/event/collaboration-cotoha-api/?utm_source=qiita&utm_medium=top_banner)を知って自分で書いていたのと、
・環境構築面倒だから[Google Colab](https://colab.research.google.com/notebooks/intro.ipynb#recent=true)で！
・何も考えずにコピペ１つで使える！

って感じのものが欲しかったので記事として出しました。

この記事を読めばコピペ１つで即座に解析できるようになる...！（はず）。



##このコピペでできるようになること+実装例
```py:
cotoha_call("ne", "ブラックサンダーが食べたい")
```
と入力すると、
「**ブラックサンダーが食べたい**」の解析結果（これは固有表現抽出）が返ってきます。

>
===>
固有表現抽出
===>
{'message': '',
 'result': [{'begin_pos': 0,
   'class': 'ART',
   'end_pos': 8,
   'extended_class': 'Product_Other',
   'form': 'ブラックサンダー',
   'source': 'basic',
   'std_form': 'ブラックサンダー'}],
 'status': 0}
>

"ne"のところは以下に変更可能です（developersで使用できるapiはすべてカバーしているはず）

| API名 | 入力 |
|:-:|:-:|
|  構文解析 | parse  |
| 固有表現抽出   |  ne |
| キーワード抽出  |  keyword |
|  照応解析 | coref  |
|  類似度算出 | simi  |
| 文タイプ判定  | sen_type  |
| ユーザ属性推定(β)  | user_at |
| 言い淀み除去(β)  | filter |
| 音声認識誤り検知(β)  |  detect |
|  感情分析 |  senti |
| 要約(β)  | summary  |

for文を使って全部やってみるとこんな感じ→

```py:
for api_type in ["ne", "parse", "coref", "keyword", "simi", "sen_type", "user_at", "filter", "detect", "senti", "summary"]:
    cotoha_call(api_type, "ブラックサンダーを食べたい。")
    print("\n") #結果を見やすくするための改行
print("解析終了！")
```

<details><summary>出力</summary><div>
>
===>
固有表現抽出
===>
{'message': '',
 'result': [{'begin_pos': 0,
   'class': 'ART',
   'end_pos': 8,
   'extended_class': 'Product_Other',
   'form': 'ブラックサンダー',
   'source': 'basic',
   'std_form': 'ブラックサンダー'}],
 'status': 0}
>
>
===>
構文解析
===>
{'message': '',
 'result': [{'chunk_info': {'chunk_func': 2,
    'chunk_head': 1,
    'dep': 'D',
    'head': 1,
    'id': 0,
    'links': []},
   'tokens': [{'attributes': {},
     'features': [],
     'form': 'ブラック',
     'id': 0,
     'kana': 'ブラック',
     'lemma': 'ブラック',
     'pos': '名詞'},
    {'attributes': {},
     'dependency_labels': [{'label': 'compound', 'token_id': 0},
      {'label': 'case', 'token_id': 2}],
     'features': [],
     'form': 'サンダー',
     'id': 1,
     'kana': 'サンダー',
     'lemma': 'サンダー',
     'pos': '名詞'},
    {'attributes': {},
     'features': ['連用'],
     'form': 'を',
     'id': 2,
     'kana': 'ヲ',
     'lemma': 'を',
     'pos': '格助詞'}]},
  {'chunk_info': {'chunk_func': 1,
    'chunk_head': 0,
    'dep': 'O',
    'head': -1,
    'id': 1,
    'links': [{'label': 'object', 'link': 0}],
    'predicate': []},
   'tokens': [{'attributes': {},
     'dependency_labels': [{'label': 'dobj', 'token_id': 1},
      {'label': 'aux', 'token_id': 4},
      {'label': 'punct', 'token_id': 5}],
     'features': ['A'],
     'form': '食べ',
     'id': 3,
     'kana': 'タベ',
     'lemma': '食べる',
     'pos': '動詞語幹'},
    {'attributes': {},
     'features': ['終止'],
     'form': 'たい',
     'id': 4,
     'kana': 'タイ',
     'lemma': 'たい',
     'pos': '動詞接尾辞'},
    {'attributes': {},
     'features': [],
     'form': '。',
     'id': 5,
     'kana': '',
     'lemma': '。',
     'pos': '句点'}]}],
 'status': 0}
>
>
===>
照応解析
===>
{'message': 'OK',
 'result': {'coreference': [],
  'tokens': [['ブラック', 'サンダー', 'を', '食べ', 'たい', '。']]},
 'status': 0}
>
>
===>
キーワード抽出
===>
{'message': '', 'result': [{'form': 'ブラックサンダー', 'score': 10.0}], 'status': 0}
>
>
===>
類似度算出
===>
{'message': 'OK', 'result': {'score': 0.99846786}, 'status': 0}
>
>
===>
文タイプ判定
===>
{'message': '',
 'result': {'dialog_act': ['information-providing'],
  'modality': 'declarative'},
 'status': 0}
>
>
===>
ユーザ属性推定（β）
===>
{'message': 'OK',
 'result': {'civilstatus': '既婚',
  'hobby': ['ANIMAL',
   'COOKING',
   'FISHING',
   'FORTUNE',
   'GYM',
   'INTERNET',
   'SHOPPING',
   'STUDY']},
 'status': 0}
>
>
===>
言い淀み除去（β）
===>
{'message': 'OK',
 'result': [{'fillers': [],
   'fixed_sentence': 'ブラックサンダーを食べたい。',
   'normalized_sentence': 'ブラックサンダーを食べたい。'}],
 'status': 0}
>
>
===>
音声認識誤り検知（β）
===>
{'message': 'OK',
 'result': {'candidates': [{'begin_pos': 4,
    'correction': [{'correct_score': 0.709220240165901, 'form': 'ダンサー'},
     {'correct_score': 0.6137611877341953, 'form': 'バンダー'},
     {'correct_score': 0.6054945064139393, 'form': 'thunder'},
     {'correct_score': 0.5943849175403254, 'form': 'サンダ'},
     {'correct_score': 0.5878497568567171, 'form': 'ザンダー'}],
    'detect_score': 0.05464221591729093,
    'end_pos': 8,
    'form': 'サンダー'}],
  'score': 0.05464221591729093},
 'status': 0}
>
>
===>
感情分析
===>
{'message': 'OK',
 'result': {'emotional_phrase': [],
  'score': 0.38033421036210907,
  'sentiment': 'Neutral'},
 'status': 0}
>
>
===>
要約（β）
===>
{'result': 'ブラックサンダーを食べたい。', 'status': 0}
>
>
解析終了！
>

</div></details>


##コピペの前に
・[COTOHA API](https://api.ce-cotoha.com/contents/index.html)からユーザー登録し、client_idとclient_secretを入手する（ユーザー登録はかなりわかりやすかったです）。

・「Python is 何？」状態だけどやってみたいって方はこちらの超わかりやすい解説（[自然言語処理を簡単に扱えると噂のCOTOHA APIをPythonで使ってみた](https://qiita.com/gossy5454/items/83072418fb0c5f3e269f) ）を読んでみてください。


##コピペするコード

<details><summary>コピペするコード</summary><div>

```py:コピペ後にクライアントIDとクライアントシークレットを書き換える
# -*- coding:utf-8 -*-
#参考：https://qiita.com/gossy5454/items/83072418fb0c5f3e269f#python%E3%81%A7%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F

import os
import urllib.request
import json
import configparser
import codecs
import sys

client_id = "クライアントID"
client_secret = "クライアントシークレット"

developer_api_base_url = "https://api.ce-cotoha.com/api/dev/nlp/"
access_token_publish_url = "https://api.ce-cotoha.com/v1/oauth/accesstokens"

api_name_show_switch = 1 #出力結果にapi名を表示させたくない場合は0にする

def cotoha_call(api_type, sentence_1, sentence_2 = "ホワイトサンダーを食べたい", sent_len = 1, ):
    # アクセストークン取得
    def getAccessToken():
        # アクセストークン取得URL指定
        url = access_token_publish_url

        # ヘッダ指定
        headers={
            "Content-Type": "application/json;charset=UTF-8"
        }

        # リクエストボディ指定
        data = {
            "grantType": "client_credentials",
            "clientId": client_id,
            "clientSecret": client_secret
        }
        # リクエストボディ指定をJSONにエンコード
        data = json.dumps(data).encode()

        # リクエスト生成
        req = urllib.request.Request(url, data, headers)

        # リクエストを送信し、レスポンスを受信
        res = urllib.request.urlopen(req)

        # レスポンスボディ取得
        res_body = res.read()

        # レスポンスボディをJSONからデコード
        res_body = json.loads(res_body)

        # レスポンスボディからアクセストークンを取得
        access_token = res_body["access_token"]

        return access_token

    # API URL指定
    if api_type == "parse":
        api_name = "構文解析"
        base_url_footer = "v1/" + api_type
        request_body_type = 1
    elif api_type == "ne":
        api_name = "固有表現抽出"
        base_url_footer = "v1/" + api_type
        request_body_type = 1
    elif api_type == "keyword":
        api_name = "キーワード抽出"
        base_url_footer = "v1/" + api_type
        request_body_type = 2
    elif api_type == "coref":
        api_name = "照応解析"
        base_url_footer = "v1/coreference"
        request_body_type = 2
    elif api_type == "simi":
        api_name = "類似度算出"
        base_url_footer = "v1/similarity"
        request_body_type = 3
    elif api_type == "sen_type":
        api_name = "文タイプ判定"
        base_url_footer = "v1/sentence_type"
        request_body_type = 1
    elif api_type == "user_at":
        api_name = "ユーザ属性推定（β）"
        base_url_footer = "beta/user_attribute"
        request_body_type = 2
    elif api_type == "filter":
        api_name = "言い淀み除去（β）"
        base_url_footer = "beta/remove_filler"
        request_body_type = 4
    elif api_type == "detect":
        api_name = "音声認識誤り検知（β）"
        base_url_footer = "beta/detect_misrecognition"
        request_body_type = 1
    elif api_type == "senti":
        api_name = "感情分析"
        base_url_footer = "v1/sentiment"
        request_body_type = 1
    elif api_type == "summary":
        api_name = "要約（β）"
        base_url_footer = "beta/summary"
        request_body_type = 5
    else :
        print("Api Type Error.")
        sys.exit()

    if api_name_show_switch == 1:
        print("===>\n" + api_name + "\n===>")
    
    url = developer_api_base_url + base_url_footer

    # ヘッダ指定
    headers={
        "Authorization": "Bearer " + getAccessToken(), #access_token,
        "Content-Type": "application/json;charset=UTF-8",
    }
    # リクエストボディ指定
    if request_body_type == 1:
        data = {
            "sentence": sentence_1
        }
    elif request_body_type == 2:
        data = {
            "document": sentence_1
        }
    elif request_body_type == 3:
        data = {
            "s1": sentence_1,
            "s2": sentence_2
        }
    elif request_body_type == 4:
        data = {
            "text": sentence_1
        }
    elif request_body_type == 5:
        data = {
            "document": sentence_1,
            "sent_len": sent_len
        }

    # リクエストボディ指定をJSONにエンコード
    data = json.dumps(data).encode()
        # リクエスト生成
    req = urllib.request.Request(url, data, headers)
        # リクエストを送信し、レスポンスを受信
    try:
        res = urllib.request.urlopen(req)
    # リクエストでエラーが発生した場合の処理
    except urllib.request.HTTPError as e:
        # ステータスコードが401 Unauthorizedならアクセストークンを取得し直して再リクエスト
        if e.code == 401:
            access_token = getAccessToken()
            headers["Authorization"] = "Bearer " + access_token
            req = urllib.request.Request(url, data, headers)
            res = urllib.request.urlopen(req)
        # 401以外のエラーなら原因を表示
        else:
            print ("<Error> " + e.reason)
            #sys.exit()

    # レスポンスボディ取得
    res_body = res.read()
    # レスポンスボディをJSONからデコード
    res_body = json.loads(res_body)
    # レスポンスボディから解析結果を取得
    return res_body

```

</div></details>

あとは

```py:
cotoha_call("入力", "解析したい文章")
```

で解析が始まります！


##後書き
企画参加する方がんばりましょう！


##参考
[自然言語処理を簡単に扱えると噂のCOTOHA APIをPythonで使ってみた](https://qiita.com/gossy5454/items/83072418fb0c5f3e269f)