Låt oss börja med nyheterna. Igår tillkännagav Yandex.Cloud lanseringen av en serverlös beräkningstjänst . Det betyder: du skriver bara koden för din tjänst (till exempel en webbapplikation eller chatbot), och molnet skapar och underhåller virtuella maskiner där den körs, och till och med replikerar dem om belastningen ökar. Du behöver inte tänka alls, jättebekvämt. Och avgiften tas bara ut för beräkningstiden.
Emellertid kan vissa kanske inte betala alls. Det handlar om utvecklare , det vill säga de inbyggda chatbottarna. Vem som helst kan skriva, hosta och registrera en sådan färdighet, och från och med idag behöver färdigheter inte ens hostas — det räcker att ladda upp deras kod till molnet i form av .
Men det finns ett par nyanser. För det första kan din Python-kod kräva vissa beroenden, och att föra in dem i molnet är ingen liten uppgift. För det andra måste varje normal chatbot lagra dialogens tillstånd (därav ‘stateful’); hur kan detta göras på enklast möjliga sätt i en serverlös funktion? För det tredje, hur kan man snabbt och smutsigt skriva en färdighet för Alice eller någon annan bot med en icke-noll berättelse? Om dessa nyanser handlar egentligen artikeln.

Moralisk beredskap
För de som har bråttom: jag samlar de nödvändiga beroendena med en make-fil innan jag laddar upp funktionen till molnet, dialogens tillstånd lagrar jag i Yandex Object Storage (det stödjer S3 API), och för att hantera dialogen använder jag mitt eget bibliotek . Resultatet blir demo-färdighet. Och nu ska vi gå igenom allt detta lite mer i detalj.
För de som är lite mindre otåliga: innan du dyker ner i min historia om svårigheterna rekommenderar jag starkt att börja enkelt. Det vill säga, skapa en enfil-function-echo-bot, registrera och testa den i Dialogutvecklarens konsol; detaljer finns i och . Och först därefter börja.
Om du vill känna på en gång varför vi kämpar här, be Alice ‘‘. Det bör inträffa ungefär följande dialog:
Alice: Hej! Du är i färdigheten "IT-horoskop". Säg "Start" för att ta reda på vad stjärnorna spårar för dig.
Användare: Start
A: Vänligen ange ditt namn
U: Vasilij
A: Säg nu vilket år du är född. Bara fyra siffror, inget extra.
J: andra
A: Var god, försök igen. Ange året för din födelse – fyra siffror.
J: 2002
A: Utmärkt! Nu får du ange månaden för din födelse.
J: Februari
A: Bra! Slutligen, ange datumet för din födelse – bara siffran, högst två siffror.
J: 18
A: Tack, Vasisauliy! Nu vet vi: du är 17 år och ditt stjärntecken är Vattumannen. Vad händer, hade du tur! Stjärnorna säger dig: vad stjärnorna säger, får du veta genom att aktivera färdigheten.
Problemet är att för att upprätthålla även en så enkel dialog måste man komma ihåg användarens namn och födelsedatum, och i en serverlös miljö är detta inte trivialt. Att lagra kontext i RAM eller på en fil på disken fungerar inte, eftersom Yandex.Cloud kan starta funktionen på flera virtuella maskiner samtidigt och byta mellan dem arbiträrt. Vi måste använda något extern lagring. Valet föll på Object Storage, som en ganska billig och enkel lagring direkt i Yandex.Cloud (alltså troligen snabbt). Som ett gratis alternativ kan man prova, till exempel, en gratis bit någonstans långt borta. Och både för Object Storage (det stöder S3-gränssnittet) och för Mongo finns det bekväma Python-bibliotek.
Ett annat problem är att för att arbeta med både Object Storage och MongoDB, samt med vilken annan databas eller lagring som helst, behövs externa beroenden som måste laddas upp till Yandex Functions tillsammans med koden för sin funktion. Och man skulle vilja göra detta bekvämt. Helt bekvämt (typ som på heroku) tyvärr inte, men man kan skapa en viss grundläggande komfort genom att skriva ett skript för att bygga miljön (make-fil).
Hur man startar stjärnteckensfärdigheten
- Förbered dig: gå till en maskin med Linux. I princip bör det också gå att arbeta med Windows, men då måste du experimentera med starten av make-filen. Och i vilket fall som helst behöver du ha installerad Python version 3.6 eller högre.
- Klona från GitHub .
- Registrera dig på Y. Cloud:
- Skapa två bucketer i , döp dem till valfritt namn
{BUCKET NAME}ochtgalice-test-cold-storage(det här andra namnet är just nu hårdkodad imain.pymitt exempel). Den första bucketen behövs bara för deployment, den andra – för att lagra dialogens tillstånd. - Skapa , ge det rollen
redigerare, och få statiska autentiseringsuppgifter för det{KEY ID}och{KEY VALUE}— vi kommer att använda dem för att registrera dialogens tillstånd. Allt detta behövs så att funktionen från Y.Cloud kan få åtkomst till lagringen från Y.Cloud. Förhoppningsvis kommer autentiseringen en dag att bli automatisk, men för tillfället — så här. - (Ej nödvändigt) installera
yc. Du kan också skapa funktionen via webbgränssnittet, men CLI är bra för att nya funktioner dyker upp där snabbare. - Nu kan vi egentligen förbereda installationen av beroenden: kör i kommandoraden från mappen med exempel på färdigheten
make all. En mängd bibliotek kommer installeras (främst, som vanligt, onödiga) i mappendist. - Manuellt laddas det resulterande arkivet från föregående steg upp i Object Storage (i bucket
{BUCKET NAME}) . Om man vill kan detta göras även från kommandoraden, till exempel meddist.zipAWS CLI . - . För verktyget ser kommandot ut så här:
ycyc 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
Vid manuell skapande av funktionen fylls alla parametrar i på samma sätt.Nu kan den funktion du har skapat testas via utvecklarkonsolen, och sedan vidareutvecklas och publiceras.
Vad som finns under huven

Make-filen innehåller faktiskt ett ganska enkelt skript för att installera beroenden och paketera dem i ett arkiv
, ungefär så här: dist.zipmkdir -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 ./
Resten är några enkla verktyg inpackade i ett bibliotek. Processen för att fylla i användardata beskrivs av konfigurationen tgaliceform.yaml form.yaml:
form_name: 'horoskop_form'
start:
regexp: 'start|börja'
suggests:
- Start
fields:
- name: 'name'
question: Vänligen ange ditt namn.
- name: 'year'
question: Nu, berätta för mig vilket år du föddes. Endast fyra siffror, inget mer.
validate_regexp: '^[0-9]{4}$'
validate_message: Vänligen försök igen. Ange ditt födelseår - fyra siffror.
- name: 'month'
question: Utmärkt! Nämn nu månaden då du föddes.
options:
- januari
...
- december
validate_message: Det du angav verkar inte vara en månad. Vänligen ange månaden då du föddes, utan andra ord.
- name: 'day'
question: Utmärkt! Slutligen, ge mig datum för din födelse - endast siffror, en eller två siffror.
validate_regexp: '[0123]?d$'
validate_message: Vänligen försök igen. Du måste ange ditt födelsedatum (t.ex. tjugo); det är en eller två siffror.Arbetet med att tolka denna konfiguration och beräkna det slutliga resultatet tas om hand av en Python-klass
class CheckableFormFiller(tgalice.dialog_manager.form_filling.FormFillingDialogManager):
SIGNS = {
'januari': 'Stenbocken',
...
}
def handle_completed_form(self, form, user_object, ctx):
response = tgalice.dialog_manager.base.Response(
text='Tack, {}! Nu vet vi: du är {} år gammal och du är {}. n'
'Det var verkligen tur! Stjärnorna säger dig: {}'.format(
form['fields']['name'],
2019 - int(form['fields']['year']),
self.SIGNS[form['fields']['month']],
random.choice(FORECASTS),
),
user_object=user_object,
)
return responseMer exakt, basklassen FormFillingDialogManager fyller i "formuläret", och metoden i underklassen handle_completed_form anger vad man ska göra när den är klar.
Förutom detta huvudflöde av användardialogen behöver man också hälsa, ge hjälp med kommandot "hjälp" och avsluta från färdigheten med kommandot "avsluta". För detta finns det också en mall, så hela dialoghanteraren är sammansatt av bitar: tgalice dm = tgalice.dialog_manager.CascadeDialogManager( tgalice.dialog_manager.GreetAndHelpDialogManager( greeting_message=DEFAULT_MESSAGE, help_message=DEFAULT_MESSAGE, exit_message='Adjö, kom tillbaka till färdigheten "IT-horoskop" igen!' ), CheckableFormFiller(`form.yaml`, default_message=DEFAULT_MESSAGE) )
CascadeDialogManagerfungerar enkelt: försöker tillämpa alla sina beståndsdelar på den aktuella dialogens tillstånd i tur och ordning och väljer den första lämpliga. Som svar på varje meddelande returnerar dialoghanteraren ett Python-objekt
Response Response, som sedan kan konverteras till ren text eller ett meddelande i Alice eller Telegram – beroende på var boten körs; den innehåller också det ändrade tillståndet av dialogen som måste bevaras. Allt detta hanteras av en annan klass, DialogConnector, så skriptet för att starta färdigheten på Yandex Functions ser ut så här:
...
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_handlerSom ni ser skapar större delen av denna kod en anslutning till S3-gränssnittet för Object Storage. Hur denna anslutning används kan man läsa om .
Den sista raden skapar funktionen alice_handler – den som vi instruerade Yandex.Cloud att kalla när vi angav parametern --entrypoint=main.alice_handler.
Och det är allt. Make-filer för byggande, S3-liknande Object Storage för att lagra kontext och Python-bibliotek tgalice. I kombination med serverlösa funktioner och Pythons uttrycksfullhet är detta tillräckligt för att utveckla en hälsosam färdighet.
Du kanske undrar varför det var nödvändigt att skapa tgalice? Весь скучный код, перекладывающий JSON’ы из запроса в ответ и из хранилища в память и обратно, лежит в ней. Там же лежит применялка регулярок, функция для понимания того, что «феврарь» похоже на «февраль», и прочее NLU для бедных. По моей задумке, этого уже должно быть достаточно, чтобы можно было набрасывать прототипы навыков в yaml-файлах, не слишком отвлекаясь на технические детали.
Om du önskar en mer seriös NLU kan du koppla till din färdighet eller , men för deras konfiguration krävs ytterligare kringelikrokar, särskilt på serverlös. Om du inte vill koda alls, är det värt att använda en visuell byggare som . När jag skapade tgalice tänkte jag på en slags mellanväg. Vi får se vad som kommer ut ur det.
Men nu går med i , läs , och skapa fantastiska !
Källa: habr.com
