Stateful készség létrehozása Alisza számára a Yandex.Cloud serverless funkcióin és Python nyelven

Kezdjük a hírekkel. Tegnap a Yandex.Cloud bejelentette a szerver nélküli számítások szolgáltatásának indulását. Yandex Cloud Functions. Ez azt jelenti: te csak a szolgáltatásod (például webalkalmazás vagy chatbot) kódját írod, a Cloud pedig automatikusan létrehozza és fenntartja azokat a virtuális gépeket, ahol ez fut, és akár replikálja is őket, ha nő a terhelés. Valójában nem is kell semmivel foglalkozni, nagyon kényelmes. És csak a számítási időért fizetsz.

Egyesek viszont akár nem is fizethetnek. Ők a külső Alice-készségek, azaz az őt integráló chatbotok. Bármilyen fejlesztő létrehozhat, hosztolhat és regisztrálhat ilyen készséget, és mától már nem is kell hosztolni a készségeket - elegendő a kódjukkal feltölteni őket a felhőbe, egyfajta az említett szerver nélküli funkció.

De van néhány nüansz. Először is, a Python kódod bizonyos függőségeket igényelhet, és ezeket a Cloudba betenni nem triviális feladat. Másodszor, bármely normális chatbotnak valahol tárolnia kell a párbeszéd állapotát (stateful ezért); hogyan lehet ezt a legegyszerűbben megoldani egy szerver nélküli funkcióban? Harmadszor, hogyan lehet gyorsan és koszosan készíteni egy készséget Alice számára, vagy bármilyen bot számára valamilyen cselekménnyel? Ezek a nüanszok, igazából, a cikk témája.

Stateful készség létrehozása Alisza számára a Yandex.Cloud serverless funkcióin és Python nyelven

Morális felkészülés

Türelmetleneknek: a szükséges függőségeket egy make-fájllal gyűjtöm össze a funkció felhőbe töltése előtt, a párbeszéd állapotát a Yandex Object Storage-ban tárolom (támogatja az S3 API-t), és a párbeszéd irányítására a saját könyvtáramat használom, tgalice. Végül kapunk egy ilyen demó készséget. Most pedig nézzük meg ezt egy kicsit részletesebben.

A némileg türelmetleneknek: mielőtt belemerülnénk az én történetembe a nehézségekről, nagyon ajánlom, hogy kezdjétek az egyszerűvel. Nevezetesen, hozz létre egy fájlban egy echo bot-díjat, regisztráld, és teszteld a Dialogs fejlesztői konzoljában; részletek a Dialogs blogjában és a Cloud dokumentációjában. És csak azután kezdjétek el.

Ha azonnal szeretnéd érezni, miért küzdünk itt, mondd Alice-nak ‘kapcsold be a 'IT horoszkóp' készséget‘. Körülbelül a következő párbeszédnek kellene zajlania:

Alice: Helló! Az 'IT horoszkóp' készségben vagy. Mondd, hogy 'Kezdet', ha szeretnéd tudni, mit jósolnak neked a csillagok.
Felhasználó: Kezdet
A: Kérlek, add meg a neved.
Felhasználó: Vasziszuali
A: Most mond meg az születési éved. Csak négy számot, semmi feleslegeset.
Felhasználó: második
A: Kérem, próbálja meg újra. Mondja meg születési évét — négy számjegy.
Y: 2002
A: Csodás! Most mondja meg születési hónapját.
Y: Február
A: Kitűnő! Végül pedig mondja meg születési dátumát — csak a nap, maximum egy vagy két számjegy.
Y: 18
A: Köszönöm, Vasilij! Most már tudjuk: 17 éves vagy, és Kos vagy. Ez igazán szerencsés helyzet! A csillagok azt mondják neked: a csillagok üzeneteit a készség aktiválásával ismerheted meg.

A probléma az, hogy még egy ilyen egyszerű párbeszéd fenntartásához is emlékezni kell a felhasználó nevére és születési dátumára, ami a serverless funkciók környezetében nem triviális. A kontextust nem lehet az operatív memóriában vagy fájlformátumban tárolni, mivel a Yandex.Cloud egyszerre több virtuális gépen is futhat, és véletlenszerűen válthat közöttük. Valamilyen külső tárolót kell használnunk. Az Object Storage-ra esett a választás, mint viszonylag kedvező árú és egyszerű tárolóra közvetlenül a Yandex.Cloud-ban (tehát valószínűleg gyors). Mint ingyenes alternatívát kipróbálhatjuk például a szabad MongoDB-t. felhő. És az Object Storage (ami S3 interfészt támogat) és a MongoDB számára is léteznek kényelmes Python csomagolások.

Egy másik probléma az, hogy az Object Storage és a MongoDB, valamint bármilyen más adatbázis vagy adattároló használatához külső függőségekre van szükség, amelyeket fel kell tölteni a Yandex Functions-hoz a funkció adottságaival együtt. Szeretnénk ezt kényelmesen megtenni. Teljesen kényelmesen (például mint a Heroku-n) sajnos nem fog sikerülni, de valamilyen alapvető kényelmet létrehozhatunk, ha írnánk egy környezetépítő szkriptet (make file).

Hogyan indítsuk el a horoszkóp készséget

  1. Készüljön fel: lépjen be egy Linux rendszert futtató gépre. Elvben Windows-on is használható, de a make file elindításához ott kicsit varázsolni kell. Mindenesetre szüksége lesz legalább 3.6-os Python telepítésére.
  2. Klónozza le a GitHubról a horoszkóp készség példáját.
  3. Regisztráljon a Y. Cloud-ra: https://cloud.yandex.ru
  4. Hozzon létre két tárolót a Object Storage, nevezze el őket bármilyen névvel {BUCKET NAME} és tgalice-test-cold-storage (ez a második név jelenleg hardcode-olva van a main.py példámba). Az első tárolóra csak a telepítéshez van szükség, a másodikra pedig a párbeszédek állapotának tárolásához.
  5. Létrehozás szolgáltatói fiók, adjon neki szerepet szerkesztő, és szerezzen hozzá statikus hitelesítő adatokat {KEY ID} és {KEY VALUE} — ezeket a párbeszéd állapotának rögzítésére fogjuk használni. Mindez szükséges ahhoz, hogy a Funkció az Y.Cloud-ból hozzáférhessen a tárolóhoz az Y.Cloud-ból. Remélem, hogy egyszer az azonosítás automatikussá válik, de addig is így.
  6. (Nem kötelező) telepíteni parancssori felület yc. Funkciót létrehozni webes felületen is lehetséges, de a CLI előnye, hogy az új fejlesztések itt gyorsabban jelennek meg.
  7. Most már készíthetjük a függőségek összeszerelését: futtatni a parancssorban a példa készlet mappájából make all. Számos könyvtár (főleg, ahogy az lenni szokott, haszontalanok) fog települni a mappába dist.
  8. Kézzel feltölteni az Object Storage-ba (a tárolóba {BUCKET NAME}) a korábban létrehozott archívumot dist.zip. Ha szeretné, ezt parancssorból is megteheti, például az alábbiak használatával AWS CLI.
  9. Létrehozni egy szerver nélküli funkciót a webes interfészen vagy az eszköz használatával yc. Az eszköz parancsa így fog kinézni:

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

A funkció manuális létrehozásakor minden paraméter hasonló módon van kitöltve.

Most már a létrehozott funkciót tesztelheti a fejlesztői konzolon, majd tovább fejlesztheti és publikálhatja a készséget.

Stateful készség létrehozása Alisza számára a Yandex.Cloud serverless funkcióin és Python nyelven

Mi van a motorháztető alatt

A Make-fájl valójában egy meglehetősen egyszerű szkriptet tartalmaz a függőségek telepítésére és archiválására dist.zip, körülbelül ennyit:

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

A többi — néhány egyszerű eszköz, amely könyvtárba van csomagolva tgalice. A felhasználói adatokról szóló folyamat a konfig fájlban van leírva form.yaml:

form_name: 'horoscope_form'
start:
  regexp: 'kezdet|kezd(és|eni)'
  suggests:
    - Kezdés
fields:
  - name: 'name'
    question: Kérlek, mondd meg a nevedet.
  - name: 'year'
    question: Most mondd el nekem a születési évedet. Csak négy szám, semmi más.
    validate_regexp: '^[0-9]{4}$'
    validate_message: Kérlek, próbáld újra. Mondd meg a születési évedet - négy szám.
  - name: 'month'
    question: Kiváló! Most mondd meg a születési hónapodat.
    options:
      - január
      ...
      - december
    validate_message: Amit mondtál, nem tűnik hónapnak. Kérlek, mondd meg a születési hónapodat, más szavak nélkül.
  - name: 'day'
    question: Nagyszerű! Végül, mondj egy dátumot a születésnapodra - csak egy szám, maximum két számjegy.
    validate_regexp: '[0123]?d$'
    validate_message: Kérlek, próbáld újra. Meg kell mondanod a születésnapod számát (például huszadik); ez egy vagy két számjegy.

A konfiguráció feldolgozását és a végső eredmény kiszámítását a Python osztály végzi

class CheckableFormFiller(tgalice.dialog_manager.form_filling.FormFillingDialogManager):
    SIGNS = {
        'január': 'Bak',
        ...
    }

    def handle_completed_form(self, form, user_object, ctx):
        response = tgalice.dialog_manager.base.Response(
            text='Köszönöm, {}! Most már tudjuk: {} éves vagy, és te {}. n'
                 'Ez igazán szerencsés! A csillagok azt mondják neked: {}'.format(
                form['fields']['name'],
                2019 - int(form['fields']['year']),
                self.SIGNS[form['fields']['month']],
                random.choice(FORECASTS),
            ),
            user_object=user_object,
        )
        return response

Pontosabban, az alap osztály FormFillingDialogManager foglalkozik a "forma" kitöltésével, míg az alosztály módszere handle_completed_form megmondja, mit kell tenni, amikor az készen áll.

Ezen alapvető felhasználói párbeszédfolyam mellett üdvözölni is kell, valamint segítséget adni a "segítség" parancsra, és ki kell lépni a készségből a "kilépés" parancsra. Ehhez tgalice szintén van sablon, így a teljes párbeszédkezelő darabokból áll:

dm = tgalice.dialog_manager.CascadeDialogManager(
    tgalice.dialog_manager.GreetAndHelpDialogManager(
        greeting_message=DEFAULT_MESSAGE,
        help_message=DEFAULT_MESSAGE,
        exit_message='Viszlát, gyere vissza az "IT Horoszkóp" készségbe még!'
    ),
    CheckableFormFiller(`form.yaml`, default_message=DEFAULT_MESSAGE)
)

CascadeDialogManager egyszerűen működik: megpróbálja alkalmazni a párbeszéd aktuális állapotára az összes alkotóelemét egymás után, és kiválasztja az első megfelelő elemet.

Hálás válaszként a párbeszédkezelő minden üzenetre Python objektumot ad vissza Válasz, amelyet aztán átkonvertálhatunk nyers szöveggé, vagy üzenetté az Aliszban vagy a Telegramon – attól függően, hol fut a bot; ebben található a párbeszéd módosított állapota is, amelyet meg kell őriznünk. Az egész feladat a továbbiakban egy másik osztályra hárul, DialogConnector, így a Yandex Functions platformon a készséget aktiváló közvetlen szkript így néz ki:

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

Ahogy látjátok, ennek a kódnak a nagy része az S3 interfészhez való csatlakozást hozza létre. Az, hogy ezt a csatlakozást közvetlenül hogyan használjuk, a tgalice kódban.
Az utolsó sor létrehozza a alice_handler — azt a funkciót, amelyet megadtunk a Yandex Cloud-nak, amikor a paramétert adtuk meg --entrypoint=main.alice_handler.

A lényeg pedig ennyi. Make fájlok a buildhez, S3-szerű Object Storage a kontextus tárolására, és Python könyvtárak. tgaliceEzek együttesen, a serverless funkciókkal és a Python kifejezőerejével elegendőek egy egészséges ember készségeinek fejlesztéséhez.

Megkérdezheted, miért is kellett létrehozni tgalice? Весь скучный код, перекладывающий JSON’ы из запроса в ответ и из хранилища в память и обратно, лежит в ней. Там же лежит применялка регулярок, функция для понимания того, что «феврарь» похоже на «февраль», и прочее NLU для бедных. По моей задумке, этого уже должно быть достаточно, чтобы можно было набрасывать прототипы навыков в yaml-файлах, не слишком отвлекаясь на технические детали.

Ha komolyabb NLU-ra vágyunk, a készségünkhöz hozzácsatolhatunk Rasa vagy DeepPavlov, de ennek beállításához további bonyodalmakra lesz szükség, különösen a serverless környezetben. Ha valósággal nem akarsz kódot írni, érdemes egy vizuális tervezőre támaszkodni, mint például Aimylogic. A tgalice létrehozásakor valami középutat kerestem. Nézzük meg, mi sül ki belőle.

Nos, most lépj be a fejlesztők Alisz készségeihez tartozó csevegésébe,olvass a dokumentációval, és készíts csodálatos készségek!

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster