wip: references
This commit is contained in:
parent
5a854479f9
commit
d7fe0e037d
17
CLAUDE.md
17
CLAUDE.md
|
|
@ -17,8 +17,9 @@ pnpm remove-bg -- <file|dir> # 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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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 "<description>" --output <path> [--aspect-ratio <ratio>]');
|
||||
console.error('Usage: node banatie.mjs --prompt "<description>" --output <path> [--aspect-ratio <ratio>] [--ref <file|id>]...');
|
||||
process.exit(1);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue