1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

アレクサスキルで自由入力の手順 【2024/11版】

Posted at

誰向けか

アレクサスキルで自由入力をしたいが、詰まっている人

記載しないこと

長くなってしまうので、以下は割愛します
※後述の「参考にした記事」に説明がありますので、興味があればそちらを参照してください

  • アレクサスキルのゼロからの作成手順
    • 本記事ではIntentの作成、既存Lambdaの関数に処理を追記する形です
  • そもそも自由入力とはなにか
  • 自由入力の本来の使い方、仕組み

自由入力の使用の背景

アレクサ経由で「簡単にAIに質問や相談」ができるシステムを個人開発(以下)で作成
ただし、「キャリアフレーズ」という仕様があるおかげで使い勝手がとても悪かった

※当時は「質問」を「キャリアフレーズ」に設定していました
例:質問 {プログラミングのFlutterって何?}
 ↓
{}の中身がバックエンド側のLambdaに連携され、AIにリクエストとして送信、レスポンスをそのまま返し、レスポンス内容をアレクサが喋ってくれる

記事執筆の背景

以下の記事がとても参考になりましたが、「私のやり方が悪かった」のか「当時から仕様が変わった」のか分かりませんが、2024/11時点で成功しませんでした
※「スキルがリクエストに正しく応答できませんでした」と言われてしまいました

悪戦苦闘した結果「自由入力」ができるようになりましたので、私の対応方法を残し、悩んでいる人の一助になりたかった

参考にした記事

「自由入力の概念」、「最終的に使えるようになった足がかり」にもなりました。
この場を借りてお礼申し上げます。

自由入力の手順

①アレクサスキル側の対応

コンソールの手順

jsonだけ欲しい人は読み飛ばしてください
※余談ですが、このコンソールで日本語設定してるのにほぼ英語なのは私だけですかね?
 数ヶ月前は日本語だったんですが...

1. Intentの追加

ここでは名前を「ChatGPTIntent」とします

名前は任意ですが、Lambdaのコードでこの名前を指定する箇所があります

image.png

2. slotの設定

重要!! Sample Utterancesは何も設定しません

image.png

slot名を設定し、+アイコンをクリック
ここでは名前を「prompt」とします
image.png

typeは「AMAZON.SearchQuery」です
Edit Dialogをクリック(↓へ続く)
image.png

3. Dialogの設定

Dialogタブでそれぞれ以下を入力後、+アイコンをクリック
すべて設定できたら画面左上のSaveボタンをクリック

  • Is this slot required to fulfill the intent?
    • ONに変更
  • Alexa speech prompts
    • 必須なのでなにかしら入力
    • ※本来はアレクサがslotを収集する際に使用しますが、今回はLambdaで「アレクサの収集処理」をカット(行わないように)するため、実際には使用されません
  • User utterances
    • ↑で作成したslot名を{}付きで入力

image.png

3. Dialog Delegation Strategyの設定

「disable auto delegation」に変更

重要!!
ここで「自動デリゲートを無効」にしておかないと、Lambdaでアレクサのslot収集がカットできず、動作確認でアレクサに「スキルがリクエストに正しく応答できませんでした」と言われます
ちなみに私はここで躓き、10時間ほど時間を溶かしました

image.png

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

おわりに

以上になります!
質問などありましたらコメントしていただければ、分かる範囲で答えます!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?