:实现微信、QQ提示音接管与 OpenCode 联动桌面宠物开发实录
桌面宠物开发实录实现微信、QQ提示音接管与 OpenCode 联动文章目录桌面宠物开发实录实现微信、QQ提示音接管与 OpenCode 联动摘要一、场景切入我想要的不是挂件而是嵌入生活的角色二、总体架构一个进程四条线程三、原理拆解与关键实现3.1 精灵图动画一图多动作配置驱动3.2 声音引擎场景 → 文件映射多通道播放3.3 核心难点WASAPI 只读监听实现提示音接管3.4 定时提醒与日程调度线程 SQLite3.5 OpenCode 联动内嵌 FastAPI信号桥接线程配置提示关键实现四、项目结构速览五、总结摘要本文分享一个 PyQt5 桌面宠物的完整实现不碰任何第三方文件用 pycaw / WASAPI 对音频会话做只读轮询配合状态机降误报在微信响起的瞬间播放自定义语音叠加 / 软替换双模式同时内嵌 FastAPI 服务接入 opencode-im-notifier 插件任务完成时弹窗并播任务完成语音。文章围绕精灵动画、声音引擎、音频监听、定时调度、OpenCode 联动五个子技术点展开以低资源占用、高体验为设计取舍只保留关键实现与可复用代码。一、场景切入我想要的不是挂件而是嵌入生活的角色做桌宠的初衷很简单把自己喜欢的动漫角色放进电脑里。但是又不希望只是一张会动的图片——真正的期待是角色**活在工作环境里**来消息时开口提醒到点催喝水任务跑完击掌提醒等。市面上的桌宠大多是个挂件用法有限主要是一个会动的背景板接不了微信/QQ 提示音也感知不到你的开发任务热闹一阵就沦为桌面角落的装饰。资源占用为变现塞满广告白白吃掉大量内存和 CPU——为了一点可爱付出卡顿的代价本末倒置。于是我把目标定为三个① 一个可自定义、会卖萌的精灵图桌宠把喜欢的角色请进电脑② 微信/QQ 来消息时播自定义语音“接管提示音——角色真的会说话”③ opencode 任务完成时主动通知——角色见证你的工作而不是在旁边发呆。一句话概括这条主线低资源占用 高用户体验让桌宠从挂件变成嵌入生活的工具。下面按原理拆解 → 关键实现记录这条路。首先效果展示气泡效果如图所示功能详情如图所示二、总体架构一个进程四条线程项目是单进程多线程PyQt5 事件循环为主干三个守护线程各自干活通过Qt 信号Signal回主线程更新 UI天然线程安全。为守住低资源占用这条底线三个守护线程全部做成事件驱动音频轮询 0.25s 一次、调度每秒一次、OpenCode 服务惰性导入——平时几乎不占 CPU只在关键时刻向主线程发信号让资源让位给体验。线程职责与主线程通信主线程精灵动画、气泡、提醒 UI、托盘—SchedulerManager每秒扫 SQLite查到期提醒remind_signalAudioWatcher0.25s 轮询 WASAPI 会话notify_signalOpenCodeHook内嵌 FastAPI 服务收通知hook_signal┌──────────────────── 主线程UI ────────────────────┐ │ FloatingBall 精灵动画 / 气泡 / 提醒卡片 / 托盘 │ │ │ │ │ │ │ SoundEngine(声音) SchedulerManager AudioWatcher │ │ │ (定时调度) (音频监听:pycaw) │ │ │ │ │ │ │ OpenCodeHook ◄── 内嵌FastAPI ◄── opencode-im-notifier│ └────────────────────────────────────────────────────┘代码量分布也说明主线floating_ball.py是躯干其余模块各司其职。下面按五个子技术点拆解。三、原理拆解与关键实现3.1 精灵图动画一图多动作配置驱动精灵图是精灵表Sprite Sheetimg/spt.webp共 9 行 × 8 列每格 192×208 像素一行一个动作。帧配置在img/spt.txt格式是每行动作保留的帧数 # 动作描述例如6 # 眨眼待机 8 # 向右跑 4 # 打招呼1 5 # 跳跃这样加新动作只需改文本配置不用动代码。加载时按行裁剪并用keep_cfg截断帧数defload_sprite_sheet(self):imgImage.open(self.sprite_path).convert(RGBA)forrowinrange(self.rows):action_frames[]forcolinrange(self.cols):frameimg.crop((col*self.frame_width,row*self.frame_height,(col1)*self.frame_width,(row1)*self.frame_height))# 剔除几乎全透明的帧动作末尾的空帧alphaframe.getdata(3)ifsum(1forainalphaifa10)len(alpha)*0.005:continue# RGBA 原始字节 → QImage → QPixmapdataframe.tobytes(raw,RGBA)qimageQImage(data,self.frame_width,self.frame_height,QImage.Format_RGBA8888)action_frames.append(QPixmap.fromImage(qimage))ifrowinkeep_cfg:# 按 spt.txt 截断保留帧数action_framesaction_frames[:keep_cfg[row]]self.all_actions.append(action_frames)播放是QTimer驱动的两态逻辑switch_action切动作并复位帧号next_frame在乒乓PingPong模式下到边界反向动作更自然loop模式则直接取模循环defnext_frame(self):framesself.all_actions[self.current_action_index]ifself.play_modeloop:# 循环模式self.current_frame_index(self.current_frame_index1)%len(frames)returnnext_idxself.current_frame_indexself.direction# 乒乓模式ifnext_idx0ornext_idxlen(frames):# 到边界折返self.direction*-1next_idxself.current_frame_indexself.direction self.current_frame_indexnext_idx3.2 声音引擎场景 → 文件映射多通道播放语音文件放在voice_tmp/命名约定XX-场景序号.wav。启动时扫描目录按文件名前缀建立场景Scene映射SCENE_ALIASES{消息:msg,提醒:remind,闹钟:alarm,彩蛋:easter,任务完成:done,}新增语音零代码改动丢个XX-任务完成.wav进去就自动归入done场景。播放时从场景池里随机选、尽量不与上次重复并维护多个QMediaPlayer通道实现叠加播放——提醒音不会打断消息音defplay_random(self,key):filesself._scene_files.get(key,[])ifnotfiles:returnNone# 场景无语音 → 静默降级pool[fforfinfilesiff!self._last_played.get(key)]orfiles chosenrandom.choice(pool)self._last_played[key]chosen self.play(chosen)3.3 核心难点WASAPI 只读监听实现提示音接管这是全文最有含金量的一段。原理pycaw 封装了 WASAPIAudioUtilities.GetAllSessions()能拿到每个进程的音频会话会话状态State在响一声时是Inactive → Active → Inactive。难点在于误报微信播放语音消息、语音通话也会使会话变Active。解决思路是状态机 时长阈值 冷却会话变Active记下时间戳若持续超过阈值默认 2s→ 判定为长播放语音/通话本次忽略若在阈值内回到Inactive→ 是一次短提示音触发接管同一会话触发后进入冷却默认 3s避免连续提示音重复连响。def_update(self,name,state,session,now):trself._track.setdefault(name,{active_since:None,decided:False,last_trigger:0.0})ifstate_SESSION_ACTIVE:iftr[active_since]isNone:# 提示音响起的瞬间tr[active_since]now tr[decided]Falseelifnottr[decided]andnow-tr[active_since]self.sensitivity:tr[decided]True# 超过阈值 → 长播放忽略else:# Inactive → 一次播放结束sincetr[active_since]ifsinceisnotNoneandnottr[decided]\andnow-sinceself.sensitivity \andnow-tr[last_trigger]self.cool_down_s:# 冷却防连响tr[last_trigger]now self._on_notify(name,session,now)# 通知主线程播自定义语音tr[active_since]Nonetr[decided]False接管有两种模式模式行为叠加Overlay保留微信原声在其上额外播自定义语音默认软替换Silent触发瞬间把该会话音量MasterVolume临时置 0播完恢复——不碰文件也能只响自定义音def_mute(self,name,session,now):# 软替换临时静音该应用session.SimpleAudioVolume.MasterVolume0.0self._silenced[name](session,nowself._mute_seconds)def_restore(self,name):# 播完恢复音量volumeself._silenced.pop(name)[0].SimpleAudioVolume volume.MasterVolume1.0选 pycaw 而不用 ctypes 强转 COM 指针是因为 pycaw 内部管理 COM 生命周期能避免常见的_ctypes.pyd崩溃这是踩过坑换来的经验。3.4 定时提醒与日程调度线程 SQLite提醒和日程存 SQLitedata.dbSchedulerManager线程每秒查一次到期项命中就发remind_signalclassSchedulerManager(QThread):remind_signalpyqtSignal(dict)# {title:..., sound_key:..., time:...}defrun(self):whileself._running:self._check(datetime.now())time.sleep(1.0)def_check(self,now):forrinself.db.due_reminders(now):# 查已到期且未触发的项self.remind_signal.emit({kind:reminder,title:r[title],time:r[start_time],sound_key:alarm})self._advance_reminder(r,now)# 触发后推进下一次每日/每周主线程收到信号后播remind场景语音、弹提醒卡片、切打招呼动作。提醒支持一次性 / 每日 / 每周日程有独立日历视图CalendarView管理这里不展开。3.5 OpenCode 联动内嵌 FastAPI信号桥接线程配置提示opencode 用opencode-im-notifier插件把任务完成消息推送到 HTTP 端点桌宠内嵌一个 FastAPI 服务来接。在 opencode-im-notifier 中根据提示配置好文件将飞书的webhook地址替换成后端的地址默认http://127.0.0.1:8992/hook或者见下面的代码复制到~/.config/opencode/opencode-im-notifier.json中{dingtalk:{enable:false},feishu:{enable:true,webhook:http://127.0.0.1:8992/hook},wecom:{enable:false,webhook:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?keyxxx},notifyOn:[idle,permission,question,error],quietHours:{start:22:00,end:08:00},title:我的项目}关键实现OpenCodeHook(QThread)在独立线程里跑uvicorn.Server.run()自带事件循环不阻塞 Qt收到POST /hook后解析消息通过 Qt 信号交回主线程classOpenCodeHook(QThread):hook_signalpyqtSignal(dict)# 线程 → 主线程的桥defrun(self):appbuild_app(self._handle_payload)# POST /hook 端点serveruvicorn.Server(uvicorn.Config(app,hostself.host,portself.port,log_levelwarning))server.run()def_handle_payload(self,payload):parsedparse_opencode_payload(payload)# 从卡片消息里提取标题/正文self.hook_signal.emit(parsed)主线程收到信号就弹完成卡片、播done场景语音如银月-任务完成.wav、切打招呼动作def_on_opencode_hook(self,parsed):self.sound.play_random(done)# 任务完成语音self.card.show_card(parsed[title],subtitleparsed[body],anchorself)idxself._find_action(打招呼1)orself._find_action(打招呼2)ifidxisnotNone:self.play_action(idx,notifyFalse)细节fastapi/uvicorn惰性导入——没装依赖时线程直接退出并提示不影响桌宠本体端口被占用如调试用的test.py仍开着也会优雅降级。这是低侵入设计哲学的延续。四、项目结构速览VoxNotify/ ├── main.py # 入口 ├── floating_ball.py # 桌宠主体动画/交互/气泡/提醒 ├── audio_watcher.py # WASAPI 音频监听核心语音接管 ├── sound_engine.py # 声音引擎场景映射 多通道播放 ├── opencode_hook.py # OpenCode 联动内嵌 FastAPI ├── schedule_manager.py # 定时调度线程 ├── reminder_dialog.py # 定时提醒 UI ├── calendar_view.py # 日程日历 UI ├── database.py # SQLite 数据层 ├── bubble_widget.py # 气泡 / 提醒卡片无边框置顶 ├── config.py config.json ├── logger.py # 统一日志轮转文件 ├── img/ # 精灵图 spt.webp 帧配置 spt.txt └── voice_tmp/*.wav # 场景语音消息/提醒/彩蛋/任务完成项目源码地址五、总结回头看这个桌宠在我这里已经不再是一个挂件——会提醒、会恭喜、会在角落陪着你干活真正嵌进了日常的工作流。如果你也在做类似的桌宠 / 通知工具希望我的实现思路能给你一定的灵感。后续可做的方向打包成单 exePyInstaller、声音文件按主题分类、精灵图增加更多动作帧。增加精灵图和声音替换的用户体验等等这只是我的一个想法的初步样子后续还有待探索。

相关新闻

Windows端口检查全攻略:从netstat到PowerShell实战排查

Windows端口检查全攻略:从netstat到PowerShell实战排查

1. 项目概述:为什么你需要掌握端口检查在Windows环境下折腾网络应用、部署服务或者排查连接故障时,你大概率会遇到一个经典问题:“我的程序明明启动了,为什么就是连不上?”或者“这个端口到底被谁占用了?”…

2026/8/16 2:57:50 阅读更多 →
【每周分享】详解MCU编译生成的map文件,原来这么多内容

【每周分享】详解MCU编译生成的map文件,原来这么多内容

临近放假,得空研究了一下MCU编译生成的map文件,之前主要是通过这个文件查看RAM和Flash的使用情况,其他的内容倒是没怎么仔细去关注,最近研究了一下,与大家分享。以Keil编译为例,在工程指定的文件夹下面&…

2026/8/16 2:57:49 阅读更多 →
解决AutoCAD双击DWG文件提示“找不到acad.exe”的终极修复指南

解决AutoCAD双击DWG文件提示“找不到acad.exe”的终极修复指南

1. 问题现象与根源剖析“双击DWG文件,Windows弹窗提示‘找不到xxx.acad.exe’”,这个报错对于依赖AutoCAD进行日常工作的设计师、工程师来说,无异于当头一棒。它粗暴地中断了你的工作流,让你面对急需打开的图纸文件束手无策。我遇…

2026/8/16 2:57:49 阅读更多 →

最新新闻

ArcGIS管网数据生产实战:从表格到拓扑完整流程

ArcGIS管网数据生产实战:从表格到拓扑完整流程

1. 项目概述:从零到一构建管网空间数据在市政、水利、石油化工乃至园区管理的日常工作中,我们常常会遇到一个基础但繁琐的任务:将一堆只有坐标和属性的表格数据,比如阀门位置、水表读数、管线材质规格,变成一张能在GIS…

2026/8/16 3:59:10 阅读更多 →
Go语言钉钉机器人插件ddingtalk实战:从入门到生产级告警系统构建

Go语言钉钉机器人插件ddingtalk实战:从入门到生产级告警系统构建

1. 项目概述与核心价值最近在折腾一个内部告警通知系统,需要把各种服务日志、监控告警实时推送到团队群里。市面上现成的方案要么太重,要么定制化不够灵活。直到我发现了largezhou/ddingtalk这个 OpenClaw 插件,它专门用于深度集成钉钉机器人…

2026/8/16 3:59:10 阅读更多 →
Linux上安装FFmpeg

Linux上安装FFmpeg

FFmpeg 是一套处理多媒体文件的软件。凭借这些强大的库,FFmpeg 能够转换格式、推流以及处理音频和视频文件。许多 Linux 的前端应用都使用 FFmpeg 作为后端支持,所以这些应用对 FFmpeg 的依赖度非常高。举个例子,录屏软件可能会用到 FFmpeg 将…

2026/8/16 3:59:10 阅读更多 →
LeetCode AI助手:苏格拉底式引导与面试模拟提升算法思维

LeetCode AI助手:苏格拉底式引导与面试模拟提升算法思维

这次我们来看一个专门为 LeetCode 刷题和面试准备设计的浏览器扩展工具。它不是一个需要本地部署的 AI 模型,而是一个直接集成在浏览器侧边栏的智能助手。核心功能非常直接:在你刷 LeetCode 时,它能在旁边提供苏格拉底式的引导提示&#xff0…

2026/8/16 3:58:09 阅读更多 →
云原生AI助手深度对比:AWS Q、Azure Copilot与国内CloudQ如何选型

云原生AI助手深度对比:AWS Q、Azure Copilot与国内CloudQ如何选型

1. 从“云原生AI助手”的混战说起:我们到底需要什么?最近几个月,云服务商在AI领域的动作密集得让人眼花缭乱。先是AWS在re:Invent大会上正式推出AWS Q,紧接着微软的Azure AI Studio和Azure Copilot也动作频频,而国内各…

2026/8/16 3:57:09 阅读更多 →
OpenClaw与Deepgram构建自动化语音转录工作流实战

OpenClaw与Deepgram构建自动化语音转录工作流实战

1. 项目概述:当笔记工具遇上语音智能最近在折腾一个挺有意思的自动化流程:把语音笔记自动转录成文字。核心工具是 OpenClaw 和 Deepgram。OpenClaw 你可能听说过,它是一个开源的、功能强大的自动化工作流平台,可以连接各种应用和服…

2026/8/16 3:57:09 阅读更多 →

日新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/16 0:00:54 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/16 0:00:55 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/16 0:03:55 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/16 0:00:54 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/16 0:00:55 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/16 0:03:55 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/14 13:40:53 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/14 14:06:45 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/15 2:35:29 阅读更多 →