AI-powered architectural image analysis and generation tool. Upload a photo of a building or interior, get a structured analysis via Google Gemini vision, then generate styled variations using Gemini's native image generation.
- Framework: Next.js 16 (App Router) with React 19 and TypeScript
- AI: Google Gemini API (
gemini-2.5-flashfor analysis,gemini-2.5-flash-imagefor generation) - Database: PostgreSQL via
@vercel/postgres - Storage: Cloudflare R2 (primary) or Vercel Blob (fallback)
- Cache: Upstash Redis (optional, falls back to in-memory)
- UI: Tailwind CSS v4 + shadcn/ui + Framer Motion
- Deployment: Vercel
- Upload an architectural photo (building, interior, exterior)
- Analyze — Gemini vision extracts structured metadata: style, building type, materials, lighting, camera angle, color palette, spatial elements
- Generate — Combine the analysis with style presets (15 available: Editorial Luxury, Soft Minimal, Cinematic Mood, etc.) and custom prompts to generate new architectural images
- Projects — Analyses and generations are saved to projects in Postgres for later reference
- Node.js 18+
- A Google AI Studio API key
- A Cloudflare R2 bucket or a Vercel Blob store
- A PostgreSQL database (optional — app works without it, but no project persistence)
git clone https://github.com/mien-bot/exp-banana-clean.git
cd exp-banana-clean
npm installCopy the example env file and fill in your keys:
cp .env.example .env.localnpm run devThe app will be available at http://localhost:3000.
| Variable | Description |
|---|---|
GOOGLE_API_KEY |
Your Google AI Studio API key. Get one at aistudio.google.com. Used for both image analysis (vision) and image generation endpoints. |
The app needs somewhere to store uploaded originals and generated images. Choose one of:
| Variable | Description |
|---|---|
R2_ACCOUNT_ID |
Your Cloudflare account ID. Found in the Cloudflare dashboard under R2 > Overview. |
R2_ACCESS_KEY_ID |
R2 API token access key. Create one in R2 > Manage R2 API Tokens. |
R2_SECRET_ACCESS_KEY |
R2 API token secret key. Shown once when you create the token. |
R2_BUCKET |
Name of your R2 bucket (e.g. exb-uploads). Create one in R2 > Create bucket. |
R2_PUBLIC_BASE_URL |
Public URL for your bucket. Set up a custom domain or use the R2.dev subdomain under R2 > your bucket > Settings > Public access. Example: https://cdn.yourdomain.com |
R2_ENDPOINT |
(Optional) Custom S3-compatible endpoint. Auto-derived from account ID if not set. |
| Variable | Description |
|---|---|
BLOB_READ_WRITE_TOKEN |
Your Vercel Blob read-write token. Create a Blob store in your Vercel project dashboard under Storage > Create > Blob. |
| Variable | Description |
|---|---|
STORAGE_PROVIDER |
(Optional) Force a specific provider: cloudflare_r2 or vercel_blob. If unset, auto-detects based on which env vars are present (R2 takes priority). |
Without Postgres, the app still works for one-off analysis and generation — you just lose project persistence and the usage ledger.
| Variable | Description |
|---|---|
POSTGRES_URL |
PostgreSQL connection string. On Vercel, create a Postgres store under Storage > Create > Postgres and the env vars are auto-injected. For external providers (Neon, Supabase, Railway, etc.), use the pooled connection string. Example: postgres://user:pass@host:5432/dbname?sslmode=require |
The database schema is created automatically on the first API call — no manual migrations needed.
Tables created:
projects— user projects (grouped by session)analyses— Gemini vision analysis results (JSONB)generations— generated images with prompts usedusage_events— request ledger tracking tokens, costs, and rate limit hits
Used for distributed rate limiting and analysis caching in production. Falls back to in-memory if not configured.
| Variable | Description |
|---|---|
UPSTASH_REDIS_REST_URL |
Upstash Redis REST API URL. Create a database at console.upstash.com. |
UPSTASH_REDIS_REST_TOKEN |
Upstash Redis REST API token. Found on your database details page. |
| Variable | Description |
|---|---|
SITE_PASSWORD |
(Optional) Password-protects the entire site. Users see a login form and get a 30-day auth cookie. Leave unset for public access. |
GENERATE_ACCESS_CODE |
(Optional) Bypass code for the per-IP generation cap (5 free generations per IP). Users who enter this code get unlimited generations. |
USAGE_API_TOKEN |
(Optional) Bearer token to protect the GET /api/usage endpoint. If unset, the endpoint is open. |
| Variable | Default | Description |
|---|---|---|
ANALYZE_RATE_LIMIT_PER_MINUTE |
10 | Max analysis requests per minute per identity |
GENERATE_RATE_LIMIT_PER_MINUTE |
6 | Max generation requests per minute per identity |
UPLOAD_RATE_LIMIT_PER_MINUTE |
20 | Max upload requests per minute per identity |
ANALYZE_MAX_IMAGE_BYTES |
5 MB | Max image size for analysis |
GENERATE_MAX_IMAGE_BYTES |
8 MB | Max image size for generation |
MAX_UPLOAD_SIZE_BYTES |
10 MB | Max file size for uploads |
ANALYZE_CACHE_TTL_SECONDS |
43200 | Analysis cache duration (12 hours) |
GENERATE_MAX_PROMPT_CHARS |
4000 | Max prompt length |
ANALYZE_DAILY_CAP_GLOBAL |
1000 | Global daily analysis limit |
ANALYZE_DAILY_CAP_PER_IDENTITY |
150 | Per-user daily analysis limit |
GENERATE_DAILY_CAP_GLOBAL |
400 | Global daily generation limit |
GENERATE_DAILY_CAP_PER_IDENTITY |
80 | Per-user daily generation limit |
UPLOAD_DAILY_CAP_GLOBAL |
5000 | Global daily upload limit |
UPLOAD_DAILY_CAP_PER_IDENTITY |
100 | Per-user daily upload limit |
| Endpoint | Method | Description |
|---|---|---|
/api/analyze |
POST | Analyze an image with Gemini vision |
/api/generate |
POST | Generate a new image with Gemini |
/api/uploads/original |
POST | Upload an original image to storage |
/api/download |
GET | Proxy image downloads (bypasses CORS) |
/api/projects |
GET/POST | List or create projects |
/api/projects/[id] |
GET | Get a project with its analyses and generations |
/api/usage |
GET | View usage metrics and event ledger |
/api/login |
POST | Authenticate with site password |
npm run dev # Start dev server
npm run build # Production build
npm start # Start production server
npm run typecheck # TypeScript type checking- Push the repo to GitHub
- Import the repo in vercel.com/new
- Add your environment variables in the Vercel project settings
- Vercel auto-detects Next.js — deploy triggers on push to
main
For Postgres and Blob storage, you can create them directly in the Vercel dashboard under Storage and the env vars will be auto-linked.