feat: add cmhub AI backend
This commit is contained in:
@@ -17,9 +17,9 @@
|
||||
| 应用配置 | `config.json`(JSON,stdlib) | 已定 | 少量应用级设置:Chrome 路径、目录根、端口、DB 路径等 |
|
||||
| 业务数据 | SQLite(stdlib `sqlite3`,`cmshopee.db`) | 已定 | 账号、任务、结果:成行增长、要查询/统计/导出 |
|
||||
| Excel 读写 | `openpyxl` | 已定 | 导入任务、回写结果;stdlib 读不了 .xlsx |
|
||||
| AI 模型注册 | `config/ai_models.json` 多模型清单(HTTP 调用) | 已定(结构) | 每模型 name/category(text/image)/url/model/key/api_type/连接超时;⑤ 设置可增删改+测试连接;Key 本地明文保存,保存/变更时提示 |
|
||||
| AI 文本生成 | `app/ai.py` 读取 `default_text_model`(category=text),通用 chat JSON HTTP | 已接入 | 提示词+旧标题→新标题;失败重试,错误脱敏 |
|
||||
| AI 图像生成 | `app/ai.py` 读取 `default_image_model`(category=image),支持 chat 多模态 JSON / images_edits multipart | 已接入 | 提示词+旧封面→新封面;分辨率 512/1k/2k/4k,jpg_quality 存盘,返回超时随分辨率 |
|
||||
| AI 模型注册 | `config/ai_models.json` direct 模型清单 + `config/cmhub.json` 网关 Key | 已接入(后端) | direct 模式保留每模型 name/category/url/model/key/api_type;cmhub 模式用 `config.json` 的 Base URL/别名 + `config/cmhub.json` 单 Key;⑤ cmhub 面板待 T-527 |
|
||||
| AI 文本生成 | `app/ai.py` 支持 direct chat JSON 与 cmhub `POST /api/v1/generate/title` | 已接入 | 提示词+旧标题→新标题;返回值不变;cmhub 计费 metadata 通过事件回调上报 |
|
||||
| AI 图像生成 | `app/ai.py` 支持 direct chat/images_edits 与 cmhub `POST /api/v1/generate/image` | 已接入 | 提示词+旧封面→新封面;cmhub 拿 `image_url` 后安全下载并转本地 JPEG;生图读超时不自动重发 |
|
||||
| 并发 | 标准库 `concurrent.futures.ThreadPoolExecutor` | 已定 | 标题/图片分别按并发数并行;③ 可按账号并行更新;可停止、可重试 |
|
||||
| 运行日志 | SQLite `run_logs` / `run_log_events` | 已定 | ③ dry-run 与真实更新都留痕;结构化内容走脱敏 |
|
||||
| 图片处理 | `requests`(下载)+ `Pillow`(按分辨率/jpg质量存盘) | 部分待定 | 下载旧封面;新封面按 resolution 生成、jpg_quality 存盘 |
|
||||
@@ -34,9 +34,9 @@
|
||||
- **Excel 用 openpyxl**:运营用真实 .xlsx;stdlib 无法读写 xlsx,引入一个轻依赖比改用 CSV 更贴合用户习惯。
|
||||
- **多账号隔离用独立 user-data-dir,不用 Chrome profile**:profile 共享同一 user-data-dir/进程/调试端口,无法每账号独立 CDP 与并行;独立 user-data-dir 才契合自动化。详见 [架构 3.0](04-architecture.md)。
|
||||
- **快捷方式生成用 PowerShell(无额外依赖)**:用 `WScript.Shell.CreateShortcut` 生成 `.lnk`,不引入 `pywin32` 等依赖。
|
||||
- **AI 服务商不写死在代码里**:T-301 已采用 `config/ai_models.json` 的通用 HTTP 接入,当前支持 OpenAI-compatible chat JSON 与 images_edits multipart;具体服务商/模型/Key 由⑤设置维护。
|
||||
- **AI 服务商不写死在代码里**:T-301 已采用 `config/ai_models.json` 的 direct 通用 HTTP 接入,支持 OpenAI-compatible chat JSON 与 images_edits multipart;T-526 已新增 `backend=cmhub` 网关后端,cmhub 模式使用 Base URL + 生文/生图别名 + `config/cmhub.json` 单 Key,直连模型清单保留用于回退。
|
||||
- **AI 模型 category 是硬约束**:`config/ai_models.json` 每个模型必须有 `category=text` 或 `category=image`;启动时报 “AI 模型 category 必须是 text 或 image” 时,按 [常见问题排查](troubleshooting.md) 修复本地配置,不删除或提交含 Key 的配置文件。
|
||||
- **敏感信息不加密但强提示与脱敏**:密码与 AI Key 只在本机 SQLite / `config/ai_models.json` 明文保存;保存/变更时弹窗提示,UI 打码,日志/导出必须脱敏,相关本地文件必须 gitignore。
|
||||
- **敏感信息不加密但强提示与脱敏**:密码与 AI Key 只在本机 SQLite / `config/ai_models.json` / `config/cmhub.json` 明文保存;保存/变更时弹窗提示,UI 打码,日志/导出必须脱敏,相关本地文件必须 gitignore。
|
||||
- **AI 产出无逐条审核**:生成的新标题/新封面经 ③ 批量确认后提交线上;无常驻提交开关,本地留档 + 回写 Excel 供追溯。
|
||||
- **T-504 更新执行增强**:③ 支持 dry-run 预览、运行日志和按账号并行;默认 dry-run 关闭、并行关闭,不引入新依赖。
|
||||
- **不引入数据库(指外部 DB)**:用 stdlib SQLite 足够;不引入 Postgres/MySQL 等。
|
||||
|
||||
+34
-12
@@ -27,7 +27,7 @@ GUI(PySide6 QTabWidget,5 Tab)
|
||||
└── ai 文本生成(提示词+旧标题→新标题)/ 图像生成(提示词+旧封面→新封面)
|
||||
|
|
||||
v
|
||||
Google Chrome(每账号独立 --user-data-dir + --remote-debugging-port) + AI 服务(外部)
|
||||
Google Chrome(每账号独立 --user-data-dir + --remote-debugging-port) + AI 服务(direct 外部模型或 cmhub 网关)
|
||||
|
|
||||
v
|
||||
Shopee 卖家中心页面 / 本地图片目录
|
||||
@@ -38,7 +38,7 @@ Shopee 卖家中心页面 / 本地图片目录
|
||||
- GUI 入口:根目录 `main.py` 调用 `app/gui/` 包(PySide6 + `QMainWindow` + `QTabWidget`,5 Tab);包入口 `app/gui/__init__.py` 提供 `main()` 并兼容 `from app import gui` / `from app.gui import MainWindow`;也支持 `python -m app`。
|
||||
- 核心模块统一放在正式代码包 `app/`:`appconfig.py`、`db.py`、`excel.py`、`config.py`、`accounts.py`、`chrome.py`、`editor.py`、`workers.py`、`ai.py`、`prompts.py`;CDP 底座迁入 `app/cdp.py`(当前根目录 `cdp.py` 为已验证来源)。
|
||||
- 已验证脚本(重构进模块):`prototypes/demo.py`、`prototypes/set_title.py`、`prototypes/set_cover.py`、`prototypes/get_title.py`、`prototypes/cookies.py`、`prototypes/inspect_images.py`、`prototypes/grab.py`。
|
||||
- 外部依赖:本机 Google Chrome;Shopee;AI 服务(文本+图像,服务商/模型由 `config/ai_models.json` 配置);`openpyxl`。
|
||||
- 外部依赖:本机 Google Chrome;Shopee;AI 服务(文本+图像;direct 模式由 `config/ai_models.json` 配置,cmhub 模式由 `config.json` 的 `ai.cmhub` + `config/cmhub.json` 配置);`openpyxl`。
|
||||
|
||||
## 二、流水线(核心)
|
||||
|
||||
@@ -71,12 +71,13 @@ imported → collected → generated → applied
|
||||
- `chrome`:拼接启动命令、启动、探测端口、(可选)生成快捷方式。
|
||||
- `cdp`:连接调试端口、找/开 tab、执行 JS、拖拽、注入文件。
|
||||
- `editor`:登录检测、**采集**(读旧标题、下载旧封面)、改标题、换封面、点更新。
|
||||
- `ai`:`gen_title(prompt, old_title)`、`gen_cover(prompt, old_cover_path)`(外部 AI;模型清单配置;通用 HTTP)。
|
||||
- `ai`:`gen_title(prompt, old_title)`、`gen_cover(prompt, old_cover_path)`(外部 AI;支持 `direct` 模型清单和 `cmhub` 网关 backend;返回值保持标题字符串/本地 JPEG 路径)。
|
||||
|
||||
**存储(同一事实只存一处)**
|
||||
|
||||
- 应用配置(模型选择、生成参数、目录、Chrome 路径)→ `config.json`。
|
||||
- AI 模型清单(url/模型/密钥/类型/连接超时)→ `config/ai_models.json`(API Key 本地明文保存,必须 gitignore,UI 打码显示)。
|
||||
- AI 模型清单(direct 模式 url/模型/密钥/类型/连接超时)→ `config/ai_models.json`(API Key 本地明文保存,必须 gitignore,UI 打码显示)。
|
||||
- cmhub 网关 Key → `config/cmhub.json`,schema `{ "api_key": "..." }`;`config.json` 只保存 Base URL、别名和超时,不保存 Key。
|
||||
- 业务数据(账号、任务、各阶段结果)→ SQLite `cmshopee.db`。
|
||||
- 图片(采集的旧封面、AI 生成的新封面)→ 本地图片目录(路径记在 DB)。
|
||||
- 提示词 → 标题提示词存单文件 `title_prompt.txt`;封面提示词存多模板 `prompts/cover/<名称>.txt`。
|
||||
@@ -103,6 +104,14 @@ imported → collected → generated → applied
|
||||
"default_text_model": "GPT-5.5 文本",
|
||||
"default_image_model": "Nano Banana 2",
|
||||
"generate_cover": false,
|
||||
"backend": "direct",
|
||||
"cmhub": {
|
||||
"base_url": "",
|
||||
"title_alias": "",
|
||||
"image_alias": "",
|
||||
"connect_timeout": 10,
|
||||
"check_balance_before_batch": false
|
||||
},
|
||||
"title_concurrency": 4,
|
||||
"image_concurrency": 4,
|
||||
"retry": 2,
|
||||
@@ -125,12 +134,14 @@ imported → collected → generated → applied
|
||||
|
||||
`ai` 段只放**选择 + 全局生成参数**:
|
||||
|
||||
- `default_text_model` / `default_image_model`:引用 `ai_models.json` 里的模型名(标题用文本模型、封面用图像模型)。
|
||||
- `backend`:`direct` / `cmhub`。全新配置和旧配置缺字段时均为 `direct`,避免未配置 cmhub 时破坏既有直连生成;只有用户在⑤显式切换并配置完整后才走 cmhub。
|
||||
- `cmhub`:cmhub 网关配置,`base_url` 为网关根地址,`title_alias` / `image_alias` 为 `GET /api/v1/models` 发现的能力别名,`connect_timeout` 为连接超时;API Key 不在此处保存。
|
||||
- `default_text_model` / `default_image_model`:direct 模式下引用 `ai_models.json` 里的模型名(标题用文本模型、封面用图像模型);cmhub 模式不读取这些模型定义。
|
||||
- `generate_cover`:②「开始生成」时是否调用图片模型生成新封面;默认 `false`,避免用户无意产生图片生成成本。该字段只控制 AI 生成阶段,不等同于 ③ 的 `allow_cover_update`。
|
||||
- `resolution`:当前分辨率,下拉 `512 / 1k / 2k / 4k`。
|
||||
- `resolution_timeouts`:分辨率 → **等待大模型返回超时(秒)** 的映射;用户选分辨率即自动套用,不单独填。
|
||||
- 模型本身的定义(url/key/类型/连接超时…)在 `config/ai_models.json`,见 5.1b。
|
||||
- 密钥不在 `config.json`:每个模型的 `api_key` 存于 `config/ai_models.json`,本地明文保存、保存/变更时弹窗提示、UI 打码、gitignore、不入日志/导出。
|
||||
- direct 模式模型本身的定义(url/key/类型/连接超时…)在 `config/ai_models.json`,见 5.1b。
|
||||
- 密钥不在 `config.json`:direct 模式每个模型的 `api_key` 存于 `config/ai_models.json`;cmhub 模式 API Key 存于 `config/cmhub.json`。两者均本地明文保存、保存/变更时弹窗提示、UI 打码、gitignore、不入日志/导出。
|
||||
|
||||
`shopee_update` 段放**真实更新前的安全开关**:
|
||||
|
||||
@@ -147,7 +158,7 @@ imported → collected → generated → applied
|
||||
|
||||
### 5.1b AI 模型清单 `config/ai_models.json`
|
||||
|
||||
模型定义清单("有哪些模型"),与 `config.json` 的 `ai` 段("选了哪个 + 全局参数")职责分开。
|
||||
模型定义清单("有哪些模型"),与 `config.json` 的 `ai` 段("选了哪个 + 全局参数")职责分开。该文件只用于 `backend=direct`;`backend=cmhub` 时生文/生图使用 cmhub 别名,不读取此文件。
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -177,6 +188,16 @@ imported → collected → generated → applied
|
||||
- `name` 唯一;`api_key` 本地明文保存、保存/变更时弹窗提示、打码显示。
|
||||
- 日志/状态/导出不得含密码或 API Key;结构化对象统一先过 `appconfig.sanitize_for_log()`,自由文本只允许在掌握明文值时用 `appconfig.redact_secrets()` 替换。
|
||||
|
||||
### 5.1c cmhub Key `config/cmhub.json`
|
||||
|
||||
```json
|
||||
{ "api_key": "sk_cmhub_xxx" }
|
||||
```
|
||||
|
||||
- 文件必须 gitignore,不提交;UI 展示打码。
|
||||
- `appconfig.load_cmhub_config()` 缺文件时返回空 Key,不自动启用 cmhub。
|
||||
- `backend=cmhub` 但 Base URL、API Key 或别名缺失时,`app/ai.py` 抛 `CMHubError(code="cmhub_not_configured")`,提示去⑤设置配置,不静默回退 direct。
|
||||
|
||||
### 5.2 SQLite `cmshopee.db`
|
||||
|
||||
```sql
|
||||
@@ -374,8 +395,8 @@ images/<batch_id>/<slug>/<task_id>_<item_id>_new.<ext> # AI 生成的新封
|
||||
|
||||
单个「开始生成」按钮,标题必生成,封面按本轮成本开关可选生成:
|
||||
|
||||
1. **并发生成标题**:线程池大小 = `title_concurrency`,用 `default_text_model` 调 `gen_title(标题提示词, old_title)` → new_title。
|
||||
2. **若②勾选「生成封面图片(成本较高)」**:接着并发生成图片,线程池大小 = `image_concurrency`,用 `default_image_model` 调 `gen_cover(封面提示词, old_cover_path, resolution, jpg_quality)` → 新图存 `images/<batch_id>/<slug>/<task_id>_<item_id>_new.jpg`。
|
||||
1. **并发生成标题**:线程池大小 = `title_concurrency`,调 `gen_title(标题提示词, old_title)` → new_title。`backend=direct` 时使用 `default_text_model`;`backend=cmhub` 时调用 `POST /api/v1/generate/title` 并使用 `title_alias`。
|
||||
2. **若②勾选「生成封面图片(成本较高)」**:接着并发生成图片,线程池大小 = `image_concurrency`,调 `gen_cover(封面提示词, old_cover_path, resolution, jpg_quality)` → 新图存 `images/<batch_id>/<slug>/<task_id>_<item_id>_new.jpg`。`backend=direct` 时使用 `default_image_model`;`backend=cmhub` 时调用 `POST /api/v1/generate/image`,拿 `image_url` 后立即安全下载并转本地 JPEG。
|
||||
- 连接超时取该模型 `connect_timeout_seconds`;**返回超时取 `resolution_timeouts[resolution]`**(512→180/1k→240/2k→360/4k→600)。
|
||||
3. **若未勾选生成封面**:标题成功后立即写 `new_title`,`new_cover_path=NULL`,不渲染封面提示词、不调用 `gen_cover()`、不创建本地新封面文件。
|
||||
|
||||
@@ -462,7 +483,8 @@ cmshopee/
|
||||
├── main.py # GUI 启动入口:from app.gui import main
|
||||
├── shopee待处理任务模板.xlsx # 标准空 Excel 模板,可提交;业务填写后的副本不提交
|
||||
├── config.json # 应用配置(模型选择/生成参数/路径,gitignore)
|
||||
├── config/ai_models.json # AI 模型清单(含密钥,必须 gitignore)
|
||||
├── config/ai_models.json # direct AI 模型清单(含密钥,必须 gitignore)
|
||||
├── config/cmhub.json # cmhub API Key(含密钥,必须 gitignore)
|
||||
├── cmshopee.db # SQLite(账号/任务/结果,gitignore)
|
||||
├── chrome_user_data_dir/ # 各账号 Chrome 配置(含登录态,gitignore)
|
||||
├── images/ # 旧封面/新封面本地图片(gitignore)
|
||||
@@ -472,7 +494,7 @@ cmshopee/
|
||||
# 逻辑待并入 app/editor.py 后清理;见 prototypes/README.md
|
||||
```
|
||||
|
||||
> `config.json`、`config/ai_models.json`、`cmshopee.db`、`chrome_user_data_dir/`、`images/` 含密钥/凭证/业务数据,必须 gitignore。`shopee待处理任务模板.xlsx` 是标准空模板,可以提交;运营填写后的 Excel 副本属于业务数据,不提交。
|
||||
> `config.json`、`config/ai_models.json`、`config/cmhub.json`、`cmshopee.db`、`chrome_user_data_dir/`、`images/` 含配置/密钥/凭证/业务数据,必须 gitignore。`shopee待处理任务模板.xlsx` 是标准空模板,可以提交;运营填写后的 Excel 副本属于业务数据,不提交。
|
||||
|
||||
## 十、架构纪律
|
||||
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@
|
||||
|
||||
| ID | 任务 | 依赖 | 验收要点 | 状态 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| T-526 | `app/ai.py` + `appconfig` 接入 cmhub backend | T-301, T-303, T-520 | 依据 `docs/cmhub-integration-design.md` v3.2。`config.json` 的 `ai` 段加 `backend`(`cmhub`/`direct`)+ `cmhub` 子段(`base_url`/`title_alias`/`image_alias`/`connect_timeout` 等);为保护既有用户,全新配置默认 `backend=direct`、加载既有配置缺 `backend` 时也补 `direct`,`cmhub` 一律由用户在⑤显式 opt-in;`backend=cmhub` 但 `base_url`/Key 缺失时须抛清晰「请去⑤配置 cmhub」错误(`CMHubError`/`AIError`),不崩溃、不静默直连。cmhub API Key 固定存 `config/cmhub.json`(schema `{ "api_key": "..." }`),新增读写/打码 helper 并把该文件加入 `.gitignore`;日志脱敏。`gen_title`/`gen_cover` **返回值不变**,内层按 backend 分流并保留 `direct`;计费元数据不塞进返回值,允许给二者**新增一个可选事件回调参数**(如 `on_meta`/`on_event`)承载,属向后兼容加参,`generate_batch` 显式传回调不受影响。cmhub 分支:生文 `POST /api/v1/generate/title` 体 `{prompt,model:别名,resolution?}`、取 `titles[0]`、空则 `AIError`;生图 `POST /api/v1/generate/image` 体 `{prompt,model:别名,image_base64:<旧封面>,resolution,aspect_ratio:"1:1"}`、拿 `image_url` 后**立即下载**再走 `_save_jpeg`;`resolution` 归一大写 `512/1K/2K/4K`。新增 `CMHubError(AIError)`,带 `code/status/retryable/retry_after`,错误按 `code` 优先分支(`insufficient_points`/`unauthorized`/`account_disabled`/`bad_request`/`model_not_allowed`/`no_pricing_rule`/`content_blocked`/`upstream_error`/`rate_limited`,未知 code 当不可重试);cmhub HTTP helper 需区分 connect/read timeout(优先用 `requests timeout=(connect, read)`),只对 502/429/连接超时重试,生图读超时绝不自动重发,读超时按分辨率封顶 600s。`points_cost`/`points_balance`/`call_id` 不改返回值,通过 `on_step`/事件回调上报;T-526 只保证 metadata 事件完整传出,T-528 再由 GUI worker 脱敏写 run_logs 和余额展示。`image_url` 下载必须限制 http/https、拒绝内网/回环地址、校验域名解析后的 IP 仍不是内网/回环/本机地址,并设置超时和大小上限。新增 `fetch_cmhub_models(base_url, api_key)` helper 调 `GET /api/v1/models` 返回别名清单(`alias/operation_type/requires_image/pricing_status/prices`)供 T-527 渲染下拉,错误脱敏。不碰 editor/cdp/chrome/accounts/excel/db,也不改 ①③④流程。`tests/test_ai.py` 加 cmhub mock(titles 列表、image_url 下载、安全下载、错误码与重试、读超时不重发、metadata 事件)、`tests/test_appconfig.py` 加 schema 和 key 文件 helper,direct 用例保持绿 | TODO |
|
||||
| T-526 | `app/ai.py` + `appconfig` 接入 cmhub backend | T-301, T-303, T-520 | 依据 `docs/cmhub-integration-design.md` v3.2。`config.json` 的 `ai` 段加 `backend`(`cmhub`/`direct`)+ `cmhub` 子段(`base_url`/`title_alias`/`image_alias`/`connect_timeout` 等);为保护既有用户,全新配置默认 `backend=direct`、加载既有配置缺 `backend` 时也补 `direct`,`cmhub` 一律由用户在⑤显式 opt-in;`backend=cmhub` 但 `base_url`/Key 缺失时须抛清晰「请去⑤配置 cmhub」错误(`CMHubError`/`AIError`),不崩溃、不静默直连。cmhub API Key 固定存 `config/cmhub.json`(schema `{ "api_key": "..." }`),新增读写/打码 helper 并把该文件加入 `.gitignore`;日志脱敏。`gen_title`/`gen_cover` **返回值不变**,内层按 backend 分流并保留 `direct`;计费元数据不塞进返回值,允许给二者**新增一个可选事件回调参数**(如 `on_meta`/`on_event`)承载,属向后兼容加参,`generate_batch` 显式传回调不受影响。cmhub 分支:生文 `POST /api/v1/generate/title` 体 `{prompt,model:别名,resolution?}`、取 `titles[0]`、空则 `AIError`;生图 `POST /api/v1/generate/image` 体 `{prompt,model:别名,image_base64:<旧封面>,resolution,aspect_ratio:"1:1"}`、拿 `image_url` 后**立即下载**再走 `_save_jpeg`;`resolution` 归一大写 `512/1K/2K/4K`。新增 `CMHubError(AIError)`,带 `code/status/retryable/retry_after`,错误按 `code` 优先分支(`insufficient_points`/`unauthorized`/`account_disabled`/`bad_request`/`model_not_allowed`/`no_pricing_rule`/`content_blocked`/`upstream_error`/`rate_limited`,未知 code 当不可重试);cmhub HTTP helper 需区分 connect/read timeout(优先用 `requests timeout=(connect, read)`),只对 502/429/连接超时重试,生图读超时绝不自动重发,读超时按分辨率封顶 600s。`points_cost`/`points_balance`/`call_id` 不改返回值,通过 `on_step`/事件回调上报;T-526 只保证 metadata 事件完整传出,T-528 再由 GUI worker 脱敏写 run_logs 和余额展示。`image_url` 下载必须限制 http/https、拒绝内网/回环地址、校验域名解析后的 IP 仍不是内网/回环/本机地址,并设置超时和大小上限。新增 `fetch_cmhub_models(base_url, api_key)` helper 调 `GET /api/v1/models` 返回别名清单(`alias/operation_type/requires_image/pricing_status/prices`)供 T-527 渲染下拉,错误脱敏。不碰 editor/cdp/chrome/accounts/excel/db,也不改 ①③④流程。`tests/test_ai.py` 加 cmhub mock(titles 列表、image_url 下载、安全下载、错误码与重试、读超时不重发、metadata 事件)、`tests/test_appconfig.py` 加 schema 和 key 文件 helper,direct 用例保持绿 | DONE |
|
||||
| T-527 | ⑤设置 cmhub 网关面板 | T-526, T-517 | 依据 `docs/cmhub-integration-design.md` v3.2。⑤ AI 设置按 `backend` 切换:cmhub 模式显示「网关 Base URL + API Key(打码,提示从网页端复制、仅显示一次)+ 生文别名 + 生图别名 + 测试连接/查余额」;**别名从 `GET /api/v1/models`(T-526 的 `fetch_cmhub_models`)动态拉取渲染下拉**,按 `operation_type` 分生文/生图,过滤 `pricing_status="unpriced"` 的别名,可展示单价与 `requires_image` 提示,选中值持久化到 `ai.cmhub.title_alias/image_alias`(网关临时不可达时回退已存值);不写死别名。direct 模式保留现有 AI 模型 master-detail。保存写 `config.json` 的 `ai` 段与 `config/cmhub.json`;切换 backend 时不删除 legacy `config/ai_models.json`。测试连接/查余额经后台 worker 调 cmhub(复用 `AIModelTestWorker` 思路或新增 worker),错误必须脱敏并给用户可读提示。同步 GUI 设置测试;不改 Shopee/CDP 流程 | TODO |
|
||||
| T-528 | ② 计费错误提示 + 余额展示 | T-526, T-527, T-303 | 依据 `docs/cmhub-integration-design.md` v3.2。② AI生成页把 cmhub 计费失败态显式化:通过 `CMHubError.code` 识别 `insufficient_points`,弹明确提示「点数不足,请先充值」并引导去网页端充值,本轮未开始任务可提前中止,不靠中文字符串匹配、不淹没在失败计数里;用 T-526 成功响应事件里的 `points_balance` 刷新②页剩余点数显示,`/balance` 仅作手动刷新/可选批量前预检;`points_cost`/`call_id` 记入脱敏 run_logs。只改② UI、`GenerateWorker` 事件处理/文案及 GUI 单测;不改 AI HTTP 协议、DB schema、Excel、Shopee/CDP 流程 | TODO |
|
||||
|
||||
|
||||
+26
-9
@@ -6,7 +6,7 @@
|
||||
|
||||
- 形态:本地函数 + 子进程(Chrome)+ CDP(`127.0.0.1:<port>`)+ SQLite + openpyxl + AI 服务调用。
|
||||
- 编码:UTF-8;传 Chrome / `setFileInputFiles` 的路径为 **Windows 绝对路径**。
|
||||
- 凭证:登录态在 user-data-dir;密码、AI Key 本地明文存于 config/DB;`config.json`、`config/ai_models.json`、`cmshopee.db`、`chrome_user_data_dir/`、`images/` 必须 gitignore;UI 打码显示,不出现在日志/导出。
|
||||
- 凭证:登录态在 user-data-dir;密码、AI Key 本地明文存于 config/DB;`config.json`、`config/ai_models.json`、`config/cmhub.json`、`cmshopee.db`、`chrome_user_data_dir/`、`images/` 必须 gitignore;UI 打码显示,不出现在日志/导出。
|
||||
- 失败处理:抛带中文说明的异常或返回状态字段;GUI 负责提示,不静默吞错。
|
||||
|
||||
## appconfig 模块(`app/appconfig.py`,已建)
|
||||
@@ -29,10 +29,13 @@ cdp_ready_timeout(config=None) -> int
|
||||
ai_config(config=None) -> dict # default_text_model/default_image_model/
|
||||
# title_concurrency/image_concurrency/retry/jpg_quality/
|
||||
# resolution/resolution_timeouts
|
||||
ai_backend(config=None) -> str # direct / cmhub
|
||||
cmhub_config(config=None) -> dict # base_url/title_alias/image_alias/connect_timeout
|
||||
cmhub_request_url(base_url, endpoint) -> str
|
||||
response_timeout(config=None) -> int # = resolution_timeouts[resolution](返回超时,随分辨率)
|
||||
```
|
||||
|
||||
`default_config()` / `load_config()` 包含 `shopee_update` 安全配置段:历史/调试兼容测试商品 ID、是否允许真实提交、是否允许更新封面、每批最大更新条数、成功后是否关闭本轮新开编辑页、内部兼容 `dry_run`、多账号并行、最大并行账号数。普通正式更新不再用测试商品 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`、多账号并行、最大并行账号数。普通正式更新不再用测试商品 ID 阻断当前筛选结果。`config.json` 不保存 AI Key;写入 `api_key` / `*_key` / `token` / `*_token` / `password` / `*_password` 等敏感字段时抛 `ConfigError`。AI Key 留给 `config/ai_models.json`(direct)或 `config/cmhub.json`(cmhub)。
|
||||
|
||||
敏感信息展示/日志辅助:
|
||||
|
||||
@@ -42,6 +45,17 @@ sanitize_for_log(value) -> object # 递归打码 api_key/password/tok
|
||||
redact_secrets(text, secret_values=None) -> str # 用已知明文值替换自由文本中的秘密
|
||||
```
|
||||
|
||||
|
||||
cmhub Key 文件(`config/cmhub.json`,含本地明文密钥,T-526 已建;UI 由 T-527 接入):
|
||||
|
||||
```python
|
||||
default_cmhub_config() -> dict
|
||||
load_cmhub_config(path="config/cmhub.json") -> dict # 缺文件返回空 key,不自动启用 cmhub
|
||||
save_cmhub_config(config, path="config/cmhub.json") -> dict
|
||||
get_cmhub_api_key(path="config/cmhub.json", masked=False) -> str
|
||||
```
|
||||
|
||||
`config.json` 只保存 `ai.backend`、`ai.cmhub.base_url/title_alias/image_alias/connect_timeout` 等非密钥配置;`config/cmhub.json` 必须 gitignore,展示时打码,不写日志/导出。
|
||||
AI 模型清单(`config/ai_models.json`,含本地明文密钥,已建;UI 由 ⑤ 设置复用):
|
||||
|
||||
```python
|
||||
@@ -271,14 +285,15 @@ 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", on_step=None) -> str
|
||||
# 文本生成:读取 default_text_model,chat JSON 请求;提示词 + 旧标题 → 新标题
|
||||
gen_title(title_prompt, old_title, retry=None, config=None, models_path="config/ai_models.json", on_step=None, on_event=None, cmhub_config_path="config/cmhub.json") -> str
|
||||
# 文本生成:按 backend 分流;direct 走 chat JSON,cmhub 走 /generate/title;提示词 + 旧标题 → 新标题
|
||||
|
||||
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;
|
||||
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, on_event=None, cmhub_config_path="config/cmhub.json") -> str
|
||||
# 图像生成(image-to-image):按 backend 分流;direct 走 chat/images_edits,cmhub 走 /generate/image;
|
||||
# 支持返回 url / data URL / b64_json,按 resolution resize 并以 jpg_quality 保存 JPEG,返回路径;新生成默认写入 `image_dir/<batch_id>/<slug>/<task_id>_<item_id>_new.jpg`,历史 DB 已存路径继续按原路径读取
|
||||
|
||||
generate_batch(tasks, prompts, ai_cfg=None, on_progress=None, should_stop=None) -> dict
|
||||
fetch_cmhub_models(base_url, api_key, connect_timeout=10, read_timeout=30) -> list[dict]
|
||||
# 编排:先以 title_concurrency 线程池并发跑 gen_title;ai.generate_cover 为 true 时再以 image_concurrency 并发跑 gen_cover
|
||||
# 标题-only 模式标题成功即 db.set_generated(task_id, new_title, None);标题+封面模式图片成功后写 new_cover_path;should_stop() 为真则取消未开始项
|
||||
# on_progress({"total","title_done","cover_done","failed","cancelled","ok"}) 回调刷新进度
|
||||
@@ -288,10 +303,12 @@ generate_batch(tasks, prompts, ai_cfg=None, on_progress=None, should_stop=None)
|
||||
|
||||
要点:
|
||||
|
||||
- 标题用 `default_text_model`、封面用 `default_image_model`(`appconfig.get_model` 取定义,含 url/key/api_type)。
|
||||
- `backend=direct`:标题用 `default_text_model`、封面用 `default_image_model`(`appconfig.get_model` 取定义,含 url/key/api_type)。
|
||||
- `backend=cmhub`:标题调用 `POST /api/v1/generate/title`,封面调用 `POST /api/v1/generate/image`,模型字段使用 `ai.cmhub.title_alias/image_alias`,Key 来自 `config/cmhub.json`。
|
||||
- `fetch_cmhub_models()` 调 `GET /api/v1/models` 返回别名清单,供 T-527 设置页动态下拉使用。
|
||||
- `api_type=chat/auto` 走 OpenAI-compatible chat JSON;`api_type=images_edits` 走 multipart form。
|
||||
- 连接超时参考模型 `connect_timeout_seconds`;**返回超时 = 模型 `timeout_seconds` 或 `appconfig.response_timeout()`(随分辨率:512/1k/2k/4k → 180/240/360/600)**。
|
||||
- 并发数/重试/分辨率/jpg 质量来自 `appconfig.ai_config()`;Key 本地明文存储,但不入日志、不导出。
|
||||
- direct 连接超时参考模型 `connect_timeout_seconds`;**返回超时 = 模型 `timeout_seconds` 或 `appconfig.response_timeout()`(随分辨率:512/1k/2k/4k → 180/240/360/600)**。cmhub 使用 `requests timeout=(connect, read)`,connect 来自 `ai.cmhub.connect_timeout`,read 随分辨率且封顶 600s。
|
||||
- 并发数/重试/分辨率/jpg 质量来自 `appconfig.ai_config()`;Key 本地明文存储,但不入日志、不导出。cmhub 响应的 `points_cost/points_balance/call_id` 不改变返回值,通过 `on_event` metadata 事件上报,GUI 余额/计费展示留给 T-528。
|
||||
- 标题快、图片慢:分两段、各用各自并发数;失败按 `retry` 重试,仍失败记 error 不阻塞其余。
|
||||
- 调用有成本与失败可能:超时、限流、内容安全拒绝都要返回明确错误。
|
||||
- 生成结果**直接进入 ③ 更新候选**;③ 点击「开始更新」后弹窗批量确认,确认后提交线上。本地留档 + 回写 Excel 供追溯。
|
||||
|
||||
+15
-15
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user