"BOKU"のITな日常

62歳・文系システムエンジニアの”BOKU”は日々勉強を楽しんでます

A3RTの「Text Summarization API」で長い文章をAIで要約をするデモ画面/Python+django2.0+bootstrap4

文章を入力して要約された結果を返すデモ画面を作ってみます。

今回もA3RT(リクルート)のAPIを使います。

f:id:arakan_no_boku:20190320212948j:plain

 

この記事の前提

 

djangoのインストール・設定や、bootstrapを使うための設定などは、以下で説明している内容を前提にしています。

arakan-pgm-ai.hatenablog.com

arakan-pgm-ai.hatenablog.com

arakan-pgm-ai.hatenablog.com

 

Text Summarization API

 

 A3RTの「Text Summarization API」を使います。

こちらのページに解説があります。

a3rt.recruit-tech.co.jp

概要を引用します。

Text Summarization APIは、文章要約を行うAPIです。
入力された文章それぞれの意味を読み取り、特徴的な文章を抽出することができます。

利用するには「API KEY」が必要なので、上記のページから取得しておきます。

メールアドレスを入力したら、メールで送られてくるので、手続き的には簡単です。

 

デモ画面のイメージから

 

入力画面はこんな感じ。

f:id:arakan_no_boku:20190320221235j:plain

単純に複数行入力エリアに、要約元の文章を貼り付けて、送信ボタンを押すと。

f:id:arakan_no_boku:20190320221548j:plain

1行に要約された文章を青いボックスに表示する。

とまあ。

これだけです。 

 

上記のソースコードです

 

まず、入力するテキストエリアを定義します。

 

forms.py
from django import forms


class UserForm(forms.Form):
    areathree = forms.CharField(
        label='要約元文章',
        max_length=200,
        min_length=20,
        widget=forms.Textarea(
            attrs={
                'id': 'commu',
                'placeholder': 'ここに要約したい文章を入力してください(200文字迄)。',
                'rows': 10,
                'cols': 5,
            }))

APIの制約として「要約できる1文の最大文字数は200文字、且つ最大文章数は10です。」とあるので、とりあえずmax-length=200でしばりをいれてます。

あまり短すぎる文章も意味がないので、min-lengthは20にしてます。

 

views.py
from django.shortcuts import render
from . import forms
from django.template.context_processors import csrf
from .tf20 import vgg16_imagenet as cl
from . import typo_v2 as t2
from . import textsum as apido


def summarize(request):
    api = apido.TextSummarize()
    if request.method == 'POST':
        # テキストボックスに入力されたメッセージ
        input_text = request.POST["areathree"]
        # APIリクエストを投げてからの応答を取得
        rets = api.get(input_text)
        c = {
            'areathree': input_text,
            'results': rets
        }
        return render(request, 'textsum_result.html', c)
    else:
        # 初期表示の時にセッションもクリアする
        request.session.clear()
        # フォームの初期化
        form = forms.UserForm(label_suffix=':')
        c = {'form': form}
        c.update(csrf(request))
        return render(request, 'textsum.html', c)

APIを使って要約文を取得する処理は「TextSummarize()」クラスに集約します。

画面のテキストエリアの入力を 「 textone = request.POST["areathree"]」で受けて、要約結果のレスポンスを「rets = api.get(areathree)」で受け取ります。

入力画面が「textsum.html」。

要約結果を「textsum_result.html」で表示します。

 

textsum.py
import requests
import json


class TextSummarize:
    def __init__(self):
        self.key = 'DZZL4YgS8jq9DrHhtCOeuCMh27ssQ9s8'
        self.api = 'https://api.a3rt.recruit-tech.co.jp/text_summarization/v1'

    def get(self, inputtext):
        url = self.api
        quoted_text = inputtext
        print(quoted_text)
        r = requests.post(url,
                          {'apikey': self.key,
                           'sentences': quoted_text,
                           'linenumber': 1,
                           'separation': '。'})
        data = json.loads(r.text)
        if data['status'] == 0:
            ret = data['summary']
        else:
            ret = ['サマリが取得できませんでした。']
        return ret

指定のURLとオプションでPOSTします。 

基本は「sentences」オプションで 要約する文章をリクエストして、レスポンスの「summary」で要約済のテキストを得ます。

レスポンスを扱いやすくするため、一度JSON形式にして、キー指定「data['summary']」でとりだしているわけです。

処理状況は「 data['status'] 」が0(OK)かどうかで判断し、エラーなら「サマリが取得できませんでした」というエラーメッセージを返します。

 

urls.py
from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('demo04/', views.summarize, name='textsum'),
]

demo04/で入力画面を表示するURLを定義します。

templetsフォルダの「textsum.html」を表示します。

 

textsum.html

 

HTMLです。

{% extends 'base.html' %}
{% load static %}
{% load bootstrap4 %}
{% load widget_tweaks %}

{% block header %}

{% endblock %}

{% block title %}
  テキスト要約デモンストレーション
{% endblock %}

{% block content %}
<div class="container">

    <form action="" method="post">{% csrf_token %}
        <h1>文章の要約</h1>
        <div class="form-group row my-4">         
            <label class="col-lg-2 col-form-label"><h4>{{form.areathree.label}}</h4></label>
    		<div class="col-lg-6">       
	            {{form.areathree|add_class:"form-control"}}
    		</div>
    		<div class="col-lg-2">       
	            <button type="submit" class="btn btn-primary">送信する</button>
    		</div>
        </div>
     </form>
 </div>  
{% endblock %}

forms.pyで定義した名称「textone」で参照しています。

今度は、結果を表示する画面です。

 

textsum_result.html

 

HTMLです。

{% extends 'base.html' %}
{% load static %}
{% load bootstrap4 %}
{% load widget_tweaks %}

{% block header %}

{% endblock %}

{% block title %}
  文章要約デモンストレーション
{% endblock %}

{% block content %}
<div class="container">

    <form action="" method="post">{% csrf_token %}
        <h1>文章の要約</h1>
        <div class="form-group row my-4">         
            <label class="col-lg-2 col-form-label"><h4>元文章</h4></label>
    		<div class="col-lg-6">       
	            <p class="card-text">{{ areathree }}</p>
    		</div>
         </div>
     </form>
        <div id="resultarea">
        {% for txt in results %}
        	<div class="form-group row my-2">         
	        	<div class="col-lg-2"><img src="{% static "images/k_boy.png" %}" /></div> 
     			<div class="p-3 m-1 col-lg-6 bg-primary text-white">       
	           		{{ txt }}
	        	</div> 
        	</div>
        {% endfor %}
        </div>
</div>  
{% endblock %}

 

これで一応、実行できるはずです。

 

おまけ:URLエンコードに関する試行錯誤

 

ここまでで、一応できているんですが、どうも引っ掛かってるところがあります。

それは、このページに書いてある制限事項のURLエンコードの記述です。

https://a3rt.recruit-tech.co.jp/product/TextSummarizationAPI/

要約できる1文の最大文字数は200文字、且つ最大文章数は10です。
「&」記号や半角スペースがある場合には、URLエンコードをしてください(curlでは-data-urlencodeを使用) 。
入力する文章に文字の切れ目となるseparationを必ずいれてください。デフォルトのseparationは「。」です。デフォルトの場合は「。」を必ず文章に入れてください。 

ここに”「&」記号や半角スペースがある場合には、URLエンコードをしてください。”と書いてあるのですが・・どういう意味か、いまいちわかりません。

何故かというと。

&記号や半角スペースはURLエンコードするけど、他はしなくてもよい?という意味かと思ってやってみたんですね。

 

&と半角スペースだけURLエンコードする

 

抜粋です。

    encode_dic = {'&':'%26',' ':'%20'}
    enc_table = str.maketrans(encode_dic)
    quoted_text = inputtext.translate(enc_table)
    r = requests.post(url,{'apikey':self.key,'sentences':quoted_text,'linenumber':1,'separation':'。'})

辞書に定義した置換をまとめて行えるpythonのtranslate()を使って変換したものでやってみました。 

文章の頭に「& & &」みたいにいれて送信すると。

f:id:arakan_no_boku:20190321145007j:plain

うーーん。

なんだかおかしいな。

 

インプット全体をURLエンコードしてみる

 

じゃあ・・・、ということで、入力された文章全体をURLエンコードしてみました。

     quoted_text = urllib.parse.quote(inputtext)
     r = requests.post(url,{'apikey':self.key,'sentences':quoted_text,'linenumber':1,'separation':'。'})

urllib.parse.quote()を使ってURLエンコードしてます。 

これで実行すると。 

f:id:arakan_no_boku:20190321144456j:plain

あれあれ・・。

&も空白も関係なく、エラーになりました。

 

じゃあ、何もしない状態で&と空白は処理できないのか?

 

制限事項に書いてあるくらいなので、&や半角スペースを何も処理しないで渡すとエラーになるんだろうか?

これも試してみました。

    quoted_text = inputtext
    r = requests.post(url,{'apikey':self.key,'sentences':quoted_text,'linenumber':1,'separation':'。'})

もう何もしてません。

inputtextをそのまま渡してます。

これだと・・「& & &」みたいな文字列はどうなるんでしょうね。

やってみると。

f:id:arakan_no_boku:20190321150100j:plain

うーーん。

普通に処理されている。

あの制限事項は何なんですかね。

まあ・・とりあえず、そのままでいいやということで。

ではでは。