アレクサ、助けて


この記事はHamee Advent Calendar 2021の11日目の記事です。

はじめに

この記事は「開発してみた」系の記事です。
あまり技術や思想的に「おおお!!!!」となる記事ではありません。
Goでアレクサスキルを作ってみたい。lambdaからDynamoDBに触りたいという人には向いているかもしれません。

課題

私「(この設計どうしようかな)」
私「アレクサーこの設計どうすればいい?」
アレクサ「わかりません」

そう。アレクサは助けてくれない。
在宅が続き、アレクサと二人っきりの時間が増えようともアレクサは仕事を手伝ってはくれない。外出も減った今とでは天気を聞くこともなく、音楽を流すことしかしない。

せめて相槌でもして欲しい。

そう何か、いい感じに、返事をして欲しい。

仕組み

AlexaからLambdaを叩き、DynamoDBからそれっぽい文章を取ってきてもらう。
Lambdaは最近社内で勉強会があったのでGoを使ってみます。

コードはこちら

1. アレクサスキルを作る

1.1 スキルを作る

AlexaのDeveloper Consoleからスキルを作っていきます。

今回はGoで作るので、ホスティングはユーザー定義のプロビジョニングを選びます

1.2 対話モデルを作る

対話モデル>インテント を選択し、インテントを埋めていきます。
個人的には、インテントを最初に作ることでユーザーの使っている感じがイメージしやすいので先にやってます。

インテントとは、アプリ起動時「アレクサ、〇〇を開いて」と言った後の会話です。
必須の要素は以下の意味なので、順にそれっぽいワードを入れていきます。
Cancelintentは、アプリの終了
HelpIntentは、アプリに関しての質問
StopIntentは、アプリの一時停止

2. DynamoDBを作る

本来はコードベースで作った方がいいのでしょうが、ぽちぽちして作ります。

それっぽい文章は、以下の書籍やサイトを参考に汎用性を高くした文章を10個ほど考えました。

コーチングの基礎
自由の森 コーチングでよく使う質問集

3. lambdaを作成する

3.1 開発する

基本的な部分はこちらの記事を参考にさせていただきました。
AlexaスキルをGoとServerlessで書いてみた

主に追加したのは、DynamoDBにアクセスをする箇所です。
aws-sdk-goを使ってDynamoDBから値を取得しました。

dynamodbattribute.UnmarshalMapでいい感じに構造体にマッピングできるのはいいですね。

package dynamodb

import (
    "fmt"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/dynamodb"
    "github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)

type Question struct {
    MessageId int    `json:"message_id"`
    Question  string `json:"question"`
}

//DynamoDBから文字列を取得する
func GetQuestions() []Question {
    var questions []Question = []Question{}

    svc := dynamodb.New(session.New(), aws.NewConfig().WithRegion("ap-northeast-1"))

    input := &dynamodb.ScanInput{
        TableName: aws.String("coaching_words"),
    }

    result, err := svc.Scan(input)
    if err != nil {
        fmt.Println("[GetItem Error]", err)
        questions = append(questions, Question{MessageId: 0, Question: "DBにアクセスできませんでした"})
    }

    for _, question := range result.Items {
        var questionTmp Question
        _ = dynamodbattribute.UnmarshalMap(question, &questionTmp)
        questions = append(questions, questionTmp)
    }
    return questions
}

3.2 デプロイ

デプロイは、先例に習いserverlessを使って行います。

awsのクレデンシャルを通す

以下のどちらかで行えます。

export AWS_ACCESS_KEY_ID=<your-key-here>
export AWS_SECRET_ACCESS_KEY=<your-secret-key-here>
serverless config credentials --provider aws --key {} --secret {}

~/.aws/credentialsに以下の形式で宣言し、export AWS_PROFILE="hogehoge"で動かす方が便利そう。

[profileName1]
aws_access_key_id=***************
aws_secret_access_key=***************

※ serverlssは~/.aws/credentialしか見ないので、~/.aws/configに書いてあったとしてもエラーになるので注意が必要
Serverless Framework - AWS Lambda Guide - Credentials

コンパイルする

env GOOS=linux go build -o bin/main

デプロイする

sls deploy

lambdaに新しい関数ができていれば成功です

4. lambdaと各種を繋ぐ

4.1 alexa skillと繋ぐ

lambdaのarnをコピーして、アレクサスキルのエンドポイントに記入していきます。

続いて、alexaスキルのIDをlambdaのトリガーに追加します。

4.2 DynamoDBと繋ぐ

lambdaのアクセス権限>実行ロールから、MicroserviceExecutionRoleを含むポリシーをアタッチします。
これをしないとDynamoDBからデータを取得できません。

5. 結論

すごくイライラする

同僚や先輩に同じセリフを言われても感謝はしてもイライラはしないのに、なぜだろう。

そうか、これが、、、心か、、、、、、

終わりに

読んでいただきありがとうございました。

GoもAWSもハンズオンや勉強会などで中心で、あまり1から扱うことがなかったのでとても新鮮に開発できました。やっぱり、普段の重い腰をあげるといい意味でもアドベントカレンダーはいいですね。

アレクサスキルも様々なことができそうでかなり面白いですね。
同じセッション内での値の受け渡しとか、オーディオの再生とか。Echo Showでもスキルが作れるとのことなので、できることがかなり広がっていて楽しみです。

今回は残念ながら課題の解決はできませんでしたが、私は諦めません。アレクサが私の代わりに仕事や家事をこなしてくれることを願っています。

参考文献

AlexaスキルをGoとServerlessで書いてみた
コーチングの基礎
自由の森 コーチングでよく使う質問集