Skip to content

Commit f6115ac

Browse files
fix(image-models): support all aspect ratios for pruna and nano banana pro (#36)
pruna models: - skip standard size/aspectRatio validation - support all t2i aspect ratios: 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, custom - support all edit aspect ratios: match_input_image, 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3 - support custom width/height for t2i (256-1440, multiple of 16) - support 1-5 images for edit nano banana pro model: - skip standard size/aspectRatio validation - support all aspect ratios: 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 21:9, 9:21 - support resolution: 1k, 2k, 4k - support output_format: jpeg, png, webp
1 parent a613d99 commit f6115ac

File tree

2 files changed

+107
-40
lines changed

2 files changed

+107
-40
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
"@runpod/ai-sdk-provider": patch
3+
---
4+
5+
Fix Pruna and Nano Banana Pro model support for all aspect ratios:
6+
7+
Pruna models:
8+
- Skip standard size/aspectRatio validation
9+
- Support all t2i aspect ratios: 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, custom
10+
- Support all edit aspect ratios: match_input_image, 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3
11+
- Support custom width/height for t2i (256-1440, must be multiple of 16)
12+
- Support 1-5 images for edit
13+
14+
Nano Banana Pro model:
15+
- Skip standard size/aspectRatio validation
16+
- Support all aspect ratios: 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 21:9, 9:21
17+
- Support resolution: 1k, 2k, 4k
18+
- Support output_format: jpeg, png, webp

src/runpod-image-model.ts

Lines changed: 89 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,21 @@ export class RunpodImageModel implements ImageModelV2 {
7575
> {
7676
const warnings: Array<ImageModelV2CallWarning> = [];
7777

78+
// Check if this is a Pruna model (skip standard size/aspectRatio validation)
79+
const isPrunaModel =
80+
this.modelId.includes('pruna') || this.modelId.includes('p-image');
81+
82+
// Check if this is a Nano Banana Pro model (skip standard size/aspectRatio validation)
83+
const isNanoBananaProModel = this.modelId.includes('nano-banana-pro');
84+
7885
// Determine the size to use
7986
let runpodSize: string;
8087

81-
if (size) {
88+
if (isPrunaModel || isNanoBananaProModel) {
89+
// These models use aspect_ratio string directly, skip size validation
90+
// Pass through the aspectRatio or use default, validation happens at API level
91+
runpodSize = aspectRatio || '1:1';
92+
} else if (size) {
8293
// Convert AI SDK format "1328x1328" to Runpod format "1328*1328"
8394
const runpodSizeCandidate = size.replace('x', '*');
8495

@@ -128,7 +139,8 @@ export class RunpodImageModel implements ImageModelV2 {
128139
prompt,
129140
runpodSize,
130141
seed,
131-
providerOptions.runpod
142+
providerOptions.runpod,
143+
aspectRatio
132144
);
133145

134146
const { value: response, responseHeaders } = await postJsonToApi({
@@ -286,7 +298,8 @@ export class RunpodImageModel implements ImageModelV2 {
286298
prompt: string,
287299
runpodSize: string,
288300
seed?: number,
289-
runpodOptions?: Record<string, unknown>
301+
runpodOptions?: Record<string, unknown>,
302+
aspectRatio?: string
290303
): Record<string, unknown> {
291304
// Check if this is a Flux model that uses different parameters
292305
const isFluxModel =
@@ -329,60 +342,96 @@ export class RunpodImageModel implements ImageModelV2 {
329342
}
330343

331344
// Check if this is a Pruna model
332-
const isPrunaModel = this.modelId.includes('pruna') || this.modelId.includes('p-image');
345+
const isPrunaModel =
346+
this.modelId.includes('pruna') || this.modelId.includes('p-image');
333347
if (isPrunaModel) {
334348
const isPrunaEdit = this.modelId.includes('edit');
335349

336350
if (isPrunaEdit) {
337-
// Pruna image edit uses images array and aspect_ratio string
338-
return {
351+
// Pruna image edit
352+
// Supported aspect_ratio: "match_input_image", "1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"
353+
// Supports 1-5 images via providerOptions.runpod.images
354+
const editPayload: Record<string, unknown> = {
339355
prompt,
340-
seed: seed ?? -1,
341-
aspect_ratio: runpodOptions?.aspect_ratio ?? 'match_input_image',
342-
disable_safety_checker: runpodOptions?.disable_safety_checker ?? false,
343-
enable_sync_mode: runpodOptions?.enable_sync_mode ?? false,
344-
...runpodOptions,
356+
aspect_ratio:
357+
(runpodOptions?.aspect_ratio as string) ??
358+
aspectRatio ??
359+
'match_input_image',
360+
disable_safety_checker:
361+
(runpodOptions?.disable_safety_checker as boolean) ?? false,
345362
};
346-
} else {
347-
// Pruna text-to-image uses aspect_ratio string format
348-
const aspectRatioMap: Record<string, string> = {
349-
'1328*1328': '1:1',
350-
'1472*1140': '4:3',
351-
'1140*1472': '3:4',
352-
'512*512': '1:1',
353-
'768*768': '1:1',
354-
'1024*1024': '1:1',
355-
'1536*1536': '1:1',
356-
'2048*2048': '1:1',
357-
'4096*4096': '1:1',
358-
'512*768': '2:3',
359-
'768*512': '3:2',
360-
'1024*768': '4:3',
361-
'768*1024': '3:4',
362-
};
363-
const aspectRatio = runpodOptions?.aspect_ratio ?? aspectRatioMap[runpodSize] ?? '1:1';
364363

365-
return {
364+
// Add seed if provided
365+
if (seed !== undefined) {
366+
editPayload.seed = seed;
367+
} else if (runpodOptions?.seed !== undefined) {
368+
editPayload.seed = runpodOptions.seed;
369+
}
370+
371+
// Add images array (required, 1-5 images)
372+
if (runpodOptions?.images) {
373+
editPayload.images = runpodOptions.images;
374+
}
375+
376+
return editPayload;
377+
} else {
378+
// Pruna text-to-image
379+
// Supported aspect_ratio: "1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "custom"
380+
// For custom: width/height 256-1440, must be multiple of 16
381+
const t2iPayload: Record<string, unknown> = {
366382
prompt,
367-
seed: seed ?? 0,
368-
aspect_ratio: aspectRatio,
369-
enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,
370-
...runpodOptions,
383+
aspect_ratio:
384+
(runpodOptions?.aspect_ratio as string) ?? aspectRatio ?? '1:1',
385+
disable_safety_checker:
386+
(runpodOptions?.disable_safety_checker as boolean) ?? false,
371387
};
388+
389+
// Add seed if provided
390+
if (seed !== undefined) {
391+
t2iPayload.seed = seed;
392+
} else if (runpodOptions?.seed !== undefined) {
393+
t2iPayload.seed = runpodOptions.seed;
394+
}
395+
396+
// Handle custom aspect ratio with width/height
397+
if (t2iPayload.aspect_ratio === 'custom') {
398+
if (runpodOptions?.width) {
399+
t2iPayload.width = runpodOptions.width;
400+
}
401+
if (runpodOptions?.height) {
402+
t2iPayload.height = runpodOptions.height;
403+
}
404+
}
405+
406+
return t2iPayload;
372407
}
373408
}
374409

375410
// Check if this is a Nano Banana Pro model (google/nano-banana-pro-edit)
376411
const isNanaBananaProModel = this.modelId.includes('nano-banana-pro');
377412
if (isNanaBananaProModel) {
378-
return {
413+
// Nano Banana Pro image edit
414+
// Supported aspect_ratio: "1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "21:9", "9:21"
415+
// Supported resolution: "1k", "2k", "4k"
416+
// Supported output_format: "jpeg", "png", "webp"
417+
const nanoBananaPayload: Record<string, unknown> = {
379418
prompt,
380-
resolution: runpodOptions?.resolution ?? '1k',
381-
output_format: runpodOptions?.output_format ?? 'jpeg',
382-
enable_base64_output: runpodOptions?.enable_base64_output ?? false,
383-
enable_sync_mode: runpodOptions?.enable_sync_mode ?? false,
384-
...runpodOptions,
419+
aspect_ratio:
420+
(runpodOptions?.aspect_ratio as string) ?? aspectRatio ?? '1:1',
421+
resolution: (runpodOptions?.resolution as string) ?? '1k',
422+
output_format: (runpodOptions?.output_format as string) ?? 'jpeg',
423+
enable_base64_output:
424+
(runpodOptions?.enable_base64_output as boolean) ?? false,
425+
enable_sync_mode:
426+
(runpodOptions?.enable_sync_mode as boolean) ?? false,
385427
};
428+
429+
// Add images array (required)
430+
if (runpodOptions?.images) {
431+
nanoBananaPayload.images = runpodOptions.images;
432+
}
433+
434+
return nanoBananaPayload;
386435
}
387436

388437
// Default format for Qwen and other models

0 commit comments

Comments
 (0)