身の回りの困りごとを楽しく解決! by Works Human Intelligence Advent Calendar 2023 の15日目の記事です。
この記事では、アレクサにしゃべりかけたことばを LINE に送信するスキルの作り方について解説します。
アレクサにしゃべりかけるだけで LINE に通知することができるので、わざわざスマホを開く必要がありません。
スキルの作成には、Alexa Skills Kit(ASK)を使います。
ASK を使えば、簡単にアレクサスキルを作ることができます。
スキルは、アレクサ用のアプリのようなものです。スキルによって、音声を使っていろいろなことをできるようになります。
ASK は、アレクサ向けの開発キットで、開発者アカウントを登録すればすぐに使うことができます。
アレクサの基本
アレクサは常にユーザーの呼びかけを待っています。
ウェイクワードである「アレクサ」とユーザーが呼びかけると、アレクサはユーザーのリクエストに対応するスキルを呼び出します。
アレクサに次のように話しかければ、ユーザーがリクエストした「今日の天気」を答えるスキルを起動して応答します。
アレクサ、今日の天気は?
ユーザーがスキルを起動すると、アレクサはユーザーのことばをクラウドにある Alexa サービスに送ります。
Alexa サービスでユーザーのことばがテキストに変換され、AWS Lambda 関数にリクエストを送信します。
AWS Lambda 関数でコードを実行し、アレクサへの応答を返します。
Alexaスキルを開発する理由
アレクサスキルを作るのには、次のことについて理解する必要があります。
- ウェイクワード
- 呼び出し名
- インテント
- スロット
ウェイクワード
ユーザーがアレクサに何かをリクエストする前に言うコマンドです。
「アレクサ」や「アマゾン」、「エコー」、「コンピューター」などのことばを使うことができます。
呼び出し名
アレクサスキルを開始するための呼び出し名です。
十二星座占いというスキルを使うときは、次のようにアレクサにしゃべりかけます。
「十二星座占い」が呼び出し名になります。
アレクサ、十二星座占いを開いて
これによって、アレクサは「十二星座占い」のスキルを起動します。
インテント
ユーザーからの音声によるリクエストを満たすアクションのことです。
次の発話だと、ユーザーが求めているのは天気予報を知るです。天気予報を教えるためのアクションがインテントになります。
- 今日の天気を教えて
- 天気予報を知りたい
- 雨は降る?
スロット
スロットは、インテントの引数です。
次の発話は、天気を教えるインテントに、「明日」というスロット値を引数として渡します。
アレクサ、明日の天気を教えて
作成するスキルの概要
LINE に送信するアレクサスキルを作ってみましょう。
ユーザーがアレクサに話しかけると、話しかけたことばを LINE に送信するします。
次のように話しかけると、LINE に「ハローワールド」と送信します。
アレクサ、メモ通知 で ハローワールド を送って
「アレクサ」がウェイクワード。
「メモ通知」が呼び出し名。
「LINE に送信する」というのがインテント。
「ハローワールド」がスロット値です。
スキルを作成する
開発者アカウントで、Alexa開発者コンソールにアクセスします。
開発者アカウントの作成方法については、以下の記事を参考にしてください。
普段使っている Echo などと紐づいているアカウントで開発者アカウントを作成すれば、スキルを公開しなくても自分だけのスキルとして使うことができます。
Alexa開発者コンソールで「スキルの作成」をクリックします。
スキルの名前などを入力する画面が開くので、次のように入力します。
- スキル名:メモ通知
- プライマリロケール:日本語
- エクスペリエンスのタイプ:その他
- モデル:カスタム
- ホスティングサービス:Alexa-hosted(Python)
- ホスト地域:米国西部(オレゴン)
- Templates:スクラッチで作成
入力が終わったら「スキルを作成する」をクリックします。
呼び出し名を変更する
スキルを起動するための呼び出し名を変更します。
今回のスキルでは、「メモ通知」という呼び出し名にします。
呼び出し名を変更するには、左パネルの「呼び出し」→「スキルの呼び出し名」をクリックします。
スキルの呼び出し名に「メモ通知」と入力します。
インテントを変更する
このスキルのインテントは、「LINE に送信する」になります。
SendToLINEIntent というインテントを作成します。
スキルを作成すると、はじめから HelloWorldIntent というインテントが登録されているのでこれを変更します。
左パネルの「インテント」→「HelloWorldIntent」をクリックします。
インテント名を「HelloWorldIntent」から「SendToLINEIntent」に変更します。
サンプル発話にある「hello」、「ハロー」、「こんにちは」とすでに3つ登録されているので、これもゴミ箱アイコンをクリックして削除します。
サンプル発話は、インテントを呼び出すためのフレーズです。
今回の場合は、「~~を送って」というフレーズで動作するようにします。
LINE に送るメッセージは、ユーザーが話す「~~を送って」の ~~ の部分になります。
この ~~ の部分をスロットとして受け取ります。
SendToLINEIntent のサンプル発話に次のように入力し、Enterを押します。
{message} を送って
{ message } の部分がスロットになります。
SendToLINEIntent を呼び出すためのサンプル発話の登録ができました。
スロットを編集する
サンプル発話に messege というスロットを登録すると、インテントスロットにも message スロットが自動で作成されます。
インテントスロットに表示されている message をクリックして、スロットを編集します。
スロットタイプを「AMAZON.SearchQuery」、スロット入力を必須にして、Alexa の音声プロンプトに「ラインに送るメッセージを教えてください」と入力して Enter を押します。
スキルをビルドする
ここまで出来たら、スキルをビルドしましょう。
画面上部にある「保存」をクリックして、「スキルをビルド」をクリックします。
コードを変更する
AWS Lambda 関数でのコードを変更します。
画面上部の「コードエディタ」タブをクリックすると、コードエディタ画面に切り替わります。
すでにアレクサスキルが動作するためのコードが書かれています。
ここで、LINE に送信するためのコードを書いていきます。
LINE に送信するのには、LINE Notify というサービスを使います。
アクセストークンを取得する
LINE Notify を使うために、マイページにアクセスして、アクセストークンを取得します。
トークンの取得方法については、次の記事を参考にしてください。
LINE に送信するコード
LINE に送信するコードは、次のようになります。
POST リクエストをするために requests ライブラリをインポートしています。
import requests
def sendToLINE(message):
token = 'ここに発行したトークンを貼り付ける'
line_notify_api = 'https://notify-api.line.me/api/notify'
headers = {'Authorization': f'Bearer {token}'}
payload = {'message': message}
requests.post(line_notify_api, headers = headers, data = payload)
このコードをコードエディタに書きます。
次のコードの8行目と、22行目から29行目が追加したコードになります。
# -*- coding: utf-8 -*-
# This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK for Python.
# Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management,
# session persistence, api calls, and more.
# This sample is built using the handler classes approach in skill builder.
import logging
import requests
import ask_sdk_core.utils as ask_utils
from ask_sdk_core.skill_builder import SkillBuilder
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.dispatch_components import AbstractExceptionHandler
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_model import Response
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
def sendToLINE(message):
token = 'ここに発行したトークンを貼り付ける'
line_notify_api = 'https://notify-api.line.me/api/notify'
headers = {'Authorization': f'Bearer {token}'}
payload = {'message': message}
requests.post(line_notify_api, headers = headers, data = payload)
class LaunchRequestHandler(AbstractRequestHandler):
"""Handler for Skill Launch."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
~省略~
23行目の「ここに発行したトークンを貼り付ける」というところを、先ほど取得した LINE Notify のトークンに置き換えてください。
インテントハンドラーのコードを変更する
コードエディタでは、アレクサの各インテントに対応するコードが初めから書かれています。
「HelloWorldIntent」を「SendToLINEIntent」に変更しましたが、コードエディタでも同じように「HelloWorldIntent」を「SendToLINEIntent」に変更します。
コードエディタで、次のような HelloWorldIntentHandler クラスを探してください。
class HelloWorldIntentHandler(AbstractRequestHandler):
"""Handler for Hello World Intent."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_intent_name("HelloWorldIntent")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
speak_output = "Hello World!"
return (
handler_input.response_builder
.speak(speak_output)
# .ask("add a reprompt if you want to keep the session open for the user to respond")
.response
)
次のコードでいうと1行目と5行目を「HelloWorldIntent」から「SendToLINEIntent」に変更します。
class SendToLINEIntentHandler(AbstractRequestHandler):
"""Handler for Hello World Intent."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_intent_name("SendToLINEIntent")(handler_input)
スロットの値を取得する
LINE に送信するメッセージを取得します。
送信するメッセージは、message スロットに保存されているので、次のコードでスロットに保存されているテキストを取得します。
message = handler_input.request_envelope.request.intent.slots['message'].value
あとは message を sendToLINE 関数に渡します。
次のようにコードを追加してください。
class SendToLINEIntentHandler(AbstractRequestHandler):
"""Handler for Hello World Intent."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_intent_name("SendToLINEIntent")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
message = handler_input.request_envelope.request.intent.slots['message'].value
sendToLINE(message)
アレクサにしゃべってもらうことばを変える
speak_output という変数に格納されているテキストが、インテントを実行した後に、アレクサがしゃべることばになります。
speak_output を変更して、アレクサがしゃべることばを変更しましょう。
ここでは、「LINE に送った message を通知した」という内容をアレクサにしゃべってもらうようにします。
SendToLINEIntentHandler クラスの speak_output を次のように変更します。
class SendToLINEIntentHandler(AbstractRequestHandler):
"""Handler for Hello World Intent."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_intent_name("SendToLINEIntent")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
message = handler_input.request_envelope.request.intent.slots['message'].value
sendToLINE(message)
speak_output = f"{message}を通知しました。"
return (
handler_input.response_builder
.speak(speak_output)
# .ask("add a reprompt if you want to keep the session open for the user to respond")
.response
)
スキルで使うハンドラー登録を変更する
コードエディタの下の方にも「HelloWorldIntentHandler()」と書かれているコードがあるので、これも変更します。
sb = SkillBuilder()
sb.add_request_handler(LaunchRequestHandler())
sb.add_request_handler(SendToLINEIntentHandler())
sb.add_request_handler(HelpIntentHandler())
sb.add_request_handler(CancelOrStopIntentHandler())
sb.add_request_handler(FallbackIntentHandler())
sb.add_request_handler(SessionEndedRequestHandler())
sb.add_request_handler(IntentReflectorHandler()) # make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers
sb.add_exception_handler(CatchAllExceptionHandler())
変更が終われば、画面上部の「保存」→「デプロイ」の順にクリックします。
テスト
これでスキルの主要な機能は完成しました。
スキルをテストしてみましょう。
画面上部の「テスト」タブをクリックします。
テストが「非公開」になっているので、「開発中」に変更します。
左側の入力ボックスを使って、テストすることができます。
入力ボックスに「メモ通知でハローワールドを送って」と入力して、Enter をクリックします。
アレクサが「ハローワールドを通知しました。」と答えて、LINE にも「ハローワールド」と通知されます。
スキルは公開しなくても、自分のアカウントで設定している Echo などで実行することができます。
アレクサの実機でも試してみてください。
スキルの呼び出し方
アレクサのスキルの呼び出し方にはいろいろな方法があります。
次のドキュメントの例を参考にしてください。