fix(canvas): 项目画风执行 - 自动同步模型路由与画风计划
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { applyStyleExecutionPlan, createStyleProfileSnapshot, parseStyleProfile, resolveStyleExecutionPlan, serializeStyleProfile, type StyleExecutionPlan, type StyleProfileSnapshot } from "@/lib/canvas/style-profile";
|
||||
import { resolveModelRequestConfig, type AiConfig } from "@/stores/use-config-store";
|
||||
import { logicalModelIDForConfig, resolveModelRequestConfig, type AiConfig } from "@/stores/use-config-store";
|
||||
import type { CanvasNodeData } from "@/types/canvas";
|
||||
|
||||
export type CanvasStyleExecutionRuntime = {
|
||||
@@ -16,7 +16,8 @@ export function resolveCanvasStyleExecution(nodes: CanvasNodeData[], sourceNode:
|
||||
if (!profile) return null;
|
||||
const requestConfig = resolveModelRequestConfig(config, config.model);
|
||||
const plan = resolveStyleExecutionPlan(profile, { mode, model: requestConfig.model, interfaceType: requestConfig.interfaceType || requestConfig.apiFormat });
|
||||
if (plan.status === "blocked") throw new Error(`项目画风与当前模型不兼容:${plan.warnings.join(";")}`);
|
||||
// 平台模型的真实供应模型由后端入队时路由,前端只能预览,最终兼容性由后端重算。
|
||||
if (plan.status === "blocked" && !logicalModelIDForConfig(config)) throw new Error(`当前模型无法完整执行项目画风:${plan.warnings.join(";")}。请切换模型,或在项目设置中停用对应画风资产`);
|
||||
return { profile, profileJson: serializeStyleProfile(profile), plan, prompt: applyStyleExecutionPlan(prompt, plan) };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import { runBackendCanvasGenerationTask } from "@/lib/canvas/canvas-project-generation";
|
||||
import { resolveStyleExecutionPlan, serializeStyleProfile, type StyleProfileSnapshot } from "@/lib/canvas/style-profile";
|
||||
import { resolveModelRequestConfig, type AiConfig } from "@/stores/use-config-store";
|
||||
import { logicalModelIDForConfig, resolveModelRequestConfig, type AiConfig } from "@/stores/use-config-store";
|
||||
|
||||
type ProjectStylePrompt = { id: string; title: string; prompt: string; profile?: StyleProfileSnapshot };
|
||||
|
||||
export async function generateCharacterTurnaround(input: { projectId: string; assetId: string; versionId: string; name: string; definition: Record<string, unknown>; projectStyle?: ProjectStylePrompt; config: AiConfig }) {
|
||||
const promptTemplateVariables = characterTurnaroundVariables(input.name, input.definition, input.projectStyle);
|
||||
const requestConfig = resolveModelRequestConfig(input.config, input.config.imageModel || input.config.model);
|
||||
const generationConfig = { ...input.config, model: input.config.imageModel || input.config.model, count: "1" };
|
||||
const requestConfig = resolveModelRequestConfig(generationConfig, generationConfig.model);
|
||||
const styleExecutionPlan = input.projectStyle?.profile ? resolveStyleExecutionPlan(input.projectStyle.profile, { mode: "image", model: requestConfig.model, interfaceType: requestConfig.interfaceType || requestConfig.apiFormat }) : undefined;
|
||||
if (styleExecutionPlan?.status === "blocked") throw new Error(`项目画风与当前图片模型不兼容:${styleExecutionPlan.warnings.join(";")}`);
|
||||
if (styleExecutionPlan?.status === "blocked" && !logicalModelIDForConfig(generationConfig)) throw new Error(`当前图片模型无法完整执行项目画风:${styleExecutionPlan.warnings.join(";")}。请切换图片模型,或在项目设置中停用对应画风资产`);
|
||||
await runBackendCanvasGenerationTask({
|
||||
projectId: input.projectId,
|
||||
nodeId: `character-turnaround:${input.assetId}`,
|
||||
mode: "image",
|
||||
prompt: "使用当前启用的角色三视图模板。",
|
||||
config: { ...input.config, model: input.config.imageModel || input.config.model, count: "1" },
|
||||
config: generationConfig,
|
||||
metadata: { operation: "character_turnaround", promptTemplateOperation: "character_turnaround", promptTemplateVariables, characterAssetId: input.assetId, stylePresetId: input.projectStyle?.id, styleProfileJson: input.projectStyle?.profile ? serializeStyleProfile(input.projectStyle.profile) : undefined, styleExecutionPlan, resolvedCharacterVersions: [{ assetId: input.assetId, versionId: input.versionId }] },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,12 +7,14 @@ import { isLocalDreaminaBackgroundTask, localDreaminaTaskId, projectLocalDreamin
|
||||
import { modelCapabilityConfigFor } from "@/lib/model-capabilities";
|
||||
import { grokImagePromptLimitError } from "@/lib/grok-image-prompt-limit";
|
||||
import { resolveVideoOperation } from "@/lib/model-selection";
|
||||
import { modelOptionName, resolveModelChannel, resolveModelRequestConfig, type AiConfig } from "@/stores/use-config-store";
|
||||
import { logicalModelIDForConfig, modelOptionName, resolveModelChannel, resolveModelRequestConfig, type AiConfig } from "@/stores/use-config-store";
|
||||
import { useLocalDreaminaModelStore } from "@/stores/use-local-dreamina-model-store";
|
||||
import type { ReferenceImage } from "@/types/image";
|
||||
import type { ReferenceAudio, ReferenceVideo } from "@/types/media";
|
||||
import { buildBackendToolRequests, type ResponseFunctionTool, type ResponseInputMessage, type ToolChoice, type ToolResponseResult } from "@/services/api/image";
|
||||
|
||||
export { logicalModelIDForConfig };
|
||||
|
||||
export type BackendGenerationMode = "text" | "image" | "video" | "audio";
|
||||
|
||||
export type BackendGenerationResult = {
|
||||
@@ -500,11 +502,6 @@ export function backendProviderConfig(config: AiConfig) {
|
||||
};
|
||||
}
|
||||
|
||||
export function logicalModelIDForConfig(config: AiConfig) {
|
||||
const channel = resolveModelChannel(config, config.model);
|
||||
return channel.modelCosts?.find((item) => item.model === modelOptionName(config.model))?.logicalModelId || "";
|
||||
}
|
||||
|
||||
function logicalCapabilityOptions(config: AiConfig, mode: BackendGenerationMode) {
|
||||
const channel = resolveModelChannel(config, config.model);
|
||||
const spec = channel.modelCosts?.find((item) => item.model === modelOptionName(config.model))?.logicalCapabilitySpec;
|
||||
|
||||
@@ -494,6 +494,11 @@ export function resolveModelChannel(config: AiConfig, value: string) {
|
||||
return matched || config.channels[0] || createModelChannel({ id: "default", name: "默认渠道", baseUrl: config.baseUrl, apiKey: config.apiKey, apiFormat: config.apiFormat, models: config.models.map(modelOptionName) });
|
||||
}
|
||||
|
||||
export function logicalModelIDForConfig(config: AiConfig) {
|
||||
const channel = resolveModelChannel(config, config.model);
|
||||
return channel.modelCosts?.find((item) => item.model === modelOptionName(config.model))?.logicalModelId || "";
|
||||
}
|
||||
|
||||
export function channelConnectionSignature(channel: ModelChannel) {
|
||||
return [channel.baseUrl.trim(), channel.apiKey.trim(), channel.secretKey?.trim() || "", channel.apiFormat, channel.interfaceType || "auto", channel.allowLocalChannel === true ? "local:1" : "local:0", JSON.stringify(channel.headers || [])].join("\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user