はじめに
前回 Google Home と Twitter をiftttで連携させてツイートしました。
しかし様々な課題が出たのでなんとか解決してみます。
問題を整理すると次のようなことでした。
- 喋り損ねた際にそのまま送信される
- メッセージに謎のスペース
- 短いメッセージしか認識してくれない
原因は Google Home からコマンドするとノンストップでアウトプットされることにありそうです。
一度どこかにメッセージを貯めて確認できるようにした後スクリプトなどで調整して送信すれば良いのではないかと思います。二段階出力となるのでひとつのメッセージで2回コマンドしなければなりませんが そこは仕方ないとします。メッセージの保管は ifttt対応しているサービスならどこでも良いです。
Google 製品だから Google のサービスで統一し誰ってことで Google スプレッドシートを選ぶことにしました。
構成
Google Home とifttt を利用します。
どちらも前回体験済みなのですでに一通りの初期設定は済ませてあります。
Google Home から利用するのが前提なので ifttt アプレットで this 側には Google アシスタントを選びます。
Google Sheets は ifttt の that にも対応しています。
特定のシートに対してセルを編集する機能と行を追加する機能のどちらかを選べます。
これらを組み合わせて次の二つの機能実現します 。
- 受け取ったメッセージをスプレッドシートに貯める
- スプレッドシートのメッセージを Twitter にポストする
ネックとなるのが Twitter へのポスト処理です。iftttではひとつのコマンドに対して一つの処理しかできません。シートのメッセージを読み取りそれを Twitter にポストするような複雑な処理はできません。幸いにも Google の web アプリケーションはgas(Google Apps Script)が使えます 。Excel VBA に似た感触でシートを処理できますからデータの読み取りと出力を同時に行うことも可能です。しかも嬉しいことにRest api クライアント用のライブラリも用意されており さらに Twitter を利用するためのサンプルもあちこちで公開されています。
この記事を参考にしてコピペするだけの簡単な作業ですね。
Google Apps Script で Twitter を使ってみる
まとめますと次の三つの仕組みで構成されることになります 。
- 会話を文章化するアプレット
- 文章をポストするスクリプト
- スクリプトを実行するトリガーをファイヤーするためのアプレット
実装
会話の文章化 「メモして」でスプレッドシートにメッセージを追加する
Google Home が拾った会話をiftttを使ってGoogle アシスタントから Google スプレッドシートに流し込みます。
事前準備に新規のスプレッドシートを作成します。 今回はGoogle ドライブからマイドライブに Google というフォルダを作成してそこに memo という名前のシートを作成します。 シート名を messages としておきます。 このシートのセルにメッセージを保管します。
this にGoogle assistant を選択してChoose TRIGGER では Say a phrase with a text ingredient を選びます。
入力フォームには次のように答えます 。
What do you want to say?
メモして $
What do you want the Assistant to say in response?
$ とメモしました
Language
Japanese
that に Google Sheet そして Add row to spreadsheetを選択して次のように答えます 。
Spreadsheet name
memo
Formatted row
{{CreatedAt}}|||{{TextField}}
Drive folder path (optional)
Google/
最後にappletの名前を入力します。
これで [Ok Google メモして Twitter でポストしたい]とコマンドすればスプレッドシートmemoの B 列にメッセージ[Twitter でポストしたい]が追加されます。
A 列が空っぽなのはご愛嬌。 Formatted row のデフォルト設定で CreatedAt が指定されているので コマンド日時が入ることを期待していたのですが実際には入りません。 それには一工夫必要なようです。
まあともあれこれでメッセージは B 列に蓄えられます。
音声認識されたメッセージは レスポンスとして Google ホームがおうむ返してくれるのできちんと確認できます。 メッセージは行方向に追加されていきます。
文章のポスト 「メモをツイート」で投稿
iftttアプレット作成
とりあえずアプレットを作成してみましょう 。
this にGoogle assistant を選択してChoose TRIGGER では Say a simple phrase を選びます。
入力フォームには次のように答えます 。
What do you want to say?
メモをツイート
What do you want the Assistant to say in response?
メモをツイートしました
Language
Japanese
that に Google Sheet そして Add row to spreadsheetを選択して次のように答えます 。
Spreadsheet name
tweet memo
Formatted row
{{CreatedAt}}|||ツイートしました
Drive folder path (optional)
Google/
Applet 名に 「メモをツイート」で投稿 で Finish。
これで [Ok Google メモをツイート]とコマンドすればスプレッドシートtweet memoの B 列にメッセージが追加されます。
スクリプトのトリガー
まだスクリプトすら書いていませんが, 今のままではたとえ書いたとしても シートにツイートした旨のメッセージが追加されていくだけで何の処理も起動されません。 トリガーを設定して関数を呼び出す形にしなければなりません。
スプレッドシートは次の三つの条件で TRIGGER イベントを発生させます。
スクリプトの関数を起動させることができます。
- シートを編集した時
- セルを編集した時
- 一定間隔で定期的に
楽なのはタイマー駆動なんですが用もないのに実行したくありませんね 。 シートに行を追加したきっかけでスクリプトを実行するのが良さそうです。 gasではスクリプト内にイベントに関わる特定の関数名が定義されている場合, その関数を実行します。 今回の場合 onChange / onEvent が編集時にトリガーされる関数名です。
Twitter に送信する仕組みを実現するためのシートtweet memoを新規に作成してそちらにスクリプトを書けばできるんじゃないでしょうか
memo のmessages シートの B 列から テキストを取得して送信すれば良いでしょう。
ポスト処理
Google Apps Script で Twitter を使ってみる
文章の調整
- Google Home が音声認識して変換した文字列は半角スペースによって分かち書きされているのでそのまま投稿すると精神的にやばい人に見えます。
- スクリプトでいらない文字は削除してしまいましょう。
- Google Home では句読点をつけられないので行松に句点をつければより読みやすいでしょう。
- Twitter 送信に特化するつもりなのでひとつのツイートを140文字以内に治るように結合してしまいます 。
大雑把に組んでみましたがこんな感じです。 大変あれなコードですが動けばまあいいでしょう。
// ツイートしたいメッセージを記入するシートをゲットする
function getSheet() {
try {
var ss = SpreadsheetApp.openById(SHEET_ID);
return ss.getSheetByName("messages");
} catch(e) {
Logger.log("Bad id");
}
return null;
}
// シートの B 列に記入された全ての文字列を配列にして返す
function getMessages(sheet) {
var rows = sheet.getLastRow();
if (rows < 1) {
return [];
} else {
var values = sheet.getRange(1,2,rows).getValues();
var messages = [];
for (var row = 0; row < values.length; row++) {
messages.push(values[row][0]);
// Logger.log(messages[messages.length-1]);
}
return messages;
}
}
// 配列で受け取った文字列内の余分なスペースを取り除く
function strippedMessages(messages) {
return messages.map(function (value, index, array) { return value.replace(/\s+/g, "")});
}
// 配列で受け取った文字列に句点を加えながら140文字を超えないように結合していく
function joinMessages(messages) {
var res = [];
var msg = "";
for each (var item in messages) {
var work = msg + item + "。";
// Logger.log(work.length);
if (work.length > 140) {
res.push(msg);
var msg = "";
msg = item;
} else {
msg = work;
}
}
res.push(msg);
return res;
}
がしかし期待したようには動いてくれませんで。
ドキュメントを見るとスクリプトから編集した場合イベントが発生しないことがあるとあるのでこの方法ではトリガーにできないのかもしれませんね。 もう疲れたので 後日再挑戦することにします 。
そして後日
Web アプリケーションとして公開して Web フックから叩く方式で実現しました。