Smart AI Curator

An archive becomes a body of work.

Visual search & AI curationPrivate product
The image archive and its collections.

The image archive and its collections.

The project

I designed and engineered the curation product end to end: the dashboard, visual and text embeddings, semantic retrieval, collections and the public portfolio. The system helps a photographer find relationships between images and shape a coherent selection.

My contribution

  • Product & interface
  • Visual embeddings
  • Semantic search
  • Curation & publishing
More on the engineering

An AI curator that reads a photographer's archive the way a critic would, finds the connections between frames, and turns a pile of good pictures into a coherent body of work. I built it for a working photographer sitting on hundreds of strong frames with no way to see how they fit together. I designed and engineered the whole thing end to end — the curation model, the retrieval, the chat where you steer a description instead of accepting whatever the AI first writes, and the two surfaces: a private dashboard where the work happens, and a public portfolio it generates on its own.

The Lana library — a grid of curated photographs, each with AI-generated metadata, ratings and collections
The library — the photographer's whole archive, read and made navigable.

Good frames, no through-line

It begins with a frustration any working photographer knows. You shoot constantly, and the individual frames are good — but good frames don't make a body of work. You sit with hundreds of strong images and can't see how they fit together: which ones belong in a set, what the through-line is, where one photograph answers another. The pictures are there. The connective tissue between them isn't.

So the system is built around one idea — read a photograph the way a person does (light, composition, mood, the small detail that holds you), turn that reading into something a machine can compare, and use it to surface the connections that stay invisible by hand. Group what belongs together. Sequence it. Build coherent sets out of a pile of good pictures.

"Svetlost kao materija koja istovremeno otkriva i skriva."— an actual description the system wrote for one frame
The inbox — drag-and-drop import that kicks off background AI analysis
It starts at the inbox. Drop a shoot in; the system analyzes, classifies, and embeds every frame in the background.
The timeline — the whole archive laid out by month as a dense mosaic
From there the whole archive becomes navigable — here, laid out by month as a single continuous mosaic.

How the system is put together

A monorepo with three deployable parts and a deliberate split between where heavy work runs and where the public experience is served: a React + Vite dashboard SPA and a generated portfolio SPA on Vercel, an Express Node API on Railway running analysis, embeddings, retrieval and discovery, and a data layer of SQLite (catalog + vectors), Cloudflare R2 (originals), and Vertex AI (models). One decision that paid off repeatedly: keeping the API a single long-lived Node process rather than serverless functions. Embedding a 20-photo batch, running k-means, holding an SSE progress stream open — these want a warm process and a real filesystem, not a cold function with a payload ceiling.

The AI / RAG backend

The interesting part is the retrieval-augmented loop at its center. "RAG" usually means stuffing text chunks into a prompt; here the retrieval space is visual, and the augmentation feeds both grouping and generation. Three layers stack up:

  • A · Reading — every photograph gets two embeddings: a 1408-dimensional multimodal vector of the image itself (Vertex multimodalembedding@001), and a text vector of a Gemini-written artistic analysis — lighting, composition, palette, mood, depth of field, technique. Two complementary coordinates per frame: how it looks, and how it is made.
  • B · Retrieval — "find more like this" becomes cosine similarity. The same trick powers semantic search: a text query embedded into the same space, so "quiet, backlit, lonely" surfaces frames no one ever tagged. Retrieval also drives discovery — k-means with silhouette scoring carves the archive into coherent clusters by sensibility.
  • C · Generation — clusters go back to Gemini with their member frames to be named and given a curatorial subtitle. The retrieval result becomes the context for generation — RAG in its purest form. The same model writes per-photo descriptions and assembles showcases.
A 3D point cloud of every photograph's embedding, clustered by aesthetic similarity and coloured by theme
The embedding space, made navigable in 3D — every point is a photograph, distance is aesthetic affinity, colour is the inferred theme. This is what retrieval and discovery actually move through.
A point selected in the 3D space — its photo opens with its nearest neighbours ranked by similarity
Select a point and retrieval runs live: the frame opens with its nearest neighbours — ranked by cosine similarity, scored as percentages — and a line drawn to each. Here a sunset pulls in its fellow golden hours.
AI-discovered collections, each named and given a curatorial subtitle by the model
Discovery's output — clusters the system found on its own, each named and described by the model. "Umbra Sculptura: a study of form revealed through dramatic light and shadow."

The feature I'm proudest of

You don't accept the AI's description — you argue with it. When it's off, you don't re-roll the whole thing; you chat with it ("less abstract, push the shadows"). It revises against the actual image, and on save it re-embeds, so the correction feeds future grouping.

Chatting with the AI to refine a photo's interpretive description
Describe, in dialogue. Argue with the description until it's right, then save and re-embed.
The full-screen Loupe viewer for inspecting a single photo with its AI metadata and a filmstrip
Loupe. A full-screen viewer for living with one frame — rate it, read its AI metadata, refine it, pick it for the portfolio.
A showcase opened — its photos, its model-written title and subtitle, and the description chat panel
Inside a showcase. Each set carries a model-written title and subtitle, editable in the same chat — loose affinity becomes a presentable body of work.
The duplicates view — near-identical frames paired with a similarity score for review
Duplicates. Embedding similarity surfaces near-identical frames as scored pairs, so culling a heavy shoot takes minutes instead of an afternoon.

It runs in production: the dashboard on one host, the API and its volume on another, images on object storage, models on Vertex. It analyzes, retrieves, clusters, and writes — and it gave a sprawling archive something it never had, a point of view. React · Node · Vertex AI · SQLite · Cloudflare R2 · Railway · Vercel.

Start a dialogue

Quiet correspondence preferred. For anything urgent — a voice call cuts through faster than a thread.

contact@jjovan.com

Banja Luka, Bosnia and Herzegovina · Open to contract work and full-time roles.

+387 65 461 922Download CV ↓LinkedIn ↗