feat: 完成T-504更新执行增强
- 新增 dry-run、多账号并行和最大并行账号数设置 - 增加 run_logs/run_log_events 运行日志表及读写接口 - ApplyWorker 支持 dry-run 预览、按账号并行、端口冲突阻断和日志展示 - 补充 DB/GUI 单元测试并同步任务、架构、API、路由和当前状态文档 验证: python -m compileall app main.py tests; python -m unittest discover -s tests
This commit is contained in:
+19
-10
@@ -32,7 +32,7 @@ ai_config(config=None) -> dict # default_text_model/default_image
|
||||
response_timeout(config=None) -> int # = resolution_timeouts[resolution](返回超时,随分辨率)
|
||||
```
|
||||
|
||||
`default_config()` / `load_config()` 包含 `shopee_update` 安全配置段:测试商品 ID、是否允许真实提交、是否允许封面更新、单次最大更新条数、成功后是否关闭本轮新开编辑页。`config.json` 不保存 AI Key;写入 `api_key` / `*_key` / `token` / `*_token` / `password` / `*_password` 等敏感字段时抛 `ConfigError`。AI Key 留给 `config/ai_models.json`。
|
||||
`default_config()` / `load_config()` 包含 `shopee_update` 安全配置段:测试商品 ID、是否允许真实提交、是否允许封面更新、单次最大更新条数、成功后是否关闭本轮新开编辑页、dry-run、多账号并行、最大并行账号数。`config.json` 不保存 AI Key;写入 `api_key` / `*_key` / `token` / `*_token` / `password` / `*_password` 等敏感字段时抛 `ConfigError`。AI Key 留给 `config/ai_models.json`。
|
||||
|
||||
敏感信息展示/日志辅助:
|
||||
|
||||
@@ -65,6 +65,7 @@ SQLite 读写,表见 [架构 5.2](04-architecture.md)。
|
||||
```python
|
||||
class DbError(RuntimeError): ...
|
||||
Batch / Account / Task # dataclass,字段同 SQLite schema
|
||||
RunLog / RunLogEvent # dataclass,运行日志与逐条事件
|
||||
connect(path=None) -> sqlite3.Connection # 设置 foreign_keys/WAL/busy_timeout/synchronous/row_factory
|
||||
init_db(path=None)
|
||||
create_batch(file_paths, note=None, path=None) -> str
|
||||
@@ -86,6 +87,12 @@ mark_skipped(task_id, reason) -> None # status=skipped,stage 不前
|
||||
set_collected(task_id, old_title, old_cover_path) -> None # stage=collected,status=success,collect_attempts+1
|
||||
set_generated(task_id, new_title, new_cover_path) -> None # stage=generated,status=success,generate_attempts+1
|
||||
set_applied(task_id, committed, error=None) -> None # 成功 stage=applied;失败 status=failed 且 stage 不前进
|
||||
# 运行日志
|
||||
create_run_log(run_type, dry_run=False, total=0, options=None) -> int
|
||||
finish_run_log(run_id, **fields) -> None # status/done/success_count/skipped_count/failed_count/summary_json
|
||||
add_run_log_event(run_id, message, task_id=None, alias=None, item_id=None, level="info") -> int
|
||||
list_run_logs(limit=50, run_type=None) -> list[RunLog]
|
||||
list_run_log_events(run_id=None, limit=200) -> list[RunLogEvent]
|
||||
```
|
||||
|
||||
`stage` 表示最后成功业务阶段(imported→collected→generated→applied);`status` 表示当前处理结果(pending/running/success/failed/skipped/cancelled)。任意步失败写 `last_error` 且 `status=failed`,`stage` 不前进。无 confirmed 阶段。
|
||||
@@ -309,11 +316,11 @@ main() -> int # 创建 QApplication + MainWindow
|
||||
class MainWindow(QMainWindow) # QTabWidget: ①②③④⑤;支持注入 db_path/config/config_path/ai_models_path 便于测试
|
||||
class CollectTab(QWidget) # ① 导入采集:导入 Excel + 汇总栏 + QTableView 任务列表 + 未匹配略过标记
|
||||
class GenerateTab(QWidget) # ② AI生成:提示词管理 + 筛选任务 + 开始/停止生成 + 新旧封面预览
|
||||
class ApplyTab(QWidget) # ③ 更新shopee:筛选已生成任务 + 安全开关拦截 + 确认后串行执行更新
|
||||
class ApplyTab(QWidget) # ③ 更新shopee:筛选已生成任务 + 安全开关拦截 + 确认后 dry-run/真实更新 + 运行日志
|
||||
class SettingsTab(QWidget) # ⑤ 设置:AI 模型管理 + 角色/生成参数/路径端口 + Shopee 更新安全
|
||||
class CollectWorker(BaseWorker) # ① 后台采集:账号就绪预检 -> editor.collect -> db.set_collected/mark_skipped/mark_failed
|
||||
class GenerateWorker(BaseWorker) # ② 后台生成:ai.generate_batch -> db.set_generated/mark_failed + 进度
|
||||
class ApplyWorker(BaseWorker) # ③ 后台更新:账号就绪预检 -> editor.apply_task(close_success_tab=...) -> db.set_applied/mark_skipped
|
||||
class ApplyWorker(BaseWorker) # ③ 后台更新:账号就绪预检 -> dry-run 预览或 editor.apply_task(close_success_tab=...) -> db.set_applied/mark_skipped
|
||||
class WriteBackWorker(BaseWorker) # ①/③ 后台回写:旧字段或更新结果写回原 Excel
|
||||
class AIModelTestWorker(BaseWorker) # ⑤ 后台测试 AI 模型连接:appconfig.test_ai_model
|
||||
class TaskTableModel(QAbstractTableModel) # 任务表格模型:账号/别名/商品ID/阶段;未匹配别名显示“略过”
|
||||
@@ -325,7 +332,7 @@ TAB_TITLES: list[str] # 固定 Tab 顺序
|
||||
TAB_STYLE: str # 顶层 Tab 栏防误点样式:最小宽度/padding/间距/当前态
|
||||
```
|
||||
|
||||
`MainWindow` 已实现五 Tab、① 导入采集任务列表、② AI生成布局/提示词/开始生成/停止/封面对照预览、③ 更新shopee筛选列表与确认后串行更新、④ 账号管理、⑤ AI 模型管理。缺 PySide6 时 `main()` 返回 1 并输出明确提示。
|
||||
`MainWindow` 已实现五 Tab、① 导入采集任务列表、② AI生成布局/提示词/开始生成/停止/封面对照预览、③ 更新shopee筛选列表与确认后 dry-run/真实更新、④ 账号管理、⑤ AI 模型管理。缺 PySide6 时 `main()` 返回 1 并输出明确提示。
|
||||
|
||||
主 Tab 栏必须在 `MainWindow` 初始化时应用 `TAB_STYLE`:5 个 Tab 不使用 Qt 默认紧凑宽度,需保证点击区域稳定、间距清晰、当前 Tab 高亮明显。该样式属于全局导航基础,不归后续业务 Tab 任务重复实现。
|
||||
|
||||
@@ -346,7 +353,7 @@ TAB_STYLE: str # 顶层 Tab 栏防误点样式:
|
||||
- 角色与生成参数读写 `config.json`:标题大模型(仅 text)、图片大模型(仅 image)、标题/图片并发、失败重试、分辨率、jpg 质量。
|
||||
- 分辨率下拉固定 `512/1k/2k/4k`;返回超时标签只读展示 `resolution_timeouts[resolution]`。
|
||||
- 路径与端口读写 `config.json`:Chrome 路径、账号数据根目录、图片目录、DB 路径、默认调试端口、调试端口范围、CDP 就绪超时。保存时校验端口范围和默认端口。
|
||||
- Shopee 更新安全读写 `config.json` 的 `shopee_update` 段:测试商品 ID、允许真实提交、允许更新封面、单次最大更新条数、成功后关闭本次新开编辑页。
|
||||
- Shopee 更新安全读写 `config.json` 的 `shopee_update` 段:测试商品 ID、允许真实提交、允许更新封面、单次最大更新条数、成功后关闭本次新开编辑页、dry-run、多账号并行、最大并行账号数。
|
||||
- 真实提交与封面更新默认关闭;用户在 ⑤ 保存开启后,③ 仍需要通过安全开关检查并弹窗确认,才会创建更新 worker。
|
||||
|
||||
① 导入采集当前要点(T-202/T-202b):
|
||||
@@ -383,11 +390,13 @@ TAB_STYLE: str # 顶层 Tab 栏防误点样式:
|
||||
- 状态筛选支持:已生成(默认,`stage=generated` 且 `status=success/pending`)、失败、已更新、略过、全部状态。
|
||||
- 任务列表使用 `QTableView + ApplyTaskTableModel`,列为:店铺、商品ID、新标题、新封面、阶段、结果。
|
||||
- 「开始更新」只读取当前筛选结果;无任务时只提示,不弹确认、不改库。
|
||||
- 点击「开始更新」先读取 `shopee_update`:未允许真实提交、超过单次最大条数、包含非测试商品 ID、或包含新封面但未允许封面更新时,弹警告并阻断;通过后才弹窗展示批次/店铺/状态/任务数、提交线上风险和当前安全设置。
|
||||
- 用户点否/取消时不执行、不改库;用户点是后才创建 `ApplyWorker` 串行执行更新。
|
||||
- 点击「开始更新」先读取 `shopee_update`:dry-run 关闭且未允许真实提交、超过单次最大条数、包含非测试商品 ID、或包含新封面但未允许封面更新时,弹警告并阻断;通过后才弹窗展示批次/店铺/状态/任务数、提交线上风险和当前安全设置。
|
||||
- 用户点否/取消时不执行、不改库;用户点是后才创建 `ApplyWorker`。dry-run 开启时只预览;dry-run 关闭时才可能真实提交。
|
||||
- `ApplyWorker` 只处理当前筛选结果里 `stage=generated` 且已有新标题或新封面、状态为 `success/pending/failed` 的任务;已更新和略过记录仅查看,不会再次提交。
|
||||
- 更新前先做账号就绪预检:无账号、当前筛选结果匹配账号 Chrome 未启动或未登录时,返回 `blocked=True`,GUI 弹窗汇总并跳转/引导去④账号管理;预检不通过时不调用 `editor.apply_task()`、不写失败状态。
|
||||
- 预检通过后逐条 `db.mark_running(..., "apply")` → `editor.apply_task(account, task, close_success_tab=设置值)` → `db.set_applied()`;成功推进 `stage=applied/status=success/committed=1`,失败保持原 stage、`status=failed/committed=0/last_error`,单条失败继续下一条。
|
||||
- dry-run:不做账号登录预检,不调用 `editor.apply_task()`,不写任务状态,不回写 Excel;只把每条“将更新/将略过”写入运行日志并弹汇总。
|
||||
- 真实更新前先做账号就绪预检:无账号、当前筛选结果匹配账号 Chrome 未启动、未登录,或本轮涉及账号调试端口冲突时,返回 `blocked=True`,GUI 弹窗汇总并跳转/引导去④账号管理;预检不通过时不调用 `editor.apply_task()`、不写失败状态。
|
||||
- 预检通过后默认串行;若 `parallel_accounts=true` 且 `max_parallel_accounts>1`,按账号分组并行执行,不同账号可同时跑,同一账号内仍串行。每条执行 `db.mark_running(..., "apply")` → `editor.apply_task(account, task, close_success_tab=设置值)` → `db.set_applied()`;成功推进 `stage=applied/status=success/committed=1`,失败保持原 stage、`status=failed/committed=0/last_error`,单条失败继续下一条。
|
||||
- dry-run 和真实更新都会创建 `run_logs`,并把逐条事件写入 `run_log_events`;③ 页面显示最近运行日志。
|
||||
- 若 `close_success_tab=true`,`editor.apply_task()` 只关闭本轮自动新开且成功提交的商品页;失败和复用的用户已有 tab 不关闭。
|
||||
- 别名未匹配账号的任务逐条 `db.mark_skipped()`,原因 `别名未匹配账号`;「停止」调用 worker 协作式 `cancel()`,已开始单条跑到安全边界后结束。
|
||||
- ③ 没有常驻提交开关;确认弹窗是提交线上前的边界。
|
||||
@@ -426,7 +435,7 @@ run_worker(worker: BaseWorker, thread_name=None, start=True) -> QThread
|
||||
- 采集、AI 生成、更新、Excel 回写都通过 worker 执行,用 signal 回传进度。
|
||||
- 每个 worker/线程按需创建自己的 SQLite connection,不跨线程共享连接。
|
||||
- ③ 的批量确认弹窗在 GUI 主线程完成;用户确认后才创建 `ApplyWorker`。
|
||||
- `ApplyWorker` 串行调用 `editor.apply_task(..., close_success_tab=...)`,逐条 `set_applied()`,失败继续;账号未就绪时整体阻断并引导④,不进入逐条提交。
|
||||
- `ApplyWorker` 支持 dry-run、默认串行和按账号并行;真实更新调用 `editor.apply_task(..., close_success_tab=...)`,逐条 `set_applied()`,失败继续;账号未就绪或端口冲突时整体阻断并引导④,不进入逐条提交。
|
||||
- `WriteBackWorker` 默认 `mode="old"` 回写旧字段;③ 使用 `mode="results"` 回写新标题/新封面/更新状态,支持单批次或多批次列表。
|
||||
- `execute()` 未捕获异常会发 `failed(-1, error)` 与 `finished({"ok": False, "error": ...})`;普通单行失败由业务 worker 自己发 `failed(task_id, error)` 后继续处理。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user