Sync Studio models and add all-category pickers

This commit is contained in:
Anil Matcha
2026-08-05 19:58:13 +05:30
parent 8431746324
commit 85d6c1218a
5 changed files with 747 additions and 64 deletions
+21 -17
View File
@@ -841,23 +841,27 @@ export default function AudioStudio({
{isOpen && (
<div className="absolute left-0 right-0 mt-1 z-50 bg-[#161618] border border-zinc-700 rounded shadow-3xl max-h-60 overflow-y-auto custom-scrollbar p-1">
{schema.enum.map((opt) => (
<button
key={opt}
type="button"
onClick={() => {
setParams(prev => ({ ...prev, [key]: opt }));
setOpenParamDropdown(null);
}}
className={`w-full text-left px-4 py-2.5 rounded text-xs font-bold transition-all border ${
params[key] === opt
? "text-primary bg-primary/10 border-primary/20"
: "text-zinc-200 border-transparent hover:bg-zinc-900 hover:text-white"
}`}
>
{opt}
</button>
))}
{schema.enum.map((opt) => {
const optionValue = typeof opt === "object" ? opt.value : opt;
const optionLabel = typeof opt === "object" ? (opt.label || opt.value) : opt;
return (
<button
key={optionValue}
type="button"
onClick={() => {
setParams(prev => ({ ...prev, [key]: optionValue }));
setOpenParamDropdown(null);
}}
className={`w-full text-left px-4 py-2.5 rounded text-xs font-bold transition-all border ${
params[key] === optionValue
? "text-primary bg-primary/10 border-primary/20"
: "text-zinc-200 border-transparent hover:bg-zinc-900 hover:text-white"
}`}
>
{optionLabel}
</button>
);
})}
</div>
)}
{schema.description && (
+62 -18
View File
@@ -582,13 +582,32 @@ const PROVIDER_LOGOS = {
const invertLogos = ['openai', 'blackforest', 'runway', 'ideogram', 'lightricks', 'grok'];
function ModelDropdown({ models, selectedModel, onSelect, onClose }) {
function ModelDropdown({ selectedModel, onSelect, onClose }) {
const [search, setSearch] = useState("");
// Find current model's provider to pre-select the provider tab ("slide")
const currentModelObj = models.find((m) => m.id === selectedModel);
const initialProvider = currentModelObj?.provider || "all";
const [selectedProvider, setSelectedProvider] = useState(initialProvider);
const modelCategories = [
{
id: "all",
label: "All",
entries: [
...t2iModels.map((model) => ({ model, category: "t2i" })),
...i2iModels.map((model) => ({ model, category: "i2i" })),
],
},
{
id: "t2i",
label: "Text to Image",
entries: t2iModels.map((model) => ({ model, category: "t2i" })),
},
{
id: "i2i",
label: "Image to Image",
entries: i2iModels.map((model) => ({ model, category: "i2i" })),
},
];
const [selectedCategory, setSelectedCategory] = useState("all");
const [selectedProvider, setSelectedProvider] = useState("all");
const activeCategory = modelCategories.find((category) => category.id === selectedCategory) || modelCategories[0];
const modelEntries = activeCategory.entries;
const activeItemRef = useRef(null);
@@ -639,7 +658,7 @@ function ModelDropdown({ models, selectedModel, onSelect, onClose }) {
const availableProviders = [];
const seenProviders = new Set();
models.forEach(m => {
modelEntries.forEach(({ model: m }) => {
const pId = m.provider || 'muapi';
const pName = m.provider_name || 'Muapi';
if (!seenProviders.has(pId)) {
@@ -648,7 +667,7 @@ function ModelDropdown({ models, selectedModel, onSelect, onClose }) {
}
});
const filtered = models.filter((m) => {
const filtered = modelEntries.filter(({ model: m }) => {
// 1. Filter by provider tab
if (selectedProvider !== "all") {
const pId = m.provider || 'muapi';
@@ -714,7 +733,26 @@ function ModelDropdown({ models, selectedModel, onSelect, onClose }) {
{/* Right Pane: Search input + Models list */}
<div className="flex-1 flex flex-col gap-2 min-w-0">
<div className="border-b border-white/5 shrink-0 pb-2">
<div className="border-b border-white/5 shrink-0 pb-2 space-y-2">
<div className="flex gap-1.5 overflow-x-auto custom-scrollbar pb-0.5">
{modelCategories.map((category) => (
<button
key={category.id}
type="button"
onClick={() => {
setSelectedCategory(category.id);
setSelectedProvider("all");
}}
className={`shrink-0 rounded-lg px-2.5 py-1.5 text-[10px] font-bold transition-colors border ${
selectedCategory === category.id
? "bg-primary/15 text-primary border-primary/30"
: "bg-white/[0.02] text-white/50 border-white/[0.04] hover:bg-white/5 hover:text-white"
}`}
>
{category.label}
</button>
))}
</div>
<div className="flex items-center gap-3 bg-white/5 rounded-xl px-4 py-2 border border-white/5 focus-within:border-primary/50 transition-colors">
<svg
width="14"
@@ -740,7 +778,7 @@ function ModelDropdown({ models, selectedModel, onSelect, onClose }) {
</div>
<div className="text-xs font-semibold text-secondary py-1 shrink-0 flex items-center justify-between">
<span>Available models</span>
<span>{activeCategory.label} models</span>
{selectedProvider !== "all" && (
<span className="text-[10px] bg-white/5 px-2 py-0.5 rounded text-white/60">
{availableProviders.find(p => p.id === selectedProvider)?.name || selectedProvider}
@@ -754,13 +792,13 @@ function ModelDropdown({ models, selectedModel, onSelect, onClose }) {
No models found
</div>
) : (
filtered.map((m) => (
filtered.map(({ model: m, category }) => (
<div
key={m.id}
key={`${category}:${m.id}`}
ref={selectedModel === m.id ? activeItemRef : null}
onClick={(e) => {
e.stopPropagation();
onSelect(m);
onSelect(m, category);
onClose();
}}
className={`flex items-center justify-between p-3 hover:bg-white/5 rounded-lg cursor-pointer transition-all border border-transparent hover:border-white/5 ${
@@ -1149,23 +1187,30 @@ export default function ImageStudio({
}, [selectedModelId]);
// ── Model selection ──────────────────────────────────────────────────────
const handleModelSelect = (m) => {
const ars = imageMode
const handleModelSelect = (m, category = imageMode ? "i2i" : "t2i") => {
const nextImageMode = category === "i2i";
const ars = nextImageMode
? getAspectRatiosForI2IModel(m.id)
: getAspectRatiosForModel(m.id);
const resolutions = imageMode
const resolutions = nextImageMode
? getResolutionsForI2IModel(m.id)
: getResolutionsForModel(m.id);
if (!nextImageMode && imageMode) {
setUploadedImageUrls([]);
setSwapImageUrl(null);
}
setImageMode(nextImageMode);
setSelectedModelId(m.id);
setSelectedModelName(m.name);
setSelectedAr(ars[0] || "1:1");
setSelectedQuality(resolutions[0] || null);
setSwapImageUrl(null);
if (imageMode) {
if (nextImageMode) {
setMaxImages(getMaxImagesForI2IModel(m.id));
const effects = getEffectsForI2IModel(m.id);
setSelectedEffect(effects.length > 0 ? (getDefaultEffectForI2IModel(m.id) || effects[0]) : "");
} else {
setMaxImages(1);
setSelectedEffect("");
}
};
@@ -1542,7 +1587,6 @@ export default function ImageStudio({
>
<PromptPopoverHeader>Model</PromptPopoverHeader>
<ModelDropdown
models={currentModels}
selectedModel={selectedModelId}
onSelect={handleModelSelect}
onClose={() => setDropdownOpen(null)}
+75 -23
View File
@@ -146,15 +146,38 @@ const PROVIDER_LOGOS = {
const invertLogos = ['openai', 'blackforest', 'runway', 'ideogram', 'lightricks', 'grok'];
function ModelDropdown({ imageMode, selectedModel, onSelect, onClose }) {
function ModelDropdown({ selectedModel, onSelect, onClose }) {
const [search, setSearch] = useState("");
const generationModels = imageMode ? i2vModels : t2vModels;
// Find current model's provider to pre-select the provider tab ("slide")
const allCurrentModels = [...generationModels, ...v2vModels];
const currentModelObj = allCurrentModels.find((m) => m.id === selectedModel);
const initialProvider = currentModelObj?.provider || "all";
const [selectedProvider, setSelectedProvider] = useState(initialProvider);
const modelCategories = [
{
id: "all",
label: "All",
entries: [
...t2vModels.map((model) => ({ model, category: "t2v" })),
...i2vModels.map((model) => ({ model, category: "i2v" })),
...v2vModels.map((model) => ({ model, category: "v2v" })),
],
},
{
id: "t2v",
label: "Text to Video",
entries: t2vModels.map((model) => ({ model, category: "t2v" })),
},
{
id: "i2v",
label: "Image to Video",
entries: i2vModels.map((model) => ({ model, category: "i2v" })),
},
{
id: "v2v",
label: "Video Tools",
entries: v2vModels.map((model) => ({ model, category: "v2v" })),
},
];
const [selectedCategory, setSelectedCategory] = useState("all");
const [selectedProvider, setSelectedProvider] = useState("all");
const activeCategory = modelCategories.find((category) => category.id === selectedCategory) || modelCategories[0];
const modelEntries = activeCategory.entries;
const activeItemRef = useRef(null);
@@ -205,7 +228,7 @@ function ModelDropdown({ imageMode, selectedModel, onSelect, onClose }) {
const availableProviders = [];
const seenProviders = new Set();
allCurrentModels.forEach(m => {
modelEntries.forEach(({ model: m }) => {
const pId = m.provider || 'muapi';
const pName = m.provider_name || 'Muapi';
if (!seenProviders.has(pId)) {
@@ -216,7 +239,7 @@ function ModelDropdown({ imageMode, selectedModel, onSelect, onClose }) {
const lf = search.toLowerCase();
const filterFn = (m) => {
const filterFn = ({ model: m }) => {
// 1. Filter by provider tab
if (selectedProvider !== "all") {
const pId = m.provider || 'muapi';
@@ -229,8 +252,8 @@ function ModelDropdown({ imageMode, selectedModel, onSelect, onClose }) {
);
};
const filteredMain = generationModels.filter(filterFn);
const filteredV2V = v2vModels.filter(filterFn);
const filteredMain = modelEntries.filter(filterFn).filter(({ category }) => category !== "v2v");
const filteredV2V = modelEntries.filter(filterFn).filter(({ category }) => category === "v2v");
const getIconColor = (m, isV2V) => {
if (isV2V) return "bg-orange-500/10 text-orange-400 border-orange-500/10";
@@ -240,14 +263,16 @@ function ModelDropdown({ imageMode, selectedModel, onSelect, onClose }) {
return "bg-primary/10 text-primary border-primary/10";
};
const renderItem = (m, isV2V = false) => (
const renderItem = ({ model: m, category }) => {
const isV2V = category === "v2v";
return (
<div
key={m.id}
key={`${category}:${m.id}`}
ref={selectedModel === m.id ? activeItemRef : null}
className={`flex items-center justify-between p-3.5 hover:bg-white/5 rounded-2xl cursor-pointer transition-all border border-transparent hover:border-white/5 ${selectedModel === m.id ? "bg-white/5 border-white/5" : ""}`}
onClick={(e) => {
e.stopPropagation();
onSelect(m, isV2V);
onSelect(m, category);
onClose();
}}
>
@@ -286,7 +311,8 @@ function ModelDropdown({ imageMode, selectedModel, onSelect, onClose }) {
</div>
{selectedModel === m.id && <CheckSvg />}
</div>
);
);
};
const invertLogos = ['openai', 'blackforest', 'runway', 'ideogram', 'lightricks', 'grok'];
@@ -340,7 +366,26 @@ function ModelDropdown({ imageMode, selectedModel, onSelect, onClose }) {
{/* Right Pane: Search + Lists */}
<div className="flex-1 flex flex-col gap-2 min-w-0">
<div className="px-1 pb-2 border-b border-white/5 shrink-0">
<div className="px-1 pb-2 border-b border-white/5 shrink-0 space-y-2">
<div className="flex gap-1.5 overflow-x-auto custom-scrollbar pb-0.5">
{modelCategories.map((category) => (
<button
key={category.id}
type="button"
onClick={() => {
setSelectedCategory(category.id);
setSelectedProvider("all");
}}
className={`shrink-0 rounded-lg px-2.5 py-1.5 text-[10px] font-bold transition-colors border ${
selectedCategory === category.id
? "bg-primary/15 text-primary border-primary/30"
: "bg-white/[0.02] text-white/50 border-white/[0.04] hover:bg-white/5 hover:text-white"
}`}
>
{category.label}
</button>
))}
</div>
<div className="flex items-center gap-3 bg-white/5 rounded-xl px-4 py-2 border border-white/5 focus-within:border-primary/50 transition-colors">
<svg
width="14"
@@ -366,7 +411,7 @@ function ModelDropdown({ imageMode, selectedModel, onSelect, onClose }) {
</div>
<div className="text-xs font-bold text-secondary px-2 py-1 shrink-0 flex items-center justify-between">
<span>Video models</span>
<span>{activeCategory.label} models</span>
{selectedProvider !== "all" && (
<span className="text-[10px] bg-white/5 px-2 py-0.5 rounded text-white/60">
{availableProviders.find(p => p.id === selectedProvider)?.name || selectedProvider}
@@ -381,13 +426,13 @@ function ModelDropdown({ imageMode, selectedModel, onSelect, onClose }) {
</div>
) : (
<>
{filteredMain.map((m) => renderItem(m, false))}
{filteredMain.map((entry) => renderItem(entry))}
{filteredV2V.length > 0 && (
<>
<div className="text-xs font-bold text-orange-400/70 px-3 py-2 mt-1 border-t border-white/5">
Video Tools
</div>
{filteredV2V.map((m) => renderItem(m, true))}
{filteredV2V.map((entry) => renderItem(entry))}
</>
)}
</>
@@ -1011,7 +1056,8 @@ export default function VideoStudio({
// ── model selection from dropdown ─────────────────────────────────────────
const handleModelSelect = useCallback(
(m, isV2V) => {
(m, category = imageMode ? "i2v" : "t2v") => {
const isV2V = category === "v2v";
if (isV2V) {
setV2vMode(true);
setImageMode(false);
@@ -1037,9 +1083,16 @@ export default function VideoStudio({
setUploadedVideoName(null);
setPromptDisabled(false);
}
const nextImageMode = category === "i2v";
if (!nextImageMode && imageMode) {
setUploadedImageUrl(null);
setUploadedImageUrls([]);
setUploadedEndImageUrl(null);
}
setImageMode(nextImageMode);
setSelectedModel(m.id);
setSelectedModelName(m.name);
applyControlsForModel(m.id, imageMode, false);
applyControlsForModel(m.id, nextImageMode, false);
}
},
[v2vMode, imageMode, applyControlsForModel],
@@ -1881,7 +1934,6 @@ export default function VideoStudio({
>
<PromptPopoverHeader>Model</PromptPopoverHeader>
<ModelDropdown
imageMode={imageMode}
selectedModel={selectedModel}
onSelect={handleModelSelect}
onClose={() => setOpenDropdown(null)}
+579
View File
@@ -217,6 +217,7 @@ export const t2iModels = [
{
"id": "hidream-i1-fast",
"name": "Hidream I1 Fast",
"endpoint": "hidream_i1_fast_image",
"inputs": {
"prompt": {
"examples": [
@@ -264,6 +265,7 @@ export const t2iModels = [
{
"id": "hidream-i1-dev",
"name": "Hidream I1 Dev",
"endpoint": "hidream_i1_dev_image",
"inputs": {
"prompt": {
"examples": [
@@ -311,6 +313,7 @@ export const t2iModels = [
{
"id": "hidream-i1-full",
"name": "Hidream I1 Full",
"endpoint": "hidream_i1_full_image",
"inputs": {
"prompt": {
"examples": [
@@ -668,6 +671,7 @@ export const t2iModels = [
{
"id": "bytedance-seedream-v3",
"name": "Bytedance Seedream v3",
"endpoint": "bytedance-seedream-image",
"inputs": {
"prompt": {
"examples": [
@@ -3235,6 +3239,100 @@ export const t2iModels = [
},
"provider": "bytedance",
"provider_name": "ByteDance"
},
{
"id": "qwen3-text-to-image",
"name": "Qwen 3 Text to Image",
"endpoint": "qwen3-text-to-image",
"inputs": {
"prompt": {
"type": "string",
"title": "Prompt",
"name": "prompt",
"description": "Text prompt describing the image to generate."
},
"resolution": {
"enum": ["1k", "2k"],
"type": "string",
"title": "Resolution",
"name": "resolution",
"default": "1k"
},
"aspect_ratio": {
"enum": ["1:1", "3:2", "2:3", "4:3", "3:4", "16:9", "9:16", "21:9"],
"type": "string",
"title": "Aspect Ratio",
"name": "aspect_ratio",
"default": "16:9"
},
"output_format": {
"enum": ["png", "jpeg"],
"type": "string",
"title": "Output Format",
"name": "output_format",
"default": "png"
},
"prompt_extend": {
"type": "boolean",
"title": "Intelligent Prompt Extend",
"name": "prompt_extend",
"default": true
},
"negative_prompt": {
"type": "string",
"title": "Negative Prompt",
"name": "negative_prompt"
}
},
"provider": "alibaba",
"provider_name": "Alibaba"
},
{
"id": "qwen3-pro-text-to-image",
"name": "Qwen 3 Pro Text to Image",
"endpoint": "qwen3-pro-text-to-image",
"inputs": {
"prompt": {
"type": "string",
"title": "Prompt",
"name": "prompt",
"description": "Text prompt describing the image to generate."
},
"resolution": {
"enum": ["1k", "2k"],
"type": "string",
"title": "Resolution",
"name": "resolution",
"default": "1k"
},
"aspect_ratio": {
"enum": ["1:1", "3:2", "2:3", "4:3", "3:4", "16:9", "9:16", "21:9"],
"type": "string",
"title": "Aspect Ratio",
"name": "aspect_ratio",
"default": "16:9"
},
"output_format": {
"enum": ["png", "jpeg"],
"type": "string",
"title": "Output Format",
"name": "output_format",
"default": "png"
},
"prompt_extend": {
"type": "boolean",
"title": "Intelligent Prompt Extend",
"name": "prompt_extend",
"default": true
},
"negative_prompt": {
"type": "string",
"title": "Negative Prompt",
"name": "negative_prompt"
}
},
"provider": "alibaba",
"provider_name": "Alibaba"
}
];
@@ -5534,6 +5632,7 @@ export const t2vModels = [
"id": "wan2.7-text-to-video",
"name": "Wan2.7",
"endpoint": "wan2.7-text-to-video",
"family": "wan2.7",
"inputs": {
"prompt": {
"type": "string",
@@ -7629,6 +7728,80 @@ export const t2vModels = [
},
"provider": "bytedance",
"provider_name": "ByteDance"
},
{
"id": "minimax-h3-text-to-video",
"name": "MiniMax H3 Text to Video",
"endpoint": "minimax-h3-text-to-video",
"family": "minimax-h3",
"inputs": {
"prompt": {
"type": "string",
"title": "Prompt",
"name": "prompt",
"description": "Text prompt describing the video to generate."
},
"aspect_ratio": {
"enum": ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"],
"type": "string",
"title": "Aspect Ratio",
"name": "aspect_ratio",
"default": "16:9"
},
"resolution": {
"enum": ["2k"],
"type": "string",
"title": "Resolution",
"name": "resolution",
"default": "2k"
},
"duration": {
"enum": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
"type": "integer",
"title": "Duration",
"name": "duration",
"default": 5
}
},
"provider": "minimax",
"provider_name": "Minimax"
},
{
"id": "minimax-h3-open-text-to-video",
"name": "MiniMax H3 Open Text to Video",
"endpoint": "minimax-h3-open-text-to-video",
"family": "minimax-h3",
"inputs": {
"prompt": {
"type": "string",
"title": "Prompt",
"name": "prompt",
"description": "Text prompt describing the video to generate."
},
"aspect_ratio": {
"enum": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "9:21"],
"type": "string",
"title": "Aspect Ratio",
"name": "aspect_ratio",
"default": "16:9"
},
"resolution": {
"enum": ["480p", "768p"],
"type": "string",
"title": "Resolution",
"name": "resolution",
"default": "480p"
},
"duration": {
"enum": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
"type": "integer",
"title": "Duration",
"name": "duration",
"default": 5
}
},
"provider": "minimax",
"provider_name": "Minimax"
}
];
@@ -10826,6 +10999,122 @@ export const i2iModels = [
},
"provider": "bytedance",
"provider_name": "ByteDance"
},
{
"id": "qwen3-image-to-image",
"name": "Qwen 3 Image to Image",
"endpoint": "qwen3-image-to-image",
"family": "qwen3",
"imageField": "images_list",
"maxImages": 3,
"inputs": {
"prompt": {
"type": "string",
"title": "Prompt",
"name": "prompt",
"description": "Text prompt describing the desired image edit."
},
"images_list": {
"type": "array",
"field": "images_list",
"title": "Input Images",
"name": "images_list",
"maxItems": 3,
"items": {"type": "string"}
},
"resolution": {
"enum": ["1k", "2k"],
"type": "string",
"title": "Resolution",
"name": "resolution",
"default": "1k"
},
"aspect_ratio": {
"enum": ["1:1", "3:2", "2:3", "4:3", "3:4", "16:9", "9:16", "21:9"],
"type": "string",
"title": "Aspect Ratio",
"name": "aspect_ratio",
"default": "16:9"
},
"output_format": {
"enum": ["png", "jpeg"],
"type": "string",
"title": "Output Format",
"name": "output_format",
"default": "png"
},
"prompt_extend": {
"type": "boolean",
"title": "Intelligent Prompt Extend",
"name": "prompt_extend",
"default": true
},
"negative_prompt": {
"type": "string",
"title": "Negative Prompt",
"name": "negative_prompt"
}
},
"provider": "alibaba",
"provider_name": "Alibaba"
},
{
"id": "qwen3-pro-image-to-image",
"name": "Qwen 3 Pro Image to Image",
"endpoint": "qwen3-pro-image-to-image",
"family": "qwen3",
"imageField": "images_list",
"maxImages": 3,
"inputs": {
"prompt": {
"type": "string",
"title": "Prompt",
"name": "prompt",
"description": "Text prompt describing the desired image edit."
},
"images_list": {
"type": "array",
"field": "images_list",
"title": "Input Images",
"name": "images_list",
"maxItems": 3,
"items": {"type": "string"}
},
"resolution": {
"enum": ["1k", "2k"],
"type": "string",
"title": "Resolution",
"name": "resolution",
"default": "1k"
},
"aspect_ratio": {
"enum": ["1:1", "3:2", "2:3", "4:3", "3:4", "16:9", "9:16", "21:9"],
"type": "string",
"title": "Aspect Ratio",
"name": "aspect_ratio",
"default": "16:9"
},
"output_format": {
"enum": ["png", "jpeg"],
"type": "string",
"title": "Output Format",
"name": "output_format",
"default": "png"
},
"prompt_extend": {
"type": "boolean",
"title": "Intelligent Prompt Extend",
"name": "prompt_extend",
"default": true
},
"negative_prompt": {
"type": "string",
"title": "Negative Prompt",
"name": "negative_prompt"
}
},
"provider": "alibaba",
"provider_name": "Alibaba"
}
];
@@ -18892,6 +19181,220 @@ export const i2vModels = [
},
"provider": "bytedance",
"provider_name": "ByteDance"
},
{
"id": "minimax-h3-image-to-video",
"name": "MiniMax H3 Image to Video",
"endpoint": "minimax-h3-image-to-video",
"family": "minimax-h3",
"imageField": "image_url",
"lastImageField": "last_image_url",
"hasPrompt": true,
"inputs": {
"prompt": {
"type": "string",
"title": "Prompt",
"name": "prompt",
"description": "Motion prompt describing the desired video."
},
"image_url": {
"type": "string",
"field": "image",
"title": "Image URL",
"name": "image_url"
},
"last_image_url": {
"type": "string",
"field": "image",
"title": "Last Image URL",
"name": "last_image_url"
},
"resolution": {
"enum": ["2k"],
"type": "string",
"title": "Resolution",
"name": "resolution",
"default": "2k"
},
"duration": {
"enum": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
"type": "integer",
"title": "Duration",
"name": "duration",
"default": 5
}
},
"provider": "minimax",
"provider_name": "Minimax"
},
{
"id": "minimax-h3-reference-to-video",
"name": "MiniMax H3 Reference to Video",
"endpoint": "minimax-h3-reference-to-video",
"family": "minimax-h3",
"imageField": "reference_images",
"hasPrompt": true,
"inputs": {
"prompt": {
"type": "string",
"title": "Prompt",
"name": "prompt",
"description": "Prompt describing the desired video."
},
"reference_images": {
"type": "array",
"field": "image",
"title": "Reference Images",
"name": "reference_images",
"items": {"type": "string"}
},
"reference_videos": {
"type": "array",
"field": "video",
"title": "Reference Videos",
"name": "reference_videos",
"items": {"type": "string"}
},
"reference_audios": {
"type": "array",
"field": "audio",
"title": "Reference Audio",
"name": "reference_audios",
"items": {"type": "string"}
},
"aspect_ratio": {
"enum": ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"],
"type": "string",
"title": "Aspect Ratio",
"name": "aspect_ratio",
"default": "16:9"
},
"resolution": {
"enum": ["2k"],
"type": "string",
"title": "Resolution",
"name": "resolution",
"default": "2k"
},
"duration": {
"enum": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
"type": "integer",
"title": "Duration",
"name": "duration",
"default": 5
}
},
"provider": "minimax",
"provider_name": "Minimax"
},
{
"id": "minimax-h3-open-image-to-video",
"name": "MiniMax H3 Open Image to Video",
"endpoint": "minimax-h3-open-image-to-video",
"family": "minimax-h3",
"imageField": "image_url",
"lastImageField": "last_image",
"hasPrompt": true,
"inputs": {
"prompt": {
"type": "string",
"title": "Prompt",
"name": "prompt",
"description": "Motion prompt describing the desired video."
},
"image_url": {
"type": "string",
"field": "image",
"title": "First Frame Image URL",
"name": "image_url"
},
"last_image": {
"type": "string",
"field": "image",
"title": "Last Frame Image URL",
"name": "last_image"
},
"resolution": {
"enum": ["480p", "768p"],
"type": "string",
"title": "Resolution",
"name": "resolution",
"default": "480p"
},
"duration": {
"enum": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
"type": "integer",
"title": "Duration",
"name": "duration",
"default": 5
}
},
"provider": "minimax",
"provider_name": "Minimax"
},
{
"id": "minimax-h3-open-reference-to-video",
"name": "MiniMax H3 Open Reference to Video",
"endpoint": "minimax-h3-open-reference-to-video",
"family": "minimax-h3",
"imageField": "images_list",
"maxImages": 9,
"hasPrompt": true,
"inputs": {
"prompt": {
"type": "string",
"title": "Prompt",
"name": "prompt",
"description": "Prompt describing the desired video."
},
"images_list": {
"type": "array",
"field": "images_list",
"title": "Reference Images",
"name": "images_list",
"maxItems": 9,
"items": {"type": "string"}
},
"videos_list": {
"type": "array",
"field": "videos_list",
"title": "Reference Videos",
"name": "videos_list",
"maxItems": 3,
"items": {"type": "string"}
},
"audios_list": {
"type": "array",
"field": "audios_list",
"title": "Reference Audio",
"name": "audios_list",
"maxItems": 3,
"items": {"type": "string"}
},
"aspect_ratio": {
"enum": ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "9:21"],
"type": "string",
"title": "Aspect Ratio",
"name": "aspect_ratio",
"default": "16:9"
},
"resolution": {
"enum": ["480p", "768p"],
"type": "string",
"title": "Resolution",
"name": "resolution",
"default": "480p"
},
"duration": {
"enum": [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
"type": "integer",
"title": "Duration",
"name": "duration",
"default": 5
}
},
"provider": "minimax",
"provider_name": "Minimax"
}
];
@@ -18902,6 +19405,8 @@ export const getMaxImagesForI2VModel = (modelId) => {
const model = getI2VModelById(modelId);
if (!model) return 1;
if (model.maxImages) return model.maxImages;
const imageInput = model.inputs?.[model.imageField];
if (imageInput?.type === 'array') return imageInput.maxItems || 1;
if (model.lastImageField) return 2;
return 1;
};
@@ -22737,6 +23242,80 @@ export const audioModels = [
"maximum": 2
}
}
},
{
"id": "elevenlabs-tts-turbo-2-5",
"name": "ElevenLabs TTS Turbo 2.5",
"endpoint": "elevenlabs-tts-turbo-2-5",
"family": "audio-generation",
"description": "Convert text to natural-sounding speech with adjustable voice stability, similarity, and speed.",
"required": ["prompt"],
"inputs": {
"prompt": {
"type": "string",
"title": "Prompt",
"name": "prompt",
"description": "Text to convert to speech."
},
"voice_id": {
"type": "string",
"title": "Voice ID",
"name": "voice_id",
"default": "21m00Tcm4TlvDq8ikWAM",
"enum": [
{"label": "James — Husky, Engaging and Bold", "value": "ZQe5CZNOzWyzPSCn5a3c"},
{"label": "Arabella — Mysterious and Emotive", "value": "Z3R5wn05IrDiVCyEkUrK"},
{"label": "Bradford — Expressive and Articulate", "value": "NNl6r8mD7vthiJatiJt1"},
{"label": "Xavier — Dominating, Metallic Announcer", "value": "YOq2y2Up4RgXP2HyXjE5"},
{"label": "Taksh — Calm, Serious and Smooth", "value": "qDuRKMlYmrm8trt5QyBn"},
{"label": "Monika Sogam — Deep and Natural", "value": "iP95p4xoKVk53GoZ742B"},
{"label": "Mark — Casual, Relaxed and Light", "value": "UgBBYS2sOqTuMpoF3BR0"},
{"label": "Adeline — Feminine and Conversational", "value": "5l5f8iK3YPeGga21rQIX"},
{"label": "Sam — Support Agent", "value": "yoZ06aMxZJJ28mfd3POQ"},
{"label": "Spuds Oxley — Wise and Approachable", "value": "NOpBlnGInO9m6vDvFkFC"},
{"label": "Eve — Authentic, Energetic and Happy", "value": "scOwDtmlLZohaFMFCHFe"},
{"label": "Callum — Husky Trickster", "value": "N2lVS1w4EtoT3dr4eOWO"},
{"label": "Laura — Enthusiast, Quirky Attitude", "value": "FGY2WhTYpPnrIDTdsKH5"},
{"label": "Brian — Deep, Resonant and Comforting", "value": "zPhCVfO2NBER7bRLIdbq"},
{"label": "Nathan — Virtual Radio Host", "value": "nPczCjzI2devNBz1zQrb"},
{"label": "Charlie — Natural", "value": "IKne3meq5aSn9XLyUdCD"},
{"label": "George — Warm", "value": "JBFqnCBsd6RMkjVDRZzb"},
{"label": "Sarah — Soft", "value": "EXAVITQu4vr4xnSDxMaL"},
{"label": "Charlotte — Clear", "value": "XB0fDUnXU5powFXDhCwa"},
{"label": "Hope — Bubbly, Gossipy and Girly", "value": "tnSpp4vdxKPjI9w0GnoV"},
{"label": "Finn — Youthful, Eager and Energetic", "value": "DYkrAHD8iwork3YSUBbs"},
{"label": "Tom — Conversations and Books", "value": "56AoDkrOh6qfVPDXZ7Pt"},
{"label": "Lucy — Fresh and Casual", "value": "lcMyyd2HUfFzxdCaC4Ta"},
{"label": "Tiffany — Natural and Welcoming", "value": "6aDn1KB0hjpdcocrUkmq"},
{"label": "Brock — Commanding and Loud Sergeant", "value": "7ftFdxRlmR6Z9V3nTdUh"},
{"label": "Viraj — Rich and Soft", "value": "bajNon13EdhNMndG3z05"}
]
},
"stability": {
"type": "number",
"title": "Stability",
"name": "stability",
"default": 0.5
},
"similarity_boost": {
"type": "number",
"title": "Similarity Boost",
"name": "similarity_boost",
"default": 0.75
},
"speed": {
"type": "number",
"title": "Speed",
"name": "speed",
"default": 1
},
"language_code": {
"enum": ["en", "fr", "de", "ja", "vi", "hu", "no"],
"type": "string",
"title": "Language Code",
"name": "language_code"
}
}
}
];
+10 -6
View File
@@ -125,12 +125,16 @@ export async function generateI2V(apiKey, params) {
const payload = {};
if (params.prompt) payload.prompt = params.prompt;
const imageField = modelInfo?.imageField || 'image_url';
if (params.images_list && params.images_list.length > 0) {
if (imageField === 'images_list') payload.images_list = params.images_list;
else payload[imageField] = params.images_list[0];
} else if (params.image_url) {
if (imageField === 'images_list') payload.images_list = [params.image_url];
else payload[imageField] = params.image_url;
const imageInput = modelInfo?.inputs?.[imageField];
const imageUrls = params.images_list?.length > 0
? params.images_list
: (params.image_url ? [params.image_url] : []);
if (imageUrls.length > 0) {
if (imageInput?.type === 'array' || imageField === 'images_list') {
payload[imageField] = imageUrls;
} else {
payload[imageField] = imageUrls[0];
}
}
const lastImageField = modelInfo?.lastImageField;
if (lastImageField && params.last_image) {