Files
Qt_DesktopPet/docs/QtDesktopPet_后续功能规划与结构审查.md
T

30 KiB
Raw Blame History

QtDesktopPet 后续功能开发与当前结构审查文档

适用仓库:https://git.emoera.com/Make/Qt_DesktopPet
目的:在继续新增功能前,先收口当前结构风险,并为后续功能扩展确定统一入口和实现边界。
注意:本文档不是让 Codex 一次性实现所有功能,而是作为后续开发路线和代码审查依据。


1. 当前项目状态概览

根据当前 README 和仓库结构,项目已经具备较完整的桌宠应用基础:

  • 透明无边框桌宠窗口
  • 鼠标拖动、置顶、右键菜单
  • 托盘显示、隐藏、退出
  • 单实例限制
  • PNG 序列帧动画播放
  • idle / talk / think / sleep / happy / drag / error 多状态动画
  • 隐藏时暂停动画,显示时恢复
  • 窗口位置、置顶、缩放、性能设置保存
  • 文件日志和日志轮转
  • AI Provider 分组配置
  • OpenAI Compatible 聊天请求
  • Google Gemini 原生聊天请求
  • SSE 流式输出
  • AI 回复气泡
  • 聊天输入框
  • 对话历史面板
  • 本地历史保存和历史上限
  • AI 请求取消和对话清空
  • 角色文件夹导入和角色切换
  • 删除用户导入角色
  • 本地一次性/重复提醒、提醒列表、取消提醒和到点通知
  • 内置/用户提醒音效切换、导入、删除和试听
  • 天气查询、默认城市、公网 IP 定位兜底和多候选提示
  • 本地文件操作安全入口:读取文本、列目录、复制、备份、重命名
  • 联网模式:输入框开关、OpenAI/Gemini 原生联网、DeepSeek/Custom 不支持提示
  • 本地应用启动:登记应用、开始菜单 / App Paths 发现、手选 .exe 和二次确认
  • Windows 打包脚本和 Inno Setup 安装器脚本
  • Release exe 双击不弹控制台窗口

项目已经从早期 MVP 进入到“可扩展桌面应用原型”阶段,可以开始规划工具能力扩展。

但是,在正式加入定时提醒、天气、本地文件操作、联网模式之前,建议先做一轮结构收口。


2. 当前需要优先审查或优化的地方

2.1 审查角色切换是否保存后立即生效

当前已经支持角色导入和角色切换。经当前测试确认:

设置页选择新角色
保存设置
当前桌宠窗口是否立即重新加载新角色包

结论:保存后会立即切换,不依赖重启。

当前代码路径:

PetWindow::openSettingsDialog()
↓
applyAppConfig(dialog.appConfig())
↓
PetWindow::applyAppConfig() 比较旧 characterId 与新 characterId
↓
characterId 变化时停止当前动画并调用 loadCharacterPackage()
↓
loadCharacterPackage() 重新构建动画状态并从 idle 状态开始播放

后续不需要围绕 2.1 做修复,只需要保留为回归检查项:

设置页切换角色后点击保存,桌宠应立即显示新角色
不需要关闭或重启程序
切换后动画状态应可继续正常播放

2.2 不要继续向 PetWindow 堆功能

目前 PetWindow 已经承担了过多职责,后续不能继续把所有新功能塞进去。

PetWindow 应该主要负责:

窗口显示
拖动
菜单
子组件组织
基础 UI 信号转发

不建议继续负责:

提醒解析
天气查询
联网模式
本地文件读写
AI 工具调度
复杂业务状态管理

后续应逐步拆出:

ChatController
ReminderController
WeatherController
FileOperationController
ToolCommandDispatcher

即使暂时不大规模重构,也至少要为后续功能增加统一调度层,不要直接把新逻辑写进 PetWindow::submitChatMessage()


2.3 新增 IntentRouter / CommandDispatcher

后续功能包括:

定时提醒
天气查询
本地文件操作
联网模式
本地应用启动
普通 AI 对话

这些都来自用户输入框。如果没有统一入口,逻辑会混乱。

可拆成两个模块:

src/intent/
 ├── IntentTypes.h
 ├── IntentRouter.h
 └── IntentRouter.cpp

src/command/
 ├── CommandDispatcher.h
 └── CommandDispatcher.cpp

当前阶段已选择合并为一个轻量模块:

src/assistant/
 ├── UserIntent.h
 ├── IntentRouter.h
 ├── IntentRouter.cpp
 ├── CommandDispatcher.h
 └── CommandDispatcher.cpp

当前意图枚举:

enum class UserIntentType
{
    Chat,
    Reminder,
    Weather,
    FileOperation,
    LaunchApp
};

建议入口流程:

用户输入
↓
IntentRouter 判断意图
↓
CommandDispatcher 分发
↓
ReminderManager / WeatherManager / FileOperationManager / WebChatManager / AppLaunchManager / ConversationManager

第一版意图识别不需要复杂,规则优先即可。


2.4 意图优先级建议

多个意图可能同时出现,需要固定优先级。

推荐:

Reminder > FileOperation > Weather > LaunchApp > Chat/WebChat

原因:

“明天早上提醒我看天气”
虽然包含“天气”,但本质是提醒。

“把天气截图保存到桌面”
可能是文件操作,而不是单纯天气查询。

“搜索一下明天天气”
新版不再作为独立搜索工具处理;如果已有 WeatherTool,应优先走天气工具,否则按普通聊天或输入框联网开关进入 Chat/WebChat。

2.5 检查 CMAKE_AUTOMOC 设置

如果后续新增的 Manager 使用 QObjectsignalsslots,建议开启:

set(CMAKE_AUTOMOC ON)

如果继续保持 CMAKE_AUTOMOC OFF,则后续模块应避免 Q_OBJECT,全部使用普通 C++ 回调或现有信号体系。

建议明确选择一种:

方案 A:开启 AUTOMOC,后续工具模块正常使用 QObject 信号槽
方案 B:保持 OFF,后续模块不得引入 Q_OBJECT

当前阶段选择方案 B:继续保持 CMAKE_AUTOMOC OFF,新增意图分发模块使用普通 C++ 类和同步返回值,不引入 Q_OBJECT

后续如果 Reminder / Weather / WebChat 等模块需要大量跨对象异步信号,再单独评估是否切换到方案 A。


2.6 README 与实际功能保持同步

当前 README 已经比较完整,但后续每实现一个功能,应同步更新:

当前状态
配置说明
隐私说明
日志说明
用户数据目录
发布包包含内容

尤其是以下功能需要额外说明:

提醒数据保存位置
天气 API 请求说明
IP 定位隐私说明
本地文件操作权限说明
联网模式来源和隐私说明

2.7 继续保持角色导入安全策略

当前角色导入已经有较多安全边界,比如:

只导入本地文件夹
验证失败不复制
角色 id 安全字符限制
内置角色不能被覆盖
只允许删除用户导入角色
状态路径安全检查

后续本地文件操作模块也应该沿用这种风格:

路径必须安全
不允许任意系统目录
危险操作必须确认
修改前备份
删除必须二次确认

3. 后续功能总路线

建议不要一次做完所有功能,按以下顺序推进:

阶段 0:结构收口
阶段 1:定时提醒
阶段 2:天气查询
阶段 3:本地文件操作
阶段 4:联网模式
阶段 5:语音对话 / 更复杂 Agent 能力

当前结构收口和定时提醒已经进入实现阶段。下一步最推荐继续做:

1. 天气查询
2. 本地文件操作安全边界
3. 联网模式

4. 阶段 0:结构收口任务

4.1 目标

在正式加新功能之前,先让用户输入有统一分发入口,避免所有功能混进聊天逻辑。

4.2 当前新增文件

src/assistant/UserIntent.h
src/assistant/IntentRouter.h
src/assistant/IntentRouter.cpp
src/assistant/CommandDispatcher.h
src/assistant/CommandDispatcher.cpp

4.3 IntentRouter 职责

判断用户输入属于什么类型:
- 普通聊天
- 定时提醒
- 天气查询
- 本地文件操作
- 联网模式

第一版可以使用规则判断,不依赖 AI。

4.4 CommandDispatcher 职责

接收用户输入
调用 IntentRouter
根据意图分发到不同 Manager
普通聊天才交给现有 ConversationManager / LLMProvider

4.5 PetWindow 改造要求

PetWindow 只负责把用户输入交给 CommandDispatcher,不直接判断业务逻辑。

示例流程:

PetWindow::submitChatMessage()
↓
CommandDispatcher::dispatch(userText)
↓
根据返回信号更新气泡、状态机、历史

不要继续在 PetWindow 中直接写提醒、天气、搜索或文件逻辑。


5. 阶段 1:定时提醒功能

5.1 功能定位

实现本地一次性和基础重复提醒功能。

用户可以输入:

晚上8点提醒我提交作业
明天9点提醒我开会
10分钟后提醒我喝水
半小时后提醒我休息
2小时后提醒我看消息

桌宠创建本地提醒,到点后气泡提示或托盘提示。

当前实现状态:

已新增 src/reminder/ 模块
已支持一次性提醒解析、JSON 持久化、启动后加载、到点触发和状态标记
已支持聊天创建 / 查询 / 取消提醒
已支持设置页按状态查看提醒、取消 pending 提醒、编辑 pending 提醒、清理 20 天前已触发/已取消历史
已支持 reminder_default / reminder_soft 内置音效
已支持用户 wav 音效导入、删除、切换和试听
已限制用户音效删除路径,只允许删除用户音效目录内的安全 sound id
提醒触发时使用当前设置页选择的全局音效,ReminderItem.soundId 仅保留为历史兼容字段
已接入 Qt Multimedia / QSoundEffect 播放提醒音效
已预留 NotificationDispatcher,当前 Windows 仍由托盘通知承接
已支持每天 / 每周 / 每月重复提醒
已支持提醒触发后的“知道了”和“5分钟后再提醒”
已支持提醒数据原子保存
已支持多提醒可见队列,避免同时触发时互相覆盖
已支持 60 秒兜底扫描,覆盖睡眠唤醒、系统时间变化和长间隔 timer 延迟场景
通知后端不可用时会记录日志,不补气泡

5.2 第一版范围

要做:

一次性提醒
每天 / 每周 / 每月重复提醒
本地保存
程序重启后提醒不丢
到点后触发气泡和托盘通知
提醒触发后标记 triggered
支持查询当前提醒列表
支持取消提醒

暂不做:

工作日提醒
自定义间隔重复提醒
农历提醒
复杂日历
跨设备同步
联网日程
语音提醒

5.3 建议目录

src/reminder/
 ├── ReminderTypes.h
 ├── ReminderCommandHandler.h
 ├── ReminderCommandHandler.cpp
 ├── ReminderParser.h
 ├── ReminderParser.cpp
 ├── ReminderManager.h
 ├── ReminderManager.cpp
 ├── ReminderStore.h
 ├── ReminderStore.cpp
 ├── ReminderSoundRepository.h
 ├── ReminderSoundRepository.cpp
 ├── ReminderSoundPlayer.h
 └── ReminderSoundPlayer.cpp

5.4 数据结构建议

struct ReminderItem
{
    QString id;
    QString title;
    QString originalText;
    QDateTime remindAt;
    ReminderStatus status = ReminderStatus::Pending;
    QDateTime createdAt;
    QDateTime finishedAt; // triggered/canceled 记录的完成时间;旧数据缺失时按 remindAt 兼容
    QString soundId; // 历史兼容字段,触发时不再读取
    ReminderRecurrence recurrence;
};

struct ReminderRecurrence
{
    ReminderRecurrenceType type = ReminderRecurrenceType::None; // None / Daily / Weekly / Monthly
    int interval = 1;
    int weekday = 0;   // 1-7,仅 weekly 使用
    int monthDay = 0;  // 1-31,仅 monthly 使用
    int hour = -1;
    int minute = -1;
    QDateTime lastTriggeredAt;
};

5.5 存储文件

保存到:

QStandardPaths::AppConfigLocation/reminders.json

示例:

{
  "reminders": [
    {
      "id": "reminder_001",
      "title": "提交作业",
      "originalText": "晚上8点提醒我提交作业",
      "remindAt": "2026-06-01T20:00:00",
      "status": "pending",
      "createdAt": "2026-06-01T15:20:00",
      "soundId": "",
      "recurrence": {
        "type": "none",
        "interval": 1,
        "weekday": 0,
        "monthDay": 0,
        "hour": -1,
        "minute": -1
      }
    }
  ]
}

旧版 reminders.json 没有 recurrence 字段时按一次性提醒读取,继续兼容;没有 finishedAt 字段时,已触发/已取消历史按 remindAt 作为保留时间兜底。

提醒数据保存使用原子写入。写入失败时创建 / 取消会回滚内存变更,到点触发会保留 pending 并等待下次重试,不播放音效、不通知、不气泡。

历史记录默认只保留最近 20 天。自动清理和设置页“清理20天前历史”只删除超过 20 天的 triggered/canceled 记录,不删除 pending。

配置损坏时备份:

reminders.broken.yyyyMMdd-HHmmss.json

5.6 时间解析策略

第一版规则解析优先,不依赖 AI。

支持:

8点
8点30
20:30
晚上8点
下午3点
明天9点
明天上午10点
后天9点
今天下午3点
6月3日9点
6/3 09:00
下周一上午10点
10分钟后
半小时后
一个半小时后
一小时后
1小时后
两小时后
2小时后
每天9点
每天提醒我9点打卡
每日晚上8点
每周一上午10点
每周一提醒我上午10点周会
每星期五下午3点
每月3号9点
每月3号提醒我9点交报告

如果规则解析失败,后续可以再接 AI 解析。当前重复提醒只支持每天 / 每周 / 每月。包含“工作日 / 每两天 / 每月最后一天 / 每季度 / 农历 / 自定义复杂规则”等语义时,返回明确暂不支持提示,不创建一次性提醒。

5.7 AI 辅助解析的设计边界

可以后续做 AI 辅助解析,但 AI 不允许直接写文件。

正确流程:

AI 解析用户意图
↓
返回结构化 JSON
↓
程序校验
↓
ReminderManager 创建提醒
↓
ReminderStore 保存

禁止:

AI 直接读写 reminders.json
AI 直接修改本地文件

AI 解析时必须由程序提供当前本地时间:

currentLocalTime
timeZone
weekday
userText

因为 API 模型无法可靠知道用户本机时间。

5.8 到点触发

建议行为:

桌宠可见:播放当前全局音效,显示 ChatBubble + 切 happy,无 happy 时回退 talk,不发 Windows 通知
桌宠隐藏:播放当前全局音效,触发 Windows 托盘通知,不在下次显示时补气泡
AI 正在请求或流式回复:按隐藏场景处理,播放当前全局音效并发 Windows 通知,不显示气泡,不进入补气泡队列
Windows 托盘通知后端不可用:记录日志,不补气泡,不进入可见队列
用户拖动中:播放当前全局音效,不打断 drag,拖动结束后显示气泡,不发 Windows 通知
多条提醒同时触发:可见状态下进入队列逐条展示,避免后一条覆盖前一条
桌宠可见触发时显示轻量操作区:“知道了”关闭当前提示,“5分钟后再提醒”固定创建新的 5 分钟一次性提醒
重复提醒触发后先推进下一次 remindAt 并保存;稍后提醒不会影响原重复规则

提醒文案:

到时间啦:提交作业

5.9 给 Codex 的阶段任务

1. 新增 reminder 模块
2. 实现一次性 ReminderItem
3. 实现 ReminderStore JSON 读写
4. 实现 ReminderParser 规则解析
5. 实现 ReminderManager 定时检查
6. 到点后发信号给 UI 层
7. UI 层显示气泡和托盘通知
8. 不要把提醒逻辑写进 PetWindow
9. 不要让 AI 直接写本地文件

6. 阶段 2:天气查询功能

当前天气查询 v1 已进入实现阶段:

  • 已新增独立 src/weather/ 模块
  • 已支持 Open-Meteo 市级城市优先的基础地理编码和基础天气查询
  • 已支持设置页默认城市
  • 已支持默认城市为空时通过公网 IP 定位兜底
  • 已支持当前/今天、明天、后天和未来 1-3 天模板回复
  • 已支持读取前 5 个地理编码候选;多候选时仍查首项,并在回复中提示同名城市风险和其他候选
  • 已支持设置页测试默认城市;测试只展示匹配结果,不自动保存配置
  • 已通过 CommandDispatcher 将 Weather 意图接入聊天入口
  • 已保持 PetWindow 只负责 UI 展示,不承载天气解析或网络逻辑

v1 明确暂不支持:

  • AI 润色天气回复
  • 空气质量
  • 天气预警
  • 天气提醒联动
  • 多天气源切换
  • 小时级精细降雨判断
  • 穿衣指数

默认城市为空且启用公网 IP 定位时,会请求 ipapi.co 判断城市;回复必须说明“根据公网 IP 判断城市”。设置页默认城市和公网 IP 定位都属于非用户明确城市来源,回复必须说明来源。

当前 v1 推荐填写市级城市名;区县、乡镇、街道不保证精确识别,可能无法匹配或被匹配到上级/同名城市。同名城市当前使用天气源返回的第一个结果,并在回复或测试结果中提示其他候选。后续优先补可交互候选选择、区县级定位和国内天气源增强。

6.1 功能定位

天气是独立工具能力,不放进联网模式。

正确流程:

用户问天气
↓
程序识别 Weather 意图
↓
WeatherManager 调用天气 API
↓
拿到结构化天气数据
↓
AI 根据结构化数据自然语言回复

不要让 AI 自己搜索天气,也不要让 AI 自己拼 URL。

6.2 为什么不用联网模式做天气

用联网模式查询天气有几个问题:

结果格式不稳定
摘要可能过期
地区解析不稳定
无法稳定提取温度、降雨、风力、湿度等字段
AI 总结容易出错

天气应该走天气 API。

6.3 第一版范围

要做:

识别天气请求
支持默认城市
支持用户指定城市
支持当前天气
支持简单今天/明天查询
AI 不可用时模板兜底回复
查询中切 think
回复时切 talk
失败时切 error

暂不做:

天气预警
空气质量详情
分钟级降水
生活指数
地图定位
GPS 定位
自动后台推送
天气提醒
多天气源自动切换

6.4 建议目录

src/weather/
 ├── WeatherTypes.h
 ├── WeatherConfig.h
 ├── WeatherStore.h
 ├── WeatherStore.cpp
 ├── WeatherParser.h
 ├── WeatherParser.cpp
 ├── WeatherSummaryFormatter.h
 ├── WeatherSummaryFormatter.cpp
 ├── WeatherManager.h
 └── WeatherManager.cpp

6.5 天气源建议

第一版推荐:

Open-MeteoProvider

优点:

不需要 API Key
全球可用
适合开源项目默认方案

后续再加:

AmapWeatherProvider
OpenWeatherProvider

如果主要面向国内用户,高德天气也可以作为第二个 Provider,但需要用户配置 Web 服务 Key。

6.6 WeatherConfig

struct WeatherConfig
{
    bool enabled = true;

    QString provider = "open-meteo";

    QString defaultLocationName;
    double defaultLatitude = 0.0;
    double defaultLongitude = 0.0;
    bool hasDefaultCoordinate = false;

    bool allowIpLocation = false;
    bool askBeforeIpLocation = true;

    QString apiKey;
    int timeoutMs = 10000;

    bool useAIResponse = true;
    bool showRawDataWhenAIUnavailable = true;
};

保存到:

QStandardPaths::AppConfigLocation/weather_config.json

6.7 地点策略

优先级:

用户明确输入城市
↓
用户设置的默认城市
↓
用户主动选择 IP 定位
↓
追问用户城市

不要默认静默使用 IP 定位。

6.8 IP 定位原则

IP 定位可以做,但只能作为可选辅助。

原因:

VPN / 代理会导致定位错误
运营商出口可能定位不准
校园网 / 公司网可能不准
用户可能不希望程序自动请求定位服务

建议交互:

你还没有设置默认城市。
可以手动输入城市,也可以使用 IP 自动定位。
是否使用 IP 自动定位?

识别到城市后仍要确认:

我识别到你可能在西安,要设为默认城市吗?

6.9 天气意图关键词

天气
气温
温度
冷不冷
热不热
下雨
降雨
带伞
刮风
风力
湿度
空气质量
雾霾
适合出门
穿什么
外面怎么样

6.10 AI 回复上下文

当前 v1 采用模板优先,不依赖 AI 润色;本节作为 v1.1 预留方向。

程序应把结构化天气数据交给 AI

用户问题:
今天西安天气怎么样?

天气数据:
城市:西安
当前天气:多云
温度:26℃
体感温度:27℃
湿度:60%
风向:东北风
风速:3级
降雨概率:20%
更新时间:2026-06-01 15:00

请根据以上数据,用简洁自然的语气回答。不要编造没有提供的数据。

6.11 AI 不可用时兜底

如果天气 API 成功但 AI 失败,则模板回复:

西安当前天气:多云,26℃,湿度 60%,风力 3 级。更新时间:15:00。

7. 阶段 3:本地文件操作功能

7.1 功能定位

本地文件操作是高风险功能,必须后置,不能早于提醒和天气。

当前本地文件操作 v1 已进入实现阶段:

  • 已新增独立 src/fileops/ 模块
  • 已通过 CommandDispatcher 将 FileOperation 意图接入聊天入口
  • 已支持读取用户主动选择的常见文本文件
  • 已支持列出用户主动选择的文件夹
  • 已支持复制文件、创建备份、重命名文件
  • 写操作会展示操作计划并二次确认
  • 聊天文本不会直接变成本地路径,所有路径必须由用户通过文件选择框选择
  • 已拒绝删除、覆盖、移动、执行脚本、运行命令和系统目录访问
  • 已拒绝符号链接路径,降低路径逃逸风险

v1 明确暂不支持:

  • zip 打包
  • 删除文件
  • 覆盖文件
  • 移动文件
  • 执行脚本或命令
  • 修改源码

目标是让桌宠能辅助用户处理本地文件,例如:

帮我整理这个文件夹里的图片
帮我把这些日志文件打包
帮我读取这个 txt 总结一下
帮我把这个 md 转成备份副本

7.2 基本原则

AI 不能直接操作本地文件。

正确流程:

AI 理解用户意图
↓
生成操作计划
↓
程序校验路径和权限
↓
展示计划给用户确认
↓
程序执行
↓
执行结果反馈给 AI / 用户

禁止:

AI 直接读写任意文件
AI 直接删除文件
AI 直接覆盖文件
AI 自己决定访问系统目录

7.3 安全边界

必须实现:

工作目录白名单
路径标准化
禁止符号链接逃逸
禁止访问系统目录
禁止访问用户隐私目录,除非用户显式选择
修改前备份
删除前二次确认
批量操作前显示操作计划

7.4 建议目录

src/fileops/
 ├── FileOperationTypes.h
 ├── FileOperationManager.h
 ├── FileOperationManager.cpp
 ├── FileSandbox.h
 ├── FileSandbox.cpp
 ├── FileBackupManager.h
 └── FileBackupManager.cpp

7.5 第一版建议只做低风险操作

第一版可做:

读取用户主动选择的文本文件
列出用户主动选择的文件夹
复制文件
创建备份
打包 zip
重命名文件,需确认

当前 v1 中 zip 打包延期,因为 Qt 公共 API 没有稳定内置写 zip 能力;不为此引入重依赖。后续如果要补 zip,优先选择明确许可和可维护的压缩库。

暂不做:

删除文件
覆盖文件
移动大量文件
修改源码
执行脚本
运行命令
访问系统目录

7.6 修改/删除必须二次确认

即使用户说“删掉它”,也必须确认:

即将删除:
D:/xxx/a.txt
D:/xxx/b.txt

此操作会移动到回收站/备份后删除。
是否继续?

7.7 应用启动独立模块

当前已新增独立 src/launcher/ 模块,不放进 src/fileops/

src/launcher/
 ├── AppLaunchTypes.h
 ├── AppLaunchStore.h
 ├── AppLaunchStore.cpp
 ├── AppDiscovery.h
 ├── AppDiscovery.cpp
 ├── AppLaunchManager.h
 └── AppLaunchManager.cpp

应用启动支持:

打开 Codex
启动酷狗音乐
帮我打开 VSCode

解析和发现顺序:

用户在设置页登记的应用别名
↓
Windows 开始菜单快捷方式
↓
Windows App Paths 注册表
↓
未知应用时由用户手动选择 .exe

启动安全边界:

启动前始终二次确认
只允许 .exe 或开始菜单 .lnk
不执行 .bat / .cmd / .ps1 / .vbs / .js / .msi
不执行聊天文本里的命令
不拼接聊天文本参数
不以管理员权限启动

配置保存到:

QStandardPaths::AppConfigLocation/launcher_config.json

损坏时备份为:

launcher_config.broken.yyyyMMdd-HHmmss.json

8. 阶段 4:联网模式

联网能力已从旧“搜索引擎聚合器”重做为 Web 端 AI 对话式联网模式。

当前已落地:

  • 已删除旧 src/search/ 模块,不再维护 Google/百度/360/搜狗页面解析、SearXNG 旧配置、多源聚合和旧 search_config.json 兼容。
  • 已新增独立 src/web/ 模块:WebConfigWebStoreWebCapabilityDetectorWebChatManager 和 Web citation 类型。
  • 输入框新增“联网”开关;开关开启后,普通聊天进入 WebChat 流程。
  • 支持 OpenAI 官方 Provider 的 Responses API Web Search。
  • 支持 Google Gemini Provider 的 Google Search grounding。
  • DeepSeek 官方 API 当前不提供托管联网搜索工具,显示“不支持原生联网”。
  • Custom / 第三方 OpenAI-Compatible 默认无法确认联网能力,不发送未知联网参数,不做旧搜索页抓取。
  • 设置页改为“联网模式”:显示当前能力状态、开关记忆、默认开关、Provider 模式、超时、来源展示和测试联网模式。
  • search_config.json 已废弃;新版使用 web_config.json,损坏时备份为 web_config.broken.yyyyMMdd-HHmmss.json

边界:

  • 不再默认每次联网,模型可判断稳定常识无需联网。
  • 不做搜索结果页 HTML 解析,避免登录、帮助、反馈、验证码页面污染答案。
  • 不实现 Tavily / Brave / Bing Search API、自建搜索后端、网页全文抓取或长期缓存。
  • 天气仍是独立工具能力,不放进联网模式。

后续可选:

  • 更多 AI Provider 原生联网适配。
  • 结构化搜索 API 或自建联网后端,用于不支持原生联网的模型。
  • 更强的引用 UI、证据片段摘录和来源可点击展示。

9. 建议最终开发顺序

9.1 第一步:收口架构

1. 角色切换保存后立即生效已确认,后续作为回归项保留
2. 新增 IntentRouter
3. 新增 CommandDispatcher
4. 调整 PetWindow 输入流程
5. 当前阶段保持 CMAKE_AUTOMOC OFF,新增模块不使用 Q_OBJECT

9.2 第二步:定时提醒

当前已落地一次性提醒、每天/每周/每月重复提醒、提醒列表、取消提醒、编辑 pending 提醒、20 天历史保留、到点气泡/托盘通知、稍后提醒和提醒音效管理。
后续可继续补工作日/自定义间隔、跨平台通知实现和更复杂的提醒管理能力。

9.3 第三步:天气查询

当前已落地天气 v1WeatherTypes、WeatherConfig / WeatherStore、WeatherParser、WeatherManager、模板回复、设置页默认城市、公网 IP 定位兜底和 Weather 意图接入。
当前已落地天气 v1.2 / v1.3:多候选城市提示和设置页默认城市测试。后续可继续补可交互候选选择、区县级定位、国内天气源增强、AI 润色、空气质量、天气预警、多天气源切换、小时级降雨判断和天气提醒联动。

9.4 第四步:本地文件操作

当前已落地 FileSandbox、FileOperationTypes、FileOperationManager、FileBackupManager 和用户确认 UI。
v1 支持读取文本、列出文件夹、复制、备份、重命名。
v1 不支持 zip、删除、覆盖、移动、脚本/命令执行和系统目录访问。

9.5 第五步:联网模式

当前已落地 WebConfig、WebStore、WebCapabilityDetector、WebChatManager 和输入框联网开关。新版支持 OpenAI/Gemini 原生联网;DeepSeek/Custom 明确提示不支持或无法确认;旧搜索聚合与 SearXNG 旧配置已废弃。

9.6 第六步:应用启动

当前已落地 AppLaunchStore、AppDiscovery、AppLaunchManager 和设置页应用登记。
v1 支持已登记应用、开始菜单快捷方式、App Paths 注册表和用户确认手选 .exe。
v1 不支持脚本、聊天参数、命令执行、管理员权限和跨平台应用发现。

10. 给 Codex 的总提示

下面这段可以直接作为后续任务总说明:

当前不要急着直接实现提醒、天气、文件操作或联网模式。

请先审查当前 QtDesktopPet 项目结构,并完成以下准备工作:

1. 角色切换在设置保存后已确认立即生效,后续只需保留回归检查。
2. 新增 IntentRouter / CommandDispatcher,使用户输入先经过统一意图分发。
3. 意图类型包括 Chat、Reminder、Weather、FileOperation、LaunchApp;联网模式由输入框开关决定,不再是独立 Search 意图。
4. 意图优先级为 Reminder > FileOperation > Weather > LaunchApp > Chat/WebChat。
5. 普通聊天继续走现有 AI 对话流程。
6. 新功能不得继续直接塞进 PetWindow。
7. 后续 Reminder、Weather、FileOperation、LaunchApp、WebChat 均应作为独立模块接入。
8. 当前阶段保持 CMAKE_AUTOMOC OFF,后续模块不要使用 Q_OBJECT;确需 Qt 信号槽时再单独评估。
9. 保持现有隐私策略:API Key、Authorization、完整用户消息、完整错误响应不得写入日志。
10. 保持现有文件安全策略:路径校验、危险操作确认、修改前备份。

11. 当前结论

项目已经可以进入“工具能力扩展阶段”,但不建议直接开写业务功能。

建议先做:

结构收口 → IntentRouter / CommandDispatcher → 定时提醒 → 天气 → 本地文件操作 → 联网模式

其中:

定时提醒:已作为第一个工具能力落地
天气:建议第二个落地
本地文件操作:风险较高,第三个落地
联网模式:通用 AI 对话增强,最后落地