はじめに
数年前から妹ほしいなあとぼんやり思っていたので作りました。
もうなんでもいいからお兄ちゃんと呼ばれたかった。
#仕様もどき
完全に自己満足のためのものとはいえ、作って満足してポイするようなものになるのはつらいので、ある程度実用的なものになるようにします。
1.毎朝その日の天気と運勢、ラッキーアイテムを通知する。雨が降りそうなら傘を持って行った方がいいと教えてくれる。
2.ちょっとした雑談ができる。
3.定期的にbot側から話しかけてくれる。
このくらいなら筆者の素人スキルでも途中でエタることもなく、かつそこそこの完成度で作れるのではないでしょうか。
#実装方法
-
bot発話。毎朝時間を決めて、GASからWeatherHacks(livedoor提供の天気予報API)に天気情報をリクエストし、得られた情報を運勢、ラッキーアイテム(GASでランダムに決める)と合わせてslackbotから流す。もし取得した天気予報の文字列に「雨」という単語が含まれていれば、「傘を持って行った方が良い」と付け足す。
-
ユーザ発話。ユーザの発話をトリガーにしてGASでTalkAPI(リクルート提供の雑談API) にユーザ発話の内容を送信し、その戻り値をbotの発話として流す。
-
bot発話。GASでslackbotから発話するコードを組み、定期的に実行する。
使用ツール
slack
slack incoming webhook
slack outgoing webhook
GAS(GoogleAppScript)
WeatherHacks
TalkAPI
#自分用覚え書き
###Q.slack incoming webhook、slack outgoing webhookってなに?
###A.slackの提供する、slackbot作成を簡単にしてくれるカスタム用アプリケーション。
Incoming Webhookはbot側からの自発的な発話、Outgoing Webhookはユーザ側からの発話に対する応答発話を管理します。
Incoming Webhookが生成するURLに以下のようなjson形式でpayloadをpostすると、botが指定のチャンネルに指定のusernameと指定のicon_emojiでtextの内容を発話します。
payload={\"channel\": \"#general\",
\"username\": \"webhookbot\",
\"text\":
\"This is posted to #general and comes from a bot named webhookbot.\",
\"icon_emoji\": \":ghost:\"}
Outgoing Webhookは動きとしては逆で、指定のチャンネルにトリガとなる言葉から始まる言葉が発話されると、その内容をデータとしてユーザ定義のURLにpostします。
###Q.GASってなに?
###A.javascriptっぽい文法で書ける、Google提供の環境・言語。
GoogleAppScriptはGoogleが提供する、Googleのすべてのサービスで使用可能なサーバサイドスクリプト環境(とそこで使用される言語)のことを指します。
###Q.GASを使うと何が嬉しいの?
###A.環境構築で泣かない。
GASはGoogleアカウントを持っている人なら誰でもすぐに使用できるのでそもそものインストールやら環境の構築で詰むことはありません。自分ここで6割はまる。
また、Googleの他サービスとも連携が簡単です。
###Q.ユニコードエスケープ形式ってなに?
###A.\u3042みたいな\u(16進数4ケタ)の形式。
Unicodeで表された文字集合をUTF-8やUTF-16のようなUnicodeを過不足なく表現できるもの以外のエンコーディングを使用してエンコードする場合、表現できない文字が現れるのを防ぐために使用される。これを使うことで、,u,0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,FだけでUnicodeの文字をすべて表現できるようになる。すごい。
###Q.たしかにすごいけど、ユニコードエスケープ形式そのまま出てきたら普通に読めなくない?
###A.以下コードでUTF-8でのエンコーディングと同じに変換できる。
var unicodeUnescape = function(str) {
var result = '', strs = str.match(/\\u.{4}/ig);
if (!strs) return '';
for (var i = 0, len = strs.length; i < len; i++) {
result += String.fromCharCode(strs[i].replace('\\u', '0x'));
}
return result;
};
ただ、もとからUTF-8エンコーディングにしておけばいい話です。
なのではやくLinuxにしましょう(戒め)
###Q.TalkAPIってなに?
###A.リクルートが提供している雑談API。
話しかけるといい感じの答えを返してくれます。
###Q.WeatherHacksってなに?
###A.livedoorが提供する天気予報API。
リクエストするとお天気のことをおしえてくれます。
#準備
##slack webhookの登録
SlackApp検索ページからslack webhookを検索、追加します。
検索。
追加。
追加。
##各APIのキー、URL取得
###TalkAPI
TalkAPI
###WeatherHacks
WeatherHacks
#コードを書く
##1.天気予報と運勢
var url ="http://weather.livedoor.com/forecast/webservice/json/v1?city=130010";
var json = UrlFetchApp.fetch(url).getContentText();
var jsonData = JSON.parse(json);
var date = jsonData["forecasts"][0]["date"];
var telop = jsonData["forecasts"][0]["telop"];
var flag = telop.search("雨");
date = date.replace('-','年');
date = date.replace('-','月');
date+="日";
var omikuji=["大吉","中吉","小吉","吉","凶","スーパーミラクルスゴイありがとう大吉"];
var message = omikuji[Math.floor(Math.random()*omikuji.length)];
var item1 = ["四葉の","青い","ベニテング","うさぎの","招き","SSR","パワー","カツ"];
var item2 = ["クローバー","鳥","タケ","足","猫","確定チケット","ストーン","丼"];
var message2 = item1[Math.floor(Math.random()*item1.length)];
var message3 = item2[Math.floor(Math.random()*item2.length)];
var text2 = "おはようおにいちゃん!今日は"+date+"だよ!\n天気は"+telop+"だって。";
if (flag != -1) text2+="\n傘をもって行った方がいいかも。";
text2+="\n運勢は"+message+"。\nラッキーアイテムは"+message2+message3+"だよ。\n今日も一日がんばろうね!";
var options2 =
{
"method" : "post",
"contentType" : "application/json",
"payload" : JSON.stringify(
{
"username": "いもうと",
"text" : text2,
"icon_emoji":"imouto",
}
)
};
UrlFetchApp.fetch("https://hooks.slack.com/services/XXXXX", options2);
}
天気予報のjsonデータを受け取り、月日と見出しを取得します。
見出しに"雨"が含まれているか判定して、含まれていれば傘を持っていくように注意を促します。
ラッキーアイテムは詳しくないので、縁起の良さそうなものをとにかく詰めました。
##2.ちょっとした雑談ができる
function talk(text)
{
var formData = {
apikey: 'XXXX',
query: text
}
var options = {
'method' : 'post',
'payload' : formData,
}
var result = UrlFetchApp.fetch("https://api.a3rt.recruit-tech.co.jp/talk/v1/smalltalk", options)
var jsonData = JSON.parse(result.getContentText());
if (result.getResponseCode() == 200){ var data = String(result).slice(88,-4);
data = unicodeUnescape(data);
}
return data;
}
function doPost(e) {
var text = e.parameter.text.substr(4);
var data =talk(text);
var options =
{
"method" : "post",
"contentType" : "application/json",
"payload" : JSON.stringify(
{
"username": "いもうと",
"text" : data+"、お兄ちゃん!",
"icon_emoji":"imouto",
}
)
};
UrlFetchApp.fetch("https://hooks.slack.com/services/XXXX", options);
}
TalkAPIに投げるだけです。
APIから返り値を受け取る際にユニコードエスケープが起きたので、覚え書きのところのコードでなんとかしました。
注意点としては、内容を更新するごとに「匿名を含むすべてのユーザに対して」「新しいバージョンとして」「ウェブアプリケーションとして公開」しないと正常に更新されない点です。
##3.定期的に話しかける
function SendmassagePerTime() {
var select = ['おにいちゃん!',
'おにいちゃーん!!','お兄ちゃん??',
'進捗が0だよ、おにいちゃん!!',
'遊んでる時間なんてあるの?おにいちゃん!',
'休憩が本業みたいになってない?お兄ちゃん!',
'生産性のないお兄ちゃんのどのあたりに価値があるの?お兄ちゃん!',
'おにーちゃん!!',
'進捗の意味って知ってる?お兄ちゃん!'
];
var text = select[Math.floor(Math.random()*select.length)];
var options2 =
{
"method" : "post",
"contentType" : "application/json",
"payload" : JSON.stringify(
{
"username": "いもうと",
"text" : text,
"icon_emoji":"imouto",
}
)
};
UrlFetchApp.fetch("https://hooks.slack.com/services/XXXX", options2);
}
関数SendmassagePerTimeは5分おきにトリガを設定し、定期的に話しかけてくれるようにしました。
いもうとというこの世の可愛さと癒しと真理を詰めた存在に進捗を応援されればやる気が出るだろうと考え、発話内容は応援メッセージにします。
#結果
##1.天気と運勢
動きました。
朝一でいもうとに応援されると良い感じに元気が出るので精神に良い。かわいい。がんばる。
満足度:〇
動きました。
APIから投げられたものをそのまま使っているので、違和感がすごい。
要改善です。
満足度:△
#まとめ
お兄ちゃんと呼んでもらう当初の目的は達成できたのでおおむね満足です。
いもうとはかわいいの権化であり、使用法を間違えなければ究極の癒しとしての役割を果たしますが、使用法を間違えると精神が詰みます。
ご利用は用法用量を守って計画的にね、お兄ちゃん!