# snap-mixer-python-prototype **Repository Path**: deali/snap-mixer-python-prototype ## Basic Information - **Project Name**: snap-mixer-python-prototype - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-09-24 - **Last Updated**: 2026-08-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # snap-mixer-python-prototype 跨目录图片整理与**相似图去重**工具。扫描手机/平板等图库,用感知哈希(pHash)找出重复或近似重复的壁纸,并按**分辨率优先、同分辨率比文件体积**的规则保留质量更高的版本。 ## 产品化方案(文档) 当前仓库采用简单 monorepo:Python 应用位于 `apps/api`,Web 应用位于 `apps/web`,根目录通过 Taskfile 统一管理。P0 产品入口是桌面壳 + Web 控制台;CLI 扫描/报告仍可用。 **目标产品与实施方案**(薄原生壳 + HTTP/SSE 后端 + shadcn Web 控制台)见: - **[docs/PRODUCT_SPEC.md](./docs/PRODUCT_SPEC.md)** — 唯一权威的产品与实施规格 - [docs/README.md](./docs/README.md) — 文档维护和 AI Agent 使用说明 - [docs/decisions/](./docs/decisions/) — 架构决策记录 ## 功能 - 递归扫描多目录、多格式(jpg / png / webp / heic …) - 按路径识别游戏标签:`原神` / `绝区零` / `星穹铁道` - pHash 相似聚类(可调汉明距离阈值) - 每组自动选出 **KEEP(高质量)** 与 **DROP(低质量副本)** - 导出 JSON + CSV 报告 - 可选:隔离(移动到 quarantine)或删除低质量文件(默认 dry-run) ## 环境要求 - Python **3.11 – 3.13**(推荐 3.12) - [uv](https://github.com/astral-sh/uv) 包管理 本项目已从 Poetry 迁移到 **uv**,请勿再使用 `poetry install`。 ## 安装 ```powershell cd c:\code\snap-mixer\snap-mixer-python-prototype # 安装所有 Python 与 Web 依赖 task install ``` 安装完成后可直接启动产品: ```powershell # 开发:同时启动 FastAPI 与 Vite task dev # 产品入口:托盘壳 + 本地后端 + 浏览器控制台 task api:app # 或 task api:cli -- app ``` 旧的命令行扫描/报告仍然可用: ```powershell task api:cli -- --help task api:cli -- dedup --help ``` ### 可选依赖 ```powershell # FastAPI / Uvicorn 产品后端依赖 uv sync --package snap-mixer-python-prototype --extra api --python 3.12 # imagededup / 可视化 uv sync --package snap-mixer-python-prototype --extra dedup-extra --python 3.12 # EXIF 深度处理 uv sync --package snap-mixer-python-prototype --extra exif --python 3.12 ``` ## 快速开始:手机 + 平板 游戏壁纸去重 针对 `手机图片` 与 `平板图片` 中「原神 / 绝区零 / 星穹铁道」相关目录: ```powershell task api:cli -- dedup ` "C:\Users\deali\Pictures\手机图片" ` "C:\Users\deali\Pictures\平板图片" ` --game 原神 --game 绝区零 --game 星穹铁道 ` --threshold 8 ` --report-dir ./dedup_reports ``` 默认只**分析并写报告**,不会改动任何原图。 ### 只看跨设备重复(手机 vs 平板) ```powershell task api:cli -- dedup ` "C:\Users\deali\Pictures\手机图片" ` "C:\Users\deali\Pictures\平板图片" ` --cross-source-only ` --report-dir ./dedup_reports ``` ### 预览隔离低质量副本(仍不真正移动) ```powershell task api:cli -- dedup ` "C:\Users\deali\Pictures\手机图片" ` "C:\Users\deali\Pictures\平板图片" ` --action quarantine ` --quarantine-dir "C:\Users\deali\Pictures\_dup_quarantine" ``` ### 确认报告后真正隔离 ```powershell task api:cli -- dedup ` "C:\Users\deali\Pictures\手机图片" ` "C:\Users\deali\Pictures\平板图片" ` --action quarantine ` --quarantine-dir "C:\Users\deali\Pictures\_dup_quarantine" ` --apply ``` > **建议**:先 `report` → 人工抽查 CSV → 再 `quarantine --apply`。慎用 `delete`。 ## 质量判定规则 对每组相似图: 1. **像素数**(宽 × 高)更大者优先 2. 像素相同则 **文件体积** 更大者优先(通常压缩更轻) 3. 仍相同则按路径字符串稳定排序 展示分数公式(实现见 `apps/api/src/image_tidy/core/models.py`): ```text quality_score = pixels + file_size / (file_size + 1_000_000_000) ``` 文件体积加成始终小于 1,因此不会越过哪怕 1 像素的分辨率差距;实际 KEEP 排序继续使用“像素数 → 文件体积 → 路径”的稳定排序键。 ## 阈值说明 | threshold | 含义 | |-----------|------| | 0–3 | 几乎同一张(轻微重编码) | | **5–8** | 推荐:同图不同裁剪/压缩/缩放 | | 10–12 | 更松,可能把同系列壁纸判进一组 | ## 报告 运行后在 `--report-dir`(默认 `./dedup_reports`)生成: - `dedup_report_YYYYMMDD_HHMMSS.json` — 完整分组 - `dedup_report_YYYYMMDD_HHMMSS.csv` — 便于 Excel 筛选(`role=keep|discard`) ## 可视化审阅(推荐) CSV/JSON 适合统计,**并排看图**请用本地网页审阅: ```powershell # 打开最新报告(自动起本地服务并打开浏览器) task api:cli -- view # 指定某份报告 task api:cli -- view .\dedup_reports\dedup_report_20260812_231822.json # 分析完直接打开 task api:cli -- dedup DIR1 DIR2 --view ``` 页面能力: - UI:**产品化前端**(Vite + Tailwind CSS 4 + daisyUI 5,构建产物离线可用) - 顶部统计卡片 + 筛选栏 + 底部选择操作坞 - **KEEP / DROP 对比布局**(左侧保留、右侧可丢弃网格) - 主题切换(night / dark / dim / nord …) - **定位**:资源管理器中选中文件(Windows;macOS/Linux 预留) - **丢弃 / 批量丢弃**:低质量 DROP 移入隔离区(KEEP 受保护) - **回滚历史**:按操作记录恢复 ```powershell # 自定义隔离区 task api:cli -- view --quarantine-dir "C:\Users\deali\Pictures\_dup_quarantine" ``` 默认隔离区:`dedup_reports/quarantine/`(`_journal.json` 可回滚)。 > 服务默认监听 `127.0.0.1`;**只有报告中的 DROP 可被丢弃**。 ### 前端开发(改 UI 时) ```powershell task web:install task codegen # 从 Python 后端 OpenAPI 生成前端类型与请求函数 task web:build # 输出到 apps/api/src/image_tidy/web/static/dist/ ``` 可选联调: ```powershell # 终端 1:API task api:dev # 终端 2:Vite HMR(代理 /api → 8765) task web:dev ``` ### 静态 HTML 图库(可离线) 把缩略图嵌进单个 HTML,双击即可打开(组很多时文件会偏大): ```powershell task api:cli -- html .\dedup_reports\dedup_report_20260812_231822.json ` --cross-source-only --max-groups 100 ``` ## 仅统计不扫描哈希 ```powershell task api:cli -- scan ` "C:\Users\deali\Pictures\手机图片" ` "C:\Users\deali\Pictures\平板图片" ``` ## 作为库调用 ```python from image_tidy import scan_paths, find_duplicate_groups from image_tidy.core.scanner import collect_image_paths from image_tidy.core.dedup import export_report, apply_dedup pairs = collect_image_paths( [r"C:\Users\deali\Pictures\手机图片", r"C:\Users\deali\Pictures\平板图片"], game_tags=["原神", "绝区零", "星穹铁道"], ) images = scan_paths(pairs, use_phash=True, workers=4) groups = find_duplicate_groups(images, threshold=8) for g in groups[:5]: print("KEEP", g.keeper.describe()) for d in g.discards: print(" DROP", d.describe()) export_report(groups, "./dedup_reports", scanned_count=len(images)) ``` ## 项目结构 ```text apps/ api/ # Python 项目(uv workspace member) src/image_tidy/ # core / viewer / web / cli scripts/ pyproject.toml Taskfile.yml web/ # Vite 前端项目 src/api/generated/ # OpenAPI 自动生成类型与请求函数 scripts/codegen.mjs package.json Taskfile.yml Taskfile.yml # install / dev / build / lint / test / codegen pyproject.toml # uv workspace uv.lock # monorepo Python 依赖锁 docs/ ``` ## 与旧 Poetry 环境 - 删除/忽略 `poetry.lock`,改用 `uv.lock`(由 `uv sync` 生成) - `pyproject.toml` 已改为 PEP 621 + hatchling - 旧 `image_tidy.demo.scan_lib` / `organize` 仍可导入,但推荐 `snap-tidy` ## 许可证 私有原型项目,按需自用。