Skip to content
openhanako-labsPublic

About

OC桌面宠物 - 基于PySide6的透明桌面宠物,支持AI对话与帧动画

Resources

Contributing

Security policy

Stars

4 stars

Watchers

0 watching

Forks

Latest commit

 

History

529 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OC Desktop Pet

License: AGPL v3

⚠️ Live2D 模型版权说明

本项目不随仓库分发任何 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 联动

  • 🔗 状态监控 -- 实时读取 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 工具(桌宠反过来被 AI 调用)

桌宠内置一个 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 增大缓冲)。

1. 创建虚拟环境并安装依赖

# 推荐:创建 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 分钟空闲 → 桌宠主动找你说话
  • 🖱️ 左键拖动桌宠,释放后弹跳
  • 📌 拖到屏幕边缘 → 桌宠坐下

2. 确保 Hanako 已安装

桌宠从 Hanako 读取:

  • ~/.hanako/agents/<agent>/ - 身份、意识、记忆、模型配置
  • ~/.hanako/provider-catalog.json - API 地址、密钥、模型列表

不需要单独配置 API,自动复用 Hanako 的。

3. 下载 Live2D 模型(首次)

桌宠不随仓库分发 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 素材文件?"

4. 启动

python main.py

或双击 start_pet.bat。

首次启动由引导流程选择角色包(默认无内置模型,需自行提供)。以 miku 占位角色为例: 把官方/有许可的 Live2D 模型放入 characters/miku/live2d/,再把 config.json 的 character 改为 miku 即切换为 Live2D 桌宠;其他角色同理。


引导教程:从零到能聊天

下面是一条最短可用路径。每步都有「做对了会看到什么」,卡住时按这个对。

第 0 步:先确认 Hanako 活着

桌宠是壳,灵魂在 Hanako。先跑:

# 看 Hanako 服务在不在(默认端口 20099)
curl http://127.0.0.1:20099/api/health
  • ✅ 返回 JSON(含 user 字段,就是你的名字)→ 继续
  • ❌ 连接被拒 → 先启动 Hanako,否则桌宠只能用降级对话

第 1 步:确认桌宠读到了身份

启动桌宠后看日志,应该出现:

[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) 决定说话的是谁。桌宠本身没有人设,用的是助手的人设。

第 2 步:确认对话链路通

左键点桌宠 → 弹出聊天框 → 发一句「你好」。

  • ✅ 气泡出字 + (若开了 TTS)有声音
  • ❌ 一直「思考中」→ 看日志有没有 LLM 401(凭证失效)或 连不上(网络);改 .env 或重登 Hanako

第 3 步:确认表情/动作真的生效

这是**最容易「看着像对但其实是死的」**的一环。发一句带情绪的话, 然后看日志:

[DECISION] emotion: happy (src=...)
[DECISION] expression: 脸红 (src=exact:happy)
Live2DRenderer: 播放动作 idx=2(motions/waving.motion3.json)
  • ✅ 三行都在 → 情绪→表情→动作链路通
  • ❌ 只有 emotion 没有 expression → 模型的表情名不匹配, 查 characters/<角色>/live2d/profile.json 的映射
  • ❌ no-match → 表情名/情绪名搞混了(工具收表情名, 内部映射收情绪名)

第 4 步:接 MCP(可选,但推荐)

想让 Hanako 反过来驱动桌宠(比如让 AI 主动让桌宠比个心):

  1. 确认桌宠的 MCP server 起来了:
    curl http://127.0.0.1:8979/mcp
  2. 在 Hanako 的 MCP 连接器配置里加 oc-pet,指向上面这个地址
  3. 重启 Hanako
  4. 把连接器授权到 agent 级(只在 host 级打开不够),确认弹出的工具授权卡
  • ✅ Hanako 能看到 21 个 pet_* 工具
  • ❌ 连不上 → 顺序问题:Hanako 比桌宠先起,且不会自动重试。 先开桌宠,再开 Hanako。
  • ❌ 连接器显示 running、toolCount=21,但调用报「未找到工具」→ 授权层级问题:host 级开着、agent 级没开。见下方「电脑操作」第 4 节。

第 5 步(可选):语音

想要 做什么 代价
免费、秒级、免注册 设置 → TTS → Edge TTS 需联网
本地克隆音色 见上方「本地 CosyVoice TTS 部署」 需 NVIDIA 显卡,8–10 秒/句
语音输入 设置 → ASR → Whisper 本地 首次下载模型

卡住了看哪里

症状 先看
桌宠不说话 .env 的 LLM_*;Hanako 是否在跑
人格不对 日志 Agent identity injected (…, agent=?)
桌宠记忆串了 日志 [session] … session=?,是否与预期一致
表情/动作不动 [DECISION] expression: 那行有没有
MCP 连不上 启动顺序(桌宠 → Hanako)

本地 CosyVoice TTS 部署(从零)

桌宠默认用本地 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 即可。如需手动分步,见下方。

手动分步

  1. 获取代码:把 cosyvoice-tts(含 src/ 与 models/)放到 oc-pet 同级目录, 或在 .env 设置 OC_PET_COSYVOICE_DIR 指向它。
  2. 装环境(关键: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
  3. 下载模型(约 4.6GB):
    .venv_cosy\Scripts\python scripts/download_cosyvoice_model.py
  4. 在 .env 写入 OC_PET_COSYVOICE_DIR 与 OC_PET_COSYVOICE_PYTHON (引导脚本会自动写;手动装则需自己加)。

配置项(.env)

变量 说明 默认
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 即可。

配置说明

config.json

{
  "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                  // 截图模糊(隐私保护)
  }
}

.env 文件

# 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 配置(手机活动上报)

  1. 安装 MacroDroid(Android)
  2. 创建新宏:触发器 = "应用启动/切换" → 动作 = "HTTP 请求"
  3. HTTP 请求配置:
    • 方法:POST
    • URL:http://<电脑IP>:8077/phone/activity
    • Header:X-Auth-Token: <你的token>
    • Body:{"app": "{app_name}", "event": "switch"}
  4. 保存并启用宏

💡 如果桌宠和手机在同一局域网,用电脑的内网 IP。如果需要外网访问,考虑用 ngrok 或 frp 做内网穿透。

电脑操作(Computer Use,可选)

桌宠除了被 AI 驱动着表演,还能当 AI 的手:枚举窗口、读元素树、启动应用、 点击、输入、按键。执行侧由独立的 cua-driver(trycua/cua,MIT) 完成,桌宠只做代理——所以桌宠本身不碰键盘鼠标,能力的边界和权限都归 cua-driver 管。

⚠️ 写操作(启动 / 点击 / 输入 / 按键)默认关闭。打开就等于把桌面交给 AI, 请确认你知道自己在开什么。

1. 安装 cua-driver(一次性)

它不是 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

2. 让 daemon 跑起来

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)—— 不想要常驻后台进程,就别开它。

3. 打开写权限

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 异步写回文件 (缩放、设置保存等动作都会触发),手改的键会被覆盖回去。

4. Hana 侧要授权到 agent 这一层

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 而不是失败的原因。

打包发布(PyInstaller)

把桌宠打成免 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-build.txt

内容 产物体积
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/ 下,或直接源码运行。

Qt 模块裁剪

oc_pet.spec 里显式排除了 628MB 的无关 Qt DLL(QtWebEngineCore 单个就 195MB)。 原则:只排代码里零 import 且不被已用模块间接依赖的。已用模块的依赖链不能碰:

QtWidgets → QtGui → QtCore
QtMultimedia → QtNetwork / ffmpeg(avcodec 等)
QtOpenGLWidgets → QtOpenGL / QtGui

CI 自动构建

.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/)

常见问题

Q: 桌宠不说话?

A: 检查 LLM API 配置。桌宠会自动使用 Hanako 的配置,如果 Hanako 没配置,需要在 .env 中指定。

Q: TTS 不工作?

A: TTS 是可选功能,不影响文字对话。在设置面板切换 TTS 引擎。

Q: 屏幕感知不触发主动对话?

A: 当前版本屏幕感知只触发情绪,不触发主动对话。主动对话由 ProactiveScheduler 根据空闲时间和前台窗口触发。

Q: 如何添加更多桌宠?

A: 在设置面板的"角色包"中添加,或在 ~/.hanako/agents/ 下创建新的 agent 目录。

Q: ntfy 通知怎么用?

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。主动对话决策管线、情绪状态机设计语言等参考来源。

感谢以上项目的开源贡献。

许可

本项目采用双重许可:

About

OC桌面宠物 - 基于PySide6的透明桌面宠物,支持AI对话与帧动画

Resources

Contributing

Security policy

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages