今回は、Alexaスキル開発入門として音声スキルの HelloWorld 的存在である「豆知識スキル」を、AWSアカウントを用いずに(Amazon.co.jpアカウント + Alexa-hostedを用いて)開発する方法をお伝えしたいと思いいます
- VUI(Voice user interface)を理解できるようになる
- Alexaスキルを作成できるようになる
- 事前にAmazon.co.jpアカウントをご用意ください(Amazon.co.jp ECショッピングアカウントをお持ちの方は、それが「Amazon.co.jpアカウント」となります、アカウントの新規作成は特段必要ありません)
- Amazon.co.jpアカウント作成でお困りの際は「Alexa Blogs:Alexa 開発者アカウント作成時のハマりどころ」をご参照ください
- パソコン(Windows/MacOS X/Linux 他)
- インターネット環境(Wi-Fi/有線LAN)
- キーボード
- マウス
- ディスプレイ
- ブラウザ(Chromeブラウザ推奨)
- Amazonが販売・サービス提供しているAlexaデバイスで利用する「音声スキル」のこと
- 「Alexaスキル」は「スキルを有効」にすることでお持ちのAlexaデバイスで音声スキルを利用可能となる
- Alexaスキルの呼び出し方は「アレクサ、<スキル名> を開いて」と話かけることで実行可能
- 「Amazon開発者ポータル」から開発者独自のAlexaスキル(カスタムスキルと呼ぶ)を作成し、日本国内にAlexaスキルを公開することが可能
- Alexaスキル(カスタムスキル)を開発する開発言語には、主にNode.jsが用いられる(Pythonでの開発も可能)
- AWSアカウント不要でAlexaスキルを開発することができる方法のひとつ
- 本来必要となるAWSアカウント(AWS Lambdaなどのバックエンド部分)は、Amazonが提供してくれているものを利用させてもらう形式をとる(「Alexa-hostedスキル」のLambdaプログラム部はバージニアリージョン(us-east-1)で動作)
- そのため、S3やDynamoDBを用いたLambdaプログラムを作成する際は、「Alexa-hostedスキル」独自の永続化プログラム記述が必要となる
- Alexa-hostedの利用は個人開発やPoC開発までにとどめ、業務利用する際は Amazon Alexa + AWS(AWS Lambda)の構成で開発をした方が好ましい
- 声で操作できる
- 声の操作に加えディスプレイ表示も可能
- 両手がふさがっている状態(料理中など)であっても音声スキルを利用可能
- Alexaスキル(カスタムスキル)を公開することに費用はかからない
- Amazon.co.jpアカウントさえあれば、すぐにAlexaスキル開発をおこなえる
- Alexaデバイスに限らず、WindowsPC、スマートフォン、FireTVでAlexaスキルが利用可能
- Alexaスキル(カスタムスキル)を「有効」にしてもらえないと、一般の方からご利用していただけない
- スキル名を覚えてもらう必要があり、スキル名を忘れるとAlexaスキル(カスタムスキル)を呼び出してもらえない
- 周囲の雑音に弱い、主な利用シーンは室内となる
- Alexaスキルの非公開利用:無料
- Alexaスキルの公開:無料
- Alexa-hostedを用いたAlexaスキルの運用:無料
- Alexa-hostedを用いず別途AWS Lambdaによるバックエンド(エンドポイント)開発をおこなった場合:AWS Lambdaの運用コスト
- 個人ユースであれば、まずはAlexa-hostedを用いたスキル開発を無料で体験いただき知識を高めることをおすすめします
ユーザー:「アレクサ(wake word)、ピカチュウトーク(skill name) を 開いて(launch phrase)」
- 起動フレーズ(launch)は「起動して」「実行して」「スタートして」なども使える
- 接続詞「で」の使用は原則禁止とのこと
アレクサ:「ご利用の日付と時間をお知らせください」
ユーザー:「今日(slot)の15(slot)時」
- slotは変数のこと
- slotには変数の型(AMAZON.DATE、AMAZON.NUMBER)が利用できる
- <今日>は、AMAZON.DATE スロット
- <15>は、AMAZON.NUMBER スロット
ユーザー:「ニュースを聞かせて(NewsIntent)」
ユーザー:「運勢を占って(FortuneIntent)」
ユーザー:「今日(slot)のニュースを聞かせて(NewsIntent)」
- NewsIntentにAMAZON.DATEスロットがひもづく関係
ユーザー:「ニュースを聞かせて」
ユーザー:「ニュースを知りたい」
ユーザー:「ニュースを読んで」
ユーザー:「ニュース!!」
- すべて NewsIntent の呼び出しフレーズとなる
- 人が言いそうな発話パターンを洗い出し、あらかじめサンプル発話として登録すると音声認識率がアップする
- Skill name(スキル名)
- Invocation Name(スキル呼び出し名)
- Intent Schema(インテントの定義)
- Intent(インテント:人間の「意図」)
- Slot(スロット:変数みたいなもの)
- Sample Utterances(サンプル発話:インテント呼び出しフレーズ)
- Endpoint(エンドポイント Lambda のARN)
サンプル発話登録不要、標準で使える、ビルトインインテント
- AMAZON.YesIntent ・・・「はい/オッケー/いいよ」
- AMAZON.NoIntent ・・・「いいえ/ノー」
Amazon様仕様により必須となるインテント
- AMAZON.CancelIntent ・・・「キャンセル/取り消し/やっぱりやめる」
- AMAZON.StopIntent ・・・「ストップ/止めて/中止」
- AMAZON.HelpIntent ・・・「ヘルプ/どうすればいいの/使い方を教えて」
スロット登録不要、標準で使える、ビルトインスロット
- AMAZON.DATE、AMAZON.TIME、AMAZON.NUMBERなど
→Amazonが用意したスロット登録済み用語
→音声認識精度が高く、Good!
基本のリクエストは3つ
- ‘LaunchRequest’ ・・・インテント無し起動
- ‘IntentRequest’ ・・・インテント指定発話
- ‘SessionEndedRequest’ ・・・予期せぬ終了
IntentRequestには、子供Intentがいる
- 必須インテント3兄弟(CancelIntent、StopIntent、HelpIntent)
- はい/いいえインテント姉妹(YesIntent、NoIntent)
- ユーザ定義インテント(NewsIntent、FortuneIntent)
ユーザー:「アレクサ、新幹線予約 を開いて」
アレクサ:「新幹線予約へようこそ、このスキルでは新幹線チケットをご購入いただけます、ご利用の日付と時間をお知らせください」
ユーザー:「今日の15時」
アレクサ:「〇月〇日の15時ですね、自由席か指定席のどちらになさいますか?」
ユーザー:「自由席でお願い」
アレクサ:「自由席ですね、チケット購入を確定しますか?」
ユーザー:「はい」
アレクサ:「チケット購入を確定しました、ご利用ありがとうございます」
- ユーザ発話から、スキル呼び出し名 を決定する
ユーザー:「アレクサ、新幹線予約 を開いて」
- インテント指定なしの初回起動は ‘LaunchRequest’ が呼ばれる
- ユーザ発話から、Intent と Slot を抽出する
ユーザー:「今日の15時」
- AMAZON.DATE と AMAZON.NUMBERが使えそう
- Intent名は、DateAndTimeIntent にするとよさそうかな
- サンプル発話は、DateAndTimeIntent {DATE(slot)} の {TIME(slot)} 時 でいけそうかな
- ユーザ発話から、Intent と Slot を抽出する
ユーザー:「自由席でお願い」
- ビルトインは使えなさそうだから、カスタムスロットにようかな
- LIST_OF_SEATスロットを定義して、値に「自由席」と「指定席」を設定しようかな
- Intent名は、SeatIntent にするとよさそうかな
- サンプル発話は、SeatIntent {SEAT(slot)} でお願い でいけそうかな
`
- ユーザ発話から、Intent と Slot を抽出する
ユーザー:「はい」
- これはAMAZON.YesIntent でよさそうだ
- Slot定義は不要でいけるね
- サンプル発話には、AMAZON.YesIntent 購入します も加えておこうかな
- ここからは、AWSアカウントを用いずに「Amazon.co.jpアカウント + Alexa-hosted」を用いて「豆知識スキル」を開発する方法をお伝えしたいと思いいます
- 既にAmazon.co.jpアカウント(JP Amazon(Amazon.co.jp))をお持ちの方は、特段対応は必要ありません
- Amazon.co.jpアカウントをお持ちでない方は、Amazon.co.jp ECショッピングサイトから、アカウントの新規登録をおこなってください
- US Amazon(Amacon.com)のアカウントをお持ちで、JP Amazon(Amazon.co.jp)と同じパスワードを登録されている方は、日本環境のAlexaではなく、アメリカ環境のAlexaスキルを開発することになってしまいますので、「Alexa Blogs:Alexa 開発者アカウント作成時のハマりどころ」を参照し、US AmazonとJP Amazonのパスワードを異なるパスワードに事前に変更しておくことをおすすめします
- ログインメールアドレス、パスワードに、Amazon.co.jpアカウントを入力します
- Amazon開発者コンソール
- ヘッダーメニューから「Alexa」をクリックする
- スキル名:秘密の豆知識(任意)
- プライマリロケール:日本語(日本)
- モデル:カスタム
- バックエンドリソース:Alexa-hosted(Node.js)
- 今回は、Alexa-hosted(Node.js)を選択肢、スキルを作成します
- リージョンは「バージニア北部」とします
- Alexaスキル作成に1分ほど待ちます
- 呼び出し > スキルの呼び出し名 をクリックし、「スキルの呼び出し名」を確認する
- インテント をクリックし、「インテント」を確認する
- インテント > GetNewFactIntent をクリックし、サンプル発話およびスロットを確認する
- インテント > JSONエディター をクリックし、JSON定義を確認する
- スロットタイプをクリックし、「スロットタイプ」を確認する
- 「コードエディタ」をクリックし、「プログラムソース」を確認する
- index.jsファイルが、Alexaスキルのプログラム本体になります
- プログラムソースを修正した場合は、保存、デプロイをおこない修正内容を反映する必要があります
- また、Alexaスキルの各種設定を変更した際は、「ビルド」をおこない会話モデルの変更内容を反映する必要がります
「テスト」をクリックし、「開発中」ドロップダウンリストを選択する
- 「マイクアイコン」をクリックし、「秘密の豆知識 を開いて」と発話する
- ブラウザのマイクが有効になっていない場合は、キーボードを用いて「秘密の豆知識 を開いて」と入力してみてください
- 「JSON入力」から、「”request”」を探し、「”LaunchRequest”」(ローンチリクエストインテント/起動インテント)がリクエストされていることを確認する
- プログラムソースから「LaunchRequest」のプログラム部分を参照確認してみましょう
“request”: {
“type”: “LaunchRequest”,
“requestId”: “amzn1.echo-api.request.********-****-****-****-************”,
“locale”: “ja-JP”,
“timestamp”: “2022-09-27T07:33:53Z”,
“shouldLinkResultBeReturned”: false
}
- 「JSON出力」から、「”response”」を探し、「”ssml”(発話内容)」を確認してみましょう
- プログラムソースから「LaunchRequest」のプログラム部分を参照確認してみましょう
“response”: {
“outputSpeech”: {
“type”: “SSML”,
“ssml”: “知ってましたか?水星の一年はたった88日です。”
},
- 画面を下にスクロールし、カード表示(ディスプレイ表示)を確認しましょう
- 「JSON出力」から「”card”」を探し、「”card”(表示内容)」を確認してみましょう
- プログラムソースから「LaunchRequest」のプログラム部分を参照確認してみましょう
“card”: {
“type”: “Simple”,
“title”: “スペース 日本語版豆知識”,
“content”: “水星の一年はたった88日です。”
},
- 今回開発で用いたAmazon.co.jpアカウントに紐づけている「Echoデバイス」をお持ちの方は、Echoデバイスに向かって「アレクサ、秘密の豆知識 を開いて」と発話してみましょう
- Amazon.co.jpアカウントに紐づけている「Echoデバイス」であれば、開発中のAlexaスキル(カスタムスキル)をEchoデバイス実機で動作確認することができます
- プログラムのmain処理はindex.jsファイルの「exports.handler」から始まる部分が該当します
- もしもAlexaスキルの各種設定を変更し、インテントを追加した場合は、インテントに該当するHandlerを追記する必要があります
- このmain処理にて、Alexaが音声認識した「リクエストのインテント」に該当するハンドラーが呼び出されます
exports.handler = skillBuilder
.addRequestHandlers(
GetNewFactHandler,
HelpHandler,
ExitHandler,
FallbackHandler,
SessionEndedRequestHandler,
SetPersonalizedFactPreferencesHandler
)
.addRequestInterceptors(LocalizationInterceptor)
.addErrorHandlers(ErrorHandler)
//define personalized persistence adapter for preference storage.
.withPersistenceAdapter(personalizationStorageUtil.personlizedPersitenceAdapter())
.withCustomUserAgent(‘sample/basic-fact/v2’)
.lambda();
- 「アレクサ、秘密の豆知識 を開いて」と発話し、Alexaによって’LaunchRequest’がリクエストされたと音声認識された場合は、GetNewFactHandlerが呼び出されます
- canHandle部では、どのインテントが呼び出された場合にハンドラが起動するかを定義しています
- canHandle部で、request.type === ‘LaunchRequest’ を定義していたため、GetNewFactHandlerが実行されました
- handle部には、レスポンスで応答したい処理内容が記載されています
- speakOutput 変数には、レスポンス応答する発話内容がセットされています
- 発話内容自体は、別のファイルを参照するようにプログラムされているようです
const GetNewFactHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
// checks request type
return request.type === ‘LaunchRequest’
|| (request.type === ‘IntentRequest’
&& request.intent.name === ‘GetNewFactIntent’);
},
async handle(handlerInput) {
const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
//gets fact topic name
var topicName = await getTopicName(handlerInput, requestAttributes);
// gets a random fact by assigning an array to the variable
// the random item from the array will be selected by the i18next library
// the i18next library is set up in the Request Interceptor
const randomFact = requestAttributes.t(getTopicLookupText(topicName, requestAttributes));
const name = personalizationUtil.getPersonalizedPrompt(handlerInput);
// concatenates a standard message with the random fact
var speakOutput = “”
if (name && name.length > 0) {
speakOutput = requestAttributes.t(‘GET_FACT_MESSAGE_PERSONALIZED’, name) + randomFact
} else {
speakOutput = requestAttributes.t(‘GET_FACT_MESSAGE’, name) + randomFact
}
return handlerInput.responseBuilder
.speak(speakOutput)
// Uncomment the next line if you want to keep the session open so you can
// ask for another fact without first re-opening the skill
.reprompt(requestAttributes.t(‘HELP_REPROMPT’))
.withSimpleCard(requestAttributes.t(‘SKILL_NAME’, requestAttributes.t(topicName)), randomFact)
.getResponse();
},
};
- languageStrings.jsファイルには、レスポンス応答するAlexaの発話内容があらかじめ定義されているようです
- 豆知識のAlexa発話内容を変更したい場合は、この部分を修正してみるとよいでしょう
- プログラムソースを修正した際は、保存、デプロイを必ずおこなうようにしましょう
ja: {
translation: {
SPACE: ‘スペース’,
FOOTBALL: ‘フットボール’,
SKILL_NAME: ‘%s 日本語版豆知識’,
GET_FACT_MESSAGE: ‘知ってましたか?’,
GET_FACT_MESSAGE_PERSONALIZED: ‘わかりました%sここにあなたの事実があります’,
HELP_MESSAGE: ‘豆知識を聞きたい時は「豆知識」と、終わりたい時は「おしまい」と言ってください。どうしますか?’,
HELP_REPROMPT: ‘どうしますか?’,
ERROR_MESSAGE: ‘申し訳ありませんが、エラーが発生しました’,
PREFERENCE_ERROR: ‘申し訳ありませんが、個人のIDを取得できません’,
STOP_MESSAGE: ‘さようなら’,
CONFIRMATION_MESSAGE: ‘わかりました%s、お気に入りのトピックとして%sを追加しました’,
SPACE_FACTS:
[
‘水星の一年はたった88日です。’,
‘金星は水星と比べて太陽より遠くにありますが、気温は水星よりも高いです。’,
‘金星は反時計回りに自転しています。過去に起こった隕石の衝突が原因と言われています。’,
‘火星上から見ると、太陽の大きさは地球から見た場合の約半分に見えます。’,
‘木星の1日は全惑星の中で一番短いです。’,
‘天の川銀河は約50億年後にアンドロメダ星雲と衝突します。’,
],
FOOTBALL_FACTS:
[
‘サッカーは、地球上で最も注目され、最もプレイされているスポーツです’,
‘これまでに得点した最速のゴールはわずか2.4秒でした’,
‘ワールドカップで優勝したのは8か国だけです’,
],
}
},
いかがでしたでしょうか?以上でAlexaスキル(カスタムスキル)の開発がひととおり完了しているかと思います
今回の記事が、少しでも、、、みなさまの学習の参考になれば幸いです
2022/09/27 たかひろ