[PYTHON] Conseils pour créer un bot interactif avec LINE

Bonjour, c'est Ninomiya de LIFULL CO., LTD. J'ai participé à l'implémentation prototype du bot LINE cette année.

Pour le développement LINE, SDK est également disponible dans des langages tels que Python, et vous pouvez facilement commencer à créer un robot simple. Cependant, si vous essayez de créer une application qui est plus compliquée qu'un certain niveau, elle sera un peu difficile à implémenter, comme la gestion de scénarios et la génération de FlexMessage json.

Pour ceux qui l'implémenteront ensuite, je partagerai les points que j'ai imaginés principalement dans l'implémentation du bot LINE.

Activé pour gérer les scénarios dans le fichier de paramètres

Le fichier de configuration vous donne un aperçu du scénario d'interaction. L'implémentation est telle que l'expression régulière est définie par trigger_message dans senario, et le contrôleur défini par ʻendpoint` est appelé lorsqu'il correspond.

config.json


//En raison des spécifications de json, les commentaires ne peuvent pas être saisis, mais ils sont inclus pour plus de commodité.
{
  "scenario": {
    "initial": {
      "trigger_message": "Démarrer le bot",
      "endpoint": "controllers.initial",
      "possible_replies": [
        "initial"
      ]
    },
    //Réponse à la recherche de produits. lors de l'événement de publication"method: first_search, target:Livre"Supposé qu'une valeur telle que est envoyée dynamiquement
    "search_products": {
      "trigger_message": "method: search_products, target: (?P<target>[\\s\\S]+)",
      "endpoint": "controllers.search_products",
      "possible_replies": [
        "selection"
      ]
    },
    //Choix par défaut
    "default": {
      "endpoint": "controllers.default",
      "possible_replies": [
        "default"
      ]
    }
 },
  "replies": {
    "initial": {
      "view": "views.initial",
      "template": [
        {
          "mode": "text",
          "text": "Sélectionnez la fonction que vous souhaitez appeler"
        },
        {
          "mode": "flex",
          "template": "flex_messages/buttons.tpl.json",
          "alt_text": "Les choix"
        }
      ]
    }, 
    "products": {
      "view": "views.search_result",
      "template": [
        {
          "mode": "text",
          "text": "J'ai recherché un produit"
        },
        {
          "mode": "flex",
          "template": "flex_messages/products.tpl.json",
          "alt_text": "Produits recommandés"
        }
      ]
    }
  }
}

[Automate limité] du dialogue avec le bot (https://ja.wikipedia.org/wiki/%E6%9C%89%E9%99%90%E3%82%AA%E3%83%BC%E3%83 Considérant% 88% E3% 83% 9E% E3% 83% 88% E3% 83% B3), le message du bot est fait avec l'image que l'état est sélectionné par le bouton pour sélectionner la prochaine transition de l'utilisateur. Toutefois, comme le contenu de l'événement de publication est créé dans le message au lieu du fichier de paramètres, il ne gère pas le type de transition effectué par l'utilisateur.

Depuis que je l'ai implémenté en Python, j'ai utilisé importlib pour appeler le contrôleur. Aussi, je l'ai implémenté avec json, mais il est difficile de commenter, alors faites-le yaml ou par exemple, Django dispatcher Il peut être préférable de pouvoir écrire un script qui associe le message d'entrée à la classe que vous souhaitez exécuter, comme / http / urls /).

trigger_message est analysé avec une expression régulière, et le contrôleur l'appelle comme argument comme indiqué ci-dessous. Cette fois, comme événement de publication, c'est comme "l'utilisateur appuie sur le bouton préparé ici", alors déclenchez l'expression régulière (Publier), mais si vous souhaitez répondre librement, utilisez un outil tel que Dialogflow pour définir le contexte (contrôleur pour démarrer) et l'entité (son argument). ..

script/controllers/search_products/__init__.py


from script.controllers._utils import AbstractController, Response, render, UserContext
from script.models import search_model

class Controller(AbstractController):
    """Contrôleur qui donne le premier choix"""

    def call(self, user_context: UserContext, target: str) -> Response:
        """Traitement des appels du contrôleur

        Args:
            user_context:Classe qui encapsule l'identifiant, etc.
            target:Contenu analysé avec une capture nommée d'une expression régulière
        Returns:
Répondre à l'utilisateur

        """
        products = search_model.search(target)
        return render("initial", proc=lambda view: view.render(products=products))

FlexMessage a été assemblé avec le moteur de modèle (jinja2)

Dans LINE, vous pouvez utiliser Messages avec une mise en page flexible appelée FlexMessage.

Pour ce faire, vous devez assembler un json complexe pour FlexMessage et envoyer l'API LINE Reply. J'ai d'abord créé FlexMessage avec un dictionnaire Python, mais c'était assez difficile, alors j'ai fait référence à cet article et j'ai utilisé le modèle du moteur de modèle (jinja2). Je l'ai préparé et mis en œuvre en vue.

Cependant, si vous l'avez conçu à l'aide de Simulator, il serait fastidieux de le réécrire dans un modèle SDK. La source sera également plus longue. Dans un tel cas, il semble préférable d'utiliser le moteur de modèle pour incorporer la valeur dans JSON et convertir le résultat dans le modèle SDK. Il existe une méthode appelée new_from_json_dict () pour construire un modèle à partir de JSON.

Je l'ai implémenté dans jinja2, mais je ne pense pas que cela changera beaucoup dans d'autres langues et bibliothèques.

https://palletsprojects.com/p/jinja/

{
  "type": "carousel",
  "contents": [
{% for product in products %}
    {
      "type": "bubble",
      "body": {
        "type": "box",
        "layout": "vertical",
        "contents": [
          {
            "type": "box",
            "layout": "horizontal",
            "contents": [
              {
                "type": "image",
                "url": {{ product.image | json_escape }},
                "size": "full",
                "aspectMode": "cover",
                "action": {
                  "type": "uri",
                  "uri": {{ product.url | json_escape }}
                }
              }
            ]
          },
//Ce qui suit est omis

L'état réel de json_escape ici est json.dumps, qui exécute le processus" d'échapper à la chaîne et d'ajouter "" "pour s'assurer que le json correct est assemblé."

class JsonTemplete(object):
    ENV = Environment(loader=FileSystemLoader(
        str(Path(__file__).resolve().parent / "../templetes"), encoding='utf8'))
    ENV.filters["json_escape"] = json.dumps

#Ce qui suit est omis

Chargez-le dans le SDK avec la méthode appelée new_from_json_dict et utilisez-la.

    def __build_contents(self, content):
        """Triez les types de conteneurs dans FlexSendMssage.
        Args:
            content (dict):Informations sur le conteneur
        Returns:
            BubbleContainer/CarouselContainer:Conteneur dans FlexSendMessage
        """
        t = content["type"]
        if t == "bubble":
            return BubbleContainer.new_from_json_dict(content)
        elif t == "carousel":
            return CarouselContainer.new_from_json_dict(content)
        else:
            raise RuntimeError(f"C'est un conteneur non pris en charge: {t}")

Cependant, dans le cas de "la grammaire est correcte pour json, mais les spécifications de message LINE ne sont pas satisfaites", le problème que le débogage est un peu gênant demeure. Je ne peux pas penser à une bonne solution pour cela, alors faites-le moi savoir si vous avez des connaissances.

Autres points avec lesquels j'ai eu du mal dans le projet LINE

Selon le modèle et les paramètres du smartphone de l'utilisateur, l'apparence de FlexMessage a changé (par exemple, les caractères étaient plus grands que prévu et des sauts de ligne étaient insérés), et parfois il ne ressemblait pas à ce que vous attendiez. Vous ne pouvez pas spécifier la taille de la police en détail, vous ne devriez donc pas viser un design très élaboré.

De plus, comme on le dit souvent dans d'autres articles, il est facile d'ajuster l'apparence avec FlexMssageSimulator et d'incorporer le contenu du bouton dans le modèle pour l'implémenter. ..

à la fin

J'espère que cet article sera utile pour ceux qui commencent à implémenter des chatbots.

Cet article est le premier article du Calendrier de l'Avent LIFULL. Merci pour votre soutien continu.

Recommended Posts

Conseils pour créer un bot interactif avec LINE
Conseils pour créer de petits outils avec python
Conseils pour utiliser Realsense SR300 sur MacBook en 2020
Procédure de création d'un Line Bot sur AWS Lambda
Rechercher des fichiers volumineux sous Linux à partir de la ligne de commande