本项目不随仓库分发任何 Live2D 模型文件(characters/*/live2d/ 已在 .gitignore 中排除)。
- 仓库仅内置 miku 占位角色配置(
pet.json+profile.json),不含任何模型素材;Rory/sample_live2d等完整角色包由用户本地放置模型后使用,不随仓库分发。 - Live2D 渲染器代码完整保留,但模型需用户自行提供——请使用有分发许可的模型(如 Live2D 官方示例),或运行
python tools/fetch_free_live2d_sample.py下载官方 Haru 示例模型。 - 请勿将无再分发许可的模型(如游戏提取模型)放入仓库。
占位角色(需自备模型):
miku/Rory/sample_live2d是占位角色——仓库仅含配置与profile.json,不含任何模型素材。使用前请按对应角色目录放置模型文件;缺少模型时桌宠会提示「需下载模型」且不会加载(不会白屏或崩溃)。无默认角色:首次启动由引导流程选择角色包;仓库不含内置精灵图角色。
基于 PySide6 的 AI 桌面伴侣,深度集成 Hanako 生态。支持多桌宠并行运行,每个 Hanako agent 可独立拥有一个桌宠窗口。
💡 一句话说明:Hanako 是什么? Hanako(本项目的宿主)是运行在后台的 AI 助手框架。oc-pet 桌宠不是独立 AI—— 它的对话、记忆、工具调用都复用你机器上
~/.hanako/里已有的 Hanako 配置。 换句话说:先装 Hanako 并配好模型/API,桌宠才有灵魂;没装 Hanako 时桌宠会用内置降级逻辑跑基础对话。 安装见下方「环境要求」。
功能清单
- 💬 文字对话 -- 复用 Hanako 身份/记忆/模型配置,支持 tool calling
- 🗣️ TTS 语音输出 -- 四种引擎可选:
- CosyVoice2 本地克隆(零样本克隆,需 GPU)
- 微软 Edge TTS(免费在线,秒级,免注册免 key)
- MIMO TTS(小米 MiMo V2.5,音色可选)
- OpenAI 兼容 API
- 🎤 ASR 语音输入 -- 三种引擎可选:
- Whisper 本地(离线识别)
- MIMO ASR(小米 MiMo V2.5)
- OpenAI 兼容 API
- 🔌 插件工具调用 -- 自动扫描 Hanako 插件,LLM tool calling 执行插件工具
- ⏰ 时间感知 -- 区分早晨/中午/下午/晚上/深夜/凌晨,影响对话风格
- 😊 情绪状态机 -- happy/sad/thinking/surprised/neutral 五种情绪,自动衰减
- 📸 屏幕感知 -- 定时截屏 + 视觉模型分析,注入对话上下文(独立进程,不卡 UI)
- 🎭 屏幕情绪检测 -- 从屏幕内容推断用户情绪(如"看视频" → happy)
- 🪟 前台窗口监听 -- 检测用户正在使用的应用,用于窗口互动和主动对话触发
- 📱 手机活动感知 -- MacroDroid 上报前台 App 切换,自动分类(娱乐/通讯/音乐/购物/阅读/工作/游戏)并注入上下文
- 🔌 掌心窗集成 -- 通过 linjian-peek 服务获取手机截图、生活状态(电量/网络)、远程控制(打开App/通知/闹钟)
- 🎵 SMTC 媒体感知 -- 读取正在播放的媒体信息(歌曲名、艺术家、专辑)
- 📝 微事件生成 -- 空闲时自动生成小事件(观察/关心/笑话/提问/问候)
- 🤖 感知走 AI 发挥 -- 有 LLM 时走生成,无 LLM 才降级模板(不念预置台词)
- 🔄 情境缓存 + 冷却控制 -- 避免重复内容,冷却 600 秒(可配置)
- 🖱️ 鼠标交互 -- 视线跟随 + 靠近反应 + 悬停 + 追逐 + 惊吓
- 🖐️ 拖拽 -- 左键拖动桌宠,释放后弹跳
- 📌 边缘吸附 -- 拖到屏幕边缘坐下
- 🪟 窗口互动 -- 检测前台窗口,桌宠自动走过去(冷却时间可配置)
- 💬 右键菜单 -- 穿透/设置/插件/退出
- ⌨️ 聊天框 -- 左键点击切换聊天输入
- 🤖 规则引擎 -- 对话空闲时长 + 前台窗口分类 → 自动搭话
- 📊 屏幕内容触发 -- 根据屏幕分析结果主动搭话(检测到视频/游戏/代码等关键词)
- ⏱️ 冷却控制 -- 屏幕内容触发 5 分钟冷却,避免频繁打扰
- 🔗 状态监控 -- 实时读取 Hanako 状态(TODO/通知/对话回复)
- 💬 对话同步 -- Hanako 有新回复时,桌宠显示气泡 + 播放 TTS
- 📋 工作状态 -- 检测到 Hanako 有 TODO 时,桌宠显示"工作中"状态
- 🔔 通知转发 -- Hanako 通知显示为桌宠消息气泡
- 🌐 多桌宠协作 -- 多个桌宠之间可以互相"聊天"/反应/关心/送礼物
- 📁 记忆读取 -- 读取 Hanako 的置顶记忆和最近对话记录
桌宠通过两条独立通道感知手机状态,统一注入 LLM 上下文:
通道 1:MacroDroid 直连(常态感知)
- 📱 前台 App 上报 -- MacroDroid 规则检测应用切换,HTTP POST 到桌宠本地接收器
- 🏷️ 自动分类 -- 7 类应用(娱乐/通讯/音乐/购物/阅读/工作/游戏)+ 情绪映射
- 📊 活动摘要 -- "最近1小时使用了 小红书(3次)、微信(2次)"
- ⏱️ 空闲检测 -- 距上次手机活动的分钟数
- 🔒 隐私优先 -- 数据不出本机,标准库 HTTP server,零外部依赖
通道 2:掌心窗集成(按需增强)
- 📸 手机截图 -- 通过 linjian-peek 服务请求手机截图并返回
- 🔋 生活状态 -- 电量、充电、网络、当前 App、屏幕时间、解锁次数
- 🎮 远程控制 -- 打开应用、返回桌面、发送通知、设置闹钟
- 🔌 MCP 工具 -- 通过 Hanako 插件系统注册,LLM tool calling 触发
数据流:
MacroDroid → HTTP POST → PhoneActivityReceiver → PhoneActivityPerception ─┐
├→ PerceptionController.build_context()
linjian-peek → MCP Plugin → Hanako tool calling ──────────────────────────┘
- 💾 记忆快照 -- 导出/导入 Agent 记忆,支持 overwrite/smart/skip_existing 合并
- 📏 动态记忆预算 -- 自动按模型 context 1% 计算,或手动指定字符数
- 📌 置顶记忆 -- 读取 pinned-memory.json
- 📊 Token/费用统计 -- 按会话/按天统计,可配预算上限
- 🔄 记忆自动维护 -- 空闲时自动归纳/去重/修剪/重要性衰减
- ⚡ 异步写入 -- 批量 flush + 异步落盘,不阻塞对话
- 🏠 多窗口并行 -- 每个 Hanako agent 独立运行一个桌宠
- 🔍 Agent 发现 -- 自动扫描
~/.hanako/agents/ - 🎨 角色包管理 -- 自定义精灵 + 内置回退
- 🎛️ per-pet 独立配置 -- 每个桌宠可单独绑定自己的 TTS 引擎/音色与对话助手 (设置面板 → 基础 →「桌宠独立配置」;不配置则沿用全局默认)
- 🏥 子服务健康四态 -- 服务状态可视化(enabled/running/ready/last_error)
- 🎛️ 主动能力面板 -- 统一展示开关 + 运行状态 + 费用边界
- 🔒 隐私暂停 -- 一键停掉所有隐私敏感能力
- 💾 备份恢复 -- 完整备份 + SHA-256 校验 + 一键恢复
- 🎮 插件 KV 存储 -- 插件自带配置页 + 持久存储
桌宠内置一个 MCP server(默认 http://127.0.0.1:8979/mcp),把自身的
表情/动作/感知能力暴露给 Hanako 等 MCP 客户端 —— 桌宠不只是被驱动的
壳,也可以被 AI 主动操作。共 21 个工具:
| 分组 | 工具 | 说明 |
|---|---|---|
| 状态 | pet_state / pet_capabilities |
读当前情绪/动作/可用能力快照 |
| 表达 | pet_set_emotion / pet_play_anim / pet_expression / pet_say / pet_celebrate / pet_reset_idle |
设情绪、播动作、设表情、说话、庆祝、重置待机 |
| 电脑操作 | pet_computer_*(8 个) |
窗口枚举/元素树/启动/点击/输入/按键(默认只读,需显式开启动作) |
| Hanako | pet_hana_*(5 个) |
读 Hanako 状态/会话/agent/app 列表 |
开关:
config.json→mcp_server.enabled。默认端口 8979, 仅监听127.0.0.1(不对外网暴露)。 电脑操作默认关闭动作:computer_use.allow_actions=false时只读窗口信息, 不执行点击/输入——避免桌宠被误用来操作你的桌面。 想真的用起来(装驱动 → 起 daemon → 开写权限 → Hana 侧授权), 见下方「电脑操作(Computer Use,可选)」。
- 📱 ntfy 通知 -- 推送通知到手机(需安装 ntfy app)
- Python: 3.10+
- 操作系统: Windows 10/11
- Hanako: 已安装并配置(桌宠读取
~/.hanako/下的配置和角色数据)- Hanako 项目:https://github.com/liliMozi/openhanako
- 安装后运行至少一次(生成
~/.hanako/agents/与provider-catalog.json) - 不装 Hanako 也能启动桌宠(走本地降级对话),但会缺失身份/记忆/多助手等核心能力
首次拉取仓库如果因网络中断报
early EOF,重试一次即可(可加git config http.postBuffer 524288000增大缓冲)。
# 推荐:创建 venv,避免污染系统 Python
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt不用 venv 直接
pip install -r requirements.txt也可以跑,但会装进全局环境。 强烈建议用 venv——本项目依赖较多(PySide6 等 170MB+),可随时删除重建。
跑起来你会看到什么(首次启动):
- 🖱️ 眼睛跟着鼠标转(视线跟随)
- 👁️ 自动眨眼(每隔几秒)
- 😴 5 分钟没操作 → 犯困打哈欠
- 😵 15 分钟没操作 → 打瞌睡倒头
- 💬 10 分钟空闲 → 桌宠主动找你说话
- 🖱️ 左键拖动桌宠,释放后弹跳
- 📌 拖到屏幕边缘 → 桌宠坐下
桌宠从 Hanako 读取:
~/.hanako/agents/<agent>/- 身份、意识、记忆、模型配置~/.hanako/provider-catalog.json- API 地址、密钥、模型列表
不需要单独配置 API,自动复用 Hanako 的。
桌宠不随仓库分发 Live2D 模型文件。需要自备或下载官方示例模型:
# 方式 A:下载官方 Haru 示例模型(推荐新手)
python tools/fetch_free_live2d_sample.py haru
# 方式 B:按角色目录 README 下载
# 见 characters/miku/README.md(或任意角色目录的 README.md)模型硬要求(三条):
- ✅ 裸文件:解压后能看到
.model3.json+.moc3+ 贴图 - ✅ 没加密:模型文件可直接导入 VTube Studio
- ✅ Cubism 3+:支持 Cubism 3 或 4 的模型
💡 判断标准:能导入 VTube Studio 的模型就能用。下单前问卖家:"是否提供 model3.json 素材文件?"
python main.py或双击 start_pet.bat。
首次启动由引导流程选择角色包(默认无内置模型,需自行提供)。以 miku 占位角色为例:
把官方/有许可的 Live2D 模型放入 characters/miku/live2d/,再把 config.json 的 character 改为 miku 即切换为 Live2D 桌宠;其他角色同理。
下面是一条最短可用路径。每步都有「做对了会看到什么」,卡住时按这个对。
桌宠是壳,灵魂在 Hanako。先跑:
# 看 Hanako 服务在不在(默认端口 20099)
curl http://127.0.0.1:20099/api/health- ✅ 返回 JSON(含
user字段,就是你的名字)→ 继续 - ❌ 连接被拒 → 先启动 Hanako,否则桌宠只能用降级对话
启动桌宠后看日志,应该出现:
[session] 已从磁盘恢复 pin: agent=ophelia session=sess_xxx # 重启后
Agent identity injected (329 chars, agent=ophelia) # 人格来源
这两个字段是排查的两根支柱:
agent=xxx—— 人格从哪个助手来(由config.json的dialog.agent_id决定)session=sess_xxx—— 桌宠在哪个会话里说话
⚠️ 人格 vs 模型包是两个概念:character(如miku)决定画的是什么;dialog.agent_id(如ophelia) 决定说话的是谁。桌宠本身没有人设,用的是助手的人设。
左键点桌宠 → 弹出聊天框 → 发一句「你好」。
- ✅ 气泡出字 + (若开了 TTS)有声音
- ❌ 一直「思考中」→ 看日志有没有
LLM 401(凭证失效)或连不上(网络);改.env或重登 Hanako
这是**最容易「看着像对但其实是死的」**的一环。发一句带情绪的话, 然后看日志:
[DECISION] emotion: happy (src=...)
[DECISION] expression: 脸红 (src=exact:happy)
Live2DRenderer: 播放动作 idx=2(motions/waving.motion3.json)
- ✅ 三行都在 → 情绪→表情→动作链路通
- ❌ 只有
emotion没有expression→ 模型的表情名不匹配, 查characters/<角色>/live2d/profile.json的映射 - ❌
no-match→ 表情名/情绪名搞混了(工具收表情名, 内部映射收情绪名)
想让 Hanako 反过来驱动桌宠(比如让 AI 主动让桌宠比个心):
- 确认桌宠的 MCP server 起来了:
curl http://127.0.0.1:8979/mcp
- 在 Hanako 的 MCP 连接器配置里加
oc-pet,指向上面这个地址 - 重启 Hanako
- 把连接器授权到 agent 级(只在 host 级打开不够),确认弹出的工具授权卡
- ✅ Hanako 能看到 21 个
pet_*工具 - ❌ 连不上 → 顺序问题:Hanako 比桌宠先起,且不会自动重试。 先开桌宠,再开 Hanako。
- ❌ 连接器显示
running、toolCount=21,但调用报「未找到工具」→ 授权层级问题:host 级开着、agent 级没开。见下方「电脑操作」第 4 节。
| 想要 | 做什么 | 代价 |
|---|---|---|
| 免费、秒级、免注册 | 设置 → TTS → Edge TTS | 需联网 |
| 本地克隆音色 | 见上方「本地 CosyVoice TTS 部署」 | 需 NVIDIA 显卡,8–10 秒/句 |
| 语音输入 | 设置 → ASR → Whisper 本地 | 首次下载模型 |
| 症状 | 先看 |
|---|---|
| 桌宠不说话 | .env 的 LLM_*;Hanako 是否在跑 |
| 人格不对 | 日志 Agent identity injected (…, agent=?) |
| 桌宠记忆串了 | 日志 [session] … session=?,是否与预期一致 |
| 表情/动作不动 | [DECISION] expression: 那行有没有 |
| MCP 连不上 | 启动顺序(桌宠 → Hanako) |
桌宠默认用本地 CosyVoice2 配音(无需联网/付费)。它跑在独立子进程里, 不卡 UI;合成延迟约 8–10 秒/句(GPU + fp16)。下面是从零让另一台机器 也能用本地 TTS 的步骤。
前置:Windows + NVIDIA 显卡(本地 TTS 需要 CUDA);Python 3.10~3.12。 没有独显的机器会自动给出告警,可在「设置 → TTS」改用 MIMO / 在线 TTS。
# 1) 把 cosyvoice-tts 仓库放到 oc-pet 的同级目录(两仓库并排即零配置),或:
setup_tts.bat --cosyvoice-repo https://your.git/cosyvoice-tts.git
# 2) 引导脚本会:建 venv → 装 CUDA 版 torch + 依赖 → 获取 cosyvoice-tts
# → 下载 CosyVoice2-0.5B 模型(约 4.6GB,需联网)→ 写 .env引导完成后直接 start_pet.bat 即可。如需手动分步,见下方。
- 获取代码:把
cosyvoice-tts(含src/与models/)放到 oc-pet 同级目录, 或在.env设置OC_PET_COSYVOICE_DIR指向它。 - 装环境(关键:torch 必须带 CUDA,否则本地 TTS 会跑 CPU 慢速):
python -m venv .venv_cosy .venv_cosy\Scripts\python -m pip install torch torchaudio ` --index-url https://download.pytorch.org/whl/cu124 .venv_cosy\Scripts\python -m pip install -r requirements_cosyvoice.txt
- 下载模型(约 4.6GB):
.venv_cosy\Scripts\python scripts/download_cosyvoice_model.py
- 在
.env写入OC_PET_COSYVOICE_DIR与OC_PET_COSYVOICE_PYTHON(引导脚本会自动写;手动装则需自己加)。
| 变量 | 说明 | 默认 |
|---|---|---|
OC_PET_COSYVOICE_DIR |
cosyvoice-tts 目录 | 相邻 ../cosyvoice-tts → 兜底硬编码 |
OC_PET_COSYVOICE_PYTHON |
运行 worker 的解释器(需含 torch+onnxruntime-gpu+cudnn) | 自动探测 |
OC_PET_COSYVOICE_MODEL |
模型名 | CosyVoice2-0.5B |
解析顺序:OC_PET_COSYVOICE_DIR → config.json 的 tts.cosyvoice_dir
→ 与 oc-pet 相邻的 ../cosyvoice-tts → 内置兜底路径。
- 合成一句要 1–2 分钟? 说明跑在 CPU 上(无 CUDA / cudnn 没生效)。
确认显卡驱动正常、torch 是 CUDA 版、且
onnxruntime-gpu+nvidia-cudnn-cu12已装。 - 没独显? 本地 TTS 会优雅降级为不可用并告警,改用 MIMO / 在线 TTS 即可。
{
"behavior": "normal", // 行为模式: quiet/normal/active/cling
"window_interaction": {
"enabled": true, // 是否启用窗口互动
"cooldown_seconds": 30 // 窗口互动冷却时间(秒)
},
"memory": {
"budget_chars": 0, // 记忆预算字符数(0=自动)
"budget_percent": 1.0 // 自动模式:模型 context 的百分比
},
"tts": {
"enabled": true,
"provider": "cosyvoice", // TTS 引擎: cosyvoice(本地) / edge(微软免费) / mimo(在线) / api
"volume": 0.8
},
"asr": {
"provider": "whisper_local" // ASR 引擎: whisper_local/mimo/api
},
"proactive": {
"enabled": true,
"cooldown_minutes": 10 // 主动对话冷却时间
},
"screen": {
"enabled": true,
"interval": 120, // 截屏间隔(秒)
"blur": true // 截图模糊(隐私保护)
}
}# LLM(可选,优先使用 Hanako 配置)
LLM_PROVIDER=deepseek
LLM_BASE_URL=https://api.deepseek.com
LLM_API_KEY=sk-xxx
LLM_MODEL=deepseek-chat
# TTS(可选)
TTS_PROVIDER=mimo
TTS_BASE_URL=https://token-plan-cn.xiaomimimo.com/v1
TTS_API_KEY=sk-xxx
# ASR(可选)
ASR_PROVIDER=whisper_local
# 视觉模型(可选,用于屏幕感知)
VISION_BASE_URL=https://api.siliconflow.cn
VISION_API_KEY=sk-xxx
VISION_MODEL=Qwen/Qwen2.5-VL-7B-Instruct
# ntfy 通知(可选)
NTFY_TOPIC=your-topic-name
# 手机活动感知 - MacroDroid 直连(可选)
PHONE_RECEIVER_PORT=8077
PHONE_AUTH_TOKEN=your-secret-token
# 掌心窗 - linjian-peek 集成(可选)
LINJIAN_URL=https://xxx.onrender.com
LINJIAN_TOKEN=your-linjian-token- 安装 MacroDroid(Android)
- 创建新宏:触发器 = "应用启动/切换" → 动作 = "HTTP 请求"
- HTTP 请求配置:
- 方法:
POST - URL:
http://<电脑IP>:8077/phone/activity - Header:
X-Auth-Token: <你的token> - Body:
{"app": "{app_name}", "event": "switch"}
- 方法:
- 保存并启用宏
💡 如果桌宠和手机在同一局域网,用电脑的内网 IP。如果需要外网访问,考虑用 ngrok 或 frp 做内网穿透。
桌宠除了被 AI 驱动着表演,还能当 AI 的手:枚举窗口、读元素树、启动应用、 点击、输入、按键。执行侧由独立的 cua-driver(trycua/cua,MIT) 完成,桌宠只做代理——所以桌宠本身不碰键盘鼠标,能力的边界和权限都归 cua-driver 管。
⚠️ 写操作(启动 / 点击 / 输入 / 按键)默认关闭。打开就等于把桌面交给 AI, 请确认你知道自己在开什么。
它不是 pip 包,是独立二进制;Windows 上免管理员、免开发者模式:
irm https://cua.ai/driver/install.ps1 | iex验证:
cua-driver --version # 例:cua-driver 0.28.2
cua-driver doctor # 完整环境自检安装位置(桌宠按「driver_path → 环境变量 CUA_DRIVER_PATH → PATH → 已知位置」
自动探测,一般无需手配):
%LOCALAPPDATA%\Programs\Cua\cua-driver\bin\cua-driver.exe%USERPROFILE%\.cua-driver\packages\current\cua-driver.exe
pet_computer_* 最终都落到 cua-driver 的 CLI 上,而 CLI 需要一个在跑的 daemon;
cua-driver status 会告诉你它在不在。两种起法,二选一:
| 方式 | 怎么做 | 适合 |
|---|---|---|
| 手动 | 终端里 cua-driver serve,窗口保持开着 |
只在用的时候开 |
| 开机常驻 | cua-driver autostart enable(注册登录自启计划任务) |
想一直能用 |
验证:
cua-driver status # 期望:Cua Driver daemon is running桌宠自己不会替你拉起 daemon(
computer_use.auto_start_daemon默认false)—— 不想要常驻后台进程,就别开它。
config.json:
{
"mcp_server": { "enabled": true },
"computer_use": {
"enabled": true,
"driver_path": "",
"allow_actions": false,
"auto_start_daemon": false,
"timeout_s": 30
}
}allow_actions 改成 true,才允许启动 / 点击 / 输入 / 按键。
两个坑,都踩过:
- 改完必须重启桌宠。
computer_use和mcp_server不在热生效列表里 (热生效只有a2a/game/lip_sync/llm_gate)。 - 改之前先退出桌宠。 桌宠运行期间会把自己内存里的整份 config 异步写回文件 (缩放、设置保存等动作都会触发),手改的键会被覆盖回去。
MCP 连接器在 Hanako 里是两级开关:host 级 + agent 级。只开 host,
桌宠虽然显示 running、toolCount 也是 21,但工具进不了 agent 的工具索引,
调用会报「未找到工具」。开到 agent 级后,Hanako 会弹一张授权卡,
确认之后工具才真正可用。
| 只读(默认可用) | 写(需 allow_actions: true) |
|---|---|
pet_computer_status 驱动 / daemon 状态 |
pet_computer_launch 启动应用 |
pet_computer_apps 列出应用 |
pet_computer_click 点元素 / 坐标 |
pet_computer_windows 列出窗口 |
pet_computer_type 输入文字 |
pet_computer_window_state 读窗口 UIA 元素树 |
pet_computer_key 按键 |
- 自绘界面读不到内容。 QQ、部分 Electron 应用把整个窗口画成一块画布,
UIA 树里只有一个空
Document节点,pet_computer_window_state拿不到文字; 这类应用只能靠它一并返回的窗口截图来「看」。 pet_computer_window_state的返回会带一张窗口截图(base64), 在元素多 / 窗口大的应用上体积可能到 MB 级。- 写操作默认走后台 UIA Invoke(不抢焦点);坐标点击是元素句柄缺失时的回退。
- 这套能力能点到你桌面上任何东西——默认关是有意的,不是没做完。
| 功能 | 测试方法 | 预期效果 |
|---|---|---|
| 拖拽 | 左键拖动桌宠 | 桌宠跟随鼠标移动 |
| 边缘吸附 | 拖到屏幕边缘 | 桌宠坐下 |
| 鼠标跟随 | 鼠标靠近桌宠 | 桌宠视线跟随 |
| 窗口互动 | 切换前台应用 | 桌宠走过去 |
| 屏幕感知 | 等 2 分钟 | 日志显示 Screen analysis: ... |
| 叙事引擎 | 等 10 分钟 | 桌宠自言自语 |
| 聊天 | 左键点击桌宠 | 弹出聊天框 |
| 设置 | 右键菜单 → 设置 | 打开设置面板 |
| 手机感知 | MacroDroid POST 到 localhost:8077 | 日志显示 Phone activity: app=小红书 event=switch |
| 掌心窗状态 | Hanako 对话中调用 phone_status |
返回服务在线状态 |
PetManager(多桌宠管理器)
├─ PetWindow[<character>] ── ConversationEngine ── HanakoPetAdapter (LLM)
│ ├─ SpriteRenderer (精灵渲染)
│ ├─ MouseTracker (鼠标交互)
│ ├─ PerceptionController (感知)
│ │ ├─ ScreenWatcher (屏幕感知)
│ │ ├─ PhoneActivityPerception (手机活动)
│ │ ├─ PhoneActivityReceiver (MacroDroid HTTP)
│ │ ├─ ProactiveScheduler (主动对话)
│ │ └─ EmotionStateMachine (情绪)
│ ├─ NarrativeEngine (叙事引擎)
│ ├─ WindowInteraction (窗口互动)
│ ├─ Bubble (对话气泡)
│ └─ PluginPanel (插件面板)
└─ SettingsDialog (设置)
├─ LLM/TTS/ASR Provider 选择
├─ Agent 管理
└─ 记忆/行为/日程配置
oc-pet/
├── main.py # 入口
├── pet_manager.py # 多桌宠管理
├── pet.py # 单桌宠窗口(主逻辑)
├── config.py # 配置管理
├── env_config.py # .env 配置
├── core/ # 核心模块
│ ├── conversation_engine.py # 对话引擎
│ ├── harness_adapter.py # LLM 适配器(Hanako / 直连双通道)
│ ├── hana_client.py # Hanako HTTP 客户端(读状态/会话/agent/app)
│ ├── mcp_server.py # 内置 MCP server(21 个 pet_* 工具)
│ ├── computer_use_bridge.py # 电脑操作桥(窗口枚举/点击/输入)
│ ├── hanako_session_manager.py # Hanako 会话管理(流式聚合)
│ ├── emotion_classifier.py # 情绪分类器(embedding 近邻 + VAD)
│ ├── capability_snapshot.py # 能力快照(模型/动作/预设扫描)
│ ├── perception.py # 感知系统(时间/情绪/屏幕/手机/主动对话)
│ ├── phone_activity.py # 手机活动数据管理 + 感知层
│ ├── phone_receiver.py # MacroDroid HTTP 接收器
│ ├── narrative_engine.py # 叙事引擎
│ ├── window_interaction.py # 窗口互动
│ ├── hanako_bridge.py # Hanako 联动(状态读取)
│ ├── hanako_monitor.py # Hanako 监控(TODO/通知/回复)
│ ├── multi_pet_bridge.py # 多桌宠协作(事件通信)
│ ├── tool_registry.py # 工具注册表
│ ├── tool_executor.py # 工具执行器
│ ├── hanako_context.py # 上下文构建
│ └── memory_snapshot.py # 记忆快照
├── ui/ # UI 模块
│ ├── settings_dialog.py # 设置面板
│ ├── plugin_panel.py # 插件面板
│ └── bubble.py # 对话气泡
├── avatar/ # 精灵渲染
│ └── sprite_renderer.py
├── motion/ # 运动系统
│ ├── physics.py # 物理引擎
│ ├── behavior.py # 行为状态机
│ └── foreground_watcher.py # 前台窗口监听
├── tts_provider/ # TTS 引擎
├── asr_provider/ # ASR 引擎
├── characters/ # 内置角色
│ ├── miku/ # Miku(占位,模型自备)
│ ├── Rory/ # Rory(本地角色包,模型自备,不入库)
│ └── sample_live2d/ # 免费示例模型(Haru 等)
└── requirements.txt # 依赖列表
Live2D 模型不进仓库:
characters/*/live2d/*已在.gitignore中排除 (版权原因)。克隆后只有profile.json(参数映射配置), 模型需自己放或跑tools/fetch_free_live2d_sample.py。 这也是 CI 上部分资产测试会skip而不是失败的原因。
把桌宠打成免 Python 环境的独立目录,发给别人直接跑。
# 1) 装构建依赖(**不是** requirements.txt)
pip install -r requirements-build.txt
pip install pyinstaller
# 2) 构建
pyinstaller oc_pet.spec
# 3) 产物
# dist/oc_pet/oc_pet.exe ← 双击运行
# 整个 dist/oc_pet/ 目录要一起发,不能只发 exe| 内容 | 产物体积 | |
|---|---|---|
requirements.txt |
完整(含 torch 4.2GB / onnxruntime 748MB) | 650MB+ |
requirements-build.txt |
精简(核心功能 + 有降级路径的可选件) | 显著更小 |
被砍掉的每一项都有代码级降级路径(import 在 try/except 内):
| 砍掉 | 后果 |
|---|---|
openai-whisper → torch |
本地 ASR 降级 faster-whisper(CPU) |
onnxruntime |
记忆召回降级纯 BM25 |
cosyvoice / funasr |
TTS 降级 Edge(默认引擎,不受影响) |
用户想补回时,把包装到产物的 _internal/ 下,或直接源码运行。
oc_pet.spec 里显式排除了 628MB 的无关 Qt DLL(QtWebEngineCore 单个就 195MB)。
原则:只排代码里零 import 且不被已用模块间接依赖的。已用模块的依赖链不能碰:
QtWidgets → QtGui → QtCore
QtMultimedia → QtNetwork / ffmpeg(avcodec 等)
QtOpenGLWidgets → QtOpenGL / QtGui
.github/workflows/build.yml:打 v* tag 时自动构建并创建 GitHub Release。
完整发版流程(三步):
# 1) 改版本号:version.py 的 __version__ / BUILD_DATE / BUILD_NUMBER
# 2) 在 CHANGELOG.md 顶部新增一节(写清本版改了什么)
git add version.py CHANGELOG.md
git commit -m "release: v0.15.0 —— …"
git push origin master
# 3) 打 tag 并推送 —— 这一步才触发构建
git tag -a v0.15.0 -m "v0.15.0 — …"
git push origin v0.15.0注意:普通
push到 master 不会触发打包,只跑测试(test.yml)。 发版必须推 tag —— 只推 commit 的话,源码更新了但 Release 不会出现。
CI 在干净环境用
requirements-build.txt从零构建(不依赖你的本机 环境),所以它构建成功 = 别人 clone 也能构建成功。
- ✅ 全量测试绿:
python -m pytest tests/ -q - ✅ 在干净环境验证过:依赖
config.json/ Live2D 模型的测试会skip,不应报错 - ✅ Live2D 模型不会进产物(除非你自己放
characters/<角色>/live2d/)
A: 检查 LLM API 配置。桌宠会自动使用 Hanako 的配置,如果 Hanako 没配置,需要在 .env 中指定。
A: TTS 是可选功能,不影响文字对话。在设置面板切换 TTS 引擎。
A: 当前版本屏幕感知只触发情绪,不触发主动对话。主动对话由 ProactiveScheduler 根据空闲时间和前台窗口触发。
A: 在设置面板的"角色包"中添加,或在 ~/.hanako/agents/ 下创建新的 agent 目录。
A: 1) 手机安装 ntfy app(Android/iOS);2) 订阅一个 topic;3) 在 .env 中配置 NTFY_TOPIC=your-topic。
本项目在架构设计与技术方案上参考了以下开源项目:
- Code-Amadeus / Amadeus — 实时多模态桌面 Agent。oc-pet 的 Live2D 渲染架构、HUD 设计语言、情感驱动参数体系均以此为参照。
- Soullink Emotion SDK — TypeScript / MIT。Embody 层(情绪→参数映射抽象)的设计思想来源,未集成 SDK 本体,以 Python 独立重写。
- Live2D CubismWebSamples — Live2D 官方免费示例模型(Haru / Hiyori 等),可直接下载使用。
- Hanako — AI 助手框架。桌宠的对话、记忆、工具调用、多助手协作均复用 Hanako 配置。
- N.E.K.O. — Apache 2.0。主动对话决策管线、情绪状态机设计语言等参考来源。
感谢以上项目的开源贡献。
本项目采用双重许可:
- 开源许可:GNU AGPL v3 — 开源免费,但修改必须开源
- 商业许可:闭源使用需购买商业授权,详见 COMMERCIAL-LICENSE.md