Laten we beginnen met het nieuws. Gisteren kondigde Yandex.Cloud de lancering aan van een serverloze computerdienst . Dit betekent dat u alleen de code voor uw service schrijft (bijvoorbeeld een webapplicatie of een chatbot), en dat de Cloud zelf de virtuele machines waarop deze draait, creëert en onderhoudt. Bovendien worden deze machines zelfs gerepliceerd als de belasting toeneemt. Je hoeft er helemaal niet over na te denken, het is heel gemakkelijk. En de vergoeding geldt alleen voor de rekentijd.
Het kan echter ook zo zijn dat sommige mensen helemaal niet betalen. Dit zijn de ontwikkelaars , dat wil zeggen, ingebouwde chatbots. Elke ontwikkelaar kan zo'n vaardigheid schrijven, hosten en registreren, en vanaf vandaag hoeven vaardigheden niet eens meer gehost te worden: ze hoeven hun code alleen maar in de vorm van een bestand naar de cloud te uploaden. .
Maar er zijn een paar nuances. Ten eerste kan het zijn dat uw pitchcode afhankelijkheden nodig heeft. Het is niet eenvoudig om deze naar de Cloud te slepen. Ten tweede moet elke normale chatbot de status van de dialoog ergens opslaan (daarom is het stateful); Wat is de gemakkelijkste manier om dit te doen in een serverloze functie? Ten derde, hoe kun je snel en eenvoudig een vaardigheid schrijven voor Alice of een andere bot met een plot die niet nul is? Het artikel gaat inderdaad over deze nuances.

Morele voorbereiding
Voor de ongeduldigen: ik compileer de benodigde afhankelijkheden met een makefile voordat ik de functie upload naar de cloud, ik sla de dialoogstatus op in Yandex Object Storage (het ondersteunt de S3 API) en ik gebruik mijn eigen bibliotheek om de dialoog te beheren . Het resultaat is demovaardigheid. Laten we dit nu eens wat nader bekijken.
Voor degenen die iets minder ongeduldig zijn, raad ik u aan om, voordat ik in mijn verhaal over complicaties duik, met de eenvoudige aanpak te beginnen. Maak namelijk een echobot-functie in één bestand, registreer deze en test deze in de Dialogs-ontwikkelaarsconsole; details - in и . En pas dan beginnen.
Als je direct wilt voelen waar we hier voor strijden, vraag het dan aan Alice ''. Het volgende dialoog zou moeten plaatsvinden:
Alice: Hallo! U bevindt zich in de vaardigheid "IT-horoscoop". Zeg "Start" en ontdek wat de sterren voor jou in petto hebben.
Gebruiker: Start
A: Wilt u uw naam vermelden?
Jij: Vassily
A: Vertel me nu eens in welk jaar je geboren bent. Slechts vier cijfers, meer niet.
Yu: tweede
A: Probeer het opnieuw. Geef uw geboortejaar op - vier cijfers.
U: 2002
A: Geweldig! Noem nu de maand waarin u geboren bent.
Y: Februari
A: Uitstekend! Vertel me ten slotte uw geboortedatum. Gewoon een getal, één of twee cijfers.
U: 18
A: Dank je wel, Vasiliy! Nu weten we het: je bent 17 jaar oud en je bent een Waterman. Jij hebt zeker geluk! De sterren vertellen je: а что говорят звёзды, вы узнаете, запустив навык.
Het probleem is dat je, om zelfs zo'n eenvoudige dialoog te onderhouden, de naam en geboortedatum van de gebruiker moet onthouden. En in een serverloze omgeving is dat niet zo eenvoudig. Het is niet mogelijk om de context in het RAM-geheugen of als bestand op de schijf op te slaan, omdat Yandex.Cloud de functie op meerdere virtuele machines tegelijk kan uitvoeren en willekeurig tussen deze machines kan schakelen. Je zult externe opslag moeten gebruiken. Er werd gekozen voor Object Storage omdat dit een relatief goedkope en eenvoudige opslagoplossing is die direct in Yandex.Cloud beschikbaar is (dus waarschijnlijk snel). Als gratis alternatief kunt u bijvoorbeeld een gratis stukje proberen ergens ver weg. Er zijn handige Python-wrappers voor zowel Object Storage (het ondersteunt de S3-interface) als Mongo.
Een ander probleem is dat je voor de toegang tot Object Storage, MongoDB en andere databases of gegevensopslag een aantal externe afhankelijkheden nodig hebt die samen met de code van je functie naar Yandex Functions moeten worden geüpload. En ik wil dit graag op een gemakkelijke manier doen. Helaas zal het niet helemaal handig zijn (zoals op Heroku), maar er kan wel wat basiscomfort gecreëerd worden door een script te schrijven voor het samenstellen van de omgeving (make file).
Hoe je de horoscoopvaardigheid start
- Voorbereiding: log in op een willekeurige machine waarop Linux draait. In principe, met Windows Dit zou waarschijnlijk ook kunnen werken, maar het uitvoeren van het makefile vereist wel wat magie. En in elk geval heb je Python 3.6 of hoger nodig.
- Kloon het van GitHub .
- Registreren in Yandex.Cloud:
- Maak twee emmers voor jezelf noem ze bij welke naam dan ook
{BUCKET NAME}иtgalice-test-cold-storage(deze tweede naam is nu hard gecodeerd inmain.py(mijn voorbeeld). De eerste bucket is alleen nodig voor de implementatie, de tweede voor het opslaan van dialoogstatussen. - Creëren geef hem een rol
editor, en krijg er statische referenties voor{KEY ID}и{KEY VALUE}— we zullen ze gebruiken om de status van de dialoog vast te leggen. Dit alles is nodig zodat de functie van Yandex.Cloud toegang heeft tot de opslag van Yandex.Cloud. Ik hoop dat autorisatie ooit automatisch wordt, maar voorlopig is dat niet anders. - (Optioneel) installeren
yc. Je kunt ook een functie via de webinterface maken, maar de CLI is handig omdat allerlei vernieuwingen daarin sneller verschijnen. - Nu kunt u de afhankelijkheidsopbouw daadwerkelijk voorbereiden: voer deze uit op de opdrachtregel vanuit de map met de voorbeeldvaardigheid
make all. Er worden een aantal bibliotheken (meestal, zoals gewoonlijk, onnodig) in de map geïnstalleerddist. - Handmatig uploaden naar Object Storage (in een bucket)
{BUCKET NAME}) het archief verkregen in de vorige stapdist.zip. Als u dat wenst, kunt u dit doen vanaf de opdrachtregel, bijvoorbeeld met behulp van . - Maak een serverloze functie via de webinterface of met behulp van een hulpprogramma
yc. Voor het hulpprogramma ziet de opdracht er als volgt uit:
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=3sWanneer u een functie handmatig aanmaakt, worden alle parameters op dezelfde manier ingevuld.
Nu kunt u de functie die u hebt gemaakt testen via de ontwikkelaarsconsole en vervolgens de vaardigheid verfijnen en publiceren.

Wat zit er onder de motorkap?
De Makefile bevat eigenlijk een vrij eenvoudig script voor het installeren van afhankelijkheden en het plaatsen ervan in het archief. dist.zip, zoiets als dit:
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 ./*De rest bestaat uit een paar eenvoudige hulpmiddelen, samengevoegd in een bibliotheek. tgalice. Het proces van het invullen van gebruikersgegevens wordt beschreven door de configuratie 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: Пожалуйста, попробуйте ещё раз. Вам нужно назвать число своего рождения (например, двадцатое); это одна или две цифры.Het werk van het parsen van deze configuratie en het berekenen van het uiteindelijke resultaat wordt overgenomen door de Python-klasse
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 responsePreciezer gezegd, de basisklasse FormFillingDialogManager is bezig met het invullen van het "formulier" en de methode van de kinderklasse handle_completed_form vertelt haar wat ze moet doen als ze er klaar voor is.
Naast deze hoofdstroom van dialoog moet de gebruiker ook worden begroet en via de opdracht 'help' hulp krijgen, en via de opdracht 'exit' uit de vaardigheid worden bevrijd. Voor dit doel, tgalice Er is ook een sjabloon, dus de hele dialoogmanager bestaat uit onderdelen:
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 werkt eenvoudig: het probeert alle componenten één voor één toe te passen op de huidige status van de dialoog en selecteert de eerste geschikte.
Als reactie op elk bericht retourneert de dialoogbeheerder een Python-object. Response, die vervolgens kan worden omgezet in platte tekst of in een bericht in Alice of Telegram, afhankelijk van waar de bot draait; Het bevat ook de gewijzigde status van de dialoog, die moet worden opgeslagen. Er is nog een andere klasse die zich met deze hele keuken bezighoudt, DialogConnector, dus het directe script voor het uitvoeren van de vaardigheid op Yandex Functions ziet er als volgt uit:
...
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_handlerZoals u kunt zien, creëert het grootste deel van deze code een verbinding met de S3 Object Storage-interface. Hoe deze verbinding direct wordt gebruikt, kunt u hier lezen .
De laatste regel creëert de functie alice_handler — dezelfde die we Yandex.Cloud vertelden te trekken toen we de parameter instelden --entrypoint=main.alice_handler.
Nou ja, dat is eigenlijk alles. Makefiles voor het bouwen, S3-achtige Object Storage voor het opslaan van context en een Python-bibliotheek tgalice. Gecombineerd met serverloze functies en de expressiviteit van Python is dit voldoende om de vaardigheden van een gezond persoon te ontwikkelen.
Je vraagt je misschien af waarom het nodig was om tgalice? Alle saaie code die JSON's van aanvraag naar antwoord en van opslag naar geheugen en terug verplaatst, zit erin. Er is ook een reguliere expressie-app, een functie om te begrijpen dat “februari” vergelijkbaar is met “februari”, en andere NLU voor de armen. Naar mijn mening zou dit al voldoende moeten zijn om prototypes van vaardigheden in yaml-bestanden te kunnen schetsen, zonder dat je te veel afgeleid wordt door technische details.
Als je een serieuzere NLU wilt, kun je deze aan je vaardigheid koppelen of , maar om ze op te zetten moet je wel wat extra met een tamboerijn dansen, vooral op serverless. Als je helemaal geen zin hebt om te coderen, kun je het beste een visueel ontwerper inhuren, zoals . Toen ik Tgalice creëerde, dacht ik aan een soort tussenpad. Laten we eens kijken wat hieruit komt.
Nou, doe dan mee , lezen en creëer prachtige !
Bron: www.habr.com
