ClojureとJavascriptを使ったチャットボットの実装とAI機能の統合

ウェブ技術 デジタルトランスフォーメーション技術 人工知能技術 自然言語処理技術 セマンティックウェブ技術 深層学習技術 オンライン学習&強化学習技術 チャットボットと質疑応答技術 ユーザーインターフェース技術 知識情報処理技術 推論技術 JavascriptとReact 本ブログのナビ
イントロダクション

前回、Node.jsとReactを使った事前に会話シーケンスを全て列挙して利用するアルゴリズムのシンプルなチャットボットの実装について述べた。現在利用されているチャットボットのほとんどがそのようなアルゴリズムで構築されており、ある程度の実用性はあるものとなる。課題としては、決まった入力にしか答えられないや、質問への応答もあらかじめ定めたシーケンスに従うしかできない等があり、もう一段進んだAIチャットボットとして自然言語処理を組み合わせたものが提案され一部では利用されている。

今回はそのようなAIチャットボットをClojureとJavascriptを用いて実装について述べる。

Clojureについて

Clojureは様々な言語と横断的につながるフレームワークを持っている。たとえばClojureScript(cljs)は、google closureを利用してcljsコードをベアなJavascriptにコンパイルするしくみを持つ(typescript等の現在のAltJavascriptと同様のしくみ)。また同様にCSSも変換する仕組みを持つことから、Clojureだけでフロントエンドを記述することができる。

この仕組みとClojureのベースプラットフォームであるJava((既存のシステムの50〜60%がJavaで構築されている)が持つ様々なライブラリーがClojureでもネイティブに利用可能であること、さらにClojure自身も後述するマイクロサービスに用いられるような優れたフレームワーク(datomicpedestalduct等)も持っていることなどから、特にwebシステム等の構築の分野ではWorld Wide(日本での事例は先進的な一部の企業に限られる)で広く用いられている。

また”ClojureとPythonの連携による機械学習“や”ClojureとRの連携による統計的学習”に述べているようにCやPython、R等のライブラリーと繋げるしくみも持つことから、機械学習/統計的学習と組み合わせたより高機能なチャットボットシステムが構築できることが期待される。

Javascriptでのチャットボットフレームの実装

まずチャットボットのフレームとして”chatux“を利用する。chatuxはシンプルながら広く使われているjavascriptのチャットボットフレームとなる。htmlの中にJavascriptのライブラリを仕込ませるだけで利用できるので、PCやモバイル等幅広く利用することができる。(下図はchatxのgitpageの写真)

htmlのコードとしては以下のようになる。(ファイル名はひとまずindex.htmlとでもする)

<!DOCtype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>チャットボットデモ</title>
</head>
<body>
<script src="https://riversun.github.io/chatux/chatux.min.js"></script>
<script>
const chatux = new ChatUx();

    //ChatUXの初期化パラメータ
 const initParam =
        {
            renderMode: 'auto',
            api: {
                //echo chat server
                endpoint: 'http://localhost:3001/chat',
                method: 'GET',
                dataType: 'json'
            },
            bot: {
                botPhoto: 'https://riversun.github.io/chatbot/bot_icon_operator.png',
                humanPhoto: null,
                widget: {
                    sendLabel: '送信',
                    placeHolder: '何か話しかけてみてください'
                }
            },
            window: {
                title: 'チャットボットデモ',
                infoUrl: 'https://github.com/riversun/chatux'
            }
        };
    chatux.init(initParam);
    chatux.start(true);
</script>
</body>
</html>

あとは任意のブラウザで上記のファイルを開くと以下のような画面が見れる。(ライブラリをウェブ経由で持ってくるため、ネットに繋がっている必要がある)

後は、サーバー側のコードをClojureで書くものとなる。

Clojureでのサーバー側の実装

Clojureでのサーバー実装は以前”Clojureでのwebサーバーの立ち上げ“で述べたRingCompojureを使う。これはRuby on Railと同等のものでpythonで言うとdjangoにあたるライブラリとなる。

まず任意のディレクトリの下でターミナルを使ってテンプレートプロジェクトを作成する。(今回はデプロイすることも想定して”lein new app”を使う)

>lein new app chatbot-test

「chatbot-test」と言う名のプロジェクトファイルが生成される。プロジェクトファイル中のproject.cljファイルにringとcompojureと関連するファイルを記述する。

(defproject chatbot-test "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "https://www.eclipse.org/legal/epl-2.0/"}
  :dependencies [[org.clojure/clojure "1.10.1"]
                 [clj-liblinear "0.1.0"]
                 [org.apache.lucene/lucene-analyzers-kuromoji "5.0.0"] 
                 [org.clojure/data.csv "1.0.0"]
                 [ring "1.8.2"]
                 [ring-cors "0.1.13"]
                 [ring/ring-defaults "0.3.2"]
                 [ring/ring-json "0.5.0"]
                 [compojure "1.6.2"]]
  :main ^:skip-aot chatbot-test.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all
                       :jvm-opts ["-Dclojure.compiler.direct-linking=true"]}})

最新バージョンのライブラリをチェックするには、”ライブラリ自動補正ツールancient“を参照して導入しておけばターミナルで以下を入力すると最新ライブラリを見つけて指摘してくれるので、必要に応じて修正する。(他のライブラリとの絡みで最新のものにすると逆にうまく動作しないことがあるので注意)

> lein ancient

chatbot-test/core.cljファイルは以下のようになる。

(ns chatbot-test.core
  (:require [ring.adapter.jetty :as server]
            [compojure.core :refer :all]
            [compojure.route :as route]
            [ring.middleware.defaults :refer [wrap-defaults site-defaults]]
            [ring.middleware.json :refer [wrap-json-response wrap-json-body]]
            [ring.middleware.cors :refer [wrap-cors]]
            [ring.middleware.x-headers :refer [wrap-frame-options]]
            [ring.util.response :as r])
  (:gen-class))

;;Server instance generation
(defonce server (atom nil)). 

;;handler
(defn hello-chat [req] 
  (r/response (response-data (str "you say " (:text (:params req))))))

;;route
(defroutes app-routes
  (GET "/chat" [] hello-chat)
  (route/not-found "Not Found"))

(def app
  (-> app-routes
      wrap-json-body
      wrap-json-response
     (wrap-defaults site-defaults)
     (wrap-cors :access-control-allow-origin [#".*"] :access-control-allow-methods [:get])))

;;server launch
(defn start-server []
  (when-not @server
    (reset! server (server/run-jetty app {:port 3001 :join? false}))))

(defn stop-server []
  (when @server
    (.stop @server)
    (reset! server nil)))

(defn restart-server []
  (when @server
    (stop-server)
    (start-server)))

(defn -main []
  (start-server))

コードの詳細は”Clojureでのwebサーバーの立ち上げ“参照のこと。上記のコードにより、ウェブサーバー上で動いているindex.htmlのapi endpoint(localhost:3001/chat)から入力ずあると、そのデータを受け取り加工して返信(今回は、”hello”と入力すると”you say hello”とおうむ返し)するシンプルな動作のコードとなっている。

サーバーが動作しているかどうかのデバッグは、上記のコードをREPL等で動かし「(start-server)」を入力してから、ターミナルを使ってcurlでサーバーにデータを送ってレスポンスを確認することでできる。例えば以下のようになる。

> curl -i localhost:3000/chat\?text=Hello

HTTP/1.1 200 OK
Date: Tue, 1 Aug 2022 05:51:35 GMT
Content-Type: application/json;charset=utf-8
Set-Cookie: ring-session=6dab4b2f-f533-4319-9706-a9772fc99fee;Path=/;HttpOnly;SameSite=Strict
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Transfer-Encoding: chunked
Server: Jetty(9.4.31.v20200723)

{"output":[{"type":"text","value":"you say hello"}]}%

HTTPの出入力のフォーマットが間違っているとHTTPのエラーコードが返される。

動作が問題なければ、ブラウザ状のchatbotの入力に”hello”を入力すると”you say hello”が帰ってくる。

AI機能の付与

上記のコードでハンドラーの部分を分割して以下のようにする。

;;devide request data
(defn param-pick [msg] (:text (:params msg)))

(defn ans-text [msg] (request-result (param-pick msg)))

(defn response-value [n] (str "you say " n ))
(defn response-data [n] {:output [{:type "text" :value (response-value n)}]})

;;handler
(defn hello-chat [req] 
 (r/response (response-data (str (ans-text req)))))

すると入力データに対して任意のrequest-result関数を規定することで、さまざまなアウトプットを出すことができる。

ここでのrequest-result関数の候補としては、”liblinearと自然言語処理を用いた文書の分類“でのSVMを使って入力文の分類を行いそれぞれの分類結果に対して定型の出力を出したり、ClojureとPythonの連携による機械学習“に述べているのようにPythonライブラリであるTransformerモデルの概要とアルゴリズム及び実装例について“でも述べているtransformerを使って入力文をベースに返答の文を自動生成して返したり、”ClojureのウェブサーバーとDBとの連携“にあるようにデータベース内のデータを返答で返すようにしたり、”知識グラフの質問応答システムへの応用“にあるようにナレッジグラフとDNNを組み合わせた返答を返したり、”Clojureでのエキスパートシステム“にあるようにエキスパートシステムと組み合わせたりと、様々なバックエンドソリューションと組み合わせたAIチャットボットを構築することができる。

コメント

  1. […] ClojureとJavascriptを使ったチャットボットの実装とAI機能の統合 […]

  2. […] ClojureとJavascriptを使ったチャットボットの実装とAI機能の統合 […]

タイトルとURLをコピーしました