# 🤖 TG 群管机器人 v2 — 重构规划 ## 📌 项目信息 | 项 | 值 | |----|-----| | 项目路径 | `/vol3/1000/Code/tg-spam-guard/` | | Git 仓库 | GitHub `ngfchl/tg-spam-guard` | | 运行环境 | Python 3.12 + Docker | | Web 框架 | FastAPI + uvicorn | | ORM | Tortoise ORM + aerich | | 数据库 | PostgreSQL (`192.168.123.5:15432`) | | Bot | python-telegram-bot ≥ 22 | | AI | Ollama (`qwen3:8b`) | | 知识库 | sentence-transformers + BGE-zh + numpy | | 前端 | Element UI 单页 | --- ## 🏗️ 项目结构 ``` tg-spam-guard/ ├── main.py # 入口:启动 FastAPI + Bot ├── config.py # 全局配置(从环境变量/配置文件读取) │ ├── db/ # 数据库层 │ ├── __init__.py # Tortoise 初始化 │ ├── models.py # 所有 ORM 模型 │ └── migrate.py # aerich 迁移配置 │ ├── handlers/ # Telegram 消息处理器 │ ├── __init__.py │ ├── welcome.py # 入群欢迎/退群告别 │ ├── verify.py # 入群验证 │ ├── spam.py # 垃圾检测+封禁 │ ├── night_mode.py # 夜间模式 │ ├── knowledge.py # /ask 知识库问答 │ ├── fun.py # 气氛组 + 小游戏 │ ├── bind.py # 账号绑定 │ └── admin.py # /ban /unban /warn /mute /kick /stats /purge │ ├── services/ # 业务逻辑层 │ ├── __init__.py │ ├── spam_detector.py # 多层垃圾检测引擎 │ ├── knowledge_base.py # RAG 检索(当前 knowledge/ 模块) │ ├── verify_service.py # 验证逻辑 │ ├── night_scheduler.py # APScheduler 定时任务 │ ├── game_service.py # 小游戏逻辑 │ └── bind_service.py # go-harvest-server verify 对接 │ ├── web/ # Web 管理面板 │ ├── api.py # FastAPI 路由 │ └── static/ │ └── index.html # Element UI 前端 │ ├── knowledge/ # 知识库(保持现有) │ ├── __init__.py │ ├── __main__.py │ ├── index/ │ └── models/ │ ├── templates/ # 消息模板 │ ├── welcome.md │ ├── verify.md │ └── night_mode.md │ ├── wheels/ # 本地 wheel 缓存(torch 等) ├── logs/ # 日志目录(运行时生成) │ ├── docker-compose.yaml ├── Dockerfile ├── requirements.txt ├── pyproject.toml ├── aerich.toml # aerich 迁移配置 ├── .env.example # 环境变量示例 └── .gitignore ``` --- ## 📦 数据库设计(PostgreSQL) ### 核心表 ```sql -- 消息记录 CREATE TABLE messages ( id BIGSERIAL PRIMARY KEY, msg_id BIGINT, chat_id BIGINT NOT NULL, user_id BIGINT NOT NULL, username VARCHAR(255), first_name VARCHAR(255), text TEXT, is_spam BOOLEAN DEFAULT FALSE, spam_reason VARCHAR(255), created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_messages_user_id ON messages(user_id); CREATE INDEX idx_messages_created_at ON messages(created_at); CREATE INDEX idx_messages_is_spam ON messages(is_spam); -- 封禁记录 CREATE TABLE bans ( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL, username VARCHAR(255), first_name VARCHAR(255), reason VARCHAR(500), method VARCHAR(50), -- 'auto' / 'command' / 'verify_fail' duration_minutes INTEGER, auto_unban BOOLEAN DEFAULT TRUE, unban_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_bans_user_id ON bans(user_id); -- 操作日志(入群/退群/删除/解封/警告等) CREATE TABLE actions ( id BIGSERIAL PRIMARY KEY, action VARCHAR(50) NOT NULL, -- JOIN/LEAVE/DELETE/UNBAN/WARN/MUTE/KICK user_id BIGINT, username VARCHAR(255), operator_id BIGINT, -- 执行操作的管理员 details JSONB, -- 扩展字段 created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_actions_action ON actions(action); CREATE INDEX idx_actions_created_at ON actions(created_at); -- 入队验证 CREATE TABLE verify_queue ( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL, username VARCHAR(255), question VARCHAR(500), answer VARCHAR(500), attempts INTEGER DEFAULT 0, status VARCHAR(20) DEFAULT 'pending', -- pending/verified/failed/expired created_at TIMESTAMPTZ DEFAULT NOW(), verified_at TIMESTAMPTZ ); CREATE INDEX idx_verify_user_id ON verify_queue(user_id); -- 账号绑定(TG ↔ Harvest) CREATE TABLE user_bindings ( id BIGSERIAL PRIMARY KEY, tg_user_id BIGINT UNIQUE NOT NULL, tg_username VARCHAR(255), harvest_uid VARCHAR(255), harvest_token VARCHAR(500), bound_at TIMESTAMPTZ DEFAULT NOW() ); -- 警告记录 CREATE TABLE warnings ( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL, username VARCHAR(255), reason VARCHAR(500), issued_by BIGINT, active BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_warnings_user_id ON warnings(user_id); CREATE INDEX idx_warnings_active ON warnings(active); -- 游戏积分 CREATE TABLE game_scores ( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL, username VARCHAR(255), game_type VARCHAR(50), score INTEGER DEFAULT 0, wins INTEGER DEFAULT 0, total INTEGER DEFAULT 0, streak INTEGER DEFAULT 0, last_played TIMESTAMPTZ, UNIQUE(user_id, game_type) ); -- 群组配置 CREATE TABLE group_config ( key VARCHAR(100) PRIMARY KEY, value JSONB, updated_at TIMESTAMPTZ DEFAULT NOW() ); ``` --- ## 📋 功能清单(去掉 PT 专属) | # | 模块 | 优先级 | 说明 | |---|------|--------|------| | 1 | 🛡️ 垃圾信息阻挡 | ✅ 已有 | 三级检测:缓存→正则→AI,保留优化 | | 2 | ⚡ 防刷屏 | 🔴 P0 | 令牌桶限速,超阈值删除多余消息 | | 3 | 🔒 新人限制 | 🔴 P0 | 入群 N 分钟内禁止发链接/图片/文件/贴纸 | | 4 | 👋 入群欢迎 | 🔴 P0 | 自定义欢迎卡片 + 群规 + 60s 自动删 | | 5 | ✅ 入群验证 | 🔴 P0 | 新人答题/点按钮,超时踢出 | | 6 | 🔗 账号绑定 | 🔴 P0 | TG ↔ Harvest 授权绑定 | | 7 | 🌙 夜间模式 | 🟡 P1 | 定时全员禁言,管理员不受影响 | | 8 | 🔨 管理工具 | 🟡 P1 | /warn /mute /kick /purge /slowmode /stats | | 9 | 📊 操作审计 | 🟡 P1 | 所有管理员操作记录到 DB | | 10 | 👥 退群告别 | 🟡 P1 | 可选,默认关闭 | | 11 | 📚 知识库问答 | ✅ 已有 | /ask + RAG,保持 | | 12 | 🎉 气氛组 | 🟢 P2 | 关键词触发表情、连击、撒花、里程碑 | | 13 | 🎮 小游戏 | 🟢 P2 | 答题/签到/积分排行/抽奖 | | 14 | 🎂 生日祝福 | 🟢 P3 | 记录生日,当天自动祝福 | --- ## 🔄 开发阶段 ### Phase 1:基建(SQLite→PG + 重构 + Git) - 初始化 Git 仓库 - 项目目录结构搭建 - config.py(环境变量管理) - db/(Tortoise ORM 模型 + aerich 初始化) - docker-compose.yaml(接入 PostgreSQL 网络) - requirements.txt / pyproject.toml 更新 - main.py 瘦身:只保留启动逻辑 ### Phase 2:核心安全(P0) - handlers/spam.py + services/spam_detector.py(从旧 main.py 提取) - handlers/admin.py(/ban /unban /warn /mute /kick /stats /purge) - 防刷屏中间件 - 新人限制(禁止链接/图片/文件) ### Phase 3:入群流程(P0) - handlers/welcome.py(入群欢迎/退群告别) - handlers/verify.py + services/verify_service.py(入群验证) - templates/(消息模板) ### Phase 4:账号绑定(P0) - handlers/bind.py + services/bind_service.py - 对接 go-harvest-server verify 接口 - /bind /unbind 命令 ### Phase 5:夜间模式 + 管理增强(P1) - handlers/night_mode.py + services/night_scheduler.py - APScheduler 集成 - 操作审计 ### Phase 6:社交 + 游戏(P2-P3) - handlers/fun.py + services/game_service.py - 气氛组(关键词触发、连击、撒花) - 小游戏(答题、签到、积分) - 生日祝福 ### Phase 7:Web 面板升级 - web/api.py(所有 API 路由) - web/static/index.html(适配新数据结构) - SSE 实时推送适配 --- ## ⚙️ 环境变量(.env) ```env # Telegram TG_BOT_TOKEN=your_telegram_bot_token TG_CHAT_ID=-1001515287526 # PostgreSQL DATABASE_URL=postgresql://user:password@192.168.123.5:15432/tg_spam_guard # Ollama OLLAMA_URL=http://127.0.0.1:11434 OLLAMA_MODEL=qwen3:8b # Proxy PROXY_URL=http://192.168.123.10:11055 # Web WEB_PORT=8766 SITE_URL=https://ptools.fun # Harvest HARVEST_SERVER_URL=https://ptools.fun ``` --- ## 📝 备忘 - 旧数据迁移:JSON → PostgreSQL(一次性脚本,放在 scripts/migrate_json_to_pg.py) - docker-compose 需要加入 `1panel-network` 网络 - aerich 配置写在 aerich.toml,用 `aerich init` / `aerich migrate` 管理 - wheels/ 目录保留(torch 等大包不走网络) - 知识库模块(knowledge/)保持独立,不改动 - 旧 main.py 备份为 main.py.bak