Metadata-Version: 2.3
Name: fashion-image-search
Version: 0.1.2
Summary: 服装以图搜图系统：YOLOv8 检测抠图 + SigLIP 视觉编码 + ZVec 向量检索，支持 AI 语义增强与批量入库/检索
Project-URL: Homepage, https://pypi.org/project/fashion-image-search/
Author-email: CC <3204624858@qq.com>
License: MIT
Keywords: clip,faiss,fashion,fastapi,image-retrieval,image-search,siglip,vector-search,yolov8,zvec
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Scientific/Engineering :: Image Recognition
Requires-Python: >=3.10
Requires-Dist: fastapi<1.0.0,>=0.115.0
Requires-Dist: huggingface-hub<0.37.0,>=0.24.0
Requires-Dist: numpy<2.0.0,>=1.24.0
Requires-Dist: open-clip-torch<4.0.0,>=2.24.0
Requires-Dist: openai<2.0.0,>=1.40.0
Requires-Dist: opencv-python-headless<5.0.0,>=4.9.0
Requires-Dist: pillow>=10.0.0
Requires-Dist: python-multipart>=0.0.9
Requires-Dist: pyyaml<7.0,>=6.0
Requires-Dist: safetensors<1.0.0,>=0.4.0
Requires-Dist: sentence-transformers<4.0.0,>=3.0.0
Requires-Dist: torch<2.4.0,>=2.3.1
Requires-Dist: torchvision<0.19.0,>=0.18.1
Requires-Dist: ultralytics<9.0.0,>=8.3.0
Requires-Dist: uuid7>=0.1.0
Requires-Dist: uvicorn[standard]<1.0.0,>=0.30.0
Requires-Dist: xxhash>=3.0.0
Requires-Dist: zvec>=0.7.0
Provides-Extra: dev
Requires-Dist: build>=1.2.0; extra == 'dev'
Requires-Dist: twine>=5.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# 👗 Fashion Search — 服装以图搜图系统

上传一张服装图片即可入库，随后用任意服装图检索出视觉最相似的单品；可选叠加 AI 语义描述做视觉 + 文本融合检索。

**向量底座为 [ZVec](https://pypi.org/project/zvec/)（进程内嵌入式向量数据库，内置 FAISS / DiskANN 引擎），按数据量自动选型（Flat → IVF+PQ → DiskANN）；推理设备（NVIDIA / AMD / Intel / Apple / CPU）自动探测。**

[![PyPI](https://img.shields.io/pypi/v/fashion-image-search)](https://pypi.org/project/fashion-image-search/)
[![Python](https://img.shields.io/pypi/pyversions/fashion-image-search)](https://pypi.org/project/fashion-image-search/)

---

## 目录

- [特性](#-特性)
- [安装](#-安装)
- [快速开始](#-快速开始)
- [命令行工具](#-命令行工具)
- [HTTP 接口](#-http-接口)
- [配置](#-配置)
- [模型权重](#-模型权重)
- [工作原理](#-工作原理)
- [向量引擎自动选型](#-向量引擎自动选型)
- [推理设备自动适配](#-推理设备自动适配)
- [常见问题](#-常见问题)

---

## 🎯 特性

- **服装检测与分割**：YOLOv8-seg 实例分割，掩码抠图 + 白底预处理
- **视觉特征编码**：MODA 微调 ViT-B-16-SigLIP，输出 768 维归一化向量（GPU 半精度加速）
- **以图搜图**：内积相似度检索，`top_k` / `min_similarity` 双重过滤
- **AI 语义增强**：OpenAI 兼容多模态接口生成结构化服装描述，视觉 + 文本加权融合
- **批量入库 / 批量检索**：检测、编码、检索全链路 batch 推理 + AI 并发描述
- **图片去重**：xxh3 精确哈希 + 64 位感知哈希模糊去重（同图不同编码也能识别）
- **ZVec 嵌入式向量库**：进程内零网络开销、WAL 持久化，数据量跨阈值自动迁移索引
- **跨品牌 GPU 支持**：NVIDIA CUDA / AMD ROCm / Intel XPU / Apple MPS 自动探测，无 GPU 自动回退 CPU

---

## 📦 安装

需要 **Python 3.10+**（推荐 3.12）。

```bash
# pip
pip install fashion-image-search

# uv
uv add fashion-image-search
```

> PyPI 发行名为 `fashion-image-search`，导入名为 `fashion_search`，命令行命令为 `fashion-search`。

> 包内**不含模型权重**（YOLO 分割模型约 50 MB、视觉编码器约 177 MB，超出 PyPI 单文件 100 MB 限制）。首次运行会自动下载到本地模型目录，之后完全离线复用。想提前拉好可执行 `fashion-search download-models`。

依赖中包含 PyTorch。若需要 GPU 加速，建议先按 [PyTorch 官方指引](https://pytorch.org/get-started/locally/) 安装对应 CUDA / ROCm 版本的 `torch` 与 `torchvision`，再安装本包：

```bash
pip install torch==2.3.1 torchvision==0.18.1 --index-url https://download.pytorch.org/whl/cu118
pip install fashion-image-search
```

---

## 🚀 快速开始

### 1. 自检环境（可选）

```bash
fashion-search doctor
```

检查依赖、运行目录、配置与模型权重是否就绪，**不会下载也不会加载模型**。

### 2. 启动服务

```bash
fashion-search serve --host 0.0.0.0 --port 8000
# 交互式接口文档: http://localhost:8000/docs
```

首次启动会自动下载缺失的模型权重。

### 3. 入库与检索

```bash
# 批量入库一个目录
fashion-search import ./my_garments

# 以图搜图
fashion-search search ./query.jpg --top-k 10
```

命令行输出示例：

```
 1. score=1.0000 id=06aca010-5ff4-7086-8000-7665c707c370 path=/home/me/.fashion-search/data/garments/06aca010-....jpg
 2. score=0.7793 id=06aca010-f680-77e5-8000-70fcedc4111e path=/home/me/.fashion-search/data/garments/06aca010-....jpg
```

也可以直接用 HTTP 接口：

```bash
curl -X POST http://localhost:8000/wardrobe/add \
  -F "file=@./my_garments/shirt.webp" \
  -F "enable_ai=false"

curl -X POST http://localhost:8000/wardrobe/search \
  -F "file=@./my_garments/shirt.webp" \
  -F "top_k=10" \
  -F "min_similarity=0.5"
```

---

## 🛠️ 命令行工具

```bash
fashion-search --help
```

| 子命令 | 用途 |
|--------|------|
| `serve` | 启动 HTTP 服务（`--host` / `--port` / `--config`） |
| `download-models` | 预下载全部模型权重（`--no-text` 跳过文本编码器，省约 90 MB） |
| `doctor` | 依赖、目录、配置、模型权重自检 |
| `stats` | 数据库记录数与索引规模、当前算法 |
| `add <图片>` | 入库单张图片（`--metadata '{...}'` 附加元数据） |
| `search <图片>` | 以图搜图（`--top-k` / `--min-similarity` / `--no-ai`） |
| `import <目录>` | 批量入库整个目录（`--reset` 先清空，`--query` 指定验证图） |
| `smoke <目录>` | 端到端冒烟测试：检测 → 编码 → 入库 → 检索 |
| `api-smoke <目录>` | 对运行中的服务做 HTTP 接口测试 |
| `reset` | 清空数据库、原图与索引（`--yes` 跳过确认） |
| `config` | 输出当前生效配置；`--write <路径>` 写出默认配置模板 |

等价入口：`python -m fashion_search <子命令>`。

---

## 🌐 HTTP 接口

服务默认监听 `http://localhost:8000`，交互式文档在 `/docs`。

### `POST /wardrobe/add` — 入库一张服装图片

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `file` | UploadFile | ✅ | 服装图片 |
| `enable_ai` | bool | 否 | 是否启用 AI 描述（默认 `true`） |
| `metadata` | str | 否 | 可选图片元数据，JSON 字符串 |

响应 `200`：

```json
{
  "id": "06a9e86f-e264-74ef-8000-a62ed2fbb5d5",
  "message": "success",
  "ai_enabled": false,
  "metadata": null
}
```

重复图片不会重复入库，返回 `{"skipped": true, "reason": "重复图片", "existing_id": "..."}`。

### `POST /wardrobe/search` — 以图搜图

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `file` | UploadFile | ✅ | 查询图片 |
| `enable_ai` | bool | 否 | 是否启用 AI 文本融合（默认 `false`） |
| `top_k` | int | 否 | 返回数量，1~100（默认取配置 `search.default_top_k`） |
| `min_similarity` | float | 否 | 相似度下限，0~1（默认取配置 `search.min_similarity`） |

响应为数组，按相似度降序：

```json
[
  {
    "id": "06a9e86f-e264-74ef-8000-a62ed2fbb5d5",
    "score": 1.0,
    "image_path": "data/garments/06a9e86f-e264-74ef-8000-a62ed2fbb5d5.jpg",
    "ai_description": null,
    "metadata": null
  }
]
```

### `POST /wardrobe/add_batch` — 批量入库

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `files` | List[UploadFile] | ✅ | 多张服装图片 |
| `enable_ai` | bool | 否 | 是否启用 AI 描述（默认 `true`） |

```bash
curl -X POST http://localhost:8000/wardrobe/add_batch \
  -F "files=@./my_garments/a.webp" \
  -F "files=@./my_garments/b.webp"
```

### `POST /wardrobe/search_batch` — 批量检索

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `files` | List[UploadFile] | ✅ | 多张查询图片 |
| `enable_ai` | bool | 否 | 是否启用 AI 文本融合（默认 `false`） |
| `top_k` | int | 否 | 每张图返回数量（默认 20） |
| `min_similarity` | float | 否 | 相似度下限（默认取配置） |

返回与上传顺序一致的数组，每项结构同 `/wardrobe/search`。

### `GET /wardrobe/{garment_id}` — 服装详情

返回该服装的元数据与 AI 描述；不存在返回 `404`。

### `GET /image/{garment_id}` — 服装原图

直接返回入库时保存的原图（JPEG 流），可直接作为 `<img>` 的 `src`；不存在或文件缺失返回 `404`。

### `GET /health` — 健康检查

```json
{
  "status": "ok",
  "version": "0.1.1",
  "garments": 128,
  "vision_index": 128,
  "text_index": 96,
  "algorithm": "flat",
  "ai_enabled": true,
  "index_dir": "/home/me/.fashion-search/data/vector_index"
}
```

---

## ⚙️ 配置

首次启动会在运行根目录生成 `config.yaml`（完整注释版）。**运行根目录**按以下顺序确定：

1. 环境变量 `FASHION_SEARCH_HOME`
2. 当前工作目录（若其中存在 `config.yaml` 或 `pyproject.toml`）
3. `~/.fashion-search`

目录结构：

```
<运行根目录>/
├── config.yaml          # 配置（首次启动自动生成）
├── data/
│   ├── wardrobe.db      # SQLite 元数据（ID / 图片路径 / AI 描述 / 去重指纹）
│   ├── garments/        # 入库原图
│   └── vector_index/    # 向量集合（vision/ 与 text/，WAL 自动持久化）
└── models/              # 模型权重
```

主要配置段：

| 配置段 | 关键项 | 说明 |
|--------|--------|------|
| `models` | `detector` / `vision_encoder` / `text_encoder` | 模型路径与名称 |
| `search` | `default_top_k` / `min_similarity` / `alpha` / `enable_ai_enhance` | 检索行为 |
| `vector_db` | `algorithm` / `flat_threshold` / `ivf_threshold` / `device` / `index_dir` | 向量库与选型 |
| `ai` | `api_key` / `platform` / `model` / `api_base` / `concurrency` | 外部 AI 描述 |
| `system` | `image_max_size` / `garments_dir` / `dedup_images` / `garment_id_prefix` | 系统参数 |

### 相关环境变量

| 变量 | 说明 |
|------|------|
| `FASHION_SEARCH_HOME` | 运行根目录（数据、模型、配置） |
| `FASHION_SEARCH_CONFIG` | 指定配置文件路径 |
| `FASHION_SEARCH_MODELS_DIR` | 单独指定模型目录 |
| `FASHION_SEARCH_DATA_DIR` | 单独指定数据目录 |
| `FASHION_SEARCH_HF_ENDPOINT` | HuggingFace 端点（默认 `https://hf-mirror.com`；设为 `https://huggingface.co` 走官方） |
| `FASHION_SEARCH_GH_PROXY` | GitHub 加速前缀（默认 `https://ghfast.top/`，置空则直连） |
| `HF_HUB_OFFLINE=1` | 完全离线，只用本地已有权重（缺失则明确报错） |
| `FASHION_SEARCH__<段>__<键>` | 覆盖任意配置项，如 `FASHION_SEARCH__VECTOR_DB__DEVICE=cpu` |

### AI 语义增强

在 `ai` 段配置 `api_key`（OpenAI 兼容接口）后，入库时会生成结构化服装描述并建立文本向量，检索时按 `search.alpha` 做视觉/文本加权融合：

```yaml
search:
  alpha: 0.4              # 1.0=纯视觉；越小文本权重越高
  enable_ai_enhance: true
ai:
  api_key: ""             # 留空则纯视觉模式
  api_base: "https://api.openai.com/v1"
  model: "gpt-4o-mini"
  image_input_size: 384   # AI 输入图最长边（越大越慢）
  concurrency: 4          # 并发识别数，建议 2~8
  max_retries: 3          # 指数退避重试次数
```

> 生产环境请用环境变量注入密钥，不要写入配置文件：
> `export FASHION_SEARCH__AI__API_KEY=sk-xxx`

AI 未配置或调用失败时系统自动降级为纯视觉检索，接口不报错（结果中带 `ai_failed: true`）。

---

## 🤖 模型权重

| 模型 | 用途 | 体积 | 来源 |
|------|------|------|------|
| `yolov8m-seg.pt` | 服装检测与分割 | ~50 MB | ultralytics assets |
| `moda-fashion-vision-fp16` | 视觉特征编码（768 维） | ~177 MB | `HopitAI/moda-fashion-vision-fp16` |
| `all-MiniLM-L6-v2` | 文本编码（384 维，AI 增强用） | ~90 MB | `sentence-transformers` |

权重不随包分发，**首次使用时自动下载**到运行根目录的 `models/`（文本编码器落在 HuggingFace 缓存），之后离线复用。可提前预下载：

```bash
fashion-search download-models            # 全部
fashion-search download-models --no-text  # 不用 AI 增强时跳过文本编码器
```

网络受限时可指定镜像：

```bash
export FASHION_SEARCH_HF_ENDPOINT=https://huggingface.co   # 走官方
export FASHION_SEARCH_GH_PROXY=                            # GitHub 直连
```

也可以手动放置权重：把 `yolov8m-seg.pt` 和 `moda-fashion-vision-fp16/vision_encoder.safetensors` 放进 `<运行根目录>/models/`，或用 `config.yaml` 的 `models` 段指向自定义路径。

---

## 🧠 工作原理

```
查询图 ──► YOLOv8-seg 分割抠图（白底）──► ViT-B-16-SigLIP 编码（768 维归一化）
                                              │
                    ┌─────────────────────────┴─────────────────────────┐
                    ▼                                                   ▼
            视觉向量检索（ZVec，内积）                        AI 描述 ──► 文本编码（384 维）
                    │                                                   │
                    └────────────► alpha 加权融合 ◄─────────────────────┘
                                        │
                                        ▼
                           top_k + min_similarity 过滤 ──► 结果（含原图路径）
```

- **入库**：图片去重 → 检测抠图 → 视觉编码入库 → （可选）AI 描述 + 文本编码入库 → 元数据写 SQLite → 索引落盘
- **检索**：检测抠图 → 视觉编码 → 视觉检索（必须）→ （可选）AI 文本融合 → 阈值过滤
- **结果**：每条含 `id` / `score` / `image_path` / `ai_description` / `metadata`，原图可由 `GET /image/{id}` 获取

---

## 📐 向量引擎自动选型

`vector_db.algorithm: auto`（默认）时按数据量选择算法，并在平台不支持时优雅回退：

| 数据量 | 算法 | 特点 |
|--------|------|------|
| < 100 万 | **FAISS Flat** | 100% 精确，硬件成本低 |
| 100 万 ~ 5000 万 | **FAISS IVF + PQ** | 内存/速度平衡（INT8 量化） |
| > 5000 万 | **DiskANN** | SSD 换内存，海量数据 |

- 阈值由 `flat_threshold` / `ivf_threshold` 控制
- 数据增长跨过阈值时自动重建索引（如 Flat → IVF+PQ），已有数据不丢失
- **DiskANN 在 Windows 上不受支持**，自动回退到 IVF+PQ
- 也可显式指定 `algorithm: flat | ivf_pq | diskann`

---

## 🎛️ 推理设备自动适配

`vector_db.device: auto`（默认）按 **NVIDIA CUDA → AMD ROCm/HIP → Intel XPU → Apple MPS → CPU** 顺序探测，检测器与视觉编码器共用同一结果：

- 无 GPU 时自动回退 CPU（全链路端到端可用，仅速度较慢）
- 强制指定：`device: gpu`（无 GPU 时回退 CPU）或 `device: cpu`
- ZVec 索引本身是进程内 CPU 索引（SIMD/AVX 自动调度），天然适配各平台

---

## 🤔 常见问题

**Q：安装后第一次运行很慢？**
A：首次运行要下载约 240 MB 模型权重。建议先执行 `fashion-search download-models`，之后再运行就完全离线。

**Q：`pip install` 报依赖解析失败或想装 GPU 版 PyTorch？**
A：本包依赖 `torch>=2.3.1,<2.4`。若要 CUDA/ROCm 版本，先按 PyTorch 官方指引安装对应 `torch` / `torchvision`，再安装本包，或使用 `pip install fashion-image-search --no-deps` 后自行补齐依赖。

**Q：没有 GPU 能跑吗？**
A：能。`device` 默认 `auto`，无 GPU 自动回退 CPU。中小数据量（< 100 万）下 CPU + FAISS Flat 已足够。

**Q：检索结果为空？**
A：检查 `min_similarity`（默认 0.7，偏高）——调低或设为 `0` 再看；确认目标图片已入库（`GET /health` 看 `vision_index`）。

**Q：AI 增强检索没有返回 AI 结果？**
A：AI 未配置或调用失败时会降级为纯视觉（结果带 `ai_failed: true`）。检查 `ai.api_key` 是否有效、`search.enable_ai_enhance` 是否为 `true`；`ai.concurrency` 过大可能触发接口限流（建议 2~8）。

**Q：索引和原图存在哪？**
A：默认在 `~/.fashion-search/data/` 下：`wardrobe.db`（元数据）、`garments/`（原图）、`vector_index/`（向量集合，由 WAL 自动持久化）。检索结果里的 `image_path` 即原图路径，也可用 `GET /image/{id}` 获取。

**Q：服务重启后数据还在吗？**
A：在。元数据在 SQLite，向量由 ZVec WAL 落盘。即使索引文件丢失，启动时会根据数据库记录与已存原图自动重建索引。
