Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mulerouter",
"version": "0.3.2",
"version": "0.4.0",
"description": "CLI for MuleRouter/MuleRun multimodal AI APIs — generate images, videos, speech, and music",
"type": "module",
"license": "MIT",
Expand Down
23 changes: 23 additions & 0 deletions packages/cli/tests/run.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,27 @@ describe("run command internals", () => {
});
});
});

describe("seedance endpoint resolution", () => {
it("should resolve 3-part seedance identifiers", () => {
const t2v = resolveEndpoint("bytedance/seedance-2.0/text-to-video");
expect(t2v.provider).toBe("bytedance");
expect(t2v.action).toBe("text-to-video");
expect(t2v.apiPath).toBe("/vendors/bytedance/v1/seedance-2.0/text-to-video/generation");
expect(t2v.resultKey).toBe("videos");
});

it("should throw for 2-part seedance identifier (ambiguous: 3 actions)", () => {
expect(() => resolveEndpoint("bytedance/seedance-2.0")).toThrow("Multiple actions");
});

it("should distinguish std vs fast variants", () => {
const std = resolveEndpoint("bytedance/seedance-2.0/text-to-video");
const fast = resolveEndpoint("bytedance/seedance-2.0-fast/text-to-video");
expect(std.modelName).toBe("seedance-2.0");
expect(fast.modelName).toBe("seedance-2.0-fast");
expect(std.parameters.find((p) => p.name === "camera_fixed")).toBeDefined();
expect(fast.parameters.find((p) => p.name === "camera_fixed")).toBeUndefined();
});
});
});
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mulerouter/core",
"version": "0.3.2",
"version": "0.4.0",
"description": "Core library for MuleRouter/MuleRun multimodal AI APIs",
"type": "module",
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const IMAGE_PARAM_NAMES = new Set([
"images",
"first_frame",
"last_frame",
"last_frame_image",
"first_frame_url",
"last_frame_url",
"ref_images_url",
Expand Down
159 changes: 159 additions & 0 deletions packages/core/src/models/bytedance/_builders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import type { ModelParameter } from "../../types.js";

/**
* Shared parameter definitions for ByteDance Seedance 2.0 series.
* Source: extracted from mule-router payloads/seedance.py + docs/api/bytedance/.
*
* Two model variants (seedance-2.0 vs seedance-2.0-fast) differ only in:
* - `resolution` enum: std accepts 1080p, fast does not.
* - T2V fast does NOT accept `camera_fixed` / `watermark` non-false values
* (so the fast T2V parameter list omits those two flags entirely).
*
* `model` is auto-injected by mule-router from URL segments and MUST NOT be
* exposed as a CLI parameter.
*/

const RESOLUTIONS_STD = ["480p", "720p", "1080p"] as const;
const RESOLUTIONS_FAST = ["480p", "720p"] as const;
const ASPECT_RATIOS = ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"] as const;

/** Parameters common to all 6 seedance endpoints. */
const commonParameters: ModelParameter[] = [
{
name: "aspect_ratio",
type: "string",
description: "Output video aspect ratio",
default: "adaptive",
enum: [...ASPECT_RATIOS],
},
{
name: "duration",
type: "integer",
description: "Video duration in seconds. Discrete: -1 (model decides) or 4..15",
default: 5,
},
{
name: "generate_audio",
type: "boolean",
description: "Generate audio track alongside video",
default: true,
},
{
name: "seed",
type: "integer",
description: "Random seed for reproducibility (-1 to 4294967295)",
},
];

function resolutionParam(forFast: boolean): ModelParameter {
return {
name: "resolution",
type: "string",
description: "Output video resolution",
default: "720p",
enum: forFast ? [...RESOLUTIONS_FAST] : [...RESOLUTIONS_STD],
};
}

/** Build T2V parameters for std (seedance-2.0) or fast variant. */
export function seedanceT2vParameters(forFast: boolean): ModelParameter[] {
const base: ModelParameter[] = [
{
name: "prompt",
type: "string",
description: "Text prompt describing the video to generate",
required: true,
},
resolutionParam(forFast),
...commonParameters,
{
name: "web_search",
type: "boolean",
description: "Enable web search grounding for the prompt",
default: false,
},
];

if (!forFast) {
// camera_fixed / watermark only accepted on std variant
base.push(
{
name: "camera_fixed",
type: "boolean",
description: "Lock camera position (no panning/zooming)",
default: false,
},
{
name: "watermark",
type: "boolean",
description: "Add watermark to the output video",
default: false,
},
);
}

return base;
}

/** Build I2V parameters for std or fast variant. */
export function seedanceI2vParameters(forFast: boolean): ModelParameter[] {
return [
{
name: "image",
type: "string",
description:
"First frame image. HTTP(S) URL, data: URI, or local file path (auto-converted to base64)",
required: true,
},
{
name: "last_frame_image",
type: "string",
description:
"Optional last frame image. HTTP(S) URL, data: URI, or local file path (auto-converted to base64)",
},
{
name: "prompt",
type: "string",
description: "Optional text prompt for video motion guidance",
},
resolutionParam(forFast),
...commonParameters,
];
}

/** Build R2V parameters for std or fast variant. */
export function seedanceR2vParameters(forFast: boolean): ModelParameter[] {
return [
{
name: "prompt",
type: "string",
description: "Optional text prompt for video generation",
},
{
name: "images",
type: "array",
description:
'Reference images (1-9). JSON array of HTTP(S) URLs / data: URIs / local file paths. At least one of --images / --videos must be provided. Example: --images \'["/tmp/a.png","https://example.com/b.jpg"]\'',
},
{
name: "videos",
type: "array",
description:
"Reference videos (1-3). JSON array of HTTPS URLs ONLY (no http, no base64). At least one of --images / --videos must be provided. Example: --videos '[\"https://example.com/clip.mp4\"]'",
},
{
name: "audios",
type: "array",
description:
"Reference audios (1-3). JSON array of URLs / data: URIs. Cannot be used alone — must be combined with --images or --videos. Example: --audios '[\"https://example.com/voice.mp3\"]'",
},
resolutionParam(forFast),
...commonParameters,
{
name: "web_search",
type: "boolean",
description: "Enable web search grounding for the prompt",
default: false,
},
];
}
6 changes: 6 additions & 0 deletions packages/core/src/models/bytedance/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import "./seedance-2.0-text-to-video.js";
import "./seedance-2.0-image-to-video.js";
import "./seedance-2.0-reference-to-video.js";
import "./seedance-2.0-fast-text-to-video.js";
import "./seedance-2.0-fast-image-to-video.js";
import "./seedance-2.0-fast-reference-to-video.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { registerEndpoint } from "../../registry.js";
import type { ModelEndpoint } from "../../types.js";
import { seedanceI2vParameters } from "./_builders.js";

const endpoint: ModelEndpoint = {
modelId: "bytedance/seedance-2.0-fast",
action: "image-to-video",
provider: "bytedance",
modelName: "seedance-2.0-fast",
description: "ByteDance Seedance 2.0-fast image-to-video: faster variant (max 720p)",
inputTypes: ["text", "image"],
outputType: "video",
apiPath: "/vendors/bytedance/v1/seedance-2.0-fast/image-to-video/generation",
availableOn: ["mulerouter", "mulerun"],
resultKey: "videos",
parameters: seedanceI2vParameters(true),
};

registerEndpoint(endpoint);

export { endpoint };
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { registerEndpoint } from "../../registry.js";
import type { ModelEndpoint } from "../../types.js";
import { seedanceR2vParameters } from "./_builders.js";

const endpoint: ModelEndpoint = {
modelId: "bytedance/seedance-2.0-fast",
action: "reference-to-video",
provider: "bytedance",
modelName: "seedance-2.0-fast",
description:
"ByteDance Seedance 2.0-fast reference-to-video: faster multi-modal references variant (max 720p)",
inputTypes: ["text", "image", "video", "audio"],
outputType: "video",
apiPath: "/vendors/bytedance/v1/seedance-2.0-fast/reference-to-video/generation",
availableOn: ["mulerouter", "mulerun"],
resultKey: "videos",
parameters: seedanceR2vParameters(true),
};

registerEndpoint(endpoint);

export { endpoint };
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { registerEndpoint } from "../../registry.js";
import type { ModelEndpoint } from "../../types.js";
import { seedanceT2vParameters } from "./_builders.js";

const endpoint: ModelEndpoint = {
modelId: "bytedance/seedance-2.0-fast",
action: "text-to-video",
provider: "bytedance",
modelName: "seedance-2.0-fast",
description:
"ByteDance Seedance 2.0-fast text-to-video: faster variant (max 720p, no camera_fixed/watermark)",
inputTypes: ["text"],
outputType: "video",
apiPath: "/vendors/bytedance/v1/seedance-2.0-fast/text-to-video/generation",
availableOn: ["mulerouter", "mulerun"],
resultKey: "videos",
parameters: seedanceT2vParameters(true),
};

registerEndpoint(endpoint);

export { endpoint };
23 changes: 23 additions & 0 deletions packages/core/src/models/bytedance/seedance-2.0-image-to-video.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { registerEndpoint } from "../../registry.js";
import type { ModelEndpoint } from "../../types.js";
import { seedanceI2vParameters } from "./_builders.js";

const endpoint: ModelEndpoint = {
modelId: "bytedance/seedance-2.0",
action: "image-to-video",
provider: "bytedance",
modelName: "seedance-2.0",
description:
"ByteDance Seedance 2.0 image-to-video: animate an image (optional last-frame target), up to 1080p",
inputTypes: ["text", "image"],
outputType: "video",
apiPath: "/vendors/bytedance/v1/seedance-2.0/image-to-video/generation",
availableOn: ["mulerouter", "mulerun"],
resultKey: "videos",
tags: ["SOTA"],
parameters: seedanceI2vParameters(false),
};

registerEndpoint(endpoint);

export { endpoint };
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { registerEndpoint } from "../../registry.js";
import type { ModelEndpoint } from "../../types.js";
import { seedanceR2vParameters } from "./_builders.js";

const endpoint: ModelEndpoint = {
modelId: "bytedance/seedance-2.0",
action: "reference-to-video",
provider: "bytedance",
modelName: "seedance-2.0",
description:
"ByteDance Seedance 2.0 reference-to-video: multi-modal references (images/videos/audios), up to 1080p",
inputTypes: ["text", "image", "video", "audio"],
outputType: "video",
apiPath: "/vendors/bytedance/v1/seedance-2.0/reference-to-video/generation",
availableOn: ["mulerouter", "mulerun"],
resultKey: "videos",
tags: ["SOTA"],
parameters: seedanceR2vParameters(false),
};

registerEndpoint(endpoint);

export { endpoint };
23 changes: 23 additions & 0 deletions packages/core/src/models/bytedance/seedance-2.0-text-to-video.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { registerEndpoint } from "../../registry.js";
import type { ModelEndpoint } from "../../types.js";
import { seedanceT2vParameters } from "./_builders.js";

const endpoint: ModelEndpoint = {
modelId: "bytedance/seedance-2.0",
action: "text-to-video",
provider: "bytedance",
modelName: "seedance-2.0",
description:
"ByteDance Seedance 2.0 text-to-video: generate videos from text prompts (up to 1080p, 4-15s)",
inputTypes: ["text"],
outputType: "video",
apiPath: "/vendors/bytedance/v1/seedance-2.0/text-to-video/generation",
availableOn: ["mulerouter", "mulerun"],
resultKey: "videos",
tags: ["SOTA"],
parameters: seedanceT2vParameters(false),
};

registerEndpoint(endpoint);

export { endpoint };
1 change: 1 addition & 0 deletions packages/core/src/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Import all vendor modules to register their endpoints with the global registry.
import "./alibaba/index.js";
import "./bytedance/index.js";
import "./google/index.js";
import "./klingai/index.js";
import "./midjourney/index.js";
Expand Down
Loading
Loading