Site cover image

Site icon image 近畿大学情報学部情報学科 - 授業ブログ

近畿大学の授業で用いる資料をアップするサイトです。複数の授業に関する資料がアップロードされるので、指定されたサイトへ行ってください。

実世界コンピューティングプロジェクトII - 自然言語処理

自然言語処理

自然言語処理(Natural Language Processing、NLP)は、コンピュータサイエンス、人工知能、言語学の交差点に位置する分野で、人間の言語をコンピュータに理解させるための一連の技術です。NLPの目標は、テキストや音声データを解析、理解、生成することにあります。以下は、NLPに関連する主要な技術とタスクの一部です。

主要な技術:
  1. 構文解析
    文の文法構造を解析し、その構成要素間の関係を明らかにします。
  2. 形態素解析
    文を単語やその他の意味のある要素に分解します。
  3. セマンティック解析
    文の意味を理解し、単語やフレーズの意味の関連性を評価します。
  4. 機械翻訳
    一つの言語で書かれたテキストを別の言語に変換します。
  5. テキスト分類
    テキストを特定のカテゴリに分類します。例えば、スパムメールのフィルタリングなど。
  6. 情報抽出
    テキストから特定の情報(例:固有名詞や関係)を抽出します。
  7. 情報検索
    ユーザーのクエリに対して関連する情報やドキュメントを検索します。
  8. 感情分析
    テキストの感情や意見、評価を分析します。
  9. 音声認識
    音声データをテキストデータに変換します。
  10. テキスト生成
    与えられた情報に基づいて新しいテキストを生成します。
主要なモデル・アプローチ:
  • 深層学習モデル
    • トランスフォーマーモデル(例:BERT、GPT)
    • リカレントニューラルネットワーク(RNN)
    • 畳み込みニューラルネットワーク(CNN)
  • 統計モデル
    • 隠れマルコフモデル(HMM)
    • 潜在ディリクレ配分(LDA)
  • シンボリックアプローチ
    • 生成文法
    • オントロジー

これらの技術やアプローチを組み合わせることで、コンピュータは人間の言語を理解し、より高度な自然言語処理タスクを遂行できます。

自然言語理解(NLU: Natural Language Understanding)

自然言語処理(Natural Language Processing、NLP)と自然言語理解(Natural Language Understanding、NLU)は、しばしば関連するが異なる概念として捉えられます。

自然言語処理(NLP)

自然言語処理は、人間の言語をコンピュータに処理させるための全般的な技術や手法のことを指します。NLPは、テキストデータの解析、処理、生成を含む広範なタスクをカバーします。NLPのタスクには、構文解析、形態素解析、機械翻訳、テキスト分類、情報抽出、音声認識、テキスト生成などが含まれます。

自然言語理解(NLU)

一方、自然言語理解は、NLPのサブセットと見なされることが一般的で、これはコンピュータが人間の言語を「理解」するプロセスに焦点を当てたものです。NLUの目標は、テキストや音声から意図、感情、事実、意見などの意味を抽出し、理解することです。これには、コンテキストの理解、単語やフレーズの関係の把握、ユーザーの意図の解釈などが含まれます。NLUは、質問応答システム、感情分析、意図認識などのタスクで重要とされます。


要するに、自然言語処理は人間の言語をコンピュータで処理する広範な分野であり、自然言語理解はその中でも特に、言語の「意味」を解析・抽出・理解するタスクや技術に焦点を当てた分野です。

意図(Intent)とエンティティ(Entity)

自然言語理解を扱う対話ボット作成プラットフォームには、対話の意図やエンティティを解析する機能がよく実装されています。それぞれの意味は以下の通りです。

意図(Intent)とは

意図とは、ユーザーが達成したいと思っている事柄を指します。ほとんどの意図は、「商品の検索」、「資金の移動」、「航空券の予約」のような単純な個別のタスクであり、通常は動詞と名詞の組み合わせで記述されます。このようなタイプの意図がユーザーとの対話を開始して、より多くの情報を取得したり、リモートシステムからデータを取得して更新したり、進捗状況をユーザーに通知したりします。インテントの認識における目標は、意図されたタスクや質問とユーザーの発話を正しく一致させることです。一般的に意図を示す単語の組み合わせを定義するいくつかのトレーニングモデルによって、ユーザーの意図を決定します。

エンティティ(Entity)とは

エンティティとは、ユーザーの意図を定義したり、形にしたり、変更したりするもので、日付や時刻、場所など、インテントを実行するために必要なものです。エンティティには通常、「dateTime」のような名前が付けられ、スロットと呼ばれることもあります。エンティティ抽出の目的は、タスクを完了するために必要な要素を特定することです。これらの要素には、数字や日付のような単純なものから、住所や空港名のような複雑なもの、製品カテゴリのようなユーザー定義の領域などがあります。

Botpress

Botpressは、開発者向けのチャットボットの構築を簡素化するツールです。このプラットフォームは、チャットボットを立ち上げて実行するために必要な定型コードとインフラストラクチャをまとめ、記録的な速さで本番グレードのチャットボットを構築、展開、管理するために必要なすべてのツールを備えた完全な開発者向けプラットフォームを提供します。プラットフォームには次のものが含まれます。

  • インテント分類、スペルチェック、エンティティ抽出などの組み込みの自然言語処理タスク。
  • マルチターンの会話とワークフローを設計するためのビジュアルConversation Studio 。
  • 会話をシミュレートし、チャットボットをデバッグするためのエミュレーターとデバッガー。
  • Slack、Telegram、Microsoft Teams、Facebook Messengerなどの一般的なメッセージングチャネル、および埋め込み可能な Web チャットのサポート。
  • 機能を拡張するための SDK とコードエディター。

Botpressで可能になること

  • ワークフローの自動化: チャットボットを自動化する。必要な潜在的なユーザー情報を収集します。
  • サイトにチャット機能を追加: 最近、サイトに見られるチャット応答機能を手軽に実装できます。
  • アプリケーションの会話型インターフェイスの作成: アプリケーションによっては GUI を使用して提供する方が適切な場合もありますが、場合によっては、会話型インターフェイスの方が優れている場合もあります。インターフェイスを閲覧するのではなく、平易な言葉で機能を呼び出すことができます。

チャットボットの種類

チャットボットは、ユーザー インターフェイスとして会話を使用するコンピューター プログラム (会話型ユーザー インターフェイス、略して CUI) です。チャットボットには、ルールベースのチャットボットとAI ベースのチャットボットの 2 種類があります。それらをさらに詳しく見てみましょう。

ルールベースのチャットボット(今回の実習はこちらを主に作ります)

チャットボットはルールベースである可能性があるため、会話についてはあまり理解できません。このようなチャットボットは通常、事前に入力された応答 (ボタンなど) または 1 語の応答に大きく依存します。ユーザーのメッセージが応答に影響を与えることはほとんどありません。チャットボットは、ユーザーのメッセージを受信した後、次のステップに進むか、事前に設定された応答 (ボタンやキーワードなど) をユーザーに求めます。

このタイプのチャットボットは安価で、実装が簡単で、99% 効果があり、問題を迅速に解決します。開発者が特定のワークフロー用にチャットボットを構築したため、このような特徴があります。ユーザーがチャットボットの目的を理解すると、その目的のためにチャットボットを簡単に使用できるようになります。

AIベースのボット

これらのチャットボットは言語を理解し、人間と同じような方法でコミュニケーションを行うことができます。日付、金額、場所などの有益な情報を会話から抽出できます。

これらのチャットボットは、日付、数量、ユーザーの気分、金額など、ユーザーのメッセージから利用可能なデータをすべて収集する必要がある場合に不可欠です。また、ユーザーの応答からできるだけ多くの情報を収集し、会話をより短く、簡潔にすることで会話を効率化することもできます。

Botpress を使用して両方の種類のチャットボットを開発できますが、AI ベースのチャットボットを構築しようとしている場合に、フレームワークから最もメリットが得られます。

チャットボットの構造

チャットボットは非常にシンプルです。メッセージングチャネルからメッセージを受信します。これらのメッセージを処理して、基礎となる情報を理解、翻訳、またはエスカレーションします。ユーザーにどのように応答するか を決定します。

Image in a image block
Channel

Botpressではチャネルを、チャットボットを目的のユーザー (Facebook Messenger など) に接続する任意のチャット プラットフォームとして記述することができます。Botpress は、チャットボットが次のチャットプラットフォームからメッセージを送受信できるようにする事前構築されたモジュールを提供します。

Processing > NLU

Natural Language Understanding (またはNLU ) を使用すると、チャットボットがメッセージを処理して、チャットボットが理解できる構造化データにすることができます。NLU エンジンの主なタスクは次のとおりです。

メッセージング チャネルから受信したメッセージは処理されます。処理中に、Botpress はチャット チャネル ユーザーによって送信されたテキストからデータを抽出し、次の方法で処理します。

  • 意図の分類: ユーザーが何を望んでいるのかを認識します。
    • エンティティ抽出: メッセージから日付、時刻、都市、名前などの構造化情報を抽出します。
    • スロットのタグ付け: 指定されたタスクを実行するために必要なパラメータを特定します。
    • 言語の識別: ユーザーがどの言語で書いているかを把握します。
    • スペルチェック: タイプミスやその他のエラーを修正して、ユーザーのテキスト入力のスペルが正しいことを確認することで、心配することが 1 つ減ります。
    • 範囲外の認識: ユーザーがチャットボットが理解できないことを言った場合のインスタンスを識別します。

    上記のすべては、より自然で楽しい会話を生み出すのに役立ちます。

Dialog Manager

チャットプラットフォームからテキストを受信し、そのテキストを構造化データに変換したら、次に関与するコンポーネントはダイアログマネージャ (または DM) です。DM の役割は、チャットボットが次に何をするか、何を言うべきかを決定することです。理論的には、ダイアログマネージャーは "If" ステートメントと "Else" ステートメントの束である可能性がありますが、この手法は実際にはうまく拡張できません。自然な対話は予測不可能であるため、このようなステートマシンの複雑さは指数関数的に増加します。Botpress は、拡張可能な Visual Flow Editor と強力な Decision Engine Manager を組み合わせることでこの問題を解決し、このようなステート マシンの背後にある複雑さを大幅に排除します。

環境構築

リソースの展開

まず、ClassroomにアップロードされているResources.zipを解凍しましょう。Resources.zipを解凍すると、以下のようなツリー構成のディレクトリが出てきます。

mediaproject
├── botpress_data
│   ├── lang
│   │   └── embeddings
│   │       ├── bp.ja.100.bin
│   │       └── bp.ja.bpe.model
│   └── server
├── docker-compose.yaml
└── nodred_data

このうち、`docker-compose.yaml`がdocker-composeの設定ファイル, `botpress_data`, `nodered_data`がそれぞれコンテナにマウントするデータディレクトリになります。解凍した時に上記の構成になっていなかったら、何らかの問題がありますので、教員・TAまでご相談ください。

`docker-compose.yaml`の構成は次のとおりです。

version: '3'
services:
  ## botpressの本体
  botpress:
    container_name: botpress
    image: botpress/server:v12_30_10
    volumes:
      - ./botpress_data/server:/botpress/data
    environment:
      BP_MODULE_NLU_DUCKLINGURL: http://botpress_nlu:8000
      BP_MODULE_NLU_LANGUAGESOURCES: '[{ "endpoint": "http://botpress_nlu:3100" }]'
    ports:
      - 3000:3000
    expose:
      - 3000
    depends_on:
      - botpress_nlu
  ## botpressと連携するNLU(Natural Language Understanding)サーバ
  botpress_nlu:
    container_name: lang
    image: botpress/server:v12_30_10
    volumes:
      - ./botpress_data/lang:/botpress/data
    expose:
      - 3100
      - 8000
    command: bash -c "./duckling -p 8000 & ./bp lang --langDir /botpress/data/embeddings --port 3100"
  ## NodeREDのサーバ。Teachable Machineプラグインとの連携のため、3.1-debianタグで起動する
  nodered:
    container_name: nodered
    image: nodered/node-red:3.1-debian
    volumes:
      - ./nodered_data:/data
    ports:
    - 1880:1880
docker-compose.yamlの内容の解説はこちら

この docker-compose.yaml ファイルでは、3つのサービス(botpressbotpress_nlunodered)を定義しています。以下に各項目について説明します。

version:

  • '3':このファイルが Docker Compose のバージョン3の構文を使用していることを示します。

services:

  • 各サービスを定義します。

botpress:

  • botpressの本体となるサービスです。

    container_name:

    • botpress:コンテナの名前を設定します。

    image:

    • botpress/server:v12_30_10:使用するDockerイメージを指定します。

    volumes:

    • ./botpress_data/server:/botpress/data:ホストの./botpress_data/serverディレクトリをコンテナの/botpress/dataにマウントします。

    environment:

    • 環境変数を設定します。ここでは、NLUサーバーのURLや言語源のエンドポイントが設定されています。

    ports:

    • 3000:3000:ホストのポート3000をコンテナのポート3000にバインドします。

    expose:

    • 3000:コンテナのポート3000を外部に公開します。

    depends_on:

    • botpress_nlubotpressサービスがbotpress_nluサービスに依存していることを示します。

botpress_nlu:

  • botpressと連携するNLU(Natural Language Understanding)サーバです。

    container_name:

    • lang:コンテナの名前を設定します。

    image:

    • botpress/server:v12_30_10:使用するDockerイメージを指定します。

    volumes:

    • ./botpress_data/lang:/botpress/data:ホストの./botpress_data/langディレクトリをコンテナの/botpress/dataにマウントします。

    expose:

    • 31008000:コンテナのポート3100と8000を外部に公開します。

    command:

    • 起動時に実行するコマンド。ここでは、ducklingとbp langが起動されます。

nodered:

  • NodeREDのサーバ。Teachable Machineプラグインとの連携のため、特定のタグで起動する。

    container_name:

    • nodered:コンテナの名前を設定します。

    image:

    • nodered/node-red:3.1-debian:使用するDockerイメージを指定します。

    volumes:

    • ./nodered_data:/data:ホストの./nodered_dataディレクトリをコンテナの/dataにマウントします。

    ports:

    • 1880:1880:ホストのポート1880をコンテナのポート1880にバインドします。
まとめ:

この docker-compose.yaml ファイルを使用すると、それぞれのサービスが定義された設定でDockerコンテナとして起動されます。それにより、ユーザーは複数のサービスを容易に一緒に運用できます。

今回の演習環境の構成を以下の図に示します。Docker-Composeによって立ち上がるサーバは以下の3つです。

  • botpress: チャットボットを構築するプラットフォーム
  • botpress_nlu:チャットボットにおいて、自然言語処理を担当するサービス
  • nodered:Node.jsによるWebアプリ構築をGUIで行うことができるプラットフォーム

これらのプラットフォームを連携させることで、Webサイトで動作するチャットボットサービスを構築することができます。

Image in a image block

Docker-Composeによる演習環境の立ち上げ

以下のコマンドで演習環境を立ち上げます。

$ docker compose up

実行時に大量のメッセージが流れますが、以下のメッセージが確認できれば、正常にサーバ群を起動できています。

NodeRED
nodered   | 30 Sep 03:58:50 - [info] Server now running at http://127.0.0.1:1880/
nodered   | 30 Sep 03:58:50 - [warn] Encrypted credentials not found
nodered   | 30 Sep 03:58:50 - [info] Starting flows
nodered   | 30 Sep 03:58:50 - [info] Started flows
Botpress NLU Server
lang      | 09/30/2023 03:58:59.418 [LANG] Launcher ========================================
lang      |                                                 Botpress Language Server        
lang      |                                                      Version 1.1.0             
lang      |                                         ========================================
lang      | 09/30/2023 03:58:59.429 [LANG] Launcher authToken: disabled (anyone can query your language server)
lang      | 09/30/2023 03:58:59.431 [LANG] Launcher adminToken: disabled (anyone can add, remove or change languages)
lang      | 09/30/2023 03:58:59.432 [LANG] Launcher limit: disabled (no protection - anyone can query without limitation)
lang      | 09/30/2023 03:58:59.433 [LANG] Launcher Mode: online (languages will be downloaded from https://nyc3.digitaloceanspaces.com/botpress-public/embeddings/index.json)
lang      | 09/30/2023 03:58:59.434 [LANG] Launcher Serving 100 language dimensions from /botpress/data/embeddings
lang      | 09/30/2023 03:58:59.471 [LANG] lang:service Found Languages: ja
lang      | 09/30/2023 03:58:59.591 [LANG] lang:service Loading Embeddings for JA
lang      | 09/30/2023 03:58:59.600 [LANG] lang:api Language Server is ready at http://localhost:3100/
lang      | 09/30/2023 03:59:07.056 [LANG] lang:service [JA] Took 7456ms to load 0mb into RAM (/botpress/data/embeddings/bp.ja.100.bin)
lang      | 09/30/2023 03:59:07.544 [LANG] lang:service [JA] Took 474ms to load 0mb into RAM (/botpress/data/embeddings/bp.ja.bpe.model)
Botpress
botpress  | 09/30/2023 03:59:52.429 [Studio] Launcher ===========================================================================
botpress  |                                                                         Botpress Studio                              
botpress  |                                                            Version 0.0.67 - Build 20230622-1609_BIN                 
botpress  |                                           =========================================================================== 
botpress  | 09/30/2023 03:59:52.513 [Studio] Server Loaded 10 modules 
botpress  | 09/30/2023 03:59:53.133 [Studio] CMS Loaded 11 content types 
botpress  | 09/30/2023 03:59:54.269 [Studio] Server Discovered 0 bots 
botpress  | 09/30/2023 03:59:54.274 [Studio] Server Started in 1829ms 
botpress  | 09/30/2023 03:59:54.275 [Studio] Launcher Studio is listening at: http://localhost:4000 
botpress  | 09/30/2023 03:59:54.527 Launcher  
botpress  | 09/30/2023 03:59:54.531 Launcher =========================================================================== 
botpress  | 09/30/2023 03:59:54.534 Launcher -->  Documentation is available at    📘 https://botpress.com/docs 
botpress  | 09/30/2023 03:59:54.549 Launcher -->  Ask your questions on            👥 https://forum.botpress.com 
botpress  | 09/30/2023 03:59:54.555 Launcher =========================================================================== 
botpress  | 09/30/2023 03:59:54.559 Launcher  
botpress  | 09/30/2023 03:59:54.565 Launcher Botpress is ready. open the Studio in your favorite browser. 
botpress  | 09/30/2023 03:59:54.567 Launcher Botpress is listening at http://localhost:3000 (browser) 
botpress  | 09/30/2023 03:59:54.569 Launcher Botpress is exposed at http://localhost:3000

実行ができたら、以下のアドレスにアクセスして、botpressとnoderedにアクセスできるか確認しましょう。

どちらか一方でもアクセスできなかったら、TAか教員を呼んでください。

トラブルシューティング
  • 大抵の問題は、ホストからマウントしているbotpress_data、 もしくは、nodered_dataのデータが壊れていることに起因します。docker compose up の実行画面でエラーが見つかったら、ターミナル画面から以下のようにデータを削除して、再起動しましょう。
    $ docker-compose down
    [+] Running 4/4
     ✔ Container nodered      Removed                                                                                                  0.0s 
     ✔ Container botpress     Removed                                                                                                  0.0s 
     ✔ Container lang         Removed                                                                                                  0.0s 
     ✔ Network intel_default  Removed
    $ rm -rf botpress_data/server
    $ mkdir -p botpress_data/server
    $ rm -rf nodered_data
    $ mkdir nodered_data
    $ docker-compose up
  • 問題:docker pullができない
    • dockerhubの制限でdocker pullできなくなった人は以下のGoogleDriveからイメージをダウンロードしてloadしましょう。

課題

今回の実習は自然言語を分類するための学習データを作成し、BotpressのBotを学習させます。次に学習させたモデルを使用して、入力された文章の分類結果を表示するWebアプリケーションを作成します。

【実習の大まかな流れ】

  • Botpressを用いたインテントの推定を行う
  • NoteREDで入力された文章の分類結果を表示するWebアプリケーションを作成する

課題1 :Botpressを用いた インテントの推定

本課題では、Botpressを用いたインテントの推定を行います。

1.1. Botpressのアカウントを作成する

http://localhost:3000 にアクセスします。

Image in a image block

最初の画面では、ユーザ登録をします。

  • メールアドレス:大学のメールアドレス
  • パスワード:botpress1234

で登録しましょう。

登録が完了し、無事、ログインができたら、以下の画面に遷移します。

Image in a image block
1.2. BotpressでBot”NLUBot”を作成する

まず、メイン画面の右横にある「Create Bot」のドロップダウンリストから「New Bot」ボタンを選び、クリックする。

Image in a image block

Create Botボタンを実行すると、以下のポップアップウィンドウが出てくる。

  • Bot Name: NLUBot
  • Bot Template: Empty Bot

をそれぞれ選択します(Bot IdはBot Nameから自動作成されます)。最後に「Create Bot」ボタンを押して、ボットを作成します。

Image in a image block

Botの作成ができたら、ホーム画面のボット一覧に作成したボットが現れます。次にBotの言語設定を行います。ボットの中のConfigの部分をクリックしましょう。

Image in a image block

Configがクリックできると以下のような設定画面に遷移します。この中の「General」→「Language」から「Japanese」(日本語)を選択しましょう。選択ができたら、「Save Changes」ボタンをクリックして設定を保存しましょう。

Image in a image block

1.3. NLUBotの”Natural Language Understanding”のタブでインテントの設定を行う

Languageを「Japanese」に設定後、サイドタブから、「Natural language understanding」(NLU)のタブを選択します。

Image in a image block

NLUタブを開くと以下のような画面となります。

Image in a image block

インテントの登録

この画面で、インテント(意図)の登録を行います。ここでは、以下の表に示すインテント(とスロット)のセットを登録していきます。

入力(Utterances) 意図・話題(Intent) Slot
明日は晴れますか? Weather weather
明日は晴れかな? Weather weather
〇〇(時間)は雨ですか? Weather weather
✕✕(場所)は現在曇りだよ。 Weather weather
□□は雨なんかな〜 Weather weather
今日は寒いです。 Temperature temperature
今日は寒いね。 Temperature temperature
□□は暖かいよな Temperature temperature
〇〇は暑いですか? Temperature temperature
✕✕は暑い! Temperature temperature

なお、表中の〇〇、✕✕、□□はそのまま入力するのではなく、場所や時間に置き換えて入力してください(例:は雨ですか?)。

ここでINTENTSにフォーカスを合わせ、その横の「+」部分をクリックします。

Image in a image block

Intent名を登録します。なお、一部大文字であった場合も登録時には全て小文字になります(ここではweatherとなります)。

Image in a image block

Intent名が登録されたら、Contextsの入力ができます。ここに指定した入力(Utterances)を書き込んでいきましょう。なお、入力欄で直接日本語入力をしようとすると動かないことがあります。その場合、一回テキストエディタなどで編集してからコピーすると入力できます。

Slotの作成

次にIntentに対応するSlotを作成します。

Image in a image block

Contextsの左横にあるバーの中の「Create slot」ボタンをクリックします。

slotを作成します。名前は「weather」とします(他の名前でも構いませんが、これもボット作成時に使用しますので作成した名前は覚えておきましょう)。Associated Entityとしてはsystem.anyを指定しましょう。

Image in a image block

なお、登録した発話(Utterance)中の特定用語を選択することで発話とスロットの紐付けができます。Slot名に対応した部分の単語を紐づけてみましょう。

Image in a image block

Image in a image block

これをTemperatureのインテントでも繰り返して、作成しましょう。

1.4. インテント推定のための最小限のNLUBotを作り、トレーニングする

次にインテント推定のために最小限のNLUBotを作ります。左のサイドバーからFlowsを選んで、以下の画面に遷移してください。このエディタでは、対話フローを生成することができます。詳しい作り方は、第5回で詳しくやりますが、今回はいくつかあるノード(Flowの構成要素)から、Slot Fillingを選んで、「Start Node」として登録します。

Image in a image block

まず、Flowエディタの左端にある選択画面から、Slot Fillingを選択し、ドラッグ&ドロップでエディタに移動させます。

Image in a image block

すると以下のようなSlot Fillingの編集画面が出てきます。画面では色々な要素が設定できますが、今回は対話そのものには注目しないので、以下の4つの要素のみ編集します。

  • Choose an intent: weather
  • Choose a slot to fill: weather
  • Bot will ask …: 下記のContent編集画面を通して、適当な発話を登録
  • Message to send when user input is invalid: 下記のContent編集画面を通して、適当な発話を登録
Image in a image block

「Bot will ask…」と「Message to send when user input is invalid」の項目は左のフォルダアイコンをクリックするとその内容を編集することができます。Botはテキスト以外にも以下のPick Content画面に出てくる様々な要素を出力することができますが、今回はシンプルにTextを選びます。

Image in a image block

「Text」を選ぶと、Textの編集画面に遷移します。Textには既に作成したものが出てきて、選択できるようになりますが、今回は何もないので、「Create new Text」ボタンをクリックして新規作成します。

Image in a image block

「Create new Text」ボタンをクリックするとメッセージの編集画面に遷移します。Message項目に適当な文字を入力しましょう。今回は

  • Bot will ask…: 「入力してください」
  • Message to send when user input is invalid: 「繰り返してください」

を入力してみましょう(別に他の文言でも構いません)。

Image in a image block

全てを登録すると以下の画面に戻ります。4つの項目がちゃんと埋まっているか確認しましょう。「Insert」ボタンをクリックして、Nodeを登録しましょう。

Image in a image block

Nodeの登録が成功すると、Flowエディタの画面に新しくSlot Fillingのノードが追加されています。

Image in a image block

Slot Fillingにフォーカスを合わせて、右クリックし、「Set as Start Node」を選択して、Slot FillingのノードをStart Nodeにしましょう。要らなくなった「entry」ノードは削除しましょう(同じく右クリックからDelete)。

Image in a image block

最後にBotを訓練して、登録したIntent情報を反映させます。

Image in a image block

ボットの訓練は画面右下(目立たないので気をつけましょう)の「Train Chatbot」ボタンから行います。訓練を始めると、「Training X%」というメッセージが出て、訓練が終わると「Ready」という表示に変化します。

Image in a image block
Image in a image block

状態が「Ready」になると訓練は終了です。ようやくIntent推定が実行できるようになりました。

トラブルシューティング
  • 問題:Train Chatbotの部分が、「Cannot train Chatbot」になっている
    • 解決策docker compose upを実行している画面(ターミナル)を開いて、Ctrl-Cで一回サーバをStopしましょう。その上でもう一回、docker compose upして、再起動するとTrainできるようになっています。
      botpress  | 10/03/2023 06:45:40.662 Launcher Botpress is exposed at http://localhost:3000 
      ^CGracefully stopping... (press Ctrl+C again to force)
      Aborting on container exit...
      [+] Stopping 3/3
       ✔ Container nodered   Stopped                                                                                                     0.0s 
       ✔ Container botpress  Stopped                                                                                                    10.2s 
       ✔ Container lang      Stopped                                                                                                    10.2s 
      canceled
      $ docker-compose up
1.5. エミュレータとDebuggerでインテント推定の結果を確認する

訓練されたBotを使って、Intentの推定結果を見てみましょう。Intentの推定結果を見るには、Flowエディタ画面の右上にある「Bottom Panel」と「Emulator」の両方を表示させる必要があります。まだ出ていない場合は「Bottom Panel」と「Emulator」を両方クリックして表示させましょう。

Image in a image block

以下の手順でIntent推定の結果を見ることができます。

  1. Emulatorに適当な文字列を入れてBotと会話します(Intentに登録した文字列が良いでしょう)
  2. Bottom PanelのSummaryのタブでIntentの推定結果を見る

以下の例では、「大阪は暖かいよな。」というReplyをEmulatorに入れることで、SummaryのTop Intentsの項目で、Temperatureが100%になっていることが確認できます。

Image in a image block

課題2: NodeREDでインテント推定をするWebアプリを作ってみよう

次に、NodeREDからBotpressにアクセスして、入力した文字列のインテント推定をするWebアプリを作ってみましょう。

アプリの実装にはBotpressのConverse APIを利用します。Converse API を使用すると、フロー内で API をすばやく呼び出すことができます。その後、外部 API から受信した応答を保存して、チャットボットのコードとフローで使用できます。

Webアプリの実装には以下の手順を踏みます。

  1. Botpress Converse APIを利用して、JWTキーを手にいれる。
  2. JWTキーを変数に組み込んで、Converse APIを利用して、Botにリクエストを送る。
  3. Botのレスポンスを解析して、Intent推定の結果を得る。
  4. 得られたIntent推定の結果をhtmlで表示する。

2.1. Botpress Converse APIを利用して、JWTキーを手にいれる

Botpress の対話APIには認証を必要とする安全なルート(プロトコル)があり、このルートを使用すると、カンマで区切られたクエリパラメータを使用して、応答に追加のデータが含まれるようにリクエストできます。このルートにアクセスするには、JWT トークンが必要です。JWT(JSON Web Token)は、ウェブ上で情報を安全に伝達するためのコンパクトでURL安全なトークンの一種です。JWTは、認証や情報交換に広く使用されています。この要件が設けられているのは、チャットボットバックエンド ユーザ宛ての機密情報がこのルート経由でアクセスできるためです。たとえば、チャットボットの意思決定ロジックにアクセスできます。

cURL を使用してこのトークンを取得するリクエストのサンプルを次に示します。

curl --location --request POST 'http://<your.botpress.server.com>/api/v1/auth/login/basic/default' \
	--header 'Content-Type: application/json' \
  --data-raw '{
    "email": "<YOUR-EMAIL>",
    "password": "<YOUR-PASSWORD>"
  }'

レスポンスは以下のようになります。

{
  "status": "success",
  "message": "Login successful",
  "payload": {
    "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFkbWtsoiwic3RyYXRlZ3kiOiJkZWZhdWx0IiwidG9rZW5WZXJzaW9uIjoxLCJpc1N1cGVyQWRtaW4iOnRydWUsImlhdCI6MTYxODU3Mjk1MCwiZXhwIjoxNjE4NTc2NTUwLCJhsdwiOiJjb2xsYWJvcmF0b3JzIn0.urYZ5A8yXH3XqzSmu7GmImufSgZ0Nx6HknzuidGWnRs",
    "exp": 3600000
  }
}

これをNodeRED上で実現しましょう。

NodeREDでは、以下の3つのノードでJWTキーを取得します。

  • Injectノード:httpリクエストでPOSTするpayloadの設定をします。
  • http requestノード:Botpressに対して、JWTキーを取得するPOSTリクエストを発行します。
  • debugノード:得られたJWTキーをデバッグメッセージとして表示します。

最終的に、作られるフローは以下の通りです。

Image in a image block
各ノードの設定

Injectノード

Injectノードは以下のように設定します。

  • 名前:リクエスト情報
  • msg.payload: JSON形式で以下の2要素を設定
    • email: Botpressに登録したメールアドレス
    • password: Botpressに登録したパスワード
    {
    	"email": "xxxx@kindai.ac.jp",
    	"password": "botpress1234"
    }
Image in a image block
Image in a image block

http requestノード:

http requestノードの設定は以下の通りです。

Image in a image block


フローが作成できたら、アプリケーションをデプロイし、injectノード横のボタンをクリックして、リクエストを実行しましょう。

Image in a image block

結果として、デバッグウィンドウに以下のJWTキーが表示されれば成功です。

Image in a image block
2.2. JWTキーを変数に組み込んで、Converse APIを利用して、Botにリクエストを送る。

次にJWTを変数に組み込んで、Converse APIでリクエストを送ってみます。Converse APIの仕様は以下のページに書かれています。

2.1.と同じ構造でリクエストをデバッグメッセージで表示するフローを作りましょう。

Image in a image block
各ノードの設定

Injectノード:

Injectノードは以下のように設定します。

  • 名前:Converse APIへの入力
  • msg.payload: JSON形式で以下の2要素を設定
    • type: text
    • text: <Intent登録時に登録した文字列のどれか>
    • includedContexts: ["global"]
    {
    	"type": "text",
    	"text": "<Intent登録時に登録した文字列のどれか>",
    	"includeContects": ["global"]
    }

http requestノード:

http requestノードの設定は以下の通りです。

debugノード:

  • 名前:Reply


フローが作成できたら、アプリケーションをデプロイし、injectノード横のボタンをクリックして、リクエストを実行しましょう。デバッグウィンドウに以下のようにintentsの項目が出てきたら成功です。

Image in a image block
2.3. 入力した文字列のインテント推定を行うWebアプリケーションを作る

これまでの演習の集大成として、入力した文字列のインテント推定を行うWebアプリケーションを作成してみましょう。

今回作るフローは大きく分けて、以下の2つです。

  • /nluにGETすると、解析するテキストを入力して、解析結果を表示するhtmlを返すフロー(下記図、上のフロー)
  • /nluにPOSTすると、botpressと通信して、intentsをJSONとして返すフロー(上記図、下のフロー)
Image in a image block

GETのフロー:

GETのフローは以下の通りです。

Image in a image block
各ノードの設定
  • http in ノード:
    • メソッド:GET
    • URL: /nlu
  • template ノード:
    • テンプレート:
    <!DOCTYPE html>
    <html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>自然言語理解(NLU)</title>
        <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
    </head>
    <body>
        <div class="container mt-5">
            <form id="textForm">
                <div class="form-group">
                    <label for="inputText">解析する文章:</label>
                    <input type="text" class="form-control" id="inputText" name="text" required>
                    <div class="invalid-feedback">解析する文章を入力してください。</div>
                </div>
                <button type="submit" class="btn btn-primary">解析</button>
            </form>
    
            <!-- ここに動的にテーブルを追加します -->
            <div id="tableContainer" class="mt-5"></div>        
        </div>
    
        <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
        <script>
            $(document).ready(function() {
                $('#textForm').submit(function(e) {
                    e.preventDefault();
                    
                    var text = $('#inputText').val();
                    
                    if (!text.trim()) {
                        $('#inputText').addClass('is-invalid');
                        return;
                    } else {
                        $('#inputText').removeClass('is-invalid');
                    }
    
                    $.ajax({
                        type: 'POST',
                        url: '/nlu', 
                        data: JSON.stringify({ inputText: text }),
                        contentType: 'application/json; charset=utf-8',
                        dataType: 'json',
                        success: function(data) {
                            console.log('Success:', data);
                            renderTable(data);
                        },
                        error: function(error) {
                            console.log('Error:', error);
                        }
                    });
                });
                
                $('#inputText').on('input', function() {
                    $(this).removeClass('is-invalid');
                });
    
                function renderTable(data) {
                    var table = $('<table class="table"></table>');
                    var thead = $('<thead><tr><th>Intent</th><th>Confidence</th></tr></thead>');
                    var tbody = $('<tbody></tbody>');
                    
                    data.forEach(function(row) {
                        var tr = $('<tr></tr>');
                        tr.append('<td>' + row.name + '</td>');
                        tr.append('<td>' + row.confidence + '</td>');
                        tbody.append(tr);
                    });
                    
                    table.append(thead);
                    table.append(tbody);
                    $('#tableContainer').html(table);
                }            
            });
        </script>
    </body>
    </html>
  • http response ノード:ただ置くだけ

POSTのフロー:

POSTのフローは以下の通りです。

Image in a image block
各ノードの設定
  • http in ノード:
    • メソッド:POST
    • URL: /nlu
  • function ノード:
    • 名前:Botへの入力
    • コード:
    msg.payload = {
        "type": "text",
        "text": msg.req.body.inputText,
        "includeContexts": ["global"]
    };
    
    return msg;
  • http request ノード:課題2.2の「POST Converse API」をコピーしてきましょう
  • change ノード
    • 名前:レスポンスの整形
    • ルール
      • 値の代入:msg.payload
        • 代入する値: msg.payload.nlu.intents
  • http response ノード:ただ置くだけ

結果の確認:

全てのフローの設定が終わったら、デプロイして、以下のURLにアクセスしてみましょう。

解析する入力に、NLUで登録した文字列を入れ解析ボタンを押すと、以下のような結果が得られるでしょう。

Image in a image block

2.4. 課題提出

Google Classroomに第三回の課題が公開されていますので、これまでやってきた課題の結果についてスナップショットを撮って、提出しましょう。

  • 課題1のスナップショット
    • エミュレータでの会話とSummaryでのインテントの推定結果が入るようにスナップショットを撮って、アップロードしてください
  • 課題2.1のスナップショット
    • 作成したフローと、デバッグの出力結果(JWTトークン)が見えるようにスナップショットを撮って、アップロードしてください
  • 課題2.2のスナップショット
    • 作成したフローと、デバッグの出力結果(JSON出力の中のインテントの推定結果)が見えるようにスナップショットを撮って、アップロードしてください
  • 課題2.3のスナップショット
    • 作成したサイトで解析するテキストを入れた上で、インテントの推定結果が見えるようにスナップショットを撮って、アップロードしてください
  • 最後に
    • 対話フローの中で、インテントの推定、およびエンティティの抽出がどのように役立つのかを考えて考察してください

参考文献