Skip to content
Chenxi-Only-YPublic

About

Somnia·眠 —— 一个住在微信里、话不多、记得住事、有作息、会兑现承诺的人

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Somnia·眠

ta 不是人。 屏幕那边的每一句,都是算出来的 —— 记得再清楚,也只是一段会断的记录。别投入真感情。

一个住在微信里的、话不多、记得住事、有作息、会兑现承诺的人。只给你一个人用。

仓库:https://github.com/Chenxi-Only-Y/Somnia

命名

名字 指什么 用在哪
Somnia·眠 项目名 文件夹名、窗口标题、给人看的名字
Somnia / somnia 代码标识 包名、入口、环境变量前缀(技术标识,不能有中文)
角色名 名字 默认没有名字,面板里显示为 ta;要名字就在「设置」里填

Somnia 取自拉丁语 somnium(睡着),中文取一个字:眠 —— "睡着的时候也在场"。

对应设计里那条:她不说话的时候,并不等于她不存在。

目录

Somnia·眠/
├── somnia/
│   ├── app.py             主循环:收 → 判 → 想 → 发
│   ├── brain.py           回不回 / 多久回 / 回几条(纯规则,不碰模型)
│   ├── gateway.py         去重 + 连发合并
│   ├── memory.py          分层记忆 + 事实抽取 + 到期
│   ├── archive.py         永久档案(三天前的原文搬进文件)
│   ├── aging.py           归档滚动:细节 → 印象 → 摘要
│   ├── persona.py         人设加载 + prompt 拼装 + 时间/作息
│   ├── composer.py        调模型 + 分句 + 复读检测
│   ├── scheduler.py       主动性:沉默 / 漂移 / 承诺
│   ├── promises.py        从她的话里认承诺 + 算兑现时间
│   ├── stickers.py        表情/照片库 + 时间归属 + 图文匹配
│   ├── imagegen.py        本地生图(现拍现生成)
│   ├── config.py          配置(env > settings.json > toml > 默认)
│   ├── settings.py        面板值
│   └── channel/
│       ├── base.py        通道契约
│       ├── cli.py         终端
│       ├── claw.py        OpenClaw Weixin(官方)
│       └── wechatauto.py  微信 4.x:库读 + 窗口写
├── tests/                 359 项(python tests/run_all.py)
├── stickers/              随包 91 张表情包 + notes.json(备注)
├── photos/                你自己的照片(可选)
└── data/                  运行时(db / settings / 日志 / 备注)

改人设,不用改代码

两个 md,改完直接生效(按 mtime 缓存)。以 > 开头的行是写给你看的注释,不会发给模型。

文件 放什么
SOUL.md 硬规则、时间、边界、不可妥协 —— 慎改
persona.md 年龄、职业、说话习惯、示例 —— 随便改

⚠️ 人设默认不进 prompt。 现在发给模型的只有 SOUL.md 的硬规则、时间、记忆, 没有身份行。想让 persona.md 里写的字影响她怎么说话,要打开这个开关:

[identity]
prompt_persona = true

面板「设置」里有个 「人设参与对话」 勾选框,勾上就等于开了这个开关。 关着的时候,面板「ta 是谁」里写的只是存档 —— 这样设计是为了让 prompt 只装"规则", 性格留给控制台,改哪看得见哪。

框架是十三块(缺哪块,她就缺哪块的表现)。面板「ta 是谁」页按块编辑, 空着的块不会写进文件、也不会发给模型。 身份 · 关系 · 对方 · 说话方式 · 状态 · 黏人与边界 · 不做什么 · 示例 · 习惯 · 情绪 · 亲密度 · 忌讳 · 未知

新装的时候 persona/ 里只有 SOUL.md 和 persona.example.md。 想用模板就复制一份改名成 persona.md。

作息

时间感不是"告诉她现在几点"就完了。她有作息表:几点在睡、几点在忙、几点在吃饭。

  • 夜里 2–7 点是静默时段,默认不回;被吵醒第一条 10%,每回一次 +20%,上限 90%
  • prompt 里会带一句"现在是 X 点,你大概在 Y",而且要求内容配得上时间(早上别提月亮)
  • 隔了一夜就算新的一天;上一轮停在"晚安",这一轮要像刚睡醒

作息表在 persona.md 里,不写就用默认那套。

她怎么记东西

按时间分四层,越久越薄:

层 时间 留什么 在哪
细节 0–3 天 原文,一字不改 数据库,直接进 prompt
印象 3–7 天 每天两三句"那天…",没有原话 数据库
模糊 7–30 天 只剩更早的印象,读不到细节 数据库
档案 30 天以上 完整原文 + 段摘要 memory/archive/*.jsonl

三天以前的原文不会消失,只是搬进了文件:按段存(间隔超过半小时算另一段), 每段带一句那天的摘要。平时不进 prompt、不占 token。

  • 想起来:你提到旧事("还记得…""上次""那天"),或者问的本来就是很久以前的东西, 她会去档案里翻;翻到就把那一整段(含原话)放进 prompt,追问能往下说细节
  • 没事的时候,档案只是躺着 —— 这就是"其余时间只保存"
  • 事实另存一条线:按重要度和半衰期排序,带时间的事实会过期 ("他今天要去看牙" 1.5 天后自动忘)
  • 面板的「回忆」页按天分组,顶部有日期条,可以只看某一天

另外单独列一块她最近说过的 12 句,明确要求"接得上、别矛盾、别重复"。

行为规则(都在 somnia.toml)

想改什么 改哪个
回不回、回几条、多快回 [behavior] reply_rate / delay_median / seg_choices
半夜被吵醒的概率 [behavior] quiet_hours / wake_chance
主动找你 [proactive] silence_hours / proactive_max_per_day
记忆多细、留多久 [memory] hot_days / impression_days / summary_keep_days
模型和温度 [model]

表情和照片

表情包(stickers/):随包带了 91 张(呆猫八条 + 这狗),备注在 stickers/notes.json, 开箱就能用。她按含义自己挑([表情:委屈]),35% 的回合给她挑选机会。

想加自己的:图丢进 stickers/,到面板「图册」写一句备注 —— 没备注的图她不会用。

照片(photos/):两种来源

  1. 库里的(上传时备注写"拍的是什么")
  2. 现拍现生成 —— 她说想给你看某个东西,库里没有就让本地模型画一张

照片有时间归属(凌晨 / 早上 / 中午 / 傍晚 / 夜里),半夜不会发"今天的外卖"。

配置优先级

环境变量  >  data/settings.json(面板)  >  somnia.toml  >  代码默认

面板里存的会盖住 toml。 改了 toml 没反应,先去面板看一眼。

跑起来

第一次用:双击 start.bat,页面上填好 API 地址/密钥/模型和通道,再点「唤醒」。 第一次不会自动接微信 —— 那时还没配账号,接了只会读到一堆不认识的消息。

之后每次:双击 start.bat 就行。它会检查有没有已经在跑,然后启动并自动打开面板。

要下载的东西:

要什么 链接 什么时候要
Python 3.12 https://www.python.org/downloads/windows/ 必须
DeepSeek 开放平台 https://platform.deepseek.com 必须(注册 → 充值 → 建 Key)
7-Zip https://www.7-zip.org/ 可选(老系统解压用)
微信 4.x https://pc.weixin.qq.com/ 接微信才要
wechatauto-replica https://pypi.org/project/wechatauto-replica/ 接微信才要(pip 装)
Ollama https://ollama.com/download 想用本地免费模型才要

从没装过 Python、也没申请过 API 的,看这份保姆级教程: docs/快速开始.md

需要 Python 3.11+(3.10 没有 tomllib)。核心零依赖;接微信才需要 pip install wechatauto-replica。

更新到新版本

两种方式,都只覆盖代码,绝不动 data/ memory/ photos/ stickers/ persona/persona.md:

① 面板里点一下(需要发布者配好地址)

左下角出现 ↓ 新版本 0.2.1 时,点它 → 弹窗说明改了什么 → 确认 → 自动下载、备份、覆盖。更新完关掉黑窗口重新 start.bat。

发布者在 somnia.toml 里填这一项,用户端就会自己检查:

[update]
update_url = "https://你的网址/version.json"

version.json 的内容:

{
  "version": "0.2.1",
  "zip": "https://你的网址/Somnia-0.2.1.zip",
  "notes": "修了发送重复、更新了模型名"
}

② 手动:update.bat

拿到新版 zip 后,双击 update.bat,把 zip 拖进去回车(等价写法: python scripts/update.py 新版本.zip)。

它会:

  • 只覆盖代码和文档(somnia/ tests/ docs/ *.bat *.md *.toml …)
  • 绝不动 data/ memory/ photos/ stickers/ persona/persona.md
  • 覆盖前把数据库和设置备份到 data/backup/pre_update_时间/
  • 新版本结构不对就什么都不改,直接退出

更新完双击 start.bat;如果刚才开着,先 stop.bat。

打包给别人

clean.bat        :: 清掉对话、密钥、日志、照片、人设

清完再看一眼 docs/发布清单.md —— 里面列了哪些路径不能进包、 以及微信真机通道有封号风险这件事必须写进说明。

控制台

http://127.0.0.1:8765,一个页面管全部。

页面 干什么
回忆 聊过的全部。按天分、日期条筛选、勾选删除
此刻 她"为什么回 / 为什么没回"的决策记录
图册 表情包和照片,上传、改备注、删除
ta 是谁 人设,按块编辑
设置 密钥、通道、主动性、人设开关、清空记忆

左下角两个按钮:唤醒 / 睡下。睡下之后她不会再回任何消息,包括主动找你。

接微信

wechatauto 通道:读微信本地库收消息(不解密、不联网),用 UIA/剪贴板驱动窗口发消息。

要填三个东西:

填什么 从哪来
聊天对象(显示名) 对方微信昵称,给窗口搜索用
对象 wxid 对方在 xwechat_files 下的目录名,去掉下划线后缀
发送账号 wxid 你自己的那一份

⚠️ 风险(这条比上面所有功能都重要):

wechatauto-replica 会往 Weixin.dll 的进程内存写 1 个字节,把无障碍闸门打开, 然后读本地库、模拟点击发消息 —— 微信没有授权这些操作。

可能发生的事 概率 能不能恢复
微信被意外登出(手机/电脑被踢下线) 比较高 重新扫码即可,聊天记录不丢
消息发重 / 发错对象 偶发 撤回
账号被限制或封禁 低 不能

建议:先用小号跑几天;出问题先点「睡下」,再关微信重新登录; 不行就 pip uninstall wechatauto-replica 退回 cli 通道。微信重启即恢复,不损坏文件。

面板里第一次切到 wechatauto 时也会弹一次这个提醒 —— 不是走过场,是真的可能被踢下线。

测试

python tests/run_all.py

会逐个数、逐文件报,最后给一个准确的数(现在是 359 项,全绿)。 某个文件崩了会直接标出来,不会因为"没跑完"而让总数看起来变少。

设计上的硬规矩

  1. 决策层不碰模型。回不回、多久回、回几条,全是规则和采样。模型只负责"回什么"。
  2. 延迟是分布的。秒回是最大的破绽。
  3. 频率由代码控制,不写在 prompt 里。模型会模仿样例,让它"偶尔"等于让它"每次"。
  4. decisions 表从第一天就记。它的价值在第十五天才显现。

免责

这是给一个人自用的玩具,不是产品。

  • 对话会发给模型服务商(和你用网页版 AI 一样),别聊不该聊的
  • data/ 里有你的聊天记录和密钥,别整个文件夹发人
  • 表情包是他人作品,自己私下用

About

Somnia·眠 —— 一个住在微信里、话不多、记得住事、有作息、会兑现承诺的人

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages