Skip to main content

gpt-image-playground

AI coding agent skill for GPT Image Playground — a React/TypeScript web app for OpenAI image generation and editing using gpt-image-1 and related APIs.

Zur Installation springen

Quellinformationen

Repository
reason-machines/trending-skills
Letzte Quellaktivität
27. April 2026 um 00:51
Erkannte Sprache von SKILL.md
Englisch
Sterne
82
Forks
15

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
gpt-image-playground
description
AI coding agent skill for GPT Image Playground — a React/TypeScript web app for OpenAI image generation and editing using gpt-image-1 and related APIs.
triggers
["set up gpt image playground","add image generation to my app","configure openai image editing tool","deploy gpt image playground with docker","integrate gpt-image-2 api in react","build image generation ui with openai","use responses api for image generation","customize gpt image playground settings"]
# GPT Image Playground > Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection. A React 19 + TypeScript + Vite web application for generating and editing images via OpenAI's Images API (`/v1/images`) or Responses API (`/v1/responses`). Features a responsive UI with waterfall task cards, IndexedDB local storage, PWA support, bulk selection, history management, and ZIP export/import. --- ## What It Does - **Text-to-image**: Generate images from prompts via `images/generations` or `responses` with `image_generation` tool - **Reference image editing**: Upload up to 16 reference images, call `images/edits` or multimodal Responses API - **Smart size selector**: Auto-calculates resolutions for 1K/2K/4K at common aspect ratios; custom sizes auto-snapped to 16px multiples, max 3840px, max ratio 3:1, pixel range 655360–8294400 - **Parameter control**: Quality (low/medium/high), format (PNG/JPEG/WebP), compression, moderation level - **History**: IndexedDB storage with SHA-256 image deduplication, bulk ops, favorites, search/filter - **Data portability**: ZIP export/import with raw image files + `manifest.json` --- ## Tech Stack | Layer | Technology | |-------|-----------| | Framework | React 19 + TypeScript | | Build | Vite | | Styling | Tailwind CSS 3 | | State | Zustand | | Storage | Browser IndexedDB API | --- ## Installation & Setup ### Prerequisites - Node.js 18+ - npm ### Clone and Run Locally ```bash git clone https://github.com/CookSleep/gpt_image_playground.git cd gpt_image_playground npm install npm run dev # Visit http://localhost:5173 ``` ### Environment Variables Create `.env.local` in the project root: ```bash # Optional: pre-fill default API URL at build time VITE_DEFAULT_API_URL=https://api.openai.com/v1 ``` ### Build for Production ```bash npm run build # Output in dist/ — deploy to any static file server ``` ### Docker ```bash # Single container docker run -d -p 8080:80 \ -e API_URL=https://api.openai.com/v1 \ ghcr.io/cooksleep/gpt_image_playground:latest # Docker Compose cat > docker-compose.yml << 'EOF' services: gpt-image-playground: image: ghcr.io/cooksleep/gpt_image_playground:latest environment: - API_URL=https://api.openai.com/v1 ports: - "8080:80" restart: unless-stopped EOF docker compose up -d ``` Update to latest: ```bash docker compose pull && docker compose up -d ``` --- ## Vercel One-Click Deploy [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FCookSleep%2Fgpt_image_playground&project-name=gpt-image-playground&repository-name=gpt-image-playground) Add environment variable in **Settings → Environment Variables**: ``` VITE_DEFAULT_API_URL=https://api.openai.com/v1 ``` --- ## API Configuration ### In-App Settings Open settings (top-right gear icon) and configure: | Field | Images API | Responses API | |-------|-----------|---------------| | Endpoint | `/v1/images/generations`, `/v1/images/edits` | `/v1/responses` | | Model example | `gpt-image-1` | `gpt-4o`, `gpt-5.5` | ### URL Query Parameters (Deep-link Config) Pre-fill settings via URL — useful for bookmarks or sharing: ``` https://gpt-image-playground.cooksleep.dev?apiUrl=https://your-proxy.com&apiKey=sk-xxxx https://cooksleep.github.io/gpt_image_playground?apiUrl=https://your-proxy.com&apiKey=sk-xxxx ``` Parameters: - `apiUrl` — API base URL - `apiKey` — OpenAI API key --- ## Local Development Proxy (CORS Bypass) When your API endpoint doesn't allow browser CORS, use the Vite dev proxy: ```bash cp dev-proxy.config.example.json dev-proxy.config.json ``` Edit `dev-proxy.config.json`: ```json { "enabled": true, "prefix": "/api-proxy", "target": "http://127.0.0.1:3000", "changeOrigin": true, "secure": false } ``` Request flow: ``` Browser → http://localhost:5173/api-proxy/v1/images/generations → Vite proxy forwards to → http://127.0.0.1:3000/v1/images/generations ``` **Note**: Proxy only works with `npm run dev`. Not included in production builds. Set `API URL` in the app settings to match `target`. The app rewrites matching requests to use the proxy prefix. > If `target` or `API URL` already includes `/v1`, the path won't be duplicated — requests become `/api-proxy/responses` not `/api-proxy/v1/responses`. --- ## Key Source Code Patterns ### Project Structure ``` src/ ├── components/ # React UI components ├── hooks/ # Custom React hooks ├── store/ # Zustand state stores ├── utils/ # Helpers (IndexedDB, image processing, etc.) ├── types/ # TypeScript type definitions └── main.tsx # App entry point ``` ### Using the Images API Directly (TypeScript) ```typescript // Pattern matching how the app calls OpenAI Images API async function generateImage(params: { prompt: string; model: string; size: string; quality: "low" | "medium" | "high"; n: number; outputFormat: "png" | "jpeg" | "webp"; outputCompression?: number; apiKey: string; apiUrl: string; }) { const response = await fetch(`${params.apiUrl}/images/generations`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${params.apiKey}`, }, body: JSON.stringify({ model: params.model, prompt: params.prompt, n: params.n, size: params.size, quality: params.quality, output_format: params.outputFormat, ...(params.outputFormat !== "png" && { output_compression: params.outputCompression, }), }), }); if (!response.ok) { const error = await response.json(); throw new Error(error.error?.message ?? "Generation failed"); } return response.json(); } ``` ### Using the Images Edit API with Reference Images ```typescript async function editImage(params: { prompt: string; images: File[]; model: string; size: string; quality: "low" | "medium" | "high"; n: number; apiKey: string; apiUrl: string; }) { const formData = new FormData(); formData.append("model", params.model); formData.append("prompt", params.prompt); formData.append("n", String(params.n)); formData.append("size", params.size); formData.append("quality", params.quality); // Up to 16 reference images params.images.forEach((file) => { formData.append("image[]", file); }); const response = await fetch(`${params.apiUrl}/images/edits`, { method: "POST", headers: { Authorization: `Bearer ${params.apiKey}`, // Do NOT set Content-Type — browser sets multipart boundary automatically }, body: formData, }); return response.json(); } ``` ### Using Responses API with image_generation Tool ```typescript async function generateViaResponsesAPI(params: { prompt: string; model: string; size: string; quality: "low" | "medium" | "high"; apiKey: string; apiUrl: string; }) { const response = await fetch(`${params.apiUrl}/responses`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${params.apiKey}`, }, body: JSON.stringify({ model: params.model, input: params.prompt, tools: [ { type: "image_generation", size: params.size, quality: params.quality, }, ], }), }); return response.json(); } ``` ### Custom Size Validation (matches app logic) ```typescript function sanitizeImageSize(width: number, height: number): { width: number; height: number; } { // Snap to 16px multiples let w = Math.round(width / 16) * 16; let h = Math.round(height / 16) * 16; // Max edge 3840px const maxEdge = 3840; if (w > maxEdge) w = maxEdge; if (h > maxEdge) h = maxEdge; // Aspect ratio must not exceed 3:1 if (w / h > 3) h = Math.ceil(w / 3 / 16) * 16; if (h / w > 3) w = Math.ceil(h / 3 / 16) * 16; // Total pixels: 655360 to 8294400 const pixels = w * h; const minPixels = 655360; const maxPixels = 8294400; if (pixels < minPixels) { const scale = Math.sqrt(minPixels / pixels); w = Math.ceil((w * scale) / 16) * 16; h = Math.ceil((h * scale) / 16) * 16; } if (pixels > maxPixels) { const scale = Math.sqrt(maxPixels / pixels); w = Math.floor((w * scale) / 16) * 16; h = Math.floor((h * scale) / 16) * 16; } return { width: w, height: h }; } ``` ### Adding IndexedDB Storage (pattern used by the app) ```typescript import { openDB, IDBPDatabase } from "idb"; // App uses native IDB API directly const DB_NAME = "gpt-image-playground"; const DB_VERSION = 1; async function initDB(): Promise<IDBDatabase> { return new Promise((resolve, reject) => { const request = indexedDB.open(DB_NAME, DB_VERSION); request.onupgradeneeded = (event) => { const db = (event.target as IDBOpenDBRequest).result; // Tasks store if (!db.objectStoreNames.contains("tasks")) { const tasks = db.createObjectStore("tasks", { keyPath: "id" }); tasks.createIndex("createdAt", "createdAt"); tasks.createIndex("status", "status"); tasks.createIndex("favorited", "favorited"); } // Images store with SHA-256 hash deduplication if (!db.objectStoreNames.contains("images")) { db.createObjectStore("images", { keyPath: "hash" }); } }; request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); } ``` ### Zustand Store Pattern (matching app architecture) ```typescript import { create } from "zustand"; import { persist } from "zustand/middleware"; interface SettingsStore { apiKey: string; apiUrl: string; apiMode: "images" | "responses"; model: string; setApiKey: (key: string) => void; setApiUrl: (url: string) => void; setApiMode: (mode: "images" | "responses") => void; setModel: (model: string) => void; } const useSettingsStore = create<SettingsStore>()( persist( (set) => ({ apiKey: "", apiUrl: "https://api.openai.com/v1", apiMode: "images", model: "gpt-image-1", setApiKey: (apiKey) => set({ apiKey }), setApiUrl: (apiUrl) => set({ apiUrl }), setApiMode: (apiMode) => set({ apiMode }), setModel: (model) => set({ model }), }),
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen