You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
5.9 KiB
143 lines
5.9 KiB
import type { AspectRatio, LLMModelType, NodeType, SelectedModel, WorkflowNodeData } from "@/types";
|
|
import type { ProviderModel } from "@/lib/providers/types";
|
|
import { POPI_PROVIDER_ID } from "@/lib/providerMode";
|
|
import { useModelStore, type PopiModelKind } from "@/store/modelStore";
|
|
import { loadNodeDefaults } from "@/store/utils/localStorage";
|
|
import {
|
|
findPopiserverModelByKey,
|
|
POPISERVER_DEFAULT_AUDIO_MODEL_ID,
|
|
POPISERVER_DEFAULT_IMAGE_MODEL_ID,
|
|
POPISERVER_DEFAULT_LLM_MODEL_ID,
|
|
POPISERVER_DEFAULT_VIDEO_MODEL_ID,
|
|
} from "@/store/utils/defaultImageModel";
|
|
import { useGenerationPreferenceStore } from "@/store/generationPreferenceStore";
|
|
import { toSelectedModel } from "@/utils/selectedModel";
|
|
|
|
type GenerationNodeType = "smartImage" | "smartVideo" | "smartAudio" | "smartText" | "nanoBanana" | "generateVideo" | "generateAudio" | "llmGenerate";
|
|
|
|
function getKindForNodeType(type: NodeType): PopiModelKind | null {
|
|
if (type === "smartImage") return "image";
|
|
if (type === "nanoBanana") return "image";
|
|
if (type === "smartVideo") return "video";
|
|
if (type === "generateVideo") return "video";
|
|
if (type === "smartAudio") return "audio";
|
|
if (type === "generateAudio") return "audio";
|
|
if (type === "llmGenerate" || type === "smartText") return "llm";
|
|
return null;
|
|
}
|
|
|
|
function getConfiguredPopiModelId(): string | null {
|
|
const defaults = loadNodeDefaults();
|
|
const llm = defaults.llm;
|
|
return llm?.provider === POPI_PROVIDER_ID && llm.model ? llm.model : null;
|
|
}
|
|
|
|
function getCodeDefaultPopiModelId(): string {
|
|
return POPISERVER_DEFAULT_LLM_MODEL_ID;
|
|
}
|
|
|
|
function matchesConfiguredModel(model: ProviderModel, configuredModelId: string): boolean {
|
|
return (
|
|
model.id === configuredModelId ||
|
|
String(model.metadata?.aiModelId ?? "") === configuredModelId ||
|
|
String(model.metadata?.aiModelCode ?? "") === configuredModelId ||
|
|
String(model.metadata?.aiModelCodeAlias ?? "") === configuredModelId
|
|
);
|
|
}
|
|
|
|
function getDefaultModelIdForPreference(type: "image" | "video" | "audio"): string {
|
|
if (type === "image") return POPISERVER_DEFAULT_IMAGE_MODEL_ID;
|
|
if (type === "video") return POPISERVER_DEFAULT_VIDEO_MODEL_ID;
|
|
return POPISERVER_DEFAULT_AUDIO_MODEL_ID;
|
|
}
|
|
|
|
function resolvePreferenceModel(type: "image" | "video" | "audio", selectedModel: SelectedModel): SelectedModel {
|
|
const models = useModelStore.getState().byKind[type];
|
|
const model =
|
|
findPopiserverModelByKey(models, selectedModel.modelId) ??
|
|
findPopiserverModelByKey(models, selectedModel.displayName) ??
|
|
findPopiserverModelByKey(models, String(selectedModel.aiModelId ?? "")) ??
|
|
findPopiserverModelByKey(models, selectedModel.aiModelCode) ??
|
|
findPopiserverModelByKey(models, selectedModel.aiModelCodeAlias) ??
|
|
findPopiserverModelByKey(models, getDefaultModelIdForPreference(type));
|
|
|
|
if (!model) return selectedModel;
|
|
const resolved = toSelectedModel(model);
|
|
const preferences = useGenerationPreferenceStore.getState();
|
|
if (type === "image") preferences.updateImagePreference({ model: resolved });
|
|
if (type === "video") preferences.updateVideoPreference({ model: resolved });
|
|
if (type === "audio") preferences.updateAudioPreference({ model: resolved });
|
|
return resolved;
|
|
}
|
|
|
|
async function buildGenerationPreferenceNodeData(type: NodeType): Promise<Partial<WorkflowNodeData> | undefined> {
|
|
const preferences = useGenerationPreferenceStore.getState();
|
|
|
|
if (type === "smartImage" || type === "nanoBanana") {
|
|
const { type: _type, model: _model, ...preferenceConfig } = preferences.image;
|
|
const aspectRatio = preferences.image.aspectRatio as AspectRatio;
|
|
const selectedModel = resolvePreferenceModel("image", preferences.image.model);
|
|
return {
|
|
...preferenceConfig,
|
|
aspectRatio,
|
|
resolution: preferences.image.resolution,
|
|
selectedModel,
|
|
imageCount: preferences.image.imageCount,
|
|
parameters: preferences.image.parameters ?? {},
|
|
} as Partial<WorkflowNodeData>;
|
|
}
|
|
|
|
if (type === "smartVideo" || type === "generateVideo") {
|
|
const { type: _type, model: _model, ...preferenceConfig } = preferences.video;
|
|
const selectedModel = resolvePreferenceModel("video", preferences.video.model);
|
|
return {
|
|
...preferenceConfig,
|
|
selectedModel,
|
|
parameters: preferences.video.parameters ?? {},
|
|
} as Partial<WorkflowNodeData>;
|
|
}
|
|
|
|
if (type === "smartAudio" || type === "generateAudio") {
|
|
const { type: _type, model: _model, ...preferenceConfig } = preferences.audio;
|
|
const parameters = preferences.audio.parameters && typeof preferences.audio.parameters === "object"
|
|
? preferences.audio.parameters as Record<string, unknown>
|
|
: {};
|
|
const selectedModel = resolvePreferenceModel("audio", preferences.audio.model);
|
|
return {
|
|
...preferenceConfig,
|
|
selectedModel,
|
|
audioVoiceId: preferences.audio.voiceId,
|
|
parameters,
|
|
} as Partial<WorkflowNodeData>;
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
export async function buildDefaultGenerationNodeData(
|
|
type: NodeType
|
|
): Promise<Partial<WorkflowNodeData> | undefined> {
|
|
const generationPreferenceData = await buildGenerationPreferenceNodeData(type);
|
|
if (generationPreferenceData) return generationPreferenceData;
|
|
|
|
const kind = getKindForNodeType(type);
|
|
if (!kind || kind === "3d") return undefined;
|
|
|
|
const generationType = type as GenerationNodeType;
|
|
const models = useModelStore.getState().byKind[kind];
|
|
if (models.length === 0) return undefined;
|
|
|
|
const preferredModelId = getConfiguredPopiModelId() ?? getCodeDefaultPopiModelId();
|
|
const model = models.find((item) => matchesConfiguredModel(item, preferredModelId)) ?? models[0];
|
|
const selectedModel = toSelectedModel(model);
|
|
|
|
if (generationType === "llmGenerate" || generationType === "smartText") {
|
|
return {
|
|
provider: POPI_PROVIDER_ID,
|
|
model: selectedModel.modelId as LLMModelType,
|
|
selectedModel,
|
|
} as Partial<WorkflowNodeData>;
|
|
}
|
|
|
|
return { selectedModel } as Partial<WorkflowNodeData>;
|
|
}
|
|
|