Krijimi i një njohurie stateful për Alisën në funksionet serverless të Yandex.Cloud dhe Python

Le të fillojmë me lajmet. Dëgjoni, dje Yandex.Cloud njoftoi lansimin e shërbimit të llogaritjeve pa serverë. Yandex Cloud Functions. Kjo do të thotë: ju shkruani vetëm kodin e shërbimit tuaj (p.sh., aplikacione veb ose chatbot), dhe Cloud automatikisht krijon dhe mirëmban makinat virtuale ku ai ekzekutohet, madje i riprodhon ato në rast se ngarkesa rritet. Nuk keni nevojë të mendoni fare, shumë e përshtatshme. Dhe pagesa bëhet vetëm për kohën e llogaritjeve.

Megjithatë, dikush mund të mos paguajë fare. Këta janë zhvilluesit e aftësive të jashtme të Alisë, pra të chatbotëve të integruar në të. Çdo zhvillues mund të shkruajë, akomodojë dhe regjistrojë një aftësi të tillë, dhe që nga sot nuk ka nevojë të akomodoni aftësitë - mjafton të ngarkoni kodin e tyre në cloud në formën e asaj funksioni pa server.

Por ka disa nuanca. Së pari, kodi juaj mund të kërkojë disa varësi, dhe ngarkimi i tyre në Cloud nuk është një punë e lehtë. Së dyti, çdo chatbot normal ka nevojë të ruajë ndonjëherë gjendjen e dialogut (prandaj është stateful); si është më lehtë ta bëni këtë në një funksion pa server? Së treti, si mund të shkruani shpejt dhe

Krijimi i një njohurie stateful për Alisën në funksionet serverless të Yandex.Cloud dhe Python

Përgatitja morale

Për ata që nuk kanë durim: unë grumbulloj varësitë e nevojshme me një skedar make para se ta ngarkoj funksionin në cloud, ruaj gjendjen e dialogut në Object Storage të Yandex-it (ai mbështet API S3), dhe për menaxhimin e dialogut përdor bibliotekën time tgalice. Në përfundim krijohet një një aftësi demo. Tani le të shqyrtojmë gjithçka pak më në detaje.

Për ata që kanë pak më pak durim: para se të zhytni në historinë time për vështirësitë, rekomandoj shumë të filloni me diçka të thjeshtë. Pra, krijoni një funksion të thjeshtë për echo-botin, regjistrojeni dhe testoni atë në konsolën e zhvilluesve të Dialogëve; detajet janë në blogun e Dialogëve dhe në dokumentacionin e Cloud. Dhe vetëm pastaj filloni.

Nëse dëshironi të ndjeni menjëherë për çfarë po luftojmë këtu, kërkoni Alisë ‘aktivizo aftësinë ‘horoskopi i IT’‘. Një dialog i tillë duhet të ndodhë:

Alia: Përshëndetje! Jeni në aftësinë ‘Horoskopi i IT’. Thoni ‘Fillim’ për të mësuar çfarë ju parashikojnë yjet.
Përdoruesi: Fillim
A: Ju lutem, thoni emrin tuaj
P: Vasisaul
A: Tani thoni vitin tuaj të lindjes. Vetëm katër cifra, asgjë tjetër.
P: dy
A: Ju lutem, provoni përsëri. Thoni vitin e lindjes suaj — katër shifra.
U: 2002
A: Shkëlqyer! Tani thoni muajin e lindjes suaj.
U: Shkurti
A: Shumë mirë! Së fundi, thoni ditën e lindjes suaj — vetëm numrin, një ose dy shifra.
U: 18
A: Faleminderit, Vasisiual! Tani e dimë: je 17 vjeç dhe je Peshqit. Kjo është fat! Yjet ju thonë: çfarë thonë yjet, do të mësoni duke nisur aftësinë.

Problemi është se për të mbajtur madje dhe një dialog kaq të thjeshtë nevojitet të mbani mend emrin dhe datën e lindjes së përdoruesit, dhe në ambientet e funksioneve pa server, kjo nuk është e thjeshtë. Nuk mund të mbani një kontekst në memorjen e operativit ose në një skedar në disku, pasi Yandex.Cloud mund të aktivizojë funksionin në disa makina virtuale njëkohësisht dhe të kalojë midis tyre rastësisht. Do të duhet të përdorni ndonjë ruajtje të jashtme. Është zgjedhur Object Storage, si një ruajtje mjaft e lirë dhe e thjeshtë pikërisht në Yandex.Cloud (dmth ndoshta e shpejtë). Si një alternativë falas mund të provoni, për shembull, një copë Mongo të shërbimit në cloud diku larg. Dhe për Object Storage (ai mbështet ndërfaqen S3), dhe për Mongo ka mbështetje të përshtatshme për Python.

Një problem tjetër është se për të hyrë në Object Storage, MongoDB, dhe çdo bazë tjetër ose ruajtje të dhënash, nevojiten disa varësi të jashtme, të cilat duhet të ngarkohen në Yandex Functions së bashku me kodin e funksionit tuaj. Do të ishte mirë që ta bëni këtë në mënyrë të përshtatshme. Krejtësisht e përshtatshme (si në heroku), fatkeqësisht, nuk do të funksionojë, por një nivel të caktuar komoditeti mund të krijoni duke shkruar një skript për ndërtimin e mjedisit (make-file).

Si të aktivizoni aftësinë e horoskopit

  1. Përgatituni: hyni në ndonjë makinë me linux. Në parim, gjithashtu duhet të jetë e mundur të punoni me Windows, por me aktivizimin e make-file do të duhet të bëni disa fiku të vogla. Dhe në çdo rast, do t'ju nevojitet Python i instaluar, jo më të ulët se 3.6.
  2. Klononi nga github shembulli i aftësisë së horoskopit.
  3. Regjistrohu në Y. Cloud: https://cloud.yandex.ru
  4. Krijoni dy balte në Object Storage, quajini me ndonjë emër {BUCKET NAME} dhe tgalice-test-cold-storage (ky emri i dytë tani është i ngurtë në main.py shembulli im). Balti i parë do të nevojitet vetëm për vendosjen, i dyti — për ruajtjen e gjendjeve të dialogut.
  5. Krijo llogaria e shërbimeve, jepni atij rolin editor, dhe merrni kredencialet statike për të {KEY ID} dhe {KEY VALUE} — do t'i përdorim për të regjistruar gjendjen e dialogut. E gjithë kjo është e nevojshme që funksioni nga Y.Cloud të mund të ketë qasje në ruajtjen nga Y.Cloud. Diku, shpresoj, autorizimi do të bëhet automatik, por për momentin — kështu.
  6. (S'është e nevojshme) të instaloni interface komandash yc. Mund të krijoni një funksion edhe përmes interfesës në web, por CLI është i mirë sepse novacionet shfaqen aty më shpejt.
  7. Tani mund të përgatiteni për të mbledhur varësitë: të drejtoni në komandën e linjës nga dosja me shembullin e aftësisë make all. Një sërë bibliotekash do të instalohen (në thelb, si zakonisht, të panevojshme) në dosjen dist.
  8. Duhen ngarkuar manualisht në Object Storage (në bucket {BUCKET NAME}) arkivi i krijuar në hapin e mëparshëm dist.zip. Nëse dëshironi, mund ta bëni këtë edhe nga komandat e linjës, për shembull, duke përdorur AWS CLI.
  9. Krijoni një funksion pa server përmes interfesës në web ose duke përdorur utilitarin yc. Për utilitarin, komanda do të duket kështu:

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

Kur krijoni funksionin manualisht, të gjitha parametrat plotesohen në mënyrë të ngjashme.

Tani funksioni që keni krijuar mund të testohet përmes konsolës së zhvilluesit, dhe më pas të përmirësohet e të publikohet aftësia.

Krijimi i një njohurie stateful për Alisën në funksionet serverless të Yandex.Cloud dhe Python

Çfarë ndodhet nën kapak

Make-file në të vërtetë përmban një skenar të thjeshtë për instalimin e varësive dhe paketimin e tyre në një arkiv dist.zip, afërsisht kështu:

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

E gjithë e tjetra — disa mjete të thjeshta, të paketuar në një bibliotekë tgalice. Procesi i mbushjes së të dhënave për përdoruesin përshkruhet nga konfigurimi form.yaml:

form_name: 'horoscope_form'
start:
  regexp: 'start|begin(ning)?'
  suggests:
    - Start
fields:
  - name: 'name'
    question: Please tell me your name.
  - name: 'year'
    question: Now tell me your birth year. Just four digits, nothing more.
    validate_regexp: '^[0-9]{4}$'
    validate_message: Please try again. State your birth year - four digits.
  - name: 'month'
    question: Wonderful! Now name the month of your birth.
    options:
      - January
      - December
    validate_message: What you provided doesn’t seem to be a month. Please name the month of your birth, no other words.
  - name: 'day'
    question: Great! Finally, tell me your birth date - just the number, one or two digits only.
    validate_regexp: '[0123]?d$'
    validate_message: Please try again. You need to provide your birth number (for example, twentieth); that’s one or two digits.

The work of parsing this config and calculating the final result is handled by the Python class

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

    def handle_completed_form(self, form, user_object, ctx):
        response = tgalice.dialog_manager.base.Response(
            text='Thank you, {}! Now we know: you are {} years old, and you are {}. n'
                 'You’re really lucky! The stars tell you: {}'.format(
                form['fields']['name'],
                2019 - int(form['fields']['year']),
                self.SIGNS[form['fields']['month']],
                random.choice(FORECASTS),
            ),
            user_object=user_object,
        )
        return response

To be precise, the base class FormFillingDialogManager is responsible for filling out the 'form', and the method of the child class handle_completed_form indicates what to do when it is ready.

In addition to this main stream of the user dialogue, it’s also necessary to greet and provide assistance upon the command 'help', and exit the skill upon the command 'exit'. For this, in tgalice there is also a template, so the complete dialog manager is composed of pieces:

dm = tgalice.dialog_manager.CascadeDialogManager(
    tgalice.dialog_manager.GreetAndHelpDialogManager(
        greeting_message=DEFAULT_MESSAGE,
        help_message=DEFAULT_MESSAGE,
        exit_message='Goodbye, come back to the "IT Horoscope" skill again!'
    ),
    CheckableFormFiller(`form.yaml`, default_message=DEFAULT_MESSAGE)
)

CascadeDialogManager operates simply: it tries to apply each of its components in order to the current state of the dialogue, and selects the first appropriate one.

In response to each message, the dialog manager returns a Python object Përgjigjja, i cili më pas mund të konvertohet në tekst të pastër, ose në një mesazh në Alisa ose Telegram — varësisht nga ku është aktivizuar boti; aty ndodhet edhe gjendja e modifikuar e dialogut që duhet ruajtur. Kjo punë merret me një klasë tjetër, DialogConnector, prandaj skenari direkt për aktivizimin e aftësisë në Yandex Functions duket kështu:

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

Siç e shihni, pjesa më e madhe e këtij kodi krijon një lidhje me ndërfaqen S3 të Object Storage. Si shfrytëzohet pikërisht kjo lidhje, mund të lexoni në kodin tgalice.
Shënimi i fundit krijon funksionin alice_handler — atë të njëjtën që i thamë Yandex.Oblakut ta thërrasë kur vendosëm parametrin --entrypoint=main.alice_handler.

Ja, në fakt, dhe gjithë kjo. Skedarët Make për ndërtim, Object Storage si S3 për ruajtjen e kontekstit, dhe libra python-ash tgalice. Në kombinim me funksionet pa server dhe shprehshmërinë e Python-it, kjo është e mjaftueshme për zhvillimin e një aftësie të një njeriu të shëndetshëm.

Mund të pyesni, pse ishte e nevojshme të krijohej tgalice? Весь скучный код, перекладывающий JSON’ы из запроса в ответ и из хранилища в память и обратно, лежит в ней. Там же лежит применялка регулярок, функция для понимания того, что «феврарь» похоже на «февраль», и прочее NLU для бедных. По моей задумке, этого уже должно быть достаточно, чтобы можно было набрасывать прототипы навыков в yaml-файлах, не слишком отвлекаясь на технические детали.

Nëse dëshoni një NLU më serioze, mund të lidhni në aftësinë tuaj Rasa ose DeepPavlov, por për konfigurimin e tyre do të kërkohen disa lëvizje të mëtejshme, veçanërisht në serverless. Nëse nuk doni fare të kodoni, ia vlen të përdorni një ndërtues vizual si Aimylogic. Kur krijoja tgalice, po mendoja për ndonjë rrugë të mesme. Le të shohim se çfarë do të dalë nga kjo.

Tani, bashkohuni në grupin e zhvilluesve të aftësive të Alisë, lexoni dokumentacion, dhe krijoni të mrekullueshme aftësitë!

Burimi: habr.com

Blini hosting të besueshëm për faqe interneti me mbrojtje nga DDoS, serverë VPS VDS 🔥 Blini hosting të besueshëm për faqe interneti me mbrojtje nga DDoS, serverë VPS VDS | ProHoster