mirror of
https://github.com/Anil-matcha/Open-Generative-AI.git
synced 2026-05-07 01:17:18 +00:00
feat: add MiniMax image-01 T2I model and document MiniMax provider support
- Add minimax-image-01 to t2iModels in src/lib/models.js and packages/studio/src/models.js (8 aspect ratios, up to 4 images per request, 1500-char prompt) - Add minimax-image-01 entry to models_dump.json (t2i section) - Update README: list MiniMax Image 01 in newly-added image models and call out existing MiniMax Hailuo 02/2.3 video model support - Add scripts/test_minimax_provider.js: validates model registration and optionally runs a live API smoke test (MUAPI_KEY env var) MiniMax Hailuo 02/2.3 T2V and I2V models were already present; this commit brings MiniMax image generation to feature parity.
This commit is contained in:
parent
6011fcb0fd
commit
bf32a393cc
5 changed files with 311 additions and 0 deletions
|
|
@ -193,6 +193,7 @@ The Image Studio automatically switches between two model sets:
|
|||
| **Nano Banana 2 Edit** | Image-to-Image | Up to **14 reference images** · Resolution 1K/2K/4K · Google Search enhancement |
|
||||
| **Seedream 5.0** | Text-to-Image | ByteDance · Quality basic/high · 8 aspect ratios · up to 4K |
|
||||
| **Seedream 5.0 Edit** | Image-to-Image | ByteDance · Natural language style transfer · Quality basic/high |
|
||||
| **MiniMax Image 01** | Text-to-Image | MiniMax · 8 aspect ratios · up to 4 images per request · 1500 char prompt |
|
||||
|
||||
#### Multi-Image Input
|
||||
|
||||
|
|
@ -239,6 +240,7 @@ The Video Studio follows the same pattern:
|
|||
| **Seedance 2.0 Extend** | Video Extension | ByteDance · Seamlessly continue any Seedance 2.0 generation · Preserves style, motion & audio · Optional continuation prompt · Duration 5 / 10 / 15s · Quality basic/high |
|
||||
| **Grok Imagine T2V** | Text-to-Video | xAI · Duration 6 / 10 / **15s** · Modes: fun / normal / spicy · Aspect ratios 9:16 / 16:9 / 2:3 / 3:2 / 1:1 |
|
||||
| **Grok Imagine I2V** | Image-to-Video | xAI · Duration 6 / 10 / **15s** · Modes: fun / normal / spicy · Cinematic motion from still images |
|
||||
| **MiniMax Hailuo 02 / 2.3 Standard & Pro** | Text-to-Video / Image-to-Video | MiniMax · Full HD video · Multiple aspect ratios · Fast variant included |
|
||||
|
||||
### 🎙️ Lip Sync Studio
|
||||
|
||||
|
|
|
|||
|
|
@ -2001,6 +2001,48 @@
|
|||
"step": 0.01
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "minimax-image-01",
|
||||
"name": "MiniMax Image 01",
|
||||
"inputs": {
|
||||
"prompt": {
|
||||
"type": "string",
|
||||
"title": "Prompt",
|
||||
"name": "prompt",
|
||||
"description": "Text prompt describing the image to generate (max 1500 characters).",
|
||||
"examples": [
|
||||
"A serene mountain lake at sunset with golden reflections on the water, surrounded by pine forests and snow-capped peaks, photorealistic, 8k."
|
||||
]
|
||||
},
|
||||
"aspect_ratio": {
|
||||
"type": "string",
|
||||
"title": "Aspect Ratio",
|
||||
"name": "aspect_ratio",
|
||||
"description": "Aspect ratio of the output image.",
|
||||
"enum": [
|
||||
"16:9",
|
||||
"9:16",
|
||||
"1:1",
|
||||
"4:3",
|
||||
"3:4",
|
||||
"3:2",
|
||||
"2:3",
|
||||
"21:9"
|
||||
],
|
||||
"default": "1:1"
|
||||
},
|
||||
"num_images": {
|
||||
"type": "int",
|
||||
"title": "Number of images",
|
||||
"name": "num_images",
|
||||
"description": "Number of images to generate in a single request.",
|
||||
"default": 1,
|
||||
"minValue": 1,
|
||||
"maxValue": 4,
|
||||
"step": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -2089,6 +2089,50 @@ export const t2iModels = [
|
|||
"default": "basic"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "minimax-image-01",
|
||||
"name": "MiniMax Image 01",
|
||||
"endpoint": "minimax-image-01",
|
||||
"family": "minimax",
|
||||
"inputs": {
|
||||
"prompt": {
|
||||
"type": "string",
|
||||
"title": "Prompt",
|
||||
"name": "prompt",
|
||||
"description": "Text prompt describing the image to generate (max 1500 characters).",
|
||||
"examples": [
|
||||
"A serene mountain lake at sunset with golden reflections on the water, surrounded by pine forests and snow-capped peaks, photorealistic, 8k."
|
||||
]
|
||||
},
|
||||
"aspect_ratio": {
|
||||
"type": "string",
|
||||
"title": "Aspect Ratio",
|
||||
"name": "aspect_ratio",
|
||||
"description": "Aspect ratio of the output image.",
|
||||
"enum": [
|
||||
"16:9",
|
||||
"9:16",
|
||||
"1:1",
|
||||
"4:3",
|
||||
"3:4",
|
||||
"3:2",
|
||||
"2:3",
|
||||
"21:9"
|
||||
],
|
||||
"default": "1:1"
|
||||
},
|
||||
"num_images": {
|
||||
"type": "int",
|
||||
"title": "Number of images",
|
||||
"name": "num_images",
|
||||
"description": "Number of images to generate in a single request.",
|
||||
"default": 1,
|
||||
"minValue": 1,
|
||||
"maxValue": 4,
|
||||
"step": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
|||
179
scripts/test_minimax_provider.js
Normal file
179
scripts/test_minimax_provider.js
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/**
|
||||
* Test script for MiniMax provider integration.
|
||||
*
|
||||
* Verifies that the MiniMax Image 01 model is correctly registered in models.js
|
||||
* and that the model definition has the expected structure.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/test_minimax_provider.js
|
||||
*
|
||||
* Set MUAPI_KEY env var to run the live API smoke test:
|
||||
* MUAPI_KEY=your_key node scripts/test_minimax_provider.js
|
||||
*/
|
||||
|
||||
import { readFileSync } from "fs";
|
||||
import { fileURLToPath } from "url";
|
||||
import { dirname, join } from "path";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = join(__dirname, "..");
|
||||
|
||||
// ── 1. Model registration check ──────────────────────────────────────────────
|
||||
|
||||
const modelsContent = readFileSync(
|
||||
join(ROOT, "src", "lib", "models.js"),
|
||||
"utf-8"
|
||||
);
|
||||
|
||||
// Extract the t2iModels JSON array via a simple regex
|
||||
const t2iMatch = modelsContent.match(/export const t2iModels = (\[[\s\S]*?\]);/);
|
||||
if (!t2iMatch) {
|
||||
console.error("FAIL: Could not parse t2iModels from src/lib/models.js");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let t2iModels;
|
||||
try {
|
||||
t2iModels = JSON.parse(t2iMatch[1]);
|
||||
} catch (err) {
|
||||
console.error("FAIL: t2iModels is not valid JSON:", err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const minimaxModel = t2iModels.find((m) => m.id === "minimax-image-01");
|
||||
|
||||
if (!minimaxModel) {
|
||||
console.error(
|
||||
'FAIL: "minimax-image-01" not found in t2iModels.\n' +
|
||||
"Expected it to be registered in src/lib/models.js."
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Validate required fields
|
||||
const required = ["id", "name", "endpoint", "family", "inputs"];
|
||||
for (const field of required) {
|
||||
if (!minimaxModel[field]) {
|
||||
console.error(`FAIL: minimax-image-01 is missing required field: ${field}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (minimaxModel.family !== "minimax") {
|
||||
console.error(
|
||||
`FAIL: expected family "minimax", got "${minimaxModel.family}"`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!minimaxModel.inputs.prompt) {
|
||||
console.error("FAIL: minimax-image-01 inputs missing 'prompt' field");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!minimaxModel.inputs.aspect_ratio?.enum?.includes("1:1")) {
|
||||
console.error(
|
||||
"FAIL: minimax-image-01 aspect_ratio enum does not include '1:1'"
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("PASS: minimax-image-01 is correctly registered in t2iModels");
|
||||
console.log(
|
||||
` endpoint=${minimaxModel.endpoint} family=${minimaxModel.family}`
|
||||
);
|
||||
console.log(
|
||||
` aspect ratios: ${minimaxModel.inputs.aspect_ratio.enum.join(", ")}`
|
||||
);
|
||||
|
||||
// ── 2. models_dump.json check ─────────────────────────────────────────────────
|
||||
|
||||
const dump = JSON.parse(
|
||||
readFileSync(join(ROOT, "models_dump.json"), "utf-8")
|
||||
);
|
||||
const dumpEntry = dump.t2i?.find((m) => m.id === "minimax-image-01");
|
||||
if (!dumpEntry) {
|
||||
console.error(
|
||||
'FAIL: "minimax-image-01" not found in models_dump.json t2i section'
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log("PASS: minimax-image-01 found in models_dump.json");
|
||||
|
||||
// ── 3. Live API smoke test (optional) ────────────────────────────────────────
|
||||
|
||||
const apiKey = process.env.MUAPI_KEY;
|
||||
if (!apiKey) {
|
||||
console.log(
|
||||
"\nINFO: Skipping live API test (set MUAPI_KEY env var to enable)."
|
||||
);
|
||||
console.log("\nAll checks passed.");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log("\nRunning live API smoke test against muapi.ai …");
|
||||
|
||||
const MUAPI_BASE = "https://api.muapi.ai";
|
||||
|
||||
async function testMiniMaxImageGeneration() {
|
||||
const endpoint = minimaxModel.endpoint;
|
||||
const url = `${MUAPI_BASE}/api/v1/${endpoint}`;
|
||||
|
||||
const payload = {
|
||||
prompt: "A simple test: a red apple on a white background.",
|
||||
aspect_ratio: "1:1",
|
||||
num_images: 1,
|
||||
};
|
||||
|
||||
console.log(`POST ${url}`);
|
||||
const res = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json", "x-api-key": apiKey },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
console.error(`FAIL: API returned ${res.status}: ${text.slice(0, 200)}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
const requestId = data.request_id || data.id;
|
||||
if (!requestId) {
|
||||
console.error("FAIL: No request_id in response:", JSON.stringify(data));
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`PASS: Generation queued — request_id=${requestId}`);
|
||||
|
||||
// Poll for result (max 60 s)
|
||||
const pollUrl = `${MUAPI_BASE}/api/v1/predictions/${requestId}/result`;
|
||||
for (let i = 0; i < 30; i++) {
|
||||
await new Promise((r) => setTimeout(r, 2000));
|
||||
const poll = await fetch(pollUrl, {
|
||||
headers: { "Content-Type": "application/json", "x-api-key": apiKey },
|
||||
});
|
||||
if (!poll.ok) continue;
|
||||
const result = await poll.json();
|
||||
const status = result.status?.toLowerCase();
|
||||
if (status === "completed" || status === "succeeded" || status === "success") {
|
||||
const imageUrl =
|
||||
result.outputs?.[0] || result.url || result.output?.url;
|
||||
console.log(`PASS: Generation complete — image URL: ${imageUrl}`);
|
||||
console.log("\nAll checks passed.");
|
||||
return;
|
||||
}
|
||||
if (status === "failed" || status === "error") {
|
||||
console.error("FAIL: Generation failed:", result.error);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(` Polling … status=${status}`);
|
||||
}
|
||||
console.error("FAIL: Timed out waiting for generation result.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
testMiniMaxImageGeneration().catch((err) => {
|
||||
console.error("FAIL: Unexpected error:", err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
@ -2089,6 +2089,50 @@ export const t2iModels = [
|
|||
"default": "basic"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "minimax-image-01",
|
||||
"name": "MiniMax Image 01",
|
||||
"endpoint": "minimax-image-01",
|
||||
"family": "minimax",
|
||||
"inputs": {
|
||||
"prompt": {
|
||||
"type": "string",
|
||||
"title": "Prompt",
|
||||
"name": "prompt",
|
||||
"description": "Text prompt describing the image to generate (max 1500 characters).",
|
||||
"examples": [
|
||||
"A serene mountain lake at sunset with golden reflections on the water, surrounded by pine forests and snow-capped peaks, photorealistic, 8k."
|
||||
]
|
||||
},
|
||||
"aspect_ratio": {
|
||||
"type": "string",
|
||||
"title": "Aspect Ratio",
|
||||
"name": "aspect_ratio",
|
||||
"description": "Aspect ratio of the output image.",
|
||||
"enum": [
|
||||
"16:9",
|
||||
"9:16",
|
||||
"1:1",
|
||||
"4:3",
|
||||
"3:4",
|
||||
"3:2",
|
||||
"2:3",
|
||||
"21:9"
|
||||
],
|
||||
"default": "1:1"
|
||||
},
|
||||
"num_images": {
|
||||
"type": "int",
|
||||
"title": "Number of images",
|
||||
"name": "num_images",
|
||||
"description": "Number of images to generate in a single request.",
|
||||
"default": 1,
|
||||
"minValue": 1,
|
||||
"maxValue": 4,
|
||||
"step": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue