【Django】チャットボットの祖、ELIZA(イライザ)を実装してみよう


投稿日 2020年6月14日 >> 更新日 2023年3月2日

今回は、チャットボットの祖であるELIZAプログラムをPythonのWebフレームワークのDjangoを使って構築していこうと思います。

ELIZA(イライザ)とは、Wikipediaを見てもらえれば分かる通り初期の自然言語処理プログラムの1つであり、心理療法士として会話を行えることが有名です。

他にも、チューリングテストというアラン・チューリングが提案した機械が人間的かどうかを判定するためのテストで、ELIZAは抜群の成績を納めた事も有名であります。

そのELIZAの開発者は、ドイツ生まれであるJoseph Weizenbaum(ジョセフ・ワイゼンバウム)と言い、1966年に初めて世に出したと言われています。

そんなELIZAプログラムですが、様々なことに影響を与えており、ゲームや映画のキャラクターにも活用され、プログラムがオープンソースという事もあり拡張や応用などをして一般にもプログラムが使われていると言われています。

今回はオープンソースでダウンロード可能なjavaScript版のELIZAプログラムをDjangoにて実装していきます。

実行環境&使用ライブラリ

実行環境
Windows Subsystem for Linux
Python 3.6.9
pip 9.0.1
使用ライブラリ ライセンス
Django==3.0.7 BSD

Djangoでテンプレートファイルの表示

ELIZAプログラムは全てJavaScriptによって構成されているので、ここではテンプレートファイルのリクエストに応えるだけの処理を書きます。

ではDjangoプロジェクトを立ち上げ、「eliza」というアプリケーションを作成します。

$ django-admin startproject project

$ cd project

/project$ python3 manage.py startapp eliza
# /project

project
    |-- eliza
    |-- project
    |-- manage.py

projectディレクトリ内の「settings.py」「urls.py」を編集します。

# /project/project/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'eliza',   # アプリケーション名の追加
]
...
...
 # 必要であれば日本語設定
LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'

....
STATIC_URL = '/static/'
# /project/project/urls.py

"""project URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
...
...
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include # 追加

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('eliza.urls')), # 追加
]

次にelizaディレクトリへ移動します。

階層は以下のようになっています。

# /project/eliza

eliza
   |-- __pychache__
   |-- migrations
   |-- ___init__.py
   |-- admin.py
   |-- apps.py
   |-- models.py
   |-- tests.py
   |-- views.py

新しく「urls.py」を作成し、Djangoがviews.pyへアクセスするために必要なURLパターンを記述します。

# /project/eliza/urls.py

from django.urls import path
from . import views

app_name = 'eliza'

urlpatterns = [
    path('', views.index, name='index'),
]

URLパターンではviews.py内のindexという関数にアクセスするよう記述しているので、「views.py」でテンプレートファイルへアクセスするための関数を定義します。

# /project/eliza/views.py

from django.shortcuts import render

def index(request):
    return render(request, 'eliza/index.html')

index関数の返り値リクエストとして、elizaディレクトリ内にあるindex.htmlというファイルを表示するよう指定しているので、新しくテンプレートファイル用のディレクトリを作成します。

以下のような階層を作成します。

# /project/eliza

eliza
   |-- __pychache__
   |-- migrations
   |-- templates  ← 追加
           |-- eliza
                  |-- index.html
   |-- __init__.py
   |-- admin.py
   |-- apps.py
   |-- models.py
   |-- tests.py
   |-- urls.py
   |-- views.py

templatesディレクトリ内の「index.html」では、単に「Hello World」とだけ記述します。

では「manage.py」のある階層で「runserver」を実行してみます。

# /project

$ python3 manage.py runserver
//127.0.0.1:8000

ローカルのIPアドレスにアクセスすると以下のような表示になっていれば成功です。

elizabot.zipのダウンロード

今回使用するELIZAプログラムはJavaScript版です。

以下のサイトから「elizabot.zip」をダウンロードすることができ、実際にELIZAと対話することもできます。

ファイルをダウンロードすることができたら、Djangoプロジェクト内に配置します(中身を取り出すので分かりやすいディレクトリでも良いです)。

eliza.zipの中身を展開(解凍)すると以下のような構造になります。

# /project

project
    |-- eliza
    |-- elizabot  ← 展開するとELIZAプログラムが現れる
            |-- elizabot
                    |-- eliza_test.html
                    |-- elizabot.js
                    |-- elizadata.js
                    |-- index.html
    |-- project
    |-- elizabot.zip   ← 展開
    |-- manage.py

elizabotディレクトリ内の各種ファイルを、Djangoのテンプレートファイル用のtemplatesディレクトリ内と静的ファイル用のstaticディレクトリ内に配置させます。

templatesディレクトリ内では既にindex.htmlが置かれているので、削除または置き換えを行ってelizabotの「index.html」と「eliza_test.html」を配置します。

以下の構造となります。

# /project/eliza

eliza
   |-- __pychache__
   |-- migrations
   |-- templates
           |-- eliza
                  |-- eliza_test.html  ← 配置
                  |-- index.html   ← 配置
   |-- __init__.py
   |-- admin.py
   |-- apps.py
   |-- models.py
   |-- tests.py
   |-- urls.py
   |-- views.py

この時点でDjangoを再起動またはリロードを実行すると、masswerk.at/elizabotのサイトと同じ画面が表示されるかと思います。

次に静的ファイルの設定です。

JavaScriptのファイルは、Djangoで言う静的ファイルとして扱うのでelizaアプリケーションのディレクトリ内「static」というディレクトリを作成し、JavaScript用のディレクトリ内に配置します。

# /project/eliza

eliza
   |-- __pychache__
   |-- migrations
   |-- templates
           |-- eliza
                  |-- eliza_test.html
                  |-- index.html
   |-- static   ← 追加
           |-- eliza
                  |-- js
                       |-- elizabot.js   ← 配置
                       |-- elizadata.js   ← 配置
   |-- __init__.py
   |-- admin.py
   |-- apps.py
   |-- models.py
   |-- tests.py
   |-- urls.py
   |-- views.py

そしてstaticディレクトリ内のファイルを読み込む為に、index.htmlのトップに「{% load static %}」と記述します。

<!-- /project/eliza/templates/eliza/index.html -->

<!-- staticファイル読み込み -->
{% load static %}
<HTML>
<HEAD>
    <TITLE>Eliza (elizabot.js)</TITLE>
    <SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript" SRC="elizabot.js"></SCRIPT>
    <SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript" SRC="elizadata.js"></SCRIPT>

<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript">
....
....
</SCRIPT>
</HEAD>
<BODY>
.....
.....
.....
</BODY>
</HTML>

続いてHEADタグ内に記述されているjsファイル読み込みルートをstaticディレクトリのルートに変更します。

<!-- /project/eliza/templates/eliza/index.html -->

{% load static %}
<HTML>
<HEAD>
    <TITLE>Eliza (elizabot.js)</TITLE>
        <!-- JavaScript -->
    <script src="{% static 'eliza/js/elizabot.js' %}"></script>
    <script src="{% static 'eliza/js/elizadata.js' %}"></script>

<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript">
....
....
</SCRIPT>
</HEAD>
<BODY>
.....
.....
.....
</BODY>
</HTML>

これでDjangoを再起動またはリロードを実行するとELIZAプログラムが実行されます。

オープンソースのELIZAプログラムをそのまま使用しているだけなので、英語での対話になってしまいますが、何か語り掛けてみましょう。

翻訳すると

ELIZA:「何か困っていますか?」

あなた:「こんにちは、イライザ。」

ELIZA:「こんにちは。 あなたの問題は何ですか?」

となります。

自由に拡張・応用が可能なので、JavaScriptに詳しい方は日本語対応にしてみたり、Djangoと紐づいているのでデータベースを上手く利用したり色々試してみるのも面白いかと思います。

ちなみに、もう1つのELIZAプログラムの「eliza_test.html」では、開発者のジョセフ・ワイゼンバウムがおこなったテスト用の会話例です。

先の設定と同じようにするだけでテストアプリケーションを使うことができます。

CSSでレイアウトを変更

それでは、簡単にですがCSSを使用してレイアウトの変更をおこなっていきたいと思います。

まず変更したいHTML要素内に「class」を定義していきます。

<!-- /project/eliza/templates/eliza/index.html -->

{% load static %}
<HTML>
<HEAD>
....
....
</HEAD>
<BODY>
<CENTER>
....
<h1>E l i z a</h1>
....
....
<TR><TD COLSPAN="2"><TEXTAREA NAME="e_display"></TEXTAREA></TD></TR>
<TR VALIGN="middle">
        <!-- class="input"の定義 -->
    <TD><INPUT TYPE="text" NAME="e_input" class="input"></TD>
        <!-- class="takl"の定義 -->
    <TD ALIGN="right"><INPUT TYPE="submit" VALUE="&nbsp;Talk&nbsp;" class="talk"> 
        <!-- class="reset"の定義 -->
        <INPUT TYPE="reset" VALUE="Reset" class="reset" onClick="window.setTimeout('elizaReset()',100)"></TD>
</TR>
....
....
</CENTER>
....
....
</BODY>
</HTML>

CSSファイルは後ほど作成していきますが、HEADタグ内にCSSファイルのルートを記述しておきます。

ここでは「style.css」というCSSファイルにします。

<!-- /project/eliza/templates/eliza/index.html -->

{% load static %}
<HTML>
<HEAD>
    <TITLE>Eliza (elizabot.js)</TITLE>
        <!-- CSS -->
        <link rel="stylesheet" type="text/css" href="{% static 'eliza/css/style.css' %}">
        <!-- JavaScript -->
        ....
        ....
</HEAD>
<BODY>
....
....
</BODY>
</HTML>

次に「static」ディレクトリ内にCSSディレクトリを作成し、「style.css」を作成します。

なお、アプリの背景画像を設定したいかたは、CSSディレクトリ内に設置すると良いでしょう。

# /project/eliza

eliza
   |-- __pychache__
   |-- migrations
   |-- templates
   |-- static
           |-- eliza
                  |-- css    ← 作成
                       |-- style.css    ← 作成
                       |-- 画像.jpg    ← 背景画像を設定する場合
                  |-- js
   |-- __init__.py
   |-- admin.py
   |-- apps.py
   |-- models.py
   |-- tests.py
   |-- urls.py
   |-- views.py

「style.css」の内容です。

// /project/eliza/static/eliza/css/style.css

/* bodyタグに適用 */
body {
    color: white;
    background-image: url("画像.jpg");  // 背景画像を指定
    background-position: center;   // 背景画像の位置は真ん中
}

/* h1タグに適用 */
h1 {
    font-size: 50px;
    color: gray;
    text-shadow: 2px 3px white;
}

/* テキストに適用 */
textarea {
    color: white;
    background-color: black;
    width: 600px;
    height: 400px;
}

/* 入力フォームに適用 */
.input {
    width: 500px;
    height: 25px;
}

/* talkボタンに適用 */
.talk {
    color: white;
    background-color: darkviolet;
}

/* resetボタンに適用 */
.reset {
    color: white;
    background-color: darkred;
}

全て適用されると以下のようなページが出来上がります。

ここでのELIZAプログラムは、「elizadata.js」によって応答する文言がハードコードされているので人工無能に過ぎませんが、人工知能とするには自然言語処理はもちろんのこと機械学習や深層学習(ディープラーニング)を取り入れることによって知的に振る舞うようになるかもしれません。

今回は単純にELIZAプログラムのファイルにアクセスするだけのDjangoプロジェクトでありましたが、各々で拡張をして楽しんでみて下さい。

それでは以上となります。

最後までご覧いただきありがとうございました。