CData Software Blog

クラウド連携のCData Software の技術ブログです。

GoQSmile でオンプレミスの在庫情報を検索するチャットボットを構築:CData API Server・SQL Server 連携

https://cdatajbuilds.s3-ap-northeast-1.amazonaws.com/CDataBlog/GoQSmile2.gif

こんにちは。CData Software Japanリードエンジニアの杉本です。

今回は GoQSmile というノーコードでAIチャットボットを構成できるクラウドサービスとCData API Serverを連携してみました。

GoQSmile とは?

GoQSmile UI上で応答や処理内容、応答するための同義語の辞書(エンティティ)の設定するだけで、手軽にAIチャットボットが作成できるクラウドサービスです。

https://goqsmile.com/

f:id:sugimomoto:20200719231523p:plain

また、外部サービスと連携するためのAPIコール機能も提供されており、今回はこのAPIコール機能を組み合わせてチャットボットを作成してみました。

https://goqsmile.com/manual/state_setting_api/

f:id:sugimomoto:20200719231531p:plain

今回やってみたこと

CData では、各種RDBやNoSQLから自動的にREST Ful API を生成することができる、CData API Server という製品を提供しています。

https://www.cdata.com/jp/apiserver/

f:id:sugimomoto:20200719231537p:plain

通常、RDBクラウドサービスからコールしたい場合は、インターフェースとなるAPIを自身で作成する必要がありますが、API Serverを利用することで簡単にRDBExcelCSVに接続できるAPIを生成することが可能です。

また、オンプレミスに配置された既存のRDBや基幹システムも、クラウドゲートウェイの機能を利用することで、クラウドサービスであるGoQSmileをセキュアに組み合わせてチャットボットを構成することができます。

今回はオンプレミスに配置したSQL Serverに対して接続し、サンプルデータベースとして有名なAdventureWorksのデータを元に在庫情報を検索するチャットボットを構成してみました。

f:id:sugimomoto:20200719231544p:plain

手順

それでは実際の手順を紹介します。

必要なもの

API Server による環境構成

まずAPI Serverの環境を構築し、SQL ServerからREST APIを生成します。

以下のURLからAPI Serverのトライアルが取得できるので、対象の環境にダウンロードして、セットアップします。

https://www.cdata.com/jp/apiserver/

f:id:sugimomoto:20200719231550p:plain

なお今回、CData API Serverはオンプレミスにインストールし、オンプレミスのSQL ServerとつないでAPIを生成しています。

クラウド側にAPIを公開するための方法として、Cloud Gatewayの機能を使用しました。

環境構築に関しては以下のBlogを参考にしてみてください。

www.cdatablog.jp

もしクラウド上で環境構成を行う場合は、この手順を省いて構いません。

API Server の環境を構成したら、SQL Serverと接続します。

SQL Serverには予めサンプルデータベースとして、AdventureWorks2014を構成しています。このデータベースの「Product」「ProductInventory」を今回は使用します。

f:id:sugimomoto:20200719231557p:plain

それでは接続を構成していきましょう。

API Serverの管理画面にログインし「設定」→「接続」で、接続先サービスの一覧から「SQL Server」を選択します。

f:id:sugimomoto:20200719231602p:plain

SQL ServerにアクセスするためのServerアドレスやID・PWを指定して、接続を行います。今回はLocalhost接続で、以下のように入力しました。

f:id:sugimomoto:20200719231608p:plain

接続テストを行い、問題なければ、設定を保存します。

対象のエンドポイントを追加する

次に今回利用するエンドポイントを新しく追加します。

「設定」→「リソース」タブに移動し「新しいリソースを追加」をクリックします。

f:id:sugimomoto:20200719231614p:plain

予め作成しておいた「SQL Server」のコネクションを選択して、次へ移動し

f:id:sugimomoto:20200719231620p:plain

「Product」「ProductInventory」等を追加します。

f:id:sugimomoto:20200719231625p:plain

下記のようにリソースが追加されていればOKです。

f:id:sugimomoto:20200719231630p:plain

あとは接続の時に利用するユーザーも登録しておきます。生成されたトークンを後で利用するので、控えておきましょう。

f:id:sugimomoto:20200719231636p:plain

構成されたAPIエンドポイントを確認してみます。「API」タブに移動すると、追加したリソースが表示されています。ここでリクエスト方法などを確認できます。

f:id:sugimomoto:20200719231644p:plain

試しにURLをクリックしてみると、以下のようなJSONを取得できました。

f:id:sugimomoto:20200719231650p:plain

これでGoQSmileがアクセスするAPIの構成は完了です。

上記画像はLocalhostになっていますが、実際にはEC2経由でアクセスする形になります。

GoQSmile のシナリオ構成

続いてGoQSmileでチャットボットを構成していきます。

今回構成するチャットボットの全体的な手順は以下のような流れになります。

  • アクション:メニューを表示:menu1
  • アクション:在庫情報検索のステートを呼び出し:CallZaicoState
  • ステート:フォーム穴埋めタイプ:製品名を入力:InputProductName
  • ステート:API送信タイプ:製品名の検索を実行:SearchProductsByProductName
  • ステート:フォーム穴埋めタイプ:検索結果を選択肢として表示:InputProductId
  • ステート:API送信タイプ:在庫情報を検索して、結果を表示:SearchInventoryByProductId

実際に構成したチャットボットは以下のようになります。

アプリケーションの作成

まず最初にチャットボットの一つの単位である「アプリケーション」を作成します。

GoQSmileの管理画面から「アプリケーション新規作成」をクリックし、以下の情報を入力します。

  • アプリケーション名:任意のアプリケーション名を入力します。(例:CDataAPIServerIntegration
  • アプリケーションタイプ:チャットボットのアプリケーションタイプを指定。今回は「Web API」を指定しました。
  • ウェブサイトへチャットボットを設置しますか?:「設置する」にチェックを入れました。今回はDemoサイトで検証を行っています。
  • チャットボットを設置するドメイン:任意のドメインを指定します。
  • 応答用イメージ:チャットボットの応答時の画像を指定します。任意のものをアップロードして、指定してください。
  • ヘッダータイトル:チャットボットが返信する際のタイトルに使用されます。今回は「サポート」としました。

なお、今回はテンプレートを使用せず、1から作成しています。

f:id:sugimomoto:20200719231736p:plain

メニューの調整

アプリケーションを作成したら、一番最初に表示されるメニューを調整しましょう。「アクション一覧」→「menu1」に移動し

f:id:sugimomoto:20200719231743p:plain

「このアクションに対する応答文」から応答文を編集します。

f:id:sugimomoto:20200719231749p:plain

以下のように応答文を指定しました。選択肢は複数出していますが、今回実装するのは「在庫情報検索」のみです。この「在庫情報検索」が選ばれた際に、対象のシナリオを実行していきます。

  • 応答メッセージ:「以下の選択肢から、実行したい機能を選んでください。」と入力します。
  • 応答選択肢:「在庫情報検索,顧客情報検索,その他」と入力します。

f:id:sugimomoto:20200719231754p:plain

導入アクションの作成:アクション:在庫情報検索のステートを呼び出し:CallZaicoState

次にメニューから「在庫情報検索」がクリックされ、具体的な処理に入っていくためのアクションを定義します。

「アクション新規作成」をクリックし「CallZaicoState」というアクションを作成しました。

f:id:sugimomoto:20200719231803p:plain

このアクションには、「ユーザーが話しかける会話文」として「在庫情報検索」のみ定義しています。

f:id:sugimomoto:20200719231809p:plain

これをトリガーとして、後続のプロセス「ステート」を実行していきます。

ユーザー入力処理の作成:ステート:フォーム穴埋めタイプ:製品名を入力:InputProductName

続いて、ユーザーに製品名を入力させるための処理を作成します。

GoQSmileでは「ステート」という定義で、ユーザーの入力を求めたり、WebAPIをコールしたりすることができるようになっています。

先程のアクションからこの製品名を入力させる本ステートを実行し、その後入力された値を元に、Web APIをコールするという流れです。

f:id:sugimomoto:20200719231816p:plain

「ステート新規作成」をクリックし、以下のようなステートを定義しました。

  • ステート:ステート名を指定します。「InputProductName」としました。
  • ステートタイプ:処理する内容を指定します。ここではユーザーに入力を求めるための「フォーム穴埋めタイプ」とします。
  • タイプ:ステートの開始条件を指定します。先程作成した「アクション」の「CallZaicoState」を指定しました。
  • 次のステート:このステートが完了した後のステートを選択します。後続のステートを作成後に指定します。ここでは「SearchProductsByProductName」を指定しました。

f:id:sugimomoto:20200719231822p:plain

ステートを作成したら、実際にステートの処理内容を定義します。

「フォーム定義」タブから「追加」をクリックし

f:id:sugimomoto:20200719231828p:plain

このステートでユーザーに入力を求めるための内容を以下のように定義します。

  • 項目名:内部に入力結果として保存される際の項目名を指定します。この値を使って、後続のフローでこの値を呼び出すことが可能になります。ここでは「ProductName」と指定しました。
  • 応答メッセージ:ユーザーに入力を求める際のメッセージを指定します。「検索したい対象の製品名を入力してください。部分一致で検索します。」と指定しました。
  • 応答選択肢:ユーザーの入力候補を指定します。今回はフリー入力のため「[no menu]」としました。

f:id:sugimomoto:20200719231834p:plain

製品名を検索するAPI処理の構成:ステート:API送信タイプ:製品名の検索を実行:SearchProductsByProductName

続いて今回の記事の要である、APIリクエストの処理ステートを構成します。前のステートで入力された検索対象の製品名を元にAPIリクエストを実施し、以下のような製品一覧を返します。

f:id:sugimomoto:20200719231839p:plain

「ステート新規作成」をクリックし、以下の内容でステートを作成します。

  • ステート:ステート名を指定します。「SearchProductsByProductName」としました。
  • ステートタイプ:WebAPIのリクエストを実行するので「API呼び出しタイプ」を指定します。
  • タイプ:ステートの開始条件を指定します。今回は先程のステートから呼び出されるので「指定なし」で、対象のステート一覧から「InputProductName」を選択しました。

f:id:sugimomoto:20200719231846p:plain

続いて、「API定義」タブから、実際に送信されるAPIリクエストの内容を定義します。

ここでは製品を検索するために構成したAPI「AdventureWorks2014_Production_Product」のエンドポイントを実行します。

また、取得条件としてNameの項目に対して部分一致の検索を行い、上位5件を取得するので、最終的なリクエストは下記のようなものとなります。

http://XXXXX/api.rsc/AdventureWorks2014_Production_Product?$filter=contains(Name,'A')&$top=5

f:id:sugimomoto:20200719231853p:plain

  • URL:API Serverで構成したURLを指定します。AWS EC2に構成したゲートウェイおよびリソースを指定するので「http://ec2-XXXXX:8387/api.rsc/AdventureWorks2014_Production_Product」のような値になります。
  • HTTPメソッド:「GET」を指定します。
  • HTTPヘッダー:認証に利用するためのヘッダー情報を指定します。キーに「x-cdata-authetoken」を指定し、値としてAPIServerで構成したユーザーのKeyを入力します。
  • パラメータ:製品を取得する際の諸条件を指定します。今回はProductテーブルのNameで部分一致検索を行い、上位5件を取得してきます。
  • パラメータ1:フィルターを行うための指定です。キー:「$filter」、値:「contains(Name,'{{ state.InputProductName.form.ProductName }}')」と指定します。「{{ state.InputProductName.form.ProductName }}」は手前のステートで入力された値を指定しています。
  • パラメータ2:上位N件の取得を指定します。キー:「$top」、値:「5」と入力します。

f:id:sugimomoto:20200719231900p:plain

API定義完了後、リクエストした後の処理も指定しましょう。

後続の処理では、取得した結果を元に、ProductIdをユーザーに指定させ、再度在庫情報を検索しに行きます。

  • 次のステート:「InputProductId」を指定します。(後続のステートを作成してから指定します。)

f:id:sugimomoto:20200719231908p:plain

  • API呼び出し成功時の応答文:以下のようにAPIレスポンスの結果をテーブル形式で表示する応答文を定義しました。
  • APIリクエストに成功しました。製品情報の検索結果上位5件を表示します。
{% for item in state.SearchProductsByProductName.api_response.value %}{% endfor %}
ProductIdName
{{ item.ProductID }}{{ item.Name }}

APIのレスポンスは「state.[StateName].api_response」で取得できます。また、djangoのフォーマットが使えるので、繰り返し文で表示する項目を制御しています。

f:id:sugimomoto:20200719231914p:plain

製品IDの入力を求める選択肢の構成:ステート:フォーム穴埋めタイプ:検索結果を選択肢として表示:InputProductId

前のステートで製品一覧を取得したので、次は製品の絞り込みを行うための選択肢をユーザーに提示します。

f:id:sugimomoto:20200719231920p:plain

フォーム穴埋めタイプで選択肢を表示するので、まず以下のように新しいステートを作成します。

  • ステート:ステート名を指定します。「InputProductId」としました。
  • ステートタイプ:処理する内容を指定します。ここではユーザーに入力を求めるための「フォーム穴埋めタイプ」とします。
  • タイプ:ステートの開始条件を指定します。先程作成した「アクション」の「CallZaicoState」としました。
  • タイプ:ステートの開始条件を指定します。今回は先程のステートから呼び出されるので「指定なし」で、対象のステート一覧から「SearchProductsByProductName」を選択しました。
  • 次のステート:選択した製品IDを元に在庫情報を検索するためのAPI処理のステート「SearchInventoryByProductId」を指定します。

f:id:sugimomoto:20200719231926p:plain

ステートを作成したら、ステートの処理内容を定義します。

「フォーム定義」タブから「追加」をクリックし

f:id:sugimomoto:20200719231938p:plain

このステートでユーザーに入力を求めるための内容を以下のように定義します。

  • 項目名:内部に入力結果として保存される際の項目名を指定します。ここでは「ProductId」と指定しました。
  • 応答メッセージ:ユーザーに入力を求める際のメッセージを指定します。「在庫情報を表示したいProductIdを選択してください。」と指定しました。
  • 応答選択肢:ユーザーの入力候補を指定します。今回は前のステートで取得しているAPIのリクエスト結果を元に選択肢を提示します。
  • 「[no menu]{% for item in state.SearchProductsByProductName.api_response.value %},{{ item.ProductID }}{% endfor %}」と入力しました。

f:id:sugimomoto:20200719231943p:plain

これで、ユーザーに背品IDの候補を提供することができます。

在庫情報の取得結果を表示:ステート:API送信タイプ:在庫情報を検索して、結果を表示:SearchInventoryByProductId

最後のステートを定義します。ここでは前のステートで入力された製品IDを元に、在庫情報をAPI経由で検索して表示してきます。基本的な処理内容は製品情報検索部分と変わりありません。

f:id:sugimomoto:20200719231949p:plain

「ステート新規作成」をクリックし、以下の内容でステートを作成します。

  • ステート:ステート名を指定します。「SearchInventoryByProductId」としました。
  • ステートタイプ:WebAPIのリクエストを実行するので「API呼び出しタイプ」を指定します。
  • タイプ:ステートの開始条件を指定します。今回は先程のステートから呼び出されるので「指定なし」で、対象のステート一覧から「InputProductId」を選択しました。

f:id:sugimomoto:20200719231955p:plain

続いて、「API定義」タブから、実際に送信されるAPIリクエストの内容を定義します。

今回は在庫情報を取得できるエンドポイントである「AdventureWorks2014_Production_ProductInventory」を指定します。

また、取得条件として事前に入力されたIDを元に検索をかけるので最終的なリクエスト内容は以下のようになります。

http://XXXXX/api.rsc/AdventureWorks2014_Production_ProductInventory/?$filter=ProductID eq 1」

f:id:sugimomoto:20200719232003p:plain

  • URL:API Serverで構成したURLを指定します。「http://XXXXX/api.rsc/AdventureWorks2014_Production_ProductInventory」と指定します。
  • HTTPメソッド:「GET」を指定します。
  • HTTPヘッダー:認証に利用するためのヘッダー情報を指定します。キーに「x-cdata-authetoken」を指定し、値としてAPIServerで構成したユーザーのKeyを入力します。
  • パラメータ:製品を取得する際の諸条件を指定します。今回はProductテーブルのNameで部分一致検索を行い、上位5件を取得してきます。
  • パラメータ1:フィルターを行うための指定です。キー:「$filter」、値:「ProductID eq {{ state.InputProductId.form.ProductId}}」と指定します。「{{ state.InputProductId.form.ProductId} }}」は手前のステートで入力された値を指定しています。

f:id:sugimomoto:20200719232008p:plain

あとは「API呼び出し成功時の応答文」を指定すれば完了です。

  • API呼び出し成功時の応答文:以下のようにAPIレスポンスの結果をテーブル形式で表示する応答文を定義しました。
  • 在庫情報の検索結果を表示します。
{% for item in state.SearchInventoryByProductId.api_response.value %}{% endfor %}
ShelfQuantity
{{ item.Shelf }}{{ item.Quantity }}

f:id:sugimomoto:20200719232017p:plain

作成したチャットボットを試す

それでは作成したチャットボットを試してみましょう。

アプリケーションの管理画面から「DEMOページへ」をクリックすると、実際にチャットボットを試すことができます。

f:id:sugimomoto:20200719232022p:plain

以下のようにAPIを経由して応答結果が返ってくればOKです。

f:id:sugimomoto:20200719232030p:plain

今回の手順では一気に書いてしまっていますが、各ステート毎に動作を確かめながら作成していくことがオススメです。

おわりに

少し長くなってしまいましたが、API連携を行うチャットボットが構成できました。

このようにAPI ServerでAPIを公開することで、クラウドサービスから既存のRDBなどがとても使いやすくなります。

今回はSQL Server を対象にしましたが、PostgreSQLMySQLOracleといったデータソースにも対応できます。

https://www.cdata.com/jp/apiserver/#databases

f:id:sugimomoto:20200719232035p:plain

また、SalesforceSharePointなどのクラウドサービスも、部分的にAPI Server経由でAPI公開することができ、通常は複雑なAPIリクエストが必要なクラウドサービスにも手軽にAPIアクセスできるようになります。

f:id:sugimomoto:20200719232042p:plain

ぜひ、いろんなシチュエーションで試してみてください。