15 changed files with 312 additions and 128 deletions
@ -0,0 +1,101 @@ |
|||
import type { LLMModelType, NodeType, SelectedModel, WorkflowNodeData } from "@/types"; |
|||
import type { ProviderModel } from "@/lib/providers/types"; |
|||
import { isPopiProviderMode, POPI_PROVIDER_ID } from "@/lib/providerMode"; |
|||
import { useModelStore, type PopiModelKind } from "@/store/modelStore"; |
|||
import { loadNodeDefaults } from "@/store/utils/localStorage"; |
|||
import { |
|||
POPISERVER_DEFAULT_AUDIO_MODEL_ID, |
|||
POPISERVER_DEFAULT_IMAGE_MODEL_ID, |
|||
POPISERVER_DEFAULT_LLM_MODEL_ID, |
|||
POPISERVER_DEFAULT_VIDEO_MODEL_ID, |
|||
} from "@/store/utils/defaultImageModel"; |
|||
|
|||
type GenerationNodeType = "nanoBanana" | "generateVideo" | "generateAudio" | "llmGenerate"; |
|||
|
|||
function getKindForNodeType(type: NodeType): PopiModelKind | null { |
|||
if (type === "nanoBanana") return "image"; |
|||
if (type === "generateVideo") return "video"; |
|||
if (type === "generateAudio") return "audio"; |
|||
if (type === "llmGenerate") return "llm"; |
|||
return null; |
|||
} |
|||
|
|||
function getConfiguredPopiModelId(type: GenerationNodeType): string | null { |
|||
const defaults = loadNodeDefaults(); |
|||
if (type === "nanoBanana") { |
|||
const model = defaults.generateImage?.selectedModel; |
|||
return model?.provider === POPI_PROVIDER_ID && model.modelId ? model.modelId : null; |
|||
} |
|||
if (type === "generateVideo") { |
|||
const model = defaults.generateVideo?.selectedModel; |
|||
return model?.provider === POPI_PROVIDER_ID && model.modelId ? model.modelId : null; |
|||
} |
|||
if (type === "generateAudio") { |
|||
const model = defaults.generateAudio?.selectedModel; |
|||
return model?.provider === POPI_PROVIDER_ID && model.modelId ? model.modelId : null; |
|||
} |
|||
const llm = defaults.llm; |
|||
return llm?.provider === POPI_PROVIDER_ID && llm.model ? llm.model : null; |
|||
} |
|||
|
|||
function getCodeDefaultPopiModelId(type: GenerationNodeType): string { |
|||
if (type === "nanoBanana") return POPISERVER_DEFAULT_IMAGE_MODEL_ID; |
|||
if (type === "generateVideo") return POPISERVER_DEFAULT_VIDEO_MODEL_ID; |
|||
if (type === "generateAudio") return POPISERVER_DEFAULT_AUDIO_MODEL_ID; |
|||
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 providerModelToSelectedModel(model: ProviderModel): SelectedModel { |
|||
return { |
|||
provider: model.provider, |
|||
modelId: model.id, |
|||
displayName: model.name, |
|||
capabilities: model.capabilities, |
|||
metadata: model.metadata, |
|||
pricing: model.pricing |
|||
? { |
|||
type: model.pricing.type, |
|||
amount: model.pricing.amount, |
|||
variants: model.pricing.variants, |
|||
} |
|||
: undefined, |
|||
}; |
|||
} |
|||
|
|||
export async function buildDefaultGenerationNodeData( |
|||
type: NodeType |
|||
): Promise<Partial<WorkflowNodeData> | undefined> { |
|||
if (!isPopiProviderMode()) return undefined; |
|||
|
|||
const kind = getKindForNodeType(type); |
|||
if (!kind || kind === "3d") return undefined; |
|||
|
|||
const generationType = type as GenerationNodeType; |
|||
await useModelStore.getState().initializePopiModels(); |
|||
|
|||
const models = useModelStore.getState().byKind[kind]; |
|||
if (models.length === 0) return undefined; |
|||
|
|||
const preferredModelId = getConfiguredPopiModelId(generationType) ?? getCodeDefaultPopiModelId(generationType); |
|||
const model = models.find((item) => matchesConfiguredModel(item, preferredModelId)) ?? models[0]; |
|||
const selectedModel = providerModelToSelectedModel(model); |
|||
|
|||
if (generationType === "llmGenerate") { |
|||
return { |
|||
provider: POPI_PROVIDER_ID, |
|||
model: selectedModel.modelId as LLMModelType, |
|||
selectedModel, |
|||
} as Partial<WorkflowNodeData>; |
|||
} |
|||
|
|||
return { selectedModel } as Partial<WorkflowNodeData>; |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
import type { ModelCapability } from "@/lib/providers/types"; |
|||
|
|||
export type PopiModelMediaKind = "image" | "video" | "audio" | "llm"; |
|||
|
|||
type PopiSubtypeConfig = { |
|||
kind: PopiModelMediaKind; |
|||
capabilities: ModelCapability[]; |
|||
}; |
|||
|
|||
export const POPI_SUBTYPE_CLASSIFICATION: Record<number, PopiSubtypeConfig> = { |
|||
102: { kind: "image", capabilities: ["text-to-image"] }, |
|||
103: { kind: "image", capabilities: ["image-to-image"] }, |
|||
104: { kind: "image", capabilities: ["image-to-image"] }, |
|||
105: { kind: "image", capabilities: ["image-to-image"] }, |
|||
106: { kind: "image", capabilities: ["image-to-image"] }, |
|||
107: { kind: "image", capabilities: ["image-to-image"] }, |
|||
108: { kind: "image", capabilities: ["image-to-image"] }, |
|||
109: { kind: "image", capabilities: ["image-to-image"] }, |
|||
202: { kind: "video", capabilities: ["image-to-video"] }, |
|||
203: { kind: "video", capabilities: ["image-to-video"] }, |
|||
204: { kind: "video", capabilities: ["image-to-video"] }, |
|||
205: { kind: "video", capabilities: ["image-to-video"] }, |
|||
301: { kind: "audio", capabilities: ["text-to-audio"] }, |
|||
501: { kind: "llm", capabilities: ["text-to-text"] }, |
|||
}; |
|||
|
|||
export const POPI_SUBTYPES_BY_KIND: Record<PopiModelMediaKind, number[]> = { |
|||
image: [102, 103, 104, 105, 106, 107, 108, 109], |
|||
video: [202, 203, 204, 205], |
|||
audio: [301], |
|||
llm: [501], |
|||
}; |
|||
|
|||
export const POPI_CAPABILITIES_BY_KIND: Record<PopiModelMediaKind, ModelCapability[]> = { |
|||
image: ["text-to-image", "image-to-image"], |
|||
video: ["text-to-video", "image-to-video", "video-to-video", "audio-to-video"], |
|||
audio: ["text-to-audio"], |
|||
llm: ["text-to-text"], |
|||
}; |
|||
|
|||
export function getPopiSubTypeFilter(kind: PopiModelMediaKind): string { |
|||
return POPI_SUBTYPES_BY_KIND[kind].join(","); |
|||
} |
|||
|
|||
export function getPopiCapabilitiesForSubType(subType: number): ModelCapability[] { |
|||
return POPI_SUBTYPE_CLASSIFICATION[subType]?.capabilities ?? []; |
|||
} |
|||
|
|||
export function getPopiKindForSubType(subType: number): PopiModelMediaKind | null { |
|||
return POPI_SUBTYPE_CLASSIFICATION[subType]?.kind ?? null; |
|||
} |
|||
|
|||
export function getPopiCapabilitiesForKind(kind: PopiModelMediaKind): ModelCapability[] { |
|||
return POPI_CAPABILITIES_BY_KIND[kind]; |
|||
} |
|||
@ -1,16 +1,13 @@ |
|||
export type PopiModelMediaFilter = "image" | "video" | "audio" | "llm"; |
|||
import { |
|||
getPopiSubTypeFilter, |
|||
type PopiModelMediaKind, |
|||
} from "@/utils/popiModelClassification"; |
|||
|
|||
const POPI_MODEL_FILTERS: Record<PopiModelMediaFilter, { subType: string }> = { |
|||
image: { subType: "102,103,106" }, |
|||
video: { subType: "202,203,204" }, |
|||
audio: { subType: "301" }, |
|||
llm: { subType: "501" }, |
|||
}; |
|||
export type PopiModelMediaFilter = PopiModelMediaKind; |
|||
|
|||
export function appendPopiModelQueryParams( |
|||
params: URLSearchParams, |
|||
filter: PopiModelMediaFilter |
|||
): void { |
|||
const config = POPI_MODEL_FILTERS[filter]; |
|||
params.set("subType", config.subType); |
|||
params.set("subType", getPopiSubTypeFilter(filter)); |
|||
} |
|||
|
|||
Loading…
Reference in new issue