誰向けか
アレクサスキルで自由入力をしたいが、詰まっている人
記載しないこと
長くなってしまうので、以下は割愛します
※後述の「参考にした記事」に説明がありますので、興味があればそちらを参照してください
- アレクサスキルのゼロからの作成手順
- 本記事ではIntentの作成、既存Lambdaの関数に処理を追記する形です
- そもそも自由入力とはなにか
- 自由入力の本来の使い方、仕組み
自由入力の使用の背景
アレクサ経由で「簡単にAIに質問や相談」ができるシステムを個人開発(以下)で作成
ただし、「キャリアフレーズ」という仕様があるおかげで使い勝手がとても悪かった
※当時は「質問」を「キャリアフレーズ」に設定していました
例:質問 {プログラミングのFlutterって何?}
↓
{}の中身がバックエンド側のLambdaに連携され、AIにリクエストとして送信、レスポンスをそのまま返し、レスポンス内容をアレクサが喋ってくれる
記事執筆の背景
以下の記事がとても参考になりましたが、「私のやり方が悪かった」のか「当時から仕様が変わった」のか分かりませんが、2024/11時点で成功しませんでした
※「スキルがリクエストに正しく応答できませんでした」と言われてしまいました
悪戦苦闘した結果「自由入力」ができるようになりましたので、私の対応方法を残し、悩んでいる人の一助になりたかった
参考にした記事
「自由入力の概念」、「最終的に使えるようになった足がかり」にもなりました。
この場を借りてお礼申し上げます。
自由入力の手順
①アレクサスキル側の対応
コンソールの手順
jsonだけ欲しい人は読み飛ばしてください
※余談ですが、このコンソールで日本語設定してるのにほぼ英語なのは私だけですかね?
数ヶ月前は日本語だったんですが...
1. Intentの追加
ここでは名前を「ChatGPTIntent」とします
名前は任意ですが、Lambdaのコードでこの名前を指定する箇所があります
2. slotの設定
重要!! Sample Utterancesは何も設定しません
slot名を設定し、+アイコンをクリック
ここでは名前を「prompt」とします
typeは「AMAZON.SearchQuery」です
Edit Dialogをクリック(↓へ続く)
3. Dialogの設定
Dialogタブでそれぞれ以下を入力後、+アイコンをクリック
すべて設定できたら画面左上のSaveボタンをクリック
- Is this slot required to fulfill the intent?
- ONに変更
- Alexa speech prompts
- 必須なのでなにかしら入力
- ※本来はアレクサがslotを収集する際に使用しますが、今回はLambdaで「アレクサの収集処理」をカット(行わないように)するため、実際には使用されません
- User utterances
- ↑で作成したslot名を{}付きで入力
3. Dialog Delegation Strategyの設定
「disable auto delegation」に変更
重要!!
ここで「自動デリゲートを無効」にしておかないと、Lambdaでアレクサのslot収集がカットできず、動作確認でアレクサに「スキルがリクエストに正しく応答できませんでした」と言われます
ちなみに私はここで躓き、10時間ほど時間を溶かしました
4. 保存とビルド
↑がすべて設定できたら画面左上のSaveボタンをクリックし、「Build skill」をクリック
重要!!
ビルドしないとスキルに反映されないため、ハマりやすいです
json
↑のコンソール手順を行った結果、以下のようなjsonが作成されます
流用する際、invocationNameは任意のスキル名にしてください
※promptsのidは全く同じだと上手くいかないかもです
その場合は↑の「コンソールの手順」でお願いします
サンプル
{
"interactionModel": {
"languageModel": {
"invocationName": "{任意のスキル名}",
"intents": [
{
"name": "ChatGPTIntent",
"slots": [
{
"name": "prompt",
"type": "AMAZON.SearchQuery",
"samples": [
"{prompt}"
]
}
],
"samples": []
},
{
"name": "AMAZON.HelpIntent",
"samples": []
},
{
"name": "AMAZON.CancelIntent",
"samples": [
"バイバイ",
"終わり"
]
},
{
"name": "AMAZON.StopIntent",
"samples": []
},
{
"name": "AMAZON.NavigateHomeIntent",
"samples": []
}
],
"types": []
},
"dialog": {
"intents": [
{
"name": "ChatGPTIntent",
"delegationStrategy": "SKILL_RESPONSE",
"confirmationRequired": false,
"prompts": {},
"slots": [
{
"name": "prompt",
"type": "AMAZON.SearchQuery",
"confirmationRequired": false,
"elicitationRequired": true,
"prompts": {
"elicitation": "Elicit.Slot.1311813009944.922337381744"
}
}
]
}
],
"delegationStrategy": "ALWAYS"
},
"prompts": [
{
"id": "Elicit.Slot.1311813009944.922337381744",
"variations": [
{
"type": "PlainText",
"value": "なにか言ってみてください。"
}
]
}
]
}
}
②Lambda側の手順
前提
LambdaはPythonでデコレータを使用しています
※大した量ではないため、ノーデコレータの方やTypeScriptでも参考になると思います
コード
1. ライブラリのimport
from ask_sdk_model.dialog import ElicitSlotDirective
from ask_sdk_model import Intent, IntentConfirmationStatus, Slot, SlotConfirmationStatus
2. 自由入力の初期化
LaunchRequestと自由入力を処理するhandlerで使い回すため、グローバル変数として宣言します
# インテント名、スロット名はAlexaスキル側の設定と合わせる
intent_name = "ChatGPTIntent"
slot_name = "prompt"
directive = ElicitSlotDirective(
slot_to_elicit=slot_name,
updated_intent=Intent(
name=intent_name,
confirmation_status=IntentConfirmationStatus.NONE,
slots={
slot_name: Slot(
name=slot_name,
value="",
confirmation_status=SlotConfirmationStatus.NONE,
)
},
),
)
3. LaunchRequestで自由入力の初期化
「.add_directive(directive)」することが重要です
他のコードは何でもOKです
これにより、スキルを起動した時点で「自由入力」を受け付ける状態になります
@sb.request_handler(can_handle_func=is_request_type("LaunchRequest"))
def launch_request_handler(handler_input):
# type: (HandlerInput) -> Response
speech_text = "エーアイモードに入ります。"
return (
handler_input.response_builder.speak(speech_text)
.ask("なにか質問ですか")
# 自由入力の初期化
.add_directive(directive)
.response
)
4. 自由入力の処理
ここでも最後に「.add_directive(directive)」することが重要です
これにより、レスポンスを返却した後も常に「自由入力」を受け付ける状態になります
@sb.request_handler(can_handle_func=is_intent_name("ChatGPTIntent"))
def chat_gpt__intent_handler(handler_input):
# type: (HandlerInput) -> Response
# スロットからAIにリクエストする文言を取得
user_utterance = get_user_utterance(handler_input)
# AIの処理を呼び出し
chat_response = get_chat_response(user_utterance)
# Alexaのレスポンスを生成
return (
handler_input.response_builder.speak(chat_response)
# 自由入力の初期化
.add_directive(directive).response
)
# ユーザーの発話を取得
def get_user_utterance(handler_input: HandlerInput) -> str:
# スロットからAIにリクエストする文言を取得
user_utterance = handler_input.request_envelope.request.intent.slots["prompt"].value
# 不要な空白を削除
user_utterance.strip()
return user_utterance
余談
Amazon自体でもアレクサでAIを使えるようにするプロジェクトが動いてるようです
2024/10リリースなんて噂もありましたが、特になかったですね
有料プラン(5$~10$)らしいですが、リリースされたら1回使ってみようかなと思います
※自分でAIのスキル作ったは良いものの、スキルの初回起動がコンスタントに遅い(4~5秒)ので使用頻度かなり低いですww
おわりに
以上になります!
質問などありましたらコメントしていただければ、分かる範囲で答えます!