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.
Files changed (34) hide show
  1. package/lib/actions/image_agents.d.ts +3 -0
  2. package/lib/actions/image_agents.js +3 -0
  3. package/lib/actions/images.d.ts +5 -0
  4. package/lib/actions/images.js +2 -0
  5. package/lib/actions/index.d.ts +1 -0
  6. package/lib/actions/index.js +1 -0
  7. package/lib/actions/markdown.d.ts +3 -0
  8. package/lib/actions/markdown.js +61 -0
  9. package/lib/agents/image_replicate_agent.js +8 -33
  10. package/lib/agents/movie_replicate_agent.js +9 -7
  11. package/lib/cli/bin.js +2 -0
  12. package/lib/cli/commands/markdown/builder.d.ts +16 -0
  13. package/lib/cli/commands/markdown/builder.js +5 -0
  14. package/lib/cli/commands/markdown/handler.d.ts +4 -0
  15. package/lib/cli/commands/markdown/handler.js +11 -0
  16. package/lib/cli/commands/markdown/index.d.ts +4 -0
  17. package/lib/cli/commands/markdown/index.js +4 -0
  18. package/lib/methods/mulmo_beat.d.ts +6 -1
  19. package/lib/types/schema.d.ts +13 -0
  20. package/lib/types/schema.js +2 -0
  21. package/lib/types/type.d.ts +1 -1
  22. package/lib/utils/context.d.ts +3 -0
  23. package/lib/utils/context.js +1 -0
  24. package/lib/utils/image_plugins/index.d.ts +7 -11
  25. package/lib/utils/image_plugins/index.js +1 -12
  26. package/lib/utils/image_plugins/markdown.d.ts +1 -0
  27. package/lib/utils/image_plugins/markdown.js +8 -1
  28. package/lib/utils/image_plugins/mermaid.d.ts +1 -0
  29. package/lib/utils/image_plugins/mermaid.js +9 -0
  30. package/lib/utils/image_plugins/text_slide.d.ts +1 -0
  31. package/lib/utils/image_plugins/text_slide.js +12 -1
  32. package/package.json +4 -3
  33. package/scripts/test/test_image_refs.json +10 -0
  34. 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
  }
@@ -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
  };
@@ -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
  },
@@ -6,3 +6,4 @@ export * from "./image_agents.js";
6
6
  export * from "./movie.js";
7
7
  export * from "./pdf.js";
8
8
  export * from "./translate.js";
9
+ export * from "./markdown.js";
@@ -6,3 +6,4 @@ export * from "./image_agents.js";
6
6
  export * from "./movie.js";
7
7
  export * from "./pdf.js";
8
8
  export * from "./translate.js";
9
+ export * from "./markdown.js";
@@ -0,0 +1,3 @@
1
+ import { MulmoStudioContext } from "../types/index.js";
2
+ export declare const markdownFilePath: (context: MulmoStudioContext) => string;
3
+ export declare const markdown: (context: MulmoStudioContext, imageWidth?: string) => Promise<void>;
@@ -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 += `![Beat ${index + 1}](${imagePath})\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
- width: canvasSize.width,
19
- height: canvasSize.height,
19
+ aspect_ratio: getAspectRatio(canvasSize),
20
20
  };
21
- if (model === "bytedance/seedream-4") {
22
- input.size = "custom";
23
- if (input.width < 1024) {
24
- const ratio = 1024 / input.width;
25
- input.width = 1024;
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
- if (canvasSize.width > canvasSize.height) {
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
- else if (canvasSize.width < canvasSize.height) {
61
- return "9:16";
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,5 @@
1
+ import { commonOptions } from "../../common.js";
2
+ export const builder = (yargs) => commonOptions(yargs).option("image_width", {
3
+ describe: "Image width (e.g., 400px, 50%, auto)",
4
+ type: "string",
5
+ });
@@ -0,0 +1,4 @@
1
+ import { CliArgs } from "../../../types/cli_types.js";
2
+ export declare const handler: (argv: CliArgs<{
3
+ image_width?: string;
4
+ }>) => Promise<void>;
@@ -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
+ };
@@ -0,0 +1,4 @@
1
+ export declare const command = "markdown <file>";
2
+ export declare const desc = "Generate markdown files";
3
+ export { builder } from "./builder.js";
4
+ export { handler } from "./handler.js";
@@ -0,0 +1,4 @@
1
+ export const command = "markdown <file>";
2
+ export const desc = "Generate markdown files";
3
+ export { builder } from "./builder.js";
4
+ export { handler } from "./handler.js";
@@ -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): typeof import("../utils/image_plugins/text_slide.js") | typeof import("../utils/image_plugins/markdown.js") | typeof import("../utils/image_plugins/chart.js") | typeof import("../utils/image_plugins/mermaid.js") | typeof import("../utils/image_plugins/html_tailwind.js") | typeof import("../utils/image_plugins/image.js") | typeof import("../utils/image_plugins/movie.js") | typeof import("../utils/image_plugins/beat.js") | typeof import("../utils/image_plugins/voice_over.js") | typeof import("../utils/image_plugins/vision.js");
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
  };
@@ -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;
@@ -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()),
@@ -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";
@@ -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: {};
@@ -34,6 +34,7 @@ const initSessionState = () => {
34
34
  multiLingual: false,
35
35
  caption: false,
36
36
  pdf: false,
37
+ markdown: false,
37
38
  },
38
39
  inBeatSession: {
39
40
  audio: {},
@@ -1,11 +1,7 @@
1
- import * as pluginTextSlide from "./text_slide.js";
2
- import * as pluginMarkdown from "./markdown.js";
3
- import * as pluginChart from "./chart.js";
4
- import * as pluginMermaid from "./mermaid.js";
5
- import * as pluginHtmlTailwind from "./html_tailwind.js";
6
- import * as pluginImage from "./image.js";
7
- import * as pluginMovie from "./movie.js";
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 = Array.isArray(beat.image.markdown) ? beat.image.markdown.join("\n") : beat.image.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 = `# ${slide.title}\n` + (slide.subtitle ? `## ${slide.subtitle}\n` : "") + (slide.bullets ?? []).map((text) => `- ${text}`).join("\n");
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.28",
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.1",
92
+ "mulmocast-vision": "^0.1.4",
92
93
  "ora": "^8.2.0",
93
- "puppeteer": "^24.19.0",
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
+ }