Пачнём з навін. Учора Яндекс.Воблака анансавала запуск сэрвісу бессерверных вылічэнняў . Гэта значыць: ты пішаш толькі код свайго сэрвісу (напрыклад, вэб-прыкладанні або чатбота), а Воблака само стварае і абслугоўвае віртуальныя машыны, дзе ён запускаецца, і нават рэплікуе іх, калі ўзрастае нагрузка. Думаць увогуле не трэба, вельмі зручна. І плата ідзе толькі за час вылічэнняў.
Зрэшты, сёй-той можа ўвогуле не плаціць. Гэта - распрацоўшчыкі , гэта значыць убудаваных у яе чататаў. Напісаць, захапіць і зарэгістраваць такі навык можа любы распрацоўшчык, а з сённяшняга дня навыкі нават не трэба хосціць - дастаткова заліць іх код у воблака ў выглядзе .
Але ёсць пара нюансаў. Па-першае, ваш пітніцкі код можа патрабаваць нейкіх залежнасцяў, і зацягваць іх у Воблака - нетрывіяльна. Па-другое, любому нармальнаму чату трэба захоўваць дзесьці стан дыялогу (stateful таму); як зрабіць гэта ў бессервернай функцыі прасцей за ўсё? Па-трэцяе, а як наогул можна хутка-брудна напісаць навык для Алісы ці ўвогуле нейкага бота з ненулявым сюжэтам? Аб гэтых нюансах, уласна, артыкул.

Маральная падрыхтоўка
Для нецярплівых: неабходныя залежнасці я збіраю make-файлам перад загрузкай функцыі ў воблака, стан дыялогу захоўваю ў яндэксаўскім Object Storage (яно падтрымлівае API S3), а для кіравання дыялогам выкарыстоўваю ўласную бібліятэку . У выніку атрымліваецца дэма-навык. А зараз разбяром усё гэта крыху больш падрабязна.
Для крыху менш нецярплівых: перш чым апускацца ў маю гісторыю пра складанасці, я вельмі рэкамендую пачаць з простага. А менавіта, стварыць аднафайлавую функцыю-эхобота, зарэгістраваць і пацясціць яе ў кансолі распрацоўніка Дыялогаў; падрабязнасці - у и . І толькі потым ужо прыступаць.
Калі жадаецца адразу адчуць, завошта мы тут дужаемся, папытаеце Алісу ''. Павінен адбыцца прыкладна наступны дыялог:
Аліса: Прывітанне! Вы знаходзіцеся ў навыку «айцішны гараскоп». Скажыце «Старт», каб даведацца, што абяцаюць вам зоркі.
Карыстальнік: Старт
А: Калі ласка, назавіце сваё імя
Ю: Васісуалій
А: Цяпер скажыце мне год вашага нараджэння. Толькі чатыры лічбы, нічога лішняга.
Ю: другі
А: Калі ласка, паспрабуйце яшчэ раз. Назавіце год вашага нараджэння - чатыры лічбы.
Ю: 2002
А: Выдатна! Цяпер назавіце месяц вашага нараджэння.
Ю: Люты
А: Выдатна! Нарэшце, назавіце мне дату вашага нараджэння - толькі лік, усяго адна ці дзве лічбы.
Ю: 18
А: Дзякуй, Васісуалій! Цяпер мы ведаем: вам 17 гадоў, і вы Вадаліў. Вось гэта вам, вядома, павезла! Зоркі кажуць вам: а что говорят звёзды, вы узнаете, запустив навык.
Праблема ў тым, што для падтрымання нават такога простага дыялогу трэба памятаць імя і дату нараджэння карыстача, а ў асяроддзі бессерверных функцый гэта нетрывіяльна. Захоўваць кантэкст у аператыўнай памяці ці файлікам на дыску не атрымаецца, т.я. Яндекс.Воблака можа запусціць функцыю на некалькіх віртуальных машынах адначасова і перамыкацца паміж імі адвольнай выявай. Прыйдзецца скарыстацца нейкім вонкавым сховішчам. Выбрана было Object Storage, як даволі недарагое і нескладанае сховішча прама ў Яндэкс.Аблокі (г.зн. мусіць хуткае). У якасці бясплатнай альтэрнатывы можна паспрабаваць, напрыклад, халяўны кавалачак недзе далёка. І для Object Storage (ён падтрымлівае інтэрфейс S3), і для Mongo існуюць зручныя пітонаўскія абгорткі.
Іншая праблема – што для хадні і ў Object Storage, і ў MongoDB, і ў любую іншую базу ці сховішча дадзеных, патрэбныя нейкія вонкавыя залежнасці, якія трэба заліць на Yandex Functions разам з кодам сваёй функцыі. І хацелася б рабіць гэта зручна. Зусім зручна (тыпу як на heroku), нажаль, не атрымаецца, але нейкі базавы камфорт можна стварыць, напісаўшы скрыпт для зборкі асяроддзя (make-файл).
Як запусціць навык-гараскоп
- Падрыхтавацца: зайсці на якую-небудзь машынку з лінуксам. У прынцыпе, з Windows таксама, мусіць, можна працаваць, але з запускам make-файла тады прыйдзецца павядзьмарыць. І ў любым выпадку, вам спатрэбіцца ўсталяваны Python не ніжэй за 3.6.
- Схіляваць сабе з гітхаба .
- Зарэгістравацца ў Я.Аблокі:
- Стварыць сабе два бакеты ў , назваць іх любым імем
{BUCKET NAME}иtgalice-test-cold-storage(вось гэта другое імя зараз захардскурана ўmain.pyмайго прыкладу). Першы бакет патрэбен будзе толькі для дэплою, другі - для захоўвання станаў дыялогу. - Стварыць , даць яму ролю
editor, і атрымаць да яго статычныя крэдэншалы{KEY ID}и{KEY VALUE}- іх будзем выкарыстоўваць для запісу стану дыялогу. Усё гэта трэба, каб функцыя з Я.Аблокі магла атрымаць доступ да сховішча з Я.Аблокі. Калі-небудзь, спадзяюся, аўтарызацыя стане аўтаматычнай, але пакуль - так. - (Не абавязкова) усталяваць
yc. Стварыць функцыю можна і праз вэб-інтэрфейс, але CLI добры тым, што ўсякія новаўвядзенні з'яўляюцца ў ім хутчэй. - Зараз можна, уласна, падрыхтаваць зборку залежнасцяў: запусціць у камандным радку з тэчкі з прыкладам навыку
make all. Усталюецца куча бібліятэк (у асноўным, як звычайна, непатрэбных) у тэчкуdist. - Ручкамі заліць у Object Storage (у бакет
{BUCKET NAME}) які атрымаўся на папярэднім кроку архіўdist.zip. Пры жаданні, можна зрабіць гэта і з каманднага радка, напрыклад, выкарыстоўваючы . - Стварыць бессерверную функцыю праз вэб-інтэрфейс або выкарыстоўваючы ўтыліту
yc. Для ўтыліты каманда будзе выглядаць вось так:
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Пры ручным стварэнні функцыі ўсе параметры запаўняюцца аналагічна.
Цяпер створаную вамі функцыю можна тэставаць праз кансоль распрацоўніка, а потым дапрацоўваць і публікаваць навык.

Што там пад капотам
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 ./*Астатняе - некалькі простых інструментаў, загорнутых у бібліятэку tgalice. Працэс запаўнення дадзеных аб карыстачы апісваецца канфігам 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: Отлично! Наконец, назовите мне дату вашего рождения - только число, всего одна или две цифры.
validate_regexp: '[0123]?d$'
validate_message: Пожалуйста, попробуйте ещё раз. Вам нужно назвать число своего рождения (например, двадцатое); это одна или две цифры.Працу па разборы гэтага канфіга і вылічэнні фінальнага выніку бярэ на сябе гадавы клас
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'
'Вот это вам, конечно, повезло! Звёзды говорят вам: {}'.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 кажа, што рабіць, калі яна гатова.
Акрамя гэтага асноўнага патоку дыялогу карыстальніка трэба яшчэ прывітаць, а таксама выдаць даведку па камандзе "дапамога" і выпусціць з навыку па камандзе "выхад". Для гэтага ў tgalice таксама ёсць шаблон, таму цалікавы дыялогавы мэнэджар складзены з кавалачкаў:
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 працуе проста: спрабуе прымяніць да бягучага стану дыялогу ўсе свае складнікі па чарзе, і выбірае першую дарэчную.
У якасці адказу на кожнае паведамленне дыялогавы мэнэджар вяртае сілкавальны аб'ект Response, які далей можна сканвертаваць у голы тэкст, або ў паведамленне ў Алісе ці Тэлеграме - гледзячы дзе бот запушчаны; у ім жа змяшчаецца і зменены стан дыялогу, які трэба захаваць. Усёй гэтай кухняй займаецца яшчэ адзін клас, 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-інтэрфейсу Object Storage. Як непасрэдна выкарыстоўваецца гэтае падлучэнне, можна пачытаць .
Апошні радок стварае функцыю alice_handler - тую самую, якую мы загадалі тузаць Яндэкс.Аблокі, калі задавалі параметр --entrypoint=main.alice_handler.
Вось, уласна, і ўсё. Make-файлы для зборкі, S3-падобнае Object Storage для захоўвання кантэксту, і питонячая бібліятэка tgalice. Разам з бессервернымі функцыямі і выразнасцю пітона гэтага дастаткова для распрацоўкі навыку здаровага чалавека.
Вы можаце спытаць, навошта патрэбна спатрэбілася ствараць tgalice? Увесь сумны код, які перакладае JSON'ы з запыту ў адказ і са сховішча ў памяць і зваротна, ляжыць у ёй. Там жа ляжыць ужывалка рэгулярак, функцыя для разумення таго, што "люты" падобна на "люты", і іншае NLU для бедных. Па маёй задумцы, гэтага ўжо павінна быць дастаткова, каб можна было накідваць прататыпы навыкаў у yaml-файлах, не занадта адцягваючыся на тэхнічныя дэталі.
Калі жадаецца больш сур'ёзнага NLU, можна прыкруціць да свайго навыку або , Але для іх наладкі запатрабуюцца дадатковыя скокі з бубнам, асабліва на serverless. Калі зусім не жадаецца кадзіць, варта скарыстацца візуальным канструктарам тыпу . Ствараючы tgalice, я думаў аб нейкім прамежкавым шляху. Пабачым, што з гэтага выйдзе.
Ну а сягоння ўступайце ў , чытайце , і стварайце выдатныя !
Крыніца: habr.com
