28
15

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

【LINEBOT】で家計簿アプリを作りながら遠くに住む姪に想いを馳せた(ソーシャルディスタンスを保ち、十分な感染症対策を行った上で)話【GAS】

Last updated at Posted at 2020-07-22

大卒後、フリーター経験8年その後エンジニア転職を果たしたニガウリと申します。
エンジニアとしての視野と領域を広げるため、また初心に帰るべく日本初のプロトタイピング専門スクールであるプロトアウトスタジオに入学して勉強の毎日を送ってます。
という自己紹介を前回投稿した記事に書くべきでしたがそこまで意識が向いていませんでした。

カリュキュラムの一環として課題に対して企画→制作→発表までを自身で行うのですが今回の課題はLINEBOTでした。

#なぜLINEなのか

端的に圧倒的なユーザ数と幅広い年齢層が使っているから。
新規にアプリをインストールするよりBOTを友達に追加するだけでアプリが使用できるという利便性が大きなアドバンテージだと言えます。

以下のページの通り__月間アクティブユーザー数:8,400万人以上__とのことです。
2020年5月更新! 12のソーシャルメディア最新動向データまとめ
その8,400万人の中には私はもちろん、70歳近い私の父親も、小学2年生の私の姪も含まれています。

#なにを作ったか
家計簿管理アプリを作りました。
当初はSongsterrのWebAPIを使用してギターのコードを取得して練習に役立てるアプリを企画しましたが、
自分が一番感心ある分野の企画をアウトプットに慣れていない状態で始めてしまうと
今後も音楽というジャンルに発想が縛られそうな気がしたことと、
LINEのように幅広いものを使うのならもっと汎用的なものを作った方が良いと思い企画を変更しました。

先人の方々が素敵なUIUXをのものを作っていらしたので差別化のために何か自分なりのアイデアを組み込めないかを考えました。
【2018年 LINE Bot 作り方】GASで支出管理Botを作ってみた
LINE Botで家計簿Botを作りました
LINE massaging APIで家計簿と買い物リスト作ってみた
なので、小学2年生の私の姪でも使えるようなものに出来たら良いんじゃないかと思いました。

#最初の目標
###対話型であること
当初の構想はSiriとコミュニケーションをする感じで対話を通して支出を記録できたらいいなと思いました。

BOT:何を買ったの?
ユーザー:おにぎり
BOT:どこで買ったの?
ユーザー:ロー○ン
BOT:いくらだったの?
ユーザー:38円
ローソン おにぎり 38円
記録したよ!

こんな動きを理想としていました。

###保護者がやりとりを管理できること
保護者が支出管理の様子を確認できるようにすることで子供のマネーリテラシーを養いコミュニケーションを促せるようにしたいと思いました。

構想としてLINEBOTで送られたデータをSpreadsheetなどで保護者が管理できる仕組みを作り、貯金ができたら褒めてあげる、赤字が出たら注意するようなやりとりが生まれるのが最高ですね。

#さてどうなったか
98d5338f8b80970032b52cbd754a852a-1.gif

ご覧のとおり初期段階では対話型の実装はできませんでした。

対話型の実装に関しては同じプロトアウトスタジオで学んでいらっしゃる@tatsuya1970さんが作成されたBOTがかなり理想に近かったのですが、私の理解力が足りず、うまくできませんでした

「LINE Messaging API + Googleスプレッドシート + 猫画像API」による1問1答ではないチャットボットを作りました

@tatsuya1970さんが制作されたBOTですが、すごく素敵です。
###猫可愛いです。
友達登録推奨です。

##開発環境
LINEBOT
GAS
授業の本筋であるnode.jsを使いたかったのですが、node.jsとGoggleの認証がうまくできず、
BOTからのメッセージを受け取ってSpreadSheetに記入するという一番ミニマムな実装が
できた時点でGASでゴリゴリ書く方向に変えました。

#実装

すごくシンプルにGASのdoPost関数でBOTからのメッセージを受け取り、文言によって閲覧と記録の処理をわけてSpreadsheetとLINEにそれぞれ返す仕組みになります。

linebot.js
var global;
var ACCESS_TOKEN = ' ';
var id = ' ';
var dataSheet = SpreadsheetApp.openById(id).getSheetByName('7月');
var url = 'https://api.line.me/v2/bot/message/reply';
function doPost(e) {
  // WebHookで受信した応答用Token
  var replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
  // ユーザーのメッセージを取得
  var userMessage = JSON.parse(e.postData.contents).events[0].message.text;
  var data = JSON.parse(e.postData.contents).events[0];
  var result;
  // 家計簿閲覧モード
  if (userMessage.match(/家計簿/)) {
    // シートの内容を取得するメソッド
    result = showSpreadSheet();             
  } else {
   // 家計簿記録モード
    result = insertToSpreadSheet(data);
  }
    //取得内容をreplyに渡す
    reply(data, result);
}

//返信用のメソッド
function reply(data, msg) {
  UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': data.replyToken,
      'messages': [{
        'type': 'text',
        'text': msg,
      }],
    }),
    });
  return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}

function showSpreadSheet() {
  var FValues = dataSheet.getRange('B:B').getValues();
  var LastRow = FValues.filter(String).length;
  var spread = "";
  var range;
  var pay = dataSheet.getRange(2,7).getValue();
  var balance = dataSheet.getRange(3,7).getValue();
  if (LastRow == 1) {
    spread = spread + "残高: " + balance + "\n"; 
    return spread;
  }
  
  for(var i = 1; i <= LastRow; i++) {
    for(var j = 1; j <= 3; j++) {
      var range = dataSheet.getRange(i, j);
      var rangeVal = range.getValue();
      if (i > 1 && j == 1) {
        rangeVal = Utilities.formatDate(rangeVal, 'Asia/Tokyo', 'MM/dd');
      }
      if (i > 1 && j == 3) {
        rangeVal = rangeVal + "";
      }
      spread = spread + rangeVal + ",";
      if(j == 3) {
        spread = spread + "\n";
      }
    }
  }
  spread = spread +"----------------------\n";
  spread = spread +"支出合計: " + pay + "\n";
  spread = spread + "残高: " + balance + "\n";
  spread = spread +"----------------------\n";
  return spread;
}

function insertToSpreadSheet(data) {
  var date = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd');
  var FValues = dataSheet.getRange('B:B').getValues();
  var LastRow = FValues.filter(String).length;
  // 入力文字は品名全角or半角スペース金額
  var inputArray = data.message.text.split(/\s+/);
  var product = inputArray[0];
  var price = inputArray[1];
  dataSheet.getRange(LastRow + 1, 1).setBorder(true, true, true, true, false, false).setValue(date);
  dataSheet.getRange(LastRow + 1, 2).setBorder(true, true, true, true, false, false).setValue(product);
  dataSheet.getRange(LastRow + 1, 3).setBorder(true, true, true, true, false, false).setValue(price);
  var str = [date, product, price].join(" ");
  return str + "\n記録しました";
};

ほんとうにゴリゴリです。
重複があったり不自然な変数名などいろいろ気になるところです。
Spreadsheetの操作とはいえ二重ループを書くことになるとは思いませんでした。

#感想
できれば授業の本筋に合わせてnode.jsとgoogleのapiを駆使して、UIも低年齢層向けの
親しみやすいプロダクトを理想としていたので到達できなかった悔しさを感じます。

ですがBOTにメッセージをなげかけてSpreadsheetに一秒待たないくらいのタイミングでデータが記録された時、うまくいえないですが__「これ・・・いい・・・」__と心の底から思いました。
保守改修がメインの日々の業務では感じることの難しい物作りの面白さを感じることができました。

プロトタイプとして最低限の実装ができたので成功ということにします。
#今後
もっとブラッシュアップして当初に構想のである対話型にしたい、UIにも拘りたいし実際に姪にも使ってもらうのが理想ですね。
コロナ禍で会うこともなかなか叶わない分、このアプリを育てていくのがいいのかもしれません。

それと、アプリの仕組みを利用して○滅の刃や○リキュアのキャラなどと対話しながらお金の動きを観察してマネーリテラシーを早い段階で養う、などの名目を作りキャラクター・マーチャンダイジングの方面に展開できたら夢が広がるな!と感じました。
HIKAKIN氏の動画をよく見ますが幅広い年齢層に響くものってどうやってつくれるんだろう。。。
それには足りないことが多すぎる!のでまだまだ頑張ります。

28
15
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
28
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?