Création d'une compétence avec état pour Alice sur les fonctions sans serveur de Yandex.Cloud et Python

Commençons par l'actualité. Hier, Yandex.Cloud a annoncé le lancement d'un service informatique sans serveur Fonctions cloud Yandex. Cela signifie : vous écrivez uniquement le code de votre service (par exemple, une application Web ou un chatbot), et le Cloud lui-même crée et maintient les machines virtuelles sur lesquelles il s'exécute, et les réplique même si la charge augmente. Vous n’avez pas besoin de réfléchir du tout, c’est très pratique. Et le paiement ne dure que le temps des calculs.

Cependant, certaines personnes peuvent ne pas payer du tout. Ce sont les développeurs Les compétences externes d'Alice, c'est-à-dire des chatbots intégrés. N'importe quel développeur peut écrire, héberger et enregistrer une telle compétence, et à partir d'aujourd'hui, les compétences n'ont même plus besoin d'être hébergées : il suffit de télécharger leur code sur le cloud sous le formulaire la même fonction sans serveur.

Mais il y a quelques nuances. Premièrement, votre code animal peut nécessiter certaines dépendances, et il n'est pas anodin de les glisser dans le Cloud. Deuxièmement, tout chatbot normal doit stocker l'état de la boîte de dialogue quelque part (avec état donc) ; comment le faire dans une fonction sans serveur de la manière la plus simple ? Troisièmement, comment pouvez-vous écrire une compétence rapide et sale pour Alice ou même une sorte de robot avec une intrigue non nulle ? Sur ces nuances, en fait, l'article.

Création d'une compétence avec état pour Alice sur les fonctions sans serveur de Yandex.Cloud et Python

préparation morale

Pour les impatients : je collecte les dépendances nécessaires avec un makefile avant de télécharger la fonction sur le cloud, je stocke l'état de la boîte de dialogue dans Yandex Object Storage (il prend en charge l'API S3) et j'utilise ma propre bibliothèque pour gérer la boîte de dialogue tgalice. En conséquence, il s'avère tel compétence de démonstration. Et maintenant analysons tout cela un peu plus en détail.

Pour les moins impatients, avant de plonger dans mon histoire de complexité, je recommande fortement de commencer simple. À savoir, créez une fonction echobot à fichier unique, enregistrez-la et testez-la dans la console de développement Dialog ; détails - dans Dialogues de blogs и documentation cloud. Et alors seulement, commencez.

Si vous voulez ressentir immédiatement ce pour quoi nous nous battons, demandez à Alice'activez la compétence "Horoscope informatique"'. Le dialogue suivant devrait avoir lieu :

Alice : Bonjour ! Vous êtes dans la compétence « Horoscope informatique ». Dites « Commencer » pour découvrir ce que les étoiles vous promettent.
Utilisateur : Démarrer
R : Veuillez indiquer votre nom.
Yu : Vasisualy
R : Maintenant, dis-moi l'année de ta naissance. Seulement quatre chiffres, rien de plus.
Yu : deuxième
R : Veuillez réessayer. Indiquez l'année de votre naissance - quatre chiffres.
Yu : 2002
Un grand! Nommez maintenant le mois de votre naissance.
Yu : février
Un grand! Enfin, dites-moi votre date de naissance – juste un chiffre, juste un ou deux chiffres.
Yu : 18
R : Merci, Vasisual ! Maintenant, nous le savons : vous avez 17 ans et vous êtes Verseau. Ici, vous avez bien sûr de la chance ! Les étoiles te le disent а что говорят звёзды, вы узнаете, запустив навык.

Le problème est que pour maintenir même une boîte de dialogue aussi simple, vous devez vous souvenir du nom et de la date de naissance de l'utilisateur, et dans un environnement sans serveur, cela n'est pas anodin. Cela ne fonctionnera pas de stocker le contexte dans la RAM ou sous forme de fichier sur le disque, car Yandex.Cloud peut exécuter la fonction sur plusieurs machines virtuelles en même temps et basculer arbitrairement entre elles. Vous devrez utiliser une sorte de stockage externe. Object Storage a été choisi comme stockage assez peu coûteux et simple directement dans Yandex.Cloud (c'est-à-dire probablement rapide). Comme alternative gratuite, vous pouvez essayer, par exemple, une pièce gratuite Mongi nuageux Quelque part au loin. Object Storage (il prend en charge l’interface S3) et Mongo disposent tous deux de wrappers Python pratiques.

Un autre problème est que pour accéder à Object Storage, MongoDB et à toute autre base de données ou magasin de données, vous avez besoin de certaines dépendances externes que vous devez télécharger sur Yandex Functions avec votre code de fonction. Et j'aimerais le faire confortablement. C'est tout à fait pratique (comme sur heroku), hélas, ça ne marchera pas, mais vous pouvez créer un certain confort de base en écrivant un script pour construire l'environnement (make file).

Comment démarrer la compétence horoscope

  1. Préparez-vous : accédez à une machine avec Linux. En principe, vous pouvez probablement aussi travailler avec Windows, mais vous devrez ensuite lancer le makefile. Et dans tous les cas, vous aurez besoin d'au moins 3.6 Python installé.
  2. Cloner depuis github exemple de compétence d'horoscope.
  3. Inscrivez-vous sur Ya.Cloud : https://cloud.yandex.ru
  4. Créez-vous deux seaux dans Stockage d'objets, appelle-les par n'importe quel nom {BUCKET NAME} и tgalice-test-cold-storage (ce deuxième prénom est désormais codé en dur dans main.py mon exemple). Le premier compartiment ne sera nécessaire que pour le déploiement, le second est destiné au stockage des états de dialogue.
  5. Créer compte de service, donne-lui un rôle editor, et obtenez des informations d'identification statiques pour cela {KEY ID} и {KEY VALUE} - nous les utiliserons pour enregistrer l'état du dialogue. Tout cela est nécessaire pour que la fonction de Ya.Cloud puisse accéder au stockage de Ya.Cloud. Un jour, j'espère, l'autorisation deviendra automatique, mais pour l'instant, c'est le cas.
  6. (Facultatif) installer interface de ligne de commande yc. Vous pouvez également créer une fonction via l'interface Web, mais la CLI est bonne car toutes sortes d'innovations y apparaissent plus rapidement.
  7. Maintenant vous pouvez en effet préparer l'assemblage des dépendances : exécutez en ligne de commande depuis le dossier avec la compétence exemple make all. Un tas de bibliothèques (pour la plupart, comme d'habitude, inutiles) seront installées dans le dossier dist.
  8. Remplissez de stylos dans Object Storage (dans un seau {BUCKET NAME}) l'archive obtenue à l'étape précédente dist.zip. Si vous le souhaitez, vous pouvez également le faire à partir de la ligne de commande, par exemple en utilisant CLI AWS.
  9. Créez une fonction sans serveur via l'interface web ou à l'aide de l'utilitaire yc. Pour l'utilitaire, la commande ressemblera à ceci :

yc serverless function version create
    --function-name=horoscope
    --environment=AWS_ACCESS_KEY_ID={KEY ID},AWS_SECRET_ACCESS_KEY={KEY VALUE}
    --runtime=python37
    --package-bucket-name={BUCKET NAME}
    --package-object-name=dist.zip
    --entrypoint=main.alice_handler
    --memory=128M
    --execution-timeout=3s

Lors de la création manuelle d'une fonction, tous les paramètres sont renseignés de la même manière.

La fonction que vous avez créée peut désormais être testée via la console développeur, puis finalisée et publiée.

Création d'une compétence avec état pour Alice sur les fonctions sans serveur de Yandex.Cloud et Python

Qu'y a-t-il sous le capot

Le makefile contient en fait un script assez simple pour installer les dépendances et les placer dans une archive. dist.zip, quelque chose comme ça:

mkdir -p dist/
pip3 install -r requirements.txt --target dist/ 
cp main.py dist/main.py
cp form.yaml dist/form.yaml
cd dist && zip --exclude '*.pyc' -r ../dist.zip ./*

Le reste est constitué de quelques outils simples regroupés dans une bibliothèque tgalice. Le processus de remplissage des données utilisateur est décrit par la configuration form.yaml:

form_name: 'horoscope_form'
start:
  regexp: 'старт|нач(ать|ни)'
  suggests:
    - Старт
fields:
  - name: 'name'
    question: Пожалуйста, назовите своё имя.
  - name: 'year'
    question: Теперь скажите мне год вашего рождения. Только четыре цифры, ничего лишнего.
    validate_regexp: '^[0-9]{4}$'
    validate_message: Пожалуйста, попробуйте ещё раз. Назовите год вашего рождения - четыре цифры.
  - name: 'month'
    question: Замечательно! Теперь назовите месяц вашего рождения.
    options:
      - январь
     ...
      - декабрь
    validate_message: То, что вы назвали, не похоже на месяц. Пожалуйста, назовите месяц вашего рождения, без других слов.
  - name: 'day'
    question: Отлично! Наконец, назовите мне дату вашего рождения - только число, всего одна или две цифры.
    validate_regexp: '[0123]?d$'
    validate_message: Пожалуйста, попробуйте ещё раз. Вам нужно назвать число своего рождения (например, двадцатое); это одна или две цифры.

La classe python prend en charge le travail d'analyse de cette configuration et le calcul du résultat final

class CheckableFormFiller(tgalice.dialog_manager.form_filling.FormFillingDialogManager):
    SIGNS = {
        'январь': 'Козерог',
        ...
    }

    def handle_completed_form(self, form, user_object, ctx):
        response = tgalice.dialog_manager.base.Response(
            text='Спасибо, {}! Теперь мы знаем: вам {} лет, и вы {}. n'
                 'Вот это вам, конечно, повезло! Звёзды говорят вам: {}'.format(
                form['fields']['name'],
                2019 - int(form['fields']['year']),
                self.SIGNS[form['fields']['month']],
                random.choice(FORECASTS),
            ),
            user_object=user_object,
        )
        return response

Plus précisément, la classe de base FormFillingDialogManager s'occupe de remplir le "formulaire" et la méthode de la classe enfant handle_completed_form dit quoi faire quand elle est prête.

En plus de ce flux principal du dialogue de l'utilisateur, il est également nécessaire de saluer l'utilisateur, ainsi que d'émettre de l'aide sur la commande "help" et de libérer la compétence sur la commande "exit". Pour cela dans tgalice il existe également un modèle, donc l'ensemble du gestionnaire de dialogue est composé de plusieurs éléments :

dm = tgalice.dialog_manager.CascadeDialogManager(
    tgalice.dialog_manager.GreetAndHelpDialogManager(
        greeting_message=DEFAULT_MESSAGE,
        help_message=DEFAULT_MESSAGE,
        exit_message='До свидания, приходите в навык "Айтишный гороскоп" ещё!'
    ),
    CheckableFormFiller(`form.yaml`, default_message=DEFAULT_MESSAGE)
)

CascadeDialogManager fonctionne simplement : il essaie d'appliquer à l'état actuel du dialogue tous ses composants tour à tour, et sélectionne le premier pertinent.

En réponse à chaque message, le gestionnaire de dialogue renvoie un objet python Response, qui peut ensuite être converti en texte brut, ou en message dans Alice ou Telegram - selon l'endroit où le bot s'exécute ; il contient également l'état modifié de la boîte de dialogue qui doit être enregistré. Toute cette cuisine est gérée par une autre classe, DialogConnector, donc le script direct pour démarrer une compétence sur Yandex Functions ressemble à ceci :

...
session = boto3.session.Session()
s3 = session.client(
    service_name='s3',
    endpoint_url='https://storage.yandexcloud.net',
    aws_access_key_id=os.environ['AWS_ACCESS_KEY_ID'],
    aws_secret_access_key=os.environ['AWS_SECRET_ACCESS_KEY'],
    region_name='ru-central1',
)
storage = tgalice.session_storage.S3BasedStorage(s3_client=s3, bucket_name='tgalice-test-cold-storage')
connector = tgalice.dialog_connector.DialogConnector(dialog_manager=dm, storage=storage)
alice_handler = connector.serverless_alice_handler

Comme vous pouvez le constater, la plupart de ce code crée une connexion à l'interface Object Storage S3. Comment cette connexion est directement utilisée, vous pouvez lire en code tgalice.
La dernière ligne crée une fonction alice_handler - celui que nous avons ordonné d'extraire Yandex.Cloud lorsque nous définissons le paramètre --entrypoint=main.alice_handler.

En fait, c'est tout. Makefiles pour la construction, stockage d'objets de type S3 pour le stockage contextuel et bibliothèque Python tgalice. Avec les fonctionnalités sans serveur et l'expressivité de Python, cela suffit pour développer les compétences d'une personne en bonne santé.

Vous vous demandez peut-être pourquoi vous devez créer tgalice? Tout le code ennuyeux qui transfère les JSON de la requête à la réponse et du stockage à la mémoire et inversement s'y trouve. Il existe également une application régulière, une fonction permettant de comprendre que « février » est similaire à « février », et d'autres NLU pour les pauvres. Selon mon idée, cela devrait déjà suffire pour pouvoir dessiner des prototypes de compétences dans des fichiers yaml sans trop être distrait par les détails techniques.

Si vous voulez un NLU plus sérieux, vous pouvez le visser à votre compétence Rasa ou ProfondPavlov, mais leur configuration nécessitera une danse supplémentaire avec un tambourin, en particulier sur les serveurs sans serveur. Si vous n’avez pas du tout envie de coder, vous devriez utiliser le constructeur de type visuel Aimylogique. Lors de la création de tgalice, j'ai pensé à une sorte de chemin intermédiaire. Voyons ce qui se passe.

Eh bien, maintenant rejoignez Chat des développeurs de compétences Aliy, lis documentationet créer d'incroyables compétences!

Source: habr.com

Ajouter un commentaire