Generate high-resolution AI images using free Kaggle GPUs β not the paid API needed.
Model: Lykon/dreamshaper-xl-v2-turbo (Stable Diffusion XL Turbo)
- Overview
- Features
- Architecture
- Folder Structure
- Local Setup
- Environment Variables
- Kaggle Setup
- Supabase Setup
- Deploy to Vercel (Frontend)
- Deploy to Railway (Backend)
- API Reference
- Aspect Ratios
- Troubleshooting
Studio AI solves one problem: AI image generation is the expensive tool. Tools like the DALL-E, Midjourney, and Stability AI all cost money.
This project uses Kaggle's free GPU tier (T4 / P100, 30 hrs/week) to run Stable Diffusion XL in cloud. You type a prompt in the browser, click Generate, and the system:
- Injects your prompt & resolution into the Kaggle script
- Pushes it to Kaggle and triggers a GPU kernel
- Polls until done (~1β3 min), downloads the PNG
- Uploads to Supabase Storage for permanent access
- Displays the result in the browser
| Feature | Details |
|---|---|
| π Free GPU | Kaggle Tesla T4 provide 30 hrs/week at zero cost |
| π¨ Studio UI | Dark-mode, glassmorphism, smooth animations |
| π 6 Aspect Ratios | Square, Wide, Classic, Portrait, Story, Cinema |
| π² Surprise Me | 10 built-in creative prompt suggestions |
| π Live Status | Real-time polling β shows elapsed time while GPU runs |
| βοΈ Auto-Save | Every image uploaded to Supabase Storage automatically |
| β¬οΈ Download | One-click download from toolbar after generation |
| π Manual Fetch | Force-download latest kernel output any time |
| π Retry Logic | Auto-retries download 3Γ before reporting failure |
flowchart TD
A[Browser\nDesign/index.html] -->|POST /generate| B[Flask Backend\nmain.py β Railway]
B --> C[Prompt/prompt.py\nInject prompt into kaggle.py]
C --> D[inject_size\nInject width & height into kaggle.py]
D --> E[Kaggle/trigger.py\nkaggle kernels push -p Kaggle]
E --> F[Kaggle GPU Kernel\nkaggle.py β DreamShaper XL]
F -->|ZIP output| G[poll_then_download\nEvery 15s poll status]
G -->|PNG| H[Supabase Storage\nImg Store bucket]
H -->|/image/name| A
A -->|GET /status every 3s| B
AI-Img-Generator/
βββ main.py # Flask backend β all API routes & pipeline logic
βββ requirements.txt # Python dependencies
βββ .env # Secret keys (never commit!)
βββ .gitignore # Excludes .env
βββ patch_index.py # One-time patch: adds Download button to UI
βββ fix_layout.py # One-time patch: fixes image canvas layout
β
βββ Design/
β βββ index.html # Full Studio AI frontend (dark UI)
β βββ vercel.json # Vercel deployment config
β βββ output/ # Local image cache (auto-created)
β
βββ Prompt/
β βββ prompt.json # Active prompt + size (auto-written by backend)
β βββ prompt.py # Injects prompt into Kaggle/kaggle.py
β
βββ Kaggle/
βββ kaggle.py # Script that runs ON Kaggle GPU (SDXL model)
βββ trigger.py # Pushes kaggle.py and triggers execution
βββ store.py # Standalone: manual download + Supabase upload
βββ kernel-metadata.json # Kernel config (ID, GPU enabled, internet on)
- Python 3.10+
- Kaggle account + API key
- Supabase account (free tier)
# 1. Clone
git clone https://github.com/YOUR_USERNAME/AI-Img-Generator.git
cd AI-Img-Generator
# 2. Virtual environment
python -m venv venv
venv\Scripts\activate # Windows
# source venv/bin/activate # macOS/Linux
# 3. Install dependencies
pip install -r requirements.txt
# 4. Create .env file (see Environment Variables section)
# 5. One-time UI patches (run once after cloning)
python patch_index.py
python fix_layout.py
# 6. Run
python main.pyCreate .env in the project root:
KAGGLE_USERNAME=your_kaggle_username
KAGGLE_KEY=your_kaggle_api_key
SUPABASE_URL=https://YOUR_PROJECT_ID.supabase.co
SUPABASE_KEY=your_supabase_service_role_key
SUPABASE_BUCKET=Img Store| Variable | Required | Note |
|---|---|---|
KAGGLE_USERNAME |
β | Your Kaggle username |
KAGGLE_KEY |
β | Kaggle API key |
SUPABASE_URL |
β | Supabase project URL |
SUPABASE_KEY |
β | Service role key β NOT the anon key |
SUPABASE_BUCKET |
Optional | Default: Img Store |
β οΈ Use the service_role key β the anon key is blocked by RLS for uploads.
- Sign up at kaggle.com (free)
- Account β Settings β API β Create New Token β copy
usernameandkeyto.env - Create a new notebook at kaggle.com/code:
- Name it
img-generator - Enable GPU accelerator
- Enable Internet access
- Run it once manually to register the kernel slot
- Name it
- Edit
Kaggle/kernel-metadata.json:
{
"id": "YOUR_KAGGLE_USERNAME/img-generator",
"title": "Img Generator",
"code_file": "kaggle.py",
"language": "python",
"kernel_type": "script",
"is_private": true,
"enable_gpu": true,
"enable_internet": true,
"dataset_sources": []
}- Verify:
kaggle kernels list --mine
- Create a project at supabase.com (free tier)
- Go to Settings β API and copy:
- Project URL β
SUPABASE_URL - service_role secret β
SUPABASE_KEY
- Project URL β
- Go to Storage β New Bucket:
- Name:
Img Store - Visibility: Public (required for browser display)
- Name:
Vercel hosts the static Design/ folder.
- Push your code to GitHub
- Go to vercel.com β New Project β Import repo
- Root Directory: set to
Design - Framework: Other
- Click Deploy
The Design/vercel.json is already configured β no changes needed:
{
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }],
"headers": [{
"source": "/(.*)",
"headers": [
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "X-Frame-Options", "value": "DENY" }
]
}]
}After deploy, update the backend URL in Design/index.html:
const API_BASE = "https://your-backend.railway.app";Railway runs main.py 24/7.
- Go to railway.app β New Project β Deploy from GitHub
- Select your repository
- Add environment variables in Variables tab (all from
.env) - Create a
Procfilein the project root:
web: gunicorn main:app --bind 0.0.0.0:$PORT --workers 1 --timeout 120
Use
--workers 1β the pipeline state is stored in memory; multiple workers will lose state.
- In
main.py, add your Vercel URL to CORS:
CORS(app, origins=[
"https://your-app.vercel.app",
r"https://.*\.vercel\.app",
"http://localhost:5000",
])- Railway generates your backend URL under Settings β Networking β Generate Domain
| Method | Endpoint | Description |
|---|---|---|
GET |
/ |
Serves index.html frontend |
POST |
/generate |
Starts image generation pipeline |
GET |
/status |
Current pipeline state (browser polls this) |
GET |
/surprise |
Returns a random prompt |
GET |
/last-image |
Most recently generated image URL |
POST |
/fetch-now |
Force-download latest Kaggle output |
POST |
/reset |
Reset pipeline to idle |
GET |
/image/<name> |
Proxy image from Supabase |
GET |
/download/<name> |
Download image as attachment |
POST /generate body:
{ "prompt": "A futuristic city at golden hour", "ratio": "16:9 Wide" }GET /status response:
{ "status": "waiting", "message": "Kaggle GPU rendering... 1m 30s elapsed", "image": null }Status values: idle β running β waiting β done / error
| Name | Resolution | Best For |
|---|---|---|
| 1:1 Square | 1024 Γ 1024 | Instagram posts |
| 16:9 Wide | 1920 Γ 1080 | YouTube / wallpapers |
| 4:3 Classic | 1440 Γ 1080 | Photography / blogs |
| 3:4 Portrait | 1080 Γ 1440 | |
| 9:16 Story | 1080 Γ 1920 | Instagram / TikTok Stories |
| 21:9 Cinema | 2560 Γ 1080 | Ultra-wide wallpapers |
The backend auto-calculates an optimal ~1MP generation size for SDXL, then upscales to the exact target using LANCZOS resampling.
Kernel error on Kaggle
- Check kernel logs at kaggle.com/code
- Ensure
"enable_internet": trueinkernel-metadata.json
Timed out (15 min)
- Click Fetch Image β if the kernel finished it will still download
- Or run
python Kaggle/store.pyto download manually
SUPABASE_KEY error
- Use the service_role key from Supabase Settings β API, not the anon key
PROMPT_START marker missing
- Restore these markers manually at the top of
Kaggle/kaggle.py:
# <<PROMPT_START>> auto-injected by Prompt/prompt.py - do not edit manually
CURRENT_PROMPT = """your test prompt here"""
# <<PROMPT_END>>
# <<SIZE_START>> auto-injected by app.py - do not edit manually
TARGET_WIDTH = 1024
TARGET_HEIGHT = 1024
# <<SIZE_END>>CORS error in browser
- Add your Vercel URL to the
CORS(app, origins=[...])list inmain.pyand redeploy
kaggle not found on Railway
- It installs from
requirements.txtautomatically - Railway reads
KAGGLE_USERNAME/KAGGLE_KEYenv vars β nokaggle.jsonfile needed
git checkout -b feature/your-feature
# make changes, test with: python main.py
git commit -m "Add your feature"
git push origin feature/your-feature
# open a Pull RequestIdeas: negative prompts Β· batch generation Β· image history gallery Β· FLUX / SDXL Lightning support Β· mobile layout
MIT License β Made with free Kaggle GPUs β