LoginSignup
1

More than 3 years have passed since last update.

posted at

LINEBOTで会話のステータス(文脈)管理(セッション管理?)

やりたいこと

会話のステータス(文脈)のようなものをサーバー側に持たせておいて(Webアプリのセッションみたいな感じ?)、それによって応答が変わるようなLINEBOTを作りたい。

イメージとしてはこんな感じ。
image.png

自然言語解析とか、DeepLearningとか、RNNとか、雑談BOTとか、そういった高度な話ではありません。

実現方法

ユーザーIDをkey、保存すべき値を集めたクラスをvalueにしたmapを作成することにしました。

その他、メッセージに応答する箇所の実装はsample-spring-boot-kitchensinkを参考にしました(replyTextメソッド)。
言語はJavaです。

実はもっと王道の方法(≒ライブラリ、フレームワーク)がある、ということがあれば是非教えてください。

ステータスを保存するクラス

Status.java
public class Status {

    private String context = "0";//ステータス
    private String place = "";//場所

    public String getContext() {
        return context;
    }
    public void setContext(String context) {
        this.context = context;
    }

    public String getPlace() {
        return place;
    }
    public void setPlace(String place) {
        this.place = place;
    }

}

マップ

PseudoSession.java
public class PseudoSession {

    private static Map<String,Status> statusMap = new HashMap<>();

    public static Status getStatus(String userId) {
        return PseudoSession.statusMap.get(userId);
    }

    public static void putStatus(String userId, Status status) {
        PseudoSession.statusMap.put(userId, status);
    }

    public static String readContext(String userId) {
        return PseudoSession.statusMap.get(userId).getContext();
    }

    public static String readPlace(String userId) {
        return PseudoSession.statusMap.get(userId).getPlace();
    }

    public static void updateContext(String userId, String context) {
        Status newStatus = PseudoSession.statusMap.get(userId);
        newStatus.setContext(context);
        PseudoSession.statusMap.put(userId, newStatus);
    }

    public static void updatePlace(String userId, String place) {
        Status newStatus = PseudoSession.statusMap.get(userId);
        newStatus.setPlace(place);
        PseudoSession.statusMap.put(userId, newStatus);
    }

}

メインの処理

Controller.java
    private void handleTextContent(String replyToken, Event event, TextMessageContent content)
            throws Exception {
        final String text = content.getText();
        final String userId = event.getSource().getUserId();

        //初めてアクセスするユーザーの場合、mapに値を入れる
        if (Objects.isNull(PseudoSession.getStatus(userId))) {
            PseudoSession.putStatus(userId, new Status());
        }

        if(PseudoSession.readContext(userId).equals("0")) {

            if (text.equals("天気教えて")) {
                this.replyText(replyToken,"どこの天気?");
                PseudoSession.updateContext(userId,"1");
            } else {
                this.replyText(replyToken,"「天気教えて」って入力してみて!");
            }

        }else if (PseudoSession.readContext(userId).equals("1")) {

            if (!("富山".equals(text))&&!("石川".equals(text))) {
                this.replyText(replyToken,"富山か石川しか分からないんだ");
            } else {
                this.replyText(replyToken,"いつの天気?");
                PseudoSession.updatePlace(userId,text);
                PseudoSession.updateContext(userId,"2");
            }

        }else if (PseudoSession.readContext(userId).equals("2")) {

            if (!("今日".equals(text))&&!("明日".equals(text))) {
                this.replyText(
                        replyToken,"今日か明日しか分からないんだ");
            } else {
                String answer = text + "の"
                        + PseudoSession.readPlace(userId) + "の"
                        + "天気は晴れです。";
                this.replyText(replyToken,answer);
                PseudoSession.updatePlace(userId,"");
                PseudoSession.updateContext(userId,"0");
            }
        }
    }

結果

image.png

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1