fix: upload fal edit inputs to fal storage
This commit is contained in:
parent
3aa031a4e4
commit
6fe69de8de
@ -654,6 +654,64 @@ function createFalClientFromApiKey(apiKey: string) {
|
||||
);
|
||||
}
|
||||
|
||||
async function uploadImageUrlToFalStorage(params: {
|
||||
fal: Awaited<ReturnType<typeof createFalClientFromApiKey>>;
|
||||
url: string;
|
||||
}) {
|
||||
const { fal, url } = params;
|
||||
if (/fal\.(?:media|run)\//i.test(url) || /fal-ai/i.test(url)) return url;
|
||||
|
||||
const response = await fetch(url, { signal: AbortSignal.timeout(60_000) });
|
||||
if (!response.ok) {
|
||||
throw new Error(`FAL input image download failed before storage upload: ${response.status}`);
|
||||
}
|
||||
|
||||
const contentType = response.headers.get("content-type") || "image/png";
|
||||
const buffer = Buffer.from(await response.arrayBuffer());
|
||||
const blob = new Blob([buffer], { type: contentType });
|
||||
return fal.storage.upload(blob);
|
||||
}
|
||||
|
||||
async function prepareFalInputImageUrls(params: {
|
||||
fal: Awaited<ReturnType<typeof createFalClientFromApiKey>>;
|
||||
input: Record<string, any>;
|
||||
sourceImageUrls: string[];
|
||||
}) {
|
||||
const { fal, input, sourceImageUrls } = params;
|
||||
const cache = new Map<string, Promise<string>>();
|
||||
const upload = (url: string) => {
|
||||
const normalized = String(url || "").trim();
|
||||
if (!/^https?:\/\//i.test(normalized)) return Promise.resolve(normalized);
|
||||
const existing = cache.get(normalized);
|
||||
if (existing) return existing;
|
||||
const uploaded = uploadImageUrlToFalStorage({ fal, url: normalized });
|
||||
cache.set(normalized, uploaded);
|
||||
return uploaded;
|
||||
};
|
||||
|
||||
const preparedInput = { ...input };
|
||||
if (typeof preparedInput.image_url === "string") {
|
||||
preparedInput.image_url = await upload(preparedInput.image_url);
|
||||
}
|
||||
if (Array.isArray(preparedInput.image_urls)) {
|
||||
preparedInput.image_urls = await Promise.all(
|
||||
preparedInput.image_urls.map((url) => upload(String(url || "")))
|
||||
);
|
||||
}
|
||||
if (typeof preparedInput.mask_url === "string") {
|
||||
preparedInput.mask_url = await upload(preparedInput.mask_url);
|
||||
}
|
||||
|
||||
const preparedSourceImageUrls = await Promise.all(
|
||||
sourceImageUrls.map((url) => upload(url))
|
||||
);
|
||||
|
||||
return {
|
||||
input: preparedInput,
|
||||
sourceImageUrls: preparedSourceImageUrls,
|
||||
};
|
||||
}
|
||||
|
||||
function buildFalRequestPayload(params: {
|
||||
modelId: string;
|
||||
overrideModelId?: string;
|
||||
@ -834,18 +892,26 @@ export async function submitFalImageTask(params: {
|
||||
}): Promise<FalSubmittedImageTask> {
|
||||
const request = buildFalRequestPayload(params);
|
||||
const fal = await createFalClientFromApiKey(params.apiKey);
|
||||
const prepared = await prepareFalInputImageUrls({
|
||||
fal,
|
||||
input: request.input,
|
||||
sourceImageUrls: request.imageUrls,
|
||||
});
|
||||
|
||||
console.log("[Fal Image] Queue submit", {
|
||||
model: request.activeModelId,
|
||||
endpoint: request.falEndpointId,
|
||||
imageCount: request.imageCount,
|
||||
hasInputImages: request.imageUrls.length > 0,
|
||||
hasInputImages: prepared.sourceImageUrls.length > 0,
|
||||
resolution: request.outputSizeLabel,
|
||||
inputKeys: Object.keys(request.input),
|
||||
inputKeys: Object.keys(prepared.input),
|
||||
storagePrepared: prepared.sourceImageUrls.some(
|
||||
(url, index) => url !== request.imageUrls[index]
|
||||
),
|
||||
});
|
||||
|
||||
const enqueueResult = await fal.queue.submit(request.falEndpointId, {
|
||||
input: request.input,
|
||||
input: prepared.input,
|
||||
});
|
||||
|
||||
return {
|
||||
@ -855,7 +921,7 @@ export async function submitFalImageTask(params: {
|
||||
imageCount: request.imageCount,
|
||||
outputSizeLabel: request.outputSizeLabel,
|
||||
prompt: request.prompt,
|
||||
sourceImageUrls: request.imageUrls,
|
||||
sourceImageUrls: prepared.sourceImageUrls,
|
||||
};
|
||||
}
|
||||
|
||||
@ -920,12 +986,17 @@ export function createFalImage({ apiKey, baseURL }: FalImageConfig) {
|
||||
});
|
||||
|
||||
const fal = await createFalClientFromApiKey(apiKey);
|
||||
const prepared = await prepareFalInputImageUrls({
|
||||
fal,
|
||||
input: request.input,
|
||||
sourceImageUrls: request.imageUrls,
|
||||
});
|
||||
const timeoutMs = normalizeTimeoutMs(options.imageParams?.timeoutMs);
|
||||
|
||||
let result: any;
|
||||
try {
|
||||
result = await fal.subscribe(request.falEndpointId, {
|
||||
input: request.input,
|
||||
input: prepared.input,
|
||||
logs: true,
|
||||
timeout: timeoutMs,
|
||||
onQueueUpdate: (update: any) => {
|
||||
@ -945,7 +1016,7 @@ export function createFalImage({ apiKey, baseURL }: FalImageConfig) {
|
||||
|
||||
const text = await normalizeFalResultToMarkdown({
|
||||
payload: result,
|
||||
sourceImageUrls: request.imageUrls,
|
||||
sourceImageUrls: prepared.sourceImageUrls,
|
||||
imageCount: request.imageCount,
|
||||
outputSizeLabel: request.outputSizeLabel,
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user