增加2.5模型调用

This commit is contained in:
andy committed 2026-09-23 15:10:13 +08:00
1 parent 3f29ba716a
commit be655b6569
32 files changed
+1075 -56

No files matched your search

+2 -2
View File
@@ -106,7 +106,7 @@ const settingDefinitions: Array<{
{
id: "evolink",
title: "EvoLink 图片 API",
description: "用于 GPT Image 2 图片生成;Base URL 和模型使用系统默认值即可。",
description: "支持 GPT Image 2 和 Image 2.5 Flare / Sunburst 图片生成;Base URL 和默认模型可保持系统默认值。",
fields: [
{ key: "EVOLINK_API_KEY", label: "EvoLink API Key", secret: true, type: "password" },
{ key: "EVOLINK_BASE_URL", label: "Base URL", defaultValue: "https://api.evolink.ai" },
@@ -165,7 +165,7 @@ const engineFieldDefinitions: FieldDefinition[] = [
options: [
{ label: "即梦 / 火山视觉", value: "jimeng" },
{ label: "Seedream 5.0 Pro / 火山方舟", value: "seedream" },
{ label: "EvoLink GPT Image 2", value: "evolink" },
{ label: "EvoLink GPT Image 2 / 2.5", value: "evolink" },
{ label: "阿里云百炼 Wan 2.7", value: "bailian" }
]
},
+32
View File
@@ -85,6 +85,36 @@ const EVOLINK_GPT_IMAGE_DIMENSIONS = [
}
] satisfies NonNullable<BillingPriceRuleInput["parameterDimensions"]>;
function evolink25PriceRule(model: string, sourceUrl: string): BillingPriceRuleInput {
const parameterDimensions = structuredClone(EVOLINK_GPT_IMAGE_DIMENSIONS);
parameterDimensions[0].tiers = [
{ value: "low", label: "快速", standardFactor: 4 / 9, markupMultiplier: DEFAULT_BILLING_MARKUP_MULTIPLIER, enabled: true },
{ value: "medium", label: "标准", standardFactor: 1, markupMultiplier: DEFAULT_BILLING_MARKUP_MULTIPLIER, enabled: true },
{ value: "high", label: "精细", standardFactor: 35 / 9, markupMultiplier: DEFAULT_BILLING_MARKUP_MULTIPLIER, enabled: true }
];
parameterDimensions[1].tiers = parameterDimensions[1].tiers.slice(0, 1);
return {
id: `base-evolink-${model}`,
provider: "evolink",
capability: "image.generate",
reqKey: model,
unit: "image",
standardUnitPriceFen: 9,
markupMultiplier: DEFAULT_BILLING_MARKUP_MULTIPLIER,
enabled: true,
note: "1K 基础输出估算:low/medium/high 成本为 ¥0.04/¥0.09/¥0.35;输入费用未单独加收,非上游实际 token 账单。",
parameterDimensions,
source: {
url: sourceUrl,
currency: "USD",
unitPrice: 0.012,
fxRate: BILLING_USD_CNY_RATE,
basis: "1024×1024、无参考图输出费用估算:low 约 $0.0053,medium 约 $0.012,high 约 $0.0474;人民币标准成本向上取整到分。参考图和提示词会影响上游实扣。",
observedAt: "2026-09-23"
}
};
}
export const DEFAULT_BILLING_PRICE_RULES: BillingPriceRuleInput[] = [
{
id: "base-volcengine-jimeng-seedream46",
@@ -124,6 +154,8 @@ export const DEFAULT_BILLING_PRICE_RULES: BillingPriceRuleInput[] = [
observedAt: BILLING_CATALOG_OBSERVED_AT
}
},
evolink25PriceRule("gpt-image-2.5-flare", "https://evolink.ai/gpt-image-2-5"),
evolink25PriceRule("gpt-image-2.5-sunburst", "https://evolink.ai/zh/gpt-image-2-5-sunburst"),
{
id: "base-bailian-wan27-image-pro",
provider: "bailian",
+9 -3
View File
@@ -9,7 +9,6 @@ import {
extractEvolinkResultUrls,
getEffectiveImageEngine,
getEvolinkImageConfig,
getEvolinkImageSettings,
getEvolinkTaskId,
mapEvolinkStatus,
queryEvolinkTask,
@@ -52,7 +51,13 @@ export type SubmitImageJobInput = {
min_ratio?: number;
max_ratio?: number;
force_single?: boolean;
quality?: string;
quality?: unknown;
model?: string;
size?: string;
resolution?: unknown;
n?: unknown;
imageCount?: unknown;
settings?: unknown;
retryOf?: string;
idempotencyKey?: string;
idempotencyFingerprint?: string;
@@ -141,6 +146,7 @@ function prepareImageGeneration(input: SubmitImageJobInput, origin: string): Pre
const capability = getEnabledImageCapability(input.capability);
const normalizedUrls = (input.imageUrls || []).map((url) => toAbsoluteUrl(url, origin));
const engine = getEffectiveImageEngine(input.capability, input.engine);
if (input.model !== undefined && engine !== "evolink") throw new Error("Unsupported image model for the selected engine.");
const providerPayload = engine === "bailian"
? buildBailianImagePayload(input.capability, { ...input, imageUrls: normalizedUrls })
: engine === "evolink"
@@ -152,7 +158,7 @@ function prepareImageGeneration(input: SubmitImageJobInput, origin: string): Pre
: engine === "evolink"
? !getEvolinkImageConfig()
: !getVisualClientConfig();
const reqKey = engine === "bailian" ? bailianConfig.imageModel : engine === "evolink" ? getEvolinkImageSettings().model : capability.reqKey;
const reqKey = engine === "bailian" ? bailianConfig.imageModel : engine === "evolink" ? String(providerPayload.model) : capability.reqKey;
const provider = engine === "bailian" ? "bailian" : engine === "evolink" ? "evolink" : "volcengine-visual";
const requestPayload = {
engine,
+9
View File
@@ -58,6 +58,7 @@ function normalizeTemplateSettings(value: unknown): ImageTemplate["settings"] {
const width = optionalPositiveInteger(value.width);
const height = optionalPositiveInteger(value.height);
const engine = normalizeImageEngine(value.engine);
const model = engine === "evolink" ? normalizeEvolinkModel(value.model) : undefined;
const scale = optionalScale(value.scale);
const quality = normalizeQuality(value.quality);
const size = normalizeSeedreamSize(value.size);
@@ -65,6 +66,7 @@ function normalizeTemplateSettings(value: unknown): ImageTemplate["settings"] {
const optimizeMode = normalizeOptimizeMode(value.optimizeMode);
return {
...(engine ? { engine } : {}),
...(model ? { model } : {}),
...(width && height ? { width, height } : {}),
...(typeof value.forceSingle === "boolean" ? { forceSingle: value.forceSingle } : {}),
...(scale !== undefined ? { scale } : {}),
@@ -99,6 +101,13 @@ function normalizeImageEngine(value: unknown): ImageTemplate["settings"]["engine
return undefined;
}
function normalizeEvolinkModel(value: unknown): string | undefined {
const text = optionalText(value, 100);
if (!text) return undefined;
if (!/^[a-z0-9][a-z0-9._-]*$/.test(text)) throw new Error("EvoLink 模型 ID 格式无效");
return text;
}
function normalizeSeedreamSize(value: unknown): ImageTemplate["settings"]["size"] | undefined {
const text = optionalText(value, 10)?.toUpperCase();
if (text === "1K" || text === "1.5K" || text === "2K") return text;
+14 -9
View File
@@ -35,7 +35,12 @@ export type PublicJobCreateBody = {
min_ratio?: number;
max_ratio?: number;
force_single?: boolean;
quality?: string;
quality?: unknown;
model?: string;
size?: string;
resolution?: unknown;
n?: unknown;
imageCount?: unknown;
engine?: ImageCreationEngine | VideoCreationEngine;
};
@@ -102,8 +107,14 @@ export async function createPublicGenerationJob(input: {
height: asNumber(input.body.height),
min_ratio: asNumber(input.body.min_ratio),
max_ratio: asNumber(input.body.max_ratio),
force_single: Boolean(input.body.force_single),
quality: normalizeQuality(input.body.quality)
force_single: input.body.force_single,
quality: input.body.quality,
model: input.body.model,
size: input.body.size,
resolution: input.body.resolution,
n: input.body.n,
imageCount: input.body.imageCount,
settings: input.body.settings
} satisfies SubmitImageJobInput, input.origin);
return { job, reused: false };
}
@@ -134,12 +145,6 @@ function asNumber(value: unknown): number | undefined {
return Number.isFinite(parsed) ? parsed : undefined;
}
function normalizeQuality(value: unknown): string | undefined {
if (typeof value !== "string") return undefined;
const normalized = value.trim().toLowerCase();
return ["low", "medium", "high"].includes(normalized) ? normalized : undefined;
}
function fingerprintBody(body: PublicJobCreateBody): string {
const { idempotencyKey: _idempotencyKey, ...fingerprintSource } = body;
return createHash("sha256").update(stableStringify(fingerprintSource)).digest("hex");