Googleアシスタントアプリ「世田谷分別チェッカー」ができるまで【開発編】

6 min読了の目安(約5600字TECH技術記事

はじめに

先日、世田谷区のゴミの分別方法を教えてくれるGoogleアシスタントアプリ「世田谷分別チェッカー」をリリースいたしました。
このアプリは、捨てたいものの名前を伝えると何ゴミで捨てればいいのか教えてくれます。

前回の記事Googleアシスタントアプリ「世田谷分別チェッカー」ができるまで【事前準備編】では、このアプリを作り始める前段階の実現方法の調査に焦点を当てました。
今回の記事では、その実現方法を用いてどのようにアプリを作り上げていったのか、もう少し具体的な部分を書いていきます。

前回のおさらい

まずは、前回の事前準備編で洗い出した実現に必要な4要素を見ていきましょう。
下記の4つがはっきりすれば、このアプリを作ることができそうという見立てでした。

  • アプリのユースケース
  • アシスタントアプリ開発の基礎知識
  • ゴミの分別データの作成方法
  • 分別データとアシスタントアプリの連携方法

それぞれはこのように整理できました。

実現に必要な要素 具体的な内容
アプリのユースケース 「ユーザー:捨てたいものを伝える」→「アプリ:分別方法を返答する」
アシスタントアプリ開発の基礎知識 Codelabにて修得
ゴミの分別データの作成方法 区のオープンソースをFirestoreで利用できる形にスプレッドシートで整形
分別データとアシスタントアプリの連携方法 スプレッドシートで整形したデータをFirestoreに移行

今回の記事では、この4つのうち開発作業に関わる後半の2つを見ていきましょう。

ゴミの分別データの作成

ゴミの分別データの作成方法は区のオープンソースをFirestoreで利用できる形にスプレッドシートで整形すればいいことが事前準備の段階で分かりました。
この章では、具体的にどのような手順でこのデータを作っていったのかをご紹介します。

さて、まずは区のオープンデータがどのような形で提供されているか見てみましょう。

上図は区から提供されているゴミの分別方法のオープンデータの一部です。
前回の事前準備編でも述べたように、このデータのままではサービス連携するには少々使いづらそうです。
このデータをそのまま使えない(使いづらい)理由はいくつかあります。

  • 1行目に不要なタイトルが含まれている
  • 1列目に今回のアプリでは使わないであろう50音のデータがある
  • 2列目(品目)が単純な名前ではない(〇〇製や〇〇の場合などの付加情報が含まれている)
  • 3列目(出し方)に単純な分別方法(可燃・不燃等)以外に出す際の注意事項(汚れを落として等)やそもそもゴミとして出せない旨の記載(拠点回収等)がある
  • 3列目(出し方)に素材の違いによる出し方が行を分けて記載されている

他にも細かい理由がいくつかあるかもですが、ざっと出してもこれだけあります。
ここからは、このデータを実際に使える(使いやすい)データに整形していきます。

1. 品目・出し方・注意事項に分割

まず、今回のアプリに不要な50音の列を削除しました。
そして、品目と出し方の2列しかなかった元データを、品目・出し方1~3・注意事項の5列に分割しました。
出し方1~3は、可燃ごみ・資源などの分類の他に「〇〇用は不燃ごみ」など、同じ品目でも用途によって分別方法が違うものなどを定義するために追加しました。
また、注意事項はごみを出す際に行うべき下準備(汚れを取り除く等)や、ごみとして出せず拠点回収する必要があるものを出し方とは別で定義するために追加しました。

Before

After

2. 材質・用途・状態に分割

(1)で分別方法を出し方1~3として整理したところ、出し方には一定の法則があることに気付きました。
基本的には出し方1がベースにあり、それとは別に材質・用途・状態の違いによって同じ品目でも違う出し方になることが分かりました。
そこで、出し方1~3として分割したデータを改めて材質・用途・状態に分けて定義し直しました。
また、このタイミングで各品目にIDを振りました。

Before

After

3. アシスタントアプリで発話させるメッセージを生成

(2)で整理したデータである程度アプリで利用するための下準備は整いました。
ユーザーが発話した「捨てたいもの」をこのデータの品目から検索し、該当する品目の材質・用途・状態・注意事項を組み合わせたメッセージを作成、そのメッセージをアシスタントアプリからの返答として返すという使い方になります。

この流れの中の「該当する品目の捨て方を材質・用途・状態・注意事項を組み合わせたメッセージを作成」の部分は当初、スプレッドシートで定義したこれらのデータを事前にFirestoreへ送信しておき、ユーザーがアプリを使う際は発話内容に含まれる品目をFirestoreのクエリとして投げて引っ掛かった品目の材質情報等をCloud Functionのメソッド内で組み合わせて発話内容を生成することを想定していました。
(例:ユーザーが「一斗缶」を捨てたい場合、一斗缶には「出し方:資源」のデータと「用途:塗料用、出し方:不燃ごみ」のデータの2種類があるため、1つ目のデータは出し方と品目を合わせて「一斗缶は資源です」というメッセージを生成します。2つ目のデータは用途と出し方と品目を組み合わせて「塗料用の一斗缶は不燃ごみです」というメッセージを生成します。)

しかし、品目に対する発話内容というのは静的なデータなので、この処理をCloud Functionにリアルタイムで行わせる必要はないことに気付きました。
事前に各情報を組み合わせて発話内容を作成しておくことで、アプリ利用時に無駄な処理を走らせることなくユーザーの要望に答えることができると考えました。

したがって、スプレッドシートのデータにメッセージの列を追加して、GASを用いて各列に定義された情報を組み合わせて発話内容を生成するスクリプトを実装しました。

// 検索に引っかかった場合に返事として発音させるメッセージを追加する
function addMessages() {
  let sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_NAME);
  let values = sheet.getDataRange().getValues();
  for (let i = 1; i < values.length; i++) {
    let row = values[i];
    let document = {
      id: row[0],
      name: row[1],
      material: row[3],
      use: row[4],
      status: row[5],
      separation: row[6],
      caution: row[7],
    }
    
    var message = "";
    // 〜用の
    if (document.use != "") {
      message = message + `${document.use}`
    }

    // 〜製の、〜式の
    if (document.material != "") {
      message = message + `${document.material}`;
    }
      
    if (document.status != "") {
      // 〜で〜のものは
      message = message + `${document.name}${document.status}`;
    } else {
      // 〜は
      message = message + `${document.name}`;
    }

   
    // 〜です
    if (document.separation != "") {
      message = message + `${document.separation}です。`;  
    }
    // 注意事項の文章
    if (document.caution != "") {
      message = message + `${document.caution}`;        
    }
    
    // セルにデータセット
    sheet.getRange(i + 1, 9).setValue(message);
  }
}

Before

After

これでごみの分別方法の検索に使用するデータが全て出揃いました。
出揃いましたが、まだ1つ課題が残っています。

4. 検索精度改善のためにシノニムを追加

(3)にて、品目の情報から発話データを生成することができました。
これで必要なデータ自体は全て出揃ったのですが、このままだとユーザーが発話した「捨てたいもの」から該当する品目データを探し当てることは困難です。
というのも、現時点ではユーザーの発話内容とデータとして定義されている品目名が完全一致した場合のみ検索に一致したとみなし発話データを返すようになっています。
そのため、ユーザーが「一斗缶」と発話した場合、Googleアシスタントが「一斗缶」と漢字に変換すれば問題ありませんが、仮に「いっとかん」とひらがなで受け取られた場合は検索結果が0件になってしまいます。
また、データに定義されている名前とは別名でユーザーが検索をかける可能性もあります。
(例:バイクを捨てたいユーザーは「バイク」と発話するかもしれないし「オートバイ」と発話するかもしれません。)

そこで、上記の課題を解決するため、漢字・ひらがなの表記揺れや同義語をシノニムとして定義します。
上の例のように、バイクに対して「オートバイ、バイク、自動二輪、自動二輪者、モーターバイク」などを各品目について定義します。

Before

After

分別データとアシスタントアプリの連携

さて、これでごみの分別データと検索に引っ掛かった際の発話データが出揃いました。
後はもうこれらのデータとアシスタントアプリを連携させるだけです。
各サービスを下図のように連携させます。

これにより、ユーザーの発話から捨てたいものを抽出し、その品目の分別方法に関する発話内容をFirestoreから返却するアプリが完成しました。

おわりに

これにて、Googleアシスタントアプリ「世田谷分別チェッカー」ができるまで【開発編】が終わりました。
後半の実装部分はかなり細かい話になってしまうため連携部分の構成のみ紹介して省略しました。
もし需要があればアシスタントアプリ自体の実装に関する話もしようかなと思っています。
最後までお読みいただきありがとうございました。