Help us understand the problem. What is going on with this article?

[入門]Clovaスキル(CEK)は作りながら覚えて行く(Lambda使ってコード実装編)

More than 1 year has passed since last update.

この記事で書いてあること

先日CEKの一般公開を期に、CEK + Lambda + API Gatewayを実践してみました。
この記事を一通りやると、簡単なClovaスキルが作成できるようになります。

No タイトル
1 [入門]Clovaスキル(CEK)は作りながら覚えて行く(前提知識編)
2 [入門]Clovaスキル(CEK)は作りながら覚えて行く(インテント、スロットなど登録編)
3 [入門]Clovaスキル(CEK)は作りながら覚えて行く(Lambda使ってコード実装変)<<今ここ
4 [入門]Clovaスキル(CEK)は作りながら覚えて行く(signature検証編)
番外編 公式SDKを使ってLambdaで開発した記事を書いてみました

Clova専用のSDKを作ったので、それを元にエンドポイント(今回はLambdaを使用)の実装について説明していく。
インテントやスロットはすでにCEKで定義している前提。

公式SDKを使ったLambdaでの開発方法も書きました。
Clovaの公式SDKがLambdaで使えるようになっていたので試してみた。

注意

今回は簡単化のために「RSA公開鍵を用いてリクエストメッセージを検証する」をしていません。
しなくても、動作はするのですがLINEさん公式では署名を検証することを推薦しています。
なので、この記事を拡張して一般公開用のスキルを作成する場合は検証機能を追加することをお勧めします。
詳しくはこちら
(次回の記事で自分の方でも検証のやり方の記事を書こうかなと思います。)

書きました。
[入門]Clovaスキル(CEK)は作りながら覚えて行く(signature検証編)

また、今回使用しているSDKはあくまで個人で開発したものであり、出来て間もないためバグなどがある可能性があります。ご了承ください。今後も修正を重ねて行く予定です。
なお、ask-sdkに似た様な書き方でかける様にしているのでおなじみの方にはやりやすいかと思います。

環境

  • npm入ってる >> (npmなにそれ、って人向けにzipファイル用意しましたので必須ではないです。)
  • node.js(8.10以上) >> (node.jsなにそれ、って人向けにzipファイル用意しましたので必須ではないです。)
  • AWSのアカウント持ってる >> これは必須です。

まずは、簡単にスキルの説明

今回は、星座で占いをしてくれる「ほげほげ占い」を作っていく。

会話例

ユーザー: 「Clova、ほげほげ占いを開いて」
Clova: 「あなたの星座を教えてください」
ユーザー: 「私の星座は魚座です。」
Clova: 「魚座ですね。魚座の今日の運勢は○○です。」(スキル終了)

Slots

スロット名: constellation

値:

ふたご座
蟹座
魚座
乙女座
etc

インテント

インテント名: DivinationIntent

発話例:

私の星座は魚座です
私の星座は蟹座だ
私の星座はふたご座​よ

開発の流れ

  1. ローカル(自分のパソコン)にてNode.jsでコードを書いちゃう。
  2. Lambdaにzipファイルとしてアップロードする。
  3. Lambdaのテスト画面で試してみる。
  4. 実機で試してみる。

ローカルでの開発

npmまたはNode.jsなんて知らないよ、という方にZIPファイル用意しました。ここからダウンロードしてください。
そして、「AWSのコンソール画面で」まですっ飛ばして大丈夫です。

初期設定

ディレクトリ作成

$ mkdir fortune-func
$ cd fortune-func
$ npm init #なんか色々聞かれるが全部エンター押していく

インストール

$ npm install --save love-clova

ファイル作成

$ vi index.js

好きなエディタをご利用ください。

コードのコピペ

index.jsに以下のコードをコピペする。
とりあえずの自作SDKなのでご了承を。

var clova = require("love-clova");

const LaunchRequestHandler = {
  canHandle: function(handlerInput){
    return handlerInput.requestEnvelope.isMatch('LaunchRequest');
  },
  handle: function(handlerInput){
    var msg = "あなたの星座を教えてください";
    return handlerInput.responseBuilder.speak(msg).reprompt(msg).getResponse();
  }
}

const SessionEndedRequestHandler = {
  canHandle: function(handlerInput){
    return handlerInput.requestEnvelope.isMatch('SessionEndedRequest');
  },
  handle: function(handlerInput){
    var msg = "";
    return handlerInput.responseBuilder.speak(msg).reprompt(msg).getResponse();
  }
}

const ClovaGuideIntentHandler = {
  canHandle: function(handlerInput){
    return handlerInput.requestEnvelope.isMatch('Clova.GuideIntent');
  },
  handle: function(handlerInput){
    var msg = "このスキルは今日のあなたの運勢を占います。あなたの星座を教えてください。";
    return handlerInput.responseBuilder.speak(msg).reprompt(msg).getResponse();
  }
}

const DivinationIntentHandler = {
  canHandle: function(handlerInput){
    return handlerInput.requestEnvelope.isMatch('DivinationIntent');
  },
  handle: function(handlerInput){
    // 運勢を配列で。
    var fortunes = ["良い", "普通", "悪い"];
    // fortunesの中からランダムで
    var fortune = fortunes[Math.floor(Math.random() * fortunes.length)];

    // slotsを取得
    var constellation = handlerInput.requestEnvelope.request.intent.slots.constellation.value;

    // clovaに話す内容を作成。
    var msg = `${constellation}ですね。${constellation}の今日の運勢は${fortune}です。`;

    return handlerInput.responseBuilder.speak(msg).getResponse();
  }
}

const errorHandler = {
  canHandle: function(handlerInput){
    return true;
  },
  handle: function(handlerInput){
    var msg = "エラー発生";
    return handlerInput.responseBuilder.speak(msg).reprompt(msg).getResponse();
  }
}

exports.handler = clova.extensionBuilders
  .addRequestHandlers(LaunchRequestHandler,SessionEndedRequestHandler,ClovaGuideIntentHandler,DivinationIntentHandler)
  .addErrorHandlers(errorHandler)
  .lambda()

zipファイル化

lambdaにコードをあげる方法はいくつかあるが、簡単なZIPファイルにしてあげる方法にする。
fortune-funcディレクトリ配下でとりあえず、存在しているファイルを確認。

$ ls 
index.js    package-lock.json    node_modules       package.json        

全部を圧縮する

$ zip -r upload.zip *

再度、存在しているファイルを確認

$ ls 
index.js    package-lock.json    node_modules       package.json    upload.zip  

upload.zipというファイルが作成されているのが確認できる。

AWSのコンソール画面で

Lambdaで関数作成

AWSのLambdaの画面に移動し、右上の「関数の作成」ボタンを押す。

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3139353838322f30363864356333652d616463332d353663322d383432372d3836623965646463636630632e706e67.png

「一から作成」を選択肢、名前ランタイムロールを以下のように設定する

  • 名前: FortuneFunc
  • ランタイム: Node.js 8.10
  • ロール: カスタムロールの作成(すでにある場合は既存のロールを選択する)

Lambda_Management_Console-2.png

カスタムロールの作成を選ぶと新規画面が勝手に出てくるので、右下の許可をクリック。

IAM_Management_Console.png

すると、先ほどの関数の作成画面に戻るはず。
右下の関数の作成をクリック。
おそらく、以下のような画面になるはず。

ご指摘いただいたのですが、人によってはLambdaの出力(画面右の方)がCloudWatchだけだったりしますが今回は動作上問題ありません。

スクリーンショット 2018-07-05 18.44.07.png

次に、画面少し下行くと関数コードという項目があるので、その中のコードエントリタイプzip ファイルをアップロードを選択する
そんで、その下のアップロードボタンを押して先ほど作成下upload.zipを選択して、右上の保存ボタンで保存する。

Lambda_Management_Console.png

とりあえず、テストしてみる。

まだ、ClovaとLambdaを連携させてないので実機でのテストはできないがLambda上でテストする方法がある。
Lambda画面右上の「テストイベントの設定」ボタンをクリックするとテストイベントの設定画面が出てくるので以下の様に入力してあげる。

Lambda_Management_Console.png

イベント名

LaunchRequest

イベント名の下のJSONを入力するところ。

{
  "version": "0.1.0",
  "session": {
    "new": true,
    "sessionAttributes": {},
    "sessionId": "sample",
    "user": {
      "userId": "V0qe",
      "accessToken": "sample"
    }
  },
  "context": {
    "System": {
      "application": {
        "applicationId": "sample"
      },
      "user": {
        "userId": "V0qe",
        "accessToken": "sample"
      },
      "device": {
        "deviceId": "sample",
        "display": {
          "size": "l100",
          "orientation": "landscape",
          "dpi": 96,
          "contentLayer": {
            "width": 640,
            "height": 360
          }
        }
      }
    }
  },
  "request": {
    "type": "LaunchRequest"
  }
}

スクリーンショット 2018-07-11 16.45.48.png

作成ボタンを押してから右上の「テスト」を押すとテストが実行される。

Lambda_Management_Console.png

テストが成功すると以下の様な画面が表示される。
赤く囲った部分が実際にClovaが喋るテキストの部分である。

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3139353838322f65366230326138392d633038342d303539322d386439392d3663643931316361383466302e706e67.png

こんな感じだと、とりあえずちゃんと動いている。

API Gateway

このままではClova側と繋ぐことができないので、API Gatewayを使用する。
API Gatewayとは外部サービスとLambdaを連携させる入り口的な役割。

AWSのサービス一覧からAPI Gatewayのページに行き「APIの作成」ボタンを押す。
次に、以下の様にAPI名と、説明(なくても良い)を入力し「APIの作成」ボタンを押す。

API名: CEKGateway
説明: for CEK Gateway

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3139353838322f33353561303331322d393035632d646630662d373137622d3436353230393464323766352e706e67.png

左上の「アクション」ボタンより「リソースの作成」を押し、以下の様にリソース名を入力し「リソースの作成」ボタンを押す。

リソース名: Fortune

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3139353838322f66336663653332632d666164612d643932302d363435652d6335333463623065313332632e706e67.png

次に、また左上の「アクション」ボタンから「メソッドの作成」ボタンを押す。
すると、ドロップボタンができるので「POST」を選択しすぐ右のチェックボタンを押す。

API_Gateway.png

セットアップ画面になるので、総合タイプを「Lambda関数」を選択し、Lambda関数項目には先ほど作成した「FortuneFunc」を入力する。

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3139353838322f37346163336538312d333066332d373438662d333462612d6634623330393661633864372e706e67.png

権限の追加の許可を聞かれるので「OK」をクリック

スクリーンショット_2018-07-14_12_14_36.png

またまた、左上の「アクション」ボタンから「APIのデプロイ」をクリックする。

API_Gateway.png

入力画面が出てくるので、以下の様に入力し「デプロイ」ボタンを押す。

デプロイされるステージ: 新しいステージ
ステージ名: prod
ステージの説明: production

API_Gateway.png

画面左のディレクトリ構成みたいなところからprod/fortune/POSTを選択すると以下の様な画面になる。
URLの呼び出しってところのURLをメモっておく。
URLの最後の部分が/prod/foutuneとなっているのを確認。

API_Gateway.png

CEK側でLambdaと連携させる

次にいよいよ、CEKとLambdaを連携させる。
先ほどの「スキル設定画面」より「サーバー設定」の欄に行く。

先ほどAPI GatewayでコピーしたURLを「ExtensionサーバーのURL」欄に入力する。
そして、保存。これで完成。

Banners_and_Alerts_と_Clova_Developer_Center_β.png

ブラウザでテスト

ブラウザでちゃんと動くかをテストしてみる。

画面左の、先ほどのビルドボタンのすぐ下あたりにある「テスト」ボタンをクリックする。
すると、ユーザーのサンプル発話をテストできるページが表示されるので私の星座は魚座です。を入力しエンターを押す。

すると、すぐ下にテスト結果が帰ってくる。

「サービスの応答」の項目にCLovaが喋る内容がテキストで帰ってきているのが確認できる。

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3139353838322f37356239613661372d366666372d383030332d616630652d3463376133366438326130352e706e67-2.png

実機でテスト

いよいよ実機でテストをしてみましょう。
実機でテストするには「Clova friends」もしくは、「Clova friends mini」が必要です。
さらには、開発したのと同じアカウントでセットアップしてある必要があります。

実機でのテストは簡単。
「Clova, ほげほげ占いを開いて」と行って見てください。
すると先ほど開発したスキルが起動します。

実機でのテストがうまくいかない。

スキルがうまく起動しない場合、考えられる原因としてClovaが誤認識した可能性があります。
ここでClovaが認識した内容を確認する方法が書かれているので参考にして見てください。

それでも、それでもうまくいかない場合

この記事か、SDKに問題がある場合も考えられるのでTwitterでここに@imasiroooご連絡いただけると助かります。
もちろん、Clova以外のスマートスピーカー開発での質問も受け付けてます。(答えられるかはわからないですが)
皆さんでスマスピを盛り上げていきましょう!!!

最後に

長々としてしまいましたが、読んでいただきありがとうございます。
今回使用したSDKは、日々修正していこうと思います。
もしご要望あればコードの中身だっったり、今回使ってない色々な機能を記事にしていこうかなと思います。

次は、公開には必須のsignature検証についてです。
[入門]Clovaスキル(CEK)は作りながら覚えて行く(signature検証編)

imajoriri
スマートスピーカーが好きすぎてエンジニアになりました。初心者です。主にCEKについて書きます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away