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:
chengma
2026-06-26 16:27:33 +08:00
parent 92735ae7a4
commit 3832697fc4
15 changed files with 152 additions and 62 deletions
+62 -21
View File
@@ -41,7 +41,7 @@ Shopee 卖家中心页面 / 本地图片目录
## 二、流水线(核心)
每个任务(Excel 行)依次走过 5 个阶段,状态字段 `stage` 贯穿全程:
每个任务(Excel 行)依次走过 4 个业务阶段,状态字段 `stage` 贯穿全程:
```text
imported → collected → generated → applied
@@ -74,7 +74,7 @@ imported → collected → generated → applied
**存储(同一事实只存一处)**
- 应用配置(模型选择、生成参数、目录、Chrome 路径)→ `config.json`。
- AI 模型清单(url/模型/密钥/类型/连接超时)→ `config/ai_models.json`(含密钥,必须 gitignore)。
- AI 模型清单(url/模型/密钥/类型/连接超时)→ `config/ai_models.json`(API Key 本地明文保存,必须 gitignore,UI 打码显示)。
- 业务数据(账号、任务、各阶段结果)→ SQLite `cmshopee.db`。
- 图片(采集的旧封面、AI 生成的新封面)→ 本地图片目录(路径记在 DB)。
- 提示词 → 标题提示词存单文件 `title_prompt.txt`;封面提示词存多模板 `prompts/cover/<名称>.txt`。
@@ -116,7 +116,7 @@ imported → collected → generated → applied
- `resolution`:当前分辨率,下拉 `512 / 1k / 2k / 4k`。
- `resolution_timeouts`:分辨率 → **等待大模型返回超时(秒)** 的映射;用户选分辨率即自动套用,不单独填。
- 模型本身的定义(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`
@@ -131,7 +131,7 @@ imported → collected → generated → applied
"enabled": true,
"url": "https://api.vectorengine.ai/v1/chat/completions",
"model": "gemini-3.1-flash-image-preview", // 模型 ID
"api_key": "***", // 密钥:加密存、UI 打码、不入日志、不进版本库
"api_key": "***", // 密钥:本地明文存、UI 打码、不入日志、不进版本库
"api_type": "auto", // chat | images_edits | auto —— 决定请求构造方式
"connect_timeout_seconds": 30, // 连接该服务超时(每模型,默认 30)
"timeout_seconds": 0, // 返回超时:0/留空 = 运行时按 resolution_timeouts 取值
@@ -147,11 +147,21 @@ imported → collected → generated → applied
- 约束:**至少各有一个 text 与一个 image 模型**;下拉默认最少一项、删到剩一项时禁用「删除」。
- `connect_timeout_seconds`(连接超时)属于**模型**;返回超时由分辨率映射决定(不在模型上单设)。
- `api_type` 反映不同 API 形状(`chat`/`images_edits`/`auto`),请求构造按它分支。
- `name` 唯一;`api_key` 加密存、打码显示。
- `name` 唯一;`api_key` 本地明文保存、打码显示。
### 5.2 SQLite `cmshopee.db`
```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 (
id INTEGER PRIMARY KEY,
@@ -161,44 +171,75 @@ CREATE TABLE accounts (
slug TEXT UNIQUE NOT NULL, -- user-data-dir 子目录名 [a-z0-9_]
user_data_dir TEXT NOT NULL,
debug_port INTEGER NOT NULL,
password_enc TEXT, -- 加密存,仅参考,不自动登录
password TEXT, -- 本地明文,仅参考,不自动登录;UI 打码,gitignore
note TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
last_login_at TEXT
);
-- 任务 + 各阶段结果(贯穿流水线)
CREATE TABLE tasks (
id INTEGER PRIMARY KEY,
batch_id TEXT NOT NULL,
source_file TEXT,
id INTEGER PRIMARY KEY,
batch_id TEXT NOT NULL REFERENCES batches(id),
-- 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)
account_name TEXT,
alias TEXT NOT NULL,
item_id TEXT NOT NULL,
account_name TEXT,
alias TEXT NOT NULL,
item_id TEXT NOT NULL,
-- 采集输出(程序写,改前快照)
old_title TEXT,
old_cover_path TEXT, -- 旧封面本地图片路径
old_title TEXT,
old_cover_path TEXT, -- 旧封面本地图片路径
-- AI 输出
new_title TEXT,
new_cover_path TEXT, -- 新封面本地图片路径
new_title TEXT,
new_cover_path TEXT, -- 新封面本地图片路径
-- 应用
committed INTEGER DEFAULT 0, -- 是否成功点「更新」提交
stage TEXT DEFAULT 'imported', -- imported/collected/generated/applied/failed/skipped
error TEXT,
updated_at TEXT
committed INTEGER NOT NULL DEFAULT 0, -- 是否成功点「更新」提交
stage TEXT NOT NULL DEFAULT 'imported', -- imported/collected/generated/applied
status TEXT NOT NULL DEFAULT 'pending', -- pending/running/success/failed/skipped/cancelled
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=别名未匹配,最后弹窗汇总。
- `account_name` 仅展示/参考;匹配以 `alias` 为准。
- `source_file_abs/source_sheet/source_row` 是回写 Excel 的权威定位;即使商品 ID 重复,也按原行回写。
- `row_key` 防止同一批次内重复导入同一行。
- `old_title/old_cover_path`:程序**采集阶段抓取**的快照(输出)。
- `new_title/new_cover_path`:**AI 生成**结果(输出),图片落本地;不设逐条确认阶段,生成即可进入 ③。
- `stage` 表示已完成到哪个业务阶段;`status` 表示当前处理结果。失败时 `stage` 保持在最后成功阶段,`status=failed`,错误写 `last_error`。
- `committed`:③ 用户确认批量更新弹窗后逐条点「更新」提交;该字段记录提交是否成功。
- 各字段**每阶段处理完立即写回 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 模板
| 列 | 含义 | 输入/输出 |
@@ -328,7 +369,7 @@ cmshopee/
- CDP 交互事实变化同步第七节。
- 存储边界:应用设置→config.json,账号/任务/结果→SQLite,图片→本地目录并记路径于 DB,登录态→user-data-dir;同一事实只存一处。
- 别名是账号↔任务唯一关联键。
- 密码与 AI Key 加密存、不外传、不写日志;不自动登录。
- 密码与 AI Key 本地明文保存、UI 打码、不外传、不写日志;不自动登录。
- AI 生成内容直接进入 ③ 更新候选;③ 批量确认后提交,新图本地留档 + 回写 Excel 以备追溯。
- 高风险模块先单独验证,再接入流水线。
- GUI 只通过 signal/slot 接收 worker 进度;禁止后台线程直接操作 Qt widget 或共享 SQLite connection。