feat: add diagnostic logs for generation flows

This commit is contained in:
chengma
2026-06-29 17:49:45 +08:00
parent 588b352eac
commit cd1256bc5e
17 changed files with 1455 additions and 104 deletions
+12 -10
View File
@@ -52,11 +52,12 @@ list_ai_models(category=None) -> list[dict] # category=text/image 过滤;默
add_ai_model(model) -> None # name 唯一校验
update_ai_model(name, **fields) -> None
delete_ai_model(name) -> None # 至少各留一个 text+image;删到剩一禁用
model_request_url(model) -> str # url 为 /v1 或 /api/v1 base 时按 api_type 补 /chat/completions 或 /images/edits
test_ai_model(name) -> dict # 「测试连接」:用 key/url/model 发最小请求 -> {ok, status?, error?}
get_model(name) -> dict # 返回模型定义,含 api_key(调用方不得写日志)
```
`list_ai_models()` 用于 UI/API 展示,默认不返回明文 `api_key`;`get_model()` 用于实际调用 AI,返回明文 `api_key`,调用方不得写日志或导出。`test_ai_model()` 不记录密钥,返回给 GUI 前仍由 worker 过 `sanitize_for_log()`;缺少 `url/model/api_key` 时直接返回 `{ok: False, error: ...}`。
`list_ai_models()` 用于 UI/API 展示,默认不返回明文 `api_key`;`get_model()` 用于实际调用 AI,返回明文 `api_key`,调用方不得写日志或导出。`url` 可填完整 endpoint,也可填 OpenAI-compatible base URL(如 `https://.../v1` 或 `https://.../api/v1`),请求前由 `model_request_url()` 按 `api_type` 补齐。`test_ai_model()` 不记录密钥,返回给 GUI 前仍由 worker 过 `sanitize_for_log()`;缺少 `url/model/api_key` 时直接返回 `{ok: False, error: ...}`。
## db 模块(`app/db.py`,已建)
@@ -255,10 +256,10 @@ apply_task(account, task, close_success_tab=False) -> dict
```python
class AIError(RuntimeError): ...
gen_title(title_prompt, old_title, retry=None, config=None, models_path="config/ai_models.json") -> str
gen_title(title_prompt, old_title, retry=None, config=None, models_path="config/ai_models.json", on_step=None) -> str
# 文本生成:读取 default_text_model,chat JSON 请求;提示词 + 旧标题 → 新标题
gen_cover(cover_prompt, old_cover_path, out_path, resolution=None, jpg_quality=None, retry=None, config=None, models_path="config/ai_models.json") -> str
gen_cover(cover_prompt, old_cover_path, out_path, resolution=None, jpg_quality=None, retry=None, config=None, models_path="config/ai_models.json", on_step=None) -> str
# 图像生成(image-to-image):读取 default_image_model;chat 多模态 JSON 或 images_edits multipart;
# 支持返回 url / data URL / b64_json,按 resolution resize 并以 jpg_quality 保存 JPEG,返回路径
@@ -266,6 +267,7 @@ generate_batch(tasks, prompts, ai_cfg=None, on_progress=None, should_stop=None)
# 编排:先以 title_concurrency 线程池并发跑 gen_title,再以 image_concurrency 并发跑 gen_cover
# 每条完成即 db.set_generated(实时落库);should_stop() 为真则取消未开始项
# on_progress({"total","title_done","cover_done","failed","cancelled","ok"}) 回调刷新进度
# ai_cfg 可传 on_event/on_error 回调,逐条报告 title/cover 阶段 step/result/detail,供 GUI run_logs 与本地诊断日志使用
# 返回同结构 summary;失败任务 mark_failed(..., "generate", error),不阻塞其余
```
@@ -315,7 +317,7 @@ render_prompt(template_text, task) -> str
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 GenerateTab(QWidget) # ② AI生成:提示词管理 + 筛选任务 + 开始/停止生成 + 新旧封面预览 + AI生成运行日志
class ApplyTab(QWidget) # ③ 更新shopee:筛选已生成任务 + 安全开关拦截 + 确认后 dry-run/真实更新 + 运行日志
class SettingsTab(QWidget) # ⑤ 设置:AI 模型管理 + 角色/生成参数/路径端口 + Shopee 更新安全
class CollectWorker(BaseWorker) # ① 后台采集:账号就绪预检 -> editor.collect -> db.set_collected/mark_skipped/mark_failed
@@ -370,27 +372,27 @@ TAB_STYLE: str # 顶层 Tab 栏防误点样式:
- 「回写旧数据到 Excel」通过 `WriteBackWorker` 后台调用 `excel.write_back()`,把已采集旧标题/旧封面路径按原 Excel 行定位写回;该按钮主要作为自动回写失败后的手动重试入口。原文件被占用时弹窗提示关闭后重试,SQLite 采集结果不回滚。
- 采集前由 `CollectWorker` 做账号就绪预检:无账号、当前批次匹配账号未启动 CDP 端口或未登录时,返回 `blocked=True`,GUI 弹窗汇总并跳转/引导去④账号管理;不无提示批量启动所有账号 Chrome。匹配账号未登录属于预检阻断,不是逐条 skipped。
② AI生成当前要点(T-302/T-302p/T-303):
② AI生成当前要点(T-302/T-302p/T-303/T-303b + 诊断日志补丁):
- 左右 `QSplitter`:左侧约 1/4 为标题提示词、封面提示词两个多行输入;右侧为筛选栏 + 任务列表。
- 标题提示词启动时从 `title_prompt.txt` 回显;点击「保存标题提示词」写回该文件。
- 封面提示词模板下拉读取 `prompts/cover/*.txt`;支持新建、保存、另存为、重命名、删除。删除由 GUI 二次确认,删空后下拉显示内存态“默认”,不会自动建文件。
- 「插入标题」在封面提示词光标处插入 `{新标题}`;「预览」使用当前选中任务(无选择则用第一条)调用 `prompts.render_prompt()` 并弹窗展示。
- 筛选栏包含:批次、店铺、状态、刷新。批次来自 `db.list_batches()`;店铺来自当前任务别名并优先显示匹配账号名;状态支持全部/待生成/已生成/失败/略过/已更新。
- 筛选栏包含:批次、店铺、商品ID、状态、刷新。批次来自 `db.list_batches()`;店铺来自当前任务别名并优先显示匹配账号名;商品ID输入框按包含匹配 `item_id`,清空表示全部;状态支持全部/待生成/已生成/失败/略过/已更新。
- 任务列表使用 `QTableView + GenerateTaskTableModel`,列为:店铺、商品ID、旧标题、新标题、状态。`stage=collected` 显示“待生成”,`stage=generated` 显示“已生成”,`status=failed/skipped/running` 优先显示对应状态。
- 双击任务行弹窗展示旧封面与新封面路径对应图片;图片不存在时显示空态/路径提示,只做查看,不做审核。
- 底部「开始生成」只处理当前筛选结果里 `stage=collected` 的任务;通过 `GenerateWorker` 调 `ai.generate_batch()`,先并发标题、再并发封面。
- 底部「开始生成」只处理当前筛选结果里 `stage=collected` 的任务;批次/店铺/商品ID/状态筛选共同决定当前筛选结果;通过 `GenerateWorker` 调 `ai.generate_batch()`,先并发标题、再并发封面。
- 「停止」调用 worker 的协作式 `cancel()`;未开始的 Future 取消,不记失败;已完成的 `db.set_generated()` 结果保留,可再次开始生成剩余任务。
- 进度标签显示:`标题x/n · 封面x/n · 失败z`;每条封面生成成功后立即 `db.set_generated()`,失败 `db.mark_failed(..., "generate", error)`,GUI 刷新任务表。
③ 更新shopee当前要点(T-401/T-402/T-403):
③ 更新shopee当前要点(T-303b/T-401/T-402/T-403):
- `ApplyTab` 顶部筛选栏包含:批次、店铺、状态、刷新。批次来自 `db.list_batches()`;店铺来自当前更新候选任务别名并优先显示匹配账号名。
- `ApplyTab` 顶部筛选栏包含:批次、店铺、商品ID、状态、刷新。批次来自 `db.list_batches()`;店铺来自当前更新候选任务别名并优先显示匹配账号名;商品ID输入框按包含匹配 `item_id`,清空表示全部。
- ③ 只列出已具备新标题/新封面、可进入更新阶段的任务:`stage=generated/applied`,或已有新字段且 `status=failed/skipped` 的任务。
- 状态筛选支持:已生成(默认,`stage=generated` 且 `status=success/pending`)、失败、已更新、略过、全部状态。
- 任务列表使用 `QTableView + ApplyTaskTableModel`,列为:店铺、商品ID、新标题、新封面、阶段、结果。
- 「开始更新」只读取当前筛选结果;无任务时只提示,不弹确认、不改库。
- 点击「开始更新」先读取 `shopee_update`:dry-run 关闭且未允许真实提交、超过单次最大条数、包含非测试商品 ID、或包含新封面但未允许封面更新时,弹警告并阻断;通过后才弹窗展示批次/店铺/状态/任务数、提交线上风险和当前安全设置。
- 点击「开始更新」先读取 `shopee_update`:dry-run 关闭且未允许真实提交、超过单次最大条数、包含非测试商品 ID、或包含新封面但未允许封面更新时,弹警告并阻断;通过后才弹窗展示批次/店铺/商品ID/状态/任务数、提交线上风险和当前安全设置。
- 用户点否/取消时不执行、不改库;用户点是后才创建 `ApplyWorker`。dry-run 开启时只预览;dry-run 关闭时才可能真实提交。
- `ApplyWorker` 只处理当前筛选结果里 `stage=generated` 且已有新标题或新封面、状态为 `success/pending/failed` 的任务;已更新和略过记录仅查看,不会再次提交。
- dry-run:不做账号登录预检,不调用 `editor.apply_task()`,不写任务状态,不回写 Excel;只把每条“将更新/将略过”写入运行日志并弹汇总。