diff --git a/AGENTS.md b/AGENTS.md index 2fc0186..fd91697 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -25,7 +25,7 @@ cmshopee 是一个 **Windows 本地桌面自动化工具**:管理多个 Shopee ## 工作规则 -- 复用已有 `cdp.py`,遵守架构第七节的选择器、就绪判断、上传/拖拽方式,不另起一套 CDP 交互。 +- 正式代码统一放入 `app/` 包;迁移完成后复用 `app/cdp.py`,遵守架构第七节的选择器、就绪判断、上传/拖拽方式,不另起一套 CDP 交互。 - 只做当前任务范围内的事;V2(多账号并行、dry-run、运行日志)只记录不实现。 - CDP 选择器 / 流程 / 配置 schema 变化,必须同步更新 `docs/04-architecture.md` 与相关任务。 - 改完后更新任务状态、追加 `progress.md`、覆盖 `docs/current-state.md`。 @@ -40,7 +40,7 @@ cmshopee 是一个 **Windows 本地桌面自动化工具**:管理多个 Shopee ## 验证 ```bash -python -m py_compile *.py # 语法检查 +python -m compileall app main.py # 语法检查(T-000 后) python -m unittest discover -s tests # 纯逻辑单元测试(T-006 完成且 tests/ 存在后) python prototypes/demo.py # 单账号闭环(不提交) ``` diff --git a/docs/00-ai-start-here.md b/docs/00-ai-start-here.md index d0ecce7..a10d228 100644 --- a/docs/00-ai-start-here.md +++ b/docs/00-ai-start-here.md @@ -34,7 +34,7 @@ cmshopee 是一个 Windows 本地桌面自动化工具(PySide6,5 Tab), 优先路径: -1. Phase 0:把已验证流程模块化(`editor.py`),建立 `config.json` 与 SQLite。 +1. Phase 0:先建立正式代码包 `app/` 与根入口 `main.py`,再把已验证流程模块化到 `app/editor.py`,建立 `config.json` 与 SQLite。 2. Phase 1:账号绑定 user-data-dir、Chrome 启动、登录保活、PySide6 主窗口骨架。 3. Phase 2:导入 Excel、采集旧标题/旧封面并回写。 4. Phase 3:AI 生成新标题/新封面。 @@ -61,7 +61,7 @@ cmshopee 是一个 Windows 本地桌面自动化工具(PySide6,5 Tab), - 单账号已登录 Chrome,通过 CDP 打开商品页、改标题、换封面。 - 原型脚本默认不提交线上,`UPDATE=1` 才点击「更新」。 -- 作为 `editor.py` 的已验证参照,不再代表当前完整产品范围。 +- 作为 `app/editor.py` 的已验证参照,不再代表当前完整产品范围。 **V1 当前 coding 目标**: @@ -86,7 +86,7 @@ cmshopee 是一个 Windows 本地桌面自动化工具(PySide6,5 Tab), - [`04-architecture.md`](04-architecture.md) 第七节:CDP 交互已验证结论(选择器、就绪判断、上传/拖拽方式)。 - [`04-architecture.md`](04-architecture.md) 5.1/5.1b/5.2/5.3:`config.json`、`config/ai_models.json`、SQLite schema、Excel 模板。 - 真实页面探查结果(用 `prototypes/inspect_images.py` / `prototypes/cookies.py` 实地确认)。 -- 已验证脚本 `cdp.py`、`prototypes/demo.py`、`prototypes/set_title.py`、`prototypes/set_cover.py` 中跑通的逻辑。 +- 已验证脚本 `cdp.py`(T-000 后迁入 `app/cdp.py`)、`prototypes/demo.py`、`prototypes/set_title.py`、`prototypes/set_cover.py` 中跑通的逻辑。 不要把以下当事实来源: @@ -106,7 +106,7 @@ cmshopee 是一个 Windows 本地桌面自动化工具(PySide6,5 Tab), - 先看 `04-architecture.md` 第七节已验证事实。 - 再看 `api.md` 的 `cdp` / `editor` 模块合约。 -- 复用 `cdp.py`,不重写一套。 +- 复用 `app/cdp.py`(迁移前参考根目录 `cdp.py`),不重写一套。 做账号配置 / Chrome 启动: @@ -116,7 +116,7 @@ cmshopee 是一个 Windows 本地桌面自动化工具(PySide6,5 Tab), ## 验证命令 ```bash -python -m py_compile *.py # 语法检查 +python -m compileall app main.py # 语法检查(T-000 后) python -m unittest discover -s tests # 纯逻辑单元测试(T-006 完成且 tests/ 存在后) python prototypes/demo.py # 单账号闭环验证(分步,不提交) ``` diff --git a/docs/03-tech-stack.md b/docs/03-tech-stack.md index 2f2cd10..06b299a 100644 --- a/docs/03-tech-stack.md +++ b/docs/03-tech-stack.md @@ -9,7 +9,7 @@ | --- | --- | --- | --- | | 语言 | Python 3.10+ | 已定 | 已有脚本均为 Python;标准库够用 | | 运行平台 | Windows(生产);WSL 可用于开发 | 已定 | Chrome 与各 user-data-dir 在 Windows;GUI 与 Chrome 同机,CDP 走 `localhost` | -| 浏览器自动化 | 自研 CDP 客户端 `cdp.py` | 已定 | 基于 websocket-client + requests 手写;不引入 playwright/selenium,规避代理与 Origin 坑 | +| 浏览器自动化 | 自研 CDP 客户端 `app/cdp.py` | 已定 | 基于 websocket-client + requests 手写;不引入 playwright/selenium,规避代理与 Origin 坑 | | WebSocket | `websocket-client`(import `websocket`) | 已定 | 讲 CDP 协议;用 `suppress_origin=True` 绕过 403 | | HTTP | `requests` | 已定 | 读 `/json` 拿 tab 列表;`trust_env=False` 忽略代理 | | 浏览器 | Google Chrome(已安装) | 已定 | 带 `--remote-debugging-port` 启动 | @@ -22,17 +22,17 @@ | AI 图像生成 | 选 `default_image_model`(category=image,image-to-image) | 选型在配置 | 提示词+旧封面→新封面;分辨率 512/1k/2k/4k,返回超时随分辨率 | | 并发 | 标准库 `concurrent.futures.ThreadPoolExecutor` | 已定 | 标题/图片分别按并发数并行;可停止、可重试 | | 图片处理 | `requests`(下载)+ `Pillow`(按分辨率/jpg质量存盘) | 部分待定 | 下载旧封面;新封面按 resolution 生成、jpg_quality 存盘 | -| 测试 | `python -m py_compile` + `unittest` + 手动 CDP/AI 验证 | 已定(分层) | 配置/DB/Excel/prompts 用单测;CDP/Shopee 与真实 AI 属集成验证或 mock | +| 测试 | `python -m compileall app main.py` + `unittest` + 手动 CDP/AI 验证 | 已定(分层) | 配置/DB/Excel/prompts 用单测;CDP/Shopee 与真实 AI 属集成验证或 mock | ## 二、决策记录与演进 -- **CDP 自研而非 playwright**:当前手写 `cdp.py`,因为它零重依赖、完全可控,并已在开发环境绕开了代理(`*_proxy` 指向本地 :1080)和 Chrome 的 Origin 403 两个坑。未来若交互复杂度大幅上升,再评估 playwright。 +- **CDP 自研而非 playwright**:当前已验证根目录 `cdp.py`,正式代码迁入 `app/cdp.py`;它零重依赖、完全可控,并已在开发环境绕开了代理(`*_proxy` 指向本地 :1080)和 Chrome 的 Origin 403 两个坑。未来若交互复杂度大幅上升,再评估 playwright。 - **GUI 选 PySide6**:V1 是 5 Tab 运营工作台,包含任务表格、筛选、图片预览、后台采集/生成/更新、进度与停止。当前环境已安装 PySide6,且 Tkinter 不可用;Qt 的 `QThread`/signal-slot 比 Tkinter 手动 queue/after 更适合长任务回传 UI。 - **存储拆两层**:应用设置进 `config.json`,账号/任务/结果进 SQLite。判据:少量人改无需查询 → 配置文件;成行增长要查询/导出 → DB。同一事实只存一处,不重复。取代早期的 `accounts.json` 方案。 - **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 服务商待定**:需选支持文本生成 + 图像 image-to-image 的服务;选型要权衡能力、合规(电商主图)、计费、Key 管理。**未确认前不在代码里写死某家 SDK**,先在 `ai.py` 留稳定接口(`gen_title`/`gen_cover`)。 +- **AI 服务商待定**:需选支持文本生成 + 图像 image-to-image 的服务;选型要权衡能力、合规(电商主图)、计费、Key 管理。**未确认前不在代码里写死某家 SDK**,先在 `app/ai.py` 留稳定接口(`gen_title`/`gen_cover`)。 - **AI 产出无逐条审核**:生成的新标题/新封面经 ③ 批量确认后提交线上;无常驻提交开关,本地留档 + 回写 Excel 供追溯。 - **不引入数据库(指外部 DB)**:用 stdlib SQLite 足够;不引入 Postgres/MySQL 等。 - **生产在 Windows 直跑**:开发期我们用过 WSL→Windows 的 `netsh portproxy`(9333→9222)连 CDP;但 GUI 与 Chrome 都在 Windows 时,直接连 `127.0.0.1:9222`,无需 portproxy。 @@ -43,7 +43,8 @@ | --- | --- | | 安装依赖 | `pip install websocket-client requests openpyxl pillow PySide6` | | 检查 PySide6 | `python -c "import PySide6; print(PySide6.__version__)"` | -| 语法检查 | `python -m py_compile *.py` | +| 语法检查 | `python -m compileall app main.py` | +| 启动 GUI | `python main.py` / `python -m app` | | 单元测试(T-006 后) | `python -m unittest discover -s tests` | | 跑单账号演示 | `python prototypes/demo.py`(分步)/ `set AUTO=1 && python prototypes/demo.py`(自动) | | 提交更新(真改线上) | `set UPDATE=1 && python prototypes/demo.py` | @@ -66,14 +67,14 @@ set AUTO=1 && python prototypes/demo.py - 新增第三方依赖前,先在本文说明用途、替代方案和维护成本。 - GUI 框架固定为 PySide6,不允许混入 Tkinter/PyQt/Web 形成两套 UI。 -- 不引入第二套浏览器自动化方案(不要 cdp.py 之外再混入 selenium/playwright)。 +- 不引入第二套浏览器自动化方案(不要 `app/cdp.py` 之外再混入 selenium/playwright)。 - 不确定的技术选型先更新本文,再进入代码。 ## 五、测试分层 | 层级 | 覆盖对象 | 验证方式 | | --- | --- | --- | -| 语法 | 所有 `.py` | `python -m py_compile *.py`,后续可扩展 `compileall` | +| 语法 | 正式代码包与入口 | `python -m compileall app main.py` | | 单元 | `appconfig/db/excel/prompts/config/chrome` 的纯逻辑 | T-006 建立 `tests/` 后运行 `python -m unittest discover -s tests`,使用临时目录/临时 SQLite/样例 Excel | | GUI 轻测 | PySide6 主窗口可创建、Tab 数量、worker signal 基本行为 | 可用 unittest 构造 `QApplication`,不连真实 Shopee | | 集成 | CDP/editor 操作 Shopee 测试商品 | 手动跑 `prototypes/demo.py` 或后续专用集成脚本 | diff --git a/docs/04-architecture.md b/docs/04-architecture.md index ebe0a1b..09ba1d8 100644 --- a/docs/04-architecture.md +++ b/docs/04-architecture.md @@ -34,8 +34,8 @@ Shopee 卖家中心页面 / 本地图片目录 真实组件: -- GUI 入口:`gui.py`(待建,PySide6 + `QMainWindow` + `QTabWidget`,5 Tab)。 -- 核心模块:`appconfig.py`、`db.py`、`excel.py`、`config.py`、`chrome.py`、`editor.py`、`ai.py`(待建);CDP 底座 `cdp.py`(已有)。 +- GUI 入口:根目录 `main.py` 调用 `app/gui.py`(待建,PySide6 + `QMainWindow` + `QTabWidget`,5 Tab);也支持 `python -m app`。 +- 核心模块统一放在正式代码包 `app/`:`appconfig.py`、`db.py`、`excel.py`、`config.py`、`chrome.py`、`editor.py`、`ai.py`、`prompts.py`、`workers.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 服务(文本+图像,服务商待定);`openpyxl`。 @@ -338,7 +338,7 @@ images//_new. # AI 生成的新封面 ## 八、推荐开发顺序 -1. **地基**:`editor.py`(含采集)、`appconfig.py`+`config.json`、`db.py`、`.gitignore`。 +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` 模块、提示词、对照预览。 @@ -350,6 +350,13 @@ images//_new. # AI 生成的新封面 ```text cmshopee/ ├── docs/ +├── app/ +│ ├── __init__.py +│ ├── __main__.py # 支持 python -m app +│ ├── cdp.py # CDP 底座(由根目录 cdp.py 迁入) +│ ├── appconfig.py / db.py / excel.py / config.py / chrome.py +│ ├── editor.py / ai.py / prompts.py / gui.py / workers.py +├── main.py # GUI 启动入口:from app.gui import main ├── config.json # 应用配置(模型选择/生成参数/路径,gitignore) ├── config/ai_models.json # AI 模型清单(含密钥,必须 gitignore) ├── cmshopee.db # SQLite(账号/任务/结果,gitignore) @@ -357,11 +364,8 @@ cmshopee/ ├── images/ # 旧封面/新封面本地图片(gitignore) ├── title_prompt.txt # 标题提示词(单文件,启动回显) ├── prompts/cover/<名称>.txt # 封面提示词模板(多个) -├── appconfig.py / db.py / excel.py / config.py / chrome.py / editor.py / ai.py / prompts.py / gui.py # 待建 -├── workers.py # PySide6 worker/QThread 编排(可选拆分) -├── cdp.py # CDP 底座(正式模块,已有) └── prototypes/ # 已验证原型/探查脚本(demo/set_*/get_title/cookies/inspect_images/grab/1.py) - # 逻辑待并入 editor.py 后清理;见 prototypes/README.md + # 逻辑待并入 app/editor.py 后清理;见 prototypes/README.md ``` > `config.json`、`config/ai_models.json`、`cmshopee.db`、`chrome_user_data_dir/`、`images/` 含密钥/凭证/业务数据,必须 gitignore。 @@ -369,6 +373,8 @@ cmshopee/ ## 十、架构纪律 - 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 打码、不外传、不写日志;不自动登录。 diff --git a/docs/05-coding-rules.md b/docs/05-coding-rules.md index 20b0831..f1eabb8 100644 --- a/docs/05-coding-rules.md +++ b/docs/05-coding-rules.md @@ -7,7 +7,7 @@ 1. **不臆造**:选择器、字段、文件、接口不确定就查证或先用 `prototypes/inspect_images.py` 探查页面,不要猜 class 名。 2. **守范围**:只做当前任务要求的事,不顺手加批量/并行等后续功能。 -3. **照架构**:复用 `cdp.py`,遵守 `04-architecture.md` 第七节“已验证结论”,不另起一套 CDP 交互。 +3. **照架构**:复用 `app/cdp.py`(迁移前参考根目录 `cdp.py`),遵守 `04-architecture.md` 第七节“已验证结论”,不另起一套 CDP 交互。 4. **小步改**:一次只解决一个问题,不夹带无关重构。 5. **可验证**:改完必须能 `py_compile`,关键路径能在测试商品上跑通,对得上验收标准。 @@ -15,7 +15,7 @@ - 按链路确认:`vision` -> `requirements` -> `tech-stack` -> `architecture` -> `tasks`。 - 找到本任务对应的验收标准,写之前就知道“怎么算做对”。 -- 复用优先:已有 `cdp.py` 的 `CDP`、`find_product_tab`、`create_tab`、`drag`;已有 `prototypes/demo.py`/`prototypes/set_*.py` 中验证过的 JS 片段。 +- 复用优先:已有 CDP 底座(T-000 后为 `app/cdp.py`,当前来源为根目录 `cdp.py`)的 `CDP`、`find_product_tab`、`create_tab`、`drag`;已有 `prototypes/demo.py`/`prototypes/set_*.py` 中验证过的 JS 片段。 - 需求含糊或改动会偏离已验证事实时,先问。 ## 2. 事实来源纪律 @@ -51,7 +51,7 @@ 完成前至少检查: -- [ ] `python -m py_compile` 通过。 +- [ ] `python -m compileall app main.py` 通过(T-000 前仅文档改动不要求)。 - [ ] T-006 完成后,纯逻辑改动有对应 `unittest`,至少覆盖正常路径和一个失败路径。 - [ ] 涉及 CDP 的改动,在测试商品(ITEM_ID 51100639510)上实跑验证。 - [ ] 涉及 DB 的改动,覆盖 schema 初始化、重复初始化、短事务写入、失败状态写入。 @@ -62,7 +62,7 @@ - [ ] 回复里如实说明跑了什么命令、结果如何。 ```bash -python -m py_compile *.py +python -m compileall app main.py python -m unittest discover -s tests # T-006 完成且 tests/ 存在后 python prototypes/demo.py # 单账号闭环验证(不提交) ``` diff --git a/docs/06-tasks.md b/docs/06-tasks.md index a2e4468..bd73371 100644 --- a/docs/06-tasks.md +++ b/docs/06-tasks.md @@ -23,9 +23,10 @@ | ID | 任务 | 依赖 | 验收要点 | 状态 | | --- | --- | --- | --- | --- | -| T-001 | `editor.py`:改标题/换封面/点更新/登录检测/**采集(读旧标题+旧封面下载)**/apply_task,复用 `cdp.py` | - | 函数可调用,在测试商品跑通;与 `prototypes/demo.py` 行为一致 | TODO | -| T-002 | `appconfig.py` + `config.json`(含 image_dir、ai 选择/参数段、端口等默认值;不含 AI Key) | - | 读写正常;不存在则写默认;AI Key 留给 `config/ai_models.json`/T-501 | TODO | -| T-003 | `db.py` + SQLite 建表(batches/accounts/tasks,含 Excel 行定位、状态、时间戳、重试字段) | - | `init_db` 幂等;`connect` 设置 WAL/busy_timeout/foreign_keys;账号/批次/任务/各 set_* 可用;schema 同架构 5.2 | TODO | +| T-000 | 正式代码包结构:创建 `app/`、迁入 `cdp.py` 为 `app/cdp.py`、新增 `app/__init__.py`、`app/__main__.py`、根入口 `main.py`、最小 `app/gui.py` 占位入口,并修正 prototypes 导入 | - | `python -m compileall app main.py` 通过;`python -m app`/`python main.py` 可进入入口(GUI 未完成时给明确提示并退出);`prototypes/demo.py` 可从项目根导入 `app.cdp` | TODO | +| T-001 | `app/editor.py`:改标题/换封面/点更新/登录检测/**采集(读旧标题+旧封面下载)**/apply_task,复用 `app/cdp.py` | T-000 | 函数可调用,在测试商品跑通;与 `prototypes/demo.py` 行为一致 | TODO | +| T-002 | `app/appconfig.py` + `config.json`(含 image_dir、ai 选择/参数段、端口等默认值;不含 AI Key) | T-000 | 读写正常;不存在则写默认;AI Key 留给 `config/ai_models.json`/T-501 | TODO | +| T-003 | `app/db.py` + SQLite 建表(batches/accounts/tasks,含 Excel 行定位、状态、时间戳、重试字段) | T-000 | `init_db` 幂等;`connect` 设置 WAL/busy_timeout/foreign_keys;账号/批次/任务/各 set_* 可用;schema 同架构 5.2 | TODO | | T-004 | `.gitignore`:排除 `config.json`、`config/ai_models.json`、`cmshopee.db`、`chrome_user_data_dir/`、`images/` | T-002, T-003 | 配置、密钥、凭证、业务数据、图片不被提交 | TODO | | T-005 | AI 模型清单后端:`config/ai_models.json` 读写 + category 过滤 + 测试连接 | T-002 | 本地明文 api_key;UI/API 打码显示;日志脱敏;至少 text/image 各一个;`get_model` 返回调用所需字段 | TODO | | T-006 | 单元测试基座:`tests/` + appconfig/db/excel/prompts 最小测试 | T-002, T-003 | `python -m unittest discover -s tests` 可跑;不依赖真实 Shopee/AI;临时文件在测试目录清理 | TODO | @@ -35,7 +36,7 @@ | ID | 任务 | 依赖 | 验收要点 | 状态 | | --- | --- | --- | --- | --- | | T-101 | `config` 生成 slug + 创建 `chrome_user_data_dir/` | T-003 | 别名→唯一 slug;目录按需建;路径绝对化 | TODO | -| T-102 | `chrome.py` 启动器:拼参数并启动、探测端口 | T-101, T-002 | 含三参数;端口就绪可探测 | TODO | +| T-102 | `app/chrome.py` 启动器:拼参数并启动、探测端口 | T-101, T-002 | 含三参数;端口就绪可探测 | TODO | | T-103 | 首次登录保活 + 登录检测 `is_logged_in` | T-102, T-001 | 关闭再启动免重登;登录/未登录判断准确 | TODO | | T-104 | PySide6 五 Tab 主窗口骨架(`QMainWindow` + `QTabWidget`,5 Tab 空壳) | T-002 | 五个 Tab 按顺序可切换;启动不阻塞;基础状态栏可用 | TODO | | T-104b | PySide6 worker 基类与线程启动工具(`BaseWorker` + `QThread` 包装) | T-104 | signals: progress/log/row_updated/failed/finished/cancelled;取消标记可用;worker 不直接操作 QWidget | TODO | @@ -46,7 +47,7 @@ | ID | 任务 | 依赖 | 验收要点 | 状态 | | --- | --- | --- | --- | --- | -| T-201 | `excel.py` 导入:解析多文件输入列入库 | T-003 | 按模板解析账号名/别名/商品id;记录 source_file_abs/source_sheet/source_row/row_key;缺必需列则拒绝整文件并记 file_errors;脏行逐行跳过计 invalid;写 batches/tasks | TODO | +| T-201 | `app/excel.py` 导入:解析多文件输入列入库 | T-003 | 按模板解析账号名/别名/商品id;记录 source_file_abs/source_sheet/source_row/row_key;缺必需列则拒绝整文件并记 file_errors;脏行逐行跳过计 invalid;写 batches/tasks | TODO | | T-202 | Tab① 任务列表 + 导入按钮 + 别名匹配标记 | T-201, T-105 | `QTableView` 显示账号/别名/商品id/阶段;未匹配标“略过” | TODO | | T-202b | Tab① 导入汇总栏 | T-202 | 导入后显示 文件数/解析行数/有效/无效/匹配(按账号)/未匹配;未匹配可点击筛出 | TODO | | T-203 | 采集旧标题+旧封面(只读),下载图片,立即写库 | T-202, T-001, T-104b | 通过 worker 执行;逐条 set_collected;旧封面下载到 `images//`;未登录/未匹配略过记原因 | TODO | @@ -57,9 +58,9 @@ | ID | 任务 | 依赖 | 验收要点 | 状态 | | --- | --- | --- | --- | --- | -| T-301 | 确定 AI 服务商/模型并接入 `ai.py`(`gen_title`/`gen_cover`,带重试/分辨率/jpg质量) | T-005 | 从 `config/ai_models.json` 读取模型与本地明文 Key;`gen_cover` 支持 resolution+jpg_quality;失败按 retry 重试;错误明确;日志脱敏 | TODO | +| T-301 | 确定 AI 服务商/模型并接入 `app/ai.py`(`gen_title`/`gen_cover`,带重试/分辨率/jpg质量) | T-005 | 从 `config/ai_models.json` 读取模型与本地明文 Key;`gen_cover` 支持 resolution+jpg_quality;失败按 retry 重试;错误明确;日志脱敏 | TODO | | T-302 | Tab② 左右布局:左提示词(标题/封面),右按批次/店铺/状态筛选 + 任务列表 | T-301, T-203 | 左 ~1/4 提示词多行;右筛选+列表(店铺/商品id/旧标题/新标题/状态) | TODO | -| T-302p | `prompts.py` + Tab② 提示词管理 | T-302 | 标题保存/启动回显 title_prompt.txt;封面多模板(下拉+新建/保存/另存为/重命名/删除,存 prompts/cover/);插入 `{新标题}`;预览变量替换;render_prompt 接入生成 | TODO | +| T-302p | `app/prompts.py` + Tab② 提示词管理 | T-302 | 标题保存/启动回显 title_prompt.txt;封面多模板(下拉+新建/保存/另存为/重命名/删除,存 prompts/cover/);插入 `{新标题}`;预览变量替换;render_prompt 接入生成 | TODO | | T-303 | Tab② 开始生成(单按钮)+ 停止 + 进度:**先并发标题再并发图片** | T-302, T-104b | `generate_batch` 先 title_concurrency 并发标题、再 image_concurrency 并发图片;worker/signal 回传进度;每条 set_generated 立即写库;停止可取消未开始项;进度 标题/封面/失败 计数;双击弹窗看新旧封面 | TODO | ## Phase 4 · 更新 shopee(③) diff --git a/docs/api.md b/docs/api.md index 6395ad3..8a2bb44 100644 --- a/docs/api.md +++ b/docs/api.md @@ -9,7 +9,7 @@ - 凭证:登录态在 user-data-dir;密码、AI Key 本地明文存于 config/DB;`config.json`、`config/ai_models.json`、`cmshopee.db`、`chrome_user_data_dir/`、`images/` 必须 gitignore;UI 打码显示,不出现在日志/导出。 - 失败处理:抛带中文说明的异常或返回状态字段;GUI 负责提示,不静默吞错。 -## appconfig 模块(`appconfig.py`,待建) +## appconfig 模块(`app/appconfig.py`,待建) 读写 `config.json`(schema 见 [架构 5.1](04-architecture.md))。 @@ -33,7 +33,7 @@ test_ai_model(name) -> dict # 「测试连接」:用 key/url get_model(name) -> dict # 返回模型定义,含 api_key(调用方不得写日志) ``` -## db 模块(`db.py`,待建) +## db 模块(`app/db.py`,待建) SQLite 读写,表见 [架构 5.2](04-architecture.md)。 @@ -69,7 +69,7 @@ SQLite 连接规则: - `connect()` 必须设置 `PRAGMA foreign_keys=ON`、`journal_mode=WAL`、`busy_timeout=5000`、`synchronous=NORMAL`。 - DB 写入短事务、单条提交;Excel 回写失败不回滚 DB。 -## excel 模块(`excel.py`,待建,依赖 openpyxl) +## excel 模块(`app/excel.py`,待建,依赖 openpyxl) ```python import_tasks(file_paths: list[str]) -> dict @@ -91,14 +91,14 @@ export_copy(batch_id, out_dir_or_path) -> dict # 退路:另存新结果 列模板见 [架构 5.3](04-architecture.md);别名以“别名”列为权威。 -## config 模块(`config.py`,待建) +## config 模块(`app/config.py`,待建) ```python make_slug(alias) -> str # 别名→唯一 slug [a-z0-9_] ensure_user_data_dir(slug) -> str # chrome_user_data_dir/ 绝对路径,按需创建 ``` -## chrome 模块(`chrome.py`,待建) +## chrome 模块(`app/chrome.py`,待建) ```python build_launch_args(account) -> list[str] # chrome + --remote-debugging-port + --remote-allow-origins=* + --user-data-dir @@ -108,7 +108,7 @@ is_running(port) -> bool create_shortcut(account, dest_dir=None) -> str # 可选 .lnk,PowerShell WScript.Shell ``` -## cdp 模块(`cdp.py`,已实现) +## cdp 模块(`app/cdp.py`,T-000 由根目录 `cdp.py` 迁入) ```python CDP_HOST: str @@ -116,7 +116,7 @@ http_get(path); find_product_tab(item_id); create_tab(url) class CDP: send/ev/val/object_id/drag/close # suppress_origin、trust_env=False ``` -## editor 模块(`editor.py`,待建,重构自现有脚本) +## editor 模块(`app/editor.py`,待建,重构自现有脚本) ```python is_logged_in(account) -> bool # 重定向登录页或缺 SPC_ST → False @@ -136,7 +136,7 @@ apply_task(account, task) -> dict # 对已生成任务:换标题+ # -> {committed, error} ``` -## ai 模块(`ai.py`,待建,外部 AI,服务商待定) +## ai 模块(`app/ai.py`,待建,外部 AI,服务商待定) ```python gen_title(title_prompt, old_title, retry=2) -> str @@ -160,7 +160,7 @@ generate_batch(tasks, prompts, ai_cfg, on_progress, should_stop) -> None - 调用有成本与失败可能:超时、限流、内容安全拒绝都要返回明确错误。 - 生成结果**直接进入 ③ 更新候选**;③ 点击「开始更新」后弹窗批量确认,确认后提交线上。本地留档 + 回写 Excel 供追溯。 -## prompts 模块(`prompts.py`,待建) +## prompts 模块(`app/prompts.py`,待建) ```python # 标题提示词:单文件 @@ -185,7 +185,7 @@ render_prompt(template_text, task) -> str - 生成封面时 `gen_cover` 的 prompt = `render_prompt(当前封面模板, task)`。 - 模板与 `title_prompt.txt` 均为可手改的纯文本文件。 -## gui / workers 模块(`gui.py` / `workers.py`,待建,PySide6) +## gui / workers 模块(`app/gui.py` / `app/workers.py`,待建,PySide6) ```python # GUI 入口 @@ -212,6 +212,22 @@ run_worker(worker: BaseWorker) -> QThread # 绑定 signals、启动、收尾 d - 每个 worker/线程按需创建自己的 SQLite connection,不跨线程共享连接。 - ③ 的批量确认弹窗在 GUI 主线程完成;用户确认后才创建 `ApplyWorker`。 +## 启动入口 + +```python +# main.py +from app.gui import main + +raise SystemExit(main()) + +# app/__main__.py +from .gui import main + +raise SystemExit(main()) +``` + +正式运行入口:`python main.py`;开发/包入口:`python -m app`。 + ## CLI / 触发合约(现有脚本,过渡期保留) ```bash diff --git a/docs/current-state.md b/docs/current-state.md index ac4d6f5..87292d0 100644 --- a/docs/current-state.md +++ b/docs/current-state.md @@ -8,7 +8,7 @@ - 日期:2026-06-26 - 阶段:V0 单账号 CDP 流程已验证;V1 多账号管理 + 5 Tab GUI + Excel/AI 流水线为既定设计,尚未开始编码。 - 技术栈:Python 3.10+,自研 CDP(websocket-client + requests),SQLite(sqlite3)+ `config.json` + openpyxl + AI(服务商待定),GUI PySide6 5 Tab(已定)。 -- 生产代码:尚无 `appconfig/db/excel/config/chrome/editor/gui/workers`;现有为验证脚本 + `cdp.py`。 +- 生产代码:正式目标为 `app/` 包 + 根入口 `main.py`,尚未创建;现有根目录 `cdp.py` 是已验证 CDP 底座,待 T-000 迁入 `app/cdp.py`。 - 测试:当前以 `py_compile` + 在测试商品上手动跑 `prototypes/demo.py` 为主;`tests/` 与 `python -m unittest discover -s tests` 由 T-006 建立,T-006 完成前不把缺少 `tests/` 视为验证失败。 - 数据:无 `config.json`、`config/ai_models.json`、`cmshopee.db`、`chrome_user_data_dir/`、`images/`(待 Phase 0/1 建立,均须 gitignore)。 @@ -28,10 +28,11 @@ | 路径 | 状态 | 说明 | | --- | --- | --- | | `docs/` | 已有 | 本 harness coding 文档集合 | -| `cdp.py` | 已有 | CDP 底座:连接/找 tab/开 tab/执行 JS/拖拽(正式模块,留根目录) | -| `prototypes/` | 已有 | 已验证原型/探查脚本(demo/set_title/set_cover/get_title/cookies/inspect_images/grab/1.py),逻辑待并入 `editor.py` 后清理;见 `prototypes/README.md` | +| `cdp.py` | 已有 | 已验证 CDP 底座来源;T-000 迁入 `app/cdp.py` 后根目录不再放正式业务模块 | +| `prototypes/` | 已有 | 已验证原型/探查脚本(demo/set_title/set_cover/get_title/cookies/inspect_images/grab/1.py),逻辑待并入 `app/editor.py` 后清理;见 `prototypes/README.md` | | `chrome-remote-debug-lan.md` | 已有 | WSL→Windows CDP 转发排查记录 | -| `appconfig.py` / `db.py` / `excel.py` / `config.py` / `chrome.py` / `editor.py` / `gui.py` / `workers.py` | 待建 | Phase 0-3 产出 | +| `app/` / `main.py` | 待建 | 正式代码包与启动入口;T-000 产出 | +| `app/appconfig.py` / `app/db.py` / `app/excel.py` / `app/config.py` / `app/chrome.py` / `app/editor.py` / `app/gui.py` / `app/workers.py` | 待建 | Phase 0-3 产出 | | `config.json` / `config/ai_models.json` / `cmshopee.db` / `chrome_user_data_dir/` / `images/` | 待建 | 含配置、密钥、业务、登录态、图片,须 gitignore | ## 已验证能力(单账号) @@ -48,19 +49,19 @@ - 已完成:无(任务均为 TODO;单账号能力以脚本形式存在,待 T-001 模块化)。 - 正在进行:无。 -- 下一个可领取任务:**T-001(`editor.py`:改标题/换封面/点更新/登录检测/采集/apply_task)**。虽然 T-002/T-003 也无依赖,但任务领取规则固定为“取 `06-tasks.md` 中第一个 TODO 且依赖均 DONE 的任务”,因此当前不能任选。 +- 下一个可领取任务:**T-000(正式代码包结构)**。先创建 `app/`、迁入 `cdp.py`、新增 `main.py`/`app/__main__.py`,再开始 T-001/T-002/T-003。 ## 当前可运行内容 ```bash -# 语法检查 -python -m py_compile *.py +# 语法检查(T-000 后) +python -m compileall app main.py # 单元测试(T-006 完成且 tests/ 存在后) python -m unittest discover -s tests # 单账号闭环(不提交线上) -python prototypes/demo.py # 分步(需根目录 cdp.py 可导入) +python prototypes/demo.py # 分步(T-000 后从项目根导入 app.cdp) set AUTO=1 && python prototypes/demo.py # 自动(cmd) # 真实提交(谨慎) diff --git a/progress.md b/progress.md index 95fc434..b63bbb6 100644 --- a/progress.md +++ b/progress.md @@ -213,4 +213,15 @@ - Excel 导入容错定稿:必需列缺失(别名/商品id)时拒绝整个文件;单行缺值或商品id格式错误等脏数据逐行跳过,计入 invalid,不阻塞同文件其他有效行。 - 下一步:按任务看板领取 T-001。 +## 【2026-06-26】决策 · 正式代码迁入 app 包 + +- 状态:DONE(仅文档) +- 变更:更新 `AGENTS.md`、`docs/00-ai-start-here.md`、`docs/03-tech-stack.md`、`docs/04-architecture.md`、`docs/05-coding-rules.md`、`docs/06-tasks.md`、`docs/current-state.md`、`docs/api.md`、`prototypes/README.md`。 +- 决策: + - 正式代码统一放入 `app/` 包,根目录只保留 `main.py`、配置/数据目录、文档和原型目录。 + - `cdp.py` 由根目录迁入 `app/cdp.py`;包内模块优先使用相对导入,根入口使用 `from app.gui import main`。 + - 新增 T-000 作为首个任务:创建 `app/`、迁移 CDP、补 `app/__main__.py` 和 `main.py`,并修正 `prototypes/demo.py` 导入。 + - 正式启动入口为 `python main.py`,开发/包入口为 `python -m app`。 +- 下一步:按任务看板领取 T-000。 + diff --git a/prototypes/README.md b/prototypes/README.md index a29fcc4..041ee46 100644 --- a/prototypes/README.md +++ b/prototypes/README.md @@ -1,25 +1,24 @@ # prototypes —— 已验证原型 / 探查脚本 -这些是单账号阶段写的**已验证脚本**,逻辑与关键事实将被正式模块(尤其 `editor.py`,见任务 T-001)移植。 -**待 `editor.py` 完成并实测通过后,本目录可清理删除。** 在此之前保留它们作为"唯一已验证参照"。 +这些是单账号阶段写的**已验证脚本**,逻辑与关键事实将被正式模块(尤其 `app/editor.py`,见任务 T-001)移植。 +**待 `app/editor.py` 完成并实测通过后,本目录可清理删除。** 在此之前保留它们作为"唯一已验证参照"。 ## 文件 | 文件 | 用途 | 移植去向 | | --- | --- | --- | -| `demo.py` | 单账号端到端:改标题 + 换封面(UPDATE=1 提交) | `editor.py` 编排 | +| `demo.py` | 单账号端到端:改标题 + 换封面(UPDATE=1 提交) | `app/editor.py` 编排 | | `set_title.py` | 改标题(原生 setter + 事件,value/modelvalue 验证) | `editor.change_title` | | `set_cover.py` | 上传图片 + 拖到第一位设封面(含选择器、拖拽落点) | `editor.replace_cover` | | `get_title.py` | 找/开商品 tab 并读取标题 | `editor.open_product` / `read_title` | | `cookies.py` | 读 shopee.tw 标签页 Cookie/会话 | `editor.is_logged_in` 的依据 | | `inspect_images.py` | 只读探查图片管理器 DOM(**Shopee 改版时重新探查可复用**) | 工具,保留参考 | | `grab.py` | 抓商品页 HTML + 列表接口 JSON(早期探查) | 参考 | -| `1.py` | OpenAI SDK 最小调用测试 | `ai.py` 调用方式参考 | +| `1.py` | OpenAI SDK 最小调用测试 | `app/ai.py` 调用方式参考 | ## 运行注意 -- **`cdp.py` 在项目根目录**(正式模块),不在本目录。 -- 仅 `demo.py` `import cdp`;其余脚本各自内置了 CDP 类,可独立运行。 - - 跑 `demo.py` 需让根目录的 `cdp.py` 可被导入(从项目根运行,或设 `PYTHONPATH=项目根`)。 +- T-000 后正式 CDP 底座在 `app/cdp.py`;`demo.py` 从项目根运行并导入 `app.cdp`。 +- 其余脚本各自内置了 CDP 类,可独立运行。 - 这些脚本默认连开发期的 WSL 转发地址 `192.168.0.224:9333`;正式模块用 `127.0.0.1:9222`(可用 `CDP_HOST` 覆盖)。 - 已验证的关键事实(选择器、SPA 就绪判断、上传/拖拽方式)权威记录见 [`../docs/04-architecture.md`](../docs/04-architecture.md) 第七节。