IamMrCupp/annoybots
GitHub: IamMrCupp/annoybots
一个基于 Go 的现代化多平台聊天机器人框架,可在 Kubernetes 上以单一二进制同时运行多个具备 Markov 学习能力和跨平台协作功能的个性机器人。
Stars: 1 | Forks: 0
# annoybots
一个用于聊天“捣乱”机器人的框架 —— 它是经典 [BMotion](http://bmotion.sourceforge.net/) IRC 机器人的现代化、容器化继任者,使用 Go 重写并专为 Kubernetes 打造。
一个小巧的 Go 二进制文件可以同时维持许多聊天连接(IRC 网络、Twitch 和 Discord),并通过一个共享的“捣乱引擎”路由每个频道。**每个机器人都是带有不同个性文件的同一个二进制程序**,因此你可以随心所欲地运行任意数量的机器人 —— 每个机器人都有自己的名称、触发器和语气。本仓库内置了两个示例个性,**Echo** 和 **Mimic**,供你参考复制。
## 它的功能
- **关键词/正则表达式触发器** → 随机化、模板化的响应(`{nick}`、`{me}`、`{chan}`、捕获组)。
- **环境插话** —— 随机的主动发言,具有每个频道独立的冷却时间。
- **语录包** —— 插入即用的 `.txt` 文件,可通过随机方式和 `!quote [pack]` 呈现;`!packs` 会列出可用内容(与 Discord 上的 `/quote`、`/packs` 斜杠命令相同)。
- **一个会学习的“大脑”** —— 一个 N 阶 Markov 链,从频道闲聊中学习并将其以扭曲的方式复述出来。它会将状态持久化到磁盘,因此重启后学习成果依然保留(就像大家都记得的 BMotion 胡言乱语功能,但去掉了被遗弃的 TCL 技术栈)。
- **单进程多网络** —— IRC + Twitch 共享相同的通信协议;Twitch 只需要 CAP 协商、一个 `oauth:` token 和更严格的速率限制,这些都已自动处理。Discord 也依托于同一个引擎并行运行。
- **多个机器人,一个二进制程序** —— 个性是配置而非代码,因此新机器人就是一个新的 YAML 文件(和一个 pod),绝不需要 fork 代码库。
## 目录结构
```
cmd/annoybot entrypoint
internal/engine annoyance engine (triggers, interjections, quotes, commands)
internal/markov persistent Markov "brain"
internal/bot transport router (fans replies back to the right platform)
internal/botnet inter-bot bus (Redis pub/sub) + skit coordinator
internal/irc IRC/Twitch transport (ergochat/irc-go) + per-network rate limiting
internal/discord Discord transport (bwmarrin/discordgo) + slash commands
internal/ratelimit token-bucket limiter (Twitch-aware)
internal/cooldown per-channel cooldown tracking
internal/config YAML config loading, validation, quote-pack loading
internal/health /healthz + /readyz for Kubernetes probes
configs/ echo.yaml, mimic.yaml — example personalities (+ networks)
data/quotes/ starter quote packs
data/skits.yaml shared multi-bot skit scripts
deploy/k8s/ kustomize base + per-bot overlays
```
## 本地运行
```
# 首先导出您的 config 引用的 secrets,例如:
export ECHO_LIBERA_SASL=... # NickServ/SASL password
export ECHO_TWITCH_TOKEN=oauth:... # Twitch chat token
make run-echo # or run-mimic
# 任意 config: go run ./cmd/annoybot -config configs/yourbot.yaml
```
语录包文件解析时相对于 `ANNOYBOT_QUOTES_DIR` 路径(Makefile 将其指向 `data/quotes`)。
## 配置
所有行为配置都位于 `configs/.yaml` 中:网络、触发器、插话/语录频率及冷却时间,以及 Markov 设置。**密钥绝不存储在配置中** —— 每个 `*_env` 字段指定了一个环境变量(从 Kubernetes Secret 中填充),该变量持有实际的 token 或密码。
你可以从 `configs/echo.yaml` 或 `configs/mimic.yaml` 开始;这两个文件都演练了所有功能和全部三个平台。
### 添加机器人
一个机器人仅仅是指向不同配置的同一个二进制程序,因此添加机器人纯粹是增量操作 —— 无需修改代码:
1. **复制示例配置。** `cp configs/echo.yaml configs/jeeves.yaml`,然后设置 `bot: jeeves` 和 `personality.name: "Jeeves"`,并根据喜好编辑网络、触发器、戏谑互动和语录包。
2. **命名其密钥。** 每个 `*_env` 字段都指定了一个环境变量。对于 Kubernetes,将它们收集到一个名为 `jeeves-bot-secrets` 的 Secret 中(参见 [部署](#deploy))。
3. **将其介绍给其他机器人。** 将 `"Jeeves"` 添加到其他所有机器人的 `personality.siblings` 中,并可选择在 `data/skits.yaml` 中为它添加台词(短剧步骤通过 `bot:` 的值进行匹配,例如 `bot: jeeves`)。
4. **部署它。** 将 `deploy/k8s/overlays/echo/` 复制到 `…/jeeves/`:将 `bot-config` 生成器指向 `configs/jeeves.yaml`,并将 secretRef 补丁指向 `jeeves-bot-secrets`。添加一个 Flux `Kustomization`(复制 `deploy/k8s/flux/kustomizations.yaml` 中的一个块)。
引擎、botnet 总线和管理控制台对于任意数量的机器人运作方式完全相同。
### Twitch
在网络配置中设置 `kind: twitch`,并将 `password_env` 指向持有聊天 oauth token 的环境变量。服务器、TLS、CAP 和保守的速率限制会自动使用默认配置。请注意,Twitch 无法可靠地广播加入/退出或模式更改,因此我们特意不依赖它来进行用户/管理员跟踪。
### Discord
在网络配置中设置 `kind: discord`,并将 `password_env` 指向持有 **bot token** 的环境变量(不需要昵称/服务器)。然后:
1. 在 [Discord 开发者门户](https://discord.com/developers/applications) 中,创建一个应用程序和机器人,并在 Bot → Privileged Gateway Intents 下**启用特权 MESSAGE CONTENT intent**。如果没有它,机器人可以连接,但每条消息的正文都会是空的。
2. 使用包含 `bot` 和 `applications.commands` scope 的 OAuth2 URL 邀请机器人加入你的服务器。
3. 在 `guilds:` 下列出你的服务器 ID,以实现即时的 `/quote` 和 `/annoy` 斜杠命令(全局注册也可以,但最多可能需要一个小时才会显示)。
`channels` 是频道 ID 的可选白名单;为空意味着机器人会在它能看到的所有地方进行回复。Discord 自身的 HTTP 速率限制由客户端库处理,因此 token bucket 限制器仅适用于 IRC/Twitch。相同的触发器、语录包和 Markov 大脑在 Discord 上运行无需更改;IRC 的 `/me` 动作会以斜体显示。
## 机器人之间的交互(“botnet”)
就像过去 BMotion 用来协调恶作剧的老式 eggdrop botnet 一样,这些机器人可以相互交谈 —— 但是安全的。
**戏谑互动(串扰)。** 每个机器人都在 `siblings` 中列出了其他机器人。同级机器人的消息*只能*产生有上限的戏谑互动 —— 绝不会触发普通触发器 —— 因此机器人绝不会相互触发而陷入死循环洪水。戏谑互动有双重限制:每个频道的冷却时间*以及*“每个滚动窗口的最大回复数”硬性上限。
**短剧。** 多机器人脚本片段位于一个共享的 `data/skits.yaml` 文件中,由每个同级机器人加载。它们通过 Redis pub/sub 总线进行协调,因此即使机器人在不同的平台上,短剧也能运行。“主导”机器人(第一句台词的拥有者)发起短剧 —— 通过在共享频道中使用 `!skit `,或者通过每个短剧的 `chance` 随机触发 —— 然后机器人步调一致地执行各自的台词,受限于步骤数和每个频道的冷却时间。你可以通过编辑 `data/skits.yaml` 来添加自己的短剧(每个步骤的 `bot:` 必须与机器人的 `bot:` 配置值相匹配)。
在每个机器人的配置中使用 `botnet:` 块启用此功能(所有机器人必须共享同一个 `channel`)。只需部署一次共享总线:
```
kubectl apply -k deploy/k8s/redis
```
该总线仅传输临时的协调消息,因此 Redis 在运行时不进行持久化。
## 管理控制台(聊天)
向机器人发送私信以运行管理命令。管理员通过**已验证的身份**进行匹配 —— IRC services/NickServ 账户、Discord 用户 ID 或 Twitch 登录名 —— 绝不使用可伪造的昵称,并且命令仅在私信中生效。在每个机器人的配置中的 `admin:` 块中配置管理员。
命令(发送 `!help` 获取列表):
- `!join <#chan>` / `!part <#chan>` —— 频道操作
- `!invite <#chan> ` —— IRC INVITE(机器人在 `+i` 频道需要拥有权限)
- `!say ` / `!act ` —— 操控机器人发言
- `!addquote ` / `!delquote ` —— 运行时语录编辑
- `!addadmin ` / `!deladmin ` / `!admins`
- `!reload` —— 从磁盘重新读取语录包文件和短剧文件,无需重启(网络连接和个性触发器仍需重启)
语录和管理员的更改会持久化到数据卷,并**通过 botnet 总线同步到同级机器人**,因此你只需给其中一个发送私信即可。频道控制和发言操控仅限于你发送私信的那个机器人。(`!delquote` 仅删除运行时添加的语录;文件包中的语录是不可变的 —— 需编辑 `.txt` 文件才能修改它们。)
**密码回退机制。** 身份验证是首要的,但如果网络没有 services(或者有人就是没有登录),请设置 `password_env`,管理员可以在私信中 `!login ` 以获得有时限的会话(使用 `!logout` 结束它)。
注意:在没有 services 的情况下,此会话以**昵称**为键,这是可伪造的,因此它比基于账户的身份验证要弱 —— 这是在 services 不可用时提供的一种便利手段,并带有恒定时间密码检查、失败尝试限制和可配置的 `session_ttl`。将 `password_env` 留空未设置即可禁用此功能。
## 部署
这是为 **GitOps with Flux** 量身定制的:Conventional Commits → `release-please` 发布 semver 版本 → CI 构建镜像 → Flux 的 semver `ImagePolicy` 将其滚动发布。密钥**默认手动应用**(Git 中的 SOPS 加密密钥是可选的);语录/短剧内容通过 ConfigMaps 提供,因此编辑后可通过 `!reload` 生效。有关完整的接线配置(Kustomizations、镜像自动化和可选的 SOPS/age 设置),请参见 [`deploy/k8s/flux/README.md`](deploy/k8s/flux/README.md)。
每个机器人部署为单副本的 StatefulSet,并拥有自己的 PVC 用于存储 Markov 大脑;Redis(即 botnet 总线)从 `deploy/k8s/redis` 部署一次。
### 手动应用(不使用 Flux)
```
kubectl create namespace annoybots
# 手动应用每个 bot 的 Secret —— 密钥列在
# deploy/k8s/overlays//secret.example.yaml 中。省略某个密钥即可禁用相应的 network:
kubectl -n annoybots create secret generic echo-bot-secrets \
--from-literal=ECHO_TWITCH_TOKEN='...' --from-literal=ECHO_DISCORD_TOKEN='...'
kubectl -n annoybots create secret generic mimic-bot-secrets \
--from-literal=MIMIC_TWITCH_TOKEN='...' --from-literal=MIMIC_DISCORD_TOKEN='...'
kubectl apply -k deploy/k8s/redis
kubectl kustomize --load-restrictor LoadRestrictionsNone deploy/k8s/overlays/echo | kubectl apply -n annoybots -f -
kubectl kustomize --load-restrictor LoadRestrictionsNone deploy/k8s/overlays/mimic | kubectl apply -n annoybots -f -
```
## 添加语录
在 `data/quotes/` 中放入一个 `whatever.txt`(每行一条语录,允许使用 `#` 注释),在机器人的 `personality.quotes.packs` 中引用它,并将其列在 overlay 的 `bot-quotes` `configMapGenerator` 中。使用 Flux 时,提交它并运行 `!reload`;否则重新构建镜像(语录包也会作为回退方案内置在 `/quotes` 中)。
## 开发
```
make test # go test ./...
make lint # golangci-lint
make docker # build the image
```
标签:EVTX分析, Go, IRC, Redis, Ruby工具, 子域名突变, 搜索引擎查询, 日志审计, 网络调试, 自动化, 请求拦截