Smart AI Curator
An archive becomes a body of work.
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
Relationships between images
Visual embeddings reveal relationships between frames, while similarity helps refine a selection.
From archive to series
Collections connect photographs to the narrative and sequence chosen by the author.
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.

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


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.



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.




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.



