Alexaサービスクライアント
Alexa Skills Kitには、スキルエクスペリエンスをパーソナライズできる複数のサービスAPIが用意されています。SDKには、スキルのロジックからAlexa APIを呼び出すのに使用するサービスクライアントが含まれます。
- ServiceClientFactory
- ApiClient
- DeviceAddressServiceClient
- DirectiveServiceClient
- ListManagementServiceClient
- MonetizationServiceClient
- UpsServiceClient
- ReminderManagementServiceClient
ServiceClientFactory
ハンドラー入力に含まれるservice_client_factory
により、サポートされているすべてのAlexaサービスのクライアントインスタンスを取得することができます。個別のサービスクライアントの作成や、api_access_token
およびapi_endpoint
などのメタデータの設定を行います。
service_client_factory
アトリビュートからhandler_input
で利用できるため、サービスクライアントは、任意のリクエストハンドラー、例外ハンドラー、リクエスト、応答インターセプターで使用できます。
利用可能なサービスクライアント
def get_device_address_service(self):
# type: () -> ask_sdk_model.services.device_address.DeviceAddressServiceClient
def get_directive_service(self):
# type: () -> ask_sdk_model.services.directive.DirectiveServiceClient
def get_monetization_service(self):
# type: () -> ask_sdk_model.services.monetization.MonetizationServiceClient
def get_ups_service(self):
# type: () -> ask_sdk_model.services.ups.UpsServiceClient
def get_reminder_management_service(self):
# type: () -> ask_sdk_model.services.reminder_management.ReminderManagementServiceClient
ApiClient
ask_sdk_model.services.api_client.ApiClient
は、AlexaサービスへのAPI呼び出しを行うときにservice_client_factory
によって使用されます。SDKを使用して、次のインターフェースに準拠する任意のカスタマイズ済みApiClient
を登録できます。
インターフェース
class ask_sdk_model.services.api_client.ApiClient:
def invoke(self, request):
# type: (ApiClientRequest) -> ApiClientResponse
class ask_sdk_model.services.api_client_request.ApiClientRequest(ApiClientMessage):
def __init__(self, headers=None, body=None, url=None, method=None):
# type: (List[Tuple[str, str]], str, str, str) -> None
class ask_sdk_model.services.api_client_request.ApiClientResponse(ApiClientMessage):
def __init__(self, headers=None, body=None, status_code=None):
# type: (List[Tuple[str, str]], str, int) -> None
class ask_sdk_model.services.api_client_message.ApiClientMessage(object):
def __init__(self, headers=None, body=None):
# type: (List[Tuple[str, str]], str) -> None
CustomSkillBuilderコンストラクターは、ApiClientの登録に使用できます。
from ask_sdk_core.skill_builder import CustomSkillBuilder
sb = CustomSkillBuilder(api_client=<YourClassInstance>)
DefaultApiClient
スキル開発者はrequests
ライブラリに基づくDefaultApiClient
を、ask_sdk_core.api_client
モジュールで利用できます。
このクライアントは、デフォルトでStandardSkillBuilderに登録されています。またはスキル開発者は、このクライアントをCustomSkillBuilder
に登録できます。
from ask_sdk_core.skill_builder import CustomSkillBuilder
from ask_sdk_core.api_client import DefaultApiClient
sb = CustomSkillBuilder(api_client=DefaultApiClient())
DeviceAddressServiceClient
DeviceAddressServiceClient
は、Device Settings APIに対してユーザーのAlexaデバイスに関連付けられた所在地データを照会するために使用できます。この所在地データを使用して、スキルの主要機能を提供したり、ユーザーエクスペリエンスを向上させることができます。たとえば、スキルはこの所在地情報を使って、近くの店舗の所在地一覧を提供したり、おすすめのレストランを紹介したりすることができます。
インターフェース
class ask_sdk_model.services.device_address.DeviceAddressServiceClient:
def get_country_and_postal_code(device_id):
# type: (str) -> Union[ShortAddress, Error]
def get_full_address(self, device_id):
# type: (str) -> Union[Address, Error]
class ask_sdk_model.services.device_address.ShortAddress:
def __init__(self, country_code=None, postal_code=None):
# type: (Optional[str], Optional[str]) -> None
class ask_sdk_model.services.device_address.Address:
def __init__(
self, address_line1=None, address_line2=None, address_line3=None,
country_code=None, state_or_region=None, city=None,
district_or_county=None, postal_code=None):
# type: (Optional[str], Optional[str], Optional[str], Optional[str], Optional[str], Optional[str], Optional[str], Optional[str]) -> None
handler_input.request_envelope.context.system.device.device_id
から取得できます。モデルの詳細については、こちら(英語)を参照してください。
サンプルコード
次の例は、リクエストハンドラーがユーザーの住所を取得する方法を示しています。
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_core.utils import is_intent_name
from ask_sdk_model.response import Response
from ask_sdk_model.ui import AskForPermissionsConsentCard
from ask_sdk_model.services import ServiceException
NOTIFY_MISSING_PERMISSIONS = ("アマゾンアレクサアプリで"
"位置情報の権限を有効にしてください。")
NO_ADDRESS = ("住所が設定されていないようです。 "
"コンパニオンアプリで住所を設定できます。")
ADDRESS_AVAILABLE = "住所は次のとおりです。{}, {}, {}"
ERROR = "申し訳ありません。エラーが発生しました。"
LOCATION_FAILURE = ("デバイスアドレスAPIでエラーが発生しました。"
"もう一度試してみてください。")
permissions = ["read::alexa:device:all:address"]
class GetAddressIntentHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return is_intent_name("GetAddressIntent")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
req_envelope = handler_input.request_envelope
service_client_fact = handler_input.service_client_factory
response_builder = handler_input.response_builder
if not (req_envelope.context.system.user.permissions and
req_envelope.context.system.user.permissions.consent_token):
response_builder.speak(NOTIFY_MISSING_PERMISSIONS)
response_builder.set_card(
AskForPermissionsConsentCard(permissions=permissions))
return response_builder.response
try:
device_id = req_envelope.context.system.device.device_id
device_addr_client = service_client_fact.get_device_address_service()
addr = device_addr_client.get_full_address(device_id)
if addr.address_line1 is None and addr.state_or_region is None:
response_builder.speak(NO_ADDRESS)
else:
response_builder.speak(ADDRESS_AVAILABLE.format(
addr.address_line1, addr.state_or_region, addr.postal_code))
return response_builder.response
except ServiceException:
response_builder.speak(ERROR)
return response_builder.response
except Exception as e:
raise e
DirectiveServiceClient
DirectiveServiceClient
は、プログレッシブ応答APIにディレクティブを送信するために使用できます。プログレッシブ応答を使用すると、スキルがユーザーのリクエストへの完全な応答を準備している間もユーザーの関心を引き続けることができます。
インターフェース
class ask_sdk_model.services.directive.DirectiveServiceClient:
def enqueue(self, send_directive_request):
# type: (SendDirectiveRequest) -> Union[Error]
class ask_sdk_model.services.directive.SendDirectiveRequest:
def __init__(self, header=None, directive=None):
# type: (Optional[Header], Optional[SpeakDirective]) -> None
class ask_sdk_model.services.directive.SpeakDirective:
def __init__(self, speech=None):
# type: (Optional[str]) -> None
モデルの詳細については、こちら(英語)を参照してください。
サンプルコード
次の例は、プログレッシブ応答を送信するためのhandle
メソッドで使用できる関数を示しています。
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_model.services.directive import (
SendDirectiveRequest, Header, SpeakDirective)
import time
def get_progressive_response(handler_input):
# type: (HandlerInput) -> None
request_id_holder = handler_input.request_envelope.request.request_id
directive_header = Header(request_id=request_id_holder)
speech = SpeakDirective(speech="わかりました。少々お待ちください")
directive_request = SendDirectiveRequest(
header=directive_header, directive=speech)
directive_service_client = handler_input.service_client_factory.get_directive_service()
directive_service_client.enqueue(directive_request)
time.sleep(5)
return
MonetizationServiceClient
スキル内課金サービス
SDKには、inSkillPurchase APIを呼び出すMonetizationServiceClient
が用意されています。このAPIでは、現在のスキルに関連付けられているすべてのスキル内商品を取得し、各商品が課金可能かまたは現在のユーザーが既に課金済みかを確認できます。
インターフェース
class ask_sdk_model.services.monetization.MonetizationServiceClient:
def get_in_skill_products(
self, accept_language, purchasable=None, entitled=None,
product_type=None, next_token=None, max_results=None):
# type: (str, Optional[PurchasableState], Optional[EntitledState], Optional[ProductType], Optional[str], Optional[float]) -> Union[Error, InSkillProductsResponse]
def get_in_skill_product(self, accept_language, product_id):
# type: (str, str) -> Union[Error, InSkillProduct]
class ask_sdk_model.services.monetization.InSkillProductsResponse:
def __init__(self, in_skill_products=None, is_truncated=None, next_token=None):
# type: (Optional[List[InSkillProduct]], Optional[bool], Optional[str]) -> None
class ask_sdk_model.services.monetization.InSkillProduct:
self, product_id=None, reference_name=None, name=None, object_type=None, summary=None, purchasable=None, entitled=None, active_entitlement_count=None, purchase_mode=None
def __init__(
self, product_id=None, reference_name=None, name=None,
object_type=None, summary=None, purchasable=None, entitled=None,
active_entitlement_count=None, purchase_mode=None):
# type: (Optional[str], Optional[str], Optional[str], Optional[ProductType], Optional[str], Optional[PurchasableState], Optional[EntitledState], Optional[int], Optional[PurchaseMode]) -> None
class ask_sdk_model.services.monetization.ProductType(Enum):
SUBSCRIPTION = "SUBSCRIPTION"
ENTITLEMENT = "ENTITLEMENT"
CONSUMABLE = "CONSUMABLE"
class ask_sdk_model.services.monetization.PurchasableState(Enum):
PURCHASABLE = "PURCHASABLE"
NOT_PURCHASABLE = "NOT_PURCHASABLE"
class ask_sdk_model.services.monetization.EntitledState(Enum):
ENTITLED = "ENTITLED"
NOT_ENTITLED = "NOT_ENTITLED"
class ask_sdk_model.services.monetization.PurchaseMode(Enum):
TEST = "TEST"
LIVE = "LIVE"
accept_language
は、リクエストのロケールで、handler_input.request_envelope.request.locale
から取得できます。モデルの詳細については、こちら(英語)を参照してください。
サンプルコード
get_in_skill_products
get_in_skill_products
メソッドは、現在のスキルに関連付けられているすべてのスキル内商品を取得し、現在のスキルとユーザーについて各スキル内商品の課金可能性と買い切り型商品のステータスを示します。
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_core.utils import is_request_type
from ask_sdk_model.response import Response
from ask_sdk_model.services.monetization import (
EntitledState, PurchasableState, InSkillProductsResponse)
class LaunchRequestHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
return is_request_type("LaunchRequest")(handler_input)
def handle(self, handler_input):
locale = handler_input.request_envelope.request.locale
ms = handler_input.service_client_factory.get_monetization_service()
product_response = ms.get_in_skill_products(locale)
if isinstance(product_response, InSkillProductsResponse):
total_products = len(product_response.in_skill_products)
entitled_products = len([l for l in product_response.in_skill_products
if l.entitled == EntitledState.ENTITLED])
purchasable_products = len([l for l in product_response.in_skill_products
if l.purchasable == PurchasableState.PURCHASABLE])
speech = (
"合計{}個の商品が見つかりました。そのうち{}個が課金可能で、{}個が"
"購入済みです".format(
total_products, purchasable_products, entitled_products))
else:
speech = "購入履歴のロード中に問題が発生しました。"
return handler_input.response_builder.speak(speech).response
API応答にはスキル内商品レコードの配列が含まれます。
get_in_skill_product
get_in_skill_product
APIは指定されたproductIdで識別される単一のスキル内商品の商品レコードを取得します。
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_core.utils import is_request_type
from ask_sdk_model.response import Response
from ask_sdk_model.services.monetization import InSkillProduct
class LaunchRequestHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
return is_request_type("LaunchRequest")(handler_input)
def handle(self, handler_input):
locale = handler_input.request_envelope.request.locale
ms = handler_input.service_client_factory.get_monetization_service()
product_id = "amzn1.adg.product.<GUID>"
product_response = ms.get_in_skill_product(locale)
if isinstance(product_response, InSkillProduct):
# InSkillProductを処理するコードがここに入ります
speech = ""
pass
else:
speech = "商品のロード中に問題が発生しました。"
return handler_input.response_builder.speak(speech).response
API応答には単一のスキル内商品レコードが含まれます。
これらのAPIとスキル実装での使い方の詳細については、こちらを参照してください。 カスタムスキルへのスキル内課金の追加
スキル内課金のインターフェース
SDKには、スキルでAlexaからスキル内課金とキャンセルのリクエストを開始するためのadd_directive()
メソッドが用意されています。Amazonシステムはユーザーとの音声による対話を管理し、課金取引を処理して、ステータス応答をリクエスト元のスキルに返します。このインターフェースを使用して、以下の3つのアクション
がサポートされます。
Upsell
Buy
Cancel
これらのアクション
と推奨されるユースケースの詳細については、こちらを参照してください。 カスタムスキルへのスキル内課金の追加
サンプルコード
Upsell
スキルは、ユーザーが明示的にコンテキストをリクエストしなかった場合にスキルのコンテキストを提供するためにUpsellアクションを開始する必要があります。たとえば、無料のコンテンツが提供されている間または後です。Upsellアクションを開始するには、製品IDとアップセルメッセージが必要です。アップセルメッセージを使って、開発者はAlexaで価格を提示する前にユーザーにスキル内商品を提示する方法を指定できます。
from ask_sdk_model.interfaces.connections import SendRequestDirective
# スキルフローでは、ユーザーから明示的な依頼なしで
# スキル内商品を提供するために意思決定がなされた場合
return handler_input.response_builder.add_directive(
SendRequestDirective(
name="Upsell",
payload={
"InSkillProduct": {
"productId": "<product_id>",
},
"upsellMessage": "<スキル内商品のアップセル用紹介説明>",
},
token="correlationToken")
).response
Buy
スキルは、ユーザーが特定のスキル内商品の課金をリクエストしたときにBuyアクションを開始します。Buyアクションを開始するには、product_idが必要です。
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_core.utils import is_intent_name
from ask_sdk_model.response import Response
from ask_sdk_model.interfaces.connections import SendRequestDirective
# スキル内商品を購入するためにユーザーのインテントをキャプチャするカスタムインテント
# (下のBuyProductIntent)を実装し、次にこれに対してBuyリクエストをトリガーします。
# 例:'アレクサ、<商品名>を買って'
class BuyProductIntentHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return is_intent_name("BuyProductIntent")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
# InSkillProducts APIを呼び出してリクエストしたスキル内商品の
# product_idを取得します。
# 以下で使われているスロット数product_nameはデモ用です。
locale = handler_input.request_envelope.request.locale
ms = handler_input.service_client_factory.get_monetization_service()
product_response = ms.get_in_skill_products(locale)
slots = handler_input.request_envelope.request.intent.slots
product_ref_name = slots.get("product_name").value
product_record = [l for l in product_response.in_skill_products
if l.reference_name == product_ref_name]
if product_record:
return handler_input.response_builder.add_directive(
SendRequestDirective(
name="Buy",
payload={
"InSkillProduct": {
"productId": product_record[0].product_id
}
},
token="correlationToken")
).response
else:
return handler_input.response_builder.speak(
"すみません。その商品は課金できません"
).response
Cancel
スキルは、ユーザーがサポートされているスキル内商品の既存の買い切り型アイテムまたはサブスクリプションのキャンセルをリクエストしたときにCancelアクションを開始します。Cancelアクションを開始するには、product_idが必要です。
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_core.utils import is_intent_name
from ask_sdk_model.response import Response
from ask_sdk_model.interfaces.connections import SendRequestDirective
# スキル内商品をキャンセルするためにユーザーのインテントをキャプチャするカスタムインテント
# (下のCancelProductIntent)を実装し、次にこれに対してCancelリクエストをトリガーします。
# 例:'アレクサ、<商品名>をキャンセルして'
class CancelProductIntentHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return is_intent_name("CancelProductIntent")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
# InSkillProducts APIを呼び出してリクエストしたスキル内商品の
# product_idを取得します。
# 以下で使われているスロット数product_nameはデモ用です。
locale = handler_input.request_envelope.request.locale
ms = handler_input.service_client_factory.get_monetization_service()
product_response = ms.get_in_skill_products(locale)
slots = handler_input.request_envelope.request.intent.slots
product_ref_name = slots.get("product_name").value
product_record = [l for l in product_response.in_skill_products
if l.reference_name == product_ref_name]
if product_record:
return handler_input.response_builder.add_directive(
SendRequestDirective(
name="Cancel",
payload={
"InSkillProduct": {
"productId": product_record[0].product_id
}
},
token="correlationToken")
).response
else:
return handler_input.response_builder.speak(
"すみません。わかりません").response
UpsServiceClient
UpsServiceClient
を使用して、AlexaユーザープロフィールAPIに対してユーザーの連絡先情報を照会したり、Device Settings APIに対してユーザーのタイムゾーン設定、長さの単位、および温度の単位を取得できます。
インターフェース
class ask_sdk_model.services.ups.UpsServiceClient:
def get_profile_email(self):
# type: () -> Union[str, Error]
def get_profile_given_name(self):
# type: () -> Union[str, Error]
def get_profile_mobile_number(self):
# type: () -> Union[PhoneNumber, Error]
def get_profile_name(self):
# type: () -> Union[str, Error]
def get_system_distance_units(self, device_id):
# type: (str) -> Union[Error, DistanceUnits]
def get_system_temperature_unit(self, device_id):
# type: (str) -> Union[TemperatureUnit, Error]
def get_system_time_zone(self, device_id):
# type: (str) -> Union[str, Error]
class ask_sdk_model.services.ups.PhoneNumber:
def __init__(self, country_code=None, phone_number=None):
# type: (Optional[str], Optional[str]) -> None
class ask_sdk_model.services.DistanceUnits(Enum):
METRIC = "METRIC"
IMPERIAL = "IMPERIAL"
class ask_sdk_model.services.TemparatureUnit(Enum):
CELSIUS = "CELSIUS"
FAHRENHEIT = "FAHRENHEIT"
サンプルコード
Alexaユーザー設定API
Alexaユーザー設定APIは、設定されている長さの単位、温度の単位、デバイスで現在設定されているタイムゾーンという3つの情報へのアクセスを提供します。UpsServiceClientを使用する場合、get_system_distance_units
およびget_system_temperature_unit
は列挙オブジェクトを返します。この値は.value
アトリビュートを使ってアクセスする必要があります。一方、get_system_time_zone
は単に文字列を返します。
device_id = req_envelope.context.system.device.device_id
user_preferences_client = handler_input.service_client_factory.get_ups_service()
# Alexa設定APIから設定されている長さの単位を取得します
preferred_distance_units = user_preferences_client.get_system_distance_units(device_id).value
print (preferred_distance_units) # 「IMPERIAL」または「METRIC」の文字列
# Alexa設定APIから設定されている温度の単位を取得します
preferred_temperature_units = user_preferences_client.get_system_temperature_unit(device_id).value
print (preferred_temperature_units) # 「FAHRENHEIT」または「CELSIUS」の文字列
# Alexa設定APIからデバイスで現在設定されているタイムゾーンを取得します
time_zone = user_preferences_client.get_system_time_zone(device_id)
print (time_zone) # タイムゾーンを表す文字列(「America/Los_Angeles」など)
handler_input.request_envelope.context.system.device.device_id
から取得できます。モデルの詳細については、こちら(英語)を参照してください。
ReminderManagementServiceClient
ReminderManagementServiceClient
を使用して、ユーザーのリマインダーを作成、管理することができます。
インターフェース
class ask_sdk_model.services.reminder_management.ReminderManagementServiceClient:
def create_reminder(self, reminder_request):
# type: (ReminderRequest) -> Union[ReminderResponse, Error]
def update_reminder(self, alert_token, reminder_request):
# type: (str, ReminderRequest) -> Union[ReminderResponse, Error]
def delete_reminder(self, alert_token):
# type: (str) -> Union[Error]
def get_reminder(self, alert_token):
# type: (str) -> Union[GetReminderResponse, Error]
def get_reminders(self):
# type: () -> Union[GetRemindersResponse, Error]
サンプルコード
以下は、ReminderManagementServiceClient
のインスタンスを作成し、新しいリマインダーを作成するリクエストハンドラーの例です。
import logging
import typing
from datetime import datetime
from ask_sdk_core.skill_builder import CustomSkillBuilder
from ask_sdk_model.ui import SimpleCard
from ask_sdk_core.utils import is_intent_name
from ask_sdk_core.api_client import DefaultApiClient
from ask_sdk_model.services.reminder_management import (
ReminderRequest, Trigger, TriggerType, AlertInfo, PushNotification,
PushNotificationStatus, ReminderResponse, SpokenInfo, SpokenText)
from ask_sdk_model.services import ServiceException
from ask_sdk_model.ui import AskForPermissionsConsentCard
if typing.TYPE_CHECKING:
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_model import Response
permissions = ["alexa::alerts:reminders:skill:readwrite"]
NOTIFY_MISSING_PERMISSIONS = ("アマゾンアレクサアプリでリマインダーの権限を"
"有効にしてください。")
sb = CustomSkillBuilder(api_client=DefaultApiClient())
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
@sb.request_handler(can_handle_func=is_intent_name("CreateReminder"))
def create_reminder_intent_handler(handler_input):
# type: (HandlerInput) -> Response
req_envelope = handler_input.request_envelope
response_builder = handler_input.response_builder
# ユーザーがリマインダーを作成する権限を与えたかどうかを確認します。
# 権限が与えられていない場合、スキルに権限を与えるようにリクエストします。
if not (req_envelope.context.system.user.permissions and
req_envelope.context.system.user.permissions.consent_token):
response_builder.speak(NOTIFY_MISSING_PERMISSIONS)
response_builder.set_card(
AskForPermissionsConsentCard(permissions=permissions))
return response_builder.response
reminder_client = handler_input.service_client_factory.get_reminder_management_service()
try:
reminder_response = reminder_client.create_reminder(
reminder_request=ReminderRequest(
request_time=datetime.utcnow(),
trigger=Trigger(
object_type=TriggerType.SCHEDULED_RELATIVE,
offset_in_seconds=60),
alert_info=AlertInfo(
spoken_info=SpokenInfo(
content=[SpokenText(locale="en-US", text="Test reminder")])),
push_notification=PushNotification(
status=PushNotificationStatus.ENABLED))) # type: ReminderResponse
speech_text = "はい、 リマインダーを設定しました。"
logger.info("Created reminder : {}".format(reminder_response))
return handler_input.response_builder.speak(speech_text).set_card(
SimpleCard(
"Reminder created with id", reminder_response.alert_token)).response
except ServiceException as e:
logger.info("Exception encountered : {}".format(e.body))
speech_text = "申し訳ありません。エラーが発生しました。"
return handler_input.response_builder.speak(speech_text).set_card(
SimpleCard(
"Reminder not created",str(e.body))).response
モデルの詳細については、こちら(英語)を参照してください。
最終更新日: 2024 年 07 月 01 日