fix ruxa image resolution mapping
This commit is contained in:
parent
e2111add87
commit
663ff7b41c
@ -205,6 +205,7 @@ export async function generateImageWithFailoverCandidate(params: {
|
|||||||
const candidateResult = await (candidateLanguageModel as any).doGenerate({
|
const candidateResult = await (candidateLanguageModel as any).doGenerate({
|
||||||
messages: candidateMessages,
|
messages: candidateMessages,
|
||||||
imageParams: imageParams || fallbackImageParams,
|
imageParams: imageParams || fallbackImageParams,
|
||||||
|
imageGenConfig: candidate.model.imageGenConfig || null,
|
||||||
modelDisplayName: candidate.model.displayName,
|
modelDisplayName: candidate.model.displayName,
|
||||||
overrideModelId: candidate.model.modelId,
|
overrideModelId: candidate.model.modelId,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -410,6 +410,7 @@ async function replayAssistantMessagesForDuplicateRequest({
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ChatImageParams = NonNullable<PostRequestBody["imageParams"]>;
|
type ChatImageParams = NonNullable<PostRequestBody["imageParams"]>;
|
||||||
|
type ChatImageSize = NonNullable<ChatImageParams["imageSize"]>;
|
||||||
type AgentRecommendedImageParams = {
|
type AgentRecommendedImageParams = {
|
||||||
aspectRatio?: string;
|
aspectRatio?: string;
|
||||||
imageSize?: string;
|
imageSize?: string;
|
||||||
@ -444,6 +445,14 @@ type AgentVideoPlan = {
|
|||||||
recommendedVideoParams?: AgentRecommendedVideoParams;
|
recommendedVideoParams?: AgentRecommendedVideoParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function normalizeChatImageSize(value?: string | null): ChatImageSize | undefined {
|
||||||
|
const normalized = String(value || "").trim().toUpperCase();
|
||||||
|
if (normalized === "1K" || normalized === "2K" || normalized === "4K") {
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
function hasUserCustomizedImageParams(params?: PostRequestBody["imageParams"]): boolean {
|
function hasUserCustomizedImageParams(params?: PostRequestBody["imageParams"]): boolean {
|
||||||
if (!params) return false;
|
if (!params) return false;
|
||||||
const customizedAspectRatio =
|
const customizedAspectRatio =
|
||||||
@ -484,7 +493,8 @@ function mergeImageParamsWithAgentRecommendation(params: {
|
|||||||
|
|
||||||
if (!hasUserCustomSettings) {
|
if (!hasUserCustomSettings) {
|
||||||
if (recommended.aspectRatio) merged.aspectRatio = recommended.aspectRatio;
|
if (recommended.aspectRatio) merged.aspectRatio = recommended.aspectRatio;
|
||||||
if (recommended.imageSize) merged.imageSize = recommended.imageSize;
|
const recommendedImageSize = normalizeChatImageSize(recommended.imageSize);
|
||||||
|
if (recommendedImageSize) merged.imageSize = recommendedImageSize;
|
||||||
if (typeof recommended.imageCount === "number") merged.imageCount = recommended.imageCount;
|
if (typeof recommended.imageCount === "number") merged.imageCount = recommended.imageCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2038,12 +2048,19 @@ export async function POST(request: Request) {
|
|||||||
imageSize: smartAutoDetectedIntent === "image_edit" ? "4K" : "2K",
|
imageSize: smartAutoDetectedIntent === "image_edit" ? "4K" : "2K",
|
||||||
imageCount: 1,
|
imageCount: 1,
|
||||||
} as const;
|
} as const;
|
||||||
|
const normalizedEffectiveImageSize = normalizeChatImageSize(effectiveImageParams?.imageSize);
|
||||||
|
const effectiveImageGenerationParams = {
|
||||||
|
...(effectiveImageParams || {}),
|
||||||
|
aspectRatio: effectiveImageParams?.aspectRatio || defaultImageQualityParams.aspectRatio,
|
||||||
|
imageSize: normalizedEffectiveImageSize || defaultImageQualityParams.imageSize,
|
||||||
|
imageCount: effectiveImageParams?.imageCount || defaultImageQualityParams.imageCount,
|
||||||
|
};
|
||||||
|
|
||||||
if (shouldApplyAgentImageParams) {
|
if (shouldApplyAgentImageParams) {
|
||||||
chatApiLogger.info("[Smart Auto Mode] 🎯 Effective image params:", {
|
chatApiLogger.info("[Smart Auto Mode] 🎯 Effective image params:", {
|
||||||
incoming: requestBody.imageParams,
|
incoming: requestBody.imageParams,
|
||||||
recommended: smartAutoRecommendedImageParams,
|
recommended: smartAutoRecommendedImageParams,
|
||||||
merged: effectiveImageParams,
|
merged: effectiveImageGenerationParams,
|
||||||
hasUserCustomImageParams,
|
hasUserCustomImageParams,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -3551,7 +3568,7 @@ export async function POST(request: Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let finalImage = firstImage;
|
let finalImage = firstImage;
|
||||||
let finalImageSizeLabel = resolvedImageSize;
|
let finalImageSizeLabel: string = resolvedImageSize;
|
||||||
try {
|
try {
|
||||||
const normalizedImage = await normalizeReplacementResultImage({
|
const normalizedImage = await normalizeReplacementResultImage({
|
||||||
generatedImageUrl: firstImage.originalUrl,
|
generatedImageUrl: firstImage.originalUrl,
|
||||||
@ -4379,7 +4396,7 @@ export async function POST(request: Request) {
|
|||||||
throw new Error("未返回结果图片");
|
throw new Error("未返回结果图片");
|
||||||
}
|
}
|
||||||
let finalImage = firstImage;
|
let finalImage = firstImage;
|
||||||
let finalImageSizeLabel = resolvedImageSize;
|
let finalImageSizeLabel: string = resolvedImageSize;
|
||||||
try {
|
try {
|
||||||
const normalizedImage = await normalizeReplacementResultImage({
|
const normalizedImage = await normalizeReplacementResultImage({
|
||||||
generatedImageUrl: firstImage.originalUrl,
|
generatedImageUrl: firstImage.originalUrl,
|
||||||
@ -6127,10 +6144,7 @@ export async function POST(request: Request) {
|
|||||||
: undefined
|
: undefined
|
||||||
);
|
);
|
||||||
const modelCreditCostPerImage = getModelCreditCost(currentModelConfig, "image", {
|
const modelCreditCostPerImage = getModelCreditCost(currentModelConfig, "image", {
|
||||||
imageSize:
|
imageSize: effectiveImageGenerationParams.imageSize,
|
||||||
typeof effectiveImageParams?.imageSize === "string"
|
|
||||||
? effectiveImageParams.imageSize
|
|
||||||
: defaultImageQualityParams.imageSize,
|
|
||||||
});
|
});
|
||||||
const modelCreditCostPerVideo = getModelCreditCost(currentModelConfig, "video", {
|
const modelCreditCostPerVideo = getModelCreditCost(currentModelConfig, "video", {
|
||||||
duration: Number(effectiveVideoParams?.duration) || undefined,
|
duration: Number(effectiveVideoParams?.duration) || undefined,
|
||||||
@ -6165,7 +6179,7 @@ export async function POST(request: Request) {
|
|||||||
1,
|
1,
|
||||||
Math.round(
|
Math.round(
|
||||||
Number(
|
Number(
|
||||||
effectiveImageParams?.imageCount || defaultImageQualityParams.imageCount || 1
|
effectiveImageGenerationParams.imageCount || defaultImageQualityParams.imageCount || 1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -6245,7 +6259,7 @@ export async function POST(request: Request) {
|
|||||||
const isGeminiImageProvider = ["gemini-image", "huanke-gemini"].includes((languageModel as any).provider);
|
const isGeminiImageProvider = ["gemini-image", "huanke-gemini"].includes((languageModel as any).provider);
|
||||||
if (isGeminiImageProvider && typeof (languageModel as any).doGenerate === "function") {
|
if (isGeminiImageProvider && typeof (languageModel as any).doGenerate === "function") {
|
||||||
chatApiLogger.info("[Chat API] Using Gemini image generation, provider:", (languageModel as any).provider);
|
chatApiLogger.info("[Chat API] Using Gemini image generation, provider:", (languageModel as any).provider);
|
||||||
chatApiLogger.info("[Chat API] Image params:", effectiveImageParams);
|
chatApiLogger.info("[Chat API] Image params:", effectiveImageGenerationParams);
|
||||||
|
|
||||||
// 🆕 获取备用模型配置
|
// 🆕 获取备用模型配置
|
||||||
const currentModelConfig = await getAiModelById({ id: finalModelId });
|
const currentModelConfig = await getAiModelById({ id: finalModelId });
|
||||||
@ -6332,11 +6346,7 @@ export async function POST(request: Request) {
|
|||||||
// 调用 doGenerate 获取图片(如果是备用模型,传入 overrideModelId)
|
// 调用 doGenerate 获取图片(如果是备用模型,传入 overrideModelId)
|
||||||
const result = await (languageModel as any).doGenerate({
|
const result = await (languageModel as any).doGenerate({
|
||||||
messages: modelMessages,
|
messages: modelMessages,
|
||||||
imageParams:
|
imageParams: effectiveImageGenerationParams,
|
||||||
effectiveImageParams || {
|
|
||||||
aspectRatio: defaultImageQualityParams.aspectRatio,
|
|
||||||
imageSize: defaultImageQualityParams.imageSize,
|
|
||||||
},
|
|
||||||
overrideModelId: isRetry ? modelIdToUse : undefined, // 🆕 使用备用模型 ID
|
overrideModelId: isRetry ? modelIdToUse : undefined, // 🆕 使用备用模型 ID
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -6362,7 +6372,7 @@ export async function POST(request: Request) {
|
|||||||
phase: "processing",
|
phase: "processing",
|
||||||
providerType: (languageModel as any).provider,
|
providerType: (languageModel as any).provider,
|
||||||
modelName: currentModelConfig?.displayName || actualModelId,
|
modelName: currentModelConfig?.displayName || actualModelId,
|
||||||
imageCount: effectiveImageParams?.imageCount || defaultImageQualityParams.imageCount || 1,
|
imageCount: effectiveImageGenerationParams.imageCount || defaultImageQualityParams.imageCount || 1,
|
||||||
},
|
},
|
||||||
"gemini:image-status-start",
|
"gemini:image-status-start",
|
||||||
);
|
);
|
||||||
@ -6384,10 +6394,10 @@ export async function POST(request: Request) {
|
|||||||
runtimeModelId: actualModelId,
|
runtimeModelId: actualModelId,
|
||||||
finalModelId,
|
finalModelId,
|
||||||
providerType: (languageModel as any).provider,
|
providerType: (languageModel as any).provider,
|
||||||
aspectRatio: effectiveImageParams?.aspectRatio,
|
aspectRatio: effectiveImageGenerationParams.aspectRatio,
|
||||||
imageSize: effectiveImageParams?.imageSize,
|
imageSize: effectiveImageGenerationParams.imageSize,
|
||||||
imageCount:
|
imageCount:
|
||||||
effectiveImageParams?.imageCount ||
|
effectiveImageGenerationParams.imageCount ||
|
||||||
defaultImageQualityParams.imageCount ||
|
defaultImageQualityParams.imageCount ||
|
||||||
1,
|
1,
|
||||||
},
|
},
|
||||||
@ -6405,7 +6415,7 @@ export async function POST(request: Request) {
|
|||||||
const fallbackResult = await generateImageWithFailoverCandidate({
|
const fallbackResult = await generateImageWithFailoverCandidate({
|
||||||
candidate,
|
candidate,
|
||||||
messages: buildMessagesForGemini(),
|
messages: buildMessagesForGemini(),
|
||||||
imageParams: effectiveImageParams,
|
imageParams: effectiveImageGenerationParams,
|
||||||
fallbackImageParams: {
|
fallbackImageParams: {
|
||||||
aspectRatio: defaultImageQualityParams.aspectRatio,
|
aspectRatio: defaultImageQualityParams.aspectRatio,
|
||||||
imageSize: defaultImageQualityParams.imageSize,
|
imageSize: defaultImageQualityParams.imageSize,
|
||||||
@ -6431,8 +6441,8 @@ export async function POST(request: Request) {
|
|||||||
primaryModelId: actualModelId,
|
primaryModelId: actualModelId,
|
||||||
fallbackModelId: candidate.model.modelId,
|
fallbackModelId: candidate.model.modelId,
|
||||||
providerType: candidate.provider.type,
|
providerType: candidate.provider.type,
|
||||||
aspectRatio: effectiveImageParams?.aspectRatio,
|
aspectRatio: effectiveImageGenerationParams.aspectRatio,
|
||||||
imageSize: effectiveImageParams?.imageSize,
|
imageSize: effectiveImageGenerationParams.imageSize,
|
||||||
},
|
},
|
||||||
}).catch((healthError) => {
|
}).catch((healthError) => {
|
||||||
chatApiLogger.warn("[Chat API] Record Gemini fallback health failure failed:", healthError);
|
chatApiLogger.warn("[Chat API] Record Gemini fallback health failure failed:", healthError);
|
||||||
@ -6467,9 +6477,9 @@ export async function POST(request: Request) {
|
|||||||
triedFallbackModelIds.add(String(candidate.model.id || ""));
|
triedFallbackModelIds.add(String(candidate.model.id || ""));
|
||||||
chatApiLogger.info(`[Chat API] 🔁 Gemini cross-provider failover: ${candidate.model.displayName} (${candidate.provider.type})`);
|
chatApiLogger.info(`[Chat API] 🔁 Gemini cross-provider failover: ${candidate.model.displayName} (${candidate.provider.type})`);
|
||||||
const fallbackResult = await generateImageWithFailoverCandidate({
|
const fallbackResult = await generateImageWithFailoverCandidate({
|
||||||
candidate,
|
candidate,
|
||||||
messages: buildMessagesForGemini(),
|
messages: buildMessagesForGemini(),
|
||||||
imageParams: effectiveImageParams,
|
imageParams: effectiveImageGenerationParams,
|
||||||
fallbackImageParams: {
|
fallbackImageParams: {
|
||||||
aspectRatio: defaultImageQualityParams.aspectRatio,
|
aspectRatio: defaultImageQualityParams.aspectRatio,
|
||||||
imageSize: defaultImageQualityParams.imageSize,
|
imageSize: defaultImageQualityParams.imageSize,
|
||||||
@ -6665,12 +6675,7 @@ export async function POST(request: Request) {
|
|||||||
const volcanoResult = await (volcanoLanguageModel as any).doGenerate({
|
const volcanoResult = await (volcanoLanguageModel as any).doGenerate({
|
||||||
messages: volcanoMessages,
|
messages: volcanoMessages,
|
||||||
maxImages: 1, // 故障转移时只生成 1 张
|
maxImages: 1, // 故障转移时只生成 1 张
|
||||||
imageParams:
|
imageParams: effectiveImageGenerationParams,
|
||||||
effectiveImageParams || {
|
|
||||||
aspectRatio: defaultImageQualityParams.aspectRatio,
|
|
||||||
imageSize: defaultImageQualityParams.imageSize,
|
|
||||||
imageCount: defaultImageQualityParams.imageCount,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const imageMarkdown = volcanoResult.text || "图片生成失败";
|
const imageMarkdown = volcanoResult.text || "图片生成失败";
|
||||||
@ -6844,7 +6849,7 @@ export async function POST(request: Request) {
|
|||||||
].includes((languageModel as any).provider);
|
].includes((languageModel as any).provider);
|
||||||
if (isAlibabaLikeImageProvider && typeof (languageModel as any).doGenerate === "function") {
|
if (isAlibabaLikeImageProvider && typeof (languageModel as any).doGenerate === "function") {
|
||||||
chatApiLogger.info("[Chat API] Using image generation provider:", (languageModel as any).provider);
|
chatApiLogger.info("[Chat API] Using image generation provider:", (languageModel as any).provider);
|
||||||
chatApiLogger.info("[Chat API] Image params:", effectiveImageParams);
|
chatApiLogger.info("[Chat API] Image params:", effectiveImageGenerationParams);
|
||||||
|
|
||||||
// 🆕 获取模型显示名称,用于错误提示
|
// 🆕 获取模型显示名称,用于错误提示
|
||||||
const alibabaModelConfig = await getAiModelById({ id: finalModelId });
|
const alibabaModelConfig = await getAiModelById({ id: finalModelId });
|
||||||
@ -6950,12 +6955,7 @@ export async function POST(request: Request) {
|
|||||||
apiKey: falApiKey,
|
apiKey: falApiKey,
|
||||||
modelId: actualModelId,
|
modelId: actualModelId,
|
||||||
messages: falMessages,
|
messages: falMessages,
|
||||||
imageParams:
|
imageParams: effectiveImageGenerationParams,
|
||||||
effectiveImageParams || {
|
|
||||||
aspectRatio: defaultImageQualityParams.aspectRatio,
|
|
||||||
imageSize: defaultImageQualityParams.imageSize,
|
|
||||||
imageCount: defaultImageQualityParams.imageCount,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const placeholderMessageId = generateUUID();
|
const placeholderMessageId = generateUUID();
|
||||||
@ -6982,9 +6982,9 @@ export async function POST(request: Request) {
|
|||||||
optimizedPrompt: smartAutoOptimizedPrompt || userPrompt || queuedTask.prompt,
|
optimizedPrompt: smartAutoOptimizedPrompt || userPrompt || queuedTask.prompt,
|
||||||
userPrompt: userPrompt || queuedTask.prompt,
|
userPrompt: userPrompt || queuedTask.prompt,
|
||||||
requestedImageCount:
|
requestedImageCount:
|
||||||
effectiveImageParams?.imageCount || defaultImageQualityParams.imageCount || 1,
|
effectiveImageGenerationParams.imageCount || defaultImageQualityParams.imageCount || 1,
|
||||||
aspectRatio: effectiveImageParams?.aspectRatio,
|
aspectRatio: effectiveImageGenerationParams.aspectRatio,
|
||||||
imageSize: effectiveImageParams?.imageSize,
|
imageSize: effectiveImageGenerationParams.imageSize,
|
||||||
outputSizeLabel: queuedTask.outputSizeLabel,
|
outputSizeLabel: queuedTask.outputSizeLabel,
|
||||||
sourceImageUrls: requestTargetResolution?.targetImageUrls || queuedTask.sourceImageUrls,
|
sourceImageUrls: requestTargetResolution?.targetImageUrls || queuedTask.sourceImageUrls,
|
||||||
sourceAssetIds: requestTargetResolution?.targetAssetIds || [],
|
sourceAssetIds: requestTargetResolution?.targetAssetIds || [],
|
||||||
@ -7012,7 +7012,7 @@ export async function POST(request: Request) {
|
|||||||
providerType: "fal-image",
|
providerType: "fal-image",
|
||||||
modelName: modelDisplayName,
|
modelName: modelDisplayName,
|
||||||
imageCount:
|
imageCount:
|
||||||
effectiveImageParams?.imageCount || defaultImageQualityParams.imageCount || 1,
|
effectiveImageGenerationParams.imageCount || defaultImageQualityParams.imageCount || 1,
|
||||||
},
|
},
|
||||||
"alibaba:image-status-queued",
|
"alibaba:image-status-queued",
|
||||||
);
|
);
|
||||||
@ -7074,12 +7074,8 @@ export async function POST(request: Request) {
|
|||||||
// 调用 doGenerate 获取图片,传递模型显示名称
|
// 调用 doGenerate 获取图片,传递模型显示名称
|
||||||
const result = await (languageModel as any).doGenerate({
|
const result = await (languageModel as any).doGenerate({
|
||||||
messages: modelMessages,
|
messages: modelMessages,
|
||||||
imageParams:
|
imageParams: effectiveImageGenerationParams,
|
||||||
effectiveImageParams || {
|
imageGenConfig: alibabaModelConfig?.imageGenConfig || null,
|
||||||
aspectRatio: defaultImageQualityParams.aspectRatio,
|
|
||||||
imageSize: defaultImageQualityParams.imageSize,
|
|
||||||
imageCount: defaultImageQualityParams.imageCount,
|
|
||||||
},
|
|
||||||
modelDisplayName, // 🆕 传递模型显示名称
|
modelDisplayName, // 🆕 传递模型显示名称
|
||||||
overrideModelId: isRetry ? modelIdToUse : undefined,
|
overrideModelId: isRetry ? modelIdToUse : undefined,
|
||||||
});
|
});
|
||||||
@ -7107,7 +7103,7 @@ export async function POST(request: Request) {
|
|||||||
phase: "processing",
|
phase: "processing",
|
||||||
providerType: (languageModel as any).provider,
|
providerType: (languageModel as any).provider,
|
||||||
modelName: alibabaModelConfig?.displayName || actualModelId,
|
modelName: alibabaModelConfig?.displayName || actualModelId,
|
||||||
imageCount: effectiveImageParams?.imageCount || defaultImageQualityParams.imageCount || 1,
|
imageCount: effectiveImageGenerationParams.imageCount || defaultImageQualityParams.imageCount || 1,
|
||||||
},
|
},
|
||||||
"alibaba:image-status-start",
|
"alibaba:image-status-start",
|
||||||
);
|
);
|
||||||
@ -7126,7 +7122,7 @@ export async function POST(request: Request) {
|
|||||||
const fallbackResult = await generateImageWithFailoverCandidate({
|
const fallbackResult = await generateImageWithFailoverCandidate({
|
||||||
candidate,
|
candidate,
|
||||||
messages: messagesForAlibaba,
|
messages: messagesForAlibaba,
|
||||||
imageParams: effectiveImageParams,
|
imageParams: effectiveImageGenerationParams,
|
||||||
fallbackImageParams: {
|
fallbackImageParams: {
|
||||||
aspectRatio: defaultImageQualityParams.aspectRatio,
|
aspectRatio: defaultImageQualityParams.aspectRatio,
|
||||||
imageSize: defaultImageQualityParams.imageSize,
|
imageSize: defaultImageQualityParams.imageSize,
|
||||||
@ -7218,12 +7214,8 @@ export async function POST(request: Request) {
|
|||||||
|
|
||||||
const candidateResult = await (candidateLanguageModel as any).doGenerate({
|
const candidateResult = await (candidateLanguageModel as any).doGenerate({
|
||||||
messages: candidateMessages,
|
messages: candidateMessages,
|
||||||
imageParams:
|
imageParams: effectiveImageGenerationParams,
|
||||||
effectiveImageParams || {
|
imageGenConfig: candidate.model.imageGenConfig || null,
|
||||||
aspectRatio: defaultImageQualityParams.aspectRatio,
|
|
||||||
imageSize: defaultImageQualityParams.imageSize,
|
|
||||||
imageCount: defaultImageQualityParams.imageCount,
|
|
||||||
},
|
|
||||||
modelDisplayName: candidate.model.displayName,
|
modelDisplayName: candidate.model.displayName,
|
||||||
overrideModelId: candidate.model.modelId,
|
overrideModelId: candidate.model.modelId,
|
||||||
});
|
});
|
||||||
@ -7501,12 +7493,7 @@ export async function POST(request: Request) {
|
|||||||
const tryGenerateImage = async (modelIdToUse: string, isRetry: boolean) => {
|
const tryGenerateImage = async (modelIdToUse: string, isRetry: boolean) => {
|
||||||
const result = await (languageModel as any).doGenerate({
|
const result = await (languageModel as any).doGenerate({
|
||||||
messages: modelMessages,
|
messages: modelMessages,
|
||||||
imageParams:
|
imageParams: effectiveImageGenerationParams,
|
||||||
effectiveImageParams || {
|
|
||||||
aspectRatio: defaultImageQualityParams.aspectRatio,
|
|
||||||
imageSize: defaultImageQualityParams.imageSize,
|
|
||||||
imageCount: defaultImageQualityParams.imageCount,
|
|
||||||
},
|
|
||||||
overrideModelId: isRetry ? modelIdToUse : undefined,
|
overrideModelId: isRetry ? modelIdToUse : undefined,
|
||||||
});
|
});
|
||||||
if (result?.finishReason === "error") {
|
if (result?.finishReason === "error") {
|
||||||
@ -7531,7 +7518,7 @@ export async function POST(request: Request) {
|
|||||||
phase: "processing",
|
phase: "processing",
|
||||||
providerType: "volcano-vision",
|
providerType: "volcano-vision",
|
||||||
modelName: volcanoModelConfig?.displayName || actualModelId,
|
modelName: volcanoModelConfig?.displayName || actualModelId,
|
||||||
imageCount: effectiveImageParams?.imageCount || defaultImageQualityParams.imageCount || 1,
|
imageCount: effectiveImageGenerationParams.imageCount || defaultImageQualityParams.imageCount || 1,
|
||||||
},
|
},
|
||||||
"volcano:image-status-start",
|
"volcano:image-status-start",
|
||||||
);
|
);
|
||||||
@ -7548,7 +7535,7 @@ export async function POST(request: Request) {
|
|||||||
const fallbackResult = await generateImageWithFailoverCandidate({
|
const fallbackResult = await generateImageWithFailoverCandidate({
|
||||||
candidate,
|
candidate,
|
||||||
messages: messagesForVolcano,
|
messages: messagesForVolcano,
|
||||||
imageParams: effectiveImageParams,
|
imageParams: effectiveImageGenerationParams,
|
||||||
fallbackImageParams: {
|
fallbackImageParams: {
|
||||||
aspectRatio: defaultImageQualityParams.aspectRatio,
|
aspectRatio: defaultImageQualityParams.aspectRatio,
|
||||||
imageSize: defaultImageQualityParams.imageSize,
|
imageSize: defaultImageQualityParams.imageSize,
|
||||||
@ -7639,12 +7626,8 @@ export async function POST(request: Request) {
|
|||||||
|
|
||||||
const candidateResult = await (candidateLanguageModel as any).doGenerate({
|
const candidateResult = await (candidateLanguageModel as any).doGenerate({
|
||||||
messages: candidateMessages,
|
messages: candidateMessages,
|
||||||
imageParams:
|
imageParams: effectiveImageGenerationParams,
|
||||||
effectiveImageParams || {
|
imageGenConfig: candidate.model.imageGenConfig || null,
|
||||||
aspectRatio: defaultImageQualityParams.aspectRatio,
|
|
||||||
imageSize: defaultImageQualityParams.imageSize,
|
|
||||||
imageCount: defaultImageQualityParams.imageCount,
|
|
||||||
},
|
|
||||||
modelDisplayName: candidate.model.displayName,
|
modelDisplayName: candidate.model.displayName,
|
||||||
overrideModelId: candidate.model.modelId,
|
overrideModelId: candidate.model.modelId,
|
||||||
});
|
});
|
||||||
@ -8402,7 +8385,7 @@ export async function POST(request: Request) {
|
|||||||
const fallbackResult = await generateImageWithFailoverCandidate({
|
const fallbackResult = await generateImageWithFailoverCandidate({
|
||||||
candidate,
|
candidate,
|
||||||
messages: messagesForCrossProvider,
|
messages: messagesForCrossProvider,
|
||||||
imageParams: effectiveImageParams,
|
imageParams: effectiveImageGenerationParams,
|
||||||
fallbackImageParams: {
|
fallbackImageParams: {
|
||||||
aspectRatio: defaultImageQualityParams.aspectRatio,
|
aspectRatio: defaultImageQualityParams.aspectRatio,
|
||||||
imageSize: defaultImageQualityParams.imageSize,
|
imageSize: defaultImageQualityParams.imageSize,
|
||||||
@ -8498,12 +8481,8 @@ export async function POST(request: Request) {
|
|||||||
|
|
||||||
const candidateResult = await (candidateLanguageModel as any).doGenerate({
|
const candidateResult = await (candidateLanguageModel as any).doGenerate({
|
||||||
messages: candidateMessages,
|
messages: candidateMessages,
|
||||||
imageParams:
|
imageParams: effectiveImageGenerationParams,
|
||||||
effectiveImageParams || {
|
imageGenConfig: candidate.model.imageGenConfig || null,
|
||||||
aspectRatio: defaultImageQualityParams.aspectRatio,
|
|
||||||
imageSize: defaultImageQualityParams.imageSize,
|
|
||||||
imageCount: defaultImageQualityParams.imageCount,
|
|
||||||
},
|
|
||||||
modelDisplayName: candidate.model.displayName,
|
modelDisplayName: candidate.model.displayName,
|
||||||
overrideModelId: candidate.model.modelId,
|
overrideModelId: candidate.model.modelId,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -30,10 +30,20 @@ const videoParamsSchema = z.object({
|
|||||||
returnLastFrame: z.boolean().optional(),
|
returnLastFrame: z.boolean().optional(),
|
||||||
}).optional();
|
}).optional();
|
||||||
|
|
||||||
|
const imageSizeValues = ["1K", "2K", "4K"] as const;
|
||||||
|
|
||||||
|
function normalizeImageSizeInput(value: unknown) {
|
||||||
|
if (typeof value !== "string") return undefined;
|
||||||
|
const normalized = value.trim().toUpperCase();
|
||||||
|
return imageSizeValues.includes(normalized as (typeof imageSizeValues)[number])
|
||||||
|
? normalized
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
// 🆕 图片生成参数 schema
|
// 🆕 图片生成参数 schema
|
||||||
const imageParamsSchema = z.object({
|
const imageParamsSchema = z.object({
|
||||||
aspectRatio: z.string().optional(),
|
aspectRatio: z.string().optional(),
|
||||||
imageSize: z.string().optional(),
|
imageSize: z.preprocess(normalizeImageSizeInput, z.enum(imageSizeValues).optional()),
|
||||||
imageCount: z.number().min(1).max(10).optional(),
|
imageCount: z.number().min(1).max(10).optional(),
|
||||||
// 阿里生图专用参数
|
// 阿里生图专用参数
|
||||||
size: z.string().optional(), // 自定义分辨率,如 "1024*1024"
|
size: z.string().optional(), // 自定义分辨率,如 "1024*1024"
|
||||||
|
|||||||
@ -71,8 +71,17 @@ const IMAGE_SIZE_OPTIONS = [
|
|||||||
{ value: "2K", label: "2K", disabled: false },
|
{ value: "2K", label: "2K", disabled: false },
|
||||||
{ value: "4K", label: "4K", disabled: false },
|
{ value: "4K", label: "4K", disabled: false },
|
||||||
] as const;
|
] as const;
|
||||||
|
type ImageSizeValue = (typeof IMAGE_SIZE_OPTIONS)[number]["value"];
|
||||||
|
|
||||||
const IMAGE_SIZE_PIXEL_MAP: Record<string, number> = {
|
function normalizeImageSizeValue(value?: string, fallback: ImageSizeValue = "2K"): ImageSizeValue {
|
||||||
|
const normalized = String(value || "").trim().toUpperCase();
|
||||||
|
if (normalized === "1K" || normalized === "2K" || normalized === "4K") {
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IMAGE_SIZE_PIXEL_MAP: Record<ImageSizeValue, number> = {
|
||||||
"1K": 1024,
|
"1K": 1024,
|
||||||
"2K": 2048,
|
"2K": 2048,
|
||||||
"4K": 4096,
|
"4K": 4096,
|
||||||
@ -143,16 +152,16 @@ export function ImageParamsBar({
|
|||||||
const fallbackCount = options[0] ?? 1;
|
const fallbackCount = options[0] ?? 1;
|
||||||
const imageCount = options.includes(raw.imageCount || fallbackCount) ? (raw.imageCount || fallbackCount) : fallbackCount;
|
const imageCount = options.includes(raw.imageCount || fallbackCount) ? (raw.imageCount || fallbackCount) : fallbackCount;
|
||||||
// 根据模型配置校正分辨率:如果当前选择的档位被禁用,则降级到可用的档位
|
// 根据模型配置校正分辨率:如果当前选择的档位被禁用,则降级到可用的档位
|
||||||
let imageSize = raw.imageSize || "2K";
|
let imageSize = normalizeImageSizeValue(raw.imageSize);
|
||||||
if (imageGenConfig) {
|
if (imageGenConfig) {
|
||||||
const sizeAllowed = (s: string) => {
|
const sizeAllowed = (s: ImageSizeValue) => {
|
||||||
if (s === "1K") return imageGenConfig.supports1K !== false;
|
if (s === "1K") return imageGenConfig.supports1K !== false;
|
||||||
if (s === "2K") return imageGenConfig.supports2K !== false;
|
if (s === "2K") return imageGenConfig.supports2K !== false;
|
||||||
if (s === "4K") return imageGenConfig.supports4K !== false;
|
if (s === "4K") return imageGenConfig.supports4K !== false;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
if (!sizeAllowed(imageSize)) {
|
if (!sizeAllowed(imageSize)) {
|
||||||
imageSize = ["2K", "1K", "4K"].find(sizeAllowed) || "2K";
|
imageSize = (["2K", "1K", "4K"] as const).find(sizeAllowed) || "2K";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -209,7 +218,7 @@ export function ImageParamsBar({
|
|||||||
return getGrsaiGptImageOutputSize(aspectRatio, imageSize);
|
return getGrsaiGptImageOutputSize(aspectRatio, imageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
const size = IMAGE_SIZE_PIXEL_MAP[imageSize] || IMAGE_SIZE_PIXEL_MAP["2K"];
|
const size = IMAGE_SIZE_PIXEL_MAP[normalizeImageSizeValue(imageSize)];
|
||||||
if (aspectRatio === "auto" || aspectRatio === "1:1") {
|
if (aspectRatio === "auto" || aspectRatio === "1:1") {
|
||||||
return { width: size, height: size };
|
return { width: size, height: size };
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,29 +15,29 @@ interface RuxaImageParams {
|
|||||||
outputFormat?: "png" | "jpg" | "jpeg" | "webp";
|
outputFormat?: "png" | "jpg" | "jpeg" | "webp";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface RuxaImageModelConfig {
|
||||||
|
supportsSize?: boolean;
|
||||||
|
supports1K?: boolean;
|
||||||
|
supports2K?: boolean;
|
||||||
|
supports4K?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
interface UploadedImage {
|
interface UploadedImage {
|
||||||
thumbnail: string;
|
thumbnail: string;
|
||||||
original: string;
|
original: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_RESOLUTION = "1k";
|
const DEFAULT_RESOLUTION = "1K";
|
||||||
const DEFAULT_OUTPUT_FORMAT = "png";
|
const DEFAULT_OUTPUT_FORMAT = "png";
|
||||||
const POLL_INTERVAL_MS = 2000;
|
const POLL_INTERVAL_MS = 2000;
|
||||||
const POLL_MAX_ATTEMPTS = 90;
|
const POLL_MAX_ATTEMPTS = 240;
|
||||||
const RUXA_NANO_BANANA_2_DOC_MODEL_ID = "gemini-3.1-flash-image-preview";
|
|
||||||
const RUXA_MODEL_ID_ALIASES: Record<string, string> = {
|
|
||||||
"google/nano-banana-2": RUXA_NANO_BANANA_2_DOC_MODEL_ID,
|
|
||||||
};
|
|
||||||
|
|
||||||
function normalizeRuxaModelId(modelId?: string) {
|
function normalizeRuxaModelId(modelId?: string) {
|
||||||
const raw = String(modelId || "").trim();
|
const raw = String(modelId || "").trim();
|
||||||
if (!raw) return "gpt-image-1.5";
|
if (!raw) {
|
||||||
return RUXA_MODEL_ID_ALIASES[raw] || raw;
|
throw new Error("RUXA 模型 ID 未配置");
|
||||||
}
|
}
|
||||||
|
return raw;
|
||||||
function isRuxaNanoBanana2Model(modelId?: string) {
|
|
||||||
const normalized = normalizeRuxaModelId(modelId);
|
|
||||||
return normalized === RUXA_NANO_BANANA_2_DOC_MODEL_ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeUrlForCompare(url: string) {
|
function normalizeUrlForCompare(url: string) {
|
||||||
@ -68,7 +68,9 @@ function normalizeAspectRatio(aspectRatio?: string) {
|
|||||||
const normalized = aspectRatio.trim().toLowerCase();
|
const normalized = aspectRatio.trim().toLowerCase();
|
||||||
if (normalized === "auto") return undefined;
|
if (normalized === "auto") return undefined;
|
||||||
const ratio = aspectRatio.trim();
|
const ratio = aspectRatio.trim();
|
||||||
if (["1:1", "16:9", "9:16", "4:3", "3:4", "2:3", "3:2"].includes(ratio)) {
|
if (
|
||||||
|
["1:1", "16:9", "9:16", "4:3", "3:4", "2:3", "3:2", "5:4", "4:5", "21:9"].includes(ratio)
|
||||||
|
) {
|
||||||
return ratio;
|
return ratio;
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -76,25 +78,65 @@ function normalizeAspectRatio(aspectRatio?: string) {
|
|||||||
|
|
||||||
function normalizeResolution(imageSize?: string) {
|
function normalizeResolution(imageSize?: string) {
|
||||||
if (!imageSize) return DEFAULT_RESOLUTION;
|
if (!imageSize) return DEFAULT_RESOLUTION;
|
||||||
const normalized = imageSize.trim().toLowerCase();
|
const normalized = imageSize.trim().toUpperCase();
|
||||||
if (["1k", "2k", "4k"].includes(normalized)) return normalized;
|
if (["1K", "2K", "4K"].includes(normalized)) return normalized;
|
||||||
return DEFAULT_RESOLUTION;
|
return DEFAULT_RESOLUTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeOutputFormat(outputFormat?: string): "png" | "jpg" | "webp" {
|
function normalizeOutputFormat(outputFormat?: string): "png" | "jpg" {
|
||||||
if (!outputFormat) return DEFAULT_OUTPUT_FORMAT;
|
if (!outputFormat) return DEFAULT_OUTPUT_FORMAT;
|
||||||
const normalized = outputFormat.trim().toLowerCase();
|
const normalized = outputFormat.trim().toLowerCase();
|
||||||
if (normalized === "jpg" || normalized === "jpeg") return "jpg";
|
if (normalized === "jpg" || normalized === "jpeg") return "jpg";
|
||||||
if (normalized === "webp") return "webp";
|
|
||||||
return "png";
|
return "png";
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeRuxaOutputFormat(modelId: string | undefined, outputFormat?: string) {
|
function isResolutionSupported(resolution: string, config?: RuxaImageModelConfig | null) {
|
||||||
const normalized = normalizeOutputFormat(outputFormat);
|
if (config?.supportsSize === false) {
|
||||||
if (!isRuxaNanoBanana2Model(modelId)) {
|
return false;
|
||||||
return normalized;
|
|
||||||
}
|
}
|
||||||
return normalized === "jpg" ? "jpeg" : normalized;
|
|
||||||
|
const normalized = resolution.toLowerCase();
|
||||||
|
if (normalized === "1k") return config?.supports1K !== false;
|
||||||
|
if (normalized === "2k") return config?.supports2K !== false;
|
||||||
|
if (normalized === "4k") return config?.supports4K !== false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRuxaTaskInput({
|
||||||
|
prompt,
|
||||||
|
imageUrls,
|
||||||
|
aspectRatio,
|
||||||
|
resolution,
|
||||||
|
outputFormat,
|
||||||
|
modelConfig,
|
||||||
|
}: {
|
||||||
|
prompt: string;
|
||||||
|
imageUrls: string[];
|
||||||
|
aspectRatio?: string;
|
||||||
|
resolution: string;
|
||||||
|
outputFormat: string;
|
||||||
|
modelConfig?: RuxaImageModelConfig | null;
|
||||||
|
}) {
|
||||||
|
const input: Record<string, unknown> = {
|
||||||
|
prompt,
|
||||||
|
output_format: outputFormat,
|
||||||
|
};
|
||||||
|
const ratio = aspectRatio || "1:1";
|
||||||
|
|
||||||
|
input.size = ratio;
|
||||||
|
input.aspect_ratio = ratio;
|
||||||
|
if (isResolutionSupported(resolution, modelConfig)) {
|
||||||
|
input.resolution = resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageUrls[0]) {
|
||||||
|
input.image = imageUrls[0];
|
||||||
|
}
|
||||||
|
if (imageUrls.length > 0) {
|
||||||
|
input.image_input = imageUrls.slice(0, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractTaskId(payload: any): string | undefined {
|
function extractTaskId(payload: any): string | undefined {
|
||||||
@ -132,9 +174,16 @@ function extractStatus(payload: any): string | undefined {
|
|||||||
|
|
||||||
function extractErrorMessage(payload: any): string {
|
function extractErrorMessage(payload: any): string {
|
||||||
let parsedResultJson: any = null;
|
let parsedResultJson: any = null;
|
||||||
if (typeof payload?.resultJson === "string" && payload.resultJson.trim()) {
|
const rawResultJson =
|
||||||
|
typeof payload?.resultJson === "string" && payload.resultJson.trim()
|
||||||
|
? payload.resultJson
|
||||||
|
: typeof payload?.data?.resultJson === "string" && payload.data.resultJson.trim()
|
||||||
|
? payload.data.resultJson
|
||||||
|
: "";
|
||||||
|
|
||||||
|
if (rawResultJson) {
|
||||||
try {
|
try {
|
||||||
parsedResultJson = JSON.parse(payload.resultJson);
|
parsedResultJson = JSON.parse(rawResultJson);
|
||||||
} catch {
|
} catch {
|
||||||
parsedResultJson = null;
|
parsedResultJson = null;
|
||||||
}
|
}
|
||||||
@ -148,7 +197,7 @@ function extractErrorMessage(payload: any): string {
|
|||||||
payload?.errorMessage ||
|
payload?.errorMessage ||
|
||||||
parsedResultJson?.failMsg ||
|
parsedResultJson?.failMsg ||
|
||||||
parsedResultJson?.error ||
|
parsedResultJson?.error ||
|
||||||
payload?.resultJson ||
|
rawResultJson ||
|
||||||
payload?.data?.message ||
|
payload?.data?.message ||
|
||||||
payload?.data?.error ||
|
payload?.data?.error ||
|
||||||
"RUXA 任务执行失败"
|
"RUXA 任务执行失败"
|
||||||
@ -388,48 +437,38 @@ export function createRuxaImage({ apiKey, baseURL }: RuxaImageConfig) {
|
|||||||
doGenerate: async (options: {
|
doGenerate: async (options: {
|
||||||
messages: Array<{ role: string; content: any }>;
|
messages: Array<{ role: string; content: any }>;
|
||||||
imageParams?: RuxaImageParams;
|
imageParams?: RuxaImageParams;
|
||||||
|
imageGenConfig?: RuxaImageModelConfig | null;
|
||||||
overrideModelId?: string;
|
overrideModelId?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { prompt, imageUrls } = extractPromptAndImages(options.messages);
|
const { prompt, imageUrls } = extractPromptAndImages(options.messages);
|
||||||
const aspectRatio = normalizeAspectRatio(options.imageParams?.aspectRatio);
|
const aspectRatio = normalizeAspectRatio(options.imageParams?.aspectRatio);
|
||||||
const resolution = normalizeResolution(options.imageParams?.imageSize);
|
const resolution = normalizeResolution(options.imageParams?.imageSize);
|
||||||
const requestedModelId = options.overrideModelId || modelId || "gpt-image-1.5";
|
const requestedModelId = options.overrideModelId || modelId;
|
||||||
const activeModelId = normalizeRuxaModelId(requestedModelId);
|
const activeModelId = normalizeRuxaModelId(requestedModelId);
|
||||||
const outputFormat = normalizeRuxaOutputFormat(activeModelId, options.imageParams?.outputFormat);
|
const outputFormat = normalizeOutputFormat(options.imageParams?.outputFormat);
|
||||||
const isNanoBanana2 = isRuxaNanoBanana2Model(activeModelId);
|
|
||||||
|
|
||||||
const createEndpoint = joinApiPath(baseURL, "/api/v1/tasks/create");
|
const createEndpoint = joinApiPath(baseURL, "/api/v1/tasks/create");
|
||||||
const callbackUrl = process.env.RUXA_CALLBACK_URL?.trim();
|
const callbackUrl = process.env.RUXA_CALLBACK_URL?.trim();
|
||||||
const input: Record<string, unknown> = {
|
const input = buildRuxaTaskInput({
|
||||||
prompt,
|
prompt,
|
||||||
output_format: outputFormat,
|
imageUrls,
|
||||||
};
|
aspectRatio,
|
||||||
if (isNanoBanana2) {
|
resolution,
|
||||||
input.size = aspectRatio || "1:1";
|
outputFormat,
|
||||||
} else {
|
modelConfig: options.imageGenConfig,
|
||||||
input.resolution = resolution;
|
});
|
||||||
}
|
|
||||||
if (aspectRatio && !isNanoBanana2) {
|
|
||||||
input.size = aspectRatio;
|
|
||||||
input.aspect_ratio = aspectRatio;
|
|
||||||
}
|
|
||||||
if (imageUrls[0]) {
|
|
||||||
input.image = imageUrls[0];
|
|
||||||
}
|
|
||||||
if (imageUrls.length > 1) {
|
|
||||||
input.image_input = imageUrls;
|
|
||||||
}
|
|
||||||
const requestBody = {
|
const requestBody = {
|
||||||
input,
|
input,
|
||||||
model: activeModelId,
|
model: activeModelId,
|
||||||
...(callbackUrl ? { callBackUrl: callbackUrl } : {}),
|
...(callbackUrl ? { callback_url: callbackUrl } : {}),
|
||||||
};
|
};
|
||||||
if (activeModelId !== requestedModelId) {
|
console.log("[Ruxa Image] Creating task:", {
|
||||||
console.log("[Ruxa Image] Remapped modelId for provider compatibility:", {
|
model: activeModelId,
|
||||||
requestedModelId,
|
resolution: input.resolution || null,
|
||||||
activeModelId,
|
aspectRatio: input.aspect_ratio || input.size || null,
|
||||||
});
|
outputFormat,
|
||||||
}
|
imageInputCount: imageUrls.length,
|
||||||
|
});
|
||||||
const createResponse = await fetch(createEndpoint, {
|
const createResponse = await fetch(createEndpoint, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@ -494,6 +533,7 @@ export function createRuxaImage({ apiKey, baseURL }: RuxaImageConfig) {
|
|||||||
doStream: async function* (options: {
|
doStream: async function* (options: {
|
||||||
messages: Array<{ role: string; content: any }>;
|
messages: Array<{ role: string; content: any }>;
|
||||||
imageParams?: RuxaImageParams;
|
imageParams?: RuxaImageParams;
|
||||||
|
imageGenConfig?: RuxaImageModelConfig | null;
|
||||||
overrideModelId?: string;
|
overrideModelId?: string;
|
||||||
}) {
|
}) {
|
||||||
const result = await this.doGenerate(options);
|
const result = await this.doGenerate(options);
|
||||||
|
|||||||
@ -587,6 +587,7 @@ export async function generateCanvasImage(
|
|||||||
...imageParams,
|
...imageParams,
|
||||||
imageCount: batchImageCount,
|
imageCount: batchImageCount,
|
||||||
},
|
},
|
||||||
|
imageGenConfig: selectedModel.model.imageGenConfig || null,
|
||||||
});
|
});
|
||||||
return result.text || "";
|
return result.text || "";
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,7 +3,7 @@ const MAX_STRING_LENGTH = 240;
|
|||||||
|
|
||||||
const SENSITIVE_KEY_PATTERN =
|
const SENSITIVE_KEY_PATTERN =
|
||||||
/(authorization|cookie|password|secret|token|apikey|api_key|accesskey|access_key|clientsecret|client_secret|credential|prompt|session|csrf|code)/i;
|
/(authorization|cookie|password|secret|token|apikey|api_key|accesskey|access_key|clientsecret|client_secret|credential|prompt|session|csrf|code)/i;
|
||||||
const URL_KEY_PATTERN = /(url|uri|endpoint|origin|href|src|image|thumbnail|avatar|file)/i;
|
const URL_KEY_PATTERN = /(url|uri|endpoint|origin|href|src|thumbnail|avatar|file)/i;
|
||||||
const DATA_URL_PATTERN = /^data:[^;]+;base64,/i;
|
const DATA_URL_PATTERN = /^data:[^;]+;base64,/i;
|
||||||
const EMBEDDED_DATA_URL_PATTERN = /data:[^;,\s]+;base64,[A-Za-z0-9+/=_-]+/gi;
|
const EMBEDDED_DATA_URL_PATTERN = /data:[^;,\s]+;base64,[A-Za-z0-9+/=_-]+/gi;
|
||||||
const EMBEDDED_URL_PATTERN = /https?:\/\/[^\s"'<>),]+/gi;
|
const EMBEDDED_URL_PATTERN = /https?:\/\/[^\s"'<>),]+/gi;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user