BOTが研究室のある八王子の天気を教えてくれます(API.AIにおける独自webサービスとの連携(その2.外部サービス連携)

運用している研究室BOTに「天気」と尋ねると八王子の現在の天気を教えてくれるようにしてみました。

結論から言うと、その1で行ったようなGoogle Apps Scriptだけでは実現できなかったのでいわば中継器となるnode.jsを使ったサービスを挟み込んでいます。

API.AIのFulfillmentはPOSTで外部サービスを呼び出しますが、調べた限りではGoogle Apps ScriptのdoPostはこれを正しく返信できません。受信はできるので、その1のような返信不要のサービスの場合には問題がなかっただけでした。また、callbackするようなAPIならば問題にならないのですが…。

この問題を回避するため、実質的にProxyとなるような外部サービスを構築することにしました。いわばPOST/GETを変換するようなものです。世の中にはそういったWebサービスがあるんじゃないかと思うのですが、現時点では見つけられていません。

node.jsによる中継サービス

GAS側での処理を簡潔にするため、intentNameとresolvedQueryだけを転送しています。まるごと転送してしまうという手段もあると思います。

'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const request = require('sync-request');

const gasUrl = '!!! google apps scriptで公開したURL !!!';

const restService = express();
restService.use(bodyParser.json());

restService.use('/hook', function (req, res) {
    try {
        var path = gasUrl+'?intentName='+encodeURIComponent(requestBody.result.metadata.intentName)+'&resolvedQuery='+encodeURIComponent(requestBody.result.resolvedQuery);
        var response = request('GET', path);
        var res2 = JSON.parse(response.getBody('utf8'));

        return res.json({
            speech: res2,
            displayText: res2,
            source: 'apiai-webhook-gas'
        });
    } catch (err) {
        return res.status(400).json({
            status: {
                code: 400,
                errorType: err.message
            }
       });
    }
});

restService.listen((3010), function () {
    console.log("Server listening");
});

 

GAS側の処理

基本的にその1と同じ構造です。ここではOpenWeatherMapを用いましたが、その他のWebサービスでも同じです。

以下のような処理を実装し、その1のコード内で分岐させます。

function getWeather() {
  var weatherS = '';
  try {
    var url = "http://api.openweathermap.org/data/2.5/weather?q=Hachioji,jp&units=metric&appid=!!! 取得したAPIキー !!!";
    result = UrlFetchApp.fetch(url);
    var retw = result.getContentText();
    var retjson = JSON.parse(retw);
    
    for (var i in retjson.weather) {
      // weatherS += retjson.weather[i].main + ' ';
      if (i != 0) {
        weatherS += ' / ';
      }
      weatherS += description[retjson.weather[i].id];
    }
    weatherS += " / 気温:" + retjson.main.temp + "度";
    Logger.log(weatherS);
  } catch (exm) {
    Logger.log(exm);
  }
  
  return weatherS;
}

コードには記載していませんが、

var description = {};

description[200] = '...';

のようにIDと天気説明を置き換える配列が必要です。

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です