Spaces:
Running
title: PixelPilotAI
emoji: π·
colorFrom: purple
colorTo: blue
sdk: docker
pinned: false
Photo Editing Recommendation Agent
Recommend global photo edits by retrieving similar expert-edited examples (MITβAdobe FiveK), aggregating Expert A recipes, and applying them deterministically. This repo is structured so dataset β embeddings β vector DB and the inference API + LLM can be developed in parallel and merged cleanly.
Project layout (merge-ready)
PhotoEditor/
βββ .env # Copy from .env.example; set FIVEK_SUBSET_SIZE, Azure Search, etc.
βββ .env.example
βββ requirements.txt
βββ photo_editor/ # Core package (shared by pipeline and future API)
β βββ config/ # Settings from env (paths, Azure, subset size)
β βββ dataset/ # FiveK paths, subset selection (filesAdobe.txt)
β βββ lrcat/ # Lightroom catalog: Expert A recipe extraction
β βββ images/ # DNG β RGB (rawpy, neutral development)
β βββ embeddings/ # CLIP image embeddings (index + query)
β βββ vector_store/ # Azure AI Search index (upload + search)
βββ scripts/
β βββ build_vector_index.py # Build vector index: subset β embed β push to Azure
βββ fivek_dataset/ # MITβAdobe FiveK (file lists, raw_photos/, fivek.lrcat)
βββ LLM.py # Existing Azure GPT-4o explanation layer (to be wired to RAG)
βββ api/ # (Future) FastAPI: /analyze-image, /apply-edits, /edit-and-explain
- Inference merge: The API will use
photo_editor.vector_store.AzureSearchVectorStorefor retrieval,photo_editor.embeddingsfor query embedding, andLLM.py(or a movedphoto_editor.llm) for explanations. Apply-edits will use a separate editing engine (OpenCV/Pillow) consumingEditRecipefromphoto_editor.lrcat.schema.
Dataset β Vector DB (this slice)
- Subset: First
FIVEK_SUBSET_SIZEimages fromfivek_dataset/filesAdobe.txt(default 500; set in.env). - Edits: Expert A only; recipes read from
fivek.lrcat(virtual copy "Copy 1"). - Embeddings: Original DNG β neutral development β RGB β CLIP (
openai/clip-vit-base-patch32). - Vector DB: Azure AI Search index (created if missing); each document =
id,image_id,embedding,recipe(JSON).
Setup
cp .env.example .env
# Edit .env: FIVEK_SUBSET_SIZE (e.g. 500), AZURE_SEARCH_*, optional paths
pip install -r requirements.txt
Build the index
From the project root:
PYTHONPATH=. python scripts/build_vector_index.py
- Requires the FiveK
raw_photosfolder (DNGs +fivek.lrcat) underfivek_dataset/. - If Azure Search is not configured in
.env, the script still runs and skips upload (prints a reminder).
How to run things
All commands below assume you are in the project root (PhotoEditor/) and have:
- created and edited
.env(see config table below), and - installed dependencies:
pip install -r requirements.txt
Deploy (Streamlit Cloud + Hugging Face Spaces)
For cloud deploy, keep the repo minimal and include only runtime files:
app.pyphoto_editor/requirements.txt.streamlit/config.toml.env.example(template only, no secrets)
Do not commit local artifacts or large datasets (fivek_dataset/, renders/, generated images/html/json, .env).
Streamlit Community Cloud
- Push this repo to GitHub.
- In Streamlit Cloud, create a new app from the repo.
- Set the app file path to
app.py. - Add required secrets in the app settings (same keys as in
.env.example, e.g.AZURE_SEARCH_*,AZURE_OPENAI_*). - Deploy.
Hugging Face Spaces (Streamlit SDK)
- Create a new Space and choose Streamlit SDK.
- Point it to this repository (or push these files to the Space repo).
- Ensure
app.pyis at repo root andrequirements.txtis present. - Add secrets in Space Settings (same variables as
.env.example). - Launch the Space.
Optional automation: sync supported secrets from local .env directly to your Space:
pip install huggingface_hub
HF_TOKEN=hf_xxx python scripts/sync_hf_secrets.py --space-id <username/space-name>
Hugging Face Spaces (Docker SDK)
This repo now includes a production-ready Dockerfile that serves the app on port 7860.
- Create a new Space and choose Docker SDK.
- Push this repository to that Space.
- In Space Settings, add secrets (or sync them later with
scripts/sync_hf_secrets.py). - Build and launch the Space.
Local Docker test:
docker build -t lumigrade-ai .
docker run --rm -p 7860:7860 --env-file .env lumigrade-ai
1. Run the Streamlit UI (full app)
Interactive app to upload an image (JPEG/PNG) or point to a DNG on disk, then run the full pipeline and see original vs edited plus the suggested edit parameters.
streamlit run app.py
This will:
- Check Azure Search + Azure OpenAI config from
.env. - For each run: retrieve similar experts β call LLM for summary + suggested edits β apply edits (locally or via external API) β show before/after.
2. Run the full pipeline from the terminal
Run the same pipeline as the UI, but from the CLI for a single image:
python scripts/run_pipeline.py <image_path> [--out output.jpg] [--api] [-v]
Examples:
# Run pipeline locally, save to result.jpg, print summary + suggested edits
python scripts/run_pipeline.py photo.jpg --out result.jpg -v
# Run pipeline but use an external editing API (requires EDITING_API_URL in .env)
python scripts/run_pipeline.py photo.jpg --out result.jpg --api -v
What -v prints:
- π Summary of what the LLM thinks should be done.
- π Suggested edits: the numeric recipe (exposure, contrast, temp, etc.) coming from Azure OpenAI for that image.
- π Expert used: which FiveK expert image/recipe was used as reference.
3. Just retrieve similar experts (no LLM / no edits)
If you only want to see which FiveK images are closest to a given photo and inspect their stored recipes:
python scripts/query_similar.py <image_path> [--top-k 50] [--top-n 5]
Examples:
# Show the best 5 expert matches (default top-k=50 search space)
python scripts/query_similar.py photo.jpg --top-n 5
# Show only the single best match
python scripts/query_similar.py photo.jpg --top-n 1
Output:
- Ranks (
1.,2., β¦), image_ids, rerank scores. - The stored Expert A recipe JSON for each match.
4. Get the exact Expert A recipe for a FiveK image
Given a FiveK image_id (with or without extension), extract the Expert A recipe directly from the Lightroom catalog:
python scripts/get_recipe_for_image.py <image_name> [-o recipe.json]
Examples:
# Print the recipe as JSON
python scripts/get_recipe_for_image.py a0001-jmac_DSC1459
# Save the recipe to a file
python scripts/get_recipe_for_image.py a0001-jmac_DSC1459 -o my_recipe.json
5. Apply a custom (LLM) recipe to a FiveK image
If you already have a JSON recipe (for example, something you crafted or got from the LLM) and want to apply it to a FiveK RAW image using the same rendering pipeline:
python scripts/apply_llm_recipe.py <image_id> <recipe.json> [--out path.jpg]
Example:
python scripts/apply_llm_recipe.py a0059-JI2E5556 llm_recipe_a0059.json --out renders/a0059-JI2E5556_LLM.jpg
This will:
- Load the DNG for
<image_id>. - Use
dng_to_rgb_normalizedto bake in exposure/brightness from the recipe. - Apply the rest of the recipe (contrast, temperature, etc.) on top of the original Expert A baseline.
- Save the rendered JPEG.
Config (.env)
| Variable | Description |
|---|---|
FIVEK_SUBSET_SIZE |
Number of images to index (default 500). |
FIVEK_LRCAT_PATH |
Path to fivek.lrcat (default: fivek_dataset/raw_photos/fivek.lrcat). |
FIVEK_RAW_PHOTOS_DIR |
Root of range folders (e.g. HQa1to700, β¦). |
AZURE_SEARCH_ENDPOINT |
Azure AI Search endpoint URL. |
AZURE_SEARCH_KEY |
Azure AI Search admin key. |
AZURE_SEARCH_INDEX_NAME |
Index name (default fivek-vectors). |
License / data
See fivek_dataset/LICENSE.txt and related notices for the MITβAdobe FiveK dataset.