Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Skill Connections やってみた / Introduction to Alexa Skill Connections

Skill Connections やってみた / Introduction to Alexa Skill Connections

【AAJUG大阪】VoiceConJapan2020直前企画!Alexaスキル開発ごった煮トーク でお話したSkill ConnectionsのLT資料です。某所でLTしたものと同じですが、少しブラッシュアップしました。サンプルコードあります。

https://aajug.connpass.com/event/161436/

Kuniaki Shimizu

February 09, 2020
Tweet

More Decks by Kuniaki Shimizu

Other Decks in Technology

Transcript

  1. Skill Connectionsやってみた
    AAJUG Osaka 2020/2/9

    View Slide

  2. About Myself
    1

    View Slide

  3. Kuniaki Shimizu (@kun432)
    - シナジーマーケティング株式会社
    - インフラエンジニア
    - Twitter/Facebook/Github/Hatena/Alexa
    - ポートフォリオ: https:/
    /kun432.github.io/
    - AWS認定Alexaスキルビルダー
    - Voiceflow Global Ambassador
    - Voiceflow Growth Award 2019
    3
    Hello!

    View Slide

  4. My Skills & Actions
    4
    - Alexa (JP): 12
    - Google: 1 - Clova: 1
    #スキル開発100チャレンジ
    - Alexa (US): 1

    View Slide

  5. ● 本資料内における意見・発言等は個人の
    見解であり、所属する組織・団体の見解
    を代表するものでは、ありません
    ● 某所でLTしたものと基本的に同じ内容
    ですので、あしからず
    ● 今日はVoiceflowの話はしません
    ● ちょっとポエム風味・・・
    5
    Disclaimer

    View Slide

  6. Skill Connections
    やってみた
    2

    View Slide

  7. 某所でのアンケートの結果
    7

    View Slide

  8. 8

    View Slide

  9. めっちゃマイナー
    9

    View Slide

  10. Skill Connectionsおさらい
    10
    ● 単純にいうと、スキル間連携
    ● スキルAから、スキルBの機能を呼び出す
    ● スキルBの処理が終わるとスキルAに戻る
    ● 用語
    ○ リクエスタ(上で言うA)
    ■ 他のスキルの機能を呼び出す
    ○ プロバイダ(上で言うB)
    ■ 他のスキルへ機能を提供する

    View Slide

  11. 11
    連携
    開始
    連携中
    連携後
    印刷インテントトリガー
    ディレクティブ送信
    (StartConnection)
    印刷インテントハンドラ
    レスポンスハンドラ
    (SessionResumedRequest)
    処理を続ける
    ● リクエスタはconnectionエンドポイントに要求を投げる
    ● プロバイダはAlexaが決めて、要求を受け渡す
    ● プロバイダの実行結果をAlexaから受け取って処理を継続
    Skill Connectionsの仕組み
    セッション切断
    A
    B
    A
    処理結果

    View Slide

  12. 今回はプリンタスキルと連携する
    リクエスタやってみた
    ※プロバイダだと両方作らないといけない
    ※プロバイダ側は特別な審査が必要らしい
    12

    View Slide

  13. 13

    View Slide

  14. 14
    リクエスタの実装
    const continueIntentHandler = {
    ・・・
    handle(handlerInput) {
    const speakOutput = 'それではプリンタスキルを呼び出して印刷します。';
    return handlerInput.responseBuilder
    .speak(speakOutput)
    .addDirective({
    'type': 'Connections.StartConnection',
    'uri': 'connection://AMAZON.PrintPDF/1',
    'input': {
    '@type': 'PrintPDFRequest',
    '@version': '1',
    'title': 'サンプルのPDF',
    'description': 'スキルコネクションズのサンプルのPDFです。',
    'url': 'https://******.s3-ap-northeast-1.amazonaws.com/sample1.pdf'
    },
    'token': 'none'
    })
    .getResponse();

    View Slide

  15. 15
    const ConnectionsResponseHandler = {
    canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'SessionResumedRequest';
    },
    handle(handlerInput) {
    const statusCode = handlerInput.requestEnvelope.request.cause.status.code;
    const statusMessage = handlerInput.requestEnvelope.request.cause.status.message;
    console.log(`SessionResumedRequest: code: ${statusCode}, msg: ${statusMessage}`;
    let speechText;
     switch (statusCode) {
    case “200”: // 購入した
    speechText = "印刷が終わりました。ご利用ありがとうございました。";
    break;
    case “204”: // ユーザキャンセル
    speechText = "またご利用くださいね。";
    Break;
    ・・・
    Default: // その他エラー
    speechText = "ごめんなさい、うまく行かなかったようです。";
    break;
     }
    return handlerInput.responseBuilder.speak(speechText).getResponse();
    },
    };

    View Slide

  16. 16
    ん?なんかこれ
    見たことない?

    View Slide

  17. 17
    課金
    処理前
    課金
    処理中
    課金
    処理後
    購入インテントトリガー
    ディレクティブ送信
    (type=Connections.SendRequest)
    購入インテントハンドラ
    レスポンスハンドラ
    (type=Connections.Response)
    getResponseで会話フロー
    をつなげる
    商品・料金説明、
    同意確認
    認証コード確認
    課金処理
    ● スキル側でやるのは購入処理の手前と後だけ
    ● 購入処理も一連のやり取りもAlexa⇔ユーザでやってくれる
    スキル内課金のやりとり
    セッション切断

    View Slide

  18. 18
    MonetizationServiceClient
    ● 購入をMonetizationServiceClientにリクエスト
    const BuyEnglishPackIntentHandler = {
    ・・・
    handle(handlerInput) {
    const locale = handlerInput.requestEnvelope.request.locale;
    const ms = handlerInput.serviceClientFactory.getMonetizationServiceClient();
    return ms.getInSkillProduct(locale, ENGLISH_PACK_ID).then(function (product) {
    if (product.entitled === "ENTITLED") {
    const speechText = `既に${product.name} を購入しています。続けますか?`;
    const repromptText = `続けますか?`;
    return handlerInput.responseBuilder
    .speak(speechText)
    .reprompt(repromptText)
    .getResponse();
    } else {
    return handlerInput.responseBuilder
    .addDirective({
    type: 'Connections.SendRequest',
    name: 'Buy',
    payload: { InSkillProduct: { productId: ENGLISH_PACK_ID } },
    token: 'correlationToken'
    })
    .getResponse();
    }
    });
    }
    };

    View Slide

  19. 19
    .getResponse();
    } else {
    return handlerInput.responseBuilder
    .addDirective({
    type: 'Connections.SendRequest',
    name: 'Buy',
    payload: { InSkillProduct:
    { productId: ENGLISH_PACK_ID } },
    token: 'correlationToken'
    })
    .getResponse();
    }
    });

    View Slide

  20. 20
    MonetizationServiceClient
    ● 購入処理結果を受けるハンドラ
    const BuyResponseHandler = {
    canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'Connections.Response' &&
    ・・・
    },
    handle(handlerInput) {
    const locale = handlerInput.requestEnvelope.request.locale;
    const ms = handlerInput.serviceClientFactory.getMonetizationServiceClient();
    return ms.getInSkillProduct(locale, ENGLISH_PACK_ID).then(function (product) {
    if (handlerInput.requestEnvelope.request.status.code === '200') {
    let speechText = product.summary;
    const repromptText = '続けますか?';
    switch (handlerInput.requestEnvelope.request.payload.purchaseResult) {
    case 'ACCEPTED': // 購入した
    speechText = product.summary + repromptText;
    break;
    case 'DECLINED': // 購入しなかった
    speechText = repromptText;
    break;
    case 'ALREADY_PURCHASED': // 既に購入済
    speechText = product.summary + repromptText;
    break;
    Default: // その他のERROR
    speechText = `うまく行かなかったようです。${repromptText}`;
    break;
    } ・・・続く・・・

    View Slide

  21. 21
    ISPも内部的にはConnections
    ※そしてAmazon Payも同じ

    View Slide

  22. Skill Connections: Pros
    22
    ● ISPやってれば実装そんなに難しくない。
    ○ プロバイダ側への受け渡し部分とプロバイダ側
    処理は勝手にやってくれる
    ○ リクエスタは所定のフォーマットで投げて、
    結果に応じて続けるだけ。
    ● 自分で実装しなくて良いのはやっぱり楽
    ■ ハードウェア連携は特に
    ■ プロバイダが増えれば機能を増やせる
    ■ プロバイダもAlexaがよしなに選んでくれる

    View Slide

  23. Skill Connections: Cons①
    23
    ● ISPと同じで会話の流れがつかみにくい
    ○ リクエスタとプロバイダが両方しゃべる。
    ○ 受け渡し時のAlexa側の発話もある。
    ○ テスト用のタスク(AMAZON.TestStatusCode)
    を使って確認
    ○ プロバイダ側独自のステータスコードも。
    ○ 実際にテストしながら発話の自然さをチェック。
    ● 連携時は、セッション切れるので要対応
    ○ Persistent Attribute
    良くも悪くもISPと同じ

    View Slide

  24. いろいろしゃべる
    24

    View Slide

  25. いろいろしゃべる
    25
    リクエスタ側
    プロバイダ側
    ASK側

    View Slide

  26. Skill Connections: Cons②
    26
    少なすぎる・・・
    ● 現在対応しているタスク
    ○ 印刷系
    ■ AMAZON.PrintImage
    ■ AMAZON.PrintPDF
    ■ AMAZON.PrintWebPage
    ○ 予約系
    ■ AMAZON.ScheduleTaxiReservation
    ■ AMAZON.ScheduleFoodEstablishmentRes
    ervation

    View Slide

  27. Skill Connections対応スキル
    27

    View Slide

  28. Skill Connections対応スキル
    28

    View Slide

  29. Skill Connections対応スキル
    29

    View Slide

  30. 30
    その他つまづいたところ
    ● 利用開始までのプロセスが長い(プリンタの場合)
    ○ プリンタのWiFi接続設定
    ○ プリンタ側のアカウント登録
    ○ アカウントリンク
    ○ スキル有効化までのハードルが高い、ここでくじける人
    が一定数いるはず
    ● 情報がない・・・
    ○ DevSummit以来、特に話がない
    ○ ドキュメントが少なすぎるし、サンプルも微妙
    ○ Githubのサンプルコード欲しい

    View Slide

  31. 31
    モチベーションが・・・

    View Slide

  32. 32
    なんで今日この話?

    View Slide

  33. 33
    https://developer.amazon.com/en-US/blogs/alexa/alexa-skills-kit/2019/12/Create-Custom-Connected-Skill-Experiences-with-Tasks-and-Direct-Skill-Connections

    View Slide

  34. 34
    Custom Tasks & Direct Connections
    ● Custom Tasks
    ○ プロバイダのタスクを自由に定義できるようになる?
    ○ “ask api search-task/get-task” でタスクを探して使う
    ● Direct Connections
    ○ Skill Connectionsでは、Amazon定義のプロバイダが
    自動的に選択される
    ○ Direct Connectionsでは、リクエスタがプロバイダを
    選択可能に?
    プロバイダの数・種類の増加に期待
    さらにプロバイダ開発も

    View Slide

  35. 35
    そして

    View Slide

  36. 36
    Alexa Conversations
    https://robotstart.info/2019/06/06/alexa-cross-skill-conversations.html

    View Slide

  37. 37
    Alexa Conversations
    https://robotstart.info/2019/06/06/alexa-cross-skill-conversations.html

    View Slide

  38. 38
    Alexa Conversations
    ● Alexa側でユーザの要望に合わせたスキルを
    チョイスしてくれる
    ○ 呼び出し名がいらない(canFulfillIntentと同じ)
    ● ユーザの要望に関連するスキルを連携して呼び出す
    ○ ユーザの要望を先回りする

    View Slide

  39. 39
    スキルが呼び出すのはユーザだけではなく
    Alexaや他のスキルから呼び出される

    View Slide

  40. まとめ
    3

    View Slide

  41. 41
    まとめ
    ● Skill Connectionsの実装はISPと似てる。ISP
    やってれば難しくない
    ● 現状は限定的なユースケースのみ
    ● 今後、Custom Tasks & Direct Connectionsが出て
    きたら可能性が広がるかも
    ● AlexaConversation含めて、ユーザ「以外」から起動され
    る・他のスキルから連携されやすい、単機能を
    きちんとこなすスキル企画・開発へ?
    スキル開発の別の形になるかも?ど

    View Slide

  42. 42
    知らんけど

    View Slide

  43. 43
    今日のサンプル
    https://github.com/kun432/alexa-skill-connections-sample

    View Slide

  44. お知らせ
    4

    View Slide

  45. 45
    2/29 技術書典8 (Day1あ09)
    ● 豪華執筆陣!CEOの前書き!
    ● 165P、1000円(予定)

    View Slide

  46. 46
    3/21 Voice Con Japan 2020

    View Slide

  47. Thanks!
    Any questions?

    View Slide