A small, secured service that embeds any product photo into a 768-dimensional, L2-normalized vector. Store them once, then let shoppers search your catalogue with a single picture — cosine similarity in the same latent space.
Both workflows call this one service — powered by SigLIP 2 — so stored vectors and query vectors always live in the same latent space. Cosine similarity is just a dot product, because every vector is unit-normalized.
The API fetches each product image, embeds it, and upserts one row per image into product_embeddings. Re-runs are safe.
One call to /products/search embeds the query image and ranks every stored product by its closest image — so a product is returned at most once.
Every embedding route is guarded by X-API-Key. Only the health probe stays open.
Deploy behind a TLS-terminating proxy on a private network. Keys live in your secret manager; docs vanish in production.
Spin it up with uv, point it at your Postgres, and start embedding. The first launch caches the SigLIP 2 weights (~400 MB) locally.
Copy the env — set CLIP_API_KEYS and CLIP_ENVIRONMENT=development.
Sync & run — uv sync then uv run fastapi dev app/main.py.
Embed an image — POST it with your key and read back 768 floats.
Response: { model, dimensions: 768, embedding: [...] }
One microservice, one embedding space, a thousand product matches. Wire it into your Laravel API and let a photo do the searching.