Przeglądaj źródła

docs(architecture): 添加智惠映项目架构分析与技术选型评估文档

- 分析了 Electron + Vue3 + Python 三层架构现状及各层职责
- 评估了打包体积构成(150M+ 来源:Electron 运行时 90M + Python 冻结包 95M + 前端 15M)
- 评估了 Python 依赖瘦身可行性(cv2/108M、numpy/46M、pandas/22M 等可优化)
- 分析了 44 处 while True 长连接均有退出机制,无裸奔循环
- 评估了 Python 图像处理 DLL 化技术路径(嵌入 CPython/薄 C ABI/纯 C++ 重写/WASM)
- 评估了 Golang + Wails2 迁移可行性及前端改造方案
- 制定了三阶段演进路线:Python 依赖瘦身 → Electron 替换为 Wails2 → 核心组件 DLL 化
- 提供了硬件通信库在 Go 侧的技术选型对比表
- 记录了特殊问题清单及解决方案(本地文件访问、Fabric.js 渲染等)
rambo 1 miesiąc temu
rodzic
commit
b0636a455e
1 zmienionych plików z 453 dodań i 0 usunięć
  1. 453 0
      架构分析与技术选型评估.md

+ 453 - 0
架构分析与技术选型评估.md

@@ -0,0 +1,453 @@
+# 智惠映(CameraMachine)架构分析与技术选型评估
+
+> 评估对象:Electron + Vue3 + Python 三层架构的 AI 自动拍照机桌面端
+> 评估目标:打包体积治理、Python 图像处理 DLL 化可行性、Golang + Wails2 迁移可行性
+> 日期:2026-09-18
+
+---
+
+## 0. 结论速览(TL;DR)
+
+| 问题 | 结论 |
+|---|---|
+| ① 包体 150M+ 从哪来 | 安装器 132~150M ≈ **Electron 运行时 ~90M(压缩后) + Python 冻结包 ~95M + 前端/Node ~15M**。磁盘展开 490M。**另有 383M 模板/字体资源(detail_temp 260M + ttf 123M)目前未进安装器**——它才是体积的"隐藏大头",谁负责装它谁就背 300M+ |
+| ② Python 占 95M+ | 属实。cx_Freeze 产物 277M(压缩后 ~95M),其中 **cv2 108M、numpy 46M、pillow_avif 23M、pandas 22M** 四者占近一半。pandas/tkinter/networkx/ffmpeg-视频后端等可剔除,可瘦到 ~150M(压缩后 ~55M) |
+| ③ while True 长连接 | 全库 44 处 `while True`,全部有退出标志/超时/断连条件,**无裸奔循环**。Go 迁移后它们变成 goroutine,反而是 Go 最擅长的形态 |
+| ④⑤ cv2/PIL 抠图、阴影、裁切、detail_template | 核心资产。**纯本地计算**(掩码/阴影混合/裁切/测量/合成)与**云端 API**(4 种抠图、AI 场景图、YOLO 左右脚)要分开看;32 个品牌详情页模板(9 客户)是 Python 业务代码,最难搬 |
+| ⑥ Python 做成 DLL | **技术上可行,收益有限**。推荐形态是"最小 DLL"(8~10 个纯图像函数)+ 薄 Python 进程(品牌模板/云 API),不建议整包嵌入解释器;更推荐的近期做法是 **Python 保持独立进程(sidecar)只做瘦身** |
+| ⑦ Golang + Wails2 | **可行,且前端改造量很小**。前端对 Electron 的硬依赖收敛在 `client.ts` 单点(`window.require('electron')`);本地图像问题可用"本地 HTTP 文件路由 + `getFilePath()` 单点转换"解决。主要工作量在 Go 壳重写(~1.5k~2.5k 行,3~5 周) |
+
+**推荐路线(三阶段)**:
+
+```
+阶段一(1~2 周,不动框架):Python 依赖瘦身 + 资源包按需下载 + 去重
+        → 安装器 150M → 约 110M,磁盘 490M → 约 350M(资源另计)
+阶段二(4~8 周):Electron 壳替换为 Wails2/3 (Go 宿主),Python 保持 sidecar
+        → 安装器约 80~90M,前端 Vue3 基本复用
+阶段三(可选,按季度):纯图像核心 DLL 化 / Go 化,Go 接管硬件编排
+        → 单进程化、内存下降、更新链路简化
+```
+
+---
+
+## 1. 现状架构分析
+
+### 1.1 总体架构
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ Vue3 渲染进程(file:// 加载, nodeIntegration=true, 3840x2160 主窗口)      │
+│  · IPC: ipcRenderer.send/on (controller.* 约 30 个通道)                  │
+│  · 直连 http://127.0.0.1:7074 (健康检查, Home/index.vue:64)             │
+│  · 直连 http://localhost:5513 (digiCamControl 预览/拍照)                 │
+│  · 直连 https://dev2.valimart.net (云端: 登录/模板/余额)                 │
+│  · <img src="C:\...\xx.jpg"> 直接以文件路径当 src (webSecurity:false)    │
+└──────────────┬──────────────────────────────┬───────────────────────────┘
+               │ ① Electron IPC               │ ② 直接 HTTP/WS(绕过主进程)
+┌──────────────▼──────────────────────────────┴───────────────────────────┐
+│ Electron 主进程 (electron-egg / ee-core 2.12.0, ~2500 行 JS, 薄壳)       │
+│  · preload/index.js:17 → service/cross.js:92-112 拉起 pyapp.exe         │
+│  · utils/socket.js:69 ws 客户端 → ws://127.0.0.1:7074/ws (消息按        │
+│    msg_type 转发到对应窗口; 预览 base64 落盘 <userData>/preview/)       │
+│  · api/*.js axios → http://127.0.0.1:7074 (REST, timeout 600s)          │
+│  · utils/camera.js:97 spawn 第三方 SmartShooter5.exe / CameraControl.exe │
+│  · controller/ota.js:23-143 OTA(隐藏窗口下载 NSIS → spawn 安装)          │
+│  · addon/: tray / autoUpdater(配置停用) / security / awaken              │
+└──────────────┬──────────────────────────────────────────────────────────┘
+               │ ③ REST + WebSocket (端口 7074)
+┌──────────────▼──────────────────────────────────────────────────────────┐
+│ Python pyapp (cx_Freeze 冻结, FastAPI+uvicorn, 单 worker, ~5.7 万行)     │
+│  · REST: /handle_detail /remove_background /get_photo_records ...       │
+│  · WS /ws: 35+ 种 type 命令分发 (sockets/message_handler.py:191)        │
+│  · MCU 串口(CH340, 0x55 帧协议) / BLE 遥控(ESP32-S3, bleak)            │
+│  · 相机: pyzmq ↔ SmartShooter5.exe (tcp 54543/54544)                    │
+│  · 图像处理: cv2 + PIL + numpy (抠图/阴影/裁切/主图/详情页/测量)          │
+│  · SQLite: C:/Zhihuiyin/database.db (SQLModel/SQLAlchemy)               │
+│  · 插件: custom_plugins/ 32 个品牌详情模板, 云端 md5 热更                │
+└─────────────────────────────────────────────────────────────────────────┘
+外部第三方进程: SmartShooter5.exe / CameraControl.exe(digiCamControl, 5513 端口)
+外部云端: dev2.valimart.net(API 代理)  3api.valimart.net(像素练抠图)
+          imageseg.cn-shanghai.aliyuncs.com(阿里云抠图)  gemini-2.5-flash(AI 图)
+```
+
+**架构特征一句话**:Electron 是纯"壳"(窗口 + 进程管理 + IPC 转发,业务≈0),Python 是"全部业务",前端同时直连 5 个"外部"(IPC、7074、5513、云端、file://)。这个切分对迁移非常有利——**壳很薄,前端耦合收敛在单点**。
+
+### 1.2 Electron 层职责清单(迁移时的对照表)
+
+| 文件 | 职责 | 行数/量级 |
+|---|---|---|
+| `electron/preload/index.js` | 主进程预加载钩子:创建 4 个 addon + **第 17 行启动 Python 进程** | ~30 行 |
+| `electron/service/cross.js:92-112` | `createPythonServer`:spawn `extraResources/py/pyapp.exe --port=7074`,cwd=py 目录,`appExit:true`(Python 死→整应用 1s 后退出,`ee-core/cross/spawnProcess.js:174-182`) | ~120 行 |
+| `electron/utils/socket.js` | ws 客户端连 7074/ws;收消息按 `msg_type` 经 `controller.socket.message_<type>` 转发到指定窗口(typeToMessage 路由表 :11-18);SmartShooter 预览 base64 原子写盘 `<userData>/preview/liveview.png`(:33-53) | 183 行 |
+| `electron/api/request.js` | axios 封装 `http://<pyapp>:7074`,timeout 600s | ~40 行 |
+| `electron/api/camera.js` | 双模式相机控制:digiCamControl 走 `http://localhost:5513/?CMD=...`(:6,:61-148);SmartShooter 走 Python WS 请求-响应(`onSocketMessage` :161-178) | ~150 行 |
+| `electron/api/takephoto.js / generate.js / setting.js` | 纯 REST 转发(/get_photo_records、/create_main_image、/handle_detail、/get_sys_config …) | 各 ~50-100 行 |
+| `electron/api/imageMatting.js` | 定义了 /segment_images 等,**无任何 controller 引用,预留死代码** | - |
+| `electron/controller/*.js` | IPC 入口(ee-core 自动把 class 方法注册为 `controller.<文件>.<方法>` 通道,`ee-core/socket/ipcServer.js:82-107`):camera / socket / takephoto / generate / setting / ota / utils / windows(有 bug 的死代码)/ example(模板) | 35 个 js 文件 |
+| `electron/controller/ota.js:23-143` | 自定义 OTA:隐藏 BrowserWindow `downloadURL` 下载 NSIS 到 %Downloads% → 进度事件 → 三选一(自动安装 = `spawn(exe,{detached:true}) + app.quit()` :128-143) | ~150 行 |
+| `electron/utils/camera.js:97` | `spawn(exePath)` 拉起第三方相机软件;不存在时弹目录选择对话框写配置(:38-82) | ~140 行 |
+| `electron/utils/config.js` | 应用配置读写 `<userData>/config.default.json`(controlType/controlPath/pyapp/env) | ~70 行 |
+| `electron/utils/camera.js` + `controller/utils.js:169-226` | sharp 缩图(`readFileImageForPath` ≤1500px)——**前端通道表里没注册,当前未使用**;且 sharp 声明了但 node_modules/package-lock 里不存在(旧依赖) | - |
+| `electron/server/http.js` | 自建 7072 静态服务器,**start() 被注释,死代码**("暂时未用到,代码暂留") | - |
+| `electron/addon/` | ee-core 纯 JS 插件目录(非 N-API):tray(close→hide 最小化到托盘 :52-58)、autoUpdater(electron-updater 封装,但 `config.default.js:187-197` 平台开关全 false → **完全停用**)、security(检测 --inspect 即退出)、awaken(ee:// 协议,仅打日志)、chromeExtension(当前目录为空) | ~400 行 |
+
+**没有的东西**(排除项,避免误判):
+- Electron 端**没有** ws **server**(ws 8.18.1 是客户端库);7070 socket.io 配置 `enable:false`;
+- **better-sqlite3 未安装**,只有 `re-sqlite` npm 脚本残留;真实数据库在 Python 端 `C:/Zhihuiyin/database.db`(`python/databases.py:15` 硬编码);
+- 前端**没有** `ws` 依赖、**没有** canvas 处理(全库 grep `canvas|toDataURL|createObjectURL|drawImage` 无命中)——所有图像计算都在 Python。
+
+### 1.3 Python 层职责清单(~5.7 万行,15 个目录)
+
+**入口与协议**
+- 入口 `python/index.py`:uvicorn 跑 `api:app`(FastAPI,`middleware.py:16`),端口 7074(`config.ini [app]`),`WindowsSelectorEventLoopPolicy`,SIGINT/SIGTERM 优雅关闭;`asyncio.gather(WS 服务, init_load_source 插件热更)`。
+- REST 路由全部在 `api.py`(2499 行):`/`(健康)、`/scan_serials`、`/forward_request`(云端代理)、**`/handle_detail`(:195,主批处理管线:抠图→AI 图→详情页→上传,`asyncio.create_task` 立即返回,进度走 WS)**、设备配置 CRUD(:1024-1168)、拍照记录(:1169-1421)、系统配置(:1447-1517)、Logo(:1538-1590)、云同步(:1635-1732)、`/remove_background`(:1775)、`/generate_calib`(:2254)/`/measurer_object`(:2276 像素标定+鞋尺寸测量)、`/open_api/*`、`/shoes_compose`。
+- WS 命令分发 `sockets/message_handler.py:191` 按 `type` 字段 match/case 分派 **35+ 种**:connect/init/control/run_mcu、run_mcu_single、take_picture/re_take、deviation 读写、smart_shooter_*、digicam_take_picture、segment_progress、dynamic_config 读写、one_key_down、mcu_power_off、delete_photo_record…
+- 推送模型:全局 `asyncio.Queue message_queue` → `socket_server.py:175` 消费循环广播到 WS 连接。
+
+**图像处理(核心资产,`python/service/`)**
+
+| 功能 | 实现 | 本地/云端 |
+|---|---|---|
+| 抠图-普通(模式1) | `remove_bg_ali.py` 阿里云 `SegmentCommodity`(AK/SK 硬编码 :23-24) | **云** |
+| 抠图-精细化(模式2) | `deal_cutout.py` 两段式:阿里云预抠 + `3api.valimart.net` 像素练 matting;先查余额后扣分 | **云** |
+| 抠图-旗舰/精细(模式3/4) | `remove_bg_ali.py:461` HLM `segment_service`(Bearer token) | **云** |
+| 绿幕掩码 | `get_mask_by_green.py` cv2 HSV `inRange` | 本地 |
+| 阴影生成 | `get_platform_shadow`/`get_ultra_shadow`(云)+ 本地阴影混合 `blend_modes.multiply`(opacity=(avg-30)/160 夹 0.5~1) | 混合 |
+| 单图管线 | `base_deal.py`(1611 行):视角排序(俯视/侧视/后跟/鞋底/内里)、随机重命名、左右脚翻转、逐图抠图→阴影→主图;`run_cutout_image` 带 40s `func_timeout` | 混合 |
+| 基础函数库 | `image_deal_base_func.py`:掩码扩缩(dilate/erode+GaussianBlur)、getbbox 裁切、缩放、锐化 | **纯本地** |
+| 单图指令 | `image_pic_deal.py` `OnePicDeal`:resize/radius/circular/rotate/paste/crop/add_text;**左右脚判定**:YOLO 云 API 或本地 alpha 像素平衡 | 混合 |
+| 主图合成 | `generate_main_image/grenerate_main_image_test.py` `GeneratePic`:裁切→levels_adjust→阴影 multiply→1600 白底居中→logo→350dpi 保存 | **纯本地** |
+| 鞋类主图 | `shoe_main_image_compose.py`:模板+logo+鞋色列+信息条,numpy 中位数探测条带宽度 —— **最适合抽 DLL 的自包含模块** | 纯本地 |
+| 详情页模板 | 系统模板(type0)= 32 个品牌 Python 类(`custom_plugins/plugins/detail_template/{clothing,hongqingting,huilima,miniso,qingyangyizhan,xiaosushuoxie,xinjunlue,xinnuo,zhudi}`,每类 500~1200 行 PIL 排版 + ttf 中文字体),`_build_config_data`(api.py:488-559)按点号路径 `importlib` 动态加载,`load_plugins.py` 递归注册,`init_load_source.py` 云端 md5 热更;自定义模板(type1)= Fabric.js JSON → `http://localhost:3001/generate`(渲染进程内 Node 服务,见 `generateServer.API.md`,**当前分支代码未找到实现,应在 cutomer_template 分支**) | 本地 |
+| 测量 | `measure/objmark_api.py`(506 行):掩码→`minAreaRect`→mm/px 标定 + 长宽高测量 | **纯本地** |
+| 图片保存 | `multi_threaded_image_saving.py` 线程池保存,PNG/JPEG 350dpi,`pillow_avif` 注册 AVIF | 本地 |
+| 货号装箱表 | `generate_goods_art_no_table/` XlsxWriter + Excel 取图(win32com) | 本地 |
+| 云端客户端 | `online_request/module_online_data.py`(884 行):AI 场景图/模特图/上脚图(gemini-2.5-flash-image-preview)、鉴权、商品查询、YOLO、上传、余额/扣分、钉钉告警 | 云 |
+
+**硬件通信(`python/mcu/`)**
+- **MCU 串口**(主硬件:相机升降/倾角电机、转台、翻转、LED、蜂鸣器):`SerialIns.py` pyserial 封装,帧协议 `0x55 0x55 LEN DATA... CHECKSUM`(校验和 `0xFF & ~sum`),自动扫描 CH340;`DeviceControl.py`(2103 行单例)上层控制,**`run_mcu_config`(:1831)拍摄动作执行器**:device_config 列表逐项"移机位→等停(双确认)→拍照→写 PhotoRecord";`ProgramItem.py` 单动作(等停 8s 超时、拍照前双确认)。
+- **蓝牙遥控**: `BlueToothMode.py` bleak 连 "ESP32-S3",同一 0x55 帧协议走 BLE notify,20 字节分片;WS 断开时触发退出。
+- **相机**: 不直连硬件。`capture/smart_shooter_class.py` 与 SmartShooter5.exe 用 **pyzmq** 通信:REQ `tcp://127.0.0.1:54544` 发命令、SUB `tcp://127.0.0.1:54543` 收事件(PhotoUpdated/LiveviewUpdated),recv 循环跑线程池;旧 digiCam 流程用 watchdog 监听输出目录。
+- **扫码**: 键盘 wedge 扫码枪 → `scan_dir` 目录落 txt(`config.ini [scan_config]`)。
+- **MCU 固件升级**: `custom_plugins/plugins/micropython_update/`(MCU 跑 MicroPython,串口刷固件)。
+
+**数据库与配置**
+- SQLite 硬编码 `C:/Zhihuiyin/database.db`(`databases.py:15`),表:DeviceConfig(拍摄程序)/ PhotoRecord / SysConfigs(key-value JSON)/ DeviceConfigTabs;首启种子 `action.json` / `action_tabs.json` / `sys_configs.json`。
+- `config.ini`:端口/mcu 命令码/output 目录/customer_template(3001)/scan 目录。
+
+### 1.4 while True 长连接清单(共 44 处,全部有退出机制)
+
+**常驻循环(13 处)**:WS 收消息(`socket_server.py:116`)、消息队列推送(:175)、ZMQ 相机事件 recv(`smart_shooter_class.py:665`,`stop_listen` 标志)、MCU 50ms tick 主循环(`DeviceControl.py:419`)、旧 MCU 100ms 循环(`Mcu.py:660`)、BLE 连接/notify/扫描(`BlueToothMode.py:146/183/239`)、有线/V2/旧版遥控器主循环(`LineControl.py:283` 等)、抠图等待(`deal_cutout.py:141`)、上传等待(`deal_one_image.py:127/171/363`)、抠图状态轮询(`base_deal.py:730`,外层 40s 超时兜底)。
+
+**有界协议解析循环(~30 处)**:串口帧组装(收满 `len+4` 字节即 break)、运动停止检查(8s/15s 超时)、动态寄存器读写(2~3s 超时)等。
+
+**退出总闸**:`@app.on_event("shutdown")`(`socket_server.py:273`)统一停 SmartShooter/MCU/BT。
+**结论**:长连接管理是规范的,没有死循环隐患;迁 Go 后全部变为 goroutine + context,语义一一对应。
+
+### 1.5 前端功能清单(Vue 3.5 + Vite 6 + Element Plus + Pinia,28 个 .vue)
+
+| 路由 | 页面 | 功能 |
+|---|---|---|
+| `/home` | `Home/index.vue` | 双入口(拍摄并处理 / 仅处理图像);挂载时轮询 7074 健康检查 |
+| `/photography/check` | `check.vue`(446 行) | 相机预览(双模式)、镜头校准、相机参数(camera_height/angle、turntable、led) |
+| `/photography/shot` | `shot.vue`(**1591 行,最大**) | 主拍摄流:货号(蓝牙扫码/手动)、遥控器(左脚/右脚/拍照/LED)、拍摄记录列表、重拍/停止/删除、打开详情生成窗口、高级生成(tk Web) |
+| `/photography/detail` | `detail.vue`(884 行) | 主图+详情页生成:抠图模式、LOGO 增删、云模板选择、EXCEL 资料、生成(进度弹窗) |
+| `/photography/seniorDetail` | `seniorDetail.vue` | 详情高级配置(图片顺序/同款检验/指定页) |
+| `/setting` | `Setting/index.vue`(728 行)+ 组件 | 基础配置(主图尺寸/格式/锐化)、其他设置(产品类型/抠图模式/设备速度)、左右脚程序设置(CRUD) |
+| `/remote_control` | `RemoteControl/index.vue` | 遥控器模拟器 |
+| `/developer` | `Developer/`(4 页) | 设备调频:偏差、MCU 其他配置、RS485 调试 |
+| `/ota` | `OTA/index.vue`(203 行) | 版本列表(OSS version.json)+ 下载/安装 |
+
+**前端通信方式(迁移关键)**:
+- 唯一 Node 触点:`stores/modules/client.ts:3` —— `window.require('electron').ipcRenderer`(全库 grep 仅此一处);
+- WS 全部经 IPC 中转(`stores/modules/socket.ts` → `controller.socket.*`),前端**无 ws 依赖**;
+- 图片读取:`getFilePath()`(`utils/appfun.ts:8-11`,**单点函数,就是原样返回**)→ `<img :src>` 裸 Windows 路径,依赖 `file://` 源 + `webSecurity:false` + Chromium 盘符解析;预览图每 200ms 自增 key 轮询(`check.vue:167-182`);
+- 跨窗口(主/setting/ota/developer/generate/RemoteControl 共 6 类窗口):`localStorage + storage 事件`(`composables/userCheck.ts`、`stores/modules/check.ts`);
+- 外部 Web 窗:`utils/menus/generate.ts:44-80` 新窗加载 `https://tkk.valimart.net/...?token=...`。
+
+---
+
+## 2. 打包体积分析(实测数据)
+
+### 2.1 安装器构成(当前构建,实测)
+
+```
+out/win-unpacked (展开 490M)  →  NSIS 安装器 ZhiHuiYin-win-1.0.0-x64.exe = 132M
+├── Electron 运行时(exe + chromium/ffmpeg/swiftshader/locales)  ≈ 216M  → 压缩后 ~90M
+├── resources/app.asar (Node 后端代码 + public/dist 前端 1.7M + node_modules 生产依赖)
+│                                                        = 24M  → 压缩后 ~8-10M
+└── resources/extraResources (250M,此构建;最新 build/ 为 375M)  → 压缩后 ~95-110M
+    ├── py/          277M   cx_Freeze 冻结包(pyapp.exe + python310.dll + lib/)
+    ├── py-0917-dev.zip  98M  ⚠️ 全仓库无任何代码引用,是 py/ 的 zip 形态重复,白白+30M(压缩后)
+    ├── dll/myDllDemo.dll 12K  (模板残留)
+    └── chromeExtension/  (空)
+```
+
+> 用户所述 "150M+ / Python 占 95M+" 与此吻合:py/ 277M 经 NSIS LZMA 压缩后正好 ≈ 95M。
+
+### 2.2 Python 冻结包 277M 内部(`python/dist/lib`,实测)
+
+| 目录/DLL | 大小 | 用途 | 可否削减 |
+|---|---|---|---|
+| `cv2/` | **108M** | opencv-python 4.11(cv2.pyd ~80M + `opencv_videoio_ffmpeg4110_64.dll` ~28M + data/gapi) | ✅ 代码中**无 `cv2.VideoCapture`/`dnn`/torch/tensorflow**(已 grep),视频后端 ffmpeg DLL 可排除 → 省 ~28M;可换 opencv-headless 再省 GUI 依赖 |
+| `numpy/` | **46M** | 数组计算(cv2/PIL 互转) | ⚠️ 必需,但 numpy 版本可锁 1.25.x 保持 |
+| `pillow_avif/` | **23M** | AVIF 编码(电商图格式) | ⚠️ 改为**懒加载**(仅保存 AVIF 时 import),不缩体积但降启动;若可弃 AVIF 则整包删 |
+| `pandas/` | **22M** | 仅 `api.py`、`service/data.py`、货号表 3 处少量使用 | ✅ 用 openpyxl(已含,1.1M)+numpy 替代 → 省 22M(+连带 networkx 2.2M、pytz 1.9M) |
+| `cryptography/` + `libcrypto-1_1.dll` | 11.8M | HTTPS 签名 | ⚠️ 需保留 |
+| `PIL/` | 5.9M | Pillow | 必需 |
+| `pydantic_core/` + `pydantic/` | 7.3M | FastAPI 依赖 | 若 Python 退化为纯处理库可删 |
+| `sqlalchemy/` + `greenlet/` | 4.2M | ORM | 若 DB 迁 Go 可删 |
+| `tcl86t.dll` + `tk86t.dll` + `library.zip` | ~5.5M | tkinter/解释器 | ✅ 代码未用 tkinter → 排除 |
+| `bleak_winrt/` + `pyzmq/` | 3M | BLE / 相机 | 硬件若留 Python 则保留 |
+| 解释器 + 标准库 pyc + fastapi/uvicorn/aiohttp/websockets | ~50-60M | 运行时 | 进程形态必需;DLL 形态可省 web 栈 |
+
+**Python 瘦身目标:277M → ~150M(压缩后 95M → ~55M)**,手段:pandas/tk/networkx 剔除、ffmpeg 视频后端排除、UPX、cx_Freeze `excludes` 收紧(或换 PyInstaller/Nuitka)。
+
+### 2.3 隐藏大头:383M 资源(`python/resources`,**当前未进安装器**)
+
+| 目录 | 大小 | 用途 |
+|---|---|---|
+| `detail_temp/` | **260M** | 9 客户 × 32 模板的底图/素材(运行时 `os.getcwd()/resources/detail_temp/<客户>/<模板>` 加载) |
+| `ttf/` | **123M** | 中文字体(simhei/simfang/DOUYINSANSBOLD 等,详情页排版用) |
+| 其他 | ~2M | LOGO/icon/init |
+
+**现状矛盾**:运行时必须有它,但打包管线(`setup.py include_files` + `bin.js python_dist` move)**没有把它打进安装器**——说明生产环境靠人工拷贝或另有分发渠道。无论哪种,一旦规范进包,安装器直接 +150M(压缩后)。
+**治理方向**:按客户/品牌**资源包分离 + 首启/按需下载**(云端 md5 机制 `init_load_source.py` 已存在,扩展到资源即可);字体按模板用到的子集分发。
+
+### 2.4 体积治理 Quick Wins(不改框架即可做)
+
+| # | 动作 | 节省(安装器,压缩后) |
+|---|---|---|
+| 1 | 删除 `py-0917-dev.zip`(无代码引用) | ~30M |
+| 2 | Python 剔除 pandas/tk/networkx/pytz,排除 ffmpeg 视频后端 | ~25M |
+| 3 | 资源 383M 移出安装器(按需下载) | 避免未来 +150M |
+| 4 | 删除 dead code(imageMatting.js、windows.js、server/http.js、Qt 时代死代码) | ~2M |
+| 5 | NSIS `compression: "maximum"` / solid 块 | ~5-10M |
+| **合计** | | **150M → ~110M** |
+
+---
+
+## 3. 专题一:Python 图像处理能否做成 DLL?(问题 ⑥)
+
+### 3.1 四种技术路径对比
+
+| 路径 | 原理 | 部署体积 | 性能 | 改造量 | 风险 |
+|---|---|---|---|---|---|
+| **A. 嵌入 CPython**(cgo 调 `python310.dll` C API,或 `python-embed`/`go-python` 类库) | Go 进程内 `Py_Initialize` → import → 调函数 | python310.dll + stdlib + cv2 + PIL + numpy ≈ **150~180M**(比进程少 fastapi/bleak/sqlalchemy 等 20~30M) | 无 IPC 开销;但 **GIL 全局串行**(cv2 多数算子会释放 GIL,批处理尚可) | 中(2~4 周:封装 + GIL/异常/中文路径) | 高:Python 段错误直接拖垮 Go 宿主;DLL+pyc 热替换难;单进程内存 = Go + 全 Python 栈 |
+| **B. pybind11/Cython 薄 C ABI 层** | 现有 Python 函数包一层 `int process(const char* in_json, const char* out_json)`,编译 `imgproc.dll`,Go 用 `syscall.LoadDLL` 直接调(无需 cgo) | 同 A | 同 A + 一次 JSON 序列化 | **低-中(2~3 周,最小 DLL 8~10 个函数)** | 同 A,但接口面窄、边界清晰,可控性最好 |
+| **C. 纯 C++/OpenCV 重写** | 核心算法用 OpenCV C++ + FreeType/HarfBuzz(中文排版)重写,导出 C ABI | `opencv_world.dll` 30~60M,**无 Python** | 最快,无 GIL | **高(2~3 个月)**:核心函数 ~2000 行可搬,但 **32 个品牌模板(~3.5 万行 PIL 排版 + 中文字体 + 业务规则)搬不动**,最终是"C++ 做 CV + Python 做模板"双栈,复杂度反升 | 中:长期维护双实现 |
+| **D. WASM**(C++→emscripten,或 Pyodide) | Go 用 wazero 跑 wasm 图像核心 | wasm 20~60M,无 native 依赖 | 慢 2~4 倍(内存拷贝) | 高(1~2 个月验证 + 迁移) | 中:字体处理、调试工具链弱 |
+
+### 3.2 本项目里"什么能进 DLL、什么必须留进程"
+
+**✅ 适合进 DLL(纯本地、无 IO、无 DB、无 WS,合计 ~2000 行)**
+- `image_deal_base_func.py`(掩码扩缩/裁切/缩放/锐化)
+- `get_mask_by_green.py`(绿幕掩码)
+- 阴影掩码 + levels + multiply 合成(`grenerate_main_image_test.py` 核心段)
+- `shoe_main_image_compose.py`(自包含,最优先)
+- `measure/objmark_api.py`(标定 + 测量)
+- `OnePicDeal` 本地图像指令(翻转/旋转/加字/贴 logo)
+
+**❌ 不适合进 DLL(必须留 Python 进程,或留在宿主)**
+- **32 个品牌详情模板插件**:importlib 动态加载 + 云端热更 + ttf 中文字体 + 每客户业务规则 → DLL 化等于重写模板引擎;
+- **4 种云端抠图 + AI 场景图 + YOLO 判定**:本质是 HTTP 调用,放 Go 侧直接发请求更干净(需移植 AK/SK、token、余额/扣分顺序、钉钉告警);
+- **硬件编排**(串口 0x55 帧 / BLE / ZMQ / 拍摄序列 / 进度推送):属于设备控制域;
+- **asyncio 风格进度推送**(`message_queue` + WS):DLL 内需改为同步函数 + 回调/channel。
+
+### 3.3 结论
+
+> **可以做,但"整包 Python → DLL"收益不抵成本。**
+>
+> 1. 本项目 Python↔Electron 之间本来就是 HTTP/WS,IPC 开销相对"云 API 延迟 + 磁盘 IO + CPU 处理时间"可忽略——**DLL 省的不是通信,是架构整洁度**;
+> 2. DLL 省下的体积只有 20~30M(web 栈/硬件库),而 cv2+numpy+PIL(~150M)必须跟 DLL 一起走;
+> 3. **进程隔离在这个项目里是优点不是缺点**:相机硬件 + 长连接 + 第三方进程(SmartShooter5.exe)随时可能异常,Python 子进程崩了不影响壳;嵌入后 segfault 直接带走整个应用;
+> 4. 推荐的 DLL 形态 = **B 路径"最小 DLL"**:纯图像 8~10 个函数给 Go 同步调用;品牌模板 + 云 API 保留在一个"薄 Python 进程"(去掉 web 栈后可压到 ~60M);硬件编排由 Go 接管。这是阶段三的事,不是必选项。
+
+---
+
+## 4. 专题二:Golang + Wails2 迁移评估(问题 ⑦)
+
+### 4.1 为什么这个项目适合 Wails
+
+- **Electron 层是薄壳**(~2500 行 JS,几乎全是转发),用 Go 重写是"1:1 替换"而非"架构改造";
+- **前端对 Electron 的硬依赖只有 1 处**(`client.ts:3` `window.require('electron')`),其余全是标准 Web API(axios/WebSocket/文件路径 img)——Vue3 前端可整体复用;
+- **项目里已有 Go 的构建位**(`bin.js` go build/goapp.exe、`builder.json` 排除 `!go/`),团队对 Go 栈不陌生;
+- Wails2 = Go 后端 + WebView2(Windows 11 预装),前端仍是浏览器环境,Element Plus 表现与 Electron(同为 Chromium)一致。
+
+### 4.2 前端改造量(小,但有一个必须改的语义点)
+
+| 改动点 | 现状 | Wails 下 | 量级 |
+|---|---|---|---|
+| IPC 桥 | `client.ts` `window.require('electron').ipcRenderer` | **shim 方案**:保留 `ipc.send/on/removeAllListeners` 接口,内部换成 wailsjs 绑定(`window.go.*`)+ `wails.EventsOn` 模拟 `on` → `ipc.ts` 通道表、20 个视图文件 **近零改动**(直接改法则 ~20 文件机械替换) | 1 个文件 |
+| Socket | IPC 三跳(渲染→主进程→WS) | 前端 WebView **直连** `ws://127.0.0.1:7074/ws`(或 Go 订阅后 EventsEmit)→ `socket.ts` 反而更简单 | 1 个文件 |
+| **本地图像(用户关注点,见 4.3)** | `<img src="C:\...">` 依赖 file:// + webSecurity:false | Go 提供本地文件 URL + `getFilePath()` 单点转换 | 1 个函数 + ~10 处 src 绑定不变 |
+| 跨窗口状态 | localStorage + storage 事件 | Wails v2 多窗同源,机制照旧 | 0 |
+| 外部 Web 窗(tk 高级生成) | `openMain` 新 BrowserWindow | `runtime.WindowCreate`(v2)/v3 多窗 API,或 `runtime.OpenBrowser` | 小 |
+| 其余(云端 API、5513 轮询、hash 路由、Element Plus) | - | 不变 | 0 |
+
+### 4.3 本地图像读取问题(用户提到的 Wails 短板)——解法明确
+
+**问题本质**:Wails 前端跑在本地 HTTP 源下(如 `http://wails.localhost`),不是 `file://`。裸 Windows 路径 `C:\x\y.jpg` 不是合法 URL,Chromium 会当相对路径解析 → 图片全挂。这正是 Electron 现在靠 `webSecurity:false + file://` 才能直读的原因。
+
+**三种解法(推荐 ①,与 ② 可叠加)**:
+
+1. **本地 HTTP 文件路由(推荐)**:Go 宿主(或 Python 7074 服务,加一个 `StaticFiles` 挂载即可——FastAPI 已有 `StaticFiles` 依赖,`middleware.py:6` 已 import)提供 `http://127.0.0.1:<port>/files?p=<绝对路径>`。前端 `getFilePath()` 单点函数把 `file_path` 转成该 URL,**视图层 ~10 处 `:src` 绑定一行不改**。同源/局域网,无 mixed-content 问题(前端源与 7074 都是 http)。
+2. **Wails 自定义 asset handler**:`wails.Options.Assets` 支持自定义 `http.Handler`,把 `/local/*` 映射到磁盘。优点是不开端口;缺点是路径映射、缓存失效要自己管。
+3. **base64 dataURL**:小图可用(主图预览),10M+ 拍摄原图不建议走这条路。
+
+**实时预览(liveview)同理**:现状是"WS 推 base64 → 主进程写 `liveview.png` → 前端 200ms 轮询路径"。Wails 下保持同样链路(把"路径"换成"URL")即可;更优做法是 Python/Go 直接给预览 HTTP 流,前端 `<img :src="streamUrl">` 刷新逻辑不变。
+
+### 4.4 Electron 层职责 → Go 映射表
+
+| Electron 职责 | Go 实现 | 量级 |
+|---|---|---|
+| 主窗口 4K + 5 类副窗口(hash 路由、外部 tk Web 窗) | Wails `CreateWindow` / v3 多窗口;外部 URL 用独立窗或 `OpenBrowser` | 中 |
+| ~30 个 IPC 通道 | 一个 Main struct 的 ~30 个绑定方法,多数是"转发 7074 REST"单行函数 | 中 |
+| WS 客户端 + msg_type 窗口路由(`utils/socket.js` 183 行) | **整层删除**(前端直连)或 Go 订阅 + EventsEmit | 小 |
+| pyapp 启动 + "Python 死→整应用退"(`cross.js:92-112` + `appExit`) | `exec.Command` + `cmd.Wait()` 监控,显式保留退出语义 | 小 |
+| SmartShooter5.exe / CameraControl.exe spawn + 目录探测对话框 | `exec.Command` + `runtime.OpenDirectoryDialog` | 很小 |
+| 文件对话框 / openPath / userData 配置 | Wails dialog API + `os.UserConfigDir` | 很小 |
+| 预览 base64 落盘 | 若 Python 侧直接吐 URL 则消失 | 很小 |
+| OTA(隐藏窗下载 + 进度 + detached spawn NSIS) | Go http 流式下载 + 进度事件 + `exec.Command(installer, {detached}) + os.Exit` | 小 |
+| tray / 协议 / security | systray(或 Wails tray API)/ `runtime.RegisterScheme` | 很小 |
+| **新职责**: 本地文件服务(4.3 解法①) | 一个 http mux,10 行 | 很小 |
+
+**Go 壳总量预估 1.5k~2.5k 行**,开发周期 **3~5 周**(含 OTA、多窗、进程联动、回归)。
+
+### 4.5 硬件通信在 Go 侧的对应库
+
+| 现状(Python) | Go 库 | 说明 |
+|---|---|---|
+| pyserial + 0x55 帧协议 | `github.com/tarm/serial` / `go.billyoncat` | 协议是自定义字节帧,纯移植,需硬件回归 |
+| bleak(BLE, ESP32-S3) | `github.com/labstack/...` → 实际用 `github.com/pixelbender/go-bluetooth` 或 Windows BLE API 封装 | **Go 的 BLE 生态最弱的一环**;建议迁移初期 BLE 留在 Python,后续再移 |
+| pyzmq(SmartShooter 54543/54544) | `github.com/pebbe/zmq4`(需 libzmq.dll)或按 ZMQ 消息格式改 TCP/WS | SmartShooter 协议是 JSON over ZMQ,可谈对方改普通 TCP |
+| win32gui 窗口操作 | `golang.org/x/sys/windows` | 小 |
+| win32com Excel 取图 | `go-ole` + Excel COM 接口 | 中,或用 openpyxl 思路改用 Go 读 xlsx 内嵌图 |
+
+> **务实建议**:阶段二硬件全部留在 Python sidecar(Go 壳只负责"拉起进程 + 透传"),阶段三再逐项搬。硬件是"能跑就不动"的部分。
+
+### 4.6 特殊问题清单
+
+| 问题 | 影响 | 对策 |
+|---|---|---|
+| **Fabric.js 自定义模板渲染**(`localhost:3001`,渲染进程内 Node 服务,`generateServer.API.md`) | 失去 Node 运行时后该服务消失 | ① 把渲染挪到 WebView 侧(前端本来就有 DOM/canvas,用 Fabric.js 直接渲染后回传 base64——**最顺**);② 保留一个极简 Node 边车;③ Go 侧 canvas 库重画(不推荐) |
+| **WebView2 运行时** | 老 Win10 可能无 Evergreen Runtime | NSIS 安装器里带 WebView2 bootstrapper(~1.8MB),静默安装 |
+| 多窗口 + localStorage 跨窗共享 | Wails v2 多窗同源,可用 | 同窗内 `storage` 事件行为需实测 |
+| `C:/Zhihuiyin/database.db` 硬编码 | 若 DB 留 Python 则无影响;若 Go 接管则迁 `modernc.org/sqlite`(纯 Go,无 cgo) | 数据文件不动,双写过渡 |
+| MCU 固件升级(micropython_update 插件) | 串口刷固件逻辑 | 留 Python 或随串口一起搬 |
+| 云登录 RSA(jsencrypt)+ token | 纯前端,不受影响 | 0 |
+| "Python 退出→整应用退出" 语义 | 必须在 Go 壳显式保留 | `cmd.Wait()` goroutine |
+| digiCamControl / SmartShooter 双模式 | 两个分支都要保留 | `controlType` 配置照搬 |
+
+### 4.7 框架对比(Wails2 / Wails v3 / Tauri / Neutralino / 留 Electron)
+
+| 维度 | **Wails2(推荐基线)** | Wails v3 | Tauri 2 | Neutralino | 留 Electron(只做瘦身) |
+|---|---|---|---|---|---|
+| 后端语言 | Go | Go | **Rust**(重写成本≈Go,团队 Go 配置已就位,不占优) | 无独立后端(仍需 sidecar) | Node |
+| 前端复用 | Vue3 原样 | 同 | 同(WebView 同为 Chromium 系) | 同 | 100% |
+| 安装包(壳) | ~25-35M 展开 / ~12-18M 压缩 | 相近 | 更小 ~10-20M | 最小 ~5M | ~90M(压缩后) |
+| 本地图像 | 自定义 asset handler / 本地 HTTP,方案成熟 | 同,API 更清晰 | `asset:` 自定义协议,方案成熟 | 需自己开 HTTP | 现状即可 |
+| 多窗口 | v2 支持(较基础) | **v3 多窗/多 webview 完善** | 成熟 | 弱 | 成熟 |
+| 生态/文档 | 成熟,中文资料多 | 2025 起稳定,新项目首选 | 成熟 | 一般 | 成熟 |
+| 风险 | 低 | 低(较新,注意版本) | 中(Rust) | 中 | 最低 |
+
+> **建议**:以 Wails v2 为基线评估(成熟、社区大),若确定立项直接上新,可评估 Wails v3(多窗口体验更好)。团队已有 Go 构建配置,**Tauri 的"更小"不足以抵消换 Rust 栈的成本**。
+
+### 4.8 迁移后体积预估
+
+```
+Wails 方案(阶段二完成时):
+├── Go 宿主(含前端 dist、窗口/OTA/进程管理)      ~30M 展开 → ~15M 压缩
+├── Python sidecar(瘦身版: 去 pandas/tk/ffmpeg, 留硬件+图像+模板)
+│                                             ~150-160M 展开 → ~55-60M 压缩
+└── 合计安装器 ≈ 80~90M   (现状 150M)
++ 资源包(按客户/品牌, 首启按需下载, 单个客户 ~30-60M, 不进安装器)
+```
+
+---
+
+## 5. 综合推荐与路线图
+
+### 阶段一:体积瘦身(1~2 周,零架构风险)——**先做这个**
+
+1. 删 `py-0917-dev.zip`(98M,无引用);
+2. Python 依赖瘦身:剔 pandas(换 openpyxl)、tkinter、networkx、pytz;排除 opencv ffmpeg 视频后端;`pillow_avif` 懒加载;收紧 cx_Freeze excludes;
+3. 资源 383M 移出主包,按客户品牌包 + 首启下载(复用 `init_load_source.py` 云端 md5 机制);
+4. 清死代码(`imageMatting.js`、`windows.js`、`server/http.py`、Qt 时代 Python 死文件、`socket_client.py` 自连遗留);
+5. NSIS 压缩等级调 maximum。
+**产出**:安装器 ~110M;生产磁盘占用(含资源)从"490M+383M 散落"变为可控。
+
+### 阶段二:壳替换 Wails2/3(4~8 周,1~2 人)
+
+1. Go 宿主:窗口管理(6 类窗口)/ pyapp 进程管理(保留退出联动)/ OTA / 对话框 / 配置 / 本地文件服务 / SQLite(若接管);
+2. 前端:`client.ts` shim + `socket.ts` 直连 + `getFilePath()` 转换,~3 个文件;
+3. Fabric.js 模板渲染挪 WebView 侧;
+4. 硬件全部暂留 Python sidecar;
+5. 回归重点:双模式相机、MCU 拍摄序列、蓝牙扫码、多窗口状态、OTA、中文路径/字体。
+**产出**:安装器 ~80-90M;启动内存下降(Electron 双进程 chromium 开销 → WebView2 单 webview);技术栈收敛为 Go + Python + Vue。
+
+### 阶段三(可选):图像核心下沉(按季度,视收益决定)
+
+- 形态 A:**最小 DLL**(pybind11/Cython,8~10 个纯图像函数,JSON ABI)→ Go 同步调用,批处理延迟与崩溃隔离改善;
+- 形态 B:硬件通信(串口帧协议先行)搬 Go,BLE 最后;
+- 形态 C:32 个品牌模板做**模板引擎抽象**(数据描述化 + 渲染器),脱离 PIL 逐页代码——这是长期收益最大但最重的一项,建议先做 2~3 个高频客户试点。
+**不做也不会死;做了收益是单进程化 + 更新链路简化(Python 可独立热更)**。
+
+### 风险登记
+
+| 风险 | 等级 | 缓解 |
+|---|---|---|
+| WebView2 在老 Win10/特定安全策略下加载本地 HTTP 图片 | 中 | 阶段二第 1 周先做"图片链路 POC"(文件路由 + 预览轮询 + 大图解码),再全面铺开 |
+| BLE 在 Go 侧生态弱 | 中 | 阶段二 BLE 留 Python |
+| 32 品牌模板回归成本 | 高 | 建立"模板截图 diff"自动化:同输入跑新旧管线比对输出像素 |
+| 云 API 凭据(AK/SK 硬编码 `remove_bg_ali.py:23-24` 等)随迁移暴露面变化 | 中 | 顺手移入配置/密钥管理 |
+| Wails v2 多窗口 API 局限(tk 外部窗、6 窗并发) | 中 | POC 覆盖;不够则上 v3 |
+
+---
+
+## 6. 附录
+
+### 6.1 端口清单
+
+| 端口 | 归属 | 状态 |
+|---|---|---|
+| 7074 | Python FastAPI(HTTP + /ws) | **核心** |
+| 5513 | digiCamControl 第三方本地服务 | 双模式之一 |
+| 54543/54544 | SmartShooter5.exe ZMQ(SUB/REQ) | SmartShooter 模式 |
+| 3001 | Fabric.js 模板渲染(渲染进程 Node 服务) | 自定义模板(当前分支未见实现) |
+| 7070/7071 | ee-core socket.io/Koa | 停用 / 空转 |
+| 7072/7073 | 自建静态 / goapp(模板预留) | 停用 |
+| 8080/3000 | 开发期 vite/ee-bin | 仅开发 |
+
+### 6.2 云端依赖(迁移时需 1:1 保留)
+
+dev2.valimart.net(API 代理/AI 图/模板/余额)、3api.valimart.net(像素练)、imageseg.cn-shanghai.aliyuncs.com(阿里云)、gemini-2.5-flash-image-preview、ossimg.valimart.net(OTA version.json)、钉钉机器人告警。
+
+### 6.3 建议先删的死代码(减体积 + 减认知负担)
+
+- Electron:`controller/windows.js`(未 import BrowserWindow 的重复 openMain)、`server/http.js`(未启动)、`api/imageMatting.js`(无引用)、`jobs/example/`;
+- Python:`detail_temp.py`/`detail_func.py`/`handle_detail.py`/`matching_photos/`/`manual_image_matching/`/`module_generate_main_image.py`(Qt 时代,import 不存在的 `UI.*`)、`auto_deal_pics/`、`match_and_cutout_mode_control/`(v2 旧路径)、`sockets/socket_client.py`(自连遗留)、`service/jack_cloud.py`(0 字节);
+- 打包:`build/extraResources/py-0917-dev.zip`、`dll/myDllDemo.dll`。
+
+### 6.4 关键文件索引
+
+| 主题 | 位置 |
+|---|---|
+| Python 入口 | `python/index.py` |
+| REST 路由全集 | `python/api.py`(2499 行) |
+| WS 命令分发 | `python/sockets/message_handler.py:191` |
+| 抠图模式分派 | `python/service/base_deal.py:577-587` |
+| 主图合成 | `python/service/generate_main_image/grenerate_main_image_test.py` |
+| 品牌模板 | `python/custom_plugins/plugins/detail_template/<客户>/` |
+| 拍摄动作执行 | `python/mcu/DeviceControl.py:1831` |
+| 串口协议 | `python/mcu/SerialIns.py` |
+| ZMQ 相机 | `python/mcu/capture/smart_shooter_class.py` |
+| DB | `python/databases.py:15`(`C:/Zhihuiyin/database.db`) |
+| cx_Freeze 配置 | `python/setup.py` |
+| Python 进程拉起 | `electron/preload/index.js:17` → `electron/service/cross.js:92-112` |
+| WS 客户端/转发 | `electron/utils/socket.js` |
+| OTA | `electron/controller/ota.js:23-143` + `frontend/src/views/OTA/index.vue` |
+| 前端 Electron 单点耦合 | `frontend/src/stores/modules/client.ts:3` |
+| 前端 IPC 通道表 | `frontend/src/utils/ipc.ts` |
+| 文件路径→URL 单点 | `frontend/src/utils/appfun.ts:8-11`(`getFilePath`) |
+| 打包配置 | `electron/config/builder.json` + `electron/config/bin.js` |