Stateful-oskuse loomine Alisele Yandex.Cloud serverless funktsioonide ning Pythoni abil

Alustame uudistega. Eile teatas Yandex.Cloud serverivabade arvutuste teenuse käivitamisest Yandex Cloud Functions. See tähendab, et sa kirjutad ainult oma teenuse koodi (näiteks veebirakenduse või vestlusroboti), samas kui Pilv loob ja haldab virtuaalmasinaid, kus see töötab, ja isegi reprodutseerib need, kui koormus suureneb. Ei pea üldse muretsema, see on väga mugav. Ja maksta tuleb ainult arvutusaega.

Kuid mõned ei pruugi üldse maksta. Need on arendajad Alisa väliste oskuste jaoks, see tähendab, et need on pistikprogrammid, mis on Alisas juba sisse ehitatud. Sellise oskuse kirjutada, hostida ja registreerida saab iga arendaja, ja alates tänasest ei pea oskusi isegi hostima — piisab, kui laadida nende kood üles Pilve kujul sama serverivaba funktsiooni.

Kuid on paar nüanssi. Esiteks võib su Python'i kood vajada teatud sõltuvusi, ja nende tõmbamine Pilve ei ole triviaalne. Teiseks, igal normaalsel vestlusrobotil peab olema kuskil hoitud dialooge (stateful seega); kuidas neid serverivaba funktsiooni puhul kõige lihtsamalt hoida? Kolmandaks, kuidas üldiselt kiiresti ja üleliigselt kirjutada oskus Alisale või mõnele muule robotile, millel on mingisugune süžee? Nendest nüanssidest räägibki see artikkel.

Stateful-oskuse loomine Alisele Yandex.Cloud serverless funktsioonide ning Pythoni abil

Moraalne ettevalmistus

Kärsitutele: vajalikke sõltuvusi kogun make-failiga enne funktsiooni üleslaadimist Pilve, dialoogide olekut hoian Yandexi Object Storage'is (see toetab S3 API-d), ja dialooge kontrollin oma raamatukoguga tgalice. Lõppkokkuvõttes saadakse niisugust demonduke. Ja nüüd vaatame seda natuke süvitsi.

Veidi vähem kärsitutele: enne kui sukelduda minu looga keerukustest, soovitan alustada lihtsast. Nimelt, luua ühtefailine funktsioon-ehkobot, registreerida ja testida seda Dialogide arenduskeskkonnas; üksikasjad — Dialogide blogis ja Pilve dokumentatsioonis. Ja alles siis alustada.

Kui soovite kohe tunda, mille nimel me siin võitleme, paluge Alisal ‘lülita sisse oskus «IT-horoskoop»‘. Juhtuma peaks umbes järgmine dialoog:

Alisa: Tere! Olete oskuses «IT-horoskoop». Öelge «Start», et teada saada, mida tähed teile lubavad.
Kasutaja: Algus
A: Palun öelge oma nimi
K: Vasisiualii
A: Nüüd öelge mulle oma sünniaasta. Ainult neli numbrit, mitte midagi muud.
Ju: teine
A: Palun proovige uuesti. Öelge oma sünniaasta — neli numbrit.
Ju: 2002
A: Suurepärane! Nüüd öelge oma sünnikuupäev.
Ju: Veebruar
A: Suurepärane! Lõpuks, öelge mulle oma sünnikuupäev — ainult päev, üks või kaks numbrit.
Ju: 18
A: Aitäh, Vassili! Nüüd teame: te olete 17 aastat vana ja teie tähtkuju on Veevalaja. Õnn kaasa! Tähed ütlevad teile: aga mida tähed ütlevad, saate teada, käivitades oskuse.

Probleem on selles, et isegi sellise lihtsa dialooge käimiseks on vaja meeles pidada kasutaja nime ja sünnikuupäeva, ja serverivabades funktsioonides on see keeruline. Konteksti hoidmine operatiivmälass või failis kettal ei toimi, kuna Yandex.Cloud võib käivitada funktsiooni mitmel virtuaalsel masinatel samaaegselt ja vahetada nende vahel suvaliselt. Peab kasutama mingit välislao. Valitud oli Object Storage, kuna see on üsna odav ja lihtne lahendus otse Yandex.Cloudis (ehk siis tõenäoliselt kiire). Tasuta alternatiivi saab proovida näiteks tasuta tükk pilve MongoDB kusagil kaugel. Nii Object Storage (mis toetab S3 liidest) kui ka Mongo jaoks on olemas mugavad Python'i mähised.

Edasi on probleem — et nii Object Storage'isse, MongoDB'sse kui ka mistahes teise andmebaasi või andmelao ligipääsemiseks on vajalikud välised sõltuvused, mis tuleb koos oma funktsiooni koodiga Yandex'i funktsioonidesse laadida. Ja tahaks, et see oleks mugav. Täiesti mugav (nagu Heroku's), kahjuks ei toimi, kuid mingisuguse baasmugavuse võib luua, kirjutades keskkonna kokkupanemise skripti (make-fail).

Kuidas käivitada horoskoobi oskust

  1. Valmistuge: minge mõnele Linuxi arvutile. Teoreetiliselt saab ka Windowsis töötada, kuid make-faili käivitamiseks võib siis olla vaja natuke võluda. Ja igal juhul on teil vaja installeeritud Pythonit, mille versioon on vähemalt 3.6.
  2. Kloonige endale GitHub'ist horoskoobi oskuse näidis.
  3. Registreeruge Yandex.Cloudis: https://cloud.yandex.ru
  4. Looge endale kaks ämbrike Object Storage, nimetage need igasuguste nimedega {BUCKET NAME} ja tgalice-test-cold-storage (väga see teine nimi on praegu kõvakooditud main.py minu näites). Esimene ämber on vajalik ainult deploy jaoks, teine — dialooge olekute hoidmiseks.
  5. Luua teenuse konto, andke sellele roll toimetaja, ja saage selle juurde staatilised mandaadid {KEY ID} ja {KEY VALUE} — neid kasutame vestluse oleku salvestamiseks. Kõik see on vajalik, et funktsioon Yandex Cloudist saaks pääseda salvestusruumile. Loodetavasti saab tulevikus autentimine automaatseks, kuid praegu on need sel viisil.
  6. (Mitte kohustuslik) paigaldada käsklusrida yc. Funktsiooni saab luua ka veebiliidese kaudu, kuid CLI on hea selle poolest, et kõik uuendused tulevad sinna kiiremini.
  7. Nüüd on võimalik tegelikult ette valmistada sõltuvuste koostamine: käivitada käsklusrida näidisoskuse kaustast make all. Paigaldatakse hunnik raamatukogusid (enamasti, nagu ikka, ebavajalikke) kausta dist.
  8. Käsitsi laadida Object Storage'i (kausta {BUCKET NAME}) saadud eelmisel sammul allalaaditud arhiiv dist.zip. Soovi korral võib seda teha ka käsklusrida kaudu, näiteks kasutades AWS CLI.
  9. Luua serverita funktsioon veebiliidese kaudu või kasutades utiliiti yc. Utiliidi käsurida näeb välja selline:

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

Funktsiooni käsitsi loomisel täidetakse kõik parameetrid analooge.

Nüüd saate testida teie loodud funktsiooni arendaja konsoolis ning seejärel täiustada ja avaldada oskuse.

Stateful-oskuse loomine Alisele Yandex.Cloud serverless funktsioonide ning Pythoni abil

Mis seal kapoti all

Make-fail sisaldab tegelikult üsna lihtsat skripti sõltuvuste paigaldamiseks ja nende kogumiseks arhiivis dist.zip, ligikaudu selline:

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

Ülejäänu — paar lihtsat tööriista, mis on pakitud raamatukokku tgalice. Kasutaja andmete täitmise protsessi kirjeldab konfigureerimisfail form.yaml:

form_name: 'horoscope_form'
start:
  regexp: 'algus|alusta'
  suggests:
    - Alusta
fields:
  - name: 'name'
    question: Palun nimeta oma nimi.
  - name: 'year'
    question: Nüüd ütle mulle, millal sa sündisid. Ainult neli numbrit, mitte midagi muud.
    validate_regexp: '^[0-9]{4}$'
    validate_message: Palun proovi uuesti. Nimetage oma sünniaasta - neli numbrit.
  - name: 'month'
    question: Suurepärane! Nüüd nimetage oma sünnikuu.
    options:
      - jaanuar
      ...
      - detsember
    validate_message: See, mida sa rääkisid, ei näe välja nagu kuu. Palun nimeta oma sünnikuu, ilma muude sõnadeta.
  - name: 'day'
    question: Suurepärane! Lõpuks, palun nimeta mulle oma sünnikuupäev - ainult number, üks või kaks numbrit.
    validate_regexp: '[0123]?d$'
    validate_message: Palun proovi uuesti. Sa pead nimetama oma sünnipäeva (näiteks kahekümnes); see on üks või kaks numbrit.

Selle konfi analüüsimise ja lõpliku tulemuse arvutamisega tegeleb Python'i klass.

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

    def handle_completed_form(self, form, user_object, ctx):
        response = tgalice.dialog_manager.base.Response(
            text='Aitäh, {}! Nüüd teame: sulla on {} aastat, ja sa oled {}. n'
                 'Sul on tõeliselt vedanud! Tähed ütlevad sulle: {}'.format(
                form['fields']['name'],
                2019 - int(form['fields']['year']),
                self.SIGNS[form['fields']['month']],
                random.choice(FORECASTS),
            ),
            user_object=user_object,
        )
        return response

Täpsemalt öeldes, põhiklass. FormFillingDialogManager tegeleb „vormi“ täitmisega, ning alamklassi meetod handle_completed_form ütleb, mida teha, kui see on valmis.

Lisaks sellele, peame kasutajat tervitama ja anda teavet käsu „abi” kohta ning lõpetama oskuse käsuga „lahku”. Selle jaoks on tgalice ka malli, seega koosneb kogu dialoogihaldur tükkidest:

dm = tgalice.dialog_manager.CascadeDialogManager(
    tgalice.dialog_manager.GreetAndHelpDialogManager(
        greeting_message=DEFAULT_MESSAGE,
        help_message=DEFAULT_MESSAGE,
        exit_message='Nägemist, tule kindlasti tagasi "IT horoskoop" oskusesse!'
    ),
    CheckableFormFiller(`form.yaml`, default_message=DEFAULT_MESSAGE)
)

CascadeDialogManager töötab lihtsalt: proovib rakendada dialooge oma elementide järgi järjestikku ja valib esimesena sobiva.

Iga dialoogihalduri vastus igale sõnumile on Python'i objekt. Vastus, mille saab seejärel konverteerida puhtaks tekstiks või sõnumiks Alices või Telegramis — sõltuvalt sellest, kus bot töötab; see sisaldab samuti muudetud dialogi olekut, mida tuleb säilitada. Kõik selle korraldamisega tegeleb veel üks klass, DialogConnector, seetõttu näeb skript Yandex Functions'i jaoks välja selline:

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

Nagu näete, loob enamik sellest koodist ühenduse S3 objekti salvestusliidesega. Kuidas seda ühendust täpselt kasutada, saab lugeda koodist tgalice.
Viimane rida loob funktsiooni alice_handler — just selle, mida käsutasime Yandex. Cloud'i kutsuma, kui määrasime parameetri --entrypoint=main.alice_handler.

Noh, ja kõik. Make-failid kogumiseks, S3-sarnane objekti salvestus konteksti hoidmiseks ja Python'i teek tgalice. Koos serveriteta funktsioonide ja Pythoni väljendusvõimega on seda piisavalt, et arendada terviklikku oskust.

Võite küsida, miks on vaja luua tgalice? Весь скучный код, перекладывающий JSON’ы из запроса в ответ и из хранилища в память и обратно, лежит в ней. Там же лежит применялка регулярок, функция для понимания того, что «феврарь» похоже на «февраль», и прочее NLU для бедных. По моей задумке, этого уже должно быть достаточно, чтобы можно было набрасывать прототипы навыков в yaml-файлах, не слишком отвлекаясь на технические детали.

Kui soovite tõsisema NLU, saate oma oskusele lisada Rasa või DeepPavlov, kuid nende seadistamiseks on vaja lisatööd, eriti serveriteta. Kui absoluutselt ei soovi kodeerida, tasub kasutada visuaalset konstruktorit nagu Aimylogic. Tgalice'i luues mõtlesin mingile vahealternatiivile. Vaatame, mida sellest välja tuleb.

Kuid nüüd liituge Alice'i oskuste arendajate vestlusega, loe dokumentatsioon, ja looge suurepäraseid oskused!

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster