Compare commits

...

3 Commits

  1. 2
      src/app/api/generate/providers/popiserver.ts
  2. 5
      src/app/api/popi/media/upload/route.ts
  3. 8
      src/components/composer/GenerationComposer.tsx
  4. 9
      src/store/execution/nanoBananaExecutor.ts
  5. 2
      src/utils/modelSchemaDefaults.ts

2
src/app/api/generate/providers/popiserver.ts

@ -564,7 +564,7 @@ function extractOutputFromTask(task: PopiTask, mediaType: string): GenerationOut
// payloads. Only use it as a defensive fallback for older responses that do
// not put generated images under resultList.
const images = [
...new Set(resultImages.length > 0 ? resultImages : collectStrings(task.images)),
...new Set(resultImages.length > 0 ? resultImages : collectStrings(task.images ?? [])),
];
return images.length > 0
? { success: true, outputs: images.map((url) => ({ type: "image", data: "", url })) }

5
src/app/api/popi/media/upload/route.ts

@ -65,6 +65,10 @@ function mediaResourceUrl(media: PopiMedia): string | null {
return media.url || media.originUrl || media.path || media.originPath || null;
}
function isPopiMedia(value: PopiMediaUploadData): value is PopiMedia {
return "url" in value || "originUrl" in value || "path" in value || "originPath" in value;
}
function uploadedMediaUrls(data: PopiMediaUploadData | undefined): string[] {
if (!data) return [];
if (Array.isArray(data)) {
@ -81,6 +85,7 @@ function uploadedMediaUrls(data: PopiMediaUploadData | undefined): string[] {
if (list) {
return list.map(mediaResourceUrl).filter((url): url is string => Boolean(url));
}
if (!isPopiMedia(data)) return [];
const single = mediaResourceUrl(data);
return single ? [single] : [];
}

8
src/components/composer/GenerationComposer.tsx

@ -989,12 +989,13 @@ export function GenerationComposer() {
return current;
}
const currentCapabilities = current.selectedModel?.capabilities ?? [];
const next = {
...current,
selectedModel: {
...resolvedModel,
capabilities: current.selectedModel.capabilities.length > 0
? current.selectedModel.capabilities
capabilities: currentCapabilities.length > 0
? currentCapabilities
: resolvedModel.capabilities,
},
};
@ -1013,10 +1014,11 @@ export function GenerationComposer() {
nodeModel &&
selectedModelNeedsPopiserverMetadataLookup(nodeModel)
) {
const nodeModelCapabilities = nodeModel.capabilities ?? [];
updateNodeData(activeContext.node.id, {
selectedModel: {
...resolvedModel,
capabilities: nodeModel.capabilities.length > 0 ? nodeModel.capabilities : resolvedModel.capabilities,
capabilities: nodeModelCapabilities.length > 0 ? nodeModelCapabilities : resolvedModel.capabilities,
},
});
}

9
src/store/execution/nanoBananaExecutor.ts

@ -7,6 +7,7 @@
import type {
NanoBananaNodeData,
Resolution,
SelectedModel,
} from "@/types";
import { calculateGenerationCost } from "@/utils/costCalculator";
@ -46,6 +47,12 @@ export interface NanoBananaOptions {
useStoredFallback?: boolean;
}
const GEMINI_RESOLUTIONS: Resolution[] = ["512", "1K", "2K", "4K"];
function normalizeGeminiResolution(value: string): Resolution {
return GEMINI_RESOLUTIONS.includes(value as Resolution) ? (value as Resolution) : "2K";
}
function isProviderOverloadError(error: unknown): boolean {
const message = error instanceof Error ? error.message : String(error);
return /provider is temporarily overloaded|system\s+disk\s+overloaded/i.test(message);
@ -376,7 +383,7 @@ export async function executeNanoBanana(
if (modelToUse.provider === "fal" && modelToUse.pricing) {
addIncurredCost(modelToUse.pricing.amount);
} else if (modelToUse.provider === "gemini") {
const generationCost = calculateGenerationCost(nodeData.model, nodeConfig.resolution);
const generationCost = calculateGenerationCost(nodeData.model, normalizeGeminiResolution(nodeConfig.resolution));
addIncurredCost(generationCost);
}

2
src/utils/modelSchemaDefaults.ts

@ -57,7 +57,7 @@ export function buildImageDefaultsFromSchema(schema: ModelParameter[]): {
return {
...(hasValue(ratioValue) ? { aspectRatio: String(ratioValue) as AspectRatio } : {}),
...(hasValue(resolutionValue) ? { resolution: String(resolutionValue) } : {}),
...(Number.isInteger(imageCountValue) && imageCountValue > 0
...(typeof imageCountValue === "number" && Number.isInteger(imageCountValue) && imageCountValue > 0
? { imageCount: imageCountValue as ImageGenerationCount }
: {}),
parameters,

Loading…
Cancel
Save