Alisa V Zadzerkalli
C++

Alisa V Zadzerkalli

Alisa v Zadzerkalli - 一个用C++编写的Discord机器人

GitHub|
image

Alisa v Zadzerkalli (乌克兰语) - 爱丽丝镜中奇遇记。镜子的另一侧世界,你刻意前往,那里的一切都是颠倒、反向、错乱的。

«Ніколи не вгадаєш, ким станеш за хвилину.»
“你永远无法猜到一分钟后的自己会变成什么样。”——爱丽丝,《爱丽丝梦游仙境》,瓦伦丁·科尔尼延科译,伊万·马尔科维奇编,第53页。

一个用C++编写的Discord机器人。

功能

斜杠命令

  • /ping - 与网关的往返延迟
  • /leaderboard - Clube de Programação (UFFS) 排行榜,从俱乐部的vjudge小组抓取,按解题数排名

对话

提及她,或在消息中说alisa或obliterator,她就会回应。回复并非本地生成。爱丽丝会整合上下文,由Providence负责思考。

她每次在消息中提供给模型的内容:

  • 每位俱乐部成员,按排行榜顺序排列,包含其用户名、解题数和最后活跃时间
  • 每位成员已解决问题的完整列表,按评测平台分类
  • 整个俱乐部中解题次数最多的十个问题

正是这些上下文让她能够回答那些没有人为其编写命令的问题。谁位列前三,他们有哪些共同解决的问题,谁已经沉寂了。模型提供推理,抓取提供事实。

俱乐部数据

成员状态在启动时由八个工作线程组成的有限线程池从vjudge拉取,每个线程为其负责的小组部分持有一个连接。每位成员消耗两次请求,一次用于获取计数和排名的个人资料页,一次用于获取问题列表的解题详情端点。

布局

  • main.cpp - 入口点
  • src/commands/ - 斜杠命令和调度器
  • src/members/ - 俱乐部名册、个人资料和解题列表抓取
  • src/parser/ - 基于lexbor的HTML查询
  • src/network/ - 支持连接复用的HTTP
  • src/speech/ - Providence连接和提示词组装
  • src/onmessage/、src/onready/ - 网关事件处理器
  • src/embeds/ - 内置嵌入消息
  • src/config/ - 集群设置和共享机器人状态

回复如何发生

消息处理器在机器人可见的每个频道的每条消息上唤醒。它过滤掉机器人的消息,过滤掉所有未通过提及或alisa、obliterator字样提及她的消息,目前还会过滤掉除一个作者外的所有作者,该ID硬编码在src/onmessage中。任何通过过滤的消息都会立即收到一条显示“思考中...”的嵌入消息,在询问模型之前发布,这样即使答案很慢,频道也能看到她已接收问题。

答案本身是对位于http://127.0.0.1:8931的Providence的/speech/deepthink/端点的POST请求,携带消息、整个俱乐部上下文以及Discord用户名作为调用者身份。它最多等待200秒。回复在UTF-8字符边界上被截断为1990字节,这样截断永远不会落在码点中间,然后占位嵌入消息会被就地编辑。超时、拒绝或无法解析的响应体都会以文本形式出现在同一嵌入消息中,而不是保持沉默。

Providence是一个独立服务,不在此仓库中。如果该端口上没有运行它,机器人仍然可以启动,仍然可以响应斜杠命令,仍然可以抓取俱乐部数据,只是不再思考。

Providence提供了什么

爱丽丝发送light true,这是廉价路径,一个推理节点,无分支。去掉该标志,同一端点将运行有界思维树,深度为二,每个节点至少有两个带标签的分支,每个分支根据成功概率以及它增加或破坏的潜力进行评分,每个节点由作为子进程生成的原生思考者生成。这套机制在她发送的每条消息上都闲置未用。

它还自行决定问题是否需要的不仅仅是对话。如果需要,分类器会将消息映射到一个命令及其参数,执行该命令,并将结果整合到最终答案中。当前列表上的内容:

  • 绘图,根据你用语言描述的函数绘制2D曲线或3D曲面
  • 代数,化简、展开、因式分解、求解变量
  • 微积分,导数、定积分和不定积分、极限
  • 矩阵,行列式、逆矩阵、特征值
  • 将任何表达式渲染为LaTeX
  • UFFS SIGAA门户,当前课程、日程、即将到来的作业
  • UFFS餐厅,哪些餐次开放预订以及过去的情况如何,通过真实的无头浏览器使用其自己的凭据驱动

这些答案中的每一个都携带结构化字段,而不仅仅是散文。绘图或LaTeX渲染以base64 PNG形式返回在image下,门户读取以JSON形式返回在data下,模型自己的评论则并列在response下。爱丽丝读取response并丢弃其余部分,因此今天产生图表的提问到达Discord时只是一句关于没人能看到的图表的句子。将图像作为附件发送是这个机器人接下来应该学会的显而易见的事情。

访问权限按调用者而非机器人进行控制。她将自己标识为discord以及作者的用户名,Providence会查找该配对并拒绝任何它不认识的人,这就是她逐字打印的拒绝信息。添加俱乐部成员意味着在那里添加,而不是在这里。

构建

需要C++20编译器、CMake 3.16或更新版本,以及三个库:用于网关的DPP、用于HTTP的cpr、用于HTML的lexbor。在Arch上,Makefile通过yay或paru安装缺失的库。在其他任何地方,请先自行安装它们。

make deps      如果不存在则获取DPP、cpr和lexbor
make           配置并构建到build/
make run       加载.env,然后运行二进制文件
make rebuild   清除build/并重新开始

构建中有两件事是刻意的。默认构建类型是RelWithDebInfo,并行编译作业数上限为二。DPP的头文件模板密集程度足以让未优化的构建每个编译器进程消耗数GB内存,而每个核心一个进程会拖垮机器。当你有足够内存时,可以增加,使用make JOBS=8。

源文件使用CONFIGURE_DEPENDS进行通配符匹配,因此src/下的新文件会在下次构建时被拾取,无需修改CMakeLists。

配置

机器人从环境变量中读取DISCORD_TOKEN,仅此而已。将其放在仓库根目录的.env中,make run会为你导出它,或者你自己导出并直接运行build/alisa-v-zadzerkalli_core。她使用默认意图加上消息内容连接,这是一个特权意图,因此请在Discord开发者门户中为应用程序启用它,否则消息处理器将只能看到空字符串。

Providence的密钥与它一起放在.env中,供套接字另一端的服务使用。此二进制文件从不读取它们。