Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Embr × Foundry — Image Gallery Sample

A small Python/FastAPI app that calls a Foundry-deployed image model (DALL-E 3 or GPT-Image-1) via the standard OpenAI SDK and shows the results in an interactive web gallery.

This is POC sample #8 in the Embr fleet. Its purpose is to surface a specific platform gap, not to be a production-ready image service.

What this demonstrates

  • A real Foundry image-generation deployment driven from an Embr-hosted app, using client.images.generate(...) against the OpenAI-compat /openai/v1 endpoint (works for both DALL-E 3 and GPT-Image-1).
  • A grid UI that lets a user type a prompt, generate 1–4 images at three aspect ratios, and delete them.
  • A clean separation between metadata (GET /api/images) and binary payload (GET /api/images/{id}.png) so the JSON wire format stays small even when the gallery contains many high-res images.

Embr platform findings (the whole point)

1. No blob / object-store binding

The biggest finding: embr.yaml has no way to declare persistent object storage. This sample keeps every generated image in process memory (collections.deque(maxlen=50)). When the Embr container restarts — deploy, scale-in, OOM, crash — every image is gone. The yellow banner at the top of the UI calls this out, and /api/store/info returns { "type": "in-memory", "restartLossWarning": true }.

Imagined fix:

storage:
  images:
    type: blob
    lifecycle: persistent

…where Embr would provision a storage account, inject the connection string / SAS URL via env var, and ideally expose a uniform SDK so apps don't have to import azure-storage-blob directly. Today the customer would have to BYO an Azure Storage account, add the connection string as a secret env var, and write the integration themselves — at which point they're back to solving infra problems instead of building the app.

2. No CDN / cached-asset primitive

Even with blob storage, an image gallery really wants a CDN-fronted public URL per asset. Today the customer would have to provision Azure Front Door or CloudFront themselves and wire it to their storage account. An Embr assets: primitive that returned a CDN URL for a blob would close this gap.

3. No quota / cost visibility

Image generation is expensive — easily $0.04–$0.12 per image. There's no Embr primitive today for declaring a per-app or per-user cost ceiling. A hypothetical quota: { dailyImages: 100 } would let an app fail fast before running up a bill.

4. In-memory base64 in JSON is fragile

A naive implementation would return b64_json directly in the POST /api/images response. With n=4 at 1792×1024 that's easily ~10 MB of JSON, which can blow past Embr's default ingress limits and is slow to parse client-side. We mitigate by storing the bytes in memory and serving them via a separate /api/images/{id}.png endpoint with Content-Type: image/png. This is a band-aid; native blob support (with CDN URLs) is the real answer.

Architecture

app/
├── foundry_image.py   # OpenAI SDK against Foundry /openai/v1, returns ImageRecord
├── store.py           # collections.deque(maxlen=50) — RAM-only by design
├── main.py            # FastAPI routes
└── static/index.html  # dark-theme gallery UI

API

Method Path Description
POST /api/images { prompt, n?, size? } → list of ImageRecord metadata + gallery size
GET /api/images Metadata only (no base64) for every image currently in memory
GET /api/images/{id}.png Raw PNG bytes
DELETE /api/images/{id} Remove one image from the gallery
GET /api/store/info { type: "in-memory", count, capacity, restartLossWarning: true }
GET /api/diag Foundry config status + store info
GET /health Liveness probe
GET / Gallery UI

Quickstart (local)

python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

export FOUNDRY_BASE_URL='https://<your-resource>.openai.azure.com/openai/v1'
export FOUNDRY_API_KEY='<your-key>'
export FOUNDRY_IMAGE_MODEL_DEPLOYMENT='gpt-image-1'   # or dall-e-3

uvicorn app.main:app --reload --port 8000

Then open http://localhost:8000.

If you pass a base URL without /openai/v1, the client appends it for you, so all of these work:

  • https://foo.openai.azure.com
  • https://foo.openai.azure.com/openai
  • https://foo.openai.azure.com/openai/v1

Foundry portal setup

  1. Open your Foundry project in the portal.
  2. Go to Models + endpoints → Deploy model and pick either gpt-image-1 or dall-e-3 (image-generation models — they appear in the "Image" filter).
  3. Give the deployment a name, e.g. gpt-image-1. Use this for FOUNDRY_IMAGE_MODEL_DEPLOYMENT.
  4. Open the deployment, copy the Endpoint (it'll look like https://<resource>.openai.azure.com/) and the API key. Use these for FOUNDRY_BASE_URL and FOUNDRY_API_KEY.

Note: DALL-E 3 only supports n=1 per call. The client silently clamps the count when the deployment name contains dall-e-3.

Deploy to Embr

embr quickstart deploy embr-devs/embr-foundry-image-gallery-sample -i 120233234
embr variables set FOUNDRY_BASE_URL='https://<resource>.openai.azure.com/openai/v1'
embr variables set FOUNDRY_API_KEY='<key>'
embr variables set FOUNDRY_IMAGE_MODEL_DEPLOYMENT='gpt-image-1'

Caveats

  • The gallery wipes on every container restart. This is not a bug — it's the entire point of this sample. See finding #1 above.
  • DALL-E 3 ignores n > 1; the app silently clamps.
  • Image generation latency is multiple seconds per image — be patient with the spinner.
  • Not suitable for production. Use as a demo / platform-finding artifact only.

About

Embr POC #8: Foundry image generation gallery (in-memory, surfaces no-blob-binding finding)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages