mulmocast 1.2.28 → 1.2.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/actions/image_agents.d.ts +3 -0
- package/lib/actions/image_agents.js +3 -0
- package/lib/actions/images.d.ts +5 -0
- package/lib/actions/images.js +2 -0
- package/lib/actions/index.d.ts +1 -0
- package/lib/actions/index.js +1 -0
- package/lib/actions/markdown.d.ts +3 -0
- package/lib/actions/markdown.js +61 -0
- package/lib/agents/image_replicate_agent.js +8 -33
- package/lib/agents/movie_replicate_agent.js +9 -7
- package/lib/cli/bin.js +2 -0
- package/lib/cli/commands/markdown/builder.d.ts +16 -0
- package/lib/cli/commands/markdown/builder.js +5 -0
- package/lib/cli/commands/markdown/handler.d.ts +4 -0
- package/lib/cli/commands/markdown/handler.js +11 -0
- package/lib/cli/commands/markdown/index.d.ts +4 -0
- package/lib/cli/commands/markdown/index.js +4 -0
- package/lib/methods/mulmo_beat.d.ts +6 -1
- package/lib/types/schema.d.ts +13 -0
- package/lib/types/schema.js +2 -0
- package/lib/types/type.d.ts +1 -1
- package/lib/utils/context.d.ts +3 -0
- package/lib/utils/context.js +1 -0
- package/lib/utils/image_plugins/index.d.ts +7 -11
- package/lib/utils/image_plugins/index.js +1 -12
- package/lib/utils/image_plugins/markdown.d.ts +1 -0
- package/lib/utils/image_plugins/markdown.js +8 -1
- package/lib/utils/image_plugins/mermaid.d.ts +1 -0
- package/lib/utils/image_plugins/mermaid.js +9 -0
- package/lib/utils/image_plugins/text_slide.d.ts +1 -0
- package/lib/utils/image_plugins/text_slide.js +12 -1
- package/package.json +4 -3
- package/scripts/test/test_image_refs.json +10 -0
- package/scripts/test/test_markdown.json +60 -0
|
@@ -35,6 +35,7 @@ export declare const imagePreprocessAgent: (namedInputs: {
|
|
|
35
35
|
agent: string;
|
|
36
36
|
movieParams: MulmoMovieParams;
|
|
37
37
|
};
|
|
38
|
+
markdown?: string;
|
|
38
39
|
htmlPrompt?: undefined;
|
|
39
40
|
htmlImageFile?: undefined;
|
|
40
41
|
htmlPath?: undefined;
|
|
@@ -64,6 +65,7 @@ export declare const imagePreprocessAgent: (namedInputs: {
|
|
|
64
65
|
agent: string;
|
|
65
66
|
movieParams: MulmoMovieParams;
|
|
66
67
|
};
|
|
68
|
+
markdown?: string;
|
|
67
69
|
htmlPrompt?: undefined;
|
|
68
70
|
htmlImageFile?: undefined;
|
|
69
71
|
htmlPath?: undefined;
|
|
@@ -96,6 +98,7 @@ export declare const imagePreprocessAgent: (namedInputs: {
|
|
|
96
98
|
agent: string;
|
|
97
99
|
movieParams: MulmoMovieParams;
|
|
98
100
|
};
|
|
101
|
+
markdown?: string;
|
|
99
102
|
htmlPrompt?: undefined;
|
|
100
103
|
htmlImageFile?: undefined;
|
|
101
104
|
htmlPath?: undefined;
|
|
@@ -60,6 +60,9 @@ export const imagePreprocessAgent = async (namedInputs) => {
|
|
|
60
60
|
if (beat.image) {
|
|
61
61
|
const plugin = MulmoBeatMethods.getPlugin(beat);
|
|
62
62
|
const pluginPath = plugin.path({ beat, context, imagePath, ...htmlStyle(context, beat) });
|
|
63
|
+
if (plugin.markdown) {
|
|
64
|
+
returnValue.markdown = plugin.markdown({ beat, context, imagePath, ...htmlStyle(context, beat) });
|
|
65
|
+
}
|
|
63
66
|
// undefined prompt indicates that image generation is not needed
|
|
64
67
|
return { ...returnValue, imagePath: pluginPath, referenceImageForMovie: pluginPath };
|
|
65
68
|
}
|
package/lib/actions/images.d.ts
CHANGED
|
@@ -58,6 +58,7 @@ export declare const beat_graph_data: {
|
|
|
58
58
|
agent: string;
|
|
59
59
|
movieParams: import("../types/type.js").MulmoMovieParams;
|
|
60
60
|
};
|
|
61
|
+
markdown?: string;
|
|
61
62
|
htmlPrompt?: undefined;
|
|
62
63
|
htmlImageFile?: undefined;
|
|
63
64
|
htmlPath?: undefined;
|
|
@@ -87,6 +88,7 @@ export declare const beat_graph_data: {
|
|
|
87
88
|
agent: string;
|
|
88
89
|
movieParams: import("../types/type.js").MulmoMovieParams;
|
|
89
90
|
};
|
|
91
|
+
markdown?: string;
|
|
90
92
|
htmlPrompt?: undefined;
|
|
91
93
|
htmlImageFile?: undefined;
|
|
92
94
|
htmlPath?: undefined;
|
|
@@ -119,6 +121,7 @@ export declare const beat_graph_data: {
|
|
|
119
121
|
agent: string;
|
|
120
122
|
movieParams: import("../types/type.js").MulmoMovieParams;
|
|
121
123
|
};
|
|
124
|
+
markdown?: string;
|
|
122
125
|
htmlPrompt?: undefined;
|
|
123
126
|
htmlImageFile?: undefined;
|
|
124
127
|
htmlPath?: undefined;
|
|
@@ -359,6 +362,7 @@ export declare const beat_graph_data: {
|
|
|
359
362
|
lipSyncFile: string;
|
|
360
363
|
hasMovieAudio: string;
|
|
361
364
|
htmlImageFile: string;
|
|
365
|
+
markdown: string;
|
|
362
366
|
};
|
|
363
367
|
output: {
|
|
364
368
|
imageFile: string;
|
|
@@ -367,6 +371,7 @@ export declare const beat_graph_data: {
|
|
|
367
371
|
lipSyncFile: string;
|
|
368
372
|
hasMovieAudio: string;
|
|
369
373
|
htmlImageFile: string;
|
|
374
|
+
markdown: string;
|
|
370
375
|
};
|
|
371
376
|
isResult: boolean;
|
|
372
377
|
};
|
package/lib/actions/images.js
CHANGED
|
@@ -285,6 +285,7 @@ export const beat_graph_data = {
|
|
|
285
285
|
lipSyncFile: ":preprocessor.lipSyncFile",
|
|
286
286
|
hasMovieAudio: ":audioChecker.hasMovieAudio",
|
|
287
287
|
htmlImageFile: ":preprocessor.htmlImageFile",
|
|
288
|
+
markdown: ":preprocessor.markdown",
|
|
288
289
|
},
|
|
289
290
|
output: {
|
|
290
291
|
imageFile: ".imageFile",
|
|
@@ -293,6 +294,7 @@ export const beat_graph_data = {
|
|
|
293
294
|
lipSyncFile: ".lipSyncFile",
|
|
294
295
|
hasMovieAudio: ".hasMovieAudio",
|
|
295
296
|
htmlImageFile: ".htmlImageFile",
|
|
297
|
+
markdown: ".markdown",
|
|
296
298
|
},
|
|
297
299
|
isResult: true,
|
|
298
300
|
},
|
package/lib/actions/index.d.ts
CHANGED
package/lib/actions/index.js
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { localizedText } from "../utils/utils.js";
|
|
3
|
+
import { writingMessage } from "../utils/file.js";
|
|
4
|
+
import { MulmoStudioContextMethods } from "../methods/mulmo_studio_context.js";
|
|
5
|
+
import path from "path";
|
|
6
|
+
const generateMarkdownContent = (context, imageWidth) => {
|
|
7
|
+
const { studio, multiLingual, lang = "en" } = context;
|
|
8
|
+
const title = studio.script.title || "MulmoCast Content";
|
|
9
|
+
const description = studio.script.description || "";
|
|
10
|
+
let markdown = `# ${title}\n\n`;
|
|
11
|
+
if (description) {
|
|
12
|
+
markdown += `${description}\n\n`;
|
|
13
|
+
}
|
|
14
|
+
studio.script.beats.forEach((beat, index) => {
|
|
15
|
+
const text = localizedText(beat, multiLingual?.[index], lang);
|
|
16
|
+
const studioBeat = studio.beats[index];
|
|
17
|
+
if (text.trim() || studioBeat?.markdown || studioBeat?.imageFile) {
|
|
18
|
+
if (studioBeat?.markdown) {
|
|
19
|
+
markdown += `${studioBeat.markdown}\n\n`;
|
|
20
|
+
}
|
|
21
|
+
else if (studioBeat?.imageFile && studioBeat.markdown !== "") {
|
|
22
|
+
const imagePath = path.relative(context.fileDirs.outDirPath, studioBeat.imageFile);
|
|
23
|
+
if (imageWidth) {
|
|
24
|
+
// Use HTML img tag for width control
|
|
25
|
+
const altText = `Beat ${index + 1}`;
|
|
26
|
+
markdown += `<img src="${imagePath}" alt="${altText}" width="${imageWidth}" />\n\n`;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
// Use standard markdown image syntax
|
|
30
|
+
markdown += `\n\n`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (text.trim()) {
|
|
34
|
+
markdown += `${text}\n\n`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
return markdown;
|
|
39
|
+
};
|
|
40
|
+
export const markdownFilePath = (context) => {
|
|
41
|
+
const { studio, fileDirs, lang = "en" } = context;
|
|
42
|
+
// Add language suffix only when target language is different from script's original language
|
|
43
|
+
const langSuffix = studio.script.lang !== lang ? `_${lang}` : "";
|
|
44
|
+
const filename = `${studio.filename}${langSuffix}.md`;
|
|
45
|
+
return path.join(fileDirs.outDirPath, filename);
|
|
46
|
+
};
|
|
47
|
+
const generateMarkdown = async (context, imageWidth) => {
|
|
48
|
+
const outputMarkdownPath = markdownFilePath(context);
|
|
49
|
+
const markdownContent = generateMarkdownContent(context, imageWidth);
|
|
50
|
+
fs.writeFileSync(outputMarkdownPath, markdownContent, "utf8");
|
|
51
|
+
writingMessage(outputMarkdownPath);
|
|
52
|
+
};
|
|
53
|
+
export const markdown = async (context, imageWidth) => {
|
|
54
|
+
try {
|
|
55
|
+
MulmoStudioContextMethods.setSessionState(context, "markdown", true);
|
|
56
|
+
await generateMarkdown(context, imageWidth);
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
MulmoStudioContextMethods.setSessionState(context, "markdown", false);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
1
2
|
import { GraphAILogger } from "graphai";
|
|
2
3
|
import Replicate from "replicate";
|
|
3
4
|
import { getAspectRatio } from "./movie_replicate_agent.js";
|
|
4
5
|
import { provider2ImageAgent } from "../utils/provider2agent.js";
|
|
5
6
|
export const imageReplicateAgent = async ({ namedInputs, params, config, }) => {
|
|
6
|
-
const { prompt } = namedInputs;
|
|
7
|
+
const { prompt, referenceImages } = namedInputs;
|
|
7
8
|
const { canvasSize } = params;
|
|
8
9
|
const model = params.model ?? provider2ImageAgent.replicate.defaultModel;
|
|
9
10
|
const apiKey = config?.apiKey;
|
|
@@ -15,40 +16,14 @@ export const imageReplicateAgent = async ({ namedInputs, params, config, }) => {
|
|
|
15
16
|
});
|
|
16
17
|
const input = {
|
|
17
18
|
prompt,
|
|
18
|
-
|
|
19
|
-
height: canvasSize.height,
|
|
19
|
+
aspect_ratio: getAspectRatio(canvasSize),
|
|
20
20
|
};
|
|
21
|
-
if (
|
|
22
|
-
input.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
input.height = Math.round(input.height * ratio);
|
|
27
|
-
}
|
|
28
|
-
if (input.height < 1024) {
|
|
29
|
-
const ratio = 1024 / input.height;
|
|
30
|
-
input.width = Math.round(input.width * ratio);
|
|
31
|
-
input.height = 1024;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
else if (model === "qwen/qwen-image") {
|
|
35
|
-
input.aspect_ratio = getAspectRatio(canvasSize);
|
|
36
|
-
}
|
|
37
|
-
// Add image if provided (for image-to-image generation)
|
|
38
|
-
/*
|
|
39
|
-
if (imagePath) {
|
|
40
|
-
const buffer = readFileSync(imagePath);
|
|
41
|
-
const base64Image = `data:image/png;base64,${buffer.toString("base64")}`;
|
|
42
|
-
const start_image = provider2MovieAgent.replicate.modelParams[model]?.start_image;
|
|
43
|
-
if (start_image === "first_frame_image" || start_image === "image" || start_image === "start_image") {
|
|
44
|
-
input[start_image] = base64Image;
|
|
45
|
-
} else if (start_image === undefined) {
|
|
46
|
-
throw new Error(`Model ${model} does not support image-to-video generation`);
|
|
47
|
-
} else {
|
|
48
|
-
input.image = base64Image;
|
|
49
|
-
}
|
|
21
|
+
if (referenceImages && referenceImages.length > 0) {
|
|
22
|
+
input.image_input = referenceImages.map((image) => {
|
|
23
|
+
const buffer = readFileSync(image);
|
|
24
|
+
return `data:image/png;base64,${buffer.toString("base64")}`;
|
|
25
|
+
});
|
|
50
26
|
}
|
|
51
|
-
*/
|
|
52
27
|
try {
|
|
53
28
|
const output = await replicate.run(model, { input });
|
|
54
29
|
// Download the generated video
|
|
@@ -54,15 +54,17 @@ async function generateMovie(model, apiKey, prompt, imagePath, aspectRatio, dura
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
export const getAspectRatio = (canvasSize) => {
|
|
57
|
-
|
|
57
|
+
const ratio = canvasSize.width / canvasSize.height;
|
|
58
|
+
const tolerance = 0.1;
|
|
59
|
+
if (ratio > 4 / 3 + tolerance)
|
|
58
60
|
return "16:9";
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
61
|
+
if (ratio > 4 / 3 - tolerance)
|
|
62
|
+
return "4:3";
|
|
63
|
+
if (ratio > 3 / 4 + tolerance)
|
|
64
64
|
return "1:1";
|
|
65
|
-
|
|
65
|
+
if (ratio > 3 / 4 - tolerance)
|
|
66
|
+
return "3:4";
|
|
67
|
+
return "9:16";
|
|
66
68
|
};
|
|
67
69
|
export const movieReplicateAgent = async ({ namedInputs, params, config, }) => {
|
|
68
70
|
const { prompt, imagePath } = namedInputs;
|
package/lib/cli/bin.js
CHANGED
|
@@ -10,6 +10,7 @@ import * as audioCmd from "./commands/audio/index.js";
|
|
|
10
10
|
import * as imagesCmd from "./commands/image/index.js";
|
|
11
11
|
import * as movieCmd from "./commands/movie/index.js";
|
|
12
12
|
import * as pdfCmd from "./commands/pdf/index.js";
|
|
13
|
+
import * as markdownCmd from "./commands/markdown/index.js";
|
|
13
14
|
import * as toolCmd from "./commands/tool/index.js";
|
|
14
15
|
import { GraphAILogger } from "graphai";
|
|
15
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -32,6 +33,7 @@ export const main = async () => {
|
|
|
32
33
|
.command(imagesCmd)
|
|
33
34
|
.command(movieCmd)
|
|
34
35
|
.command(pdfCmd)
|
|
36
|
+
.command(markdownCmd)
|
|
35
37
|
.command(toolCmd)
|
|
36
38
|
.demandCommand()
|
|
37
39
|
.strict()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Argv } from "yargs";
|
|
2
|
+
export declare const builder: (yargs: Argv) => Argv<{
|
|
3
|
+
o: string | undefined;
|
|
4
|
+
} & {
|
|
5
|
+
b: string | undefined;
|
|
6
|
+
} & {
|
|
7
|
+
l: string | undefined;
|
|
8
|
+
} & {
|
|
9
|
+
f: boolean;
|
|
10
|
+
} & {
|
|
11
|
+
p: string | undefined;
|
|
12
|
+
} & {
|
|
13
|
+
file: string | undefined;
|
|
14
|
+
} & {
|
|
15
|
+
image_width: string | undefined;
|
|
16
|
+
}>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { images, markdown } from "../../../actions/index.js";
|
|
2
|
+
import { initializeContext, runTranslateIfNeeded } from "../../helpers.js";
|
|
3
|
+
export const handler = async (argv) => {
|
|
4
|
+
const context = await initializeContext(argv);
|
|
5
|
+
if (!context) {
|
|
6
|
+
process.exit(1);
|
|
7
|
+
}
|
|
8
|
+
await runTranslateIfNeeded(context);
|
|
9
|
+
await images(context);
|
|
10
|
+
await markdown(context, argv.image_width);
|
|
11
|
+
};
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { MulmoBeat } from "../types/index.js";
|
|
2
2
|
export declare const MulmoBeatMethods: {
|
|
3
3
|
getHtmlPrompt(beat: MulmoBeat): string | undefined;
|
|
4
|
-
getPlugin(beat: MulmoBeat):
|
|
4
|
+
getPlugin(beat: MulmoBeat): {
|
|
5
|
+
imageType: string;
|
|
6
|
+
process: (params: import("../types/type.js").ImageProcessorParams) => Promise<string | undefined> | void;
|
|
7
|
+
path: (params: import("../types/type.js").ImageProcessorParams) => string | undefined;
|
|
8
|
+
markdown?: (params: import("../types/type.js").ImageProcessorParams) => string | undefined;
|
|
9
|
+
};
|
|
5
10
|
getImageReferenceForImageGenerator(beat: MulmoBeat, imageRefs: Record<string, string>): string[];
|
|
6
11
|
};
|
package/lib/types/schema.d.ts
CHANGED
|
@@ -5777,8 +5777,10 @@ export declare const mulmoStudioBeatSchema: z.ZodObject<{
|
|
|
5777
5777
|
lipSyncFile: z.ZodOptional<z.ZodString>;
|
|
5778
5778
|
captionFile: z.ZodOptional<z.ZodString>;
|
|
5779
5779
|
htmlImageFile: z.ZodOptional<z.ZodString>;
|
|
5780
|
+
markdown: z.ZodOptional<z.ZodString>;
|
|
5780
5781
|
}, "strict", z.ZodTypeAny, {
|
|
5781
5782
|
duration?: number | undefined;
|
|
5783
|
+
markdown?: string | undefined;
|
|
5782
5784
|
id?: string | undefined;
|
|
5783
5785
|
startAt?: number | undefined;
|
|
5784
5786
|
hash?: string | undefined;
|
|
@@ -5795,6 +5797,7 @@ export declare const mulmoStudioBeatSchema: z.ZodObject<{
|
|
|
5795
5797
|
htmlImageFile?: string | undefined;
|
|
5796
5798
|
}, {
|
|
5797
5799
|
duration?: number | undefined;
|
|
5800
|
+
markdown?: string | undefined;
|
|
5798
5801
|
id?: string | undefined;
|
|
5799
5802
|
startAt?: number | undefined;
|
|
5800
5803
|
hash?: string | undefined;
|
|
@@ -6027,10 +6030,12 @@ export declare const mulmoSessionStateSchema: z.ZodObject<{
|
|
|
6027
6030
|
multiLingual: z.ZodBoolean;
|
|
6028
6031
|
caption: z.ZodBoolean;
|
|
6029
6032
|
pdf: z.ZodBoolean;
|
|
6033
|
+
markdown: z.ZodBoolean;
|
|
6030
6034
|
}, "strip", z.ZodTypeAny, {
|
|
6031
6035
|
image: boolean;
|
|
6032
6036
|
video: boolean;
|
|
6033
6037
|
audio: boolean;
|
|
6038
|
+
markdown: boolean;
|
|
6034
6039
|
pdf: boolean;
|
|
6035
6040
|
multiLingual: boolean;
|
|
6036
6041
|
caption: boolean;
|
|
@@ -6038,6 +6043,7 @@ export declare const mulmoSessionStateSchema: z.ZodObject<{
|
|
|
6038
6043
|
image: boolean;
|
|
6039
6044
|
video: boolean;
|
|
6040
6045
|
audio: boolean;
|
|
6046
|
+
markdown: boolean;
|
|
6041
6047
|
pdf: boolean;
|
|
6042
6048
|
multiLingual: boolean;
|
|
6043
6049
|
caption: boolean;
|
|
@@ -6078,6 +6084,7 @@ export declare const mulmoSessionStateSchema: z.ZodObject<{
|
|
|
6078
6084
|
image: boolean;
|
|
6079
6085
|
video: boolean;
|
|
6080
6086
|
audio: boolean;
|
|
6087
|
+
markdown: boolean;
|
|
6081
6088
|
pdf: boolean;
|
|
6082
6089
|
multiLingual: boolean;
|
|
6083
6090
|
caption: boolean;
|
|
@@ -6098,6 +6105,7 @@ export declare const mulmoSessionStateSchema: z.ZodObject<{
|
|
|
6098
6105
|
image: boolean;
|
|
6099
6106
|
video: boolean;
|
|
6100
6107
|
audio: boolean;
|
|
6108
|
+
markdown: boolean;
|
|
6101
6109
|
pdf: boolean;
|
|
6102
6110
|
multiLingual: boolean;
|
|
6103
6111
|
caption: boolean;
|
|
@@ -8479,8 +8487,10 @@ export declare const mulmoStudioSchema: z.ZodObject<{
|
|
|
8479
8487
|
lipSyncFile: z.ZodOptional<z.ZodString>;
|
|
8480
8488
|
captionFile: z.ZodOptional<z.ZodString>;
|
|
8481
8489
|
htmlImageFile: z.ZodOptional<z.ZodString>;
|
|
8490
|
+
markdown: z.ZodOptional<z.ZodString>;
|
|
8482
8491
|
}, "strict", z.ZodTypeAny, {
|
|
8483
8492
|
duration?: number | undefined;
|
|
8493
|
+
markdown?: string | undefined;
|
|
8484
8494
|
id?: string | undefined;
|
|
8485
8495
|
startAt?: number | undefined;
|
|
8486
8496
|
hash?: string | undefined;
|
|
@@ -8497,6 +8507,7 @@ export declare const mulmoStudioSchema: z.ZodObject<{
|
|
|
8497
8507
|
htmlImageFile?: string | undefined;
|
|
8498
8508
|
}, {
|
|
8499
8509
|
duration?: number | undefined;
|
|
8510
|
+
markdown?: string | undefined;
|
|
8500
8511
|
id?: string | undefined;
|
|
8501
8512
|
startAt?: number | undefined;
|
|
8502
8513
|
hash?: string | undefined;
|
|
@@ -8515,6 +8526,7 @@ export declare const mulmoStudioSchema: z.ZodObject<{
|
|
|
8515
8526
|
}, "strict", z.ZodTypeAny, {
|
|
8516
8527
|
beats: {
|
|
8517
8528
|
duration?: number | undefined;
|
|
8529
|
+
markdown?: string | undefined;
|
|
8518
8530
|
id?: string | undefined;
|
|
8519
8531
|
startAt?: number | undefined;
|
|
8520
8532
|
hash?: string | undefined;
|
|
@@ -8862,6 +8874,7 @@ export declare const mulmoStudioSchema: z.ZodObject<{
|
|
|
8862
8874
|
}, {
|
|
8863
8875
|
beats: {
|
|
8864
8876
|
duration?: number | undefined;
|
|
8877
|
+
markdown?: string | undefined;
|
|
8865
8878
|
id?: string | undefined;
|
|
8866
8879
|
startAt?: number | undefined;
|
|
8867
8880
|
hash?: string | undefined;
|
package/lib/types/schema.js
CHANGED
|
@@ -404,6 +404,7 @@ export const mulmoStudioBeatSchema = z
|
|
|
404
404
|
lipSyncFile: z.string().optional(), // path to the lip sync file
|
|
405
405
|
captionFile: z.string().optional(), // path to the caption image
|
|
406
406
|
htmlImageFile: z.string().optional(), // path to the html image
|
|
407
|
+
markdown: z.string().optional(), // markdown string (alternative to image)
|
|
407
408
|
})
|
|
408
409
|
.strict();
|
|
409
410
|
export const mulmoStudioMultiLingualDataSchema = z.object({
|
|
@@ -424,6 +425,7 @@ export const mulmoSessionStateSchema = z.object({
|
|
|
424
425
|
multiLingual: z.boolean(),
|
|
425
426
|
caption: z.boolean(),
|
|
426
427
|
pdf: z.boolean(),
|
|
428
|
+
markdown: z.boolean(),
|
|
427
429
|
}),
|
|
428
430
|
inBeatSession: z.object({
|
|
429
431
|
audio: z.record(z.string(), z.boolean()),
|
package/lib/types/type.d.ts
CHANGED
|
@@ -85,7 +85,7 @@ export type Text2HtmlAgentInfo = {
|
|
|
85
85
|
};
|
|
86
86
|
export type BeatMediaType = "movie" | "image";
|
|
87
87
|
export type StoryToScriptGenerateMode = (typeof storyToScriptGenerateMode)[keyof typeof storyToScriptGenerateMode];
|
|
88
|
-
export type SessionType = "audio" | "image" | "video" | "multiLingual" | "caption" | "pdf";
|
|
88
|
+
export type SessionType = "audio" | "image" | "video" | "multiLingual" | "caption" | "pdf" | "markdown";
|
|
89
89
|
export type BeatSessionType = "audio" | "image" | "multiLingual" | "caption" | "movie" | "html" | "imageReference" | "soundEffect" | "lipSync";
|
|
90
90
|
export type SessionProgressEvent = {
|
|
91
91
|
kind: "session";
|
package/lib/utils/context.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { MulmoStudioBeat, MulmoScript, MulmoPresentationStyle, MulmoStudioM
|
|
|
2
2
|
export declare const createStudioData: (_mulmoScript: MulmoScript, fileName: string, videoCaptionLang?: string, presentationStyle?: MulmoPresentationStyle | null) => {
|
|
3
3
|
beats: {
|
|
4
4
|
duration?: number | undefined;
|
|
5
|
+
markdown?: string | undefined;
|
|
5
6
|
id?: string | undefined;
|
|
6
7
|
startAt?: number | undefined;
|
|
7
8
|
hash?: string | undefined;
|
|
@@ -354,6 +355,7 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
|
|
|
354
355
|
studio: {
|
|
355
356
|
beats: {
|
|
356
357
|
duration?: number | undefined;
|
|
358
|
+
markdown?: string | undefined;
|
|
357
359
|
id?: string | undefined;
|
|
358
360
|
startAt?: number | undefined;
|
|
359
361
|
hash?: string | undefined;
|
|
@@ -831,6 +833,7 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
|
|
|
831
833
|
multiLingual: boolean;
|
|
832
834
|
caption: boolean;
|
|
833
835
|
pdf: boolean;
|
|
836
|
+
markdown: boolean;
|
|
834
837
|
};
|
|
835
838
|
inBeatSession: {
|
|
836
839
|
audio: {};
|
package/lib/utils/context.js
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import * as pluginBeat from "./beat.js";
|
|
9
|
-
import * as pluginVoiceOver from "./voice_over.js";
|
|
10
|
-
import * as pluginVision from "./vision.js";
|
|
11
|
-
export declare const findImagePlugin: (imageType?: string) => typeof pluginTextSlide | typeof pluginMarkdown | typeof pluginChart | typeof pluginMermaid | typeof pluginHtmlTailwind | typeof pluginImage | typeof pluginMovie | typeof pluginBeat | typeof pluginVoiceOver | typeof pluginVision | undefined;
|
|
1
|
+
import { ImageProcessorParams } from "../../types/index.js";
|
|
2
|
+
export declare const findImagePlugin: (imageType?: string) => {
|
|
3
|
+
imageType: string;
|
|
4
|
+
process: (params: ImageProcessorParams) => Promise<string | undefined> | void;
|
|
5
|
+
path: (params: ImageProcessorParams) => string | undefined;
|
|
6
|
+
markdown?: (params: ImageProcessorParams) => string | undefined;
|
|
7
|
+
} | undefined;
|
|
@@ -8,18 +8,7 @@ import * as pluginMovie from "./movie.js";
|
|
|
8
8
|
import * as pluginBeat from "./beat.js";
|
|
9
9
|
import * as pluginVoiceOver from "./voice_over.js";
|
|
10
10
|
import * as pluginVision from "./vision.js";
|
|
11
|
-
const imagePlugins = [
|
|
12
|
-
pluginTextSlide,
|
|
13
|
-
pluginMarkdown,
|
|
14
|
-
pluginImage,
|
|
15
|
-
pluginChart,
|
|
16
|
-
pluginMermaid,
|
|
17
|
-
pluginMovie,
|
|
18
|
-
pluginHtmlTailwind,
|
|
19
|
-
pluginBeat,
|
|
20
|
-
pluginVoiceOver,
|
|
21
|
-
pluginVision,
|
|
22
|
-
];
|
|
11
|
+
const imagePlugins = [pluginTextSlide, pluginMarkdown, pluginImage, pluginChart, pluginMermaid, pluginMovie, pluginHtmlTailwind, pluginBeat, pluginVoiceOver, pluginVision];
|
|
23
12
|
export const findImagePlugin = (imageType) => {
|
|
24
13
|
return imagePlugins.find((plugin) => plugin.imageType === imageType);
|
|
25
14
|
};
|
|
@@ -2,3 +2,4 @@ import { ImageProcessorParams } from "../../types/index.js";
|
|
|
2
2
|
export declare const imageType = "markdown";
|
|
3
3
|
export declare const process: (params: ImageProcessorParams) => Promise<string | undefined>;
|
|
4
4
|
export declare const path: (params: ImageProcessorParams) => string;
|
|
5
|
+
export declare const markdown: (params: ImageProcessorParams) => string | undefined;
|
|
@@ -5,9 +5,16 @@ const processMarkdown = async (params) => {
|
|
|
5
5
|
const { beat, imagePath, textSlideStyle, canvasSize } = params;
|
|
6
6
|
if (!beat.image || beat.image.type !== imageType)
|
|
7
7
|
return;
|
|
8
|
-
const markdown =
|
|
8
|
+
const markdown = dumpMarkdown(params) ?? "";
|
|
9
9
|
await renderMarkdownToImage(markdown, textSlideStyle, imagePath, canvasSize.width, canvasSize.height);
|
|
10
10
|
return imagePath;
|
|
11
11
|
};
|
|
12
|
+
const dumpMarkdown = (params) => {
|
|
13
|
+
const { beat } = params;
|
|
14
|
+
if (!beat.image || beat.image.type !== imageType)
|
|
15
|
+
return;
|
|
16
|
+
return Array.isArray(beat.image.markdown) ? beat.image.markdown.join("\n") : beat.image.markdown;
|
|
17
|
+
};
|
|
12
18
|
export const process = processMarkdown;
|
|
13
19
|
export const path = parrotingImagePath;
|
|
20
|
+
export const markdown = dumpMarkdown;
|
|
@@ -2,3 +2,4 @@ import { ImageProcessorParams } from "../../types/index.js";
|
|
|
2
2
|
export declare const imageType = "mermaid";
|
|
3
3
|
export declare const process: (params: ImageProcessorParams) => Promise<string | undefined>;
|
|
4
4
|
export declare const path: (params: ImageProcessorParams) => string;
|
|
5
|
+
export declare const markdown: (params: ImageProcessorParams) => string | undefined;
|
|
@@ -19,5 +19,14 @@ const processMermaid = async (params) => {
|
|
|
19
19
|
}
|
|
20
20
|
return imagePath;
|
|
21
21
|
};
|
|
22
|
+
const dumpMarkdown = (params) => {
|
|
23
|
+
const { beat } = params;
|
|
24
|
+
if (!beat.image || beat.image.type !== imageType)
|
|
25
|
+
return;
|
|
26
|
+
if (beat.image.code.kind !== "text")
|
|
27
|
+
return; // support only text for now
|
|
28
|
+
return `\`\`\`mermaid\n${beat.image.code.text}\n\`\`\``;
|
|
29
|
+
};
|
|
22
30
|
export const process = processMermaid;
|
|
23
31
|
export const path = parrotingImagePath;
|
|
32
|
+
export const markdown = dumpMarkdown;
|
|
@@ -2,3 +2,4 @@ import { ImageProcessorParams } from "../../types/index.js";
|
|
|
2
2
|
export declare const imageType = "textSlide";
|
|
3
3
|
export declare const process: (params: ImageProcessorParams) => Promise<string | undefined>;
|
|
4
4
|
export declare const path: (params: ImageProcessorParams) => string;
|
|
5
|
+
export declare const markdown: (params: ImageProcessorParams) => string | undefined;
|
|
@@ -6,7 +6,7 @@ const processTextSlide = async (params) => {
|
|
|
6
6
|
if (!beat.image || beat.image.type !== imageType)
|
|
7
7
|
return;
|
|
8
8
|
const slide = beat.image.slide;
|
|
9
|
-
const markdown =
|
|
9
|
+
const markdown = dumpMarkdown(params) ?? "";
|
|
10
10
|
const topMargin = (() => {
|
|
11
11
|
if (slide.bullets?.length && slide.bullets.length > 0) {
|
|
12
12
|
return "";
|
|
@@ -17,5 +17,16 @@ const processTextSlide = async (params) => {
|
|
|
17
17
|
await renderMarkdownToImage(markdown, textSlideStyle + topMargin, imagePath, canvasSize.width, canvasSize.height);
|
|
18
18
|
return imagePath;
|
|
19
19
|
};
|
|
20
|
+
const dumpMarkdown = (params) => {
|
|
21
|
+
const { beat } = params;
|
|
22
|
+
if (!beat.image || beat.image.type !== imageType)
|
|
23
|
+
return;
|
|
24
|
+
const slide = beat.image.slide;
|
|
25
|
+
const titleString = slide.title ? `# ${slide.title}\n` : "";
|
|
26
|
+
const subtitleString = slide.subtitle ? `## ${slide.subtitle}\n` : "";
|
|
27
|
+
const bulletsString = (slide.bullets ?? []).map((text) => `- ${text}`).join("\n");
|
|
28
|
+
return `${titleString}${subtitleString}${bulletsString}`;
|
|
29
|
+
};
|
|
20
30
|
export const process = processTextSlide;
|
|
21
31
|
export const path = parrotingImagePath;
|
|
32
|
+
export const markdown = dumpMarkdown;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mulmocast",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.29",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.node.js",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"scripting": "npx tsx ./src/cli/bin.ts tool scripting",
|
|
50
50
|
"prompt": "npx tsx ./src/cli/bin.ts tool prompt",
|
|
51
51
|
"schema": "npx tsx ./src/cli/bin.ts tool schema",
|
|
52
|
+
"markdown": "npx tsx ./src/cli/bin.ts markdown",
|
|
52
53
|
"story_to_script": "npx tsx ./src/cli/bin.ts tool story_to_script",
|
|
53
54
|
"whisper": "npx tsx ./src/cli/bin.ts tool whisper",
|
|
54
55
|
"latest": "yarn upgrade-interactive --latest",
|
|
@@ -88,9 +89,9 @@
|
|
|
88
89
|
"graphai": "^2.0.14",
|
|
89
90
|
"jsdom": "^26.1.0",
|
|
90
91
|
"marked": "^16.2.1",
|
|
91
|
-
"mulmocast-vision": "^0.1.
|
|
92
|
+
"mulmocast-vision": "^0.1.4",
|
|
92
93
|
"ora": "^8.2.0",
|
|
93
|
-
"puppeteer": "^24.
|
|
94
|
+
"puppeteer": "^24.20.0",
|
|
94
95
|
"replicate": "^1.1.0",
|
|
95
96
|
"yaml": "^2.8.1",
|
|
96
97
|
"yargs": "^18.0.0",
|
|
@@ -55,6 +55,16 @@
|
|
|
55
55
|
"provider": "google",
|
|
56
56
|
"model": "gemini-2.5-flash-image-preview"
|
|
57
57
|
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": "seedream-4",
|
|
61
|
+
"text": "Hello World with a witch and a broom with Seadream-4",
|
|
62
|
+
"imagePrompt": "Saying hello to the world",
|
|
63
|
+
"imageNames": ["witch", "broom"],
|
|
64
|
+
"imageParams": {
|
|
65
|
+
"provider": "replicate",
|
|
66
|
+
"model": "bytedance/seedream-4"
|
|
67
|
+
}
|
|
58
68
|
}
|
|
59
69
|
]
|
|
60
70
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$mulmocast": {
|
|
3
|
+
"version": "1.1"
|
|
4
|
+
},
|
|
5
|
+
"lang": "en",
|
|
6
|
+
"title": "Test Markdown",
|
|
7
|
+
"description": "This is a test markdown file.",
|
|
8
|
+
"beats": [
|
|
9
|
+
{
|
|
10
|
+
"text": "Hello World",
|
|
11
|
+
"image": {
|
|
12
|
+
"type": "markdown",
|
|
13
|
+
"markdown": []
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"text": "Hello World",
|
|
18
|
+
"image": {
|
|
19
|
+
"type": "markdown",
|
|
20
|
+
"markdown": ["## Chapter 1"]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"image": {
|
|
25
|
+
"type": "markdown",
|
|
26
|
+
"markdown": ["## Chapter 2", "- Hello", "- World"]
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"image": {
|
|
31
|
+
"type": "textSlide",
|
|
32
|
+
"slide": {
|
|
33
|
+
"title": "Chapter 3",
|
|
34
|
+
"subtitle": "Subtitle",
|
|
35
|
+
"bullets": ["Hello", "World"]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"image": {
|
|
41
|
+
"type": "textSlide",
|
|
42
|
+
"slide": {
|
|
43
|
+
"title": "",
|
|
44
|
+
"subtitle": "Chapter 4",
|
|
45
|
+
"bullets": ["Hello", "World"]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"image": {
|
|
51
|
+
"type": "mermaid",
|
|
52
|
+
"title": "Business Process Flow",
|
|
53
|
+
"code": {
|
|
54
|
+
"kind": "text",
|
|
55
|
+
"text": "graph LR\n A[Market Research] --> B[Product Planning]\n B --> C[Development]\n C --> D[Testing]\n D --> E[Manufacturing]\n E --> F[Marketing]\n F --> G[Sales]\n G --> H[Customer Support]\n H --> A"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|