Google Home에서 영수증을 스프레드 시트에 기록하는 앱을 만들려고했습니다.

확정신고의 시기입니다(투고 시기는 3월)
나는 이미 끝났습니다만 수타로 기록하는 것이 뭐 짜증나고 비효율이라고 느꼈습니다.

그래서 음성 입력만으로 끝나도록 이번 앱을 만들었습니다.
※가계부로도 사용할 수 있습니다.

실제 동작 방식



아래를 클릭하면 동영상이 재생됩니다.
IMAGE ALT TEXT HERE

간단한 흐름
나:택시로 3800엔 교통비
→ 일시적으로 스프레드시트에 기입

Google Assi: 택시로 3800엔 교통비로 하시겠습니까?

나: 네
→ 스프레드시트에 등록됨

사용한 서비스 및 흐름도



● 사용한 서비스
· GoogleAppsScript
· AWS
lambda
API Gateway
· GoogleAssistant
· Dialogflow

이렇게 다양한 서비스를 사용하는 것은 원래
GoogleAssistant → DialogFlow → 스프레드 시트는 Integrations에서 설정할 수 있지만 Google Assistant에 텍스트를 반환 할 수는 없습니다.

또 AWS를 사용하고 있는 것은 처음 GAS로 배포한 엔드포인트를 DialogFlow의 Webhook로 설정했습니다만, 302 리다이렉트를 해 할 수 없었기 때문에 어쩔 수 없이 Lambda와 API gateway를 사용했습니다.

● 흐름도
google home에서 어린이 숙제 관리하기
에서 배차, 일부 추가


개발 흐름



Dialogflow 설정 예




· 실패의 예 -Entity에서 -

이 설정이라고 예를 들면 교통비라고 해도 "무엇"이라고 판별되기 때문에 지웠습니다.

Dialogflow ~ AWS (API Gateway & Lambda) ~



절차나 주의점은 이 기사에 적혀 있습니다.
Google 어시스턴트에서 웹훅으로 라인의 특정 인물에게 푸시 알림

~GoogleAppsScript⇄ 스프레드시트



Lambda에서 Webhook에서 흘러 온 JSON 데이터를 GAS라도 이것하고 있습니다.
다음 코드입니다 (V8)

code.gs
function doPost(e) {
  try {
    let result;
    let ss = SpreadsheetApp.openById(sheetId);
    let sh = ss.getSheetByName(sheetName);

    let request = JSON.parse(e.postData.getDataAsString());
    intentName = request.queryResult.intent.displayName;

    //領収書のIntent
    if (intentName == INTENT_RECEIPT_CONTENT) {
      let where = request.queryResult.parameters.PlacePay
      let howmuch = request.queryResult.parameters.number
      let what = request.queryResult.parameters.WhatPay

      //スプレッドシートに一時保存
      sh.getRange(1, 5).setValue(where);//where
      sh.getRange(1, 6).setValue(howmuch);//howmuch
      sh.getRange(1, 7).setValue(what);//what
      let result = { "fulfillmentText": where + "" + howmuch + "円," + what + "でよろしいでしょうか?" };
      return returnAsJSON(result);
    }

    //Yes/NOの場合
    if (intentName == INTENT_RECEIPT_YESNO) {
      let yesno = request.queryResult.parameters.YesNo
      switch (yesno) {
        case Yes:
          //一時保存から取り出す
          let temp_where = sh.getRange(1, 5).getValue();//where
          let temp_howmuch = sh.getRange(1, 6).getValue();//howmuch
          let temp_what = sh.getRange(1, 7).getValue();//what
          let lastrow = sh.getLastRow();
          sh.insertRowAfter(lastrow);
          lastrow++;

          let now = new Date();
          let date = Utilities.formatDate(now, 'Asia/Tokyo', 'yyyy-MM-dd');
          let time = Utilities.formatDate(now, 'Asia/Tokyo', 'HH:mm:ss');
          sh.getRange(lastrow, 1).setValue(date + " " + time);
          sh.getRange(lastrow, 2).setValue(temp_where);//where
          sh.getRange(lastrow, 3).setValue(temp_howmuch);//howmuch
          sh.getRange(lastrow, 4).setValue(temp_what);//what

          result = { "fulfillmentText": "登録しました" };//fulfillmentTextが大事!
          return returnAsJSON(result);

        case No:
          result = { "fulfillmentText": "キャンセルしました" };
          return returnAsJSON(result);

        default:
          return returnAsJSON({ "fulfillmentText": "もう一度最初から" });
      }
    }
    return returnAsJSON({ "fulfillmentText": "ごめんね。よくわからなかったよ" });

  } catch (ex) {
    console.log(ex)
    return returnAsJSON({ "fulfillmentText": "エラーが発生しました。ログで確認できます" });
  }
}

function returnAsJSON(obj) {
  return ContentService.createTextOutput(JSON.stringify(obj)).setMimeType(ContentService.MimeType.JSON);
}

가볍게 설명하면
request.queryResult.intent.displayName
부분이 Dialogflow로 설정된 Intent 이름입니다.


request.queryResult.parameters.***
의 부분이 각 Intent에서 설정한 파라미터값($**)입니다.

※대문자의 변수는 Dialogflow로 설정한 Intent명등을 각각 넣는 것

스프레드시트 작성



작성 및 임시 저장은 스프레드 시트에서 수행됩니다.

GAS라면 시간 지정으로 실행하는 트리거를 간단하게 설정할 수 있으므로, 달이나 연도가 바뀌었을 때에 신규 시트에 이행이라고도 할 수 있습니다.

마지막으로



이 앱으로 신호 대기하기 때문에 짧은 틈새 시간에도 영수증을 등록할 수 있게 되었습니다.
이것을 응용하면 요리 주문 앱이라든지 만들 수 있을 것 같습니다.

또 이번 GoogleHome 계이지만 알렉사에서도 만들 수 있을 것 같네요.

그런데도 Dialogflow의 편리하네요~

참고:



Google 어시스턴트에서 웹훅으로 라인의 특정 인물에게 푸시 알림
google home에서 어린이 숙제 관리하기

그리고 Dialog의 Intent등의 설정은 이쪽의 책이 알기 쉬웠다↓
부드럽게 시작 스마트 스피커 프로그래밍

좋은 웹페이지 즐겨찾기