feat(*): 模型生成链路 - 完善 Agnes 结果兼容、价格展示与请求日志追踪
This commit is contained in:
@@ -4,14 +4,14 @@ import { Popover } from "antd";
|
||||
|
||||
import { canvasThemes, type CanvasTheme } from "@/lib/canvas-theme";
|
||||
import { modelCapabilityConfigFor, videoDurationOptions } from "@/lib/model-capabilities";
|
||||
import { compatibleModelInGroup, configuredModelDisplayName, groupModelsByDisplayName, modelCompatibilityError, modelRequestOptions, resolveCompatibleModel, type ModelRequirements } from "@/lib/model-selection";
|
||||
import { normalizeVideoResolution } from "@/lib/video-generation-options";
|
||||
import { modelQuoteRequest, normalizeTierResolution, priceTiersForCurrentSelection } from "@/lib/model-pricing";
|
||||
import { compatibleModelInGroup, configuredModelDisplayName, groupModelsByDisplayName, modelCompatibilityError, resolveCompatibleModel, type ModelRequirements } from "@/lib/model-selection";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { modelDisplayName, modelIcon, modelOptionName, PUBLIC_MODEL_CATALOG_ID, resolveModelChannel, selectableModelsByCapability, type AiConfig, type ModelCapability } from "@/stores/use-config-store";
|
||||
import { useThemeStore } from "@/stores/use-theme-store";
|
||||
import { useUserStore } from "@/stores/use-user-store";
|
||||
import { ModelLogo } from "@/components/model-logo";
|
||||
import { quoteLogicalModel, type LogicalModelQuote, type ModelRequestIntent } from "@/services/api/logical-models";
|
||||
import { quoteLogicalModel, type LogicalModelQuote } from "@/services/api/logical-models";
|
||||
|
||||
type ModelPickerProps = {
|
||||
config: AiConfig;
|
||||
@@ -396,48 +396,6 @@ function pickerModelOptionLabel(config: AiConfig, model: string, showConfiguredM
|
||||
return channel.scope === "system" ? displayName : `${displayName}(${channel.name})`;
|
||||
}
|
||||
|
||||
function priceTiersForCurrentSelection(
|
||||
tiers: NonNullable<NonNullable<AiConfig["channels"][number]["modelCosts"]>[number]["logicalPriceTiers"]>,
|
||||
capability: ModelCapability | undefined,
|
||||
config: AiConfig,
|
||||
requirements?: ModelRequirements,
|
||||
) {
|
||||
const requested: Record<string, string> = {};
|
||||
if (capability === "video") {
|
||||
const imageCount = (requirements?.input?.imageCount || 0) + (requirements?.input?.characterCount || 0);
|
||||
if (imageCount > 0) requested.imageCount = String(imageCount);
|
||||
const resolution = normalizeTierResolution(config.vquality);
|
||||
if (resolution !== "*") requested.vquality = resolution;
|
||||
const seconds = Math.max(0, Math.floor(Number(config.videoSeconds) || 0));
|
||||
if (seconds > 0) requested.videoSeconds = String(seconds);
|
||||
}
|
||||
if (capability === "image") {
|
||||
if (config.quality && config.quality !== "auto") requested.quality = config.quality.toLowerCase();
|
||||
if (config.size && config.size !== "auto") requested.size = config.size.toLowerCase();
|
||||
}
|
||||
let bestScore = -1;
|
||||
let matched: typeof tiers = [];
|
||||
for (const tier of tiers) {
|
||||
const selector = tier.selector || {};
|
||||
const conditions = Object.entries(selector).filter(([, value]) => value && value !== "*");
|
||||
if (conditions.some(([key, value]) => requested[key] !== value)) continue;
|
||||
const score = conditions.length;
|
||||
if (score > bestScore) {
|
||||
bestScore = score;
|
||||
matched = [tier];
|
||||
} else if (score === bestScore) {
|
||||
matched.push(tier);
|
||||
}
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
function normalizeTierResolution(value: string) {
|
||||
const raw = String(value || "").trim();
|
||||
if (!raw || raw === "*") return "*";
|
||||
return `${normalizeVideoResolution(raw)}p`;
|
||||
}
|
||||
|
||||
function channelTierPriceSummary(
|
||||
visibleTiers: NonNullable<NonNullable<AiConfig["channels"][number]["modelCosts"]>[number]["logicalPriceTiers"]>,
|
||||
allTiers: NonNullable<NonNullable<AiConfig["channels"][number]["modelCosts"]>[number]["logicalPriceTiers"]>,
|
||||
@@ -533,31 +491,6 @@ function ModelPrice({ price, quote, compact = false }: { price: ModelMenuPrice |
|
||||
);
|
||||
}
|
||||
|
||||
function modelQuoteRequest(config: AiConfig, value: string, capability?: ModelCapability, requirements?: ModelRequirements): { logicalModelID: string; intent: ModelRequestIntent } | undefined {
|
||||
if (!capability || !value) return undefined;
|
||||
const channel = resolveModelChannel(config, value);
|
||||
if (channel.scope !== "system") return undefined;
|
||||
const cost = channel.modelCosts?.find((item) => item.model === modelOptionName(value));
|
||||
if (!cost?.logicalModelId) return undefined;
|
||||
const input = requirements?.input;
|
||||
const intent: ModelRequestIntent = {
|
||||
capability,
|
||||
operation: requirements?.videoOperation,
|
||||
inputs: {
|
||||
image: (input?.imageCount || 0) + (input?.characterCount || 0),
|
||||
video: input?.videoCount || 0,
|
||||
audio: input?.audioCount || 0,
|
||||
},
|
||||
options: {
|
||||
...modelRequestOptions(config, capability),
|
||||
...(requirements?.options || {}),
|
||||
...(requirements?.videoSeconds ? { videoSeconds: Number(requirements.videoSeconds) } : {}),
|
||||
...(requirements?.imageSize ? { size: requirements.imageSize } : {}),
|
||||
},
|
||||
};
|
||||
return { logicalModelID: cost.logicalModelId, intent };
|
||||
}
|
||||
|
||||
function modelMenuMeta(model: string, capability?: ModelCapability): { description: string; time?: string } {
|
||||
const name = modelOptionName(model).toLowerCase();
|
||||
if (capability === "image") {
|
||||
|
||||
Reference in New Issue
Block a user