diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..006f7b6 --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,2 @@ +"""cmshopee official application package.""" + diff --git a/app/__main__.py b/app/__main__.py new file mode 100644 index 0000000..49bb939 --- /dev/null +++ b/app/__main__.py @@ -0,0 +1,8 @@ +"""Package entry point for `python -m app`.""" + +from .gui import main + + +if __name__ == "__main__": + raise SystemExit(main()) + diff --git a/cdp.py b/app/cdp.py similarity index 94% rename from cdp.py rename to app/cdp.py index 81a6688..06b436e 100644 --- a/cdp.py +++ b/app/cdp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# cdp.py —— 共享 CDP 底座:连接 Chrome、定位/打开商品 tab、执行 JS、模拟拖拽。 -# 被 demo.py 及各能力脚本复用。 +# app/cdp.py —— 共享 CDP 底座:连接 Chrome、定位/打开商品 tab、执行 JS、模拟拖拽。 +# 被正式模块和 prototypes/demo.py 复用。 # # 依赖:pip install websocket-client requests @@ -14,14 +14,13 @@ import json import time import threading -import requests -from websocket import create_connection - -CDP_HOST = os.environ.get("CDP_HOST", "192.168.0.224:9333") +CDP_HOST = os.environ.get("CDP_HOST", "127.0.0.1:9222") BASE = f"http://{CDP_HOST}" def http_get(path): + import requests + s = requests.Session() s.trust_env = False # 忽略环境代理 return s.get(f"{BASE}{path}", timeout=10).json() @@ -31,6 +30,8 @@ class CDP: """单个 target 的 CDP 客户端:命令同步、事件回调异步。""" def __init__(self, ws_url): + from websocket import create_connection + # suppress_origin=True:不发 Origin 头,避免 Chrome 未开 --remote-allow-origins 时 403。 self.ws = create_connection(ws_url, max_size=None, suppress_origin=True) self._id = 0 diff --git a/app/gui.py b/app/gui.py new file mode 100644 index 0000000..b2a8cbf --- /dev/null +++ b/app/gui.py @@ -0,0 +1,10 @@ +"""GUI entry point placeholder. + +The real PySide6 main window is implemented by task T-104. +""" + + +def main() -> int: + print("cmshopee GUI 尚未实现:请继续执行 T-104 构建 PySide6 主窗口。") + return 0 + diff --git a/demo.bat b/demo.bat index fbe6834..12fd3c7 100644 --- a/demo.bat +++ b/demo.bat @@ -1,6 +1,5 @@ @echo off -rem 单账号原型演示:脚本已移到 prototypes/,设 PYTHONPATH 让根目录 cdp.py 可导入 +rem 单账号原型演示:脚本在 prototypes/,demo.py 从项目根导入 app.cdp cd /d %~dp0 -set PYTHONPATH=%~dp0 python prototypes\demo.py pause diff --git a/docs/06-tasks.md b/docs/06-tasks.md index bd73371..dc14672 100644 --- a/docs/06-tasks.md +++ b/docs/06-tasks.md @@ -23,7 +23,7 @@ | ID | 任务 | 依赖 | 验收要点 | 状态 | | --- | --- | --- | --- | --- | -| 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-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` 可进入入口(本机 `python` 不符合版本时用 `py -3 -m app`);GUI 未完成时给明确提示并退出;`prototypes/demo.py` 可从项目根导入 `app.cdp` | DONE | | 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 | diff --git a/docs/current-state.md b/docs/current-state.md index 87292d0..a5d45a2 100644 --- a/docs/current-state.md +++ b/docs/current-state.md @@ -6,9 +6,9 @@ ## 当前快照 - 日期:2026-06-26 -- 阶段:V0 单账号 CDP 流程已验证;V1 多账号管理 + 5 Tab GUI + Excel/AI 流水线为既定设计,尚未开始编码。 +- 阶段:V0 单账号 CDP 流程已验证;V1 已完成 T-000 正式代码包结构,下一步开始模块化 editor/config/DB。 - 技术栈:Python 3.10+,自研 CDP(websocket-client + requests),SQLite(sqlite3)+ `config.json` + openpyxl + AI(服务商待定),GUI PySide6 5 Tab(已定)。 -- 生产代码:正式目标为 `app/` 包 + 根入口 `main.py`,尚未创建;现有根目录 `cdp.py` 是已验证 CDP 底座,待 T-000 迁入 `app/cdp.py`。 +- 生产代码:已建立 `app/` 包 + 根入口 `main.py`;`app/cdp.py` 为已验证 CDP 底座;`app/gui.py` 目前是入口占位,完整 PySide6 主窗口待 T-104。 - 测试:当前以 `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,11 +28,12 @@ | 路径 | 状态 | 说明 | | --- | --- | --- | | `docs/` | 已有 | 本 harness coding 文档集合 | -| `cdp.py` | 已有 | 已验证 CDP 底座来源;T-000 迁入 `app/cdp.py` 后根目录不再放正式业务模块 | +| `app/cdp.py` | 已有 | CDP 底座:连接/找 tab/开 tab/执行 JS/拖拽 | | `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 转发排查记录 | -| `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 产出 | +| `app/__init__.py` / `app/__main__.py` / `main.py` | 已有 | 正式包与启动入口;`python main.py` / `python -m app` 可运行占位入口 | +| `app/gui.py` | 已有 | GUI 占位入口;完整 PySide6 主窗口待 T-104 | +| `app/appconfig.py` / `app/db.py` / `app/excel.py` / `app/config.py` / `app/chrome.py` / `app/editor.py` / `app/workers.py` | 待建 | Phase 0-3 产出 | | `config.json` / `config/ai_models.json` / `cmshopee.db` / `chrome_user_data_dir/` / `images/` | 待建 | 含配置、密钥、业务、登录态、图片,须 gitignore | ## 已验证能力(单账号) @@ -47,15 +48,19 @@ 任务状态以 [`06-tasks.md`](06-tasks.md) 为准,历史记录见 [`../progress.md`](../progress.md)。 -- 已完成:无(任务均为 TODO;单账号能力以脚本形式存在,待 T-001 模块化)。 +- 已完成:T-000(正式代码包结构);单账号能力以脚本形式存在,待 T-001 模块化。 - 正在进行:无。 -- 下一个可领取任务:**T-000(正式代码包结构)**。先创建 `app/`、迁入 `cdp.py`、新增 `main.py`/`app/__main__.py`,再开始 T-001/T-002/T-003。 +- 下一个可领取任务:**T-001(`app/editor.py`:改标题/换封面/点更新/登录检测/采集/apply_task)**。虽然 T-002/T-003 也依赖满足,但任务领取规则固定为“取 `06-tasks.md` 中第一个 TODO 且依赖均 DONE 的任务”,因此当前不能任选。 ## 当前可运行内容 ```bash -# 语法检查(T-000 后) -python -m compileall app main.py +# 语法检查(T-000 后;本机优先用 py -3) +py -3 -m compileall app main.py + +# 当前入口占位 +python main.py +py -3 -m app # 单元测试(T-006 完成且 tests/ 存在后) python -m unittest discover -s tests @@ -74,6 +79,7 @@ set UPDATE=1 && python prototypes/demo.py - 已 `pip install websocket-client requests`。 - PySide6 当前环境已可导入(验证版本 6.5.3);GUI 实现固定使用 PySide6。 - 默认连 `127.0.0.1:9222`(开发期可用 `CDP_HOST` 指向 WSL 转发的 `192.168.0.224:9333`)。 +- 本机 `python` 当前指向 `C:\Python37\python.exe`(3.7.9,isolated,不符合 Python 3.10+ 要求且 `python -m app` 不搜索当前目录);开发/验证优先用 `py -3`(当前 3.14.4)或确认 `python` 已指向 3.10+。 ## 开始编码前检查 diff --git a/main.py b/main.py new file mode 100644 index 0000000..5640182 --- /dev/null +++ b/main.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +"""cmshopee application entry point.""" + +import os +import sys + + +PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) +if PROJECT_ROOT not in sys.path: + sys.path.insert(0, PROJECT_ROOT) + +from app.gui import main + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/progress.md b/progress.md index b63bbb6..b695d2a 100644 --- a/progress.md +++ b/progress.md @@ -224,4 +224,13 @@ - 正式启动入口为 `python main.py`,开发/包入口为 `python -m app`。 - 下一步:按任务看板领取 T-000。 +## 【2026-06-26】T-000 正式代码包结构 + +- 状态:DONE +- 变更:创建 `app/` 包;将根目录 `cdp.py` 迁入 `app/cdp.py`;新增 `app/__init__.py`、`app/__main__.py`、`app/gui.py` 占位入口、根目录 `main.py`;修改 `prototypes/demo.py` 改为从项目根导入 `app.cdp`;同步 `docs/06-tasks.md` 与 `docs/current-state.md`。 +- 验证:`py -3 -m compileall app main.py` 通过;`python main.py` 输出 GUI 未实现提示并退出;`py -3 main.py` 输出同样提示并退出;`py -3 -m app` 输出同样提示并退出;`py -3 -c "import prototypes.demo"` 通过。 +- 决策:`app/gui.py` 只保留最小入口占位,不提前实现 PySide6 主窗口,完整 GUI 留给 T-104;`app/cdp.py` 对 `requests` / `websocket-client` 改为按需导入,使包导入不依赖外部库,真正连接 CDP 时仍要求安装依赖。 +- 注意:本机 `python` 指向 Python 3.7.9 isolated,不符合项目 Python 3.10+ 要求,且 `python -m app` 不搜索当前目录;本轮用 `py -3`(Python 3.14.4)完成包入口验证。 +- 下一步:按任务看板领取 T-001。 + diff --git a/prototypes/demo.py b/prototypes/demo.py index b9929f1..6014925 100644 --- a/prototypes/demo.py +++ b/prototypes/demo.py @@ -14,9 +14,11 @@ import sys import json import time -# 确保能 import 同目录的 cdp.py(某些 Windows Python 启动方式不会自动把脚本目录加进 sys.path) -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) -from cdp import CDP, http_get, find_product_tab, create_tab +# 确保从项目根运行时能导入正式 CDP 包。 +PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +if PROJECT_ROOT not in sys.path: + sys.path.insert(0, PROJECT_ROOT) +from app.cdp import CDP, http_get, find_product_tab, create_tab ITEM_ID = os.environ.get("ITEM_ID", "51100639510") IMG_WIN = os.environ.get("IMG_WIN", r"D:\chengma\cmshopee\1_TY030.jpg")