4
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

BotUIを使ってチャットボットを開発してみた

Last updated at Posted at 2021-09-15

はじめに

はじめまして! t_powerです。
本記事では、社内FAQをBotUIでチャットボット化した話を扱います。

プログラミング知識があまりない・・・
チャットボットを作ってみたいけど難しそう・・・
と思っている人にはぴったりのツールだと思うので、是非ご覧ください!

今回作成する上で下記のサイトを参考にさせていただきました。
この記事を見て実際に作ろうと思っている方はこちらも参考にしてください。

  1. JavaScriptだけで本格的なチャットボットを開発できるライブラリ「BotUI」を使ってみた!
  2. チャットボットを作ろう:2. JekyllサイトでBotUI

今回作成したもの

「はじめる」と書かれているバナーからチャットボットを使うことができます。

作ろうと思った経緯

before

chatbot2.png

従来は、問い合わせをメールなどで受け付けて、担当者が直接回答をしていました。
類似の問い合わせも多く、担当者の負担になっていました。

after

chatbot3.png

それなら・・・

AIが流行っているし、問い合わせ対応をチャットボット化すればいいじゃないか!
という流れになり、チャットボットを開発することになりました。

BotUIとは

チャットボットのUIを構築するためのJavaScriptフレームワーク。直観的なJavaScript APIを使用して、メッセージを追加し、ユーザーが実行できるアクションを表示できる。
(出典: BotUI公式ドキュメント)

要するに、これを使えば、簡単にチャットボットが作れるよ~ってわけです!

チャットボットは大きく分けるとシナリオ型と**AI型(人工知能型)**の2種類存在していて、BotUIは、シナリオ型を簡単に作ることが出来るフレームワークになっています。
※シナリオ型とAI型の違いについてはこちらをご覧ください
シナリオ型・AI型のチャットボットを比較~導入メリットとシナリオ作成のコツ

チャットボット用のフレームワークやライブラリはたくさんあるようですが、今回はBotUIが適していそうだったので、こちらを採用しました。

事前準備

作業環境

OS: Windows10
テキストエディタ: Visual Studio Code
ブラウザ: Microsoft Edge

フォルダ構成

tree2.png

  • css/botui-theme-default.css
    独自のテーマを作成することができるファイル(デザインの変更はこちらのファイルがメイン)

  • css/botui.min.css
    基本レイアウトを設定しているファイル(あまり書き換える必要ない)

※CSSファイルはCDN経由で読み込んでもよいのですが、今回はデザインを変更したかったため、GitHubからダウンロードしました
※とにかく動くチャットボットをはやく作りたい!デザインなんてどうでもいい!という方はダウンロードする必要はございません

  • images/sample.png
    BOT側のアイコン
    ※もしアイコンを表示させたい場合は、こちらの任意の画像と、botui.min.cssをダウンロードして、書き換える必要があります(無くてもチャットボットは動きます)

  • bot/index.html
    チャットボットを表示させるファイル

  • bot/answer.js
    質問に対する回答をまとめたファイル

  • bot/bot.js
    BotUIを使ってシナリオを構成するファイル

基本的な使い方

index.html

index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>チャットボット</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="../css/botui-theme-default.css" />
    <link rel="stylesheet" href="../css/botui.min.css" />
    <!-- link rel="stylesheet" href="https://unpkg.com/botui/build/botui.min.css" / -->
    <!-- link rel="stylesheet" href="https://unpkg.com/botui/build/botui-theme-default.css" / -->
  </head>
  <body>
    <div id="botui-app" style="white-space:pre-wrap; word-wrap:break-word;">
      <bot-ui></bot-ui>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.5/vue.min.js"></script>
    <script src="https://unpkg.com/botui/build/botui.min.js"></script>
    <script src="./answer.js"></script>
    <script src="./bot.js"></script>
  </body>
</html>

index.htmlは上記のコードをそのままコピペでOKです。
(デザインにこだわらない人は<!--link rel="stylesheet" href="https://unpkg.com/botui/build/botui.min.css" /><!-- link rel="stylesheet" href="https://unpkg.com/botui/build/botui-theme-default.css" / --> のコメントを外して、お使いください)

また、Bootstrapを導入して、スマホ、PC対応のレスポンシブな画面にしてもよいかもしれません。

  • style="white-space:pre-wrap; word-wrap:break-word;"について
  • CDN経由で読み込んでいるVue.jsのバージョンがなぜ最新バージョンではないのか

上記2点は苦戦した点にて記載しています。


bot.js

bot.js
var botui = new BotUI('botui-app');
var Photo = '../images/sample.png'

//初期メッセージ
botui.message.add({
  photo: Photo,
  content: 'チャットボットです',
  delay: 1000
}).then(showQuestions);

//質問の選択肢を表示する関数
function showQuestions(){
  botui.message.add({
    photo: Photo,
    content: '質問をお選びください',
    delay: 1000
  }).then(function(){

  return botui.action.button({
    autoHide: false,
    delay: 1000,
    action: [
      {icon: 'sticky-note-o', text: '採用', value: 'recruitment'},
      {icon: 'user', text: '新入社員', value: 'newEmployee'},
      {icon: 'ellipsis-h', text: 'その他', value: 'other'}]
  });
  }).then(function(res){
    botui.action.hide();
      switch(res.value){
        case 'recruitment': showRecruitment(); break;
        case 'newEmployee': showNewEmployee(); break;
        case 'other': showOther(); break;
        default: end();
      }
  });
}

//採用カテゴリの質問の選択肢を表示する関数
function showRecruitment(){
  botui.message.add({
    photo: Photo,
    delay: 1000,
    content: '当てはまるものをお選びください'
  }).then(function(){

  //ボタンを表示
  return botui.action.button({
    autoHide: false,
    delay: 1000,
    action: [
      {icon: 'circle', text: '一次面接と最終面接の違い', value: 'interviewDifference'},
      {icon: 'circle', text: '筆記試験の合格基準を教えていただけないでしょうか', value: 'successCriteria'},
      {icon: 'long-arrow-left', text: '1つ戻る', value: 'return'}]
  });
  }).then(function(res){
    botui.action.hide();
      switch(res.value){
        case 'interviewDifference': showInterviewDifference(); break;
        case 'successCriteria': showSuccessCriteria(); break;
        case 'return': showQuestions(); break;
        default: end(); 
      }  
  });
}

function showInterviewDifference(){
  botui.message.add({
    photo: Photo,
    delay: 1000,
    content: ansInterviewDifference
  }).then(askEnd);
}

/*
省略
*/

//プログラムを終了するか聞く関数
function askEnd(){
  botui.message.add({
    photo: Photo,
    delay: 2000,
    content: '他に質問はありますか'
  }).then(function(){
  return botui.action.button({
    delay: 1500,
    action: [
      {icon: 'circle-o', text: 'はい', value: true},
      {icon: 'close', text: 'いいえ', value: false}]
  });
  }).then(function(res){
    res.value ? showQuestions() : end();
  });
}

//プログラムを終了する関数
function end(){
  botui.message.add({
    photo: Photo,
    delay: 1500,
    content: ansEnd
  })
}

スクリーンショット (176).png
今回作成したシナリオはこのような構成です。
(上記のコードには記載していませんが、「新入社員」、「その他」についても、「採用」と同様に作りました)

bot.jsもphotoのパス指定だけ気を付ければ、コピペで問題ないです。

今回使用したメソッドやオブジェクトについて説明します。

method

名前 説明
botui.message.add 新規メッセージを追加する
botui.action.button ボタンを表示する
botui.action.hide アクションを非表示にする

action object

名前 説明
autoHide 自動的に非表示になるのを防ぐ
botui.action.hide()と一緒に使い、これが呼び出されたときにボタンを消す
action 今回はbutton objectのicon、text、valueでそれぞれ、ボタンのアイコン、表示させる文、値を設定できる
また、iconはFontAwesomeを利用している
botui.action.button()などと一緒に使う

message object

名前 説明
photo 画像のパスを指定して、アイコンを指定
content 表示されるメッセージを指定
delay 表示されるまでの秒数を設定できる
※ミリ秒単位なので、1000は1秒にあたる

他のメソッドやオブジェクトに関してはこちらをご覧ください。

bot.js
}).then(function(res){
    botui.action.hide();
      switch(res.value){
        case 'recruitment': showRecruitment(); break;
        case 'newEmployee': showNewEmployee(); break;
        case 'other': showOther(); break;
        default: end();
      }
  });

選択した項目からチャットを進めていくために、switch文で条件分岐させ、選択したボタンのvalueresで取得し、それに合った関数を呼び出しています。

bot.js
//プログラムを終了するか聞く関数
function askEnd(){
  botui.message.add({
    photo: Photo,
    delay: 2000,
    content: '他に質問はありますか'
  }).then(function(){
  return botui.action.button({
    delay: 1500,
    action: [
      {icon: 'circle-o', text: 'はい', value: true},
      {icon: 'close', text: 'いいえ', value: false}]
  });
  }).then(function(res){
    res.value ? showQuestions() : end();
  });
}

プログラムを終了するか聞く関数のaskEnd()では、「はい」か「いいえ」の2択しかないため、3項演算子を使用して分岐させています。
?の左側res.valuetrueならshowQuestions()falseならend()を呼び出します。

スクリーンショット (173).png


answer.js

回答メッセージの変数をまとめたファイルです。
後で、回答メッセージをDBから取得するように改修する予定なので、一旦別ファイルに分けて宣言をしています。

answer.js
var ansInterviewDifference = `一次面接は採用担当が実施します。
最終面接は社長が実施します。`

/*
省略
*/

var ansEnd = `ご利用いただきありがとうございました。
[TOPページへ戻る](http://xxx.xxx.xx.xxx)`

スクリーンショット (174).png
スクリーンショット (175).png

このように、質問に対する回答をまとめています。

また、表示させるメッセージについては、`(バッククォート)で囲むことで、実際にファイルに記載したようにメッセージボックスにも表示されるようになります。

[TOPページへ戻る](http://xxx.xxx.xx.xxx)については、苦戦した点にて記載します。

index.html
    <script src="./answer.js"></script>
    <script src="./bot.js"></script>

今回のように別のjsファイルに質問に対する回答をまとめる場合、index.html先に回答ファイルanswer.jsを読み込む必要があるので注意!

苦戦した点

指定した場所で改行できない

index.html
<div class="container" id="botui-app" style="white-space:pre-wrap; word-wrap:break-word;">
answer.js
var ansEnd = `ご利用いただきありがとうございました。
[TOPページへ戻る](http://xxx.xxx.xx.xxx)`

メッセージ内で\n\r\nなどの改行コードを試してもうまくいかず・・・

色々調べてみると・・・

Vue.jsで文字列を改行する場合
style="white-space:pre-wrap; word-wrap:break-word;"
bot-uiタグが囲まれているdivタグの中にこれを記載し、先ほどanswer.jsで紹介したメッセージの内容を`(バッククォート)で囲む必要があるみたいです。

参考記事
Vue.jsでdataの文字列を改行したい
HTMLクイックリファレンス white-space
HTMLクイックリファレンス word-wrap

リンク化できない

index.html
<!-- これだとリンク化できない -->
<script src="https://cdn.jsdelivr.net/vue/latest/vue.min.js"></script>
<!-- 2.0.5にすることでリンク化できる -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.5/vue.min.js"></script>

公式ガイドに記載されている通り、Vue.jsの最新バージョンをCDN経由で読み込んでいました。しかし、その場合URLの後に別のメッセージが表示されると、リンク化されなくなってしまうみたいです。

この問題を解決するためには、Vue.jsのバージョンを2.0.5に落とすことで、どのような状況でもリンク化されるようになります。

参考記事
URL loses its markup in javascript framework (BotUI)

URLを新規タブで展開できない

answer.js
var ansEnd = `ご利用いただきありがとうございました。
[TOPページへ戻る](http://xxx.xxx.xx.xxx)`

[表示文字](URL)で指定すると、同じタブで画面が切り替わってしまって、チャットボットが閉じてしまいます。

answer.js
var newline = `[BotUI 公式マニュアル](https://docs.botui.org/index.html)^`

新規タブで展開するには、カッコの後ろに^(キャレット)を付けることで解決できました。

デザイン

今回デザインを変更するために、GitHubからダウンロードして読み込んだ、
botui.theme-default.cssbotui.min.cssで重要だと思った点を紹介します。

botui.theme-default.css

.botui-cotainer

botui-theme-default.css
.botui-container{
  font-size:14px;
  background-color:#fff;
  font-family:"Open Sans",sans-serif
}
  • font-size
    メッセージの文字やボタンの文字の大きさを指定

  • background-color
    チャット背景色を指定

  • font-family
    フォントを指定(フォントファミリーと総称フォントの2つがある)

.botui-messages-container

botui-theme-default.css
.botui-messages-container{
  padding:10px 20px
}
  • padding

    メッセージのパディングを指定

.botui-actions-container

botui-theme-default.css
.botui-actions-container{
  padding:0px 20px
}
  • padding

    アクション(今回はボタン)のパディングを指定

.botui-message

botui-theme-default.css
.botui-message{
  min-height:30px
}
  • min-height

    メッセージ間の最小幅を指定

.botui-message-content

botui-theme-default.css
.botui-message-content{
  padding:7px 13px;
  border-radius:15px;
  color:#000000;
  background-color:#8bf8f8
}
  • padding
    メッセージ領域内のパディングを指定

  • color
    BOT側(左側)に表示されるメッセージの色を指定

  • background-color
    BOT側(左側)に表示されるメッセージ領域内の背景色を指定

※border-radiusは外枠の丸み具合を変更するプロパティだが、ここで値を変更しても変わりませんでした(メッセージの要素内を変更するプロパティだから効かない?)

.botui-message-content.human

botui-theme-default.css
.botui-message-content.human{
  color:#000000;
  background-color:#f8ddaa
}
  • color
    人間側(右側)に表示されるメッセージの色を指定

  • background-color
    人間側(右側)に表示されるメッセージ領域内の背景色を指定

.botui-message-content.text

botui-theme-default.css
.botui-message-content.text{
  line-height:150%
}
  • line-height

    メッセージ領域内の行間の高さを指定

.botui-message-content.embed

botui-theme-default.css
.botui-message-content.embed{
  padding:5px;
  border-radius:5px
}
  • padding
    動画のパディングを指定

  • border-radius
    外枠の丸みを指定

.botui-message-content-link

botui-theme-default.css
.botui-message-content-link{
  color:#1A0DAB
}
  • color

    リンクの色を指定

.botui-actions-buttons-button

botui-theme-default.css
.botui-actions-buttons-button{
  border:1;
  color:#fff;
  line-height:1;
  cursor:pointer;
  font-size:14px;
  font-weight:normal;
  padding:10px 20px;
  border-radius:4px;
  font-family:"Open Sans",sans-serif;
  background:#777979;
  box-shadow:2px 3px 4px 0 rgba(0,0,0,.25)
}
  • cursor
    ボタンにカーソルを合わせたときの種類を指定

  • font-weight
    ボタンの文字の太さを指定

botui.min.css

.botui-message-content

botui.min.css
.botui-message-content{
  width:auto;
  max-width:80%;
  display:inline-block
}
  • max-width

    メッセージボックスの幅を指定

.profil

botui.min.css
.profil{
  position:relative;
  top: -10px;
  border-radius:50%
}
  • top

    基準の位置からどれくらい上に動かすかを指定

※元々topプロパティは無かったが、アイコンを大きくしたらズレてしまったので、追記して丁度いい位置にくるように指定しました

.profil>img

botui.min.css
.profil>img{
  width:50px;
  height:50px;
  border:2px solid #e8e8e8
}
  • width
    アイコン画像の幅を指定

  • height
    アイコン画像の高さを指定

.profil>img.agent

botui.min.css
.profil>img.agent{
  /*初期設定だと変な画像になっているため、削除推奨
  content:url(http://decodemoji.com/img/logos/blue_moji_hat.svg);
  */
  border-radius:50%
}
  • content

    ここで画像指定していると、photoで表示したい画像を選んでもBOT側のアイコンは強制的にここで設定している画像になるため、削除推奨

おまけ

YouTube動画の埋め込み方

今回作成したチャットボットでは使用していませんが、試したので記載します。

bot.js
botui.message.add({
  type: 'embed',
  content: 'https://www.youtube.com/embed/1oSeywNsjak',
  delay: 1000
}).then(showQuestions);

YouTubeの動画を埋め込む際に注意する必要があります。
embedは外部要求を許可しているが、watchは許可していないため、URLを書き換える必要があります。
× https://www.youtube.com/watch?v=1oSeywNsjak
https://www.youtube.com/embed/1oSeywNsjak

youtube.png

参考記事
youtube html 埋め込み

おわりに

JavaScript初心者でも、BotUIを使うことで、簡単にシナリオ型のチャットボットを作ることが出来ました。
直観的に操作することが出来るので、プログラミングがよくわからなくても、それっぽいものを作れてしまうのが、BotUIのいいところだと思いました。

スクリーンショット (178).png
しかし、数が増えるとボタンも増える(分岐が増えてしまう)ため、見栄えがとても悪くなってしまいます。そのため、今後はAI型にシフトさせるなどの対策が必要だと思いました。

最後まで読んでいただき、ありがとうございました:bow_tone1:

4
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?