Creare una stateful skill per Alice sulle funzioni serverless di Yandex.Cloud e Python

Cominciamo dalle novità. Ieri Yandex.Cloud ha annunciato il lancio di un servizio di elaborazione serverless Funzioni cloud di Yandex. Ciò significa: tu scrivi solo il codice del tuo servizio (ad esempio, un'applicazione web o un chatbot) e il Cloud stesso crea e mantiene le macchine virtuali su cui viene eseguito, e addirittura le replica se il carico aumenta. Non devi pensare affatto, è molto conveniente. E il pagamento vale solo per il tempo dei calcoli.

Tuttavia, alcune persone potrebbero non pagare affatto. Questi sono gli sviluppatori Le competenze esterne di Alice, ovvero chatbot integrati al suo interno. Qualsiasi sviluppatore può scrivere, ospitare e registrare tale competenza, e da oggi le competenze non avranno nemmeno più bisogno di essere ospitate: basta caricare il proprio codice sul cloud nel modulo la stessa funzione serverless.

Ma ci sono un paio di sfumature. Innanzitutto, il codice del tuo animale domestico potrebbe richiedere alcune dipendenze e non è banale trascinarle nel Cloud. In secondo luogo, qualsiasi normale chatbot deve memorizzare lo stato del dialogo da qualche parte (stateful quindi); come farlo in una funzione serverless nel modo più semplice? In terzo luogo, come puoi scrivere un'abilità veloce e sporca per Alice o anche una sorta di bot con una trama diversa da zero? Su queste sfumature, infatti, l'articolo.

Creare una stateful skill per Alice sulle funzioni serverless di Yandex.Cloud e Python

preparazione morale

Per gli impazienti: raccolgo le dipendenze necessarie con un makefile prima di caricare la funzione sul cloud, memorizzo lo stato della finestra di dialogo in Yandex Object Storage (supporta l'API S3) e utilizzo la mia libreria per gestire la finestra di dialogo tgalice. Di conseguenza, si scopre tale abilità dimostrativa. E ora analizziamo tutto questo un po' più nel dettaglio.

Per i meno impazienti, prima di immergersi nella mia storia complessa, consiglio vivamente di iniziare con le cose semplici. Vale a dire, creare una funzione echobot a file singolo, registrarla e testarla nella console per sviluppatori Dialog; dettagli - dentro Dialoghi sul blog и documentazione sul cloud. E solo allora inizia.

Se vuoi sentire subito per cosa stiamo lottando, chiedi ad Alice'attiva l'abilità "Oroscopo IT"'. Dovrebbe aver luogo il seguente dialogo:

Alice: Ciao! Ti trovi nell'abilità "Oroscopo IT". Dì "Inizia" per scoprire cosa ti promettono le stelle.
Utente: Inizia
R: Per favore, indica il tuo nome.
Yu: Vasisualy
A: Ora dimmi l'anno della tua nascita. Solo quattro cifre, niente di più.
Yu: secondo
R: Per favore riprova. Indica l'anno di nascita: quattro cifre.
Yu: 2002
Un grande! Ora dai un nome al mese della tua nascita.
Yu: Febbraio
Un grande! Infine, dimmi la tua data di nascita: solo un numero, solo una o due cifre.
Yu: 18
A: Grazie, Vasisual! Adesso lo sappiamo: hai 17 anni e sei dell'Acquario. Eccoti, ovviamente, fortunato! Te lo dicono le stelle а что говорят звёзды, вы узнаете, запустив навык.

Il problema è che per mantenere anche una finestra di dialogo così semplice è necessario ricordare il nome e la data di nascita dell'utente, e in un ambiente serverless questo non è banale. Non funzionerà per archiviare il contesto nella RAM o come file su disco, perché Yandex.Cloud può eseguire la funzione su più macchine virtuali contemporaneamente e passare da una all'altra in modo arbitrario. Dovrai utilizzare una sorta di memoria esterna. Object Storage è stato scelto come spazio di archiviazione abbastanza economico e semplice direttamente in Yandex.Cloud (cioè probabilmente veloce). Come alternativa gratuita puoi provare, ad esempio, un pezzo gratuito Mongi nuvoloso da qualche parte lontano. Sia Object Storage (supporta l'interfaccia S3) che Mongo hanno comodi wrapper Python.

Un altro problema è che per accedere a Object Storage, MongoDB e qualsiasi altro database o archivio dati, sono necessarie alcune dipendenze esterne che è necessario caricare su Yandex Functions insieme al codice della funzione. E vorrei farlo comodamente. È completamente conveniente (come su Heroku), ahimè, non funzionerà, ma puoi creare un po' di conforto di base scrivendo uno script per costruire l'ambiente (make file).

Come iniziare l'abilità dell'oroscopo

  1. Preparati: vai su qualche macchina con Linux. In linea di principio probabilmente puoi lavorare anche con Windows, ma poi devi evocare il lancio del makefile. E in ogni caso, avrai bisogno di almeno 3.6 Python installato.
  2. Clona da github esempio di un'abilità dell'oroscopo.
  3. Registrati su Ya.Cloud: https://cloud.yandex.ru
  4. Creati due secchi dentro Storage degli oggetti, chiamali con qualsiasi nome {BUCKET NAME} и tgalice-test-cold-storage (questo secondo nome è ora codificato in main.py il mio esempio). Il primo bucket sarà necessario solo per la distribuzione, il secondo per la memorizzazione degli stati dei dialoghi.
  5. creare conto di servizio, dagli un ruolo editore ottenere credenziali statiche per esso {KEY ID} и {KEY VALUE} - li useremo per registrare lo stato del dialogo. Tutto ciò è necessario affinché la funzione di Ya.Cloud possa accedere allo spazio di archiviazione da Ya.Cloud. Un giorno, spero, l'autorizzazione diventerà automatica, ma per ora è così.
  6. (Facoltativo) installa interfaccia della riga di comando yc. Puoi anche creare una funzione tramite l'interfaccia web, ma la CLI è buona perché ogni tipo di innovazione appare più velocemente.
  7. Adesso puoi, infatti, preparare l'assemblaggio delle dipendenze: esegui a riga di comando dalla cartella con la skill example make all. Nella cartella verranno installate un sacco di librerie (per lo più, come al solito, non necessarie). dist.
  8. Riempi con le penne nell'Object Storage (in un secchio {BUCKET NAME}) l'archivio ottenuto nel passaggio precedente dist.zip. Se lo desideri, puoi farlo anche dalla riga di comando, ad esempio utilizzando CLI AWS.
  9. Crea una funzione serverless tramite l'interfaccia web o utilizzando l'utilità yc. Per l'utilità, il comando sarà simile al seguente:

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

Quando si crea manualmente una funzione, tutti i parametri vengono compilati allo stesso modo.

Ora la funzione che hai creato può essere testata tramite la console per sviluppatori, quindi la competenza finalizzata e pubblicata.

Creare una stateful skill per Alice sulle funzioni serverless di Yandex.Cloud e Python

Cosa c'è sotto il cofano

Il makefile in realtà contiene uno script abbastanza semplice per installare le dipendenze e inserirle in un archivio. dist.zip, qualcosa come questo:

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 ./*

Il resto sono alcuni semplici strumenti racchiusi in una libreria tgalice. Il processo di compilazione dei dati utente è descritto dal file config 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 si assume il compito di analizzare questa configurazione e di calcolare il risultato finale

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

Più precisamente, la classe base FormFillingDialogManager si occupa della compilazione del “form”, e del metodo della classe bambino handle_completed_form le dice cosa fare quando sarà pronta.

Oltre a questo flusso di dialogo principale, l'utente deve anche essere salutato, così come dare aiuto sul comando "aiuto" e liberarsi dalla skill sul comando "esci". Per questo dentro tgalice c'è anche un modello, quindi l'intero gestore di dialoghi è composto da pezzi:

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 funziona in modo semplice: cerca di applicare allo stato attuale del dialogo tutti i suoi componenti uno dopo l'altro, e seleziona il primo rilevante.

Come risposta a ciascun messaggio, il gestore dialoghi restituisce un oggetto Python Response, che può poi essere convertito in testo semplice o in un messaggio in Alice o Telegram, a seconda di dove è in esecuzione il bot; contiene anche lo stato modificato della finestra di dialogo che deve essere salvato. Tutta questa cucina è gestita da un'altra classe, DialogConnector, quindi lo script diretto per avviare un'abilità su Yandex Functions è simile al seguente:

...
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

Come puoi vedere, la maggior parte di questo codice crea una connessione all'interfaccia Object Storage S3. Come viene utilizzata direttamente questa connessione, puoi leggere nel codice tgalice.
L'ultima riga crea una funzione alice_handler - quello che abbiamo ordinato di estrarre Yandex.Cloud quando abbiamo impostato il parametro --entrypoint=main.alice_handler.

Questo, in effetti, è tutto. Makefile per la creazione, Object Storage simile a S3 per l'archiviazione del contesto e una libreria Python tgalice. Insieme alle funzionalità serverless e all'espressività di Python, questo è sufficiente per sviluppare l'abilità di una persona sana.

Potresti chiederti perché hai bisogno di creare tgalice? Tutto il codice noioso che trasferisce i JSON dalla richiesta alla risposta e dall'archiviazione alla memoria e viceversa risiede in esso. Esiste anche un'applicazione regolare, una funzione per comprendere che "febbraio" è simile a "febbraio" e altre NLU per i poveri. Secondo la mia idea, questo dovrebbe già essere sufficiente per poter abbozzare i prototipi delle skill nei file yaml senza farsi distrarre troppo dai dettagli tecnici.

Se vuoi una NLU più seria, puoi rovinarla secondo le tue capacità Rasa o Deep Pavlov, ma configurarli richiederà ulteriori danze con un tamburello, soprattutto su serverless. Se non hai affatto voglia di scrivere codice, dovresti usare il costruttore di tipi visivi Aimylogic. Durante la creazione di tgalice, ho pensato a una sorta di percorso intermedio. Vediamo cosa succede.

Bene, ora unisciti Chat per gli sviluppatori delle competenze di Aliy, leggere documentazionee creare incredibili навыки!

Fonte: habr.com

Aggiungi un commento