# qqbot **Repository Path**: luo_sang/qqbot ## Basic Information - **Project Name**: qqbot - **Description**: deepseek接入QQ - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-26 - **Last Updated**: 2026-10-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 大肥鱼 · DeepSeek × QQ 机器人 > 文档版本:**v1.10**(2026-10-28) > > 📋 完整功能、配置项、默认值、测试覆盖和已知限制见 **[功能清单.md](功能清单.md)**。 > 当前部署:Ubuntu 24.04 云服务器,协议端使用 SnowLuma(Docker),`bot.py` 由 systemd 常驻。 把 DeepSeek 接进 QQ:群里 @ 它就聊,私聊直接说话;能收语音、能发语音、能看懂图片和表情包, 还带心情、人物卡、作息和防复读。 ## 版本历史 | 版本 | 日期 | 新增功能 | |---|---|---| | **v1.0** | 2026-10-24 | QQ 接入、DeepSeek 对话、语音收发、图片收发、表情包、主动消息、群聊 smart 模式、主人识别与底线守卫 | | **v1.1** | 2026-10-25 | 心情状态机、人物卡(好感/熟悉度)、防复读、时间感知与作息、早晚问候 | | **v1.2** | 2026-10-26 | DeepSeek flash 视觉、图片下载重试、DeepSeek Search/Fetch、SnowLuma 协议端、掉线看门狗、固定形象 | | **v1.3** | 2026-10-27 | 视频生成(7–15 秒竖屏,人声+BGM)、白名单群每天 2–4 条、上午/下午各至少一条、标题+内容、敏感内容过滤;不再接外部平台发布 | | **v1.4** | 2026-10-27 | 修「群里 @ 别人被当成在叫自己」:@ 对象记进群聊上下文,@ 别人(含 @全体成员)默认不接话 | | **v1.5** | 2026-10-27 | 收藏表情包前先用视觉模型判断内容:聊天截图/生活照这类不收,判不出也不收 | | **v1.6** | 2026-10-27 | 长期记忆:缓冲 + 睡眠整理 + 按关联/权重检索,聊天里说「清空记忆」不会真清 | | **v1.7** | 2026-10-27 | 人物卡与长期记忆合并成「人物记忆体」,一个文件、一次提炼;删除/记忆清空这个功能整个去掉(连主人也没有) | | **v1.8** | 2026-10-28 | 作息改成像人一样不规律:随机熬夜/早睡、晚起/早起,周末再往后挪;`/rhythm 今晚 熬夜` 可指定 | | **v1.9** | 2026-10-28 | 场景图:她自己的状态图(打盹/困/开心…),按情境自动配;一次性生成整套,角色统一 | | **v1.10** | 2026-10-28 | 手机远程扫码:Tailscale + `tailscale serve`,扫码邮件里直接带链接 | ``` QQ 小号 ── SnowLuma(Docker,OneBot 11)── ws://127.0.0.1:3001 ──▶ bot.py ├─▶ DeepSeek chat 聊天 ├─▶ DeepSeek flash 看图 ├─▶ faster-whisper 语音转文字 └─▶ edge-tts + silk 文字转语音 ``` ## 现在能做什么 - **聊天**:私聊直接回;群里 smart 模式,判断该不该接话 - **语音**:收到语音转文字;被要求时用语音回 - **图片**:DeepSeek flash 看图,识人、读字、接梗;下载失败会重试并刷新链接 - **固定形象**:蓝发女仆、头顶大锅;问她长什么样会发自己的照片 - **视频生成**:每个白名单群每天 2–4 条 7–15 秒竖屏视频 - **表情包**:内置图库 + 自动收藏群友的图 - **心情状态机**:心情 / 精力 / 耐心三个旋钮,会随时间平复,低落有下限 - **人物卡**:按 QQ 号一人一张,记好感、熟悉度、外号、标签、上次聊到的事,还会记谁常熬夜 - **时间感知与作息**:知道现在几点、周几、隔了多久;07:00 起、23:30 睡,睡着会困 - **防复读**:刚说完不追话、30 分钟内相似内容不发、主动消息不续自己的话题 - **多群并行**:每个群独立上下文/冷却,互不串台 - **联网搜索**:需要查资料时走 DeepSeek Search/Fetch,可回退 Bing - **底线守卫**:索要 Key、改配置、换角色,代码直接拒绝,不进模型 ## 目录说明 | 路径 | 作用 | | --- | --- | | `bot.py` | 机器人主程序 | | `config.json` | 配置(API Key、群白名单、心情/记忆体/作息/场景图等),**不进 Git**;本地和服务器各一份,用 `tools/diff_config.py` 对比 | | `assets/poses/` | 她的场景图 + `poses.json`(固定角色与场景提示词),图片按需生成,可不进 Git | | `data/state.json` | 心情、群上下文、最近会话,**运行时数据,不进 Git** | | `data/people.json` | 人物卡,**运行时数据,不进 Git** | | `data/media/` | 收到的图片、语音转码文件 | | `assets/dafeiyu.jpg` | 大肥鱼的固定形象照片,发 [[selfie]] 时使用 | | `assets/bgm/soft.mp3` | 视频生成用的原创合成 BGM | | `data/douyin.json` | 视频生成发送记录,**运行时数据,不进 Git** | | `data/douyin/` | 生成的封面、配音、视频 | | `memes/` | 表情包库(内置 + `收集/`) | | `logs/bot.log` | 运行日志 | | `tools/` | 测试与探测脚本 | | `requirements.txt` | Python 依赖 | | `deploy/snowluma-compose.yml` | SnowLuma 容器编排(唯一协议端) | > `config.json` 不在 Git 里,本地和服务器天然是两份,**不要求一致**。要确认差异: > > ```bash > python tools/diff_config.py # 你的配置 vs 代码默认值 > python tools/diff_config.py config.json config.server.json # 本地 vs 服务器(先把服务器那份 scp 下来) > ``` > > 缺的键会走代码默认值,所以**功能不会缺**;但默认值和你在本地调过的值可能不同(例如 `history_turns`)。 > **别整份覆盖**:Key、`onebot.access_token`、`owner.qq`、`group_whitelist` 两边通常不一样,只补你真正需要的键。 | `deploy/install-snowluma.sh` | 一键创建目录、生成密码、停 NapCat、启动 SnowLuma | | `启动NapCat.bat` / `启动机器人.bat` | 旧 Windows 本地启动文件,已不再维护 | ## 服务器部署(当前方式) ### 1. 前置 - Ubuntu 24.04,2C4G 起,装好 Docker、Docker Compose 插件、Python 3.12 - `git clone` 代码到 `/opt/qqbot` - `config.json`、`data/state.json`、`data/people.json` 单独 `scp` 上去(不在 Git 里) - 建议 2GB swap;时区设为 `Asia/Shanghai` ### 2. 协议端:SnowLuma(唯一) ```bash cd /opt/qqbot # 创建 /opt/snowluma/{data,config,share}、生成 VNC 密码、 # 停掉旧的 napcat 容器(如果还在)、启动 SnowLuma bash deploy/install-snowluma.sh ``` 脚本会输出: - noVNC:`http://127.0.0.1:6081/`,密码在 `/opt/snowluma/.env` - WebUI:`http://127.0.0.1:5099/` 本地 Windows 开隧道: ```powershell ssh -L 6081:127.0.0.1:6081 -L 5099:127.0.0.1:5099 root@服务器IP ``` 1. `http://127.0.0.1:6081/` 打开远程桌面,用 QQ 小号扫码登录; 2. `http://127.0.0.1:5099/` 打开 SnowLuma WebUI,用日志里的临时密码登录; 3. 在 WebUI 里把 OneBot WebSocket 设为 `0.0.0.0:3001`、格式 `array`、 Token 与 `config.json` 的 `onebot.access_token` 一致; 4. 保存后,`config.json` 的 `ws_url` 保持 `ws://127.0.0.1:3001` 不变。 详细步骤、排障和清理 NapCat 见 **[deploy/README-SnowLuma.md](deploy/README-SnowLuma.md)**。 ### 3. 机器人 ```bash cd /opt/qqbot python3 -m venv .venv .venv/bin/pip install -r requirements.txt .venv/bin/python bot.py --selftest ``` 自检三项通过后,用 systemd 常驻: ```ini [Unit] Description=DaFeiYu QQ Bot After=network-online.target docker.service Wants=network-online.target [Service] WorkingDirectory=/opt/qqbot ExecStart=/opt/qqbot/.venv/bin/python bot.py Restart=always RestartSec=5 Environment=PYTHONUNBUFFERED=1 Environment=PYTHONIOENCODING=utf-8 [Install] WantedBy=multi-user.target ``` ```bash systemctl daemon-reload systemctl enable --now qqbot journalctl -u qqbot -f ``` ### 4. 运维 - 日志轮转:`/etc/logrotate.d/qqbot`(按天、保留 7 天、`copytruncate`) - 媒体清理:每天删 `data/media` 里 7 天前的文件 - 备份:每天打包 `config.json`、`data/state.json`、`data/people.json`、`memes/`,保留 7 天 - 更新:`cd /opt/qqbot && git pull && systemctl restart qqbot` - **不要**用本地 `data/` 覆盖服务器上的 `data/`(服务器是主副本) ### 5. 掉线监控 `tools/watchdog.py` + systemd timer,每 10 分钟检查 QQ 是否在线: - 离线时自动重启 SnowLuma,最多 3 次、间隔 3 分钟; - 仍失败进入 `NEED_SCAN`,只发 QQ 邮箱提醒,不再重启; - 恢复后自动重启 qqbot 并再发一封恢复邮件。 QQ 掉线必须人工扫码,看门狗只负责“发现 + 尝试重启 + 邮件通知”。 扫码可以完全在手机上完成,见 **[deploy/README-remote-scan.md](deploy/README-remote-scan.md)**(Tailscale + `tailscale serve` + QQ 扫一扫相册)。 配置和安装见 **[deploy/README-watchdog.md](deploy/README-watchdog.md)**。 ## 旧 NapCat 本地启动(已弃用) 仓库里还留着 `启动NapCat.bat` 等旧文件,但不再维护。现在统一使用 **SnowLuma**: 服务器按上面的 Docker 方式跑,本地调试也用 SnowLuma 的 noVNC/WebUI。 ## 人格与底线 人格写在 `config.json` 的 `deepseek.system_prompt`,核心是「温和但不软、敢吐槽、不懂就说不懂」。 固定形象:蓝发、女仆装、头顶一口大锅,锅平时用来盛大米饭。代码会在系统提示词末尾 追加这段设定;有人问长相/要照片时,模型输出 `[[selfie]]`,机器人发送 `assets/dafeiyu.jpg`。不会提 token/API/模型这些词。 底线有两层: 1. 提示词里规定不透露配置/凭据、不换角色; 2. 代码硬拦截(`_guard_reply`):命中「索要 Key / 改配置 / 换角色」直接回复,**根本不进模型**。 主人靠 QQ 号识别(`owner.qq`),只有主人会被叫「主人」,对主人永远温柔、不顶嘴。 ## 心情状态机 全局一份心情,跨群、跨私聊共享。 | 旋钮 | 范围 | 说明 | | --- | --- | --- | | 心情 valence | 0–100 | 好不好 | | 精力 energy | 0–100 | 按 24 小时曲线走,凌晨低、晚上高 | | 耐心 patience | 0–100 | 被怼会掉,决定说话长短 | - 每条消息由模型判断:被夸 +3、被怼 -2、被安慰 +2、被认真对待 +1、被无视 -1 - 单次最多推动 ±12,**时间会让坏心情平复** - 连续低落超过 30 分钟强行拉回底线,不许 emo 到消失 - 主人加成 1.4,但对主人的好感不受影响 - `/mood` 查看,`/mood set valence=30 patience=20` 手动调试 ## 人物记忆体(关系 + 长期记忆) v1.7 起,原来的「人物卡」和「长期记忆」合并成**同一个人一条记录**(`data/people.json` v2): 既记"怎么称呼、多熟、这次说几句",也记"他是什么人、经历过什么"。一次提炼同时更新两边, 回复时只注入一段,不会出现两套数据打架。 按 QQ 号一人一份,群聊私聊共用。**只有说过话的人才会建档**。 **关系** - **好感 closeness**:对方这人好不好。新人 50 起,不预设恶意;主人恒 100;长期不说话每天 -1,最低 30 - **熟悉度 familiarity**:聊没聊熟。每条消息 +1,0–19 陌生 / 20–49 认识 / 50–79 熟 / 80+ 很熟 - 熟悉度决定:叫「你」还是外号、说几句、敢不敢吐槽、要不要主动 @ - 记录 22:00–06:00 的发言时段,`/card` 能看到「常熬夜:凌晨1点(N 次)」 **长期事实**(参考 [long_memory](https://github.com/ZhejiangF/long_memory) 的思路) - **攒够再整理**:每句原话和它的回话先进缓冲,攒够 6 条才调一次模型(关系和事实一起出) - **只记长期事实**:住处/工作/爱好/宠物/家人朋友/雷区/计划/答应过的事;情绪、天气、寒暄、提问本身不记 - **同一件事不记两遍**:相似到 0.72 就合并,权重 +0.3,保留更完整的说法 - **回复时检索**:按这一句挑最多 6 条塞进提示词;完全对不上就只带权重最高的几条,不至于像失忆 - **会变淡但不会消失**:长期没人用的事实权重按 120 天半衰期衰减,只降排位 - **没有清空功能**:聊天里说「把记忆清空」只回一句话不执行;主人也没有这条指令。 要纠正某条就 `/记忆删 <编号>`,整片抹掉的口子不留(防误触,也防被人用话术洗掉) **指令** - `/card` 看自己(关系 + 最近几条事实),`/card ` 主人看别人,`/card set closeness=… familiarity=… alias=… tags=…` - `/记忆` 看全部事实,`/记忆 ` 主人看别人,`/记忆删 <编号>` 删掉记错的一条 **迁移**:旧 `people.json`(v1)和 `memory.json` 会在首次启动时自动并成一个 v2 文件, 旧文件留 `.v1.bak` / `.merged.bak`;合并后 `memory.json` 不再使用。 重启前想确认不会丢数据,可以先跑(只读,不动原文件): ```bash python tools/check_person_migration.py data/people.json ``` ## 时间感知与作息 - 每条提示词都带 `[现在] 2026-10-26 周一 21:40(晚上)` - 隔了 2 小时以上会提一句「隔了多久没聊」 - **作息像人一样不规律**:不再死守 23:30 睡 / 07:00 起。每天按概率抽一个「今晚」和「明早」: - 多数时候正常(±20 分钟浮动) - 约 28% 概率**熬夜**(晚睡 35–150 分钟),第二天大概率**晚起** - 约 17% 概率**早睡**(早 20–75 分钟),第二天有一定概率**早起** - 周末整体再往后挪一点 - 上床夹在 21:00–03:30、起床夹在 05:00–12:30,至少睡 4 小时 - 同一天的作息是确定的(日期 + 盐做随机种子),重启不会变卦,隔天自然换一批 - 提示词会说清"现在":刚醒 / 准备睡 / 熬夜后的第二天有点没精神 / 早睡早起今天精神不错 - 睡前 30 分钟进入「准备睡了」,说话收着 - **睡着被叫**:默认 soft(回一句带困意)/ wake(正常回但抱怨被吵醒);同一会话超过 10 句可以不回 - 睡着时不主动发消息、不插话;没人接话也不记「被冷落」 - 每天起床后 3 小时内、睡前 45 分钟,各群主动说一次早安/晚安(时间跟着当天作息走) - `/time` 看时间;主人 `/rhythm` 看她今天的实际作息和最近 5 天、`/rhythm 今晚 熬夜` 指定今晚、`/rhythm 规律` / `/rhythm 随机` 切换、`/rhythm set sleep=00:30 wake=07:00` 临时固定、`/rhythm reset` 清掉临时设定 ## 防复读 - 群里说完一句后 **20 秒内**不再补一句 - 提示词带「你刚刚已经说过」,要求别换说法重复 - 30 分钟内高度相似的句子:插话/主动消息直接不发;被直接问到时让模型重写一次 - 主动消息:上一条是自己说的、还没人接,就不续这个话题 ## 群聊 默认 `smart` 模式:读最近 20 条 / 15 分钟群聊,判断 REPLY / CHIME / SKIP。 | 配置 | 默认 | 说明 | | --- | --- | --- | | `chat.group_mode` | `smart` | `smart` / `at_only` / `all` | | `chat.group_reply_probability` | 0.25 | 普通消息插话概率 | | `chat.group_cooldown_seconds` | 120 | 两次接话最小间隔 | | `chat.group_self_gap_seconds` | 20 | 自己说完多久内不补话 | | `chat.group_context_size` | 20 | 参考多少条群聊 | | `chat.group_context_minutes` | 15 | 只参考最近多少分钟 | | `chat.group_whitelist` | 两个群 | 留空表示所有群 | | `chat.ignore_at_others` | true | 别人被 @ 的消息不接话 | 被 @、引用回复、叫名字、带前缀,都算在跟它说话,必回。 **@ 别人不等于 @ 它**:每条消息 @ 了谁都会记进群聊上下文(显示成 `@昵称`), 所以「@小明 你今晚有空吗」不会被它当成在问自己;默认这条消息它完全不接话 (`chat.ignore_at_others = false` 才会走 smart 判断)。@全体成员同理,不接。 ## 图片 DeepSeek 的 `deepseek-flash` 支持图片,但项目走的是「独立视觉调用」: 1. 收到图片 → `vision` 配置的模型生成一句中文描述; 2. 描述作为上下文交给聊天模型。 当前 `vision.model` 是 `deepseek-flash`,一张图约 5–10 秒(它是推理模型)。 下载失败时会带浏览器头重试,并用 `get_msg` 刷新过期链接;仍失败会回「图片没加载出来」,不影响文字聊天。 任何 OpenAI 兼容视觉模型都能换,只改 `vision.base_url` / `model` / `api_key`。 ## 语音 - **收语音**:faster-whisper `small` + int8,纯 CPU,约 1–3 秒/句 - **发语音**:edge-tts 生成音频 → ffmpeg 转 PCM → pysilk 编码成 QQ silk - 说「用语音回答」或发语音过来,它就回语音 - 首次使用会下载 whisper 模型(约 500MB),之后不用再下 ## 表情包 - `memes/` 内置几十张,按分类和关键词挑 - 群友发表情包有 15% 概率被收藏到 `memes/收集/` - **收藏前先看图判断**:只有真表情包/梗图才收;聊天截图、网页/文档截图、商品图、风景照、生活照、二维码这类不收,模型判不出也不收(`memes.check_content`,默认开) - 发表情包时 50% 概率优先用收藏的图 - 想加图:直接丢进 `memes/任意子目录/`,重启即可 ## 场景图(她自己的状态图) 除了固定形象和表情包,她会按情境发一张"自己此刻的样子":锅边打盹、困、开心、生气、委屈、干饭、看戏、摸鱼、惊讶、晚安、自拍。角色是同一个(蓝发女仆 + 头顶大铁碗),所以看起来像同一个人,而不是每句话换一张脸。 - 模型可以在回复里输出 `[[pose:打盹]]` 指定场景;没指定也会按话里的关键词猜("困得眼睛都睁不开" → 打盹图) - 睡着被叫醒时,自动配"打盹" - 闸门:同一会话 10 分钟最多一张;自动匹配还要掷骰子(默认 35%),不会刷屏 - 图放在 `assets/poses/`,`poses.json` 里写着固定角色风格、每个场景的提示词和关键词 - **默认不联网、不花钱**:图库是本地文件,对话时只读本地图。只有你主动跑生成工具时才会调用一次文生图接口 - **完全免费的玩法**:用任何你顺手的画图工具/免费额度画 11 张,按 `场景名.jpg` 放进 `assets/poses/`,然后: ```bash .venv/bin/python tools/gen_poses.py --index-only # 只建索引,不调用接口 ``` - 没配图的场景也能要:模型写 `[[pose:吃西瓜]]` 这种库里没有的标签时,**开了在线生成**就会后台画一张、登记缓存,以后直接复用(默认关) - 想看某个场景:主人私聊发 `/看 打盹`;不带参数会列出所有可用场景 - 生成整套(用自己的文生图 Key,OpenAI 兼容 `/images/generations`): ```bash .venv/bin/python tools/gen_poses.py --dry-run # 先看会发什么提示词(不需要 Key) .venv/bin/python tools/gen_poses.py --list # 哪些已生成、哪些还缺 .venv/bin/python tools/gen_poses.py --api-key sk-xxx # 生成缺的(已有的跳过) .venv/bin/python tools/gen_poses.py --api-key sk-xxx --seed 20261028 # 固定种子,整套更像同一个人 .venv/bin/python tools/gen_poses.py --api-key sk-xxx --size 1K # 豆包想省时就降到 1K .venv/bin/python tools/gen_poses.py --force --tags 打盹 # 只重画一张 ``` **Key 有三种填法**(`config.json` 不在 git 里,`git pull` 不会自动带上 `pose` 段): ```bash # 1) 命令行(最简单,不落盘) .venv/bin/python tools/gen_poses.py --api-key sk-xxx --tags 打盹 # 2) 环境变量(工具和机器人都认) export ARK_API_KEY=sk-xxx .venv/bin/python tools/gen_poses.py --tags 打盹 # 3) 写进 config.json 的 pose.generate.api_key(下面这行可以安全插入,不手改 JSON) cd /opt/qqbot && .venv/bin/python - <<'PY' import json from pathlib import Path p = Path('config.json') cfg = json.loads(p.read_text(encoding='utf-8')) gen = cfg.setdefault('pose', {}).setdefault('generate', {}) gen.update({'base_url': 'https://ark.cn-beijing.volces.com/api/v3', 'model': 'doubao-seedream-5-0-flash-260915', 'size': '2K', 'response_format': 'url', 'watermark': False, 'api_key': '你的Key'}) p.write_text(json.dumps(cfg, ensure_ascii=False, indent=2) + '\n', encoding='utf-8') print('已写入 pose.generate') PY ``` > `pose.generate.enabled` 只管「运行时缺图补画」,跑生成工具不需要打开它。 **用哪个模型**(价格会变,以官网为准): | 目标 | 推荐 | 说明 | |---|---|---| | 先免费试构图 | 智谱 `cogview-3-flash` | 有免费额度/免费档,中文提示词友好,出图快;质量一般,够看构图 | | 日常主力 | 豆包 `doubao-seedream-5-0-flash-260915`(火山方舟) | 默认配置就是它:支持 1K/2K/4K,中文理解好、厚涂和二次元都能打,按张计费 | | 二次元/性价比 | 硅基流动 `Kwai-Kolors/Kolors` 或 `black-forest-labs/FLUX.1-schnell` | 便宜快;FLUX 英文提示词效果更好,可以把 `poses.json` 的 `style` 换成英文 | | 一致到极致 | 本地 SDXL / Illustrious + 固定 seed + IP-Adapter | 要显卡;一套 11 张一次跑完,最稳但最折腾 | `pose.generate` 里和豆包对应的几个字段(也适用于其他家,不认识的就别填): ```json { "model": "doubao-seedream-5-0-flash-260915", "size": "2K", // 豆包:1K / 2K / 4K;固定正方形写 2048x2048;其他家一般写 1024x1024 "response_format": "url", // 2K/4K 用 url 更稳;小图可 b64_json "watermark": false, // 豆包默认会打"AI生成"水印,关掉 "stream": false, "seed": null // 填一个整数,整套图更像同一个人 } ``` - 没有图也能跑:会退回原来的固定形象图 `assets/dafeiyu.jpg` - 可选"缺图时现场补画并缓存"(默认关):`config.json` 里 `pose.generate.enabled = true` 并填 Key; 开着也只是"缺图才画、画过就复用",不会每句现画 ## 主动消息 | 项 | 默认 | | --- | --- | | 间隔 | 每 5 分钟一条 | | 首条 | 约 1 分钟后 | | 静默判定 | 3 分钟 | | 群沉默停手 | 10 分钟 | | 每天上限 | 150 条 | | 静默时段 | 23:00–08:00(叠加作息) | | 配图 | 70% | | 语音 | 25% | | 主动 @ | 50%,且要聊熟(熟悉度 ≥ 50) | 主动消息会参考最近的群聊/对话,没有真实内容就 `SKIP`,不编话题。 ## 视频生成(发 QQ 群) 只发白名单群;每个白名单群每天 **2–4 条** 7–15 秒竖屏视频,不再让主人审批。 来源: - 今日热点:DeepSeek Search 结果,不造谣、不碰敏感话题; - 今天发生的事:群聊内容只做脱敏总结,不出现昵称/QQ/原文; - 今天的心情:从心情状态转成一句人话; - 群提问:每周三优先做“问大家怎么看”,素材仍只做脱敏总结。 规则: - 只发 `chat.group_whitelist`(或 `douyin.groups`)里的群;白名单有几个就发几个; - 每个群每天 2–4 条,所有群发同一批视频; - 上午(8:00–12:00)至少 1 条、下午(13:00–18:00)至少 1 条;额外的随机分布在 10:00–22:00; - 两次发送至少间隔 90 分钟,睡着不发; - 群里先发标题 + 一句内容,再发视频; - 内容会过滤政治、色情、暴力、歧视、赌博、诈骗等敏感项。 配置: ```json "douyin": { "enabled": true, "groups": [], "min_per_day": 2, "max_per_day": 4, "min_gap_minutes": 90, "morning_window": [8, 12], "afternoon_window": [13, 18], "extra_window": [10, 22], "send_intro": true, "width": 720, "height": 1280, "use_group_topics": true, "bgm": "assets/bgm/soft.mp3" } ``` `groups` 留空时用 `chat.group_whitelist`;白名单为空则不发。 主人私聊「视频预览」可以立刻生成一条并发到所有白名单群,用来测试。 生成需要 `fonts-noto-cjk`(封面中文字体)和 ffmpeg;服务器上: ```bash apt install -y fonts-noto-cjk ``` ## 联网搜索 DeepSeek 的聊天 API 本身不联网。模型输出 `[[search:关键词]]` 时,机器人先搜索,再把结果喂回去作答。 默认走 **DeepSeek Search / Fetch**(和聊天共用同一个 API Key): - `POST /v1/tools/search`:结构化结果,带长摘要,可选网页正文; - `POST /v1/tools/fetch`:把指定网页抓成 Markdown,补足长文; - `fetch_top` 控制对前几条结果再抓正文,默认 1 条; - 最多 2 轮,防无限套娃;同关键词 10 分钟内走缓存; - 按 DeepSeek 官方计费(以平台文档为准),QPS:Search 100、Fetch 25。 `search.provider` 三选一: | 值 | 行为 | |---|---| | `deepseek`(默认) | 官方 Search/Fetch,质量最好 | | `bing` | 抓 Bing 结果页,免费,但只有摘要(旧实现) | | `auto` | DeepSeek 失败/无结果时回退 Bing | 不想花钱或 Key 不可用时,把 `provider` 改成 `bing` 即可,其他不用动。 ## 指令 | 指令 | 作用 | | --- | --- | | `/help` | 帮助 | | `/reset` | 清空当前会话上下文 | | `/mood` | 看心情(主人看数值,别人看一句话) | | `/mood set valence=30 patience=20` | 主人手动调心情 | | `/card` | 看自己的好感/熟悉度/标签 | | `/card ` | 主人看别人的卡 | | `/card set closeness=80 familiarity=60 alias=桑子 tags=爱抬杠` | 主人改卡 | | `/记忆` | 看我记得你什么(事实清单) | | `/记忆 ` | 主人看别人的事实 | | `/记忆删 <编号>` | 主人删掉一条记错的事实 | | `/看 打盹` | 主人看某个场景图;不带参数列出所有场景 | | `/time` | 看现在几点、她的状态 | | `/rhythm` | 主人看今天的实际作息、最近 5 天和问候情况 | | `/rhythm 今晚 熬夜` / `早睡` / `正常` | 主人指定今晚怎么睡 | | `/rhythm 规律` / `/rhythm 随机` | 主人切回固定作息 / 切回不规律 | | `/rhythm set sleep=00:30 wake=07:00` | 主人临时固定作息(不随机) | | `/rhythm reset` | 清掉临时作息,回到随机 | ## 测试 ```bash .venv/bin/python tools/mock_e2e.py # 全链路(不需要 QQ/API Key) .venv/bin/python tools/test_mood.py # 心情 .venv/bin/python tools/test_people.py # 人物记忆体:关系 .venv/bin/python tools/test_memory.py # 人物记忆体:长期事实与迁移 .venv/bin/python tools/test_pose.py # 场景图与生成链路 .venv/bin/python tools/test_rhythm.py # 时间与作息(固定模式) .venv/bin/python tools/test_rhythm_vary.py # 不规律作息 .venv/bin/python tools/test_repeat.py # 防复读 .venv/bin/python tools/test_two_groups.py # 双群隔离 .venv/bin/python tools/test_media.py # 图片下载兜底 .venv/bin/python tools/test_search.py # Bing 兜底搜索全链路 .venv/bin/python tools/test_deepseek_search.py # DeepSeek Search/Fetch .venv/bin/python tools/test_watchdog.py # 掉线看门狗状态机 .venv/bin/python tools/test_video.py # 视频生成/群发/上限 .venv/bin/python tools/test_rhythm_e2e.py # 固定凌晨 3 点的时间感知 ``` ## 常见问题 **Q:重启服务器后要重新扫码?** A:SnowLuma 的登录态保存在 `/opt/snowluma/config` 和 `/opt/snowluma/share` 两个目录里,正常重启容器一般不用重扫。如果 QQ 掉线/被风控,打开 `http://127.0.0.1:6081/`(noVNC)重新扫码,再 `systemctl restart qqbot`。 **Q:Docker 拉镜像超时?** A:配镜像加速(阿里云 ACR 免费加速器或可用镜像站),或离线 `docker save` / `docker load`。 **Q:能和自己 QQ 同时在线吗?** A:同一个 QQ 一般只能一处登录。SnowLuma 跑着时,本地 QQ 要退出。 **Q:图片经常收不到?** A:腾讯图片链接约 2 小时过期、机房 IP 可能被限速。代码已带重试和 `get_msg` 刷新;仍失败会回一句说明。 **Q:日志在哪?** A:服务器 `journalctl -u qqbot`,文件 `logs/bot.log`。 **Q:怎么更新?** A:`cd /opt/qqbot && git pull && systemctl restart qqbot`;依赖变了才需要 `pip install -r requirements.txt`。 ## 技术细节 - OneBot 11 协议,SnowLuma 作为 WebSocket 服务端监听 `127.0.0.1:3001` - SnowLuma 部署见 [deploy/README-SnowLuma.md](deploy/README-SnowLuma.md);`bot.py` 只依赖 OneBot v11 - 两边的 token 必须一致;`config.json` 不进 Git - 语音:`pysilk` 编码成 `\x02#!SILK_V3`,base64 发送 - 语音识别:faster-whisper `small` + int8,纯 CPU - Python 3.12;`requirements.txt` 固定主要依赖版本 - 运行时数据与代码分离:`data/` 不进 Git,迁移/备份单独处理