Files
cmshoppe/docs/04-architecture.md
T
chengma c2f2530149 feat: 完成T-301 AI生成接口
新增app/ai.py,按config/ai_models.json读取默认文本和图片模型,提供gen_title与gen_cover通用HTTP接口。

支持chat JSON与images_edits multipart、失败重试、错误脱敏、图片URL/base64解析、resolution resize和jpg_quality保存。

新增tests/test_ai.py覆盖文本重试、缺字段错误不泄露Key、封面JPEG保存;同步任务看板、API、技术栈、架构、current-state和progress,并记录Tab①真机冒烟结果。
2026-06-27 15:47:21 +08:00

391 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 架构设计
> 本文讲“怎么把技术栈搭起来”:模块职责、存储模型、流水线、CDP 已验证事实、开发顺序。
> 具体用了哪些库 / 平台,见 [技术栈](03-tech-stack.md)。
## 一、系统结构
Windows 本地桌面自动化工具,无后端服务,5 Tab GUI 驱动一条流水线。
```text
运营(人)
|
v
GUI(PySide6 QTabWidget,5 Tab)
① 导入采集 ② AI生成 ③ 更新shopee ④ 账号管理 ⑤ 设置
|
v
核心模块(Python)
├── appconfig 读应用配置 config.json(Chrome 路径、目录根、AI 配置、端口范围…)
├── db SQLite 读写:账号、任务、各阶段结果(cmshopee.db)
├── excel openpyxl 导入输入列 / 回写输出列到原 Excel
├── config 账号 ↔ user-data-dir 绑定、slug、目录创建
├── accounts 账号 CRUD 服务:生成 slug/目录、启动登录、检测登录
├── chrome 按账号拼启动参数、启动/探测 Chrome、生成快捷方式
├── cdp CDP 客户端(连接、找/开 tab、执行 JS、拖拽)
├── editor 登录检测 / 采集旧标题旧封面 / 改标题 / 换封面 / 点更新
└── ai 文本生成(提示词+旧标题→新标题)/ 图像生成(提示词+旧封面→新封面)
|
v
Google Chrome(每账号独立 --user-data-dir + --remote-debugging-port) + AI 服务(外部)
|
v
Shopee 卖家中心页面 / 本地图片目录
```
真实组件:
- GUI 入口:根目录 `main.py` 调用 `app/gui.py`(待建,PySide6 + `QMainWindow` + `QTabWidget`,5 Tab);也支持 `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`。
## 二、流水线(核心)
每个任务(Excel 行)依次走过 4 个业务阶段,状态字段 `stage` 贯穿全程:
```text
imported → collected → generated → applied
(导入 Excel) (采集旧数据) (AI 生成新数据) (改 Shopee 并提交)
① Tab ① Tab ② Tab ③ Tab
```
- **imported**:openpyxl 解析输入列入库。
- **collected**:只读打开商品页,读旧标题、下载旧封面到本地,写 `old_title/old_cover_path`,回写 Excel 旧字段。
- **generated**:AI 用提示词+旧标题生成新标题;用提示词+旧封面生成新封面(image-to-image),新图存本地。**不设逐条人工审核阶段**,生成完即可进入 ③(新图留档本地 + 回写 Excel 供事后追溯)。
- **applied**:③ 点击「开始更新」后弹窗确认当前筛选范围和任务数量;确认后打开编辑页换标题+封面,逐条点「更新」提交线上,回写结果。
任意阶段失败 → `stage` 不前进、记 `error`、`result/skipped`,不影响其他任务。
## 三、职责划分
**GUI(5 Tab)**:见 [routes.md](routes.md)。只做交互与预览,不写业务逻辑;耗时操作走 PySide6 `QObject` worker + `QThread`,用 signal 回主线程刷新 UI。**首次未配账号、对应账号 Chrome 未启动或未登录时,① ③ 执行按钮禁用或执行前拦截,并提示去 ④。**
**核心模块**
- `appconfig`:读写 `config.json`(Chrome 路径、`chrome_user_data_dir` 根、图片目录、AI 配置、端口、DB 路径)。
- `db`:SQLite 读写账号、任务、各阶段结果;建表/迁移。
- `excel`:openpyxl 读输入列、把输出列回写原 Excel(处理文件锁)。
- `config`:账号 ↔ user-data-dir 绑定;slug;目录创建。
- `accounts`:账号 CRUD 服务;生成目录、启动登录、检测登录;不自动登录/填密码。
- `chrome`:拼接启动命令、启动、探测端口、(可选)生成快捷方式。
- `cdp`:连接调试端口、找/开 tab、执行 JS、拖拽、注入文件。
- `editor`:登录检测、**采集**(读旧标题、下载旧封面)、改标题、换封面、点更新。
- `ai`:`gen_title(prompt, old_title)`、`gen_cover(prompt, old_cover_path)`(外部 AI;模型清单配置;通用 HTTP)。
**存储(同一事实只存一处)**
- 应用配置(模型选择、生成参数、目录、Chrome 路径)→ `config.json`。
- AI 模型清单(url/模型/密钥/类型/连接超时)→ `config/ai_models.json`(API Key 本地明文保存,必须 gitignore,UI 打码显示)。
- 业务数据(账号、任务、各阶段结果)→ SQLite `cmshopee.db`。
- 图片(采集的旧封面、AI 生成的新封面)→ 本地图片目录(路径记在 DB)。
- 提示词 → 标题提示词存单文件 `title_prompt.txt`;封面提示词存多模板 `prompts/cover/<名称>.txt`。
- 登录态 → 各账号 `chrome_user_data_dir/<slug>/`。
## 四、多账号隔离方案(决策)
采用**每账号独立 user-data-dir**(非 Chrome profile)。`--remote-debugging-port` 绑定在 user-data-dir/进程上,profile 方案无法每账号独立 CDP、串号风险高。启动主路径用程序 `subprocess` 直启(`--remote-debugging-port` + `--remote-allow-origins=*` + `--user-data-dir`);可选生成 `.lnk` 快捷方式(PowerShell `WScript.Shell`,参数写在「目标」字段)。
## 五、数据模型
### 5.1 应用配置 `config.json`
```json
{
"chrome_path": "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
"user_data_root": "chrome_user_data_dir",
"image_dir": "images",
"db_path": "cmshopee.db",
"default_debug_port": 9222,
"debug_port_range": [9222, 9260],
"cdp_ready_timeout": 60,
"ai": {
"default_text_model": "GPT-5.5 文本",
"default_image_model": "Nano Banana 2",
"title_concurrency": 4,
"image_concurrency": 4,
"retry": 2,
"jpg_quality": 90,
"resolution": "1k",
"resolution_timeouts": { "512": 180, "1k": 240, "2k": 360, "4k": 600 }
}
}
```
`ai` 段只放**选择 + 全局生成参数**:
- `default_text_model` / `default_image_model`:引用 `ai_models.json` 里的模型名(标题用文本模型、封面用图像模型)。
- `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、不入日志。
### 5.1b AI 模型清单 `config/ai_models.json`
模型定义清单("有哪些模型"),与 `config.json` 的 `ai` 段("选了哪个 + 全局参数")职责分开。
```json
{
"models": [
{
"name": "Nano Banana 2", // 服务商/模型名,唯一,作下拉显示与引用键
"category": "image", // text | image —— 决定它出现在“标题/图片大模型”哪个下拉
"enabled": true,
"url": "https://api.vectorengine.ai/v1/chat/completions",
"model": "gemini-3.1-flash-image-preview", // 模型 ID
"api_key": "***", // 密钥:本地明文存、UI 打码、不入日志、不进版本库
"api_type": "auto", // chat | images_edits | auto —— 决定请求构造方式
"connect_timeout_seconds": 30, // 连接该服务超时(每模型,默认 30)
"timeout_seconds": 0, // 返回超时:0/留空 = 运行时按 resolution_timeouts 取值
"extra_body": {}
}
]
}
```
关键事实:
- **`category`(文本/图像)是必需的**:角色下拉据此过滤(标题下拉只列 text、图片下拉只列 image),防止错配。
- 约束:**至少各有一个 text 与一个 image 模型**;下拉默认最少一项、删到剩一项时禁用「删除」。
- `connect_timeout_seconds`(连接超时)属于**模型**;返回超时由分辨率映射决定(不在模型上单设)。
- `api_type` 反映不同 API 形状(`chat`/`images_edits`/`auto`),请求构造按它分支。
- `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,
account_name TEXT NOT NULL, -- Shopee 登录账号名(展示/参考)
alias TEXT UNIQUE NOT NULL, -- 别名,Excel 用它匹配
region_host TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL, -- user-data-dir 子目录名 [a-z0-9_]
user_data_dir TEXT NOT NULL,
debug_port INTEGER NOT NULL,
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 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,
-- 采集输出(程序写,改前快照)
old_title TEXT,
old_cover_path TEXT, -- 旧封面本地图片路径
-- AI 输出
new_title TEXT,
new_cover_path 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 模板
标准空模板文件保留在仓库根目录:`shopee待处理任务模板.xlsx`,单工作表名为 `待处理任务`。运营使用时应复制一份再填写,填写后的业务 Excel 含商品数据,不提交版本库。
| 列 | 含义 | 输入/输出 |
| --- | --- | --- |
| 账号名 | Shopee 账号名(展示) | 输入 |
| 别名 | 关联 accounts.alias(匹配键) | 输入 |
| 商品id | item_id | 输入 |
| 旧标题 | 采集到的旧标题 | 输出,回写 |
| 旧封面图片路径 | 采集到的旧封面本地路径 | 输出,回写 |
| 新标题 | AI 生成的新标题 | 输出,回写 |
| 新封面图片路径 | AI 生成的新封面本地路径 | 输出,回写 |
| 更新状态 | 处理结果(成功/失败/跳过+原因) | 输出,回写 |
- 输入列(账号名/别名/商品id)运营填;其余为程序各阶段输出,**回写到原 Excel**(被锁→提示重试/另存副本)。
- 别名以此列为匹配权威,不解析文件名。
- 标准模板推荐前三列表头固定为:`账号名 | 别名 | 商品id`。不要使用 `账号`、`店铺名`、`店名` 代替匹配列;`别名` 必须与 ④ 账号管理中的 `accounts.alias` 一致。
- 导入容错:缺少必需列(别名/商品id)时拒绝整个文件,记入 `file_errors`,不导入该文件任何行。
- 脏行处理:单行缺别名/商品id、商品id 格式错误等逐行跳过,计入 `invalid`,不阻塞同文件其他有效行。
### 5.4 本地图片目录
```text
images/<slug>/<item_id>_old.<ext> # 采集下载的旧封面
images/<slug>/<item_id>_new.<ext> # AI 生成的新封面
```
路径记入 DB;上传新封面用本地 `<item_id>_new` 文件(Windows 绝对路径传 setFileInputFiles)。
## 六、关键流程细节
### 6.0 GUI 线程模型(PySide6)
- 主线程只运行 `QApplication`、窗口、表格、弹窗和状态刷新;不得在主线程执行 CDP、AI、Excel 回写、图片下载等耗时任务。
- 每类耗时流程封装为 `QObject` worker:`CollectWorker`、`GenerateWorker`、`ApplyWorker`、`ImportWorker`、`WriteBackWorker`。
- Worker 通过 signal 向 GUI 汇报:`progress`、`row_updated`、`log`、`failed`、`finished`、`cancelled`;GUI 槽函数只做 UI 刷新和按钮状态切换。
- Worker 不直接操作任何 Qt widget,不弹窗;需要用户确认的动作(如 ③ 开始更新确认)必须在主线程先完成,再启动 worker。
- `停止` 使用协作式取消:GUI 调用 worker 的 cancel 标记;worker 在任务间/重试前检查,取消未开始项,正在执行的单条任务跑到安全边界后结束。
- SQLite connection 不跨线程共享;每个 worker/线程按需创建自己的连接,写库后发 signal 通知 UI 刷新。
### 6.1 采集(① Tab,只读)
- 用账号 Chrome 打开商品页,等就绪,读旧标题(标题输入框 value)。
- 旧封面:取第一张 itembox 的 `img.src`(CDN 链接),下载到 `images/<slug>/<item_id>_old`。
- 写 `old_title/old_cover_path`、stage=collected;批量回写 Excel 旧字段。
- 采集任务结束且本轮有成功采集行时,自动触发当前批次旧字段回写;原 Excel 被锁时不影响 SQLite 结果,提示关闭后重试,并保留手动「回写旧数据到 Excel」入口。
### 6.2 AI 生成(② Tab)
单个「开始生成」按钮,**两段式、各自并发**(标题快、图片慢,分开并发更高效):
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/<slug>/<item_id>_new.jpg`。
- 连接超时取该模型 `connect_timeout_seconds`;**返回超时取 `resolution_timeouts[resolution]`**(512→180/1k→240/2k→360/4k→600)。
- 失败重试:每次调用失败按 `retry` 次重试,仍失败则记 error(不阻塞其余)。
- 每条/每张完成**立即 `set_generated` 写库**(实时落库,停止或崩溃不丢已生成的)。
- **「停止」**:取消未开始的任务,正在跑的少量完成或中断;停止后可再次「开始生成」对剩余继续。
- 进度:`标题 x/n · 封面 x/n · 失败 n`。
- 生成后 stage=generated;**不设逐条人工审核阶段**。双击任务弹窗查看新旧封面(纯查看),可选对某行 `重生成`;新标题直接用 AI 输出(不可编辑)。
- 并发数、重试、分辨率、jpg 质量、模型/Key 均来自 ⑤ 设置(`config.json` 的 `ai` 段)。
提示词管理:
- **标题提示词**:单个文本,「保存」写入 `title_prompt.txt`;软件启动时加载该文件回显到输入框(缺失则空)。
- **封面提示词**:多模板。下拉选模板(读 `prompts/cover/*.txt`),图标工具栏 新建/保存/另存为/重命名/删除;重名校验、删除二次确认、删空给默认。
- **变量**:封面提示词支持占位符 `{旧标题}`、`{新标题}`、`{商品id}`、`{店铺}`,生成前用该任务真实值替换(`render_prompt`)。「插入标题」= 在光标处插入 `{新标题}`;「预览」= 用某条任务的值替换变量后展示,确认实际发送给 AI 的内容。
### 6.3 应用更新(③ Tab)
- ③ 顶部筛选确定本次作用范围;点击「开始更新」后弹窗展示筛选条件、任务数量和“将提交线上”的风险提示。
- 用户点「是/确认」才开始批量更新;点「否/取消」不执行、不改库。
- 对确认后的**已生成(generated)任务**:`open_product` → `change_title(new_title)`(如有)→ `replace_cover(new_cover_path)`(如有)→ `click_update` 提交。
- 串行、单条失败继续;每条立即写 SQLite;全部完成回写 Excel(新字段+状态)+ 弹窗汇总。
### 6.4 登录检测
- 无 Shopee tab 时打开卖家中心根地址 `https://<region_host>/`(默认 `https://seller.shopee.tw/`),重定向到登录页或缺会话 Cookie(`SPC_ST`/`SPC_U`)→ 未登录;不自动登录,提示人工登录。
## 七、CDP 已验证事实(务必遵守)
| 难点 | 已验证结论 |
| --- | --- |
| Chrome 启动参数 | 全关后带 `--remote-debugging-port=<port> --remote-allow-origins=* --user-data-dir=<dir>`;缺 allow-origins 则 WebSocket 403 |
| 代理干扰 | 清除 `*_proxy`(requests `trust_env=False`),否则连本地 CDP 超时 |
| WebSocket Origin | `websocket-client` `suppress_origin=True` |
| SPA 就绪 | 不用 load 事件;轮询“标题输入框 + 图片 itembox + 上传输入框”三者都在 |
| 标题输入框 | XPath `//input[@class='eds-input__input' and string-length(@modelvalue)>24]` |
| 写标题 | 原生 setter + 派发 `input`/`change`;`value`==`modelvalue`==新值 |
| 读旧封面 | 第一张 itembox 的 `img.src`(`susercontent` CDN),下载到本地 |
| 上传输入框 | `.shopee-image-manager__upload input[type=file]`;`DOM.setFileInputFiles` 传 Windows 路径 |
| 上传成功 | 张数 +1 且新图 src 为 `susercontent` |
| 封面=第一位 | `Input.dispatchMouseEvent` 拖到第一位,落点 `第一张.left - 0.30*宽` |
| 满 9 张 | 上限 9;换封面先删第一张(`.shopee-image-manager__icon--delete`,确认框待实测)|
| 更新按钮 | `button.eds-button` 中 `<span>更新</span>`;③ 批量确认后逐条点提交;禁用态(校验未过)记为失败 |
| 登录检测 | 重定向到登录页或缺 `SPC_ST` → 未登录 |
高风险动作(删满 9 张封面、点更新提交、AI 图上线)先在测试商品验证。注意:本设计无逐条人工审核阶段、无常驻提交开关;③ 点击「开始更新」后必须弹窗确认,确认后才把当前筛选结果中的 AI 标题/封面提交线上。新图本地留档+回写 Excel 是事后追溯手段。
## 八、推荐开发顺序
1. **地基**:先建 `app/` 包、`app/cdp.py`、`app/__main__.py`、根目录 `main.py`;再做 `app/editor.py`(含采集)、`app/appconfig.py`+`config.json`、`app/db.py`、`.gitignore`。
2. **账号与启动**(④):`config` 建目录、`chrome` 启动器/快捷方式、登录保活与检测、账号 CRUD。
3. **导入采集**(①):`excel` 导入、采集旧标题/旧封面、回写。
4. **AI 生成**(②):`ai` 模块、提示词、对照预览。
5. **更新 shopee**(③):对已生成任务弹窗批量确认后换标题+封面、提交、回写。
6. **设置**(⑤)+ 首次未配账号引导保护。
## 九、项目结构建议
```text
cmshopee/
├── docs/
├── app/
│ ├── __init__.py
│ ├── __main__.py # 支持 python -m app
│ ├── cdp.py # CDP 底座(由根目录 cdp.py 迁入)
│ ├── appconfig.py / db.py / excel.py / config.py / accounts.py / chrome.py
│ ├── editor.py / ai.py / prompts.py / gui.py / workers.py
├── main.py # GUI 启动入口:from app.gui import main
├── shopee待处理任务模板.xlsx # 标准空 Excel 模板,可提交;业务填写后的副本不提交
├── config.json # 应用配置(模型选择/生成参数/路径,gitignore)
├── config/ai_models.json # AI 模型清单(含密钥,必须 gitignore)
├── cmshopee.db # SQLite(账号/任务/结果,gitignore)
├── chrome_user_data_dir/ # 各账号 Chrome 配置(含登录态,gitignore)
├── images/ # 旧封面/新封面本地图片(gitignore)
├── title_prompt.txt # 标题提示词(单文件,启动回显)
├── prompts/cover/<名称>.txt # 封面提示词模板(多个)
└── prototypes/ # 已验证原型/探查脚本(demo/set_*/get_title/cookies/inspect_images/grab/1.py)
# 逻辑待并入 app/editor.py 后清理;见 prototypes/README.md
```
> `config.json`、`config/ai_models.json`、`cmshopee.db`、`chrome_user_data_dir/`、`images/` 含密钥/凭证/业务数据,必须 gitignore。`shopee待处理任务模板.xlsx` 是标准空模板,可以提交;运营填写后的 Excel 副本属于业务数据,不提交。
## 十、架构纪律
- CDP 交互事实变化同步第七节。
- 正式代码只放 `app/` 包;根目录只保留 `main.py`、配置/数据目录、文档和原型目录,不新增正式业务模块。
- `app` 包内模块优先用相对导入(如 `from .cdp import CDP`);根入口 `main.py` 用 `from app.gui import main`。
- 存储边界:应用设置→config.json,账号/任务/结果→SQLite,图片→本地目录并记路径于 DB,登录态→user-data-dir;同一事实只存一处。
- 别名是账号↔任务唯一关联键。
- 密码与 AI Key 本地明文保存、UI 打码、不外传、不写日志;不自动登录。
- AI 生成内容直接进入 ③ 更新候选;③ 批量确认后提交,新图本地留档 + 回写 Excel 以备追溯。
- 高风险模块先单独验证,再接入流水线。
- GUI 只通过 signal/slot 接收 worker 进度;禁止后台线程直接操作 Qt widget 或共享 SQLite connection。