Metadata-Version: 2.4
Name: moxuan
Version: 0.1.0
Summary: 照片查重清理工具：识别近重复照片并推荐保留最优的一张
Author-email: Tridro <tridro@mohoutech.com>
License-Expression: MIT
Project-URL: Homepage, https://ifilevault.myasustor.com:3101/mohoutech/moxuan
Project-URL: Source, https://ifilevault.myasustor.com:3101/mohoutech/moxuan
Keywords: photo,dedup,clustering,dinov2,cleanup
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Classifier: Topic :: Multimedia :: Graphics
Classifier: Environment :: Console
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: rawpy>=0.24
Requires-Dist: numpy>=1.26
Requires-Dist: opencv-contrib-python-headless>=4.10
Requires-Dist: torch>=2.3
Requires-Dist: Pillow>=10.0
Requires-Dist: click>=8.1
Requires-Dist: fastapi>=0.115
Requires-Dist: uvicorn>=0.30
Provides-Extra: face
Requires-Dist: mediapipe>=0.10; extra == "face"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: httpx2>=2.0; extra == "dev"
Dynamic: license-file

# moxuan — 照片查重清理工具（v0.1.0）

识别近重复照片（连拍、同场景短间隔、轻微构图调整）并推荐每组保留最优的一张。

- **一键清理流程**：`scan`（扫描→特征→聚类→评分）→ `groups` 审核 → `quarantine` 隔离（可还原）→ `purge` 彻底删除
- **网页审核界面**：分组浏览 / 大图对比 / 手动改标最优 / 批量移入隔离区
- **可配置**：相似度阈值、时间窗、评分权重（config.toml + 网页设置面板）
- **支持 RAW**（CR2/NEF/ARW/RAF/DNG）：内嵌预览参与查重/评分，大图按需 demosaic（3200px 或全尺寸）

## 安装

任选一种，均无需手动激活虚拟环境；首次运行自动下载模型（DINOv2 权重约 90MB + 人脸/BRISQUE 模型，缓存在 `~/.cache/moxuan/`）：

```bash
# 方式一：uvx 即用即走（推荐，零安装）
uvx moxuan scan <照片目录> --threshold 0.88

# 方式二：uv tool 全局安装（一次安装，命令常驻 PATH）
uv tool install moxuan

# 方式三：pip 直接安装（常规 Python 环境）
pip install moxuan
```

- 人脸眼睛睁开检测默认不装，需要时用 `[face]` extra：`uv tool install "moxuan[face]"`（uvx 加 `--extra face`）
- **源码开发**（改网页前端时需要）：

```bash
git clone https://ifilevault.myasustor.com:3101/mohoutech/moxuan
cd moxuan
uv venv --python 3.13
uv pip install -e ".[face]"
```

## 使用（CLI）

`uvx` 用户把下面的 `moxuan` 换成 `uvx moxuan`：

```bash
moxuan models                                  # （可选）预置模型，scan 会自动补齐
moxuan scan <照片目录> --threshold 0.88         # 一键全流程：扫描→特征→聚类→评分
moxuan groups                                  # 查看分组
moxuan report --format html                    # 生成 HTML/CSV 审核报告
moxuan quarantine <group_id>                   # 确认组清理：保留最优，其余移入隔离区
moxuan restore <quarantine_id>                 # 还原隔离区照片
moxuan purge <quarantine_id>                   # 彻底删除（不可恢复）
moxuan restore --prune                         # 清理手动删除 quarantine/ 后的失效记录
```

`--threshold` 为相似度阈值（默认 0.88，见 config.toml）。

## 网页审核界面

```bash
moxuan serve start    # 打开 http://localhost:9100（前端后端一体）
moxuan serve status   # 查询状态
moxuan serve stop     # 停止服务
```

安装版（pip/uvx）的网页界面已内置在 wheel，由后端同一端口（默认 9100）提供；开发模式则双进程：后端 9100 + 前端 Vite `cd ui && npm run dev`（5173，`/api` 代理到 9100；npm 缓存目录无写权限报 EPERM 时加 `--cache` 参数规避）。

- 工作台：顶部展示当前工作路径，输入照片目录后依次执行 扫描→特征→聚类→评分（实时进度）；任务记录可单条删除或一键清空已完成；照片全库统一聚类/评分，**换目录前先「重置数据」清空旧照片**，避免多目录混在一起
- 审核：分组列表按 张数/最佳评分/拍摄时间 排序；网格滑块调尺寸（56–380px，默认 176px）；悬停勾选可批量移入隔离区；点照片看大图（`←/→` 翻页、`Esc` 关闭、可直接 设为最优/移出组），RAW 可「加载全尺寸」
- 清理区：还原或彻底删除（与审核页同套网格/大图）
- 设置：调整阈值/时间窗/评分权重

## API

FastAPI REST 接口（`api/routes.py`）：

- `POST /api/tasks/{scan|embed|cluster|score}`、`GET /api/tasks[/{id}]`：任务执行与进度；`DELETE /api/tasks[/{id}]`：删除记录 / 清空全部已完成（运行中的不可删）；`DELETE /api/data`：清空照片与分组（换目录重新开始）
- `GET /api/groups`、`GET /api/photos?group_id=`：分组与照片
- `GET /api/thumbnail/{photo_id}`、`GET /api/original/{photo_id}`：缩略图与原图（ETag/304 缓存）；浏览器可解码格式直出原图，RAW 渲染缓存 JPEG（默认 3200px，`?full=1` 全尺寸）
- `PATCH /api/groups/{id}/best`、`POST /api/groups/{id}/{remove|restore}`：设最优 / 移出组 / 移回组
- `GET /api/quarantine`、`POST /api/quarantine/confirm`、`POST /api/quarantine/{id}/restore`、`DELETE /api/quarantine/{id}`：隔离区
- `GET|PATCH /api/settings`：运行参数

`.thumbnails/` 是可丢弃缓存（删后自动重建）：缩略图 `{id}.jpg`；不可解码原图（如 TIFF）与 RAW 大图为 `{id}_hires.jpg`（3200px），RAW 全尺寸为 `{id}_full.jpg`。

## 配置

`config.toml`（项目根）是配置入口，环境变量 `MOXUAN_CONFIG` 可指定其他路径：

- `[service] host / port`：网页服务监听地址与端口
- `[algorithm] threshold / window`：相似度阈值（默认 0.88）与时间窗（默认 300s）
- `[algorithm.weights]`：评分权重（清晰度/锐度/人脸/曝光/裁剪/对比度/动态范围/色彩/噪点/BRISQUE/EXIF）

网页「设置」面板的修改存数据库、优先于配置文件。安装版数据（用户 config、SQLite、日志、PID、隔离区）位于 Windows `%APPDATA%\moxuan`、Linux/macOS `~/.config/moxuan`（`MOXUAN_DATA` 可重定向）。

## 算法

- **相似度**：DINOv2 embedding + 时间窗分桶（默认 300s；无 EXIF 时间单独互比）+ 余弦阈值连通分量 + SSIM 边界复核
- **选优**：清晰度 / 曝光 / 人脸（YuNet+眼睛睁开）/ BRISQUE / EXIF（分辨率/ISO/快门）加权评分
- **清理安全**：确认后移入隔离区，可还原；`purge` 彻底删除

## 环境要求

- Python 3.11+（uv 自动下载所需版本）
- 首次运行联网下载模型（`moxuan models` 可预置）；Python 访问 github.com 超时时自动改用 curl
- 运行时依赖：torch、opencv-contrib-python-headless、numpy、rawpy、Pillow、click、fastapi、uvicorn；可选 mediapipe（`[face]`）

## 发布（PyPI）

```bash
python scripts/build_frontend.py   # 构建前端到 api/web/（发布者需 node/npm）
uv build                           # 生成 sdist + wheel 到 dist/
uv publish                         # 需 UV_PUBLISH_TOKEN（PyPI API token）
```

## 测试

```bash
uv venv --python 3.13
uv pip install -e ".[dev]"
uv run pytest
```
