在開發 Alexa 技能時,有時需要在沒有使用者明確請求的情況下主動推播通知或執行特定動作。本文將介紹如何利用主動事件和通知推播功能實作此目標。首先,需要修改技能構建器,新增 ProactiveEventHandler 以處理 Alexa 主動事件。接著,實作 ProactiveEventHandler 的 can_handle 和 handle 方法,用於判斷事件型別及處理事件邏輯。設定檔中需加入 SKILL_PROACTIVE_SUBSCRIPTION_CHANGED 事件,確保技能能接收 Alexa 的主動事件通知。推播通知則需透過 Login with Amazon (LWA) 服務取得 Access Token。利用 Python requests 模組,向 LWA API 傳送 POST 請求,包含 Client ID、Client Secret 等必要資訊,即可取得 Access Token。最後,使用 Access Token 呼叫 Alexa Proactive Events API,即可傳送通知到使用者裝置。

步驟1:修改技能構建器

首先,需要修改技能構建器(SkillBuilder)以新增主動事件處理器。這涉及到在技能構建器中新增一行程式碼,以便能夠處理主動事件。

sb = SkillBuilder()
sb.add_request_handler(LaunchRequestHandler())
sb.add_request_handler(HelloWorldIntentHandler())
sb.add_request_handler(ProactiveEventHandler())  # 新增主動事件處理器
sb.add_request_handler(HelpIntentHandler())

步驟2:實作主動事件處理器

接下來,需要實作主動事件處理器本身。這涉及到建立一個新的類別,繼承自AbstractRequestHandler,並實作can_handlehandle方法。

class ProactiveEventHandler(AbstractRequestHandler):
    """Handler for Proactive Events."""
    def can_handle(self, handler_input):
        # type: (HandlerInput) -> bool
        return ask_utils.is_request_type("AlexaSkillEvent.ProactiveSubscriptionChanged")(handler_input)

    def handle(self, handler_input):
        # type: (HandlerInput) -> Response
        logger.info("Proactive event changed userId, api endpoint and subscription")
        logger.info(ask_utils.request_util.get_user_id(handler_input))
        logger.info(handler_input.request_envelope.request.body.subscriptions)
        return (
            handler_input.response_builder
           .response
        )

步驟3:組態主動事件

最後,需要在技能的組態檔案中新增主動事件的設定。這包括指定主動事件的名稱和相關的API端點。

{
    "subscriptions": [
        {
            "eventName": "SKILL_PROACTIVE_SUBSCRIPTION_CHANGED"
        }
    ],
    "regions": {
        "NA": {
            "endpoint": {
                "uri": "arn:aws:lambda:us-east-1:0000000000000:function:sampleSkill"
            }
        }
    }
}

透過以上步驟,可以成功新增主動事件處理器到Alexa技能中,並能夠處理來自Alexa的主動事件。這使得技能可以在沒有使用者明確請求的情況下主動推播通知或執行特定動作。

啟用 Alexa 通知功能

要啟用 Alexa 通知功能,使用者需要透過 Alexa Skill 進行設定。開發者可以透過 Proactive Events 來觸發通知。以下是實作通知功能的步驟:

步驟 1:啟用通知

使用者需要啟用通知功能,否則將無法收到通知。開發者可以透過檢查 ProactiveEventHandler 來確定是否已啟用通知。

步驟 2:取得存取權杖

要傳送通知,需要先取得存取權杖。這可以透過向 Amazon 傳送 POST 請求來實作,請求中包含 Client ID 和 Client Secret。

import requests

# 定義 Client ID 和 Client Secret
CLIENT_ID = 'YOUR_CLIENT_ID'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'

# 定義請求頭
headers = {
    'Content-Type': 'application/json;charset=UTF-8'
}

# 定義請求體
token_params = {
    'grant_type': 'client_credentials',
    'scope': 'alexa::proactive_events',
    'client_id': CLIENT_ID,
    'client_secret': CLIENT_SECRET
}

# 傳送 POST 請求
response = requests.post('https://api.amazon.com/auth/o2/token', headers=headers, json=token_params)

# 取得存取權杖
access_token = response.json()['access_token']

步驟 3:傳送通知

獲得存取權杖後,可以使用它來傳送通知。以下是傳送通知的示例:

import requests

# 定義通知內容
notification = {
    'event': {
        'header': {
            'namespace': 'Alerts',
            'name': 'MessageAlert'
        },
        'payload': {
            'message': 'Hello, World!'
        }
    }
}

# 定義請求頭
headers = {
    'Content-Type': 'application/json;charset=UTF-8',
    'Authorization': f'Bearer {access_token}'
}

# 傳送 POST 請求
response = requests.post('https://api.amazon.com/proactive/events', headers=headers, json=notification)

時間格式與Token存取常數

在進行程式設計時,時間格式的設定非常重要。UTC格式(Coordinated Universal Time)是一種全球通用的時間標準,通常用於網際網路應用程式中,以確保不同地區之間的時間同步。下面是設定UTC格式的範例:

UTC_FORMAT = "%Y-%m-%dT%H:%M:%S.00Z"

此外,當我們需要存取Token時,需要設定一些常數。例如,當我們使用Alexa和Raspberry Pi進行程式設計時,需要設定Client ID和Client Secret:

CLIENT_ID = credentials.key['CLIENT_ID']
CLIENT_SECRET = credentials.key['CLIENT_SECRET']

取得存取Token

要取得存取Token,需要向Amazon的Login with Amazon(LWA)服務傳送請求。以下是取得存取Token的範例程式碼:

def get_access_token():
    token_params = {
        "grant_type": "client_credentials",
        "scope": "alexa::proactive_events",
        "client_id": CLIENT_ID,
        "client_secret": CLIENT_SECRET
    }

    token_headers = {
        "Content-Type": "application/json;charset=UTF-8"
    }

    response = requests.post(TOKEN_URI, headers=token_headers, data=json.dumps(token_params), allow_redirects=True)
    print("Token response status: " + format(response.status_code))
    print("Token response body: " + format(response.text))

    if response.status_code!= 200:
        print("Error calling LWA")
        return None

    access_token = json.loads(response.text)["access_token"]
    return access_token

從技術架構視角來看,整合 Alexa Proactive Events 到技能中,需要修改 Skill Builder、實作事件處理器,並組態相關設定。本文詳細闡述了這些步驟,涵蓋了程式碼範例和設定檔修改,展現了 Proactive Events 在實作無需使用者請求的技能互動方面的價值。然而,開發者需要注意的是,主動事件的觸發時機和頻率需要謹慎設計,避免過度打擾使用者,影響使用者經驗。此外,安全考量也不容忽視,Client ID 和 Client Secret 等敏感資訊的儲存和使用需要遵循最佳實務,避免安全風險。展望未來,隨著語音互動技術的發展,Proactive Events 的應用場景將更加多元化,例如根據情境感知的主動服務推薦、個人化提醒等。對於希望提升技能互動性和使用者黏著度的開發者而言,深入理解和應用 Proactive Events 將是關鍵。玄貓認為,Proactive Events 的應用價值不容小覷,但開發者需在使用者經驗和安全風險之間取得平衡,才能最大化其效益。