4
8

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 5 years have passed since last update.

LaravelでWatson Assistantを使おう

Last updated at Posted at 2018-09-26

「もっと簡単に」呼び出せるようにパッケージ化しました。
詳細はこちら

Watson Assisantとは

会話系のインターフェースを提供してくれるIBMのサービスです。

とりあえずデモ

こんな感じで動かしていきます。
demo.gif

※デモ内ではWatson AssistantとIBM Cloud Function(ICF)を連携させて、天気予報を取得しています。
Watson AssistantとICFの連携については別記事で書こうと思います。

システム概要

概要.png

Watson AssistantをWebアプリケーションでどうやって使うか。

WatsonのサービスはREST APIで簡単に利用することが出来ます。

以前の記事ではNode.jsでWatson Assistantとの連携をしましたが、
今回はLaravelGuzzleを使ってWebアプリケーションとWatson Assistantを連携する方法について
書きたいと思います。

Watson AssistantのCall処理

<?php
namespace App\Services;

use GuzzleHttp\Client;

class CallWatsonAssistant{
    /**
     * Watson Assistantを呼び出すモジュール
     *
     * @param string $spokenWord ユーザーが入力した文字列
     * @param array $context watson assistantのcontextデータ
     * @return json Watson AssistantをCallした結果
     */
    public function call(string $spokenWord,array $context)
    {
        if(count($context)>0){
             //以前から継続されている会話の場合
            $requestData  = json_encode(['input'=>['text'=>$spokenWord],'context'=>$context]);
        }else{
            $requestData  = json_encode(['input'=>['text'=>$spokenWord]]);
        }
        $headers = ['Content-Type' => 'application/json','Content-Length' => strlen($requestData)];
        $curlOpts = [
            CURLOPT_USERPWD        => config('watson.user_name').':'.config('watson.password'),
            CURLOPT_POSTFIELDS     => $requestData,
        ];
        $guzzleClient = new Client(['base_uri'=>'https://gateway-fra.watsonplatform.net/assistant/api/v1/workspaces/']);
        $path         = config('watson.workspace_id') . '/message?version=2018-07-10';
        return $guzzleClient->request('POST',$path,['headers'=> $headers,'curl'=>$curlOpts])->getBody()->getContents();
    }
}

Guzzleを使う事で、curlを使うよりも簡潔にWatson Assistantを呼び出すことが出来ます。

envファイルに定義を追加する

セキュリティの観点より、APIをCallする為のユーザー名やパスワード、workspace_idについては、
envファイルに書くと良いと思います。

WATSON_WORKSPACEID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
WATSON_USER_NAME=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
WATSON_PASSWORD=XXXXXXXXXXXX

configファイル(watson.php)を作成する。

私はconfigフォルダ直下にwatson.phpというファイルを作っています。
これにより、呼び出すときの処理でconfig('watson.workspace_id')という書き方が出来るようになります。

<?php

return [
    /*
    |--------------------------------------------------------------------------
    | Default Workspace ID
    |--------------------------------------------------------------------------
    | IBM CloudでのWORKSPACE IDを指定します。
    */
    'workspace_id' => env('WATSON_WORKSPACEID'),
    /*
    |--------------------------------------------------------------------------
    | Default UserName/Password
    |--------------------------------------------------------------------------
    | IBM Cloudで取得したサービス資格情報を指定します。
    */
    'user_name'   => env('WATSON_USER_NAME'),
    'password'    => env('WATSON_PASSWORD')];

Controllerに記述する

上記で作成したWatson Assistant呼び出し処理をインジェクションして使っています。
Watson Assistantでは、ユーザーと連続した会話を成立させるために、APIのパラメータに
contextを持たせる必要があるので、これはsessionに格納しています。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Services\CallWatsonAssistant;

class WatsonCallController extends Controller
{
    /**
     * セッションを初期化し、初期画面を表示する。

     * @param Request $request
     * @return response 入力初期画面
     */
    public function index(Request $request)
    {
        $request->session()->flush();
        return view("talkWatson");
    }
    /**
     * WatsonAssistantを呼び出してjson形式で返却する。
     * 継続した会話を実現する為、contextはセッションに保管しておく
     *
     * @param Request リクエストデータ
     * @param CallWatsonAssistant WatsonAssistant呼び出しモジュール
     * @return json Watson Assistantからの受信データ
     */
    public function talkToWatson(Request $request,CallWatsonAssistant $CWA)
    {   
        $response      = $CWA->call($request->spokenword,session('context')?session('context'):[]);
        $responseArray = json_decode($response,true);   
        $request->session()->put('context',$responseArray['context']);
        return $response;
    }
}

ルーティングを定義する

web.php

Route::get('/', 'WatsonCallController@index')->name('index');

api.php

Route::post('talk_to_watson','WatsonCallController@talkToWatson')->name('talk_to_watson');

上記の処理ではWeb画面の表示とAPIの定義を同じControllerに書いていますが、
本来は分けた方が良いと思います。

サンプルView

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-6">
            <input type="text" id="message_to_watson" placeholder="何か入れて下さい" class="form-control"/>
        </div>
        <div class="col-md-2">
            <input type="button" id="send_message" value="聞いてみる" class="btn btn-primary"/>        
        </div>
    </div>
    <div class="row">
        <div class="col-md-6">
            <label>ユーザー入力</label>
            <ul id="input"></ul>
        </div>
        <div class="col-md-6">
            <label>Watsonからの返答</label>
            <ul id="responseFromWatson"></ul>
        </div>    
    </div>
</div>
@endsection

@section('script')
<script>
    $("#send_message").click(function(){
        $('#input').append('<li>'+$("#message_to_watson").val()+'</li>')
        $('#responseFromWatson').append('<li>'+'Watson is thinking...'+'</li>')
        $.ajax({
            type: "POST",
            url:  "{{route('talk_to_watson')}}",
            data: {spokenword:$("#message_to_watson").val()},
            dataType: 'json'
        }).done(function(response){
            for (var i = 0, len = response.output.text.length; i < len; i++) {
                if(response.output.text[i] !== ''){ 
                    $('#responseFromWatson li:last-child').text(response.output.text[i]);
                }
            }
        }).fail(function(){
            alert(errorHandler(arguments));
        });
    });
</script>
@endsection

これで、上記のデモ画面まで表示する事が出来ると思います。
こちらの方法でも簡単にChat bot等の実装が出来そうですね。

4
8
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
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?