feat: references
This commit is contained in:
parent
d7fe0e037d
commit
905d92b36a
13
CLAUDE.md
13
CLAUDE.md
|
|
@ -155,13 +155,14 @@ REST API at `https://api.banatie.app` for generating images. Auth via `X-API-Key
|
|||
|
||||
**POST `/api/v1/generations`** — create generation:
|
||||
- `prompt` (string, required) — image description
|
||||
- `aspectRatio` — `1:1`, `16:9`, `9:16`, `3:2`, `21:9` (default: `1:1`)
|
||||
- `referenceImages` (string[]) — image IDs as references
|
||||
- `aspectRatio` — `1:1`, `16:9`, `9:16`, `3:2`, `4:3`, `3:4`, `21:9` (default: `1:1`)
|
||||
- `referenceImages` (string[]) — `@alias` names of reference images
|
||||
- `flowId` (string) — associate with a flow (for flow-scoped alias resolution)
|
||||
- `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`
|
||||
- Multipart form data: `file` (up to 5MB, JPEG/PNG/WebP), `alias` (@name), `flowId`
|
||||
- Auto-creates a flow, returns `flowId` in response
|
||||
|
||||
Response returns JSON with `data.outputImage.storageUrl` (CDN URL to download).
|
||||
|
||||
|
|
@ -169,7 +170,9 @@ 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.
|
||||
- `--ref` accepts local file paths or `@alias`. Can be repeated
|
||||
- Local files are uploaded with auto-generated `@alias` into a shared flow
|
||||
- The flow's `flowId` is passed to generation for alias resolution
|
||||
|
||||
Rate limit: 100 requests/hour per API key.
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ try {
|
|||
const API_BASE = 'https://api.banatie.app/api/v1';
|
||||
const API_KEY = process.env.BANATIE_KEY || '';
|
||||
|
||||
async function uploadImage(filePath) {
|
||||
async function uploadImage(filePath, { flowId, alias }) {
|
||||
const absolutePath = resolve(filePath);
|
||||
const fileBuffer = readFileSync(absolutePath);
|
||||
const fileName = basename(absolutePath);
|
||||
|
|
@ -27,8 +27,10 @@ async function uploadImage(filePath) {
|
|||
|
||||
const form = new FormData();
|
||||
form.append('file', new Blob([fileBuffer], { type: mime }), fileName);
|
||||
form.append('alias', alias);
|
||||
if (flowId) form.append('flowId', flowId);
|
||||
|
||||
console.log(`Uploading reference: ${filePath}...`);
|
||||
console.log(`Uploading: ${filePath} as ${alias}${flowId ? ` (flow: ${flowId})` : ''}...`);
|
||||
|
||||
const response = await fetch(`${API_BASE}/images/upload`, {
|
||||
method: 'POST',
|
||||
|
|
@ -48,22 +50,37 @@ async function uploadImage(filePath) {
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Uploaded: ${result.data.id}`);
|
||||
return result.data.id;
|
||||
console.log(`Uploaded: ${alias} (${result.data.id})`);
|
||||
return result.data;
|
||||
}
|
||||
|
||||
function makeAlias(filePath, index) {
|
||||
const name = basename(filePath).replace(/\.[^.]+$/, '').replace(/[^a-z0-9-]/gi, '-').toLowerCase();
|
||||
return `@ref-${index + 1}-${name}`;
|
||||
}
|
||||
|
||||
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));
|
||||
const aliases = [];
|
||||
let flowId = null;
|
||||
|
||||
for (let i = 0; i < refs.length; i++) {
|
||||
const ref = refs[i];
|
||||
if (ref.startsWith('@')) {
|
||||
aliases.push(ref);
|
||||
} else if (existsSync(ref)) {
|
||||
const alias = makeAlias(ref, i);
|
||||
const data = await uploadImage(ref, { flowId, alias });
|
||||
if (!flowId) flowId = data.flowId;
|
||||
aliases.push(alias);
|
||||
} else {
|
||||
ids.push(ref);
|
||||
console.error(`Reference not found: ${ref}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
|
||||
return { referenceImages: aliases, flowId };
|
||||
}
|
||||
|
||||
export async function generateImage({ prompt, output, aspectRatio = '1:1', refs }) {
|
||||
|
|
@ -72,11 +89,14 @@ export async function generateImage({ prompt, output, aspectRatio = '1:1', refs
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
const referenceImages = await resolveRefs(refs);
|
||||
const resolved = await resolveRefs(refs);
|
||||
const body = { prompt, aspectRatio };
|
||||
if (referenceImages) body.referenceImages = referenceImages;
|
||||
if (resolved) {
|
||||
body.referenceImages = resolved.referenceImages;
|
||||
if (resolved.flowId) body.flowId = resolved.flowId;
|
||||
}
|
||||
|
||||
console.log(`Generating: "${prompt}" (${body.aspectRatio})${referenceImages ? ` with ${referenceImages.length} ref(s)` : ''}...`);
|
||||
console.log(`Generating: "${prompt}" (${body.aspectRatio})${resolved ? ` with ${resolved.referenceImages.length} ref(s)` : ''}...`);
|
||||
|
||||
const response = await fetch(`${API_BASE}/generations`, {
|
||||
method: 'POST',
|
||||
|
|
|
|||
Loading…
Reference in New Issue