【Alexa Skill開発】Alexaに最寄り駅の次発電車の発車時刻を教えてもらう(AmazonEcho)

経緯

Amazon Echoを買ったので、自分でも面白いものが作れないか調べたところ、公式の解説がとてもよくまとまっている。
これなら簡単にできるな・・・ということで、練習問題を少し改造して、最寄り駅の次発、次々発、次々々発の電車の時刻を教えてくれるSkillを自作してみた。

時刻表もベタ打ちだし、かなりイケてない作りだけれど、とりあえず使えるはず。

developer.amazon.com

デモ動画

www.youtube.com

Skillの動作

「Alexa、時刻表で平日の電車を教えて」
「Alexa、時刻表で休日」
「Alexa、時刻表で休日の時刻表」
等の声掛けをすると、
「"平日の時刻表です。次は6時45分,1分,14分です"」
と、現在時刻から10分後以降の電車を3つ列挙して教えてくれる。
私はほぼ乗る電車が確定しているので、路線については決め打ちだが、少し改造するだけで、「○○方面への時刻表を教えて」等のアップグレードも可能。

前提

本説明は、上記Amazonのチュートリアルの入門#1,#2を実行、理解できていることを前提とする。
つまり、
・ AWS Lambdaへの登録
・ Amazon Developerアカウントへの登録
・ スキルを登録するまでの流れ
については説明しない。

Skillの作り方

アレクサのスキルを作るためには、以下2つの作業が必要となる。以降、これらを順に説明していく。
1.AWS Lambdaスクリプトの作成
 (サーバーサイドのプログラムを設定、今回はPythonを使用)
2.Alexaの会話フローの作成
 (Alexaにどのように声掛けをするか、音声からどのような情報を取得し、サーバーに投げるかを設定)

1. AWS Lambdaスクリプトの作成

まずはサーバーサイドのプログラムを登録する。
WebブラウザでAWSマネジメントコンソール( https://console.aws.amazon.com/ )にアクセス、ログインし、画面左上の「AWSサービス」のテキストボックスに「lambda」と入力し、表示される候補から「Lambda」をクリックする。
AWS Lambdaの初期画面が表示されたら、「関数の作成」を押し、先のチュートリアル同様、求められた項目に入力していく。ランタイムの項目のみ、最初は「Node.js 6.10」となっているが「Python3.6」としておく。

その上で、スクリプト記載画面まで行ったら、以下を入力する。(住まいがわかってしまうので、時刻表の中身は変更済み)
やっていることはごく簡単。スクリプトを追えばすぐに理解できるはず。
jikoku = [,]の2次元配列に対し、時刻表を教えてほしい電車の発車時刻をベタ打ちすれば、様々な環境で使える。

import time
from datetime import datetime, timedelta, timezone

def train(jikoku,time):
    nextTrain = [0,0]
    for i in jikoku[time.hour]:
        if i >= time.minute:
            nextTrain = [time.hour,i]
            break
        
    if nextTrain[0] == 0 and nextTrain[1] == 0:
        for i in jikoku[time.hour+1]:
            if i >= 0:
                nextTrain = [time.hour+1,i]
                break
    return nextTrain


def lambda_handler(event, context):

    if event['request']['type'] == "IntentRequest":
        intent = event['request']['intent']
        value = intent['slots']['DayType']['value']
    else:
        if (jsttime.weekday() >= 5):
            value = "休日"
        else:
            value = "平日"
    
    # タイムゾーンの生成
    JST = timezone(timedelta(hours=+9), 'JST')
    jsttime = datetime.now(JST) + timedelta(minutes=10)
    
    if value == '休日' or value == '祝日':
        jikoku = [
            [8,16,25],#0,
            [],#1,
            [],#2,
            [],#3,
            [52],#4,
            [10],#5,
            [3,8],#6,
            [1,12,55],#7,
            [2,13,30],#8,
            [2,13],#9,
            [2,13],#10,
            [2,13],#11,
            [2,13],#12,
            [2,13],#13,
            [2,13],#14,
            [2,13],#15,
            [2],#16,
            [2],#17,
            [2],#18,
            [2],#19,
            [2,10],#20,
            [2,10],#21,
            [4,50],#22
            [4,51]#23            
        ]
    else:
        jikoku = [
            [8,16,25],#0,
            [],#1,
            [],#2,
            [],#3,
            [52],#4,
            [10],#5,
            [3,8],#6,
            [1,12,55],#7,
            [2,13,30],#8,
            [2,13],#9,
            [2,13],#10,
            [2,13],#11,
            [2,13],#12,
            [2,13],#13,
            [2,13],#14,
            [2,13],#15,
            [2],#16,
            [2],#17,
            [2],#18,
            [2],#19,
            [2,10],#20,
            [2,10],#21,
            [4,50],#22
            [4,51]#23      
         ]

    
    nextTrain = [[0,0],[0,0],[0,0]]
    nextTrain[0] = train(jikoku,jsttime)
    nextTrain[1] = train(jikoku,datetime(jsttime.year,jsttime.month,jsttime.day,nextTrain[0][0],nextTrain[0][1]+1,0))
    nextTrain[2] = train(jikoku,datetime(jsttime.year,jsttime.month,jsttime.day,nextTrain[1][0],nextTrain[1][1]+1,0))

    if value == '平日':
        day = "平日の時刻表です。次は" + str(nextTrain[0][0]) + "時" + str(nextTrain[0][1]) + "分," + str(nextTrain[1][1]) + "分," + str(nextTrain[2][1]) + "分です"
    elif value == '休日' or value == '祝日':
        day = "休日の時刻表です。次は" + str(nextTrain[0][0]) + "時" + str(nextTrain[0][1]) + "分," + str(nextTrain[1][1]) + "分," + str(nextTrain[2][1]) + "分です"
    else:
        day = "平日の時刻表です。次は" + str(nextTrain[0][0]) + "時" + str(nextTrain[0][1]) + "分," + str(nextTrain[1][1]) + "分," + str(nextTrain[2][1]) + "分です"


    response = {
        'version': '1.0',
        'response': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': day
            }
        }
    }
    return response

2. Alexaの会話フローの作成

次に、Alexaの会話フローを作成する。
まずは、以下の開発者コンソールから適当な名前でスキルを登録する。
Amazon Developer Sign In

次に、対話モデルのインテントスキーマの設定する。

{
  "intents": [
    {
      "slots": [
        {
          "name": "DayType",
          "type": "LIST_OF_DAY_TYPE"
        }
      ],
      "intent": "GetNewFactIntent"
    }
  ]
}

カスタムスロットタイプには平日・休日の種別を設定する。

    タイプ: LIST_OF_DAY_TYPE
    値:平日、祝日、休日

サンプル発話は以下の通り

GetNewFactIntent {DayType} の時刻表
GetNewFactIntent {DayType}
GetNewFactIntent {DayType} の時刻表を教えて
GetNewFactIntent {DayType} の次の電車は
GetNewFactIntent {DayType} の電車

あとは、先のチュートリアル通りにLambdaとスキルを紐付けたら完成。
試しにシミュレータで「平日は?」等を入力してみると、「平日の時刻表です。次は7時32分,55分,5分です"」等と帰ってくることがわかる。

感想

まとめてみると長いけれど、基本はサンプルから少し改造するだけでOK。買った翌日に試して、2~3時間程度でこの程度のことができます。
簡単なPythonプログラムが書ければ、結構日常生活に役立つSkillが作れるんじゃないかな、と思いました。
後はアイディア勝負・・・・かな。