mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-17 04:32:31 +03:00
fix(providers): extract minimax image-gen helpers to fix complexity ratchet
check:complexity-ratchets regressed 2056 -> 2058 (handleMinimaxImageGeneration: complexity 25, max-lines-per-function 97). Split logging, upstream-error, no-images, success and fetch-error branches into small named helpers so the handler stays within the cyclomatic-complexity (15) and max-lines-per-function (80) ratchets. No behavior change; existing minimax-image-provider-2482 and minimax-media-servicekinds unit tests still pass.
This commit is contained in:
@@ -19,6 +19,16 @@ interface MinimaxImageGenArgs {
|
||||
} | null;
|
||||
}
|
||||
|
||||
interface MinimaxCallLogParams {
|
||||
status: number;
|
||||
model: string;
|
||||
provider: string;
|
||||
duration: number;
|
||||
error?: string;
|
||||
requestBody?: unknown;
|
||||
responseBody?: unknown;
|
||||
}
|
||||
|
||||
const MINIMAX_ASPECT_RATIOS = new Set(["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"]);
|
||||
|
||||
function mapMinimaxAspectRatio(size?: string): string {
|
||||
@@ -26,6 +36,113 @@ function mapMinimaxAspectRatio(size?: string): string {
|
||||
return "1:1";
|
||||
}
|
||||
|
||||
/** Fire-and-forget usage log for a MiniMax image-generation call. */
|
||||
function logMinimaxCall(params: MinimaxCallLogParams): void {
|
||||
saveCallLog({
|
||||
method: "POST",
|
||||
path: "/v1/images/generations",
|
||||
...params,
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
/** Builds the upstream MiniMax request body from the OpenAI-shaped input body. */
|
||||
function buildMinimaxUpstreamBody(model: string, prompt: string, body: MinimaxImageGenArgs["body"]) {
|
||||
return {
|
||||
model: model || "image-01",
|
||||
prompt,
|
||||
aspect_ratio: mapMinimaxAspectRatio(body.size),
|
||||
n: body.n ?? 1,
|
||||
response_format: "url",
|
||||
};
|
||||
}
|
||||
|
||||
/** Handles a non-2xx MiniMax response: logs, records the call, and shapes the error result. */
|
||||
async function handleMinimaxUpstreamError(
|
||||
response: Response,
|
||||
ctx: { provider: string; model: string; startTime: number; upstreamBody: unknown; log?: MinimaxImageGenArgs["log"] }
|
||||
) {
|
||||
const errorText = await response.text();
|
||||
ctx.log?.error?.("IMAGE", `${ctx.provider} error ${response.status}: ${errorText.slice(0, 200)}`);
|
||||
|
||||
logMinimaxCall({
|
||||
status: response.status,
|
||||
model: `${ctx.provider}/${ctx.model}`,
|
||||
provider: ctx.provider,
|
||||
duration: Date.now() - ctx.startTime,
|
||||
error: errorText.slice(0, 500),
|
||||
requestBody: ctx.upstreamBody,
|
||||
});
|
||||
|
||||
return { success: false as const, status: response.status, error: errorText };
|
||||
}
|
||||
|
||||
/** Extracts and validates the `image_urls` array from a MiniMax response payload. */
|
||||
function extractMinimaxImageUrls(data: unknown): unknown[] {
|
||||
const record = data as { data?: { image_urls?: unknown } } | undefined;
|
||||
return Array.isArray(record?.data?.image_urls) ? (record?.data?.image_urls as unknown[]) : [];
|
||||
}
|
||||
|
||||
interface MinimaxResultCtx {
|
||||
provider: string;
|
||||
model: string;
|
||||
startTime: number;
|
||||
}
|
||||
|
||||
/** MiniMax returned 2xx but no images — logs and shapes the empty-result error. */
|
||||
function buildMinimaxNoImagesResult(data: unknown, ctx: MinimaxResultCtx) {
|
||||
const record = data as { base_resp?: { status_msg?: string } } | undefined;
|
||||
const errorMsg = record?.base_resp?.status_msg || "No images returned from MiniMax";
|
||||
logMinimaxCall({
|
||||
status: 502,
|
||||
model: `${ctx.provider}/${ctx.model}`,
|
||||
provider: ctx.provider,
|
||||
duration: Date.now() - ctx.startTime,
|
||||
error: errorMsg,
|
||||
});
|
||||
return { success: false as const, status: 502, error: errorMsg };
|
||||
}
|
||||
|
||||
/** MiniMax returned images — logs and shapes the OpenAI-compatible success result. */
|
||||
function buildMinimaxSuccessResult(imageUrls: unknown[], prompt: string, ctx: MinimaxResultCtx) {
|
||||
const images = imageUrls.map((url) => ({ url, revised_prompt: prompt }));
|
||||
|
||||
logMinimaxCall({
|
||||
status: 200,
|
||||
model: `${ctx.provider}/${ctx.model}`,
|
||||
provider: ctx.provider,
|
||||
duration: Date.now() - ctx.startTime,
|
||||
responseBody: { images_count: images.length },
|
||||
});
|
||||
|
||||
return {
|
||||
success: true as const,
|
||||
data: { created: Math.floor(Date.now() / 1000), data: images },
|
||||
};
|
||||
}
|
||||
|
||||
/** Network/parse failure reaching MiniMax — logs and shapes the sanitized error result. */
|
||||
function buildMinimaxFetchErrorResult(
|
||||
err: unknown,
|
||||
ctx: MinimaxResultCtx & { log?: MinimaxImageGenArgs["log"] }
|
||||
) {
|
||||
const errMsg = err instanceof Error ? err.message : String(err);
|
||||
ctx.log?.error?.("IMAGE", `${ctx.provider} fetch error: ${errMsg}`);
|
||||
|
||||
logMinimaxCall({
|
||||
status: 502,
|
||||
model: `${ctx.provider}/${ctx.model}`,
|
||||
provider: ctx.provider,
|
||||
duration: Date.now() - ctx.startTime,
|
||||
error: errMsg,
|
||||
});
|
||||
|
||||
return {
|
||||
success: false as const,
|
||||
status: 502,
|
||||
error: `Image provider error: ${sanitizeErrorMessage(errMsg)}`,
|
||||
};
|
||||
}
|
||||
|
||||
export async function handleMinimaxImageGeneration({
|
||||
model,
|
||||
provider,
|
||||
@@ -37,22 +154,12 @@ export async function handleMinimaxImageGeneration({
|
||||
const startTime = Date.now();
|
||||
const token = credentials?.apiKey || credentials?.accessToken || "";
|
||||
const prompt = typeof body.prompt === "string" ? body.prompt : String(body.prompt ?? "");
|
||||
const aspectRatio = mapMinimaxAspectRatio(body.size);
|
||||
const upstreamBody = buildMinimaxUpstreamBody(model, prompt, body);
|
||||
|
||||
const upstreamBody = {
|
||||
model: model || "image-01",
|
||||
prompt,
|
||||
aspect_ratio: aspectRatio,
|
||||
n: body.n ?? 1,
|
||||
response_format: "url",
|
||||
};
|
||||
|
||||
if (log) {
|
||||
log.info?.(
|
||||
"IMAGE",
|
||||
`${provider}/${model} (minimax-image) | prompt: "${prompt.slice(0, 60)}..." | aspect_ratio: ${aspectRatio}`
|
||||
);
|
||||
}
|
||||
log?.info?.(
|
||||
"IMAGE",
|
||||
`${provider}/${model} (minimax-image) | prompt: "${prompt.slice(0, 60)}..." | aspect_ratio: ${upstreamBody.aspect_ratio}`
|
||||
);
|
||||
|
||||
try {
|
||||
const response = await fetch(providerConfig.baseUrl, {
|
||||
@@ -65,74 +172,19 @@ export async function handleMinimaxImageGeneration({
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
if (log) log.error?.("IMAGE", `${provider} error ${response.status}: ${errorText.slice(0, 200)}`);
|
||||
|
||||
saveCallLog({
|
||||
method: "POST",
|
||||
path: "/v1/images/generations",
|
||||
status: response.status,
|
||||
model: `${provider}/${model}`,
|
||||
provider,
|
||||
duration: Date.now() - startTime,
|
||||
error: errorText.slice(0, 500),
|
||||
requestBody: upstreamBody,
|
||||
}).catch(() => {});
|
||||
|
||||
return { success: false, status: response.status, error: errorText };
|
||||
return handleMinimaxUpstreamError(response, { provider, model, startTime, upstreamBody, log });
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const imageUrls: unknown[] = Array.isArray(data?.data?.image_urls) ? data.data.image_urls : [];
|
||||
const imageUrls = extractMinimaxImageUrls(data);
|
||||
const ctx: MinimaxResultCtx = { provider, model, startTime };
|
||||
|
||||
if (imageUrls.length === 0) {
|
||||
const errorMsg = data?.base_resp?.status_msg || "No images returned from MiniMax";
|
||||
saveCallLog({
|
||||
method: "POST",
|
||||
path: "/v1/images/generations",
|
||||
status: 502,
|
||||
model: `${provider}/${model}`,
|
||||
provider,
|
||||
duration: Date.now() - startTime,
|
||||
error: errorMsg,
|
||||
}).catch(() => {});
|
||||
return { success: false, status: 502, error: errorMsg };
|
||||
return buildMinimaxNoImagesResult(data, ctx);
|
||||
}
|
||||
|
||||
const images = imageUrls.map((url) => ({ url, revised_prompt: prompt }));
|
||||
|
||||
saveCallLog({
|
||||
method: "POST",
|
||||
path: "/v1/images/generations",
|
||||
status: 200,
|
||||
model: `${provider}/${model}`,
|
||||
provider,
|
||||
duration: Date.now() - startTime,
|
||||
responseBody: { images_count: images.length },
|
||||
}).catch(() => {});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: { created: Math.floor(Date.now() / 1000), data: images },
|
||||
};
|
||||
return buildMinimaxSuccessResult(imageUrls, prompt, ctx);
|
||||
} catch (err: unknown) {
|
||||
const errMsg = err instanceof Error ? err.message : String(err);
|
||||
if (log) log.error?.("IMAGE", `${provider} fetch error: ${errMsg}`);
|
||||
|
||||
saveCallLog({
|
||||
method: "POST",
|
||||
path: "/v1/images/generations",
|
||||
status: 502,
|
||||
model: `${provider}/${model}`,
|
||||
provider,
|
||||
duration: Date.now() - startTime,
|
||||
error: errMsg,
|
||||
}).catch(() => {});
|
||||
|
||||
return {
|
||||
success: false,
|
||||
status: 502,
|
||||
error: `Image provider error: ${sanitizeErrorMessage(errMsg)}`,
|
||||
};
|
||||
return buildMinimaxFetchErrorResult(err, { provider, model, startTime, log });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user