Handle long running custom image jobs
This commit is contained in:
@@ -22,7 +22,7 @@ interface CustomApiConfig {
|
||||
systemApiId?: string;
|
||||
}
|
||||
|
||||
const GENERATION_TIMEOUT = 300_000;
|
||||
const GENERATION_TIMEOUT = Number(process.env.IMAGE_GENERATION_TIMEOUT_MS || 900_000);
|
||||
const GENERATION_TIMEOUT_SECONDS = GENERATION_TIMEOUT / 1000;
|
||||
const MAX_UPSTREAM_REFERENCE_IMAGE_BYTES = Number(process.env.MAX_UPSTREAM_REFERENCE_IMAGE_BYTES || 700 * 1024);
|
||||
|
||||
@@ -202,7 +202,7 @@ async function fetchCustomImageGeneration(
|
||||
endpoint,
|
||||
{ method: 'POST', headers: buildCustomApiHeaders(apiKey), body: JSON.stringify(requestBody) },
|
||||
GENERATION_TIMEOUT,
|
||||
1,
|
||||
0,
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -396,6 +396,30 @@ function objectKeysFromUnknown(value: unknown): string[] {
|
||||
*/
|
||||
function extractImagesFromGenerationsResponse(data: Record<string, unknown>): string[] {
|
||||
const images: string[] = [];
|
||||
const visit = (value: unknown, depth = 0) => {
|
||||
if (depth > 6 || !value) return;
|
||||
if (typeof value === 'string') {
|
||||
if (value.startsWith('data:image/') || /^https?:\/\/[^\s"'<>]+/i.test(value)) images.push(value);
|
||||
return;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
for (const item of value) visit(item, depth + 1);
|
||||
return;
|
||||
}
|
||||
if (typeof value !== 'object') return;
|
||||
|
||||
const object = value as Record<string, unknown>;
|
||||
if (typeof object.b64_json === 'string') images.push(`data:image/png;base64,${object.b64_json}`);
|
||||
if (typeof object.url === 'string') visit(object.url, depth + 1);
|
||||
if (typeof object.image_url === 'string') visit(object.image_url, depth + 1);
|
||||
if (typeof object.image === 'string') visit(object.image, depth + 1);
|
||||
if (typeof object.output === 'string') visit(object.output, depth + 1);
|
||||
if (typeof object.result === 'string') visit(object.result, depth + 1);
|
||||
for (const key of ['data', 'images', 'image_urls', 'output', 'result', 'results', 'message', 'content']) {
|
||||
if (key in object) visit(object[key], depth + 1);
|
||||
}
|
||||
};
|
||||
|
||||
if (Array.isArray(data.data)) {
|
||||
for (const item of data.data as Array<Record<string, unknown>>) {
|
||||
if (typeof item === 'string') { images.push(item); continue; }
|
||||
@@ -409,6 +433,7 @@ function extractImagesFromGenerationsResponse(data: Record<string, unknown>): st
|
||||
} else if (typeof data.image_url === 'string') {
|
||||
images.push(data.image_url);
|
||||
}
|
||||
visit(data);
|
||||
|
||||
const streamEvents = data.__streamEvents;
|
||||
if (Array.isArray(streamEvents)) {
|
||||
@@ -418,7 +443,7 @@ function extractImagesFromGenerationsResponse(data: Record<string, unknown>): st
|
||||
}
|
||||
}
|
||||
|
||||
return images;
|
||||
return Array.from(new Set(images));
|
||||
}
|
||||
|
||||
/** Track which strategy produced a result */
|
||||
@@ -454,7 +479,7 @@ async function tryImageStrategy(
|
||||
body: JSON.stringify(body),
|
||||
},
|
||||
GENERATION_TIMEOUT,
|
||||
1,
|
||||
0,
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
@@ -557,7 +582,7 @@ async function tryEditsWithFormData(
|
||||
body: bodyBuffer,
|
||||
},
|
||||
GENERATION_TIMEOUT,
|
||||
1,
|
||||
0,
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
|
||||
Reference in New Issue
Block a user