我们先从新闻说起。 昨天 Yandex.Cloud 宣布推出无服务器计算服务
然而,有些人可能根本不付钱。 这些是开发商
但有一些细微差别。 首先,您的宠物代码可能需要一些依赖项,将它们拖到云中并不是一件容易的事。 其次,任何正常的聊天机器人都需要将对话的状态存储在某处(因此是有状态的); 如何以最简单的方式在无服务器功能中做到这一点? 第三,如何为 Alice 甚至某种具有非零情节的机器人编写快速肮脏的技能? 关于这些细微差别,其实有文章。
道德准备
对于不耐烦的人:我在将函数上传到云之前使用 makefile 收集必要的依赖项,将对话框的状态存储在 Yandex 对象存储中(它支持 S3 API),并使用我自己的库来管理对话框
对于不太耐心的人,在深入研究我的复杂故事之前,我强烈建议从简单的开始。 即创建一个单文件echobot函数,在Dialog开发者控制台中注册并测试; 详细信息 - 在
如果你想立即感受到我们为何而战,就去问爱丽丝吧。
爱丽丝:你好! 您处于“IT 占星”技能中。 说“开始”,看看星星向您承诺了什么。
用户:开始
答:请说出您的姓名。
于:瓦西苏利
A:现在告诉我你的出生年份。 只有四位数,仅此而已。
于:第二
答:请再试一次。 注明您的出生年份 - 四位数。
于:2002年
一个了不起的! 现在说出您的出生月份。
于:二月
一个了不起的! 最后,告诉我你的出生日期——只是一个数字,只是一两位数字。
于:18年
答:谢谢瓦西里! 现在我们知道:你今年17岁,你是水瓶座。 当然,你很幸运! 星星告诉你 а что говорят звёзды, вы узнаете, запустив навык.
问题是,即使要维护这样一个简单的对话框,您也需要记住用户的姓名和出生日期,而在无服务器环境中,这并不是一件小事。 将上下文存储在 RAM 中或作为磁盘上的文件是行不通的,因为Yandex.Cloud可以同时在多个虚拟机上运行该功能,并在它们之间任意切换。 您必须使用某种外部存储。 对象存储被选为直接在 Yandex.Cloud 中相当便宜且简单的存储(也就是说,可能很快)。 作为免费的替代方案,您可以尝试例如免费的作品
另一个问题是,为了访问对象存储、MongoDB 和任何其他数据库或数据存储,您需要一些外部依赖项,您需要将这些依赖项与函数代码一起上传到 Yandex Functions。 我想舒服地做这件事。 它非常方便(就像在heroku上一样),可惜它不起作用,但是您可以通过编写脚本来构建环境(make文件)来创建一些基本的舒适感。
如何开始占星技能
- 准备好:转到一台装有 Linux 的机器。 原则上,您也可以使用 Windows,但是您必须启动 makefile。 无论如何,您至少需要安装 3.6 版本的 Python。
- 从 github 克隆
占星技能的例子 . - 在Ya.Cloud注册:
https://cloud.yandex.ru - 为自己创建两个桶
对象存储 ,用任何名字称呼他们{BUCKET NAME}
иtgalice-test-cold-storage
(这个中间名现在被硬编码到main.py
我的例子)。 第一个存储桶仅用于部署,第二个存储桶用于存储对话框状态。 - 创建
服务帐户 ,给他一个角色editor
,并获取它的静态凭证{KEY ID}
и{KEY VALUE}
- 我们将使用它们来记录对话的状态。 所有这些都是为了让Ya.Cloud 中的功能可以访问Ya.Cloud 中的存储。 我希望有一天,授权将变得自动,但目前 - 如此。 - (可选)安装
命令行界面 yc
。 您还可以通过 Web 界面创建函数,但 CLI 很好,因为各种创新都可以更快地出现在其中。 - 事实上,现在您可以准备依赖项的组装:从包含技能示例的文件夹中在命令行上运行
make all
。 一堆库(大部分是不必要的)将安装在该文件夹中dist
. - 将笔填充到对象存储中(放入桶中
{BUCKET NAME}
) 上一步获得的存档dist.zip
。 如果需要,您还可以从命令行执行此操作,例如使用命令行界面 . - 通过 Web 界面或使用实用程序创建无服务器函数
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
手动创建函数时,所有参数都以相同的方式填充。
现在您创建的功能可以通过开发者控制台进行测试,然后最终确定并发布技能。
引擎盖下有什么
makefile 实际上包含一个相当简单的脚本,用于安装依赖项并将它们放入存档中。 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
。 config描述了填写用户数据的过程 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: Пожалуйста, попробуйте ещё раз. Вам нужно назвать число своего рождения (например, двадцатое); это одна или две цифры.
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'
'Вот это вам, конечно, повезло! Звёзды говорят вам: {}'.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
工作原理很简单:它尝试依次将其所有组件应用于对话的当前状态,并选择第一个相关组件。
作为对每条消息的响应,对话管理器返回一个 python 对象 Response
,然后可以转换为纯文本,或者转换为 Alice 或 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 接口的连接。 这个连接是如何直接使用的,可以阅读
最后一行创建一个函数 alice_handler
- 我们在设置参数时命令拉取 Yandex.Cloud 的那个 --entrypoint=main.alice_handler
.
事实上,仅此而已。 用于构建的 Makefile、用于上下文存储的类似 S3 的对象存储以及一个 Python 库 tgalice
。 再加上Python的无服务器特性和表现力,这足以培养一个健康人的技能。
您可能会问为什么需要创建 tgalice
? 所有将 JSON 从请求传输到响应、从存储传输到内存并返回的无聊代码都在其中。 还有正则表达式应用程序、用于理解“二月”与“二月”类似的函数,以及其他面向穷人的 NLU。 按照我的想法,这应该已经足够能够在 yaml 文件中勾勒出技能原型,而不会被技术细节过多分散注意力。
如果你想要更严肃的 NLU,你可以将其运用到你的技能中
嗯,现在加入
来源: habr.com