JavaでClovaスキルを作成してみた


はじめに

Javaユーザーグループ北海道(Java Do)が共催した【9/3@札幌】LINE BOOT AWARDS - Clova スキルハンズオンは、ドタ参加の方もいらっしゃって盛況のうちに終了しました。開催にむけてご協力いただいた皆さんありがとうございました。

ハンズオンでは node.js を使っていたのですが、せっかくJUGが共催しているので、ハンズオンを聞きながらほぼ同じ内容を Clova CEK SDK Java で実装していました。

この記事ではこの実装メモを残しておきます。

手順

ここでは、次のような構成を実現します。

[あなた] ----- [Clova] ----- [Spring Boot 上の EchoHandler クラス]

下準備

ハンズオンのテキストとして用いられた、のびすけさんのClova CEKでのスキル開発の始め方〜Node.jsで開発スタート編〜のうち、

3. 使い始めの申請
4. 対話モデルの作成
     インテントとスロット
     スロット
     インテント
5. 対話モデルのビルド

のみっつを同じように進めます。

ここで作成したインテント名 CurreySearchIntent が重要なので、メモしておきます。

Java (Spring Boot) でのClovaスキル実装

のびすけさんの資料では node.js で Clova スキルを実装していますが、ここでは Java (Spring Boot) を使って実装します。

Spring Boot プロジェクトの作成

Spring Initializr にアクセスし、以下の項目を設定します。

  • Spring Bootのバージョン: 2.0.4
  • Artifact: clova_handson
  • Search for dependencies: Web, Devtools (ひとつずつ追加)

Generate Project ボタンで clova.zip をダウンロードします。

clova.zip を展開し、IDE(IntelliJ, Eclipse, Netbeansなど)でMavenプロジェクトとして開きます。

pom.xml の設定

pom.xmlの <dependencies></dependencies> の間に、 Clova CEK SDK Java の dependency を追加します、

pom.xml
<dependencies>

  (中略)

  <dependency>
    <groupId>com.linecorp.clova</groupId>
    <artifactId>clova-extension-boot-web</artifactId>
    <version>1.0.0</version>
  </dependency>

</dependencies>

application.properties

Clovaからのリクエストを受け付けるサーバーのファイルパスを設定します。

application.properties
cek.api-path=/clova

これで、 https://xxxx.../clova でClovaからのPOSTリクエストを受け取れるように設定されます。

(必要があれば cek.client.default-locale なども設定できます)

リクエストハンドラクラスを作成

ClovaからのPOSTリクエストを処理するリクエストハンドラクラスを作成します。

このクラスは、Clova CEK SDK Javaの実装例 を参考に作ってあります。

EchoHandler.java
package com.example.clova;

import com.linecorp.clova.extension.boot.handler.annotation.*;
import com.linecorp.clova.extension.boot.message.response.CEKResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Optional;

import static com.linecorp.clova.extension.boot.message.speech.OutputSpeech.text;

@CEKRequestHandler
public class EchoHandler {

  private static final Logger log = LoggerFactory.getLogger(EchoHandler.class);

  @LaunchMapping
  CEKResponse handleLaunch() {
    return CEKResponse.builder()
      .outputSpeech(text("カレー屋さんを探します。"))
      .shouldEndSession(false)
      .build();
  }

  @IntentMapping("CurreySearchIntent")
  CEKResponse handleRepeatIntent(@SlotValue Optional<String> area) {
    String outputSpeechText = area
      .map(this::callbackShop)
      .orElse("聞き取れませんでした。");
    return CEKResponse.builder()
      .outputSpeech(text(outputSpeechText))
      .shouldEndSession(false)
      .build();
  }

  private String callbackShop(String inArea) {
    switch (inArea) {
      case "秋葉原":
        return inArea + "のオススメのカレー屋は フジヤマドラゴンカレー です。";
      case "神田":
        return inArea + "のオススメのカレー屋は 共栄堂 です。";
      default:
        return "ごめんなさい、わかりませんでした。";
    }
  }

  @IntentMapping("Clova.CancelIntent")
  CEKResponse handleCancelIntent() {
    return CEKResponse.builder()
      .outputSpeech(text("カレー屋さんの検索を終了します。"))
      .shouldEndSession(true)
      .build();
  }

  @SessionEndedMapping
  CEKResponse handleSessionEnded() {
    log.info("カレー屋検索スキルを終了しました。");
    return CEKResponse.empty();
  }

}

いくつか重要な点を解説します。

IntentMapping, SlotValue アノテーション

@IntentMapping は、カスタムインテント名・ビルトインインテント名に対応する処理(メソッド)に付与するアノテーションです。

この例では、@IntentMapping(Clova.CancelIntent) が設定されたメソッド handleCancelIntent() は、スキルがキャンセル(終了)された時のビルトインインテント Clova.CancelIntent に対応します。

また、@IntentMapping(CurreySearchIntent) が設定されたメソッド handleRepeatIntent(@SlotValue...) は、前準備で作成した「秋葉原(area)のカレー屋さん教えて」というClovaへの問いかけに対応します。

引数の @SlotValue は、スロットの値が渡される引数であることを表します。この例では、「秋葉原(area)のカレー屋さん教えて」の area スロットの値が渡されます。

CEKResponse クラス

戻り値に設定されている CEKResponse クラスは、Clovaの返答を表します。builderでインスタンス化します。

outputSpeech は、返答する文字列です。shouldEndSessionは、スキルの終了を行うべきかどうかを true/false で表します。

そのほか

@LaunchMapping は、スキルの起動時に対応するメソッドに付与するアノテーションです。

@SessionEndedMapping は、スキルの終了時に対応するメソッドに付与するアノテーションです。

動作確認

Spring Bootの ClovaApplication クラスを実行します。

のびすけさんのClova CEKでのスキル開発の始め方〜Node.jsで開発スタート編〜 のうち、

 7. ngrokでホスティングせずに疎通確認
10. 実機テスト

の二つを同じように進めます(ngrokは、npmを使わなくても、本家サイトからダウンロード&実行したり、macOS の場合は homebrew を利用してもよいです)。

  • あなた: 「ねぇクローバ」
  • Clova: 「ポンっ(LEDが緑色に光る)」
  • あなた: 「カレー情報を起動して」
  • Clova: 「カレー屋さんを探します。」 (← Java で記述している)
  • Clova: 「ポンっ(LEDが緑色に光る)」
  • あなた: 「秋葉原のカレー屋さんを教えて」
  • Clova: 「秋葉原のオススメのカレー屋はフジヤマドラゴンカレーです。」 (← Java で記述している)

の様にやりとりできれば成功です。

おわりに

Bot(Messaging API)を作成する line-bot-sdk-java と同じように、Clova でも Clova CEK SDK Java を使えば簡単にJavaでClovaスキルを作成できそうです。

なお、対応するスロット(札幌, 千歳)や応答するメッセージが異なりますが、同等のソースコードを gishi-yama/ClovaSample に配置してあります。

引き続き、Botとの連携方法なども挑戦してみたいです。

宣伝

Java で LINE Bot を作るハンズオン資料を公開しています!