🗑️

Alexaが翌日のゴミ出し内容を教えてくれるskillを作ってみた

2023/10/15に公開

きっかけ

前日夜に家中のゴミを集めておくのですが、その際「明日なんのゴミの日だっけ?」と市が提供しているアプリを開いて確認しています。

我が家では家電の操作や、乳児期の育児アプリをAmazon Echoの音声インターフェースを通して利用する便利さを体験していたため、この「翌日のゴミを確認する」作業をAlexaで実現できないかと考え、初のカスタムスキル開発に挑戦してみました。

構成

Alexaのスキルは以下の3つの形式でホスティングできるのですが、AWSアカウントも所有していますし、バックエンド側の実装も自分で実施したかったため、「独自のプロビジョニング」を選択しました。

参考 Alexa-hosted skillについて

今回作成する簡単なシステム構成は以下の通りです。

Amazon Developer Console

AlexaスキルはAmazon Developer Consoleを用いて実装します。
ここでは発話の設定やバックエンドとの接続方式の設定などを行い、Alexaスキルのビルドやテストを実装できます。
以下のサイトを参考にさせていただきました。
Alexaの知識がないところからスキルを作ってみた

設定した内容は以下の通りです。ChatGPT先生に代筆してもらいました。

  1. "スキルの作成" をクリックして新しいスキルを作成します。スキル名を指定し、言語とリージョンを設定します。
  2. スキルのインテントを設定:
    スキルの「インタフェース」タブで、スキルがサポートするインテントを定義します。例えば、"GetGomiSchedule"というカスタムインテントを作成し、その中でスロットを定義します。この場合、"Date"というスロットが必要です。
  3. エンドポイントの設定:スキルの「エンドポイント」タブで、スキルが使用するLambda関数を指定します。
    作成したLambda関数のARN(Amazonリソース名)を入力し、スキルが呼び出す関数名を指定します。

Alexa側の実装に関しては以下の記事が非常にわかりやすかったので是非参考にしてください。
【Alexa初心者向け】Alexa Skill Kitを噛み砕いて解説してみる

呼び出しの設定

スキルを呼び出す際の設定項目です。

インテントの設定

インテントの設定項目です。初期設定時から存在する4つのインテントと、今回作成したインテントが含まれています。

エンドポイントの設定

エンドポイントの設定です。今回は自分自身でバックエンドのLambdaを呼ぶ構成のため、LambdaのARNを入力します。

LambdaとDynamoDBの実装

今回はいたってシンプルで、リクエストを受けた翌日のゴミを回答するだけにしています。
カスタムインテント等を活用するともっと柔軟に実装できるみたいですが、まずは動くものを作ってみたかったので簡素な実装です。

DynamoDB

翌日という日付をキーにクエリする想定なので、Dateをパーティションキーにしました。
キーに対して取得したい内容であるゴミの種別をGomiTypeというリスト型で定義しました。
日によっては燃えるゴミと段ボール、のように複数のゴミを出せるので、リスト形式で複数格納できるようにしています。

データ投入

ここが一番の鬼門だったかもしれません…
地域から頒布されているゴミカレンダーはPDF形式のみで、文字の埋め込みもありません…
OCR等で起こそうかなと思い挑戦してみましたが、うまくいきませんでした…

今回は以下のようなお手製CSVを作成し、DynamoDBにインポートしました。
品質に不安があったので、パートナーにダブルチェックしてもらい、バグを2件検出できました。手作業ダメゼッタイ。

Date,GomiType
2023/10/17,"[{""S"":""雑誌、雑紙""}]"
2023/10/18,"[{""S"":""有害ゴミ""},{""S"":""ビン""},{""S"":""プラスチック""},{""S"":""小型家電・金属類""}]"
2023/10/19,"[{""S"":""燃えるゴミ""},{""S"":""紙パック""},{""S"":""古着""}]"
2023/10/20,"[{""S"":""カン""}]"
2023/10/21
2023/10/22
2023/10/23,"[{""S"":""燃えるゴミ""}]"

Lambda

boto3を業務でよく使うのでboto3で実装しています。
特に説明する箇所もなく非常にシンプルな作りです。

import boto3
import json
from datetime import datetime, timedelta

## boto3のDynamoDBリソースをプロビジョニングし、テーブル名を設定
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('GomiSchedule')

def lambda_handler(event, context):
    if 'request' in event:
        if request_type == "LaunchRequest":
	   ## Lambdaが呼び出された日から翌日を計算
            tomorrow = (datetime.now() + timedelta(days=1)).strftime("%Y/%m/%d")
	   ## DynamoDBに対して、パーティションキーを指定してクエリ
            response = table.get_item(
                Key={
                    'Date': tomorrow
                }
            )
            if 'Item' in response:
                gomi_types = response['Item']['GomiType']
                gomi_types_text = ', '.join(gomi_types)
                return {
                    "version": "1.0",
                    "response": {
                        "outputSpeech": {
                            "type": "PlainText",
                            "text": f"翌日は{tomorrow}{gomi_types_text}の日です。"
                        }
                    }
                }


    return {
        "version": "1.0",
        "response": {
            "outputSpeech": {
                "type": "PlainText",
                "text": "翌日のゴミの日情報を取得できませんでした。"
            }
        }
    }

トリガーの設定

AlexaスキルからLambdaを呼ぶためにはトリガーを設定する必要があります。
ここも特に難しくなくAlexaを選択した後、Amazon Developer Consoleから確認できるスキルIDを入力するだけです。

スキルIDは以下の画面からコピーできました。

テスト実行

Amazon Developer Consoleの「テスト」タブでEnd to Endでテストを行うことができます。
画面右のチャット部にテストしたい発話を入力することで、対話をシミュレーションできます。開発しているPCのマイク入力でもテスト可能ですし、チャットに文字を入力してテストすることも可能です。

いいなと思ったのは画面右の「JSON入力」という項目で、Lambdaに渡されるJSONが表示されることです。
これをそのままコピペすることで、Lambda側の単体テストも容易に行えます。

最後に

今回実施した手順では、スキルを一般公開してはいません。個人的な利用にとどめる場合はここまででOKですが、一般公開したい場合は様々なレギュレーションがあるようなので機会があれば勉強してみたいです。
また、インテントやスロットを活用した柔軟な会話対応にも挑戦してみたいですね。
明日だけじゃなくて○○日のゴミの日を知るとか、次の燃えるゴミの日を知るとか改善の余地はありそうです。

Discussion