1102 lines
22 KiB
Markdown
1102 lines
22 KiB
Markdown
# 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 请求取消和对话清空
|
||
- 角色文件夹导入和角色切换
|
||
- 删除用户导入角色
|
||
- 本地一次性提醒、提醒列表、取消提醒和到点通知
|
||
- 内置/用户提醒音效切换、导入、删除和试听
|
||
- Windows 打包脚本和 Inno Setup 安装器脚本
|
||
- Release exe 双击不弹控制台窗口
|
||
|
||
项目已经从早期 MVP 进入到“可扩展桌面应用原型”阶段,可以开始规划工具能力扩展。
|
||
|
||
但是,在正式加入定时提醒、天气、本地文件操作、联网搜索之前,建议先做一轮结构收口。
|
||
|
||
---
|
||
|
||
## 2. 当前需要优先审查或优化的地方
|
||
|
||
### 2.1 审查角色切换是否保存后立即生效
|
||
|
||
当前已经支持角色导入和角色切换。经当前测试确认:
|
||
|
||
```text
|
||
设置页选择新角色
|
||
保存设置
|
||
当前桌宠窗口是否立即重新加载新角色包
|
||
```
|
||
|
||
结论:保存后会立即切换,不依赖重启。
|
||
|
||
当前代码路径:
|
||
|
||
```text
|
||
PetWindow::openSettingsDialog()
|
||
↓
|
||
applyAppConfig(dialog.appConfig())
|
||
↓
|
||
PetWindow::applyAppConfig() 比较旧 characterId 与新 characterId
|
||
↓
|
||
characterId 变化时停止当前动画并调用 loadCharacterPackage()
|
||
↓
|
||
loadCharacterPackage() 重新构建动画状态并从 idle 状态开始播放
|
||
```
|
||
|
||
后续不需要围绕 2.1 做修复,只需要保留为回归检查项:
|
||
|
||
```text
|
||
设置页切换角色后点击保存,桌宠应立即显示新角色
|
||
不需要关闭或重启程序
|
||
切换后动画状态应可继续正常播放
|
||
```
|
||
|
||
---
|
||
|
||
### 2.2 不要继续向 PetWindow 堆功能
|
||
|
||
目前 `PetWindow` 已经承担了过多职责,后续不能继续把所有新功能塞进去。
|
||
|
||
`PetWindow` 应该主要负责:
|
||
|
||
```text
|
||
窗口显示
|
||
拖动
|
||
菜单
|
||
子组件组织
|
||
基础 UI 信号转发
|
||
```
|
||
|
||
不建议继续负责:
|
||
|
||
```text
|
||
提醒解析
|
||
天气查询
|
||
联网搜索
|
||
本地文件读写
|
||
AI 工具调度
|
||
复杂业务状态管理
|
||
```
|
||
|
||
后续应逐步拆出:
|
||
|
||
```text
|
||
ChatController
|
||
ReminderController
|
||
WeatherController
|
||
FileOperationController
|
||
ToolCommandDispatcher
|
||
```
|
||
|
||
即使暂时不大规模重构,也至少要为后续功能增加统一调度层,不要直接把新逻辑写进 `PetWindow::submitChatMessage()`。
|
||
|
||
---
|
||
|
||
### 2.3 新增 IntentRouter / CommandDispatcher
|
||
|
||
后续功能包括:
|
||
|
||
```text
|
||
定时提醒
|
||
天气查询
|
||
本地文件操作
|
||
联网搜索
|
||
普通 AI 对话
|
||
```
|
||
|
||
这些都来自用户输入框。如果没有统一入口,逻辑会混乱。
|
||
|
||
可拆成两个模块:
|
||
|
||
```text
|
||
src/intent/
|
||
├── IntentTypes.h
|
||
├── IntentRouter.h
|
||
└── IntentRouter.cpp
|
||
|
||
src/command/
|
||
├── CommandDispatcher.h
|
||
└── CommandDispatcher.cpp
|
||
```
|
||
|
||
当前阶段已选择合并为一个轻量模块:
|
||
|
||
```text
|
||
src/assistant/
|
||
├── UserIntent.h
|
||
├── IntentRouter.h
|
||
├── IntentRouter.cpp
|
||
├── CommandDispatcher.h
|
||
└── CommandDispatcher.cpp
|
||
```
|
||
|
||
当前意图枚举:
|
||
|
||
```cpp
|
||
enum class UserIntentType
|
||
{
|
||
Chat,
|
||
Reminder,
|
||
Weather,
|
||
FileOperation,
|
||
Search
|
||
};
|
||
```
|
||
|
||
建议入口流程:
|
||
|
||
```text
|
||
用户输入
|
||
↓
|
||
IntentRouter 判断意图
|
||
↓
|
||
CommandDispatcher 分发
|
||
↓
|
||
ReminderManager / WeatherManager / FileOperationManager / WebSearchManager / ConversationManager
|
||
```
|
||
|
||
第一版意图识别不需要复杂,规则优先即可。
|
||
|
||
---
|
||
|
||
### 2.4 意图优先级建议
|
||
|
||
多个意图可能同时出现,需要固定优先级。
|
||
|
||
推荐:
|
||
|
||
```text
|
||
Reminder > FileOperation > Weather > Search > Chat
|
||
```
|
||
|
||
原因:
|
||
|
||
```text
|
||
“明天早上提醒我看天气”
|
||
虽然包含“天气”,但本质是提醒。
|
||
|
||
“把天气截图保存到桌面”
|
||
可能是文件操作,而不是单纯天气查询。
|
||
|
||
“搜索一下明天天气”
|
||
可能是搜索请求,但如果已有 WeatherTool,应优先走天气工具。
|
||
```
|
||
|
||
---
|
||
|
||
### 2.5 检查 CMAKE_AUTOMOC 设置
|
||
|
||
如果后续新增的 Manager 使用 `QObject`、`signals`、`slots`,建议开启:
|
||
|
||
```cmake
|
||
set(CMAKE_AUTOMOC ON)
|
||
```
|
||
|
||
如果继续保持 `CMAKE_AUTOMOC OFF`,则后续模块应避免 `Q_OBJECT`,全部使用普通 C++ 回调或现有信号体系。
|
||
|
||
建议明确选择一种:
|
||
|
||
```text
|
||
方案 A:开启 AUTOMOC,后续工具模块正常使用 QObject 信号槽
|
||
方案 B:保持 OFF,后续模块不得引入 Q_OBJECT
|
||
```
|
||
|
||
当前阶段选择方案 B:继续保持 `CMAKE_AUTOMOC OFF`,新增意图分发模块使用普通 C++ 类和同步返回值,不引入 `Q_OBJECT`。
|
||
|
||
后续如果 Reminder / Weather / Search 等模块需要大量跨对象异步信号,再单独评估是否切换到方案 A。
|
||
|
||
---
|
||
|
||
### 2.6 README 与实际功能保持同步
|
||
|
||
当前 README 已经比较完整,但后续每实现一个功能,应同步更新:
|
||
|
||
```text
|
||
当前状态
|
||
配置说明
|
||
隐私说明
|
||
日志说明
|
||
用户数据目录
|
||
发布包包含内容
|
||
```
|
||
|
||
尤其是以下功能需要额外说明:
|
||
|
||
```text
|
||
提醒数据保存位置
|
||
天气 API 请求说明
|
||
IP 定位隐私说明
|
||
本地文件操作权限说明
|
||
联网搜索来源和隐私说明
|
||
```
|
||
|
||
---
|
||
|
||
### 2.7 继续保持角色导入安全策略
|
||
|
||
当前角色导入已经有较多安全边界,比如:
|
||
|
||
```text
|
||
只导入本地文件夹
|
||
验证失败不复制
|
||
角色 id 安全字符限制
|
||
内置角色不能被覆盖
|
||
只允许删除用户导入角色
|
||
状态路径安全检查
|
||
```
|
||
|
||
后续本地文件操作模块也应该沿用这种风格:
|
||
|
||
```text
|
||
路径必须安全
|
||
不允许任意系统目录
|
||
危险操作必须确认
|
||
修改前备份
|
||
删除必须二次确认
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 后续功能总路线
|
||
|
||
建议不要一次做完所有功能,按以下顺序推进:
|
||
|
||
```text
|
||
阶段 0:结构收口
|
||
阶段 1:定时提醒
|
||
阶段 2:天气查询
|
||
阶段 3:本地文件操作
|
||
阶段 4:联网搜索
|
||
阶段 5:语音对话 / 更复杂 Agent 能力
|
||
```
|
||
|
||
当前结构收口和定时提醒已经进入实现阶段。下一步最推荐继续做:
|
||
|
||
```text
|
||
1. 天气查询
|
||
2. 本地文件操作安全边界
|
||
3. 联网搜索
|
||
```
|
||
|
||
---
|
||
|
||
# 4. 阶段 0:结构收口任务
|
||
|
||
## 4.1 目标
|
||
|
||
在正式加新功能之前,先让用户输入有统一分发入口,避免所有功能混进聊天逻辑。
|
||
|
||
## 4.2 当前新增文件
|
||
|
||
```text
|
||
src/assistant/UserIntent.h
|
||
src/assistant/IntentRouter.h
|
||
src/assistant/IntentRouter.cpp
|
||
src/assistant/CommandDispatcher.h
|
||
src/assistant/CommandDispatcher.cpp
|
||
```
|
||
|
||
## 4.3 IntentRouter 职责
|
||
|
||
```text
|
||
判断用户输入属于什么类型:
|
||
- 普通聊天
|
||
- 定时提醒
|
||
- 天气查询
|
||
- 本地文件操作
|
||
- 联网搜索
|
||
```
|
||
|
||
第一版可以使用规则判断,不依赖 AI。
|
||
|
||
## 4.4 CommandDispatcher 职责
|
||
|
||
```text
|
||
接收用户输入
|
||
调用 IntentRouter
|
||
根据意图分发到不同 Manager
|
||
普通聊天才交给现有 ConversationManager / LLMProvider
|
||
```
|
||
|
||
## 4.5 PetWindow 改造要求
|
||
|
||
`PetWindow` 只负责把用户输入交给 `CommandDispatcher`,不直接判断业务逻辑。
|
||
|
||
示例流程:
|
||
|
||
```text
|
||
PetWindow::submitChatMessage()
|
||
↓
|
||
CommandDispatcher::dispatch(userText)
|
||
↓
|
||
根据返回信号更新气泡、状态机、历史
|
||
```
|
||
|
||
不要继续在 `PetWindow` 中直接写提醒、天气、搜索或文件逻辑。
|
||
|
||
---
|
||
|
||
# 5. 阶段 1:定时提醒功能
|
||
|
||
## 5.1 功能定位
|
||
|
||
实现本地一次性提醒功能。
|
||
|
||
用户可以输入:
|
||
|
||
```text
|
||
晚上8点提醒我提交作业
|
||
明天9点提醒我开会
|
||
10分钟后提醒我喝水
|
||
半小时后提醒我休息
|
||
2小时后提醒我看消息
|
||
```
|
||
|
||
桌宠创建本地提醒,到点后气泡提示或托盘提示。
|
||
|
||
当前实现状态:
|
||
|
||
```text
|
||
已新增 src/reminder/ 模块
|
||
已支持一次性提醒解析、JSON 持久化、启动后加载、到点触发和状态标记
|
||
已支持聊天创建 / 查询 / 取消提醒
|
||
已支持设置页按状态查看提醒、取消 pending 提醒、清理已触发/已取消历史
|
||
已支持 reminder_default / reminder_soft 内置音效
|
||
已支持用户 wav 音效导入、删除、切换和试听
|
||
提醒触发时使用当前设置页选择的全局音效,ReminderItem.soundId 仅保留为历史兼容字段
|
||
已接入 Qt Multimedia / QSoundEffect 播放提醒音效
|
||
已预留 NotificationDispatcher,当前 Windows 仍由托盘通知承接
|
||
```
|
||
|
||
## 5.2 第一版范围
|
||
|
||
要做:
|
||
|
||
```text
|
||
一次性提醒
|
||
本地保存
|
||
程序重启后提醒不丢
|
||
到点后触发气泡和托盘通知
|
||
提醒触发后标记 triggered
|
||
支持查询当前提醒列表
|
||
支持取消提醒
|
||
```
|
||
|
||
暂不做:
|
||
|
||
```text
|
||
重复提醒
|
||
农历提醒
|
||
复杂日历
|
||
跨设备同步
|
||
联网日程
|
||
语音提醒
|
||
```
|
||
|
||
## 5.3 建议目录
|
||
|
||
```text
|
||
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 数据结构建议
|
||
|
||
```cpp
|
||
struct ReminderItem
|
||
{
|
||
QString id;
|
||
QString title;
|
||
QString originalText;
|
||
QDateTime remindAt;
|
||
ReminderStatus status = ReminderStatus::Pending;
|
||
QDateTime createdAt;
|
||
QString soundId; // 历史兼容字段,触发时不再读取
|
||
};
|
||
```
|
||
|
||
## 5.5 存储文件
|
||
|
||
保存到:
|
||
|
||
```text
|
||
QStandardPaths::AppConfigLocation/reminders.json
|
||
```
|
||
|
||
示例:
|
||
|
||
```json
|
||
{
|
||
"reminders": [
|
||
{
|
||
"id": "reminder_001",
|
||
"title": "提交作业",
|
||
"originalText": "晚上8点提醒我提交作业",
|
||
"remindAt": "2026-06-01T20:00:00",
|
||
"status": "pending",
|
||
"createdAt": "2026-06-01T15:20:00",
|
||
"soundId": ""
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
配置损坏时备份:
|
||
|
||
```text
|
||
reminders.broken.yyyyMMdd-HHmmss.json
|
||
```
|
||
|
||
## 5.6 时间解析策略
|
||
|
||
第一版规则解析优先,不依赖 AI。
|
||
|
||
支持:
|
||
|
||
```text
|
||
8点
|
||
8点30
|
||
20:30
|
||
晚上8点
|
||
下午3点
|
||
明天9点
|
||
明天上午10点
|
||
后天9点
|
||
今天下午3点
|
||
6月3日9点
|
||
6/3 09:00
|
||
下周一上午10点
|
||
10分钟后
|
||
半小时后
|
||
一个半小时后
|
||
一小时后
|
||
1小时后
|
||
两小时后
|
||
2小时后
|
||
```
|
||
|
||
如果规则解析失败,后续可以再接 AI 解析。包含“每天 / 每周 / 每月 / 工作日 / 重复”等语义时,当前只返回“重复提醒尚未支持”,不创建一次性提醒。
|
||
|
||
## 5.7 AI 辅助解析的设计边界
|
||
|
||
可以后续做 AI 辅助解析,但 AI 不允许直接写文件。
|
||
|
||
正确流程:
|
||
|
||
```text
|
||
AI 解析用户意图
|
||
↓
|
||
返回结构化 JSON
|
||
↓
|
||
程序校验
|
||
↓
|
||
ReminderManager 创建提醒
|
||
↓
|
||
ReminderStore 保存
|
||
```
|
||
|
||
禁止:
|
||
|
||
```text
|
||
AI 直接读写 reminders.json
|
||
AI 直接修改本地文件
|
||
```
|
||
|
||
AI 解析时必须由程序提供当前本地时间:
|
||
|
||
```text
|
||
currentLocalTime
|
||
timeZone
|
||
weekday
|
||
userText
|
||
```
|
||
|
||
因为 API 模型无法可靠知道用户本机时间。
|
||
|
||
## 5.8 到点触发
|
||
|
||
建议行为:
|
||
|
||
```text
|
||
桌宠可见:播放当前全局音效,显示 ChatBubble + 切 happy,无 happy 时回退 talk,不发 Windows 通知
|
||
桌宠隐藏:播放当前全局音效,触发 Windows 托盘通知,不在下次显示时补气泡
|
||
用户拖动中:播放当前全局音效,不打断 drag,拖动结束后显示气泡,不发 Windows 通知
|
||
```
|
||
|
||
提醒文案:
|
||
|
||
```text
|
||
到时间啦:提交作业
|
||
```
|
||
|
||
## 5.9 给 Codex 的阶段任务
|
||
|
||
```text
|
||
1. 新增 reminder 模块
|
||
2. 实现一次性 ReminderItem
|
||
3. 实现 ReminderStore JSON 读写
|
||
4. 实现 ReminderParser 规则解析
|
||
5. 实现 ReminderManager 定时检查
|
||
6. 到点后发信号给 UI 层
|
||
7. UI 层显示气泡和托盘通知
|
||
8. 不要把提醒逻辑写进 PetWindow
|
||
9. 不要让 AI 直接写本地文件
|
||
```
|
||
|
||
---
|
||
|
||
# 6. 阶段 2:天气查询功能
|
||
|
||
## 6.1 功能定位
|
||
|
||
天气是独立工具能力,不放进联网搜索。
|
||
|
||
正确流程:
|
||
|
||
```text
|
||
用户问天气
|
||
↓
|
||
程序识别 Weather 意图
|
||
↓
|
||
WeatherManager 调用天气 API
|
||
↓
|
||
拿到结构化天气数据
|
||
↓
|
||
AI 根据结构化数据自然语言回复
|
||
```
|
||
|
||
不要让 AI 自己搜索天气,也不要让 AI 自己拼 URL。
|
||
|
||
## 6.2 为什么不用联网搜索做天气
|
||
|
||
搜索天气有几个问题:
|
||
|
||
```text
|
||
结果格式不稳定
|
||
摘要可能过期
|
||
地区解析不稳定
|
||
无法稳定提取温度、降雨、风力、湿度等字段
|
||
AI 总结容易出错
|
||
```
|
||
|
||
天气应该走天气 API。
|
||
|
||
## 6.3 第一版范围
|
||
|
||
要做:
|
||
|
||
```text
|
||
识别天气请求
|
||
支持默认城市
|
||
支持用户指定城市
|
||
支持当前天气
|
||
支持简单今天/明天查询
|
||
AI 不可用时模板兜底回复
|
||
查询中切 think
|
||
回复时切 talk
|
||
失败时切 error
|
||
```
|
||
|
||
暂不做:
|
||
|
||
```text
|
||
天气预警
|
||
空气质量详情
|
||
分钟级降水
|
||
生活指数
|
||
地图定位
|
||
GPS 定位
|
||
自动后台推送
|
||
天气提醒
|
||
多天气源自动切换
|
||
```
|
||
|
||
## 6.4 建议目录
|
||
|
||
```text
|
||
src/weather/
|
||
├── WeatherTypes.h
|
||
├── WeatherConfig.h
|
||
├── WeatherStore.h
|
||
├── WeatherStore.cpp
|
||
├── WeatherProvider.h
|
||
├── WeatherProvider.cpp
|
||
├── OpenMeteoWeatherProvider.h
|
||
├── OpenMeteoWeatherProvider.cpp
|
||
├── WeatherManager.h
|
||
└── WeatherManager.cpp
|
||
```
|
||
|
||
## 6.5 天气源建议
|
||
|
||
第一版推荐:
|
||
|
||
```text
|
||
Open-MeteoProvider
|
||
```
|
||
|
||
优点:
|
||
|
||
```text
|
||
不需要 API Key
|
||
全球可用
|
||
适合开源项目默认方案
|
||
```
|
||
|
||
后续再加:
|
||
|
||
```text
|
||
AmapWeatherProvider
|
||
OpenWeatherProvider
|
||
```
|
||
|
||
如果主要面向国内用户,高德天气也可以作为第二个 Provider,但需要用户配置 Web 服务 Key。
|
||
|
||
## 6.6 WeatherConfig
|
||
|
||
```cpp
|
||
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;
|
||
};
|
||
```
|
||
|
||
保存到:
|
||
|
||
```text
|
||
QStandardPaths::AppConfigLocation/weather_config.json
|
||
```
|
||
|
||
## 6.7 地点策略
|
||
|
||
优先级:
|
||
|
||
```text
|
||
用户明确输入城市
|
||
↓
|
||
用户设置的默认城市
|
||
↓
|
||
用户主动选择 IP 定位
|
||
↓
|
||
追问用户城市
|
||
```
|
||
|
||
不要默认静默使用 IP 定位。
|
||
|
||
## 6.8 IP 定位原则
|
||
|
||
IP 定位可以做,但只能作为可选辅助。
|
||
|
||
原因:
|
||
|
||
```text
|
||
VPN / 代理会导致定位错误
|
||
运营商出口可能定位不准
|
||
校园网 / 公司网可能不准
|
||
用户可能不希望程序自动请求定位服务
|
||
```
|
||
|
||
建议交互:
|
||
|
||
```text
|
||
你还没有设置默认城市。
|
||
可以手动输入城市,也可以使用 IP 自动定位。
|
||
是否使用 IP 自动定位?
|
||
```
|
||
|
||
识别到城市后仍要确认:
|
||
|
||
```text
|
||
我识别到你可能在西安,要设为默认城市吗?
|
||
```
|
||
|
||
## 6.9 天气意图关键词
|
||
|
||
```text
|
||
天气
|
||
气温
|
||
温度
|
||
冷不冷
|
||
热不热
|
||
下雨
|
||
降雨
|
||
带伞
|
||
刮风
|
||
风力
|
||
湿度
|
||
空气质量
|
||
雾霾
|
||
适合出门
|
||
穿什么
|
||
外面怎么样
|
||
```
|
||
|
||
## 6.10 AI 回复上下文
|
||
|
||
程序应把结构化天气数据交给 AI:
|
||
|
||
```text
|
||
用户问题:
|
||
今天西安天气怎么样?
|
||
|
||
天气数据:
|
||
城市:西安
|
||
当前天气:多云
|
||
温度:26℃
|
||
体感温度:27℃
|
||
湿度:60%
|
||
风向:东北风
|
||
风速:3级
|
||
降雨概率:20%
|
||
更新时间:2026-06-01 15:00
|
||
|
||
请根据以上数据,用简洁自然的语气回答。不要编造没有提供的数据。
|
||
```
|
||
|
||
## 6.11 AI 不可用时兜底
|
||
|
||
如果天气 API 成功但 AI 失败,则模板回复:
|
||
|
||
```text
|
||
西安当前天气:多云,26℃,湿度 60%,风力 3 级。更新时间:15:00。
|
||
```
|
||
|
||
---
|
||
|
||
# 7. 阶段 3:本地文件操作功能
|
||
|
||
## 7.1 功能定位
|
||
|
||
本地文件操作是高风险功能,必须后置,不能早于提醒和天气。
|
||
|
||
目标是让桌宠能辅助用户处理本地文件,例如:
|
||
|
||
```text
|
||
帮我整理这个文件夹里的图片
|
||
帮我把这些日志文件打包
|
||
帮我读取这个 txt 总结一下
|
||
帮我把这个 md 转成备份副本
|
||
```
|
||
|
||
## 7.2 基本原则
|
||
|
||
AI 不能直接操作本地文件。
|
||
|
||
正确流程:
|
||
|
||
```text
|
||
AI 理解用户意图
|
||
↓
|
||
生成操作计划
|
||
↓
|
||
程序校验路径和权限
|
||
↓
|
||
展示计划给用户确认
|
||
↓
|
||
程序执行
|
||
↓
|
||
执行结果反馈给 AI / 用户
|
||
```
|
||
|
||
禁止:
|
||
|
||
```text
|
||
AI 直接读写任意文件
|
||
AI 直接删除文件
|
||
AI 直接覆盖文件
|
||
AI 自己决定访问系统目录
|
||
```
|
||
|
||
## 7.3 安全边界
|
||
|
||
必须实现:
|
||
|
||
```text
|
||
工作目录白名单
|
||
路径标准化
|
||
禁止符号链接逃逸
|
||
禁止访问系统目录
|
||
禁止访问用户隐私目录,除非用户显式选择
|
||
修改前备份
|
||
删除前二次确认
|
||
批量操作前显示操作计划
|
||
```
|
||
|
||
## 7.4 建议目录
|
||
|
||
```text
|
||
src/fileops/
|
||
├── FileOperationTypes.h
|
||
├── FileOperationPlanner.h
|
||
├── FileOperationPlanner.cpp
|
||
├── FileOperationManager.h
|
||
├── FileOperationManager.cpp
|
||
├── FileSandbox.h
|
||
├── FileSandbox.cpp
|
||
├── FileBackupManager.h
|
||
└── FileBackupManager.cpp
|
||
```
|
||
|
||
## 7.5 第一版建议只做低风险操作
|
||
|
||
第一版可做:
|
||
|
||
```text
|
||
读取用户主动选择的文本文件
|
||
列出用户主动选择的文件夹
|
||
复制文件
|
||
创建备份
|
||
打包 zip
|
||
重命名文件,需确认
|
||
```
|
||
|
||
暂不做:
|
||
|
||
```text
|
||
删除文件
|
||
覆盖文件
|
||
移动大量文件
|
||
修改源码
|
||
执行脚本
|
||
运行命令
|
||
访问系统目录
|
||
```
|
||
|
||
## 7.6 修改/删除必须二次确认
|
||
|
||
即使用户说“删掉它”,也必须确认:
|
||
|
||
```text
|
||
即将删除:
|
||
D:/xxx/a.txt
|
||
D:/xxx/b.txt
|
||
|
||
此操作会移动到回收站/备份后删除。
|
||
是否继续?
|
||
```
|
||
|
||
---
|
||
|
||
# 8. 阶段 4:联网搜索功能
|
||
|
||
## 8.1 功能定位
|
||
|
||
联网搜索后置,不要现在优先做。
|
||
|
||
联网搜索是通用增强能力:
|
||
|
||
```text
|
||
查询最新信息
|
||
查官网
|
||
查报错
|
||
查新闻
|
||
查版本
|
||
查文档
|
||
```
|
||
|
||
## 8.2 不要给每家模型各自配置搜索
|
||
|
||
不建议:
|
||
|
||
```text
|
||
OpenAIProvider 自己一套搜索
|
||
GeminiProvider 自己一套搜索
|
||
DeepSeekProvider 自己一套搜索
|
||
CustomProvider 自己一套搜索
|
||
```
|
||
|
||
推荐:
|
||
|
||
```text
|
||
WebSearchManager 独立负责搜索
|
||
LLMProvider 只负责回答
|
||
ConversationManager / CommandDispatcher 负责把搜索结果注入给 AI
|
||
```
|
||
|
||
## 8.3 建议目录
|
||
|
||
```text
|
||
src/search/
|
||
├── SearchTypes.h
|
||
├── SearchProvider.h
|
||
├── SearXNGSearchProvider.h
|
||
├── SearXNGSearchProvider.cpp
|
||
├── WebSearchManager.h
|
||
└── WebSearchManager.cpp
|
||
```
|
||
|
||
第一版只做:
|
||
|
||
```text
|
||
SearXNG + 自定义 Base URL
|
||
```
|
||
|
||
后续再加:
|
||
|
||
```text
|
||
Tavily
|
||
Brave Search
|
||
CustomSearchProvider
|
||
```
|
||
|
||
## 8.4 安全边界
|
||
|
||
```text
|
||
不要让 AI 自己生成任意 URL 给程序访问
|
||
不要做网页全文抓取第一版
|
||
不要默认每次都联网
|
||
不要把用户隐私查询写日志
|
||
搜索结果要显示来源
|
||
```
|
||
|
||
---
|
||
|
||
# 9. 建议最终开发顺序
|
||
|
||
## 9.1 第一步:收口架构
|
||
|
||
```text
|
||
1. 角色切换保存后立即生效已确认,后续作为回归项保留
|
||
2. 新增 IntentRouter
|
||
3. 新增 CommandDispatcher
|
||
4. 调整 PetWindow 输入流程
|
||
5. 当前阶段保持 CMAKE_AUTOMOC OFF,新增模块不使用 Q_OBJECT
|
||
```
|
||
|
||
## 9.2 第二步:定时提醒
|
||
|
||
```text
|
||
当前已落地一次性提醒、提醒列表、取消提醒、到点气泡/托盘通知和提醒音效管理。
|
||
后续可继续补确认/稍后提醒、重复提醒和跨平台通知实现。
|
||
```
|
||
|
||
## 9.3 第三步:天气查询
|
||
|
||
```text
|
||
1. WeatherTypes
|
||
2. WeatherConfig / WeatherStore
|
||
3. OpenMeteoWeatherProvider
|
||
4. WeatherManager
|
||
5. IntentRouter 天气识别
|
||
6. AI 回复 / 模板兜底
|
||
```
|
||
|
||
## 9.4 第四步:本地文件操作
|
||
|
||
```text
|
||
1. FileSandbox
|
||
2. FileOperationTypes
|
||
3. FileOperationPlanner
|
||
4. FileOperationManager
|
||
5. 用户确认 UI
|
||
6. 备份机制
|
||
```
|
||
|
||
## 9.5 第五步:联网搜索
|
||
|
||
```text
|
||
1. SearchTypes
|
||
2. SearchProvider
|
||
3. SearXNGSearchProvider
|
||
4. WebSearchManager
|
||
5. 来源展示
|
||
```
|
||
|
||
---
|
||
|
||
# 10. 给 Codex 的总提示
|
||
|
||
下面这段可以直接作为后续任务总说明:
|
||
|
||
```text
|
||
当前不要急着直接实现提醒、天气、文件操作或联网搜索。
|
||
|
||
请先审查当前 QtDesktopPet 项目结构,并完成以下准备工作:
|
||
|
||
1. 角色切换在设置保存后已确认立即生效,后续只需保留回归检查。
|
||
2. 新增 IntentRouter / CommandDispatcher,使用户输入先经过统一意图分发。
|
||
3. 意图类型包括 Chat、Reminder、Weather、FileOperation、Search。
|
||
4. 意图优先级为 Reminder > FileOperation > Weather > Search > Chat。
|
||
5. 普通聊天继续走现有 AI 对话流程。
|
||
6. 新功能不得继续直接塞进 PetWindow。
|
||
7. 后续 Reminder、Weather、FileOperation、Search 均应作为独立模块接入。
|
||
8. 当前阶段保持 CMAKE_AUTOMOC OFF,后续模块不要使用 Q_OBJECT;确需 Qt 信号槽时再单独评估。
|
||
9. 保持现有隐私策略:API Key、Authorization、完整用户消息、完整错误响应不得写入日志。
|
||
10. 保持现有文件安全策略:路径校验、危险操作确认、修改前备份。
|
||
```
|
||
|
||
---
|
||
|
||
# 11. 当前结论
|
||
|
||
项目已经可以进入“工具能力扩展阶段”,但不建议直接开写业务功能。
|
||
|
||
建议先做:
|
||
|
||
```text
|
||
结构收口 → IntentRouter / CommandDispatcher → 定时提醒 → 天气 → 本地文件操作 → 联网搜索
|
||
```
|
||
|
||
其中:
|
||
|
||
```text
|
||
定时提醒:已作为第一个工具能力落地
|
||
天气:建议第二个落地
|
||
本地文件操作:风险较高,第三个落地
|
||
联网搜索:通用能力,最后落地
|
||
```
|