Iniziamo con le novità. Ieri Yandex.Cloud ha annunciato il lancio del servizio di calcolo serverless. 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 dove viene eseguito, replicandole anche se aumenta il carico. Non c'è bisogno di pensarci, molto comodo. E la tariffa si applica solo al tempo di calcolo.
Tuttavia, alcuni potrebbero non dover pagare affatto. Si tratta degli sviluppatori , cioè dei chatbot integrati in essa. Scrivere, ospitare e registrare un'abilità di questo tipo può farlo qualsiasi sviluppatore, e da oggi non è nemmeno necessario ospitare le abilità: è sufficiente caricare il loro codice nel cloud come .
Tuttavia, ci sono alcuni dettagli da considerare. In primo luogo, il tuo codice applicativo potrebbe richiedere alcune dipendenze, e importarle nel Cloud non è banale. In secondo luogo, a qualsiasi chatbot normale serve un modo per memorizzare lo stato della conversazione; come si fa a realizzarlo in modo più semplice con una funzione serverless? Infine, come si può scrivere rapidamente e in modo rudimentale una skill per Alice o un qualsiasi bot con una trama? Di questi dettagli parlerà l'articolo.

Preparazione morale
Per i più impazienti: raccolgo le dipendenze necessarie utilizzando un file make prima di caricare la funzione nel cloud, memorizzo lo stato della conversazione nello Object Storage di Yandex (che supporta l'API S3) e utilizzo una mia libreria per gestire la conversazione. . In questo modo otteniamo una skill demo. Ora analizziamo tutto questo con più dettaglio.
Per chi è un po' meno impaziente: prima di immergerti nella mia storia sulle complessità, ti consiglio vivamente di iniziare con qualcosa di semplice. Vale a dire, crea una funzione echo in un unico file, registrala e testala nella console di sviluppo di Dialoghi; ulteriori dettagli sono nel e . Solo dopo, procedere.
Se desideri avere subito un'idea di cosa stiamo facendo qui, chiedi ad Alice ‘‘. Dovrebbe avvenire un dialogo simile:
Alice: Ciao! Sei nell'abilità «Oroscopo IT». Dì «Inizia» per scoprire cosa ti riservano le stelle.
Utente: Inizia
A: Per favore, dicci il tuo nome
U: Vassilij
A: Ora dimmi l'anno della tua nascita. Solo quattro cifre, niente di più.
U: due
A: Per favore, riprova. Indica l'anno della tua nascita — quattro cifre.
U: 2002
A: Ottimo! Ora indicami 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, Vassilij! Ora sappiamo: hai 17 anni e sei un Acquario. Questo, di certo, è un bel colpo di fortuna! Le stelle ti dicono: e cosa dicono le stelle lo scoprirai attivando l'abilità.
Il problema è che, per mantenere anche una semplice conversazione, è necessario ricordare il nome e la data di nascita dell'utente, e in un ambiente di funzioni serverless questo non è banale. Non è possibile memorizzare il contesto nella memoria operativa o in un file sul disco, poiché Yandex Cloud può avviare funzioni su più macchine virtuali contemporaneamente e passare tra di esse in modo casuale. È necessario utilizzare un qualche tipo di archiviazione esterna. È stato scelto Object Storage, come un'opzione piuttosto economica e semplice direttamente in Yandex Cloud (cioè probabilmente veloce). Come alternativa gratuita, si può provare, ad esempio, un frammento omaggio. lontano da qui. Sia per Object Storage (che supporta l'interfaccia S3), sia per Mongo, ci sono comode wrapper in Python.
Un altro problema è che, per accedere sia a Object Storage che a MongoDB, oltre che a qualsiasi altro database o sistema di archiviazione, sono necessarie delle dipendenze esterne da caricare su Yandex Functions insieme al codice della propria funzione. Sarebbe bello farlo in modo conveniente. Non sarà possibile farlo completamente comodo (come su Heroku), ma è possibile creare un certo comfort di base scrivendo uno script per la configurazione dell'ambiente (file make).
Come avviare l'abilità dell'oroscopo
- Prepararsi: accedere a un qualsiasi sistema con Linux. In teoria, si può lavorare anche con Windows, ma si dovrà giocare un po' con l'esecuzione del file make. In ogni caso, avrete bisogno di Python installato, versione 3.6 o superiore.
- Clonare dal proprio GitHub .
- Registrarsi su Yandex Cloud:
- Creare due bucket in , chiamarli con qualsiasi nome
{BUCKET NAME}etgalice-test-cold-storage(questo secondo nome è attualmente hardcoded inmain.pydel mio esempio). Il primo bucket sarà necessario solo per il deploy, il secondo per la memorizzazione degli stati del dialogo. - Crea , assegnargli il ruolo
editor, e ottenere le credenziali statiche{KEY ID}e{KEY VALUE}— li 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ì. - (Non obbligatorio) installare
yc. È possibile creare una funzione anche tramite l'interfaccia web, ma il CLI ha il vantaggio che tutte le novità vengono implementate più rapidamente. - Ora possiamo, di fatto, preparare la raccolta delle dipendenze: avviare nella riga di comando dalla cartella con l'esempio dello skill
make all. Saranno installate numerose librerie (principalmente, come al solito, inutili) nella cartelladist. - Caricare manualmente in Object Storage (nel bucket
{BUCKET NAME}) l'archivio ottenuto nel passaggio precedentedist.zip. Se lo si desidera, è possibile farlo anche dalla riga di comando, ad esempio, utilizzando . - Creare una funzione serverless tramite l'interfaccia web o utilizzando l'utilità
yc. Per l'utilità, il comando sarà così:
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=3sNel caso di creazione manuale della funzione, tutti i parametri vengono compilati in modo simile.
Ora è possibile testare la funzione creata attraverso la console degli sviluppatori, e poi perfezionarla e pubblicare l'abilità.

Cosa c'è sotto il cofano
Il file Make contiene in realtà uno script piuttosto semplice per installare le dipendenze e impacchettarle in un archivio dist.zip, più o meno 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 è composto da alcuni semplici strumenti avvolti in una libreria tgalice. Il processo di popolamento dei dati dell'utente è descritto nel file di configurazione form.yaml:
form_name: 'horoscope_form'
start:
regexp: 'inizio|cominc(iare|io)'
suggests:
- Inizio
fields:
- name: 'name'
question: Per favore, dicci 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. Indica l’anno della tua nascita - quattro cifre.
- name: 'month'
question: Ottimo! Ora indica il mese della tua nascita.
options:
- gennaio
- febbraio
- marzo
- aprile
- maggio
- giugno
- luglio
- agosto
- settembre
- ottobre
- novembre
- dicembre
validate_message: Quello che hai indicato non sembra un mese. Per favore, indica il mese della tua nascita, senza altre parole.
- name: 'day'
question: Eccellente! Infine, indica la data della tua nascita - solo il numero, una o due cifre al massimo.
validate_regexp: '[0123]?d$'
validate_message: Per favore, riprova. Devi indicare il numero della tua nascita (ad esempio, ventesimo); sono una o due cifre.Il compito di analizzare questa configurazione e calcolare il risultato finale è assunto da 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 responsePiù precisamente, la classe base FormFillingDialogManager si occupa di riempire un "modulo", e il metodo della classe derivata handle_completed_form indica cosa fare quando è pronto.
Oltre a questo flusso principale del dialogo, è necessario anche salutare l'utente e fornire assistenza al comando "aiuto" e uscire dall'assistente al comando "uscita". A tal fine, in tgalice c'è anche un modello, 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 "Oroscopo IT"!'
),
CheckableFormFiller(`form.yaml`, default_message=DEFAULT_MESSAGE)
)CascadeDialogManager funziona semplicemente: prova ad applicare a ogni stato attuale del dialogo tutti i suoi componenti uno dopo l'altro e sceglie il primo pertinente.
In risposta a ogni messaggio, il gestore del dialogo restituisce un oggetto Python Risposta, che può essere convertito in testo semplice o in un messaggio in Alice o Telegram, a seconda di dove è attivato il bot; contiene anche lo stato modificato del dialogo, che deve essere conservato. Tutta questa gestione è affidata a un'altra classe, DialogConnector, perciò lo script diretto per avviare l'abilità 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_handlerCome potete vedere, la maggior parte di questo codice stabilisce una connessione all'interfaccia S3 di Object Storage. È possibile leggere come questa connessione venga utilizzata .
L'ultima riga crea una funzione alice_handler — quella che abbiamo chiesto di gestire a Yandex.Cloud quando abbiamo impostato il parametro --entrypoint=main.alice_handler.
Ecco, sostanzialmente, il tutto. File Make per la compilazione, archiviazione oggetti simile a S3 per conservare il contesto e una libreria Python tgalice. Insieme a funzioni serverless e all'espressività di Python, questo è sufficiente per sviluppare un'abilità per persone sane.
Puoi chiederti perché sia stato necessario creare tgalice? Весь скучный код, перекладывающий JSON’ы из запроса в ответ и из хранилища в память и обратно, лежит в ней. Там же лежит применялка регулярок, функция для понимания того, что «феврарь» похоже на «февраль», и прочее NLU для бедных. По моей задумке, этого уже должно быть достаточно, чтобы можно было набрасывать прототипы навыков в yaml-файлах, не слишком отвлекаясь на технические детали.
Se desideri un NLU più serio, puoi integrare nel tuo skill o , ma la loro configurazione richiederà ulteriori passaggi complicati, soprattutto per le soluzioni serverless. Se non vuoi scrivere codice, è meglio utilizzare un costruttore visivo come . Creando tgalice, pensavo a una sorta di via intermedia. Vedremo cosa ne verrà fuori.
Beh, ora unisciti a , leggi , e crea straordinarie !
Fonte: habr.com
