Skip to content

Commit b8cb204

Browse files
feat(image-models): add pruna and nano banana pro image models (#34)
* feat(image-models): add pruna and nano banana pro image models - add pruna/p-image-t2i text-to-image model - add pruna/p-image-edit image editing model - add google/nano-banana-pro-edit image editing model - update buildInputPayload to handle pruna and nano banana pro formats - update README with new model capabilities and provider options * chore: add changeset for pruna and nano banana pro models
1 parent c883137 commit b8cb204

File tree

4 files changed

+98
-16
lines changed

4 files changed

+98
-16
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"@runpod/ai-sdk-provider": minor
3+
---
4+
5+
Add support for Pruna and Nano Banana Pro image models:
6+
- `pruna/p-image-t2i` - Pruna text-to-image generation
7+
- `pruna/p-image-edit` - Pruna image editing
8+
- `google/nano-banana-pro-edit` - Nano Banana Pro image editing (Gemini-powered)
9+
10+
These models support flexible aspect ratios and additional provider options like `aspect_ratio`, `resolution`, `enable_sync_mode`, and `enable_base64_output`.

README.md

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,11 @@ for await (const delta of textStream) {
106106

107107
### Model Capabilities
108108

109-
| Model ID | Description | Streaming | Object Generation | Tool Usage | Reasoning Notes |
110-
| ------------------------------- | ------------------------------------------------------------------- | --------- | ----------------- | ---------- | ------------------------- |
111-
| `qwen/qwen3-32b-awq` | 32B parameter multilingual model with strong reasoning capabilities |||| Standard reasoning events |
112-
| `openai/gpt-oss-120b` | 120B parameter open-source GPT model |||| Standard reasoning events |
113-
| `deepcogito/cogito-671b-v2.1-fp8` | 671B parameter Cogito model with FP8 quantization |||| Standard reasoning events |
109+
| Model ID | Description | Streaming | Object Generation | Tool Usage | Reasoning Notes |
110+
| --------------------------------- | ------------------------------------------------------------------- | --------- | ----------------- | ---------- | ------------------------- |
111+
| `qwen/qwen3-32b-awq` | 32B parameter multilingual model with strong reasoning capabilities |||| Standard reasoning events |
112+
| `openai/gpt-oss-120b` | 120B parameter open-source GPT model |||| Standard reasoning events |
113+
| `deepcogito/cogito-671b-v2.1-fp8` | 671B parameter Cogito model with FP8 quantization |||| Standard reasoning events |
114114

115115
**Note:** This list is not complete. For a full list of all available models, see the [Runpod Public Endpoint Reference](https://docs.runpod.io/hub/public-endpoint-reference).
116116

@@ -235,6 +235,9 @@ writeFileSync('landscape.jpg', image.uint8Array);
235235
| `qwen/qwen-image` | Text-to-image generation | 1:1, 4:3, 3:4 |
236236
| `qwen/qwen-image-edit` | Image editing (prompt-guided) | 1:1, 4:3, 3:4 |
237237
| `nano-banana-edit` | Image editing (multi-image) | 1:1, 4:3, 3:4 |
238+
| `google/nano-banana-pro-edit` | Image editing (Gemini-powered) | Uses resolution param (1k, 2k) |
239+
| `pruna/p-image-t2i` | Pruna text-to-image | 1:1, 16:9, 9:16, 4:3, 3:4, etc. |
240+
| `pruna/p-image-edit` | Pruna image editing | match_input_image, 1:1, 16:9, etc. |
238241

239242
**Note**: The provider uses strict validation for image parameters. Unsupported aspect ratios (like `16:9`, `9:16`, `3:2`, `2:3`) will throw an `InvalidArgumentError` with a clear message about supported alternatives.
240243

@@ -307,6 +310,8 @@ const { image } = await generateImage({
307310
});
308311
```
309312

313+
Check out our [examples](https://github.com/runpod/examples/tree/main/ai-sdk/getting-started) for more code snippets on how to use all the different models.
314+
310315
### Advanced Configuration
311316

312317
```ts
@@ -349,17 +354,22 @@ const { image } = await generateImage({
349354

350355
Runpod image models support flexible provider options through the `providerOptions.runpod` object:
351356

352-
| Option | Type | Default | Description |
353-
| ----------------------- | ---------- | ------- | ------------------------------------------------------------------------ |
354-
| `negative_prompt` | `string` | `""` | Text describing what you don't want in the image |
355-
| `enable_safety_checker` | `boolean` | `true` | Enable content safety filtering |
356-
| `image` | `string` | - | Single input image: URL or base64 data URI (Flux Kontext) |
357-
| `images` | `string[]` | - | Multiple input images (e.g., for `nano-banana-edit` multi-image editing) |
358-
| `num_inference_steps` | `number` | Auto | Number of denoising steps (Flux: 4 for schnell, 28 for others) |
359-
| `guidance` | `number` | Auto | Guidance scale for prompt adherence (Flux: 7 for schnell, 2 for others) |
360-
| `output_format` | `string` | `"png"` | Output image format ("png" or "jpg") |
361-
| `maxPollAttempts` | `number` | `60` | Maximum polling attempts for async generation |
362-
| `pollIntervalMillis` | `number` | `5000` | Polling interval in milliseconds (5 seconds) |
357+
| Option | Type | Default | Description |
358+
| ------------------------ | ---------- | ------- | ------------------------------------------------------------------------ |
359+
| `negative_prompt` | `string` | `""` | Text describing what you don't want in the image |
360+
| `enable_safety_checker` | `boolean` | `true` | Enable content safety filtering |
361+
| `disable_safety_checker` | `boolean` | `false` | Disable safety checker (Pruna models) |
362+
| `image` | `string` | - | Single input image: URL or base64 data URI (Flux Kontext) |
363+
| `images` | `string[]` | - | Multiple input images (e.g., for `nano-banana-edit` multi-image editing) |
364+
| `aspect_ratio` | `string` | `"1:1"` | Aspect ratio string (Pruna: "16:9", "match_input_image", etc.) |
365+
| `resolution` | `string` | `"1k"` | Output resolution (Nano Banana Pro: "1k", "2k") |
366+
| `num_inference_steps` | `number` | Auto | Number of denoising steps (Flux: 4 for schnell, 28 for others) |
367+
| `guidance` | `number` | Auto | Guidance scale for prompt adherence (Flux: 7 for schnell, 2 for others) |
368+
| `output_format` | `string` | `"png"` | Output image format ("png", "jpg", or "jpeg") |
369+
| `enable_base64_output` | `boolean` | `false` | Return base64 instead of URL (Nano Banana Pro) |
370+
| `enable_sync_mode` | `boolean` | `false` | Enable synchronous mode (some models) |
371+
| `maxPollAttempts` | `number` | `60` | Maximum polling attempts for async generation |
372+
| `pollIntervalMillis` | `number` | `5000` | Polling interval in milliseconds (5 seconds) |
363373

364374
## About Runpod
365375

src/runpod-image-model.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,63 @@ export class RunpodImageModel implements ImageModelV2 {
328328
}
329329
}
330330

331+
// Check if this is a Pruna model
332+
const isPrunaModel = this.modelId.includes('pruna') || this.modelId.includes('p-image');
333+
if (isPrunaModel) {
334+
const isPrunaEdit = this.modelId.includes('edit');
335+
336+
if (isPrunaEdit) {
337+
// Pruna image edit uses images array and aspect_ratio string
338+
return {
339+
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,
345+
};
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';
364+
365+
return {
366+
prompt,
367+
seed: seed ?? 0,
368+
aspect_ratio: aspectRatio,
369+
enable_safety_checker: runpodOptions?.enable_safety_checker ?? true,
370+
...runpodOptions,
371+
};
372+
}
373+
}
374+
375+
// Check if this is a Nano Banana Pro model (google/nano-banana-pro-edit)
376+
const isNanaBananaProModel = this.modelId.includes('nano-banana-pro');
377+
if (isNanaBananaProModel) {
378+
return {
379+
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,
385+
};
386+
}
387+
331388
// Default format for Qwen and other models
332389
return {
333390
prompt,

src/runpod-provider.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ const IMAGE_MODEL_ID_TO_ENDPOINT_URL: Record<string, string> = {
8484
'https://api.runpod.ai/v2/black-forest-labs-flux-1-dev',
8585
// Nano Banana (edit only)
8686
'nano-banana-edit': 'https://api.runpod.ai/v2/nano-banana-edit',
87+
// Nano Banana Pro (edit only)
88+
'google/nano-banana-pro-edit': 'https://api.runpod.ai/v2/nano-banana-pro-edit',
89+
// Pruna (t2i and edit)
90+
'pruna/p-image-t2i': 'https://api.runpod.ai/v2/p-image-t2i',
91+
'pruna/p-image-edit': 'https://api.runpod.ai/v2/p-image-edit',
8792
};
8893

8994
// Mapping of Runpod model IDs to their OpenAI model names

0 commit comments

Comments
 (0)