Metadata-Version: 2.4
Name: visualmatch
Version: 2.0.0
Summary: AI-powered visual product search engine using OpenAI CLIP. Supports Instagram Direct bot integration via NovinHub webhooks.
Project-URL: Homepage, https://github.com/your-org/visualmatch
Project-URL: Documentation, https://github.com/your-org/visualmatch/tree/main/docs
Project-URL: Repository, https://github.com/your-org/visualmatch
Project-URL: Issues, https://github.com/your-org/visualmatch/issues
Project-URL: Changelog, https://github.com/your-org/visualmatch/blob/main/CHANGELOG.md
Author: VisualMatch Contributors
License: MIT
License-File: LICENSE
Keywords: clip,computer-vision,fastapi,image-similarity,instagram-bot,product-search,pytorch,visual-search
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Scientific/Engineering :: Image Recognition
Requires-Python: >=3.10
Requires-Dist: fastapi>=0.110.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: numpy>=1.24.0
Requires-Dist: pillow>=10.0.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: python-multipart>=0.0.9
Requires-Dist: requests>=2.31.0
Requires-Dist: uvicorn[standard]>=0.28.0
Provides-Extra: all
Requires-Dist: httpx>=0.27.0; extra == 'all'
Requires-Dist: mypy>=1.10.0; extra == 'all'
Requires-Dist: openpyxl>=3.1.0; extra == 'all'
Requires-Dist: pandas>=2.0.0; extra == 'all'
Requires-Dist: pre-commit>=3.7.0; extra == 'all'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'all'
Requires-Dist: pytest-cov>=5.0.0; extra == 'all'
Requires-Dist: pytest>=8.0.0; extra == 'all'
Requires-Dist: ruff>=0.5.0; extra == 'all'
Requires-Dist: torch>=2.0.0; extra == 'all'
Requires-Dist: transformers>=4.38.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: mypy>=1.10.0; extra == 'dev'
Requires-Dist: pre-commit>=3.7.0; extra == 'dev'
Requires-Dist: ruff>=0.5.0; extra == 'dev'
Provides-Extra: import
Requires-Dist: openpyxl>=3.1.0; extra == 'import'
Requires-Dist: pandas>=2.0.0; extra == 'import'
Provides-Extra: ml
Requires-Dist: torch>=2.0.0; extra == 'ml'
Requires-Dist: transformers>=4.38.0; extra == 'ml'
Provides-Extra: test
Requires-Dist: httpx>=0.27.0; extra == 'test'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'test'
Requires-Dist: pytest-cov>=5.0.0; extra == 'test'
Requires-Dist: pytest>=8.0.0; extra == 'test'
Description-Content-Type: text/markdown

<h1 align="center">
  🔍 VisualMatch
</h1>

<p align="center">
  <strong>AI-powered visual product search engine using OpenAI CLIP</strong>
</p>

<p align="center">
  <a href="https://github.com/your-org/visualmatch/actions/workflows/ci.yml">
    <img src="https://github.com/your-org/visualmatch/actions/workflows/ci.yml/badge.svg" alt="CI">
  </a>
  <a href="LICENSE">
    <img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT">
  </a>
  <a href="https://www.python.org/downloads/">
    <img src="https://img.shields.io/badge/python-3.10%2B-blue.svg" alt="Python 3.10+">
  </a>
</p>

<p align="center">
  Upload a product photo → get the matching item with a purchase link, instantly.
</p>

---

## ✨ What It Does

VisualMatch uses **OpenAI CLIP** (`openai/clip-vit-base-patch32`) to match user-uploaded product photos against an e-commerce catalog. It integrates with **Instagram Direct** via [NovinHub](https://novinhub.com) webhooks, enabling customers to find and buy products directly from DMs.

**Key features:**

- 🧠 **Real CLIP embeddings** — 512-dimensional vectors, cosine similarity search
- 📸 **Instagram DM bot** — Conversational visual search via NovinHub webhooks
- ⚡ **<100ms search latency** — Brute-force vector search over pre-computed embeddings
- 🌐 **Web dashboard** — Built-in admin UI for catalog management and search testing
- 🐳 **Docker ready** — One-command deployment with Docker Compose
- 🔌 **Extensible** — Fan-out webhook router supports multiple bot services

## 🏗️ Architecture

```
visualmatch/
├── app/                          # Application package
│   ├── main.py                   # FastAPI server & webhook handler
│   ├── config.py                 # Environment-driven configuration
│   ├── models/                   # Pydantic data models
│   │   └── webhook.py
│   └── services/                 # Core business logic
│       ├── clip_engine.py        # CLIP embedding extraction
│       ├── catalog_service.py    # Vector search over catalog
│       └── novinhub_client.py    # NovinHub API client
├── scripts/                      # Data pipeline utilities
│   ├── generate_live_catalog.py  # Fetch products from live API
│   └── import_products.py        # Import from Excel spreadsheet
├── tests/                        # Pytest test suite
├── web/                          # Web dashboard (HTML/CSS/JS)
├── docs/                         # Documentation
│   ├── architecture.md           # System design & diagrams
│   └── api.md                    # API reference
├── pyproject.toml                # Python project configuration
├── Dockerfile                    # Multi-stage container build
├── docker-compose.yml            # Container orchestration
├── Makefile                      # Development commands
└── .github/workflows/ci.yml     # CI pipeline
```

> See [docs/architecture.md](docs/architecture.md) for detailed system diagrams and component documentation.

## 🚀 Quick Start

### Prerequisites

- Python 3.10+
- (Optional) [Docker](https://docs.docker.com/get-docker/)

### Local Setup

```bash
# Clone the repository
git clone https://github.com/your-org/visualmatch.git
cd visualmatch

# Create virtual environment
python3 -m venv venv
source venv/bin/activate

# Install dependencies
make install
# Or manually: pip install -e ".[ml,import]"

# Configure environment
cp .env.example .env
# Edit .env — at minimum, set HF_TOKEN for CLIP model access

# Generate the product catalog (fetches from your API + computes embeddings)
make catalog-generate

# Start the server
make dev
```

The server starts at **http://localhost:8000**:
- 📖 API docs: http://localhost:8000/docs
- 🖥️ Web dashboard: http://localhost:8000/web/

### Docker

```bash
cp .env.example .env
# Edit .env with your settings

docker compose up --build
```

## 📡 Webhook Setup

To connect with Instagram Direct via NovinHub:

1. Create a [NovinHub](https://novinhub.com) account and connect your Instagram Business page
2. Set your webhook URL to: `https://your-domain.com/api/v1/novinhub-webhook`
3. Configure your `.env` file:
   ```
   NOVINHUB_TOKEN=your_novinhub_api_token
   NOVINHUB_CHANNEL_ID=your_channel_id
   NOVINHUB_ACCOUNT_OWNER_ID=your_instagram_social_user_id
   ```
4. Set up an **Icebreaker button** in NovinHub with payload `FIND_MODEL`

## 🔧 Catalog Generation

The system needs a product catalog with pre-computed CLIP embeddings. Two methods are available:

### From Live API (Recommended)

Fetches products from your e-commerce API, downloads product images, and computes CLIP embeddings:

```bash
make catalog-generate
# Or: python -m scripts.generate_live_catalog
```

> **Note:** You'll need to update the API URLs in `scripts/generate_live_catalog.py` to point to your own product API.

### From Excel Spreadsheet

Place your product Excel file in `data/` and run:

```bash
make catalog-import
# Or: python -m scripts.import_products
```

**Excel format** — Required columns:
| Column | Description |
|---|---|
| `شناسه محصول` | Product ID |
| `نام محصول` | Product name |
| `نام فارسی برند` | Brand name (Persian) |
| `نام انگلیسی برند` | Brand name (English) |
| `دسته بندی` | Category |
| `قیمت اولیه` | Price (Rials) |

## ⚙️ Configuration

All configuration is managed through environment variables. See [`.env.example`](.env.example) for the complete list.

| Variable | Default | Description |
|---|---|---|
| `HF_TOKEN` | — | Hugging Face API token (for model download) |
| `CLIP_MODEL_NAME` | `openai/clip-vit-base-patch32` | CLIP model to use |
| `MATCH_THRESHOLD` | `0.70` | Minimum similarity for a match (0.0–1.0) |
| `FALLBACK_PRODUCT_URL` | — | Default product URL when no match is found |
| `NOVINHUB_TOKEN` | — | NovinHub API token |
| `NOVINHUB_ACCOUNT_OWNER_ID` | — | Your Instagram social_user_id |
| `AUTO_REPLY_ENABLED` | `true` | Auto-reply via NovinHub |
| `LOG_LEVEL` | `INFO` | Python logging level |

## 🧪 Testing

```bash
# Run full test suite
make test

# With coverage
make test-cov

# Lint & type check
make lint
```

## 📖 API Reference

Full API documentation is available at:
- **Interactive**: http://localhost:8000/docs (Swagger UI)
- **Static**: [docs/api.md](docs/api.md)

### Key Endpoints

| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/api/health` | System health check |
| `GET/POST` | `/api/v1/novinhub-webhook` | NovinHub webhook handler |
| `GET/POST` | `/api/novinhub/config` | Configuration management |
| `GET` | `/api/logs` | Activity logs |

## 🤝 Contributing

Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, code style, and the pull request process.

## 📄 License

This project is licensed under the [MIT License](LICENSE).
