Creazione di un skill stateful per Alice su funzioni serverless di Yandex.Cloud e Python

Cominciamo con le notizie. Ieri Yandex.Cloud ha annunciato il lancio del servizio di calcolo serverless Yandex Cloud Functions. Questo significa: scrivi solo il codice del tuo servizio (ad esempio, un'app web o un chatbot), mentre il Cloud crea e gestisce da solo le macchine virtuali su cui viene eseguito, e addirittura le replica se il carico aumenta. Non devi nemmeno pensarci, molto comodo. E paghi solo per il tempo di calcolo.

Tuttavia, alcuni potrebbero non dover pagare affatto. Sono gli sviluppatori di skill esterne per Alice, ossia i chatbot integrati. Chiunque può scrivere, ospitare e registrare una skill del genere, e da oggi non è nemmeno necessario ospitarle: basta caricare il loro codice nel cloud come quella famigerata funzione serverless.

Ma ci sono un paio di dettagli. In primo luogo, il tuo codice Python potrebbe richiedere alcune dipendenze, e portarle nel Cloud non è triviale. In secondo luogo, qualsiasi chatbot normale ha bisogno di memorizzare da qualche parte lo stato del dialogo (stateful, quindi); come fare per gestirlo in una funzione serverless nel modo più semplice? In terzo luogo, come si può scrivere velocemente e in modo 'sporco' una skill per Alice o per un bot qualsiasi con una trama non banale? Su questi dettagli tratta, in sostanza, l'articolo.

Creazione di un skill stateful per Alice su funzioni serverless di Yandex.Cloud e Python

Preparazione morale

Per gli impazienti: raccolgo le dipendenze necessarie con un file make prima di caricare la funzione nel cloud, memorizzo lo stato del dialogo nello Yandex Object Storage (supporta l'API S3), e per gestire il dialogo utilizzo una mia libreria tgalice. Alla fine si ottiene un skill demo. E ora analizziamo tutto questo in modo più dettagliato.

Per quelli un po' meno impazienti: prima di immergerti nella mia storia sulle difficoltà, consiglio vivamente di iniziare con qualcosa di semplice. In particolare, crea una funzione di echo in un unico file, registrala e testala nella console sviluppatori Dialoghi; dettagli nel blog dei Dialoghi e documentazione del Cloud. E solo allora procedere.

Se vuoi subito percepire per cosa stiamo lottando, chiedi ad Alice ‘attiva la skill «oroscopo IT»‘. Dovrebbe avvenire più o meno il seguente dialogo:

Alice: Ciao! Sei nella skill «Oroscopo IT». Dì ‘Inizio’ per scoprire cosa ti promettono le stelle.
Utente: Inizio
A: Per favore, dimmi il tuo nome
U: Vasilij
A: Ora dimmi l'anno della tua nascita. Solo quattro cifre, niente di più.
U: secondo
A: Per favore, riprovate. Indica l'anno della tua nascita — quattro cifre.
U: 2002
A: Ottimo! Ora indica il mese della tua nascita.
U: Febbraio
A: Perfetto! Infine, dimmi il giorno della tua nascita — solo il numero, una o due cifre.
U: 18
A: Grazie, Vasisuvaliy! Ora sappiamo: hai 17 anni e sei un Acquario. Sei fortunato! Le stelle ti dicono: e ciò che dicono le stelle lo saprai avviando l'abilità.

Il problema è che per mantenere anche un semplice dialogo bisogna ricordare il nome e la data di nascita dell'utente, e nel contesto delle funzioni serverless non è banale. Non sarà possibile mantenere il contesto in memoria o in un file su disco, dato che Yandex.Cloud può avviare le funzioni su più macchine virtuali contemporaneamente e passare tra di esse in modo casuale. Dobbiamo utilizzare qualche tipo di storage esterno. È stato scelto Object Storage, in quanto è uno storage abbastanza economico e semplice direttamente in Yandex.Cloud (ovvero probabilmente veloce). Come alternativa gratuita, si può provare, per esempio, un pezzo gratuito di cloud Mongo lontano. Sia per Object Storage (che supporta l'interfaccia S3), sia per Mongo esistono comode librerie Python.

Un altro problema è che per accedere all'Object Storage, a MongoDB e a qualsiasi altro database o storage, servono alcune dipendenze esterne, che devono essere caricate su Yandex Functions insieme al codice della propria funzione. E sarebbe bello farlo in modo semplice. Non sarà possibile farlo comodamente (tipo come su Heroku), ma è possibile creare un certo comfort di base, scrivendo uno script per la creazione dell'ambiente (un file make).

Come avviare l'abilità oroscopo

  1. Prepararsi: accedere a una macchina con Linux. In teoria, si può lavorare anche con Windows, ma ci saranno dei problemi con l'esecuzione del file make. In ogni caso, avrai bisogno di Python installato nella versione 3.6 o superiore.
  2. Clonare da GitHub un esempio di abilità oroscopo.
  3. Registrarsi in Y. Cloud: https://cloud.yandex.ru
  4. Creare due bucket in Object Storage, chiamarli come si desidera {BUCKET NAME} e tgalice-test-cold-storage (questo secondo nome è attualmente hardcoded in main.py del mio esempio). Il primo bucket sarà necessario solo per il deploy, il secondo — per memorizzare gli stati del dialogo.
  5. Crea un account di servizio, assegna il ruolo di editor, e ottieni le credenziali statiche {KEY ID} e {KEY VALUE} — le utilizzeremo per registrare lo stato del dialogo. Tutto questo è necessario affinché la funzione di Y.Cloud possa accedere allo storage di Y.Cloud. Un giorno, spero, l'autenticazione diventerà automatica, ma per ora — così.
  6. (Facoltativo) installare l'interfaccia della riga di comando yc. È possibile creare una funzione anche tramite l'interfaccia web, ma la CLI è utile perché riceve le novità prima.
  7. Ora puoi, di fatto, preparare il montaggio delle dipendenze: eseguire nella riga di comando dalla cartella con l'esempio delle abilità make all. Verranno installate molte librerie (per lo più, come al solito, inutili) nella cartella dist.
  8. Carica manualmente in Object Storage (nel bucket {BUCKET NAME}) l'archivio ottenuto nel passaggio precedente dist.zip. Se desideri, puoi farlo anche dalla riga di comando, ad esempio, utilizzando AWS CLI.
  9. Crea una funzione serverless tramite l'interfaccia web o utilizzando l'utilità yc. Per l'utilità il comando sarà simile a questo:

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

Durante la creazione manuale della funzione, tutti i parametri vengono compilati in modo simile.

Ora puoi testare la funzione da te creata tramite la console degli sviluppatori, e poi perfezionare e pubblicare l'abilità.

Creazione di un skill stateful per Alice su funzioni serverless di Yandex.Cloud e Python

Cosa c'è sotto il cofano

Il file Make contiene in realtà uno script piuttosto semplice per l'installazione delle dipendenze e per il loro confezionamento in un archivio dist.zip, grosso modo così:

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 strumenti semplici, avvolti in una libreria tgalice. Il processo di compilazione dei dati utente è descritto dal file di configurazione form.yaml:

form_name: 'horoscope_form'
start:
  regexp: 'inizio|cominc(iare|io)'
  suggests:
    - Inizio
fields:
  - name: 'name'
    question: Per favore, dimmi il tuo nome.
  - name: 'year'
    question: Ora dimmi l'anno della tua nascita. Solo quattro cifre, niente di più.
    validate_regexp: '^[0-9]{4}$'
    validate_message: Per favore, riprova. Dimmi l'anno della tua nascita - quattro cifre.
  - name: 'month'
    question: Ottimo! Adesso dimmi il mese della tua nascita.
    options:
      - gennaio
      - febbraio
      - marzo
      - aprile
      - maggio
      - giugno
      - luglio
      - agosto
      - settembre
      - ottobre
      - novembre
      - dicembre
    validate_message: Quello che hai detto non sembra un mese. Per favore, dimmi il mese della tua nascita, senza ulteriori parole.
  - name: 'day'
    question: Perfetto! Infine, dammi la data della tua nascita - solo il numero, una o due cifre.
    validate_regexp: '[0123]?d$'
    validate_message: Per favore, riprova. Devi dire il numero della tua nascita (ad esempio, ventesima); è una o due cifre.

Il compito di analizzare questa configurazione e calcolare il risultato finale è affidato a una classe Python.

class CheckableFormFiller(tgalice.dialog_manager.form_filling.FormFillingDialogManager):
    SIGNS = {
        'gennaio': 'Capricorno',
        ...
    }

    def handle_completed_form(self, form, user_object, ctx):
        response = tgalice.dialog_manager.base.Response(
            text='Grazie, {}! Ora sappiamo: hai {} anni e sei {}.\n'
                 'Sei davvero fortunato! Le stelle ti dicono: {}'.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 della "form" e il metodo della classe figlia handle_completed_form indica cosa fare quando è pronta.

Oltre a questo flusso principale di dialogo, bisogna anche dare il benvenuto agli utenti, oltre a fornire assistenza su richiesta e uscire dal skill con il comando "uscita". Per farlo, in tgalice c'è anche un template, quindi il gestore del dialogo completo è composto da pezzi:

dm = tgalice.dialog_manager.CascadeDialogManager(
    tgalice.dialog_manager.GreetAndHelpDialogManager(
        greeting_message=DEFAULT_MESSAGE,
        help_message=DEFAULT_MESSAGE,
        exit_message='Arrivederci, torna nel skill "Oroscopo IT" di nuovo!'
    ),
    CheckableFormFiller(`form.yaml`, default_message=DEFAULT_MESSAGE)
)

CascadeDialogManager funziona in modo semplice: prova ad applicare tutte le sue componenti allo stato attuale del dialogo in successione e seleziona la prima appropriata.

Come risposta a ogni messaggio, il gestore del dialogo restituisce un oggetto Python Response, che può poi essere convertito in testo normale, o in un messaggio in Alice o Telegram, a seconda di dove è in esecuzione il bot; contiene anche lo stato modificato del dialogo che deve essere mantenuto. Tutto questo è gestito da un'altra classe, DialogConnector, quindi lo script direttamente per avviare la skill su Yandex Functions appare così:

...
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 potete vedere, gran parte di questo codice crea una connessione all'interfaccia S3 dell'Object Storage. Per come viene utilizzata questa connessione, potete leggere nel codice tgalice.
L'ultima riga crea la funzione alice_handler — quella stessa, che abbiamo detto di chiamare a Yandex.Cloud, quando abbiamo impostato il parametro --entrypoint=main.alice_handler.

Ecco tutto. File Make per la compilazione, uno storage Object Storage simile a S3 per conservare il contesto e una libreria Python. tgaliceInsieme a funzioni serverless e all'espressività di Python, questo è sufficiente per sviluppare una skill di alto livello.

Potete chiedere, a cosa serve creare tgalice? Весь скучный код, перекладывающий JSON’ы из запроса в ответ и из хранилища в память и обратно, лежит в ней. Там же лежит применялка регулярок, функция для понимания того, что «феврарь» похоже на «февраль», и прочее NLU для бедных. По моей задумке, этого уже должно быть достаточно, чтобы можно было набрасывать прототипы навыков в yaml-файлах, не слишком отвлекаясь на технические детали.

Se volete un NLU più serio, potete integrare nella vostra skill Rasa o DeepPavlov, ma la loro configurazione richiederà ulteriori passaggi complicati, soprattutto su serverless. Se non volete proprio programmare, vale la pena usare un costruttore visivo come Aimylogic. Creando tgalice, pensavo a un modo intermedio. Vediamo cosa ne uscirà.

Beh, adesso unisciti al chat degli sviluppatori di skills per Alice, leggi la documentazione, e crea fantastici abilità!

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster