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

Commençons par les nouvelles. Hier, Yandex.Cloud a annoncé le lancement du service informatique sans serveur Yandex Cloud Functions . 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 des machines virtuelles là où il démarre, et même les réplique si la charge augmente. Il n'est pas nécessaire de penser du tout, c'est très pratique. Et les frais ne vont que lors du calcul.


Cependant, certains peuvent ne pas payer du tout. Ce sont les développeurs des compétences externes d' Alice , c'est-à-dire les chatbots intégrés en elle. Tout 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 dans le cloud sous la forme de la fonction très sans serveur .


Mais il y a quelques nuances. Tout d'abord, votre code d'animal de compagnie peut nécessiter certaines dépendances, et les tirer dans le Cloud n'est pas anodin. Deuxièmement, tout chatbot normal doit stocker quelque part l'état du dialogue (avec état par conséquent); comment faire cela dans une fonction sans serveur la plus simple? Troisièmement, comment pouvez-vous écrire rapidement et sale une compétence pour Alice ou une sorte de bot avec un tracé non nul? À propos de ces nuances, en fait, un article.


image

Entraînement moral


Pour les impatients: je collecte les dépendances nécessaires avec un make-file avant de télécharger la fonction dans le cloud, je stocke l'état du dialogue dans Yandex Object Storage (il supporte l'API S3), et pour gérer le dialogue j'utilise ma propre bibliothèque tgalice . Le résultat est une telle compétence de démonstration. Voyons maintenant tout cela plus en détail.


Pour un peu moins d'impatience: avant de plonger dans mon histoire sur les difficultés, je recommande fortement de commencer par une simple. À savoir, créer une fonction de sondeur d'écho à fichier unique, l'enregistrer et la tester dans la console de développement Dialogs; les détails sont sur le blog Dialogues et documentation sur le cloud . Et alors seulement pour continuer.


Si vous voulez ressentir immédiatement ce pour quoi nous nous battons, demandez à Alice d' activer la compétence "Horoscope informatique " . La boîte de dialogue suivante devrait apparaître:


Alice: Salut! Vous êtes dans la compétence de Aishish Horoscope. Dites «Commencer» pour découvrir ce que les étoiles vous promettent.
Utilisateur: Démarrer
R: Veuillez donner votre nom.
Yu: Vasisuali
R: Dites-moi maintenant l'année de votre naissance. Seulement quatre chiffres, rien de plus.
Yu: deuxième
R: Veuillez réessayer. Quelle est l'année de votre naissance - quatre chiffres.
U: 2002
R: Génial! Nommez maintenant le mois de votre naissance.
U: février
R: Génial! Enfin, dites-moi la date de votre naissance - seulement un nombre, juste un ou deux chiffres.
U: 18
R: Merci, Vasisuali! Maintenant, nous savons: vous avez 17 ans et vous êtes le Verseau. Ici, vous avez bien sûr de la chance! Les étoiles vous disent: , , .


Le problème est que pour maintenir même un dialogue aussi simple, vous devez vous souvenir du nom et de la date de naissance de l'utilisateur, et dans un environnement sans serveur, ce n'est pas anodin. Stockez le contexte dans la RAM ou un fichier sur le disque ne fonctionnera pas, car Yandex.Cloud peut exécuter la fonction sur plusieurs machines virtuelles en même temps et basculer entre elles arbitrairement. Nous devrons utiliser une sorte de stockage externe. Le stockage d'objets a été choisi comme un stockage plutôt peu coûteux et simple dans Yandex.Cloud (c'est-à-dire probablement rapide). Comme alternative gratuite, vous pouvez essayer, par exemple, un morceau gratuit de Monga nuageux quelque part très loin. Le stockage d'objets (il prend en charge l'interface S3) et Mongo ont des wrappers Python pratiques.


Un autre problème est que pour marcher dans Object Storage, dans MongoDB et dans toute autre base de données ou entrepôt de données, vous avez besoin de certaines dépendances externes que vous devez télécharger vers Yandex Functions avec votre code de fonction. Et je voudrais le faire commodément. C'est assez pratique (comme 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 exécuter une compétence horoscope


  1. Préparez-vous: allez sur une machine Linux. En principe, vous pouvez également travailler avec Windows, mais vous devez alors évoquer le lancement du fichier make. Et dans tous les cas, vous aurez besoin d'un Python installé inférieur à 3.6.
  2. Clonez-vous avec github un exemple de compétence horoscope .
  3. Inscrivez-vous dans Y. Cloud: https://cloud.yandex.ru
  4. Créez deux compartiments pour vous-même dans Object Storage , nommez-les avec n'importe quel nom {BUCKET NAME} et tgalice-test-cold-storage (ce deuxième nom est maintenant codé en dur dans main.py mon exemple). Le premier compartiment sera nécessaire uniquement pour le déploiement, le second - pour le stockage des états de dialogue.
  5. Créez un compte de service , donnez-lui le rôle d' editor et obtenez les cartes de crédit statiques {KEY ID} et {KEY VALUE} - nous les utiliserons pour enregistrer l'état du dialogue. Tout cela est nécessaire pour qu'une fonction de Y. Cloud puisse accéder au référentiel depuis Y. Cloud. Un jour, j'espère que l'autorisation deviendra automatique, mais pour l'instant - oui.
  6. (Facultatif) installez l'interface de ligne de commande yc . Vous pouvez créer une fonction via l'interface Web, mais la CLI est bonne en ce sens que toutes sortes d'innovations y apparaissent plus rapidement.
  7. Vous pouvez maintenant, en fait, préparer l'assembly de dépendance: exécutez-le à l'invite de commande à partir d'un dossier avec l'exemple de compétence make all . Un tas de bibliothèques (surtout, comme d'habitude, inutiles) seront installées dans le dossier dist .
  8. Versez dans Object Storage (dans le {BUCKET NAME} ) l'archive dist.zip obtenue à l'étape précédente. Si vous le souhaitez, vous pouvez le faire à partir de la ligne de commande, par exemple, en utilisant l' AWS CLI .
  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 maintenant être testée via la console du développeur, puis modifier et publier la compétence.



Sous le capot


Le makefile contient en fait un script assez simple pour installer les dépendances et les mettre dans l'archive dist.zip , quelque chose comme ceci:


 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 quelques outils simples enveloppés dans la bibliothèque tgalice . Le processus de remplissage des données utilisateur est décrit par la form.yaml 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: ,   .       (, );     . 

Le travail d'analyse de cette configuration et de calcul du résultat final est effectué par la classe python


 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 est engagée dans le remplissage du "formulaire", et la méthode de la classe enfant handle_completed_form indique quoi faire lorsqu'elle est prête.


En plus de ce flux principal du dialogue de l'utilisateur, vous devez également saluer, ainsi que donner de l'aide sur la commande "help" et libérer de la compétence sur la commande "exit". tgalice également un modèle pour cela, donc tout le gestionnaire de dialogue est composé de morceaux:


 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 à tour de rôle tous ses composants à l'état actuel du dialogue et sélectionne le premier approprié.


En réponse à chaque message, le gestionnaire de boîtes de dialogue renvoie un objet Response , qui peut être converti en texte nu ou en message dans Alice ou Telegram, selon l'endroit où le bot est lancé; il contient également l'état modifié du dialogue, qui doit être enregistré. Une autre classe, DialogConnector , est engagée dans toute cette cuisine, donc le script direct pour lancer la 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 voir, la plupart de ce code crée une connexion à l'interface Object Storage S3. La façon dont cette connexion est directement utilisée peut être lue dans le code tgalice .
La dernière ligne crée la fonction alice_handler - celle que nous avons ordonné à Yandex.Cloud de tirer lorsque nous définissons le --entrypoint=main.alice_handler .


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


Vous pouvez vous demander, pourquoi avez tgalice vous eu besoin de créer tgalice ? Tout le code ennuyeux qui transfère les JSON de la demande à la réponse et du stockage à la mémoire et vice-versa s'y trouve. Il existe également une application de contrôleur régulière, une fonction permettant de comprendre ce que «février» est comme «février» et d'autres NLU pour les pauvres. Selon mon idée, cela devrait déjà être suffisant pour que vous puissiez esquisser des prototypes de compétences dans des fichiers yaml sans être trop distrait par des détails techniques.


Si vous voulez une NLU plus sérieuse, vous pouvez visser Rasa ou DeepPavlov à votre compétence, mais pour les configurer, vous aurez besoin de danses supplémentaires avec un tambourin, surtout sans serveur. Si vous n'avez pas du tout envie de coder, vous devez utiliser un constructeur visuel comme Aimylogic . En créant tgalice, je pensais à une sorte de chemin intermédiaire. Voyons ce qui se passe.


Eh bien, rejoignez maintenant le chat des développeurs de leurs compétences , lisez la documentation et créez de merveilleuses compétences !

Source: https://habr.com/ru/post/fr469723/


All Articles