diff --git a/CLAUDE.md b/CLAUDE.md index 38c04fc..f1f1814 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,8 +17,9 @@ pnpm remove-bg -- # Remove white background from PNG icons Generate images via Banatie API: ```bash -node src/scripts/banatie.mjs --type background --prompt "forest theme" --output assets/backgrounds/forest.png -node src/scripts/banatie.mjs --type icon --prompt "golden star" --output assets/icons/stars/star1.png +node src/scripts/banatie.mjs --prompt "forest theme" --output assets/backgrounds/forest.png --aspect-ratio 9:16 +node src/scripts/banatie.mjs --prompt "golden star" --output assets/icons/star.png +node src/scripts/banatie.mjs --prompt "similar gem" --output assets/icons/gem.png --ref assets/icons/sample.png ``` ## Directory Structure @@ -158,11 +159,17 @@ REST API at `https://api.banatie.app` for generating images. Auth via `X-API-Key - `referenceImages` (string[]) — image IDs as references - `autoEnhance` (boolean) — prompt enhancement (default: true) +**POST `/api/v1/images/upload`** — upload image (for use as reference): +- Multipart form data, field `file` (up to 5MB, JPEG/PNG/WebP) +- Returns image ID in `data.id` + Response returns JSON with `data.outputImage.storageUrl` (CDN URL to download). -Script `src/scripts/banatie.mjs` wraps the API with presets: -- `background` → `aspectRatio: "9:16"` (vertical, for page backgrounds) -- `icon` → `aspectRatio: "1:1"` (square, for problem card icons) +Script `src/scripts/banatie.mjs` CLI: +```bash +node src/scripts/banatie.mjs --prompt "description" --output path.png [--aspect-ratio 1:1] [--ref file.png]... +``` +- `--ref` accepts local file paths (auto-uploaded) or existing image IDs (passed as-is). Can be repeated. Rate limit: 100 requests/hour per API key. diff --git a/src/scripts/banatie.mjs b/src/scripts/banatie.mjs index ae954cb..345e375 100644 --- a/src/scripts/banatie.mjs +++ b/src/scripts/banatie.mjs @@ -1,5 +1,5 @@ -import { writeFileSync, mkdirSync, readFileSync } from 'fs'; -import { resolve, dirname } from 'path'; +import { writeFileSync, mkdirSync, readFileSync, existsSync } from 'fs'; +import { resolve, dirname, basename } from 'path'; const envPath = resolve(dirname(new URL(import.meta.url).pathname), '../../.env'); try { @@ -16,15 +16,67 @@ try { const API_BASE = 'https://api.banatie.app/api/v1'; const API_KEY = process.env.BANATIE_KEY || ''; -export async function generateImage({ prompt, output, aspectRatio = '1:1' }) { +async function uploadImage(filePath) { + const absolutePath = resolve(filePath); + const fileBuffer = readFileSync(absolutePath); + const fileName = basename(absolutePath); + + const ext = fileName.split('.').pop().toLowerCase(); + const mimeTypes = { png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', webp: 'image/webp' }; + const mime = mimeTypes[ext] || 'application/octet-stream'; + + const form = new FormData(); + form.append('file', new Blob([fileBuffer], { type: mime }), fileName); + + console.log(`Uploading reference: ${filePath}...`); + + const response = await fetch(`${API_BASE}/images/upload`, { + method: 'POST', + headers: { 'X-API-Key': API_KEY }, + body: form, + }); + + if (!response.ok) { + const text = await response.text(); + console.error(`Upload error ${response.status}: ${text}`); + process.exit(1); + } + + const result = await response.json(); + if (!result.success) { + console.error(`Upload failed:`, result.error); + process.exit(1); + } + + console.log(`Uploaded: ${result.data.id}`); + return result.data.id; +} + +async function resolveRefs(refs) { + if (!refs || refs.length === 0) return undefined; + + const ids = []; + for (const ref of refs) { + if (existsSync(ref)) { + ids.push(await uploadImage(ref)); + } else { + ids.push(ref); + } + } + return ids; +} + +export async function generateImage({ prompt, output, aspectRatio = '1:1', refs }) { if (!API_KEY) { console.error('BANATIE_KEY environment variable is not set'); process.exit(1); } + const referenceImages = await resolveRefs(refs); const body = { prompt, aspectRatio }; + if (referenceImages) body.referenceImages = referenceImages; - console.log(`Generating: "${prompt}" (${body.aspectRatio})...`); + console.log(`Generating: "${prompt}" (${body.aspectRatio})${referenceImages ? ` with ${referenceImages.length} ref(s)` : ''}...`); const response = await fetch(`${API_BASE}/generations`, { method: 'POST', @@ -71,6 +123,10 @@ function parseArgs(args) { if (args[i] === '--prompt') result.prompt = args[++i]; else if (args[i] === '--output') result.output = args[++i]; else if (args[i] === '--aspect-ratio') result.aspectRatio = args[++i]; + else if (args[i] === '--ref') { + if (!result.refs) result.refs = []; + result.refs.push(args[++i]); + } } return result; } @@ -79,6 +135,6 @@ const args = parseArgs(process.argv.slice(2)); if (args.prompt && args.output) { generateImage(args); } else if (process.argv.length > 2) { - console.error('Usage: node banatie.mjs --prompt "" --output [--aspect-ratio ]'); + console.error('Usage: node banatie.mjs --prompt "" --output [--aspect-ratio ] [--ref ]...'); process.exit(1); }