docs: 补强 V1 数据与测试设计
- 扩展 SQLite schema:新增 batches、Excel 行定位、stage/status、时间戳和重试字段 - 明确 SQLite worker 并发规则:独立 connection、WAL、busy_timeout、短事务 - 调整 AI 接入顺序:先做模型清单后端,再接真实 ai.py,设置页复用后端 - 补充 unittest 测试基座要求和分层验证策略 - 敏感信息改为本地明文保存,配合 gitignore、UI 打码和日志脱敏
This commit is contained in:
@@ -32,7 +32,7 @@ cmshopee 是一个 **Windows 本地桌面自动化工具**:管理多个 Shopee
|
|||||||
|
|
||||||
## 安全红线
|
## 安全红线
|
||||||
|
|
||||||
- 绝不把真实账号、密码、Cookie、token 写进代码、文档或日志;密码加密存、不自动登录。
|
- 绝不把真实账号、密码、Cookie、token 写进代码、文档或日志;密码/API Key 可在本地配置或 DB 明文保存,但文件必须 gitignore,且不自动登录。
|
||||||
- `config.json`、`cmshopee.db`、`chrome_user_data_dir/`(含密码/登录态)绝不提交版本库。
|
- `config.json`、`cmshopee.db`、`chrome_user_data_dir/`(含密码/登录态)绝不提交版本库。
|
||||||
- 「更新」提交线上、删除满 9 张封面等不可逆动作,必须有显式确认;③ 点击「开始更新」后必须弹窗确认,用户确认后才批量更新当前筛选结果。
|
- 「更新」提交线上、删除满 9 张封面等不可逆动作,必须有显式确认;③ 点击「开始更新」后必须弹窗确认,用户确认后才批量更新当前筛选结果。
|
||||||
- 不绕过 Shopee 的验证码、风控、限流或权限校验。
|
- 不绕过 Shopee 的验证码、风控、限流或权限校验。
|
||||||
@@ -41,6 +41,7 @@ cmshopee 是一个 **Windows 本地桌面自动化工具**:管理多个 Shopee
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
python -m py_compile *.py # 语法检查
|
python -m py_compile *.py # 语法检查
|
||||||
|
python -m unittest discover -s tests # 纯逻辑单元测试(tests 存在后)
|
||||||
python prototypes/demo.py # 单账号闭环(不提交)
|
python prototypes/demo.py # 单账号闭环(不提交)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -10,4 +10,4 @@ Claude Code 处理本仓库任务时:
|
|||||||
2. 再按 `AGENTS.md` 进入 [`docs/00-ai-start-here.md`](docs/00-ai-start-here.md) 和相关文档(重点 `docs/04-architecture.md` 第七节 CDP 已验证事实)。
|
2. 再按 `AGENTS.md` 进入 [`docs/00-ai-start-here.md`](docs/00-ai-start-here.md) 和相关文档(重点 `docs/04-architecture.md` 第七节 CDP 已验证事实)。
|
||||||
3. 不在本文重复维护任务流程、编码规则或文档清单,避免和 `AGENTS.md` 漂移。
|
3. 不在本文重复维护任务流程、编码规则或文档清单,避免和 `AGENTS.md` 漂移。
|
||||||
|
|
||||||
安全红线(详见 `AGENTS.md`):不写真实凭证、密码加密存不自动登录;不提交 `config.json`、`cmshopee.db`、`chrome_user_data_dir/`;不可逆操作需显式确认,③ 开始更新前需弹窗确认;不绕过 Shopee 风控。
|
安全红线(详见 `AGENTS.md`):不写真实凭证到代码/文档/日志;密码/API Key 可本地明文保存但不自动登录;不提交 `config.json`、`cmshopee.db`、`chrome_user_data_dir/`;不可逆操作需显式确认,③ 开始更新前需弹窗确认;不绕过 Shopee 风控。
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ cmshopee 是一个 Windows 本地桌面自动化工具(PySide6,5 Tab),
|
|||||||
|
|
||||||
目标闭环:④ 配账号并登录 → ① 导入 Excel(按“别名”列关联账号)、采集旧标题/旧封面并回写 → ② 用提示词 AI 生成新标题/新封面(不设逐条确认阶段)→ ③ 对已生成任务点击「开始更新」,弹窗确认后批量改标题+换封面并点「更新」提交 → 结果实时存 SQLite、批量回写原 Excel。
|
目标闭环:④ 配账号并登录 → ① 导入 Excel(按“别名”列关联账号)、采集旧标题/旧封面并回写 → ② 用提示词 AI 生成新标题/新封面(不设逐条确认阶段)→ ③ 对已生成任务点击「开始更新」,弹窗确认后批量改标题+换封面并点「更新」提交 → 结果实时存 SQLite、批量回写原 Excel。
|
||||||
|
|
||||||
存储:应用设置 `config.json` + AI 模型清单 `config/ai_models.json`(含加密 AI Key)+ 业务数据 SQLite `cmshopee.db` + Excel 用 openpyxl + 图片存本地 `images/`。AI 服务商待定。
|
存储:应用设置 `config.json` + AI 模型清单 `config/ai_models.json`(含本地明文 AI Key,必须 gitignore)+ 业务数据 SQLite `cmshopee.db` + Excel 用 openpyxl + 图片存本地 `images/`。AI 服务商待定。
|
||||||
|
|
||||||
## 必读顺序
|
## 必读顺序
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ cmshopee 是一个 Windows 本地桌面自动化工具(PySide6,5 Tab),
|
|||||||
3. Phase 2:导入 Excel、采集旧标题/旧封面并回写。
|
3. Phase 2:导入 Excel、采集旧标题/旧封面并回写。
|
||||||
4. Phase 3:AI 生成新标题/新封面。
|
4. Phase 3:AI 生成新标题/新封面。
|
||||||
5. Phase 4:③ 批量确认后更新 Shopee 并回写结果。
|
5. Phase 4:③ 批量确认后更新 Shopee 并回写结果。
|
||||||
6. Phase 5:设置、加密密钥方案、收尾。
|
6. Phase 5:设置、敏感信息提示与日志脱敏、收尾。
|
||||||
|
|
||||||
## 领取任务规则
|
## 领取任务规则
|
||||||
|
|
||||||
@@ -116,6 +116,7 @@ cmshopee 是一个 Windows 本地桌面自动化工具(PySide6,5 Tab),
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
python -m py_compile *.py # 语法检查
|
python -m py_compile *.py # 语法检查
|
||||||
|
python -m unittest discover -s tests # 纯逻辑单元测试(tests 存在后)
|
||||||
python prototypes/demo.py # 单账号闭环验证(分步,不提交)
|
python prototypes/demo.py # 单账号闭环验证(分步,不提交)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -123,4 +124,5 @@ python prototypes/demo.py # 单账号闭环验证(分步,不
|
|||||||
|
|
||||||
- 改 CDP / editor 逻辑后:在测试商品(ITEM_ID 51100639510)上跑 `prototypes/demo.py` 实测。
|
- 改 CDP / editor 逻辑后:在测试商品(ITEM_ID 51100639510)上跑 `prototypes/demo.py` 实测。
|
||||||
- 改账号配置后:验证 SQLite 账号读写与 user-data-dir 创建;改应用设置后验证 `config.json` 读写。
|
- 改账号配置后:验证 SQLite 账号读写与 user-data-dir 创建;改应用设置后验证 `config.json` 读写。
|
||||||
|
- 改 DB / Excel / prompts / appconfig 纯逻辑后:补或更新 `tests/` 下的 unittest。
|
||||||
- 如果命令当前不可运行(如 GUI 未建),在回复里如实说明。
|
- 如果命令当前不可运行(如 GUI 未建),在回复里如实说明。
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
| 功能 | 用户能做什么 | 优先级 |
|
| 功能 | 用户能做什么 | 优先级 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 账号管理(④) | 增删改账号:账号名/别名/地区/数据目录/端口/密码(加密仅参考)/备注;登录状态;启动登录、检测登录 | P0 |
|
| 账号管理(④) | 增删改账号:账号名/别名/地区/数据目录/端口/密码(本地明文仅参考,UI 打码)/备注;登录状态;启动登录、检测登录 | P0 |
|
||||||
| 导入(①) | 导入多个 Excel,按模板解析输入列(账号名/别名/商品id)为任务列表 | P0 |
|
| 导入(①) | 导入多个 Excel,按模板解析输入列(账号名/别名/商品id)为任务列表 | P0 |
|
||||||
| 导入校验汇总(①) | 导入后展示文件数、解析行数(原始数据量)、有效/无效行、匹配账号行数(按账号细分)、未匹配行数;跑采集前先纠错 | P0 |
|
| 导入校验汇总(①) | 导入后展示文件数、解析行数(原始数据量)、有效/无效行、匹配账号行数(按账号细分)、未匹配行数;跑采集前先纠错 | P0 |
|
||||||
| 采集旧数据(①) | 程序只读打开商品页,抓取旧标题、下载旧封面到本地,回写 Excel 旧字段 | P0 |
|
| 采集旧数据(①) | 程序只读打开商品页,抓取旧标题、下载旧封面到本地,回写 Excel 旧字段 | P0 |
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
| 执行方式 | 多账号串行、逐任务执行,单条失败继续 |
|
| 执行方式 | 多账号串行、逐任务执行,单条失败继续 |
|
||||||
| 旧标题/旧封面 | 程序在「采集」阶段改前抓取的快照(输出列),运营不填 |
|
| 旧标题/旧封面 | 程序在「采集」阶段改前抓取的快照(输出列),运营不填 |
|
||||||
| 新标题/新封面 | AI 生成(输出列),直接用于 ③;不设逐条确认阶段,本地留档+回写 Excel 供追溯 |
|
| 新标题/新封面 | AI 生成(输出列),直接用于 ③;不设逐条确认阶段,本地留档+回写 Excel 供追溯 |
|
||||||
| AI 服务 | 文本+图像生成,服务商/模型待定;Key 加密存于配置;见 [技术栈](03-tech-stack.md) |
|
| AI 服务 | 文本+图像生成,服务商/模型待定;Key 本地明文存于 `config/ai_models.json`,UI 打码、不入日志;见 [技术栈](03-tech-stack.md) |
|
||||||
| 本地图片 | 旧封面下载、新封面生成存本地图片目录,路径记 DB |
|
| 本地图片 | 旧封面下载、新封面生成存本地图片目录,路径记 DB |
|
||||||
| 结果落库时机 | 各阶段处理完立即写 SQLite;该 Excel 全部完成后批量回写原文件 |
|
| 结果落库时机 | 各阶段处理完立即写 SQLite;该 Excel 全部完成后批量回写原文件 |
|
||||||
| 原文件被占用 | 回写时若原 Excel 被锁定,提示关闭重试或另存副本(SQLite 为事实来源) |
|
| 原文件被占用 | 回写时若原 Excel 被锁定,提示关闭重试或另存副本(SQLite 为事实来源) |
|
||||||
@@ -100,11 +100,11 @@
|
|||||||
## 七、待确认 / 风险点
|
## 七、待确认 / 风险点
|
||||||
|
|
||||||
- **账号 / 凭证风险**:登录态存在各账号 user-data-dir,等同账号凭证;目录不得提交版本库、不得外传。
|
- **账号 / 凭证风险**:登录态存在各账号 user-data-dir,等同账号凭证;目录不得提交版本库、不得外传。
|
||||||
- **密码存储风险**:Tab2 的密码加密存于 SQLite,仅供人工参考,**绝不自动登录/自动填**;`cmshopee.db`、`config.json` 必须 gitignore;加密密钥不得与密文同存(见 [任务 T-403](06-tasks.md))。
|
- **密码存储风险**:Tab④ 的密码本地明文存于 SQLite,仅供人工参考,**绝不自动登录/自动填**;`cmshopee.db`、`config.json` 必须 gitignore;UI 打码、日志脱敏(见 [任务 T-503](06-tasks.md))。
|
||||||
- **别名匹配风险**:别名以 Excel 列为准;不匹配的行略过并最后弹窗,执行起始在日志逐条打印「文件→匹配账号」留痕,防误改。
|
- **别名匹配风险**:别名以 Excel 列为准;不匹配的行略过并最后弹窗,执行起始在日志逐条打印「文件→匹配账号」留痕,防误改。
|
||||||
- **AI 主图风险(高,已知并接受)**:本设计不设逐条人工审核和常驻提交开关;AI 生成的标题/封面经 ③ 批量确认后会提交线上。主图若失真/夸大/侵权可能违反 Shopee 规则甚至下架。缓解:开始更新前弹窗确认筛选范围和任务数量,新图本地留档 + 回写 Excel 供事后追溯;强烈建议先在测试商品验证再批量。
|
- **AI 主图风险(高,已知并接受)**:本设计不设逐条人工审核和常驻提交开关;AI 生成的标题/封面经 ③ 批量确认后会提交线上。主图若失真/夸大/侵权可能违反 Shopee 规则甚至下架。缓解:开始更新前弹窗确认筛选范围和任务数量,新图本地留档 + 回写 Excel 供事后追溯;强烈建议先在测试商品验证再批量。
|
||||||
- **AI 成本与依赖**:接入文本+图像 AI = 新外部依赖 + API 费用 + Key 管理;服务商/模型/合规待 [技术栈](03-tech-stack.md) 确认。
|
- **AI 成本与依赖**:接入文本+图像 AI = 新外部依赖 + API 费用 + Key 管理;服务商/模型/合规待 [技术栈](03-tech-stack.md) 确认。
|
||||||
- **AI Key 安全**:Key 加密存于 `config/ai_models.json`,不写日志、不提交版本库。
|
- **AI Key 安全**:Key 本地明文存于 `config/ai_models.json`,UI 打码,不写日志,不提交版本库。
|
||||||
- **第三方平台风险**:Shopee 页面结构、class 名、接口随时可能变;限流、风控、封号风险存在,禁止高频批量。
|
- **第三方平台风险**:Shopee 页面结构、class 名、接口随时可能变;限流、风控、封号风险存在,禁止高频批量。
|
||||||
- **自动化边界风险**:③ 确认后会自动改标题、上传图片、拖拽并点「更新」提交线上;点「开始更新」并确认前需自行确保筛选范围、任务来源与 AI 产出可接受。
|
- **自动化边界风险**:③ 确认后会自动改标题、上传图片、拖拽并点「更新」提交线上;点「开始更新」并确认前需自行确保筛选范围、任务来源与 AI 产出可接受。
|
||||||
- **合规风险**:仅在自有/授权账号上操作;遵守 Shopee 卖家条款;不绕过任何平台限制。
|
- **合规风险**:仅在自有/授权账号上操作;遵守 Shopee 卖家条款;不绕过任何平台限制。
|
||||||
|
|||||||
+12
-1
@@ -22,7 +22,7 @@
|
|||||||
| AI 图像生成 | 选 `default_image_model`(category=image,image-to-image) | 选型在配置 | 提示词+旧封面→新封面;分辨率 512/1k/2k/4k,返回超时随分辨率 |
|
| AI 图像生成 | 选 `default_image_model`(category=image,image-to-image) | 选型在配置 | 提示词+旧封面→新封面;分辨率 512/1k/2k/4k,返回超时随分辨率 |
|
||||||
| 并发 | 标准库 `concurrent.futures.ThreadPoolExecutor` | 已定 | 标题/图片分别按并发数并行;可停止、可重试 |
|
| 并发 | 标准库 `concurrent.futures.ThreadPoolExecutor` | 已定 | 标题/图片分别按并发数并行;可停止、可重试 |
|
||||||
| 图片处理 | `requests`(下载)+ `Pillow`(按分辨率/jpg质量存盘) | 部分待定 | 下载旧封面;新封面按 resolution 生成、jpg_quality 存盘 |
|
| 图片处理 | `requests`(下载)+ `Pillow`(按分辨率/jpg质量存盘) | 部分待定 | 下载旧封面;新封面按 resolution 生成、jpg_quality 存盘 |
|
||||||
| 测试 | `python -m py_compile` + 手动 CDP 验证 | 待完善 | 纯 UI/浏览器交互难以单测;关键逻辑(配置读写、参数拼装)可加 `pytest` |
|
| 测试 | `python -m py_compile` + `unittest` + 手动 CDP/AI 验证 | 已定(分层) | 配置/DB/Excel/prompts 用单测;CDP/Shopee 与真实 AI 属集成验证或 mock |
|
||||||
|
|
||||||
## 二、决策记录与演进
|
## 二、决策记录与演进
|
||||||
|
|
||||||
@@ -44,6 +44,7 @@
|
|||||||
| 安装依赖 | `pip install websocket-client requests openpyxl pillow PySide6` |
|
| 安装依赖 | `pip install websocket-client requests openpyxl pillow PySide6` |
|
||||||
| 检查 PySide6 | `python -c "import PySide6; print(PySide6.__version__)"` |
|
| 检查 PySide6 | `python -c "import PySide6; print(PySide6.__version__)"` |
|
||||||
| 语法检查 | `python -m py_compile *.py` |
|
| 语法检查 | `python -m py_compile *.py` |
|
||||||
|
| 单元测试 | `python -m unittest discover -s tests` |
|
||||||
| 跑单账号演示 | `python prototypes/demo.py`(分步)/ `set AUTO=1 && python prototypes/demo.py`(自动) |
|
| 跑单账号演示 | `python prototypes/demo.py`(分步)/ `set AUTO=1 && python prototypes/demo.py`(自动) |
|
||||||
| 提交更新(真改线上) | `set UPDATE=1 && python prototypes/demo.py` |
|
| 提交更新(真改线上) | `set UPDATE=1 && python prototypes/demo.py` |
|
||||||
| 读取某账号 Cookie(调试) | `python prototypes/cookies.py` |
|
| 读取某账号 Cookie(调试) | `python prototypes/cookies.py` |
|
||||||
@@ -67,3 +68,13 @@ set AUTO=1 && python prototypes/demo.py
|
|||||||
- GUI 框架固定为 PySide6,不允许混入 Tkinter/PyQt/Web 形成两套 UI。
|
- GUI 框架固定为 PySide6,不允许混入 Tkinter/PyQt/Web 形成两套 UI。
|
||||||
- 不引入第二套浏览器自动化方案(不要 cdp.py 之外再混入 selenium/playwright)。
|
- 不引入第二套浏览器自动化方案(不要 cdp.py 之外再混入 selenium/playwright)。
|
||||||
- 不确定的技术选型先更新本文,再进入代码。
|
- 不确定的技术选型先更新本文,再进入代码。
|
||||||
|
|
||||||
|
## 五、测试分层
|
||||||
|
|
||||||
|
| 层级 | 覆盖对象 | 验证方式 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 语法 | 所有 `.py` | `python -m py_compile *.py`,后续可扩展 `compileall` |
|
||||||
|
| 单元 | `appconfig/db/excel/prompts/config/chrome` 的纯逻辑 | `python -m unittest discover -s tests`,使用临时目录/临时 SQLite/样例 Excel |
|
||||||
|
| GUI 轻测 | PySide6 主窗口可创建、Tab 数量、worker signal 基本行为 | 可用 unittest 构造 `QApplication`,不连真实 Shopee |
|
||||||
|
| 集成 | CDP/editor 操作 Shopee 测试商品 | 手动跑 `prototypes/demo.py` 或后续专用集成脚本 |
|
||||||
|
| 外部 AI | 模型连接、文本/图像生成 | 默认 mock;真实调用只在手动验证时跑,避免成本和限流 |
|
||||||
|
|||||||
+62
-21
@@ -41,7 +41,7 @@ Shopee 卖家中心页面 / 本地图片目录
|
|||||||
|
|
||||||
## 二、流水线(核心)
|
## 二、流水线(核心)
|
||||||
|
|
||||||
每个任务(Excel 行)依次走过 5 个阶段,状态字段 `stage` 贯穿全程:
|
每个任务(Excel 行)依次走过 4 个业务阶段,状态字段 `stage` 贯穿全程:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
imported → collected → generated → applied
|
imported → collected → generated → applied
|
||||||
@@ -74,7 +74,7 @@ imported → collected → generated → applied
|
|||||||
**存储(同一事实只存一处)**
|
**存储(同一事实只存一处)**
|
||||||
|
|
||||||
- 应用配置(模型选择、生成参数、目录、Chrome 路径)→ `config.json`。
|
- 应用配置(模型选择、生成参数、目录、Chrome 路径)→ `config.json`。
|
||||||
- AI 模型清单(url/模型/密钥/类型/连接超时)→ `config/ai_models.json`(含密钥,必须 gitignore)。
|
- AI 模型清单(url/模型/密钥/类型/连接超时)→ `config/ai_models.json`(API Key 本地明文保存,必须 gitignore,UI 打码显示)。
|
||||||
- 业务数据(账号、任务、各阶段结果)→ SQLite `cmshopee.db`。
|
- 业务数据(账号、任务、各阶段结果)→ SQLite `cmshopee.db`。
|
||||||
- 图片(采集的旧封面、AI 生成的新封面)→ 本地图片目录(路径记在 DB)。
|
- 图片(采集的旧封面、AI 生成的新封面)→ 本地图片目录(路径记在 DB)。
|
||||||
- 提示词 → 标题提示词存单文件 `title_prompt.txt`;封面提示词存多模板 `prompts/cover/<名称>.txt`。
|
- 提示词 → 标题提示词存单文件 `title_prompt.txt`;封面提示词存多模板 `prompts/cover/<名称>.txt`。
|
||||||
@@ -116,7 +116,7 @@ imported → collected → generated → applied
|
|||||||
- `resolution`:当前分辨率,下拉 `512 / 1k / 2k / 4k`。
|
- `resolution`:当前分辨率,下拉 `512 / 1k / 2k / 4k`。
|
||||||
- `resolution_timeouts`:分辨率 → **等待大模型返回超时(秒)** 的映射;用户选分辨率即自动套用,不单独填。
|
- `resolution_timeouts`:分辨率 → **等待大模型返回超时(秒)** 的映射;用户选分辨率即自动套用,不单独填。
|
||||||
- 模型本身的定义(url/key/类型/连接超时…)在 `config/ai_models.json`,见 5.1b。
|
- 模型本身的定义(url/key/类型/连接超时…)在 `config/ai_models.json`,见 5.1b。
|
||||||
- 密钥不在 `config.json`:每个模型的 `api_key` 存于 `config/ai_models.json`,加密、打码、gitignore。
|
- 密钥不在 `config.json`:每个模型的 `api_key` 存于 `config/ai_models.json`,本地明文保存、UI 打码、gitignore、不入日志。
|
||||||
|
|
||||||
### 5.1b AI 模型清单 `config/ai_models.json`
|
### 5.1b AI 模型清单 `config/ai_models.json`
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ imported → collected → generated → applied
|
|||||||
"enabled": true,
|
"enabled": true,
|
||||||
"url": "https://api.vectorengine.ai/v1/chat/completions",
|
"url": "https://api.vectorengine.ai/v1/chat/completions",
|
||||||
"model": "gemini-3.1-flash-image-preview", // 模型 ID
|
"model": "gemini-3.1-flash-image-preview", // 模型 ID
|
||||||
"api_key": "***", // 密钥:加密存、UI 打码、不入日志、不进版本库
|
"api_key": "***", // 密钥:本地明文存、UI 打码、不入日志、不进版本库
|
||||||
"api_type": "auto", // chat | images_edits | auto —— 决定请求构造方式
|
"api_type": "auto", // chat | images_edits | auto —— 决定请求构造方式
|
||||||
"connect_timeout_seconds": 30, // 连接该服务超时(每模型,默认 30)
|
"connect_timeout_seconds": 30, // 连接该服务超时(每模型,默认 30)
|
||||||
"timeout_seconds": 0, // 返回超时:0/留空 = 运行时按 resolution_timeouts 取值
|
"timeout_seconds": 0, // 返回超时:0/留空 = 运行时按 resolution_timeouts 取值
|
||||||
@@ -147,11 +147,21 @@ imported → collected → generated → applied
|
|||||||
- 约束:**至少各有一个 text 与一个 image 模型**;下拉默认最少一项、删到剩一项时禁用「删除」。
|
- 约束:**至少各有一个 text 与一个 image 模型**;下拉默认最少一项、删到剩一项时禁用「删除」。
|
||||||
- `connect_timeout_seconds`(连接超时)属于**模型**;返回超时由分辨率映射决定(不在模型上单设)。
|
- `connect_timeout_seconds`(连接超时)属于**模型**;返回超时由分辨率映射决定(不在模型上单设)。
|
||||||
- `api_type` 反映不同 API 形状(`chat`/`images_edits`/`auto`),请求构造按它分支。
|
- `api_type` 反映不同 API 形状(`chat`/`images_edits`/`auto`),请求构造按它分支。
|
||||||
- `name` 唯一;`api_key` 加密存、打码显示。
|
- `name` 唯一;`api_key` 本地明文保存、打码显示。
|
||||||
|
|
||||||
### 5.2 SQLite `cmshopee.db`
|
### 5.2 SQLite `cmshopee.db`
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
|
-- 批次(一次导入动作)
|
||||||
|
CREATE TABLE batches (
|
||||||
|
id TEXT PRIMARY KEY, -- batch_id,如 20260626_153000_xxxx
|
||||||
|
source_files_json TEXT NOT NULL, -- 导入文件绝对路径列表(JSON)
|
||||||
|
status TEXT NOT NULL DEFAULT 'active', -- active/done/partial/failed
|
||||||
|
note TEXT,
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
-- 账号(④ 账号管理)
|
-- 账号(④ 账号管理)
|
||||||
CREATE TABLE accounts (
|
CREATE TABLE accounts (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
@@ -161,44 +171,75 @@ CREATE TABLE accounts (
|
|||||||
slug TEXT UNIQUE NOT NULL, -- user-data-dir 子目录名 [a-z0-9_]
|
slug TEXT UNIQUE NOT NULL, -- user-data-dir 子目录名 [a-z0-9_]
|
||||||
user_data_dir TEXT NOT NULL,
|
user_data_dir TEXT NOT NULL,
|
||||||
debug_port INTEGER NOT NULL,
|
debug_port INTEGER NOT NULL,
|
||||||
password_enc TEXT, -- 加密存,仅参考,不自动登录
|
password TEXT, -- 本地明文,仅参考,不自动登录;UI 打码,gitignore
|
||||||
note TEXT,
|
note TEXT,
|
||||||
created_at TEXT NOT NULL,
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL,
|
||||||
last_login_at TEXT
|
last_login_at TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
-- 任务 + 各阶段结果(贯穿流水线)
|
-- 任务 + 各阶段结果(贯穿流水线)
|
||||||
CREATE TABLE tasks (
|
CREATE TABLE tasks (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
batch_id TEXT NOT NULL,
|
batch_id TEXT NOT NULL REFERENCES batches(id),
|
||||||
source_file TEXT,
|
-- Excel 回写定位
|
||||||
|
source_file TEXT NOT NULL, -- 展示用原路径
|
||||||
|
source_file_abs TEXT NOT NULL, -- 绝对路径,作为回写分组依据
|
||||||
|
source_sheet TEXT NOT NULL, -- sheet 名
|
||||||
|
source_row INTEGER NOT NULL, -- Excel 行号(1-based)
|
||||||
|
row_key TEXT NOT NULL UNIQUE, -- batch/file/sheet/row 组成,防重复导入
|
||||||
-- 输入列(Excel)
|
-- 输入列(Excel)
|
||||||
account_name TEXT,
|
account_name TEXT,
|
||||||
alias TEXT NOT NULL,
|
alias TEXT NOT NULL,
|
||||||
item_id TEXT NOT NULL,
|
item_id TEXT NOT NULL,
|
||||||
-- 采集输出(程序写,改前快照)
|
-- 采集输出(程序写,改前快照)
|
||||||
old_title TEXT,
|
old_title TEXT,
|
||||||
old_cover_path TEXT, -- 旧封面本地图片路径
|
old_cover_path TEXT, -- 旧封面本地图片路径
|
||||||
-- AI 输出
|
-- AI 输出
|
||||||
new_title TEXT,
|
new_title TEXT,
|
||||||
new_cover_path TEXT, -- 新封面本地图片路径
|
new_cover_path TEXT, -- 新封面本地图片路径
|
||||||
-- 应用
|
-- 应用
|
||||||
committed INTEGER DEFAULT 0, -- 是否成功点「更新」提交
|
committed INTEGER NOT NULL DEFAULT 0, -- 是否成功点「更新」提交
|
||||||
stage TEXT DEFAULT 'imported', -- imported/collected/generated/applied/failed/skipped
|
stage TEXT NOT NULL DEFAULT 'imported', -- imported/collected/generated/applied
|
||||||
error TEXT,
|
status TEXT NOT NULL DEFAULT 'pending', -- pending/running/success/failed/skipped/cancelled
|
||||||
updated_at TEXT
|
last_error TEXT,
|
||||||
|
collect_attempts INTEGER NOT NULL DEFAULT 0,
|
||||||
|
generate_attempts INTEGER NOT NULL DEFAULT 0,
|
||||||
|
apply_attempts INTEGER NOT NULL DEFAULT 0,
|
||||||
|
imported_at TEXT NOT NULL,
|
||||||
|
collected_at TEXT,
|
||||||
|
generated_at TEXT,
|
||||||
|
applied_at TEXT,
|
||||||
|
updated_at TEXT NOT NULL,
|
||||||
|
UNIQUE(batch_id, source_file_abs, source_sheet, source_row)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE INDEX idx_tasks_batch_stage_status ON tasks(batch_id, stage, status);
|
||||||
|
CREATE INDEX idx_tasks_alias ON tasks(alias);
|
||||||
|
CREATE INDEX idx_tasks_item ON tasks(item_id);
|
||||||
```
|
```
|
||||||
|
|
||||||
关键事实:
|
关键事实:
|
||||||
|
|
||||||
- `alias` 是账号↔任务**唯一关联键**;找不到账号 → stage=skipped,error=别名未匹配,最后弹窗汇总。
|
- `alias` 是账号↔任务**唯一关联键**;找不到账号 → stage=skipped,error=别名未匹配,最后弹窗汇总。
|
||||||
- `account_name` 仅展示/参考;匹配以 `alias` 为准。
|
- `account_name` 仅展示/参考;匹配以 `alias` 为准。
|
||||||
|
- `source_file_abs/source_sheet/source_row` 是回写 Excel 的权威定位;即使商品 ID 重复,也按原行回写。
|
||||||
|
- `row_key` 防止同一批次内重复导入同一行。
|
||||||
- `old_title/old_cover_path`:程序**采集阶段抓取**的快照(输出)。
|
- `old_title/old_cover_path`:程序**采集阶段抓取**的快照(输出)。
|
||||||
- `new_title/new_cover_path`:**AI 生成**结果(输出),图片落本地;不设逐条确认阶段,生成即可进入 ③。
|
- `new_title/new_cover_path`:**AI 生成**结果(输出),图片落本地;不设逐条确认阶段,生成即可进入 ③。
|
||||||
|
- `stage` 表示已完成到哪个业务阶段;`status` 表示当前处理结果。失败时 `stage` 保持在最后成功阶段,`status=failed`,错误写 `last_error`。
|
||||||
- `committed`:③ 用户确认批量更新弹窗后逐条点「更新」提交;该字段记录提交是否成功。
|
- `committed`:③ 用户确认批量更新弹窗后逐条点「更新」提交;该字段记录提交是否成功。
|
||||||
- 各字段**每阶段处理完立即写回 SQLite**(实时落库);阶段结束后批量回写 Excel。
|
- 各字段**每阶段处理完立即写回 SQLite**(实时落库);阶段结束后批量回写 Excel。
|
||||||
|
|
||||||
|
### 5.2b SQLite 并发与连接规则
|
||||||
|
|
||||||
|
- `db.connect()` 统一设置:`PRAGMA foreign_keys=ON`、`PRAGMA journal_mode=WAL`、`PRAGMA busy_timeout=5000`、`PRAGMA synchronous=NORMAL`。
|
||||||
|
- SQLite connection 不跨线程共享;每个 PySide6 worker / 后台线程按需创建自己的 connection。
|
||||||
|
- 写操作使用短事务:单条任务完成即提交,避免长时间占用写锁。
|
||||||
|
- 写库遇到 locked/busy:按短间隔重试,超过 busy timeout 后返回明确错误并通过 signal 通知 GUI。
|
||||||
|
- GUI 不直接缓存“事实状态”;写库成功后由 worker 发 `row_updated`,GUI 再刷新对应行。
|
||||||
|
- Excel 回写以 SQLite 为事实来源;原 Excel 被锁时不回滚 SQLite,只提示关闭后重试或另存副本。
|
||||||
|
|
||||||
### 5.3 Excel 模板
|
### 5.3 Excel 模板
|
||||||
|
|
||||||
| 列 | 含义 | 输入/输出 |
|
| 列 | 含义 | 输入/输出 |
|
||||||
@@ -328,7 +369,7 @@ cmshopee/
|
|||||||
- CDP 交互事实变化同步第七节。
|
- CDP 交互事实变化同步第七节。
|
||||||
- 存储边界:应用设置→config.json,账号/任务/结果→SQLite,图片→本地目录并记路径于 DB,登录态→user-data-dir;同一事实只存一处。
|
- 存储边界:应用设置→config.json,账号/任务/结果→SQLite,图片→本地目录并记路径于 DB,登录态→user-data-dir;同一事实只存一处。
|
||||||
- 别名是账号↔任务唯一关联键。
|
- 别名是账号↔任务唯一关联键。
|
||||||
- 密码与 AI Key 加密存、不外传、不写日志;不自动登录。
|
- 密码与 AI Key 本地明文保存、UI 打码、不外传、不写日志;不自动登录。
|
||||||
- AI 生成内容直接进入 ③ 更新候选;③ 批量确认后提交,新图本地留档 + 回写 Excel 以备追溯。
|
- AI 生成内容直接进入 ③ 更新候选;③ 批量确认后提交,新图本地留档 + 回写 Excel 以备追溯。
|
||||||
- 高风险模块先单独验证,再接入流水线。
|
- 高风险模块先单独验证,再接入流水线。
|
||||||
- GUI 只通过 signal/slot 接收 worker 进度;禁止后台线程直接操作 Qt widget 或共享 SQLite connection。
|
- GUI 只通过 signal/slot 接收 worker 进度;禁止后台线程直接操作 Qt widget 或共享 SQLite connection。
|
||||||
|
|||||||
@@ -52,7 +52,10 @@
|
|||||||
完成前至少检查:
|
完成前至少检查:
|
||||||
|
|
||||||
- [ ] `python -m py_compile` 通过。
|
- [ ] `python -m py_compile` 通过。
|
||||||
|
- [ ] 纯逻辑改动有对应 `unittest`,至少覆盖正常路径和一个失败路径。
|
||||||
- [ ] 涉及 CDP 的改动,在测试商品(ITEM_ID 51100639510)上实跑验证。
|
- [ ] 涉及 CDP 的改动,在测试商品(ITEM_ID 51100639510)上实跑验证。
|
||||||
|
- [ ] 涉及 DB 的改动,覆盖 schema 初始化、重复初始化、短事务写入、失败状态写入。
|
||||||
|
- [ ] 涉及 Excel 的改动,覆盖 source_file_abs/source_sheet/source_row 回写定位。
|
||||||
- [ ] 对得上需求验收标准(如标题 `value`+`modelvalue` 双等于、封面在第一位)。
|
- [ ] 对得上需求验收标准(如标题 `value`+`modelvalue` 双等于、封面在第一位)。
|
||||||
- [ ] 没有夹带无关改动。
|
- [ ] 没有夹带无关改动。
|
||||||
- [ ] 涉及选择器/流程/配置 schema 变化时,文档已同步。
|
- [ ] 涉及选择器/流程/配置 schema 变化时,文档已同步。
|
||||||
@@ -60,13 +63,14 @@
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
python -m py_compile *.py
|
python -m py_compile *.py
|
||||||
|
python -m unittest discover -s tests
|
||||||
python prototypes/demo.py # 单账号闭环验证(不提交)
|
python prototypes/demo.py # 单账号闭环验证(不提交)
|
||||||
```
|
```
|
||||||
|
|
||||||
## 7. 绝不
|
## 7. 绝不
|
||||||
|
|
||||||
- 绝不把真实账号、密码、Cookie、token 写进代码、文档或日志。
|
- 绝不把真实账号、密码、Cookie、token 写进代码、文档或日志。
|
||||||
- 绝不明文存密码;DB 里密码必须加密,且加密密钥不与密文同存。
|
- 绝不把密码/API Key 写进代码、文档、日志或导出文件;本地配置/DB 可明文保存,必须 gitignore,UI 打码。
|
||||||
- 绝不把 `config.json`、`cmshopee.db`、`chrome_user_data_dir/` 提交版本库。
|
- 绝不把 `config.json`、`cmshopee.db`、`chrome_user_data_dir/` 提交版本库。
|
||||||
- 绝不自动登录 / 自动填账号密码;登录由人工完成,程序只检测登录态。
|
- 绝不自动登录 / 自动填账号密码;登录由人工完成,程序只检测登录态。
|
||||||
- 绝不在缺少 ③ 批量确认弹窗确认的情况下点击「更新」提交线上。
|
- 绝不在缺少 ③ 批量确认弹窗确认的情况下点击「更新」提交线上。
|
||||||
|
|||||||
+9
-7
@@ -23,8 +23,10 @@
|
|||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| T-001 | `editor.py`:改标题/换封面/点更新/登录检测/**采集(读旧标题+旧封面下载)**/apply_task,复用 `cdp.py` | - | 函数可调用,在测试商品跑通;与 `prototypes/demo.py` 行为一致 | TODO |
|
| T-001 | `editor.py`:改标题/换封面/点更新/登录检测/**采集(读旧标题+旧封面下载)**/apply_task,复用 `cdp.py` | - | 函数可调用,在测试商品跑通;与 `prototypes/demo.py` 行为一致 | TODO |
|
||||||
| T-002 | `appconfig.py` + `config.json`(含 image_dir、ai 选择/参数段、端口等默认值;不含 AI Key) | - | 读写正常;不存在则写默认;AI Key 留给 `config/ai_models.json`/T-501 | TODO |
|
| T-002 | `appconfig.py` + `config.json`(含 image_dir、ai 选择/参数段、端口等默认值;不含 AI Key) | - | 读写正常;不存在则写默认;AI Key 留给 `config/ai_models.json`/T-501 | TODO |
|
||||||
| T-003 | `db.py` + SQLite 建表(accounts/tasks,含各阶段字段) | - | `init_db` 幂等;账号/任务/各 set_* 可用;schema 同架构 5.2 | TODO |
|
| T-003 | `db.py` + SQLite 建表(batches/accounts/tasks,含 Excel 行定位、状态、时间戳、重试字段) | - | `init_db` 幂等;`connect` 设置 WAL/busy_timeout/foreign_keys;账号/批次/任务/各 set_* 可用;schema 同架构 5.2 | TODO |
|
||||||
| T-004 | `.gitignore`:排除 `config.json`、`cmshopee.db`、`chrome_user_data_dir/`、`images/` | T-002, T-003 | 凭证/业务/图片不被提交 | TODO |
|
| T-004 | `.gitignore`:排除 `config.json`、`cmshopee.db`、`chrome_user_data_dir/`、`images/` | T-002, T-003 | 凭证/业务/图片不被提交 | TODO |
|
||||||
|
| T-005 | AI 模型清单后端:`config/ai_models.json` 读写 + category 过滤 + 测试连接 | T-002 | 本地明文 api_key;UI/API 打码显示;日志脱敏;至少 text/image 各一个;`get_model` 返回调用所需字段 | TODO |
|
||||||
|
| T-006 | 单元测试基座:`tests/` + appconfig/db/excel/prompts 最小测试 | T-002, T-003 | `python -m unittest discover -s tests` 可跑;不依赖真实 Shopee/AI;临时文件在测试目录清理 | TODO |
|
||||||
|
|
||||||
## Phase 1 · 账号管理(④)
|
## Phase 1 · 账号管理(④)
|
||||||
|
|
||||||
@@ -35,14 +37,14 @@
|
|||||||
| T-103 | 首次登录保活 + 登录检测 `is_logged_in` | T-102, T-001 | 关闭再启动免重登;登录/未登录判断准确 | TODO |
|
| T-103 | 首次登录保活 + 登录检测 `is_logged_in` | T-102, T-001 | 关闭再启动免重登;登录/未登录判断准确 | TODO |
|
||||||
| T-104 | PySide6 五 Tab 主窗口骨架(`QMainWindow` + `QTabWidget`,5 Tab 空壳) | T-002 | 五个 Tab 按顺序可切换;启动不阻塞;基础状态栏可用 | TODO |
|
| T-104 | PySide6 五 Tab 主窗口骨架(`QMainWindow` + `QTabWidget`,5 Tab 空壳) | T-002 | 五个 Tab 按顺序可切换;启动不阻塞;基础状态栏可用 | TODO |
|
||||||
| T-104b | PySide6 worker 基类与线程启动工具(`BaseWorker` + `QThread` 包装) | T-104 | signals: progress/log/row_updated/failed/finished/cancelled;取消标记可用;worker 不直接操作 QWidget | TODO |
|
| T-104b | PySide6 worker 基类与线程启动工具(`BaseWorker` + `QThread` 包装) | T-104 | signals: progress/log/row_updated/failed/finished/cancelled;取消标记可用;worker 不直接操作 QWidget | TODO |
|
||||||
| T-105 | Tab④ 账号增删改(账号名/别名/端口/密码加密)+ 启动登录 + 检测登录 | T-104, T-101, T-103 | 增删改入库、建目录;密码加密默认打码;状态列刷新 | TODO |
|
| T-105 | Tab④ 账号增删改(账号名/别名/端口/密码本地明文仅参考)+ 启动登录 + 检测登录 | T-104, T-101, T-103 | 增删改入库、建目录;密码字段 UI 打码;状态列刷新;不自动登录/填密码 | TODO |
|
||||||
| T-106 | 可选:为账号生成桌面快捷方式 | T-102 | `.lnk` 目标含该账号参数;双击进对应账号 | TODO |
|
| T-106 | 可选:为账号生成桌面快捷方式 | T-102 | `.lnk` 目标含该账号参数;双击进对应账号 | TODO |
|
||||||
|
|
||||||
## Phase 2 · 导入采集(①)
|
## Phase 2 · 导入采集(①)
|
||||||
|
|
||||||
| ID | 任务 | 依赖 | 验收要点 | 状态 |
|
| ID | 任务 | 依赖 | 验收要点 | 状态 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| T-201 | `excel.py` 导入:解析多文件输入列入库 | T-003 | 按模板解析账号名/别名/商品id;脏数据容错;写 tasks(batch_id) | TODO |
|
| T-201 | `excel.py` 导入:解析多文件输入列入库 | T-003 | 按模板解析账号名/别名/商品id;记录 source_file_abs/source_sheet/source_row/row_key;脏数据容错;写 batches/tasks | TODO |
|
||||||
| T-202 | Tab① 任务列表 + 导入按钮 + 别名匹配标记 | T-201, T-105 | `QTableView` 显示账号/别名/商品id/阶段;未匹配标“略过” | TODO |
|
| T-202 | Tab① 任务列表 + 导入按钮 + 别名匹配标记 | T-201, T-105 | `QTableView` 显示账号/别名/商品id/阶段;未匹配标“略过” | TODO |
|
||||||
| T-202b | Tab① 导入汇总栏 | T-202 | 导入后显示 文件数/解析行数/有效/无效/匹配(按账号)/未匹配;未匹配可点击筛出 | TODO |
|
| T-202b | Tab① 导入汇总栏 | T-202 | 导入后显示 文件数/解析行数/有效/无效/匹配(按账号)/未匹配;未匹配可点击筛出 | TODO |
|
||||||
| T-203 | 采集旧标题+旧封面(只读),下载图片,立即写库 | T-202, T-001, T-104b | 通过 worker 执行;逐条 set_collected;旧封面下载到 `images/<slug>/`;未登录/未匹配略过记原因 | TODO |
|
| T-203 | 采集旧标题+旧封面(只读),下载图片,立即写库 | T-202, T-001, T-104b | 通过 worker 执行;逐条 set_collected;旧封面下载到 `images/<slug>/`;未登录/未匹配略过记原因 | TODO |
|
||||||
@@ -53,7 +55,7 @@
|
|||||||
|
|
||||||
| ID | 任务 | 依赖 | 验收要点 | 状态 |
|
| ID | 任务 | 依赖 | 验收要点 | 状态 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| T-301 | 确定 AI 服务商/模型并接入 `ai.py`(`gen_title`/`gen_cover`,带重试/分辨率/jpg质量) | T-002 | 可调;Key 加密读取;`gen_cover` 支持 resolution+jpg_quality;失败按 retry 重试;错误明确 | TODO |
|
| T-301 | 确定 AI 服务商/模型并接入 `ai.py`(`gen_title`/`gen_cover`,带重试/分辨率/jpg质量) | T-005 | 从 `config/ai_models.json` 读取模型与本地明文 Key;`gen_cover` 支持 resolution+jpg_quality;失败按 retry 重试;错误明确;日志脱敏 | TODO |
|
||||||
| T-302 | Tab② 左右布局:左提示词(标题/封面),右按批次/店铺/状态筛选 + 任务列表 | T-301, T-203 | 左 ~1/4 提示词多行;右筛选+列表(店铺/商品id/旧标题/新标题/状态) | TODO |
|
| T-302 | Tab② 左右布局:左提示词(标题/封面),右按批次/店铺/状态筛选 + 任务列表 | T-301, T-203 | 左 ~1/4 提示词多行;右筛选+列表(店铺/商品id/旧标题/新标题/状态) | TODO |
|
||||||
| T-302p | `prompts.py` + Tab② 提示词管理 | T-302 | 标题保存/启动回显 title_prompt.txt;封面多模板(下拉+新建/保存/另存为/重命名/删除,存 prompts/cover/);插入 `{新标题}`;预览变量替换;render_prompt 接入生成 | TODO |
|
| T-302p | `prompts.py` + Tab② 提示词管理 | T-302 | 标题保存/启动回显 title_prompt.txt;封面多模板(下拉+新建/保存/另存为/重命名/删除,存 prompts/cover/);插入 `{新标题}`;预览变量替换;render_prompt 接入生成 | TODO |
|
||||||
| T-303 | Tab② 开始生成(单按钮)+ 停止 + 进度:**先并发标题再并发图片** | T-302, T-104b | `generate_batch` 先 title_concurrency 并发标题、再 image_concurrency 并发图片;worker/signal 回传进度;每条 set_generated 立即写库;停止可取消未开始项;进度 标题/封面/失败 计数;双击弹窗看新旧封面 | TODO |
|
| T-303 | Tab② 开始生成(单按钮)+ 停止 + 进度:**先并发标题再并发图片** | T-302, T-104b | `generate_batch` 先 title_concurrency 并发标题、再 image_concurrency 并发图片;worker/signal 回传进度;每条 set_generated 立即写库;停止可取消未开始项;进度 标题/封面/失败 计数;双击弹窗看新旧封面 | TODO |
|
||||||
@@ -70,15 +72,15 @@
|
|||||||
|
|
||||||
| ID | 任务 | 依赖 | 验收要点 | 状态 |
|
| ID | 任务 | 依赖 | 验收要点 | 状态 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| T-501 | Tab⑤ 设置 · AI 模型管理(master-detail):模型下拉 + 新增/删除 + 详情(服务商名/类别/api_type/模型ID/网址/密钥打码/连接超时) + 测试连接 | T-002 | 读写 `config/ai_models.json`;name 唯一;类别 text/image;至少各一个;密钥打码加密;测试连接可用 | TODO |
|
| T-501 | Tab⑤ 设置 · AI 模型管理 UI(master-detail):模型下拉 + 新增/删除 + 详情(服务商名/类别/api_type/模型ID/网址/密钥打码/连接超时) + 测试连接 | T-005, T-104 | 复用 T-005 后端;name 唯一;类别 text/image;至少各一个;密钥本地明文保存、UI 打码;测试连接可用 | TODO |
|
||||||
| T-501b | Tab⑤ 设置 · 角色与生成参数:标题大模型/图片大模型下拉、分辨率(512/1k/2k/4k)、返回超时随分辨率、并发/重试/jpg质量、路径/端口 | T-501 | 角色下拉按类别过滤;分辨率选后返回超时按 resolution_timeouts 自动;持久化 config.json | TODO |
|
| T-501b | Tab⑤ 设置 · 角色与生成参数:标题大模型/图片大模型下拉、分辨率(512/1k/2k/4k)、返回超时随分辨率、并发/重试/jpg质量、路径/端口 | T-501 | 角色下拉按类别过滤;分辨率选后返回超时按 resolution_timeouts 自动;持久化 config.json | TODO |
|
||||||
| T-502 | 满 9 张封面:删第一张再上传 | T-001 | 实测删除确认框并处理;满 9 张流程正确 | TODO |
|
| T-502 | 满 9 张封面:删第一张再上传 | T-001 | 实测删除确认框并处理;满 9 张流程正确 | TODO |
|
||||||
| T-503 | 密码 / AI Key 加密密钥方案落地 | T-105, T-501 | 密钥不与密文同存;说明威胁模型 | TODO |
|
| T-503 | 敏感信息本地明文存储提示与日志脱敏 | T-105, T-501 | 首次保存密码/API Key 时提示“本地明文保存”;UI 打码;日志/导出不含密码/API Key;文档说明 config/DB 必须 gitignore | TODO |
|
||||||
| T-504 | 多账号并行 / dry-run / 运行日志(V2) | T-402 | 端口不冲突;dry-run 只预览;操作留痕 | TODO |
|
| T-504 | 多账号并行 / dry-run / 运行日志(V2) | T-402 | 端口不冲突;dry-run 只预览;操作留痕 | TODO |
|
||||||
|
|
||||||
## 里程碑
|
## 里程碑
|
||||||
|
|
||||||
- M1:editor(含采集)模块化、config.json + SQLite 就绪(Phase 0)。
|
- M1:editor(含采集)模块化、config.json + SQLite + AI 模型清单后端 + 测试基座就绪(Phase 0)。
|
||||||
- M2:账号管理可用、能登录与检测(Phase 1)。
|
- M2:账号管理可用、能登录与检测(Phase 1)。
|
||||||
- M3:导入 + 采集 + 回写旧数据(Phase 2)。
|
- M3:导入 + 采集 + 回写旧数据(Phase 2)。
|
||||||
- M4:AI 生成新标题/新封面(Phase 3)。
|
- M4:AI 生成新标题/新封面(Phase 3)。
|
||||||
|
|||||||
+29
-15
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
- 形态:本地函数 + 子进程(Chrome)+ CDP(`127.0.0.1:<port>`)+ SQLite + openpyxl + AI 服务调用。
|
- 形态:本地函数 + 子进程(Chrome)+ CDP(`127.0.0.1:<port>`)+ SQLite + openpyxl + AI 服务调用。
|
||||||
- 编码:UTF-8;传 Chrome / `setFileInputFiles` 的路径为 **Windows 绝对路径**。
|
- 编码:UTF-8;传 Chrome / `setFileInputFiles` 的路径为 **Windows 绝对路径**。
|
||||||
- 凭证:登录态在 user-data-dir;密码、AI Key 加密存于 config/DB,不出现在日志/导出明文。
|
- 凭证:登录态在 user-data-dir;密码、AI Key 本地明文存于 config/DB,文件必须 gitignore;UI 打码显示,不出现在日志/导出。
|
||||||
- 失败处理:抛带中文说明的异常或返回状态字段;GUI 负责提示,不静默吞错。
|
- 失败处理:抛带中文说明的异常或返回状态字段;GUI 负责提示,不静默吞错。
|
||||||
|
|
||||||
## appconfig 模块(`appconfig.py`,待建)
|
## appconfig 模块(`appconfig.py`,待建)
|
||||||
@@ -24,13 +24,13 @@ ai_config() -> dict # default_text_model/default_image_
|
|||||||
# resolution/resolution_timeouts
|
# resolution/resolution_timeouts
|
||||||
response_timeout() -> int # = resolution_timeouts[resolution](返回超时,随分辨率)
|
response_timeout() -> int # = resolution_timeouts[resolution](返回超时,随分辨率)
|
||||||
|
|
||||||
# AI 模型清单 config/ai_models.json(含密钥;CRUD 由 ⑤ 设置)
|
# AI 模型清单 config/ai_models.json(含本地明文密钥;CRUD 由 ⑤ 设置)
|
||||||
list_ai_models(category=None) -> list[dict] # category=text/image 过滤;含 connect_timeout_seconds 等
|
list_ai_models(category=None) -> list[dict] # category=text/image 过滤;含 connect_timeout_seconds 等
|
||||||
add_ai_model(model) -> None # name 唯一校验
|
add_ai_model(model) -> None # name 唯一校验
|
||||||
update_ai_model(name, **fields) -> None
|
update_ai_model(name, **fields) -> None
|
||||||
delete_ai_model(name) -> None # 至少各留一个 text+image;删到剩一禁用
|
delete_ai_model(name) -> None # 至少各留一个 text+image;删到剩一禁用
|
||||||
test_ai_model(name) -> dict # 「测试连接」:用 key/url/model 发最小请求 -> {ok, error}
|
test_ai_model(name) -> dict # 「测试连接」:用 key/url/model 发最小请求 -> {ok, error}
|
||||||
get_model(name) -> dict # 解密 api_key 供调用
|
get_model(name) -> dict # 返回模型定义,含 api_key(调用方不得写日志)
|
||||||
```
|
```
|
||||||
|
|
||||||
## db 模块(`db.py`,待建)
|
## db 模块(`db.py`,待建)
|
||||||
@@ -38,28 +38,42 @@ get_model(name) -> dict # 解密 api_key 供调用
|
|||||||
SQLite 读写,表见 [架构 5.2](04-architecture.md)。
|
SQLite 读写,表见 [架构 5.2](04-architecture.md)。
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
connect(path=None) -> sqlite3.Connection # 设置 foreign_keys/WAL/busy_timeout/synchronous/row_factory
|
||||||
init_db(path)
|
init_db(path)
|
||||||
|
create_batch(file_paths, note=None) -> str
|
||||||
|
get_batch(batch_id) -> Batch|None
|
||||||
|
list_batches(status=None) -> list[Batch]
|
||||||
|
update_batch(batch_id, **fields) -> None
|
||||||
# 账号
|
# 账号
|
||||||
list_accounts() -> list[Account]
|
list_accounts() -> list[Account]
|
||||||
get_account_by_alias(alias) -> Account|None
|
get_account_by_alias(alias) -> Account|None
|
||||||
add_account(account_name, alias, region_host, debug_port, password_enc=None, note=None) -> Account
|
add_account(account_name, alias, region_host, debug_port, password=None, note=None) -> Account
|
||||||
update_account(alias, **fields) -> None
|
update_account(alias, **fields) -> None
|
||||||
delete_account(alias) -> None
|
delete_account(alias) -> None
|
||||||
# 任务 / 各阶段结果
|
# 任务 / 各阶段结果
|
||||||
insert_tasks(batch_id, rows) -> int # 写输入列
|
insert_tasks(batch_id, rows) -> int # 写输入列;rows 含 source_file_abs/source_sheet/source_row/row_key
|
||||||
list_tasks(batch_id=None, stage=None) -> list[Task]
|
list_tasks(batch_id=None, stage=None, status=None, alias=None) -> list[Task]
|
||||||
set_collected(task_id, old_title, old_cover_path) -> None # 采集结果,立即写
|
mark_running(task_id, phase) -> None
|
||||||
set_generated(task_id, new_title, new_cover_path) -> None # AI 结果,立即写
|
mark_failed(task_id, phase, error) -> None
|
||||||
set_applied(task_id, committed, error=None) -> None # 更新结果,立即写
|
mark_skipped(task_id, reason) -> None
|
||||||
|
set_collected(task_id, old_title, old_cover_path) -> None # stage=collected,status=success, attempts+1
|
||||||
|
set_generated(task_id, new_title, new_cover_path) -> None # stage=generated,status=success, attempts+1
|
||||||
|
set_applied(task_id, committed, error=None) -> None # stage=applied,status=success/failed, attempts+1
|
||||||
```
|
```
|
||||||
|
|
||||||
`stage` 随各 set_* 推进(imported→collected→generated→applied);任意步失败写 `error` 且 stage 标 failed/skipped。无 confirmed 阶段。
|
`stage` 表示最后成功业务阶段(imported→collected→generated→applied);`status` 表示当前处理结果(pending/running/success/failed/skipped/cancelled)。任意步失败写 `last_error` 且 `status=failed`,`stage` 不前进。无 confirmed 阶段。
|
||||||
|
|
||||||
|
SQLite 连接规则:
|
||||||
|
|
||||||
|
- 每个 worker/线程使用自己的 `connect()`;禁止跨线程共享 connection。
|
||||||
|
- `connect()` 必须设置 `PRAGMA foreign_keys=ON`、`journal_mode=WAL`、`busy_timeout=5000`、`synchronous=NORMAL`。
|
||||||
|
- DB 写入短事务、单条提交;Excel 回写失败不回滚 DB。
|
||||||
|
|
||||||
## excel 模块(`excel.py`,待建,依赖 openpyxl)
|
## excel 模块(`excel.py`,待建,依赖 openpyxl)
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import_tasks(file_paths: list[str]) -> dict
|
import_tasks(file_paths: list[str]) -> dict
|
||||||
# 只解析【输入列】:账号名、别名、商品id(+ source_file);输出列运行时回写
|
# 只解析【输入列】:账号名、别名、商品id;并记录 source_file/source_file_abs/source_sheet/source_row/row_key
|
||||||
# -> {"rows": [...], "stats": {"files": int, "total": int, "valid": int, "invalid": int}}
|
# -> {"rows": [...], "stats": {"files": int, "total": int, "valid": int, "invalid": int}}
|
||||||
# invalid = 缺别名/商品id 或脏数据的行
|
# invalid = 缺别名/商品id 或脏数据的行
|
||||||
|
|
||||||
@@ -67,10 +81,11 @@ match_summary(rows: list[dict], accounts: list) -> dict
|
|||||||
# 用 accounts 的别名对 rows 做匹配统计(导入汇总栏用)
|
# 用 accounts 的别名对 rows 做匹配统计(导入汇总栏用)
|
||||||
# -> {"matched": int, "unmatched": int, "by_account": {别名: 行数}, "unmatched_aliases": [..]}
|
# -> {"matched": int, "unmatched": int, "by_account": {别名: 行数}, "unmatched_aliases": [..]}
|
||||||
|
|
||||||
write_back(batch_id, excel_path) -> str
|
write_back(batch_id, excel_path=None) -> dict
|
||||||
# 把【旧标题/旧封面/新标题/新封面/更新状态】批量回写到【原 Excel】
|
# 把【旧标题/旧封面/新标题/新封面/更新状态】批量回写到【原 Excel】
|
||||||
|
# excel_path 为空则按 source_file_abs 分组回写本批次涉及的所有原文件
|
||||||
# 原文件被占用(锁) → 抛错,调用方提示“请关闭后重试”,或改用 export_copy
|
# 原文件被占用(锁) → 抛错,调用方提示“请关闭后重试”,或改用 export_copy
|
||||||
export_copy(batch_id, out_path) -> str # 退路:另存新结果文件,不动原文件
|
export_copy(batch_id, out_dir_or_path) -> dict # 退路:另存新结果文件,不动原文件
|
||||||
```
|
```
|
||||||
|
|
||||||
列模板见 [架构 5.3](04-architecture.md);别名以“别名”列为权威。
|
列模板见 [架构 5.3](04-architecture.md);别名以“别名”列为权威。
|
||||||
@@ -139,7 +154,7 @@ generate_batch(tasks, prompts, ai_cfg, on_progress, should_stop) -> None
|
|||||||
|
|
||||||
- 标题用 `default_text_model`、封面用 `default_image_model`(`appconfig.get_model` 取定义,含 url/key/api_type)。
|
- 标题用 `default_text_model`、封面用 `default_image_model`(`appconfig.get_model` 取定义,含 url/key/api_type)。
|
||||||
- 连接超时 = 模型 `connect_timeout_seconds`;**返回超时 = `appconfig.response_timeout()`(随分辨率:512/1k/2k/4k → 180/240/360/600)**。
|
- 连接超时 = 模型 `connect_timeout_seconds`;**返回超时 = `appconfig.response_timeout()`(随分辨率:512/1k/2k/4k → 180/240/360/600)**。
|
||||||
- 并发数/重试/分辨率/jpg 质量来自 `appconfig.ai_config()`;Key 加密存、不入日志。
|
- 并发数/重试/分辨率/jpg 质量来自 `appconfig.ai_config()`;Key 本地明文存储,但不入日志、不导出。
|
||||||
- 标题快、图片慢:分两段、各用各自并发数;失败按 `retry` 重试,仍失败记 error 不阻塞其余。
|
- 标题快、图片慢:分两段、各用各自并发数;失败按 `retry` 重试,仍失败记 error 不阻塞其余。
|
||||||
- 调用有成本与失败可能:超时、限流、内容安全拒绝都要返回明确错误。
|
- 调用有成本与失败可能:超时、限流、内容安全拒绝都要返回明确错误。
|
||||||
- 生成结果**直接进入 ③ 更新候选**;③ 点击「开始更新」后弹窗批量确认,确认后提交线上。本地留档 + 回写 Excel 供追溯。
|
- 生成结果**直接进入 ③ 更新候选**;③ 点击「开始更新」后弹窗批量确认,确认后提交线上。本地留档 + 回写 Excel 供追溯。
|
||||||
@@ -209,7 +224,6 @@ set UPDATE=1 && python prototypes/demo.py # 走完点击「更新」提交
|
|||||||
## 待实现时确认
|
## 待实现时确认
|
||||||
|
|
||||||
- AI 服务商/模型/计费;图像 image-to-image 能力与合规。
|
- AI 服务商/模型/计费;图像 image-to-image 能力与合规。
|
||||||
- 密码、AI Key 加密的密钥来源(机器派生 / 主口令)。
|
|
||||||
- 满 9 张删除封面的确认框选择器(需实测)。
|
- 满 9 张删除封面的确认框选择器(需实测)。
|
||||||
- Excel 缺列/脏数据容错(整文件拒绝 vs 逐行跳过)。
|
- Excel 缺列/脏数据容错(整文件拒绝 vs 逐行跳过)。
|
||||||
- 旧封面下载的图片格式/扩展名处理。
|
- 旧封面下载的图片格式/扩展名处理。
|
||||||
|
|||||||
@@ -9,14 +9,14 @@
|
|||||||
- 阶段:V0 单账号 CDP 流程已验证;V1 多账号管理 + 5 Tab GUI + Excel/AI 流水线为既定设计,尚未开始编码。
|
- 阶段:V0 单账号 CDP 流程已验证;V1 多账号管理 + 5 Tab GUI + Excel/AI 流水线为既定设计,尚未开始编码。
|
||||||
- 技术栈:Python 3.10+,自研 CDP(websocket-client + requests),SQLite(sqlite3)+ `config.json` + openpyxl + AI(服务商待定),GUI PySide6 5 Tab(已定)。
|
- 技术栈:Python 3.10+,自研 CDP(websocket-client + requests),SQLite(sqlite3)+ `config.json` + openpyxl + AI(服务商待定),GUI PySide6 5 Tab(已定)。
|
||||||
- 生产代码:尚无 `appconfig/db/excel/config/chrome/editor/gui/workers`;现有为验证脚本 + `cdp.py`。
|
- 生产代码:尚无 `appconfig/db/excel/config/chrome/editor/gui/workers`;现有为验证脚本 + `cdp.py`。
|
||||||
- 测试:以 `py_compile` + 在测试商品上手动跑 `prototypes/demo.py` 为主,无自动化测试。
|
- 测试:当前以 `py_compile` + 在测试商品上手动跑 `prototypes/demo.py` 为主;T-006 将补 `unittest` 自动化测试基座。
|
||||||
- 数据:无 `config.json`、`cmshopee.db`、`chrome_user_data_dir/`(待 Phase 0/1 建立)。
|
- 数据:无 `config.json`、`cmshopee.db`、`chrome_user_data_dir/`(待 Phase 0/1 建立)。
|
||||||
|
|
||||||
## 既定设计要点(文档已定)
|
## 既定设计要点(文档已定)
|
||||||
|
|
||||||
- GUI:**PySide6 5 Tab 流水线**,顺序 ① 导入采集 → ② AI生成 → ③ 更新shopee → ④ 账号管理 → ⑤ 设置;后台任务用 worker/QThread/signal。
|
- GUI:**PySide6 5 Tab 流水线**,顺序 ① 导入采集 → ② AI生成 → ③ 更新shopee → ④ 账号管理 → ⑤ 设置;后台任务用 worker/QThread/signal。
|
||||||
- 流水线阶段:imported → collected(采集旧标题/旧封面+下载+回写)→ generated(AI 提示词生成新标题/新封面)→ applied(③ 弹窗批量确认后改 Shopee 并提交)。**无 confirmed、无常驻提交开关。**
|
- 流水线阶段:imported → collected(采集旧标题/旧封面+下载+回写)→ generated(AI 提示词生成新标题/新封面)→ applied(③ 弹窗批量确认后改 Shopee 并提交)。**无 confirmed、无常驻提交开关。**
|
||||||
- 存储:`config.json`(应用设置)+ `config/ai_models.json`(AI 模型清单与加密 Key)+ SQLite `cmshopee.db`(账号/任务/各阶段结果)+ openpyxl(Excel)+ 本地 `images/`(旧/新封面)。
|
- 存储:`config.json`(应用设置)+ `config/ai_models.json`(AI 模型清单与本地明文 Key)+ SQLite `cmshopee.db`(账号/任务/各阶段结果)+ openpyxl(Excel)+ 本地 `images/`(旧/新封面)。
|
||||||
- 多账号隔离:每账号独立 user-data-dir(非 profile)。
|
- 多账号隔离:每账号独立 user-data-dir(非 profile)。
|
||||||
- 账号↔任务绑定:以 Excel“别名”列为权威;未匹配略过,结束弹窗汇总。
|
- 账号↔任务绑定:以 Excel“别名”列为权威;未匹配略过,结束弹窗汇总。
|
||||||
- 执行:多账号串行、单条失败继续;③ 点击「开始更新」后弹窗确认当前筛选范围和任务数量,确认后逐条点「更新」提交线上。
|
- 执行:多账号串行、单条失败继续;③ 点击「开始更新」后弹窗确认当前筛选范围和任务数量,确认后逐条点「更新」提交线上。
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
- 已完成:无(任务均为 TODO;单账号能力以脚本形式存在,待 T-001 模块化)。
|
- 已完成:无(任务均为 TODO;单账号能力以脚本形式存在,待 T-001 模块化)。
|
||||||
- 正在进行:无。
|
- 正在进行:无。
|
||||||
- 下一个可领取任务:Phase 0 的 **T-001(`editor.py` 含采集)/ T-002(`appconfig.py`+`config.json`)/ T-003(`db.py`+SQLite)**——三者无相互依赖,可任选其一起步。
|
- 下一个可领取任务:Phase 0 的 **T-001(`editor.py` 含采集)/ T-002(`appconfig.py`+`config.json`)/ T-003(`db.py`+SQLite)**——三者无相互依赖,可任选其一起步;AI 真实接入前先做 T-005。
|
||||||
|
|
||||||
## 当前可运行内容
|
## 当前可运行内容
|
||||||
|
|
||||||
@@ -56,6 +56,9 @@
|
|||||||
# 语法检查
|
# 语法检查
|
||||||
python -m py_compile *.py
|
python -m py_compile *.py
|
||||||
|
|
||||||
|
# 单元测试(T-006 后)
|
||||||
|
python -m unittest discover -s tests
|
||||||
|
|
||||||
# 单账号闭环(不提交线上)
|
# 单账号闭环(不提交线上)
|
||||||
python prototypes/demo.py # 分步(需根目录 cdp.py 可导入)
|
python prototypes/demo.py # 分步(需根目录 cdp.py 可导入)
|
||||||
set AUTO=1 && python prototypes/demo.py # 自动(cmd)
|
set AUTO=1 && python prototypes/demo.py # 自动(cmd)
|
||||||
|
|||||||
+3
-3
@@ -13,7 +13,7 @@
|
|||||||
| ① 导入采集 | 导入多个 Excel;任务列表;**采集**商品当前的旧标题/旧封面(只读),封面图下载本地;回写 Excel 旧字段 | 只读,低 |
|
| ① 导入采集 | 导入多个 Excel;任务列表;**采集**商品当前的旧标题/旧封面(只读),封面图下载本地;回写 Excel 旧字段 | 只读,低 |
|
||||||
| ② AI生成 | 左侧标题/封面**提示词**;右侧按批次/店铺筛选任务列表;AI 生成新标题/新封面;双击看新旧封面 | 不触线上,中 |
|
| ② AI生成 | 左侧标题/封面**提示词**;右侧按批次/店铺筛选任务列表;AI 生成新标题/新封面;双击看新旧封面 | 不触线上,中 |
|
||||||
| ③ 更新shopee | 对**已生成**任务点击「开始更新」后弹窗确认;确认后打开编辑页换标题+封面并逐条点「更新」提交;结果回写 Excel | **写线上,高** |
|
| ③ 更新shopee | 对**已生成**任务点击「开始更新」后弹窗确认;确认后打开编辑页换标题+封面并逐条点「更新」提交;结果回写 Excel | **写线上,高** |
|
||||||
| ④ 账号管理 | Shopee 账号(账号名/别名/数据目录/端口/密码加密/登录状态);启动登录、检测登录、生成快捷方式 | 中 |
|
| ④ 账号管理 | Shopee 账号(账号名/别名/数据目录/端口/密码本地明文仅参考/登录状态);启动登录、检测登录、生成快捷方式 | 中 |
|
||||||
| ⑤ 设置 | AI 模型/API Key、本地图片目录、Chrome 路径、默认端口等 | — |
|
| ⑤ 设置 | AI 模型/API Key、本地图片目录、Chrome 路径、默认端口等 | — |
|
||||||
|
|
||||||
任务的**阶段状态**贯穿各 Tab:`imported → collected → generated → applied`(或 `failed/skipped`)。② 不设逐条人工确认阶段;③ 无常驻提交开关,但点击「开始更新」后必须弹窗确认当前筛选范围和任务数量。各 Tab 聚焦各自阶段的列与按钮,但操作同一批任务(同一 batch)。
|
任务的**阶段状态**贯穿各 Tab:`imported → collected → generated → applied`(或 `failed/skipped`)。② 不设逐条人工确认阶段;③ 无常驻提交开关,但点击「开始更新」后必须弹窗确认当前筛选范围和任务数量。各 Tab 聚焦各自阶段的列与按钮,但操作同一批任务(同一 batch)。
|
||||||
@@ -107,11 +107,11 @@
|
|||||||
└───────────────────────────────────────────────────────────────┘
|
└───────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
账号弹窗字段:账号名、别名(唯一,Excel 用它匹配)、地区域名、调试端口、密码(加密仅参考)、备注;配置目录按别名生成 slug 只读显示。
|
账号弹窗字段:账号名、别名(唯一,Excel 用它匹配)、地区域名、调试端口、密码(本地明文仅参考,UI 打码,不自动登录)、备注;配置目录按别名生成 slug 只读显示。
|
||||||
|
|
||||||
## ⑤ 设置
|
## ⑤ 设置
|
||||||
|
|
||||||
- AI:服务商 / 文本模型 / 图像模型 / API Key(加密存)。
|
- AI:服务商 / 文本模型 / 图像模型 / API Key(本地明文存,UI 打码,不入日志)。
|
||||||
- AI 生成参数:**标题并发数、图片并发数、失败重试次数、分辨率、jpg 质量**。
|
- AI 生成参数:**标题并发数、图片并发数、失败重试次数、分辨率、jpg 质量**。
|
||||||
- 本地图片目录(旧封面下载、新封面生成的存放根目录)。
|
- 本地图片目录(旧封面下载、新封面生成的存放根目录)。
|
||||||
- Chrome 路径、默认调试端口 / 端口范围、超时、DB 路径。
|
- Chrome 路径、默认调试端口 / 端口范围、超时、DB 路径。
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
<rect class="card" x="0" y="0" width="168" height="210" rx="8"/>
|
<rect class="card" x="0" y="0" width="168" height="210" rx="8"/>
|
||||||
<text class="tt" x="14" y="28">④ 账号管理</text>
|
<text class="tt" x="14" y="28">④ 账号管理</text>
|
||||||
<text class="ds" x="14" y="52">账号名/别名/端口</text>
|
<text class="ds" x="14" y="52">账号名/别名/端口</text>
|
||||||
<text class="ds" x="14" y="72">密码加密·仅参考</text>
|
<text class="ds" x="14" y="72">密码本地明文·仅参考</text>
|
||||||
<text class="ds" x="14" y="92">独立 user-data-dir</text>
|
<text class="ds" x="14" y="92">独立 user-data-dir</text>
|
||||||
<text class="ds" x="14" y="112">启动并登录(人工)</text>
|
<text class="ds" x="14" y="112">启动并登录(人工)</text>
|
||||||
<text class="ds" x="14" y="132">检测登录状态</text>
|
<text class="ds" x="14" y="132">检测登录状态</text>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
@@ -63,7 +63,7 @@
|
|||||||
<text x="20" y="92">别名*</text><rect class="inp" x="96" y="78" width="224" height="22" rx="4"/>
|
<text x="20" y="92">别名*</text><rect class="inp" x="96" y="78" width="224" height="22" rx="4"/>
|
||||||
<text x="20" y="122">地区域名</text><rect class="inp" x="96" y="108" width="224" height="22" rx="4"/>
|
<text x="20" y="122">地区域名</text><rect class="inp" x="96" y="108" width="224" height="22" rx="4"/>
|
||||||
<text x="20" y="152">端口/密码</text><rect class="inp" x="96" y="138" width="108" height="22" rx="4"/>
|
<text x="20" y="152">端口/密码</text><rect class="inp" x="96" y="138" width="108" height="22" rx="4"/>
|
||||||
<rect class="inp" x="212" y="138" width="108" height="22" rx="4"/><text x="222" y="153" fill="#8a92a0">••••(加密)</text>
|
<rect class="inp" x="212" y="138" width="108" height="22" rx="4"/><text x="222" y="153" fill="#8a92a0">••••(本地明文)</text>
|
||||||
</g>
|
</g>
|
||||||
<text class="mut" x="20" y="182">配置目录(只读):chrome_user_data_dir\nuzhuang</text>
|
<text class="mut" x="20" y="182">配置目录(只读):chrome_user_data_dir\nuzhuang</text>
|
||||||
<rect class="btn" x="180" y="186" width="64" height="24" rx="5"/><text class="btnT" x="198" y="202">取消</text>
|
<rect class="btn" x="180" y="186" width="64" height="24" rx="5"/><text class="btnT" x="198" y="202">取消</text>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
@@ -76,6 +76,6 @@
|
|||||||
|
|
||||||
<g transform="translate(0,512)">
|
<g transform="translate(0,512)">
|
||||||
<rect class="btnP" x="822" y="0" width="100" height="34" rx="6"/><text class="btnPT" x="850" y="22">保存设置</text>
|
<rect class="btnP" x="822" y="0" width="100" height="34" rx="6"/><text class="btnPT" x="850" y="22">保存设置</text>
|
||||||
<text class="mut" x="18" y="22">模型清单存 config/ai_models.json(密钥加密);选择与参数存 config.json。均 gitignore。</text>
|
<text class="mut" x="18" y="22">模型清单存 config/ai_models.json(密钥本地明文);选择与参数存 config.json。均 gitignore。</text>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
+12
@@ -180,4 +180,16 @@
|
|||||||
- 新增 `workers.py` 作为可选模块承载 PySide6 worker/QThread 编排。
|
- 新增 `workers.py` 作为可选模块承载 PySide6 worker/QThread 编排。
|
||||||
- 下一步:继续处理 SQLite/Excel schema 与 AI 接入任务依赖。
|
- 下一步:继续处理 SQLite/Excel schema 与 AI 接入任务依赖。
|
||||||
|
|
||||||
|
## 【2026-06-26】补强 · 数据模型 / AI 顺序 / 测试 / SQLite 并发 / 明文敏感信息
|
||||||
|
|
||||||
|
- 状态:DONE(仅文档)
|
||||||
|
- 变更:更新 `docs/04-architecture.md`、`docs/api.md`、`docs/06-tasks.md`、`docs/03-tech-stack.md`、`docs/05-coding-rules.md`、`docs/00-ai-start-here.md`、`docs/02-requirements.md`、`docs/current-state.md`、`docs/routes.md`、`AGENTS.md`、`CLAUDE.md` 与 UI 线框。
|
||||||
|
- 决策:
|
||||||
|
- 数据模型补强:新增 `batches` 表;`tasks` 增加 `source_file_abs/source_sheet/source_row/row_key`、`stage/status` 分离、时间戳、attempts、`last_error`,用于可靠回写、重试与断点续跑。
|
||||||
|
- SQLite 并发:每个 worker 独立 connection;统一 `foreign_keys=ON`、`journal_mode=WAL`、`busy_timeout=5000`、`synchronous=NORMAL`;短事务单条提交。
|
||||||
|
- AI 顺序:先做 T-005 AI 模型清单后端,再做 T-301 真实 AI 接入;T-501 只做设置页 UI。
|
||||||
|
- 测试策略:引入 `tests/` + stdlib `unittest` 基座,优先覆盖 appconfig/db/excel/prompts 纯逻辑;CDP/Shopee/真实 AI 作为集成或手动验证。
|
||||||
|
- 不做加密:密码与 AI Key 本地明文保存,文件必须 gitignore;UI 打码,日志/导出脱敏,不自动登录。
|
||||||
|
- 下一步:继续按任务看板从 Phase 0 开始实现,建议优先 T-003/T-006 或 T-001。
|
||||||
|
|
||||||
<!-- 新一轮从这里向下追加记录。 -->
|
<!-- 新一轮从这里向下追加记录。 -->
|
||||||
|
|||||||
Reference in New Issue
Block a user