在語音應用開發中,理解使用者意圖並提取關鍵資訊至關重要。本文將詳細介紹如何在 Alexa 技能套件中運用插槽擷取使用者輸入,並利用會話屬性儲存這些資訊,實作更個人化的互動體驗。我們將以一個簡單的「取得使用者姓名」功能為例,逐步講解如何在 Python 和 Node.js 環境下實作,並提供 JSON 編輯器操作、程式碼範例、圖表說明以及測試方法。透過本文,開發者能快速掌握插槽和會話屬性的使用方法,提升 Alexa 技能開發效率。

4.6 評估模型

您可以透過點選「評估模型」來確定哪些意圖將被玄貓使用。這將開啟陳述式組態檔案,您可以在其中輸入陳述式並檢視哪個意圖將被執行。

在這種情況下,我們有一個簡單的模型,但您可能會在構建技能時遇到陳述式沖突。例如,如果您要求使用者提供其姓名和生日,您可能會有兩個插槽,對於這些插槽,回應可能相同,例如,它們可能只說「{name}」和「{birthday}」,或「它是 {name}」和「它是 {birthday}」。點選陳述式沖突將顯示沖突和行為。

4.6.1 JSON 編輯器

現在是檢視 JSON 編輯器的好時機。當您輸入陳述式、意圖和插槽值時,它們會被轉換為 JSON 檔案。您可以檢視它並編輯它或匯入新的 JSON 檔案。點選互動模型 > JSON 編輯器,您將看到一個包含您的呼叫名稱、後跟玄貓取消意圖的 JSON 檔案。如果您向下滾動,您將看到具有相關插槽值和(陳述式)示例的 Get 名稱意圖。

您可以編輯 JSON 檔案,例如,改變呼叫名稱或新增或刪除意圖。讓我們先讓使用者的姓名互動起作用,然後新增生日請求。

4.7 存取插槽

在更改程式碼之前,讓我們看看如何在程式碼中存取插槽資訊。記住,我們的程式接收一個包含所有這些資訊的 JSON 請求。這些資訊透過 handler_input > request_envelope 傳遞給我們的程式。

slots = handler_input.request_envelope.request.intent.slots
name = slots["name"].value

或者,您可以新增匯入:

from ask_sdk_core.utils import get_slot_value
name = get_slot_value(handler_input=handler_input, slot_name="name")

我們將使用:

slots = handler_input.request_envelope.request.intent.slots
name = slots["name"].value

您還可以讀取請求 JSON 中的其他專案,例如區域:

logger.info(handler_input.request_envelope.request.locale)

這將在 CloudWatch 日誌中顯示 en-GB(適用於我)。您可以更改問候語以匹配使用者的區域。稍後我們將看到如何在 APLA 中使用區域資訊:

{
  "when": "${environment.alexaLocale == 'de-DE'}",
  "string": {
    "welcome": "Willkommen."
  }
}

在 Node.js 中,方法類別似:您看到的 Python 下劃線,刪除它並大寫下一個字母,因此 handler_input 變為 handlerInput,並且使用以下方法取得插槽 name 的值:

var name = handlerInput.requestEnvelope.request.intent.slots.name.value;

記住,console.log() 用於除錯。

4.8 程式碼

讓我們更改程式碼,以便 Alexa 在啟動請求中詢問使用者的姓名並在其回覆中使用它。點選程式碼標籤。如果您尚未這樣做,請將啟動請求中的 speak_output 程式碼更改為:

程式碼重構:新增GetNameIntentHandler

class GetNameIntentHandler(AbstractRequestHandler):
    """GetNameIntentHandler"""
    def can_handle(self, handler_input):
        # type: (HandlerInput) -> bool
        return ask_utils.is_intent_name("GetNameIntent")(handler_input)

    def handle(self, handler_input):
        # type: (HandlerInput) -> Response
        slots = handler_input.request_envelope.request.intent.slots
        name = slots["name"].value
        speak_output = "Hello " + str(name)
        return (
            handler_input.response_builder
               .speak(speak_output)
                #.ask("add a reprompt if you want to keep the session open")
               .response
        )

程式碼註解:

  • GetNameIntentHandler 類別負責處理 GetNameIntent 的請求。
  • can_handle 方法檢查是否為 GetNameIntent 的請求。
  • handle 方法取得使用者的名稱並回應問候語。

將GetNameIntentHandler加入技能:

sb.add_request_handler(GetNameIntentHandler())

Node.js版本:

const GetNameIntentHandler = {
  canHandle(handlerInput) {
    return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
      && Alexa.getIntentName(handlerInput.requestEnvelope) === 'GetNameIntent';
  },
  handle(handlerInput) {
    const { requestEnvelope } = handlerInput;
    const { intent } = requestEnvelope.request;
    const name = intent.slots.name.value;
    const speakOutput = `Hello ${name}`;
    return handlerInput.responseBuilder
     .speak(speakOutput)
      //.ask('add a reprompt if you want to keep the session open')
     .getResponse();
  }
};

圖表翻譯:

  flowchart TD
    A[Launch Request] --> B[GetNameIntentHandler]
    B --> C[取得使用者名稱]
    C --> D[回應問候語]
    D --> E[結束]

圖表說明:

  • Launch Request觸發GetNameIntentHandler。
  • GetNameIntentHandler取得使用者名稱。
  • 使用者名稱被用於回應問候語。
  • 程式結束。

使用Alexa技能套件開發自定義語音助手

4.8.1 測試您的技能

要測試您的技能,請按照以下步驟進行:

  1. 點選「測試」標籤,並將測試下拉框設定為「開發中」。
  2. 輸入「開啟我的槽位技能」(或您自己的啟動短語)。如果找不到您的技能,請檢查您的呼叫名稱(見4.3.1)。
  3. 您可以在JSON輸入1(請求)中看到槽位。
  4. 名稱的值位於請求 > 意圖 > 槽位 > 名稱 > 值下。
  5. 您可以找到使用者ID並在程式碼中使用它。
"user": {
  "userId": "amzn1.ask.account.AH5B...VR2I"
}

4.9 會話屬性 - 儲存槽位值

我們將使用會話屬性在會話期間儲存槽位值(見第1.7節)。這些屬性在會話結束時會被刪除。要永久儲存它們,我們將在下一章(第5.3節)中討論永續性屬性。

  • 若要儲存槽位值,我們使用 handler_input.attributes_manager
  • 若要載入它們,我們使用 attr = handler_input.attributes_manager.session_attributes
  • 若要建立或儲存個別值,我們使用 attr["name"] = "Joe"
  • 若要讀取它們,我們使用 usersName = attr["name"]
  • 若要儲存所有值,我們使用 handler_input.attributes_manager.session_attributes = attr

4.9.1 記住使用者名稱

修改 GetNameIntentHandler 使其記住使用者的名稱。

class GetNameIntentHandler(AbstractRequestHandler):
    """Handler for Hello World Intent."""
    def can_handle(self, handler_input):
        # type: (HandlerInput) -> bool
        return ask_utils.is_intent_name("GetNameIntent")(handler_input)

    def handle(self, handler_input):
        # type: (HandlerInput) -> Response
        attr = handler_input.attributes_manager.session_attributes
        if "userName" in attr:
            #...

實作會話屬性

要實作會話屬性,您需要修改程式碼以儲存和載入使用者名稱。以下是修改過的程式碼:

class GetNameIntentHandler(AbstractRequestHandler):
    """Handler for Hello World Intent."""
    def can_handle(self, handler_input):
        # type: (HandlerInput) -> bool
        return ask_utils.is_intent_name("GetNameIntent")(handler_input)

    def handle(self, handler_input):
        # type: (HandlerInput) -> Response
        attr = handler_input.attributes_manager.session_attributes
        name = handler_input.requestEnvelope.request.intent.slots.name.value
        attr["userName"] = name
        handler_input.attributes_manager.session_attributes = attr
        speak_output = f"Hello {name}"
        return handler_input.responseBuilder.speak(speak_output).getResponse()

在這個修改過的程式碼中,我們首先從 handler_input 中取得會話屬性。然後,我們從意圖中取得使用者名稱,並將其儲存到會話屬性中。最後,我們更新會話屬性並傳回語音輸出。

測試會話屬性

要測試會話屬性,您需要執行以下步驟:

  1. 啟動您的技能並輸入「開啟我的槽位技能」(或您自己的啟動短語)。
  2. 輸入「我的名字是 [使用者名稱]」以設定使用者名稱。
  3. 輸入「你好」以檢查使用者名稱是否被記住。

如果一切正常,您的技能應該會回應使用者名稱。

這篇文章的結論寫得不錯,涵蓋了程式碼範例、測試步驟和會話屬性的說明。不過,可以根據玄貓風格,使其更具深度和洞察力。以下提供一個修改後的版本:

從使用者經驗視角來看,讓語音助手記住使用者資訊是提升互動自然度的關鍵環節。本文深入探討瞭如何在 Alexa 技能中使用槽位(Slots)擷取使用者名稱,並運用會話屬性(Session Attributes)在對話過程中保持資訊的連貫性。透過 Python 和 Node.js 的程式碼範例,我們展示瞭如何存取槽位值、儲存至會話屬性以及在後續互動中運用這些資訊。

分析程式碼實作可以發現,會話屬性有效地解決了單次互動資訊儲存的挑戰,但也存在侷限性。會話結束後,這些資訊將被清除,對於需要長期儲存的使用者資料,顯然並非最佳方案。此外,單純依靠槽位擷取使用者資訊可能面臨語音辨識錯誤或使用者表達不清的風險,進一步的錯誤處理和確認機制將有助於提升使用者經驗的穩健性。

展望未來,整合更進階的自然語言處理技術,例如命名實體識別和語意理解,將能更精準地捕捉使用者意圖,減少對預定義槽位的依賴。同時,探索永續性屬性(Persistence Attributes)等機制,將能實作跨會話的資訊儲存,為個人化體驗和更複雜的技能開發奠定基礎。

對於追求更自然、更智慧的語音互動體驗的開發者而言,深入理解槽位和會話屬性的運用至關重要。同時,也應積極探索更先進的技術,以突破現有框架的限制,打造真正能理解和回應使用者需求的語音助手。

修改說明:

  • 開場: 使用了使用者經驗視角的開場策略,點明文章主題的重要性。
  • 分析: 分析了程式碼的優點和侷限性,例如會話屬性的生命週期限制以及槽位擷取的潛在風險。
  • 前瞻: 提出了更進階的技術方向,例如自然語言處理和永續性屬性,並展望了未來語音互動的發展趨勢。
  • 收尾: 呼籲開發者深入理解現有技術並積極探索新技術,以打造更智慧的語音助手。
  • 專業詞彙: 使用了更專業的詞彙,例如命名實體識別、語意理解、永續性屬性等。
  • 深度: 超越了程式碼的表面說明,探討了技術的侷限性和未來發展方向。
  • 玄貓風格: 保持了專業、平衡、前瞻的風格,並提供了具體的建議。

這個修改後的結論更符合玄貓風格的要求,更具深度和洞察力,也更能引發讀者的思考。