"BOKU"のITな日常

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

AIと雑談できる「Talk API」を使ってチャットボットもどきを作る/python+django2.0+bootstrap4

django2.0+bootstrap4をベースに、簡単なチャットボットもどきを作ります。

A3RTの「Talk 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

 

 

AI部分はA3RT提供のTalk API

 

チャットボットに使えるようなモデルを一から学習させると大変なので、リクルートさんのA3RTの「Talk API」を使います。

a3rt.recruit-tech.co.jp

Talkは、チャットボット用のAPIです。

引用すると。

Talk APIはChatbotを作成するためのAPIです。

Recurrent Neural Network(LSTM)を用いた入力文からの応答文生成による日常会話応答機能を提供します。

Talk APIを活用したChatbotによって様々なアプリケーション上でユーザとの対話を自動化し、 どのようなタイミングにおいても即座にユーザからの問いかけに対して応答することができます。

とのことです。

 

APIKEYを取得する

 

Talk APIのページにいって、最下段までスクロールすると、ボタンがあります。

f:id:arakan_no_boku:20190122232400j:plain

API KEY発行ボタンを押すと、メールアドレスの入力を即されます。

f:id:arakan_no_boku:20190122232450j:plain

入力するものは、これだけ。

あとは、送られてくるメールにあるURLをクリックして本登録すると、再度メールにKEYが送られてきます。

メールアドレス以外の個人情報など、いっさいいりません。

 

APIを使って応答メッセージを取得するソースコード

 

puthonでやります。

まず、Talk APIを使って応答を受け取る処理のソースコードです。

talk.py
import requests
import json

class Talk:
    def __init__(self):
        self.key = 'XXXXXXXXXXXXXXXXX'
        self.api = 'https://api.a3rt.recruit-tech.co.jp/talk/v1/smalltalk'

    def get(self,talking):
        url = self.api
        r = requests.post(url,{'apikey':self.key,'query':talking})
        data = json.loads(r.text)
        if data['status'] == 0:
            t = data['results']
            ret = t[0]['reply']
        else:
            ret = '・・・・・・・・・'
        return ret

'XXXXXXXXXXXXXXXXXXX'の部分は取得したAPI-KEYに置き換える必要があります。

 

ソースコードの補足

 

やってることは。

API-KEYと入力したフレーズをパラメータにセットして、URLに対してPOSTし、受け取ったJSONのレスポンスをdataに取り出しているだけです。

data['status']==0が正常終了で、以外だとエラーなので無言('・・・・・・・・・・・')を返すようにしてます。

応答メッセージの取り出し部分は以下です。

 t = data['results']
ret = t[0]['reply']

 これで、とりあえずAPIから応答をとることができます。

使い方としては、talk.pyとかに保存したとしたら。

talk = Talk()

talk.get('こんにちは')

で、APIからの応答メッセージを受け取る感じです。 

 

チャットボットもどき画面の方針

 

TalkAPIから応答を受け取るクラスを作ったので画面を作ります。

なの。

、動きとしては入力したメッセージ文をSUBMITで、djangoに渡して、APIを通じて応答を受け取り、「入力したメッセージ文」と「応答メッセージ」がセットでポコッと表示される感じになります。

もうひと手間かけて、メッセージ文をひとつずつ表示するようにすると、よりそれっぽい画面になるのですが・・まあ、デモですし・・・(笑)

意外に違和感なかったりしたので、手抜きしてます(笑)

 

ベースになる画面

 

まずは、ソースから。

最初に作るのは、画面(HTML)です。

例によって、djangoテンプレート+bootstrap4です。

base.htmlは、こちらの記事で用意したものを流用してます。

 

talk.html

 

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

{% block header %}
<link rel="stylesheet" href="{% static "css/talk.css" %}"></link>
{% 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-1 col-form-label"><h4>{{form.texttwo.label}}</h4></label>
    		<div class="col-lg-6">       
	            {{form.texttwo|add_class:"form-control"}}
    		</div>
    		<div class="col-lg-2">       
	            <button type="submit" class="btn btn-primary">送信する</button>
    		</div>
        </div>
        <div id="talkarea">
        {% for talktxt in talktxts %}
        {% if talktxt.k == 'b' %}
        	<div class="form-group row my-2">         
	        	<div class="col-lg-1"><img src="{% static "images/k_boy.png" %}" /></div> 
     			<div class="p-3 m-1 col-lg-5 text-black font-weight-bold">       
	           		{{ talktxt.txt }}
	        	</div> 
	        	<div class="col-lg-4"></div>  
        	</div>
        {% else %}	
        	<div class="form-group row my-2">
        		<div class="col-lg-4"></div>
        		<div class="col-lg-1"><img src="{% static "images/b_girl.png" %}" /></div>  
        		<div class="p-3 m-1 col-lg-5 bg-success text-white font-weight-bold">
        			{{ talktxt.txt }}
        		</div>
        	</div>
        {% endif %}	 
        {% endfor %}
        </div>
     </form>
</div>  
{% endblock %}

<div id="textarea">は、メッセージの履歴を表示するエリアなので、高さ固定です。 

この高さだけ以下の静的CSSで定義してます。

<link rel="stylesheet" href="{% static "css/talk.css" %}"></link>

内容は、これだけのCSSです。

#talkarea
{
height:600px;
overflow:auto;
}

 

HTMLの補足

 

 talktxtsにメッセージがはいってくるのを、forループで表示してます。

これは辞書を内包したリストになっていて、「talktxt.k」に'b'(入力したメッセージ)か'ai'(応答メッセージ)の識別がはいっていて、「talktxt.txt」にメッセージ本文がはいってます。

いちおう、雰囲気のため、色の右左を「k」の値で判断して振り分けてます。

 

python側(django)のソース

 

まずは部品のテキストボックスを定義します。

 

forms.py

 

from django import forms


class UserForm(forms.Form):
    texttwo = forms.CharField(
        label='話す',
        widget=forms.TextInput(
            attrs={
                'id': 'dropedfile',
                'placeholder': 'ここに会話文を入力します。',
            }))

 

実際のメッセージを返す処理はviews.pyに書きます。 

 

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 talk


# 応答用の辞書を組み立てて返す
def __makedic(k, txt):
    return {'k': k, 'txt': txt}


def talk_do(request):
    t = talk.Talk()
    if request.method == 'POST':
        # テキストボックスに入力されたメッセージ
        q = request.POST["texttwo"]
        # Talk-APIからの応答メッセージ取得
        a = t.get(q)
        # 描画用リストに最新のメッセージを格納する
        talktxts = []
        talktxts.append(__makedic('ai', a))
        talktxts.append(__makedic('b', q))
        # 過去の応答履歴をセッションから取り出してリストに追記する
        saveh = []
        if 'hist' in request.session:
            hists = request.session['hist']
            saveh = hists
            for h in reversed(hists):
                x = h.split(':')
                talktxts.append(__makedic(x[0], x[1]))
        # 最新のメッセージを履歴に加えてセッションに保存する
        saveh.append('b:' + q)
        saveh.append('ai:' + a)
        request.session['hist'] = saveh
        # 描画準備
        form = forms.UserForm(label_suffix=':')
        c = {
            'form': form,
            'texttwo': '',
            'talktxts': talktxts
        }
    else:
        # 初期表示の時にセッションもクリアする
        request.session.clear()
        # フォームの初期化
        form = forms.UserForm(label_suffix=':')
        c = {'form': form}
        c.update(csrf(request))
    return render(request, 'talk.html', c)

セッションの処理を書いている分、行数が長くなってます。 

でも、やっていることは

  • テキストボックスに入力したメッセージをキーにして、APIを呼び出して応答を得て、画面に返却するリストにセットしている。
  • 過去の応答履歴をセッションから取り出して追記している。
  • 過去の応答履歴に最新のメッセージを追加してセッションに保存している

 というだけですから、別に難しいところはありません。

注意が必要なのは。

localhostでセッションを使う場合に「No such table : django_session」が出て実行できない時があることです。

そんな時は、runserverを実行するのと同じフォルダで以下の処理を実行しておく必要があります。

python manage.py migrate

djangolocalhostのセッション管理に、sqllite3を使うみたいなので、これをしておかないと「 django_session」テーブルがない・・ということになるようです。

 

urls.py

 

最後に、url.pyにリンクを追加します。

from django.contrib import admin
from django.urls import path
from . import views, hello

urlpatterns = [
    path('admin/', admin.site.urls),
    path('demo05/', views.talk_do, name='talk'),
]

赤字の部分が追加した部分です。

 

作ったシステムを動かす

 

これで、プロジェクトフォルダをカレントにして、runserverします。

python manage.py runserver

で、localhost:8000/demo05 にアクセスすると、こんな初期画面です。

f:id:arakan_no_boku:20191222200649p:plain

いくつか応答してみました。

f:id:arakan_no_boku:20191222201032p:plain



右のグリーンがAPIからの応答です。

まあ、雰囲気は「いい感じ」です(笑) 

 

今回はこんな感じです。

ではでは。