Ալիսայի համար stateful հմտություն ստեղծելը Yandex.Cloud-ի serverless ֆունկցիաների և Python-ի միջոցով

Աρχենք նորություններից: երեկ Yandex.Cloud-ն հայտարարեց serverless հաշվարկների ծառայության մեկնարկի մասին Yandex Cloud Functions. Դա նշանակում է, որ դուք գրում եք միայն ձեր ծառայության (օրինակ՝ վեբ-ծրագրի կամ չատ-բոտի) կոդը, իսկ Cloud-ը ինքնուրույն ստեղծում և սպասարկում է վիրտուալ մեքենաներ, որտեղ այն գործարկվում է, և նույնիսկ կրկնօրինակում է դրանք, եթե բեռը մեծանում է: Չի անհրաժեշտ մտածել, շատ հարմար է: Եվ վճարումները տեղի են ունենում միայն հաշվարկների ժամանակի համար:

Այդուհանդերձ, որոշ մարդիկ կարող են ընդհանրապես չվճարել: Դա՝ Ալիսայի արտաքին հմտությունների մշակողները , այսինքն՝ նրա մեջ встроված չատ-բոտերը: Նման հմտություն գրելը, հոստինգ անելն ու գրանցելը կարող է անել ցանկացած մշակող, իսկ այսօր հմտություններից նույնիսկ հոստինգ անելն այլևս պետք չէ՝ պարզապես պետք է մղել նրանց կոդը ամպի մեջ որպեսայդ իսկ serverless ֆունկցիան Աλλά կան մի քանի нюансы: առաջինը, ձեր Python կոդը կարող է պահանջել որոշ կախվածություններ, և դրանք Cloud տեղափոխելը՝ միանգամայն բարդ է: Երկրորդ՝ ցանկացած նորմալ չատ-բոտի համար անհրաժեշտ է ինչ-որ տեղ պահել երկխոսության վիճակը (stateful այդ պատճառով); ինչպես կարելի է դա անել serverless ֆունկցիայի մեջ առավել հեշտությամբ? Երրորդ, ինչպես կարելի է արագ ու պակաս մաքուր գրել Ալիսայի կամ ընդհանրապես որևէ բոտի հմտություն, որն ունի մի աղջկա սյուժե: Այդ нюансов մասին, փաստորեն, հոդվածն է:.

Մաքսային պատրաստություն

Ալիսայի համար stateful հմտություն ստեղծելը Yandex.Cloud-ի serverless ֆունկցիաների և Python-ի միջոցով

Անհամբերների համար: անհրաժեշտ կախվածությունները ես հավաքում եմ make-файл-ով ֆունկցիան ամպի մեջ загрузելուց առաջ, երկխոսության վիճակը պահում եմ Yandex-ի Object Storage-ում (այն աջակցում է S3 API-ին), իսկ երկխոսությունը կառավարելու համար օգտագործում եմ իմ սեփական գրադարանն՝

tgalice . Արդյունքում ստացված էայսպիսի դեմո-հմտություն: Հիմա դա մանրամասն զննում ենք: Կոնկրետ ոչ անհամբերների համար: նախքան իմ պատմությանը մտնելը, ես շատ խորհուրդ եմ տալիս սկսել պարզից: Բանը, ստեղծեք մեկ ֆայլային echo bot, գրանցեք և փորձեք այն Developer Console-ի միջոցով; մանրամասները՝

Dialog-ների բլոգում Cloud-ի փաստաթղթերում և . Եվ միայն հետո սկսել:Եթե ուզում եք անմիջապես զգալ, ինչի համար մենք այստեղ պայքարում ենք, խնդրեք Ալիսային '

իրականացրու «IT-ի աստղագուշակ»': Արդյունքում պետք է տեղի ունենա մոտավորապես հետևյալ երկխոսությունը՝Ալիսա: բարև! Դուք գտնվում եք «IT-ի աստղագուշակ»-ում: Ասեք 'Սկիզբ', որ իմանաք, ինչ են ասում աստղերը:

Օգտատեր: Սկիզբ
Ա: Խնդրում եմ, նշեք ձեր անունը
Օ: Վասիսուալյան
Ա: Հիմա ասեք ինձ ձեր ծննդյան տարին: Միայն չորս թվեր, ոչ մի ավելորդ բան:
Օ: երկրորդ
Ա: Խնդրում եմ, փորձեք մեկ անգամ ևս: Նշեք ձեր ծննդյան տարին՝ չորս թվերով:
Օ: 2002
Ա: Շատ хуб բան! Հիմա նշեք ձեր ծննդյան ամիսը:
Օ: Փետրվար
Ա: Հոյակապ! Ի վերջո, նշեք ձեր ծննդյան օրը՝ միայն թիվ, մեկ կամ երկու թվերով:
Օ: 18
Ա: Շնորհակալություն, Վասիսուալյան: Հիմա մենք գիտենք՝ դուք 17 տարեկան եք, և դուք Մղեղ եք: Սա ձեզ հաստատ հաջողմի խողովակ է: Աստղերը ձեզ ասում են:
А: Спасибо, Васисуалий! Теперь мы знаем: вам 17 лет, и вы Водолей. Вот это вам, конечно, повезло! Звёзды говорят вам: աստղերը ինչ են ասում, դուք կիմանաք, երբ գործարկեք հմտությունը:

Պроблема в том, что для поддержания даже такого простого диалога нужно помнить имя и дату рождения пользователя, а в среде бессерверных функций это нетривиально. Хранить контекст в оперативной памяти или файликом на диске не получится, т.к. Яндекс.Облако может запустить функцию на нескольких виртуальных машинах одновременно и переключаться между ними произвольным образом. Придётся воспользоваться каким-то внешним хранилищем. Выбрано было Object Storage, как довольно недорогое и несложное хранилище прямо в Яндекс.Облаке (т.е. наверное быстрое). В качестве бесплатной альтернативы можно попробовать, например, халявный кусочек մկնիկի ամպի որտեղ-то հեռու: և Object Storage (այն աջակցում է S3 ինտերֆեյսին), և Mongo-ի համար կան հարմար Python-wrapper-ներ:

Մյուս խնդիրն այն է, որ Object Storage-ում և MongoDB-ում, և ցանկացած այլ բազայում պետք է լինեն արտաքին կախվածություններ, որոնք պետք է загрузить Yandex Functions-ի հետ ձեր ֆունկցիայի կոդի հետ միասին: Եվ ցանկալին է, որ դա լինի հարմար: Համիզ մաքուր է (օրինակ: heroku), ցավոք, չի ստացվի, բայց որևէ հիմնական հարմարություն կարելի է ստեղծել, գրել շրջակա միջավայրի օղակ (make-file):

Ինչպես գործարկել հորոսկոպի հմտությունը

  1. Պատրաստվել: մտնել ցանկացած Linux մեքենայի վրա: Իհարկե, Windows-ի վրա նույնպես կարելի է աշխատել, բայց make-file-ի գործարկում ստիպված եք կլինի «հավանականորեն» ինչ-որ բան անել: Եվ ամեն դեպքում, ձեզ անհրաժեշտ կլինի Python, որն ավելի բարձր է, քան 3.6:
  2. GitHub-ից կլոնավորել հորոսկոպային հմտության օրինակ.
  3. Ստանալ Я.Облаке: https://cloud.yandex.ru
  4. Ստեղծեք երկու բակետ Object Storage, անվանել դրանք ցանկացած անունով {BUCKET NAME} և tgalice-test-cold-storage (այս երկրորդ անունը այժմ կոշտ գրանցված է main.py սեփական օրինակս): Առաջին բակետը պետք է լինի միայն տեղադրման համար, երկրորդը՝ երկխոսության վիճակները պահելու համար.
  5. Ստեղծել ծառայության հաշիվ, նրան տալ դերը խմբագիր, և ստանալ ստատիկական կրեդենշալներ {KEY ID} և {KEY VALUE} — դրանք կօգտագործենք երկխոսության վիճակը գրելու համար: Դրանք բոլորն էլ անհրաժեշտ են, որպեսզի Я.Облако-ի ֆունկցիան կարողանա մուտք գործել Я.Облако-ի պահեստը: Մի օր, հույս ունեմ, որ ավտորիզացիան ավտոմատ կլինի, բայց այս պահին — այնպես:
  6. (Կարևոր չէ) տեղադրել հրկիզային հրահանգների ինտերֆեյս yc. Ֆունկցիան կարելի է ստեղծել նաև վեբ-համակարգի միջոցով, բայց CLI-ն լավ է, որ նոր սարքերը ի հայտ են գալիս արագ:
  7. Այժմ կարելի է, իրականում, պատրաստել կախվածությունների հավաքումը: բացել հրամանային տողը օրինակային հմտության ֆայլից make all. Փաթեթում բազմաթիվ գրադարաններ (հատուկ, սովորաբար, անպետք) ձեւավորվելու է dist.
  8. Ձեռքով խաղալ Object Storage-ում (բակետում {BUCKET NAME}) նախորդ փուլից ստացված արխիվը dist.zip. Ցանկության դեպքում, դա կարելի է անել նաև հրամանային տողից՝ օգտագործելով AWS CLI.
  9. Ստեղծել առանց սերվերի ֆունկցիա միջոցով վեբ-համակարգի կամ օգտագործելով ինտերվիցիա yc. Ծրագիրը կlooks այսպես.

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

Հետադարձի ձեռքով կառուցման գործընթացում բոլոր պարամետրերը լրացվում են համապատասխանաբար.

Այժմ դուք ստեղծած ֆունկցիան կարող եք փորձարկել ծրագրավորողի կոնսոլում, ապա կատարելագործել և հրապարակել հմտությունը.

Ալիսայի համար stateful հմտություն ստեղծելը Yandex.Cloud-ի serverless ֆունկցիաների և Python-ի միջոցով

Ինչ կա ներսում

Make-файл-ը իրականում պարունակում է բավականին պարզ սկրիպտ կախյալությունները տեղադրելու և դրանք արխիվում տեղավորելու համար dist.zip, մոտավորապես այսպես.

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

Այլ բաներ — մի քանի պարզ գործիքներ, որոնք ընդգրկված են գրադարանում . Արդյունքում ստացված է. Օգտվողի տվյալներ լրացնելու գործընթացը նկարագրվում է կոնֆիգուրացիայում form.yaml:

form_name: 'horoscope_form'
start:
  regexp: 'старт|нач(ать|ни)'
  suggests:
    - Старт
fields:
  - name: 'name'
    question: Խնդրում եմ նշեք ձեր անունը.
  - name: 'year'
    question: Այժմ ասեք, թե որ տարին եք ծնվել. Միայն չորս թիվ, ոչ մի ավելորդ բան.
    validate_regexp: '^[0-9]{4}$'
    validate_message: Խնդրում եմ փորձեք նորից. Նշեք ձեր ծննդյան տարին - չորս թիվ.
  - name: 'month'
    question: Գեղեցիկ! Այժմ նշեք ձեր ծննդյան ամիսը.
    options:
      - հունվար
     ...
      - դեկտեմբեր
    validate_message: Նա, ինչ որ դու նշեցիր, չի հիշեցնում ամիս. Խնդրում եմ նշեք ձեր ծննդյան ամիսը, առանց այլ բառերի.
  - name: 'day'
    question: Նշանդանք է! Վերջապես, նշեք ձեր ծննդյան ամսաթիվը - միայն թիվ, ընդամենը մեկ կամ երկու cifra.
    validate_regexp: '[0123]?d$'
    validate_message: Խնդրում եմ փորձեց նորից. Դուք պետք է նշեք ձեր ծննդյան թիվը (օրինակ, քսան);
    սա մեկ կամ երկու թիվ է.

Դատարկության գործընթացը և վերջնական արդյունքի հաշվարկը իրականացնում է Python դասը

class CheckableFormFiller(tgalice.dialog_manager.form_filling.FormFillingDialogManager):
    SIGNS = {
        'յանվար': 'Կոզերոգ',
        ...
    }

    def handle_completed_form(self, form, user_object, ctx):
        response = tgalice.dialog_manager.base.Response(
            text='Շնորհակալություն, {}! Այժմ մենք գիտենք, որ ձեզնից {} տարեկան է, և դուք {}. n'
                 'Դա իսկապես հիանալի է! Stars ասում են ձեզ: {}'.format(
                form['fields']['name'],
                2019 - int(form['fields']['year']),
                self.SIGNS[form['fields']['month']],
                random.choice(FORECASTS),
            ),
            user_object=user_object,
        )
        return response

Գծել, հիմնական դասը FormFillingDialogManager զբաղվում է «ֆորմայի» լրացման, իսկ հետագա դասի մեթոդը handle_completed_form նշում է, թե ինչ անել, երբ այն պատրաստ է.

Սա հիմնական խոսակցությունը օգտվողի համար չպետք է բացակայել, ինչպես նաև տրամադրել օգնություն «օգնություն» հրահանգի միջոցով և դուրս գալ հմտությունից «ելք» հրահանգով. Հենց դրա համար . Արդյունքում ստացված է բոլոր աղերսի առջևում կա ձևանմուշ, այնպես որ ամբողջական զրույցի կառավարիչը կազմված է կտորներից:

dm = tgalice.dialog_manager.CascadeDialogManager(
    tgalice.dialog_manager.GreetAndHelpDialogManager(
        greeting_message=DEFAULT_MESSAGE,
        help_message=DEFAULT_MESSAGE,
        exit_message='Համար, մոռացեք "Հայտնի տեխնոլոգիաների հորոսկոպում"  մինչև նորից հանդիպել եք!'
    ),
    CheckableFormFiller(`form.yaml`, default_message=DEFAULT_MESSAGE)
)

CascadeDialogManager իցը աշխատում է պարզապես: ամեն մեկը իր բաղադրիչները probeert применить текущему состоянию диалага по очереди и выберет первую уместную.

Քանի որ պատասխան ունի յուրաքանչյուր հաղորդագրություն, диалоговый менеджер возвращает питонячий объект Պատասխան, որը հետագայում կարող է վերափոխվել մերկ տեքստի կամ հաղորդագրության Ալիսի կամ Telegram-ում՝ կախված նրանից, թե որտեղ է բոտը գործարկված։ Այն նույնպես պարունակում է փոփոխված диալога, որը պետք է պահպանել: Այս ամենի համար զբաղվում է մեկ այլ դաս, DialogConnector, այնպես որ, Yandex Functions-ում навыка запускаի համար առանցքային սցենարը выглядит так:

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

Ինչպես տեսնում եք, այս կոդի մեծ մասը ստեղծում է կապ S3-զարգացման դիմելին: Ինչպես այդ կապն օգտագործվում է, կարելի է կարդալ tgalice-ի կոդում.
Վերջին տողի ստեղծում է ճառ alice_handler այդ նույնը, որ մենք ասել ենք, որ Yandex.Cloud-ի կողմից կիրառվի, երբ շարադրեցինք պարամետրը --entrypoint=main.alice_handler.

Вот, собственно, и всё. Make-файлы для сборки, S3-подобное Object Storage для хранения контекста, и питонячья библиотека . Արդյունքում ստացված է. Միասին серверնակու ֆունկեքսիաների և Python-ի արտահայտություններից, սա բավական է առողջ մարդու հատկանիշի զարգացման համար:

Դուք կարող եք հարցնել, ինչու անհրաժեշտ էր ստեղծել . Արդյունքում ստացված է? Весь скучный код, перекладывающий JSON’ы из запроса в ответ и из хранилища в память и обратно, лежит в ней. Там же лежит применялка регулярок, функция для понимания того, что «феврарь» похоже на «февраль», и прочее NLU для бедных. По моей задумке, этого уже должно быть достаточно, чтобы можно было набрасывать прототипы навыков в yaml-файлах, не слишком отвлекаясь на технические детали.

Եթե դուք ուզում եք ավելի լուրջ NLU, կարող եք ձեր навыка прикрутить Rasa կամ DeepPavlov, բայց դրանց կարգավորման համար անհրաժեշտ կլինի հավելյալ պարանոցներ, հատկապես առանց серверի: Եթե անմիջապես ցանկություն չկա կոդավորել, արժե օգտվել մոդելի տեսողական կառուցումով Aimylogic. Создавая tgalice, я думал о каком-то промежуточном пути. Посмотрим, что из этого получится.

Եվ հիմա միացեք ալիսի навыки մշակողների չատին, կարդացեք փաթեթավորում, և ստեղծեք հրաշալի навыки!

Ընտանիք: habr.com

Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով 🔥 Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով | ProHoster