Chatbot implementation using Clojure and Javascript and integration of AI functionality

Web Technology Digital Transformation Technology Artificial Intelligence Technology Natural Language Processing Technology Semantic Web Technology Deep Learning Technology Online Learning & Reinforcement Learning Technology Chatbot and Q&A Technology User Interface Technology Knowledge Information Processing Technology Reasoning Technology Javascript and React Navigation of this blog
Introduction

In the previous article, we discussed the implementation of a simple chatbot that uses an algorithm that enumerates all conversational sequences in advance using Node.js and React. Most of the chatbots in use today are built with such algorithms, which makes them somewhat practical. The issues include the ability to respond only to fixed input and to follow a predefined sequence of responses to questions.

In this report, we describe an implementation of such an AI chatbot using Clojure and Javascript.

About Clojure

Clojure has a framework that connects across various languages. For example, ClojureScript (cljs) has a mechanism to compile cljs code into bare Javascript using google closure (similar to current AltJavascript such as typescript). It also has a mechanism to convert CSS as well, so the front end can be written using only Clojure.

This mechanism and the fact that various libraries of Java, the base platform of Clojure ((50-60% of existing systems are built on Java), can be used natively in Clojure, and Clojure itself is also an excellent framework (as used in microservices as described below). Clojure itself has excellent frameworks (datomic, pedestal, duct, etc.) that can be used for microservices as described below, and so Clojure is widely used worldwide, especially in the field of building web systems (examples in Japan are limited to some advanced companies).

In addition, as described in “Machine Learning with Clojure and Python” and “Statistical Learning with Clojure and R”, it has a mechanism to connect with libraries such as C, Python, and R. Therefore, it is expected that more highly functional chatbot systems can be constructed by combining machine learning/statistical learning with Clojure. It is expected to be possible to build more functional chatbot systems in combination with machine learning/statistical learning.

Implementation of chatbot frame in Javascript

First, we will use “chatux” as a chatbot frame. chatux is a simple yet widely used javascript chatbot frame that can be used by simply inserting a javascript library into html, so it can be used for a wide range of applications including PC and mobile. It can be used for a wide range of applications, including PC and mobile devices. (The following figure is a picture of chatux’s gitpage)

The html code is as follows. (The file name is index.html for the time being.)

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

    //Initialization parameters for 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: 'send',
                    placeHolder: 'Try to talk to them about something.'
                }
            },
            window: {
                title: 'chatbot demo',
                infoUrl: 'https://github.com/riversun/chatux'
            }
        };
    chatux.init(initParam);
    chatux.start(true);
</script>
</body>
</html>

Then open the above file in any browser and you will see the following screen. (You need to be connected to the Internet to bring the library via the web.)

The rest of the server-side code shall be written in Clojure.

Server-side implementation in Clojure

The server implementation in Clojure uses Ring and Compojure as described in “Setting up a web server in Clojure“. This is equivalent to Ruby on Rail, which is a library equivalent to django in python.

First, create a template project under an arbitrary directory using the terminal. (In this case, we will use “lein new app” in anticipation of deploying it.)

>lein new app chatbot-test

A project file named “chatbot-test” is generated. In the project file, the project.clj file describes the ring, compojure, and related files.

(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"]}})

To check for the latest version of a library, refer to the “Automatic Library Correction Tool “ancient” and install it. (Note that the latest version may not work well with other libraries.)

> lein ancient

The chatbot-test/core.clj file looks like this

(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))

For details of the code, see “Setting up a web server in Clojure“. With the above code, when there is input from the api endpoint (localhost:3001/chat) of index.html running on the web server, the code receives the data, processes it, and replies (in this case, “hello” is input and “you say hello” is returned). The code is a simple operation.

To debug whether the server is working or not, run the above code with a REPL, etc., enter “(start-server)”, and then use a terminal to send data to the server with curl and check the response. For example, the following is possible.

> 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"}]}%

If the HTTP input/output format is incorrect, an HTTP error code is returned.

If the operation is OK, “you say hello” will be returned when “hello” is input to the browser-like chatbot.

Assigning AI functions

Split the handler part in the above code as follows

;;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)))))

Then, by specifying an arbitrary request-result function for the input data, various outputs can be produced.

Candidates for the request-result function here include: classification of input sentences using SVM as described in “Document classification using liblinear and natural language processing” and output of a fixed type for each classification result, and machine learning using Clojure and Python as described in “Machine learning with Clojure and Python“. As described in “Machine Learning with Clojure and Python”, the Python library transformer described in Overview of Transformer Models, Algorithms, and Examples of Implementations is used to automatically generate and return a response based on the input sentences, as described in “Interfacing Clojure’s Web Server and DB“, data in a database can be returned as a response, and “Application of Knowledge Graphs to Question Answering Systems“. As shown in Combining Knowledge Graph and DNN and “Expert System in Clojure“, AI chatbots can be built in combination with various backend solutions.

コメント

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