mulmocast 0.0.8 → 0.0.9

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 (36) hide show
  1. package/assets/templates/akira_comic.json +28 -0
  2. package/assets/templates/children_book.json +13 -0
  3. package/assets/templates/comic_strips.json +14 -1
  4. package/assets/templates/drslump_comic.json +28 -0
  5. package/assets/templates/ghibli_comic.json +28 -0
  6. package/assets/templates/ghost_comic.json +35 -0
  7. package/assets/templates/onepiece_comic.json +28 -0
  8. package/assets/templates/sensei_and_taro.json +21 -0
  9. package/lib/actions/audio.js +2 -2
  10. package/lib/actions/captions.js +2 -2
  11. package/lib/actions/images.js +48 -6
  12. package/lib/actions/movie.d.ts +1 -1
  13. package/lib/actions/movie.js +13 -11
  14. package/lib/actions/pdf.js +6 -4
  15. package/lib/actions/translate.js +2 -2
  16. package/lib/agents/image_openai_agent.d.ts +1 -0
  17. package/lib/agents/image_openai_agent.js +15 -3
  18. package/lib/cli/bin.js +7 -0
  19. package/lib/cli/helpers.js +2 -1
  20. package/lib/tools/create_mulmo_script_from_url.js +2 -2
  21. package/lib/tools/create_mulmo_script_interactively.js +2 -2
  22. package/lib/tools/story_to_script.js +2 -2
  23. package/lib/types/schema.d.ts +1738 -228
  24. package/lib/types/schema.js +8 -2
  25. package/lib/utils/file.js +20 -9
  26. package/lib/utils/pdf.d.ts +1 -0
  27. package/lib/utils/pdf.js +5 -3
  28. package/lib/utils/preprocess.d.ts +50 -16
  29. package/package.json +9 -9
  30. package/scripts/templates/children_book.json +0 -7
  31. package/scripts/templates/image_prompts_template.json +41 -0
  32. package/scripts/templates/sensei_and_taro.json +0 -11
  33. package/scripts/templates/text_only_template.json +35 -0
  34. package/assets/templates/ghibli_strips.json +0 -6
  35. package/scripts/templates/comic_strips.json +0 -30
  36. package/scripts/templates/ghibli_strips.json +0 -30
@@ -109,7 +109,9 @@ export const mulmoImageAssetSchema = z.union([
109
109
  mulmoPdfMediaSchema,
110
110
  mulmoImageMediaSchema,
111
111
  mulmoSvgMediaSchema,
112
- mulmoMovieMediaSchema,
112
+ mulmoMovieMediaSchema.extend({
113
+ mixAudio: z.number().default(1.0),
114
+ }),
113
115
  mulmoTextSlideMediaSchema,
114
116
  mulmoChartMediaSchema,
115
117
  mulmoMermaidMediaSchema,
@@ -128,12 +130,14 @@ const mulmoMidiMediaSchema = z
128
130
  })
129
131
  .strict();
130
132
  export const mulmoAudioAssetSchema = z.union([mulmoAudioMediaSchema, mulmoMidiMediaSchema]);
133
+ const imageIdSchema = z.string();
131
134
  export const mulmoImageParamsSchema = z
132
135
  .object({
133
136
  model: z.string().optional(), // default: provider specific
134
137
  size: z.string().optional(), // default: provider specific
135
138
  style: z.string().optional(), // optional image style
136
139
  moderation: z.string().optional(), // optional image style
140
+ images: z.record(imageIdSchema, mulmoImageMediaSchema).optional(),
137
141
  })
138
142
  .strict();
139
143
  export const textSlideParamsSchema = z
@@ -173,6 +177,7 @@ export const mulmoBeatSchema = z
173
177
  audioParams: beatAudioParamsSchema.optional(), // beat specific parameters
174
178
  speechOptions: speechOptionsSchema.optional(),
175
179
  textSlideParams: textSlideParamsSchema.optional(),
180
+ imageNames: z.array(imageIdSchema).optional(), // list of image names to use for image generation. The default is all images in the imageParams.images.
176
181
  imagePrompt: z.string().optional(), // specified or inserted by preprocessor
177
182
  })
178
183
  .strict();
@@ -231,7 +236,7 @@ export const mulmoReferenceSchema = z.object({
231
236
  url: URLStringSchema,
232
237
  title: z.string().optional(),
233
238
  description: z.string().optional(),
234
- type: z.union([z.literal("article"), z.literal("image"), z.literal("video"), z.literal("audio")]).default("article"),
239
+ type: z.union([z.literal("article"), z.literal("paper"), z.literal("image"), z.literal("video"), z.literal("audio")]).default("article"),
235
240
  });
236
241
  export const mulmoScriptSchema = mulmoPresentationStyleSchema
237
242
  .extend({
@@ -305,6 +310,7 @@ export const mulmoScriptTemplateSchema = z
305
310
  description: z.string(),
306
311
  systemPrompt: z.string(),
307
312
  scriptName: z.string().optional(),
313
+ presentationStyle: mulmoPresentationStyleSchema.optional(),
308
314
  })
309
315
  .strict();
310
316
  export const mulmoStoryboardSceneSchema = z
package/lib/utils/file.js CHANGED
@@ -18,13 +18,22 @@ export function readMulmoScriptFile(arg2, errorMessage) {
18
18
  return null;
19
19
  }
20
20
  const scriptData = fs.readFileSync(scriptPath, "utf-8");
21
- const script = ([".yaml", ".yml"].includes(path.extname(scriptPath).toLowerCase()) ? yamlParse(scriptData) : JSON.parse(scriptData));
22
- const parsedPath = path.parse(scriptPath);
23
- return {
24
- mulmoData: script,
25
- mulmoDataPath: scriptPath,
26
- fileName: parsedPath.name,
27
- };
21
+ try {
22
+ const script = ([".yaml", ".yml"].includes(path.extname(scriptPath).toLowerCase()) ? yamlParse(scriptData) : JSON.parse(scriptData));
23
+ const parsedPath = path.parse(scriptPath);
24
+ return {
25
+ mulmoData: script,
26
+ mulmoDataPath: scriptPath,
27
+ fileName: parsedPath.name,
28
+ };
29
+ }
30
+ catch (__error) {
31
+ if (errorMessage) {
32
+ GraphAILogger.info("read file format is broken.");
33
+ process.exit(1);
34
+ }
35
+ return null;
36
+ }
28
37
  }
29
38
  export const fetchMulmoScriptFile = async (url) => {
30
39
  try {
@@ -120,10 +129,12 @@ export const readScriptTemplateFile = (scriptName) => {
120
129
  export const readTemplatePrompt = (templateName) => {
121
130
  const templatePath = getTemplateFilePath(templateName);
122
131
  const templateData = fs.readFileSync(templatePath, "utf-8");
123
- const template = mulmoScriptTemplateSchema.parse(JSON.parse(templateData));
132
+ // NOTE: We don't want to schema parse the template here to eliminate default values.
133
+ const template = JSON.parse(templateData);
124
134
  const script = (() => {
125
135
  if (template.scriptName) {
126
- return readScriptTemplateFile(template.scriptName);
136
+ const script = readScriptTemplateFile(template.scriptName);
137
+ return { ...script, ...(template.presentationStyle ?? {}) };
127
138
  }
128
139
  return undefined;
129
140
  })();
@@ -2,6 +2,7 @@ import { PDFFont } from "pdf-lib";
2
2
  export declare const fontSize = 12;
3
3
  export declare const textMargin = 6;
4
4
  export declare const drawSize: (fitWidth: boolean, expectWidth: number, expectHeight: number, origWidth: number, origHeight: number) => {
5
+ containerWidth: number;
5
6
  drawWidth: number;
6
7
  drawHeight: number;
7
8
  };
package/lib/utils/pdf.js CHANGED
@@ -6,6 +6,7 @@ export const drawSize = (fitWidth, expectWidth, expectHeight, origWidth, origHei
6
6
  const scale = drawWidth / origWidth;
7
7
  const drawHeight = origHeight * scale;
8
8
  return {
9
+ containerWidth: expectWidth,
9
10
  drawWidth,
10
11
  drawHeight,
11
12
  };
@@ -14,6 +15,7 @@ export const drawSize = (fitWidth, expectWidth, expectHeight, origWidth, origHei
14
15
  const scale = drawHeight / origHeight;
15
16
  const drawWidth = origWidth * scale;
16
17
  return {
18
+ containerWidth: expectWidth,
17
19
  drawWidth,
18
20
  drawHeight,
19
21
  };
@@ -37,10 +39,10 @@ export const wrapText = (text, font, fontSize, maxWidth) => {
37
39
  const currentIsFull = isFullwidth(char);
38
40
  const nextIsFull = nextChar && isFullwidth(nextChar);
39
41
  const isBreakable = currentIsFull || (!currentIsFull && (char === " " || nextChar === " " || nextIsFull));
40
- if (width > maxWidth && buffer) {
42
+ if (width > maxWidth && line) {
41
43
  lines.push(line);
42
- line = "";
43
- buffer = char;
44
+ line = buffer;
45
+ buffer = "";
44
46
  }
45
47
  if (isBreakable || i === rawLine.length - 1) {
46
48
  line += buffer;
@@ -101,21 +101,6 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
101
101
  path: string;
102
102
  kind: "path";
103
103
  };
104
- } | {
105
- type: "movie";
106
- source: {
107
- url: string;
108
- kind: "url";
109
- } | {
110
- kind: "base64";
111
- data: string;
112
- } | {
113
- text: string;
114
- kind: "text";
115
- } | {
116
- path: string;
117
- kind: "path";
118
- };
119
104
  } | {
120
105
  type: "textSlide";
121
106
  slide: {
@@ -147,6 +132,22 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
147
132
  } | {
148
133
  type: "html_tailwind";
149
134
  html: string | string[];
135
+ } | {
136
+ type: "movie";
137
+ source: {
138
+ url: string;
139
+ kind: "url";
140
+ } | {
141
+ kind: "base64";
142
+ data: string;
143
+ } | {
144
+ text: string;
145
+ kind: "text";
146
+ } | {
147
+ path: string;
148
+ kind: "path";
149
+ };
150
+ mixAudio: number;
150
151
  } | undefined;
151
152
  audio?: {
152
153
  type: "audio";
@@ -172,6 +173,22 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
172
173
  size?: string | undefined;
173
174
  style?: string | undefined;
174
175
  moderation?: string | undefined;
176
+ images?: Record<string, {
177
+ type: "image";
178
+ source: {
179
+ url: string;
180
+ kind: "url";
181
+ } | {
182
+ kind: "base64";
183
+ data: string;
184
+ } | {
185
+ text: string;
186
+ kind: "text";
187
+ } | {
188
+ path: string;
189
+ kind: "path";
190
+ };
191
+ }> | undefined;
175
192
  } | undefined;
176
193
  audioParams?: {
177
194
  padding?: number | undefined;
@@ -179,6 +196,7 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
179
196
  textSlideParams?: {
180
197
  cssStyles: string | string[];
181
198
  } | undefined;
199
+ imageNames?: string[] | undefined;
182
200
  imagePrompt?: string | undefined;
183
201
  }[];
184
202
  lang?: string | undefined;
@@ -189,6 +207,22 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
189
207
  size?: string | undefined;
190
208
  style?: string | undefined;
191
209
  moderation?: string | undefined;
210
+ images?: Record<string, {
211
+ type: "image";
212
+ source: {
213
+ url: string;
214
+ kind: "url";
215
+ } | {
216
+ kind: "base64";
217
+ data: string;
218
+ } | {
219
+ text: string;
220
+ kind: "text";
221
+ } | {
222
+ path: string;
223
+ kind: "path";
224
+ };
225
+ }> | undefined;
192
226
  } | undefined;
193
227
  textSlideParams?: {
194
228
  cssStyles: string | string[];
@@ -196,7 +230,7 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
196
230
  omitCaptions?: boolean | undefined;
197
231
  description?: string | undefined;
198
232
  references?: {
199
- type: "image" | "audio" | "article" | "video";
233
+ type: "image" | "audio" | "article" | "paper" | "video";
200
234
  url: string;
201
235
  title?: string | undefined;
202
236
  description?: string | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mulmocast",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "lib/cli/bin.js",
@@ -52,22 +52,22 @@
52
52
  "homepage": "https://github.com/receptron/mulmocast-cli#readme",
53
53
  "dependencies": {
54
54
  "@google-cloud/text-to-speech": "^6.1.0",
55
- "@graphai/anthropic_agent": "^2.0.0",
55
+ "@graphai/anthropic_agent": "^2.0.2",
56
56
  "@graphai/browserless_agent": "^2.0.0",
57
- "@graphai/gemini_agent": "^1.0.1",
58
- "@graphai/groq_agent": "^1.0.1",
57
+ "@graphai/gemini_agent": "^2.0.0",
58
+ "@graphai/groq_agent": "^2.0.0",
59
59
  "@graphai/input_agents": "^1.0.1",
60
- "@graphai/openai_agent": "^2.0.0",
61
- "@graphai/stream_agent_filter": "^2.0.1",
62
- "@graphai/vanilla": "^2.0.2",
63
- "@graphai/vanilla_node_agents": "^2.0.0",
60
+ "@graphai/openai_agent": "^2.0.3",
61
+ "@graphai/stream_agent_filter": "^2.0.2",
62
+ "@graphai/vanilla": "^2.0.4",
63
+ "@graphai/vanilla_node_agents": "^2.0.1",
64
64
  "@pdf-lib/fontkit": "^1.1.1",
65
65
  "canvas": "^3.1.0",
66
66
  "clipboardy": "^4.0.0",
67
67
  "dotenv": "^16.4.7",
68
68
  "fluent-ffmpeg": "^2.1.3",
69
69
  "google-auth-library": "^9.15.1",
70
- "graphai": "^2.0.3",
70
+ "graphai": "^2.0.5",
71
71
  "inquirer": "^12.6.1",
72
72
  "marked": "^15.0.11",
73
73
  "ora": "^8.2.0",
@@ -4,13 +4,6 @@
4
4
  "credit": "closing"
5
5
  },
6
6
  "title": "桃太郎",
7
- "canvasSize": {
8
- "width": 1536,
9
- "height": 1024
10
- },
11
- "imageParams": {
12
- "style": "A hand-drawn style illustration with a warm, nostalgic atmosphere. The background is rich with natural scenery—lush forests, cloudy skies, and traditional Japanese architecture. Characters have expressive eyes, soft facial features, and are portrayed with gentle lighting and subtle shading. The color palette is muted yet vivid, using earthy tones and watercolor-like textures. The overall scene feels magical and peaceful, with a sense of quiet wonder and emotional depth, reminiscent of classic 1980s and 1990s Japanese animation."
13
- },
14
7
  "lang": "ja",
15
8
  "beats": [
16
9
  {
@@ -0,0 +1,41 @@
1
+ {
2
+ "$mulmocast": {
3
+ "version": "1.0",
4
+ "credit": "closing"
5
+ },
6
+ "title": "[TITLE: Brief, engaging title for the topic]",
7
+ "lang": "en",
8
+ "references": [
9
+ {
10
+ "url": "[SOURCE_URL: URL of the source material]",
11
+ "title": "[SOURCE_TITLE: Title of the referenced article, or paper]",
12
+ "type": "[SOURCE_TYPE: article, paper]"
13
+ }
14
+ ],
15
+ "beats": [
16
+ {
17
+ "text": "[OPENING_BEAT: Introduce the topic with a hook. Reference the source material and set up why this topic matters. Usually 2-3 sentences that grab attention and provide context.]",
18
+ "imagePrompt": "[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]"
19
+ },
20
+ {
21
+ "text": "[MAIN_CONCEPT: Define or explain the core concept/idea. This should be the central focus of your narrative. Keep it clear and accessible.]",
22
+ "imagePrompt": "[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]"
23
+ },
24
+ {
25
+ "text": "[SUPPORTING_DETAIL_1: Additional context, examples, or elaboration that helps illustrate the main concept. This could include how it works, why it's important, or real-world applications.]",
26
+ "imagePrompt": "[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]"
27
+ },
28
+ {
29
+ "text": "[SUPPORTING_DETAIL_2: Continue with more examples, deeper explanation, or different aspects of the topic if needed.]",
30
+ "imagePrompt": "[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]"
31
+ },
32
+ {
33
+ "text": "[ADDITIONAL_BEATS: Add more beats as necessary to fully explore the topic. Complex topics may require 6-10+ beats to cover adequately. Each beat should advance the narrative or provide valuable information.]",
34
+ "imagePrompt": "[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]"
35
+ },
36
+ {
37
+ "text": "[CONCLUSION/IMPACT: Wrap up with the significance, implications, or key takeaway. Help the audience understand why this matters to them.]",
38
+ "imagePrompt": "[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]"
39
+ }
40
+ ]
41
+ }
@@ -6,17 +6,6 @@
6
6
  "title": "韓国の戒厳令とその日本への影響",
7
7
  "description": "韓国で最近発令された戒厳令とその可能性のある影響について、また日本の憲法に関する考慮事項との類似点を含めた洞察に満ちた議論。",
8
8
  "lang": "ja",
9
- "imageParams": {
10
- "style": "<style>Ghibli style. Student (Taro) is a young teenager with a dark short hair with glasses. Teacher is a middle-aged man with grey hair and moustache.</style>"
11
- },
12
- "speechParams": {
13
- "provider": "nijivoice",
14
- "speakers": {
15
- "Announcer": { "displayName": { "ja": "アナウンサー" }, "voiceId": "afd7df65-0fdc-4d31-ae8b-a29f0f5eed62" },
16
- "Student": { "displayName": { "ja": "太郎" }, "voiceId": "a7619e48-bf6a-4f9f-843f-40485651257f" },
17
- "Teacher": { "displayName": { "ja": "先生" }, "voiceId": "bc06c63f-fef6-43b6-92f7-67f919bd5dae" }
18
- }
19
- },
20
9
  "beats": [
21
10
  {
22
11
  "speaker": "Announcer",
@@ -0,0 +1,35 @@
1
+ {
2
+ "$mulmocast": {
3
+ "version": "1.0",
4
+ "credit": "closing"
5
+ },
6
+ "title": "[TITLE: Brief, engaging title for the topic]",
7
+ "lang": "en",
8
+ "references": [
9
+ {
10
+ "url": "[SOURCE_URL: URL of the source material]",
11
+ "title": "[SOURCE_TITLE: Title of the referenced article, or paper]",
12
+ "type": "[SOURCE_TYPE: article, paper]"
13
+ }
14
+ ],
15
+ "beats": [
16
+ {
17
+ "text": "[OPENING_BEAT: Introduce the topic with a hook. Reference the source material and set up why this topic matters. Usually 2-3 sentences that grab attention and provide context.]"
18
+ },
19
+ {
20
+ "text": "[MAIN_CONCEPT: Define or explain the core concept/idea. This should be the central focus of your narrative. Keep it clear and accessible.]"
21
+ },
22
+ {
23
+ "text": "[SUPPORTING_DETAIL_1: Additional context, examples, or elaboration that helps illustrate the main concept. This could include how it works, why it's important, or real-world applications.]"
24
+ },
25
+ {
26
+ "text": "[SUPPORTING_DETAIL_2: Continue with more examples, deeper explanation, or different aspects of the topic if needed.]"
27
+ },
28
+ {
29
+ "text": "[ADDITIONAL_BEATS: Add more beats as necessary to fully explore the topic. Complex topics may require 6-10+ beats to cover adequately. Each beat should advance the narrative or provide valuable information.]"
30
+ },
31
+ {
32
+ "text": "[CONCLUSION/IMPACT: Wrap up with the significance, implications, or key takeaway. Help the audience understand why this matters to them.]"
33
+ }
34
+ ]
35
+ }
@@ -1,6 +0,0 @@
1
- {
2
- "title": "American Comic Strips",
3
- "description": "Template for Dilbert-style comic strips.",
4
- "systemPrompt": "Generate a script for a presentation of the given topic. Another AI will generate comic strips for each beat based on the text description of that beat. Mention the reference in one of beats, if it exists. Use the JSON below as a template.",
5
- "scriptName": "ghibli_strips.json"
6
- }
@@ -1,30 +0,0 @@
1
- {
2
- "$mulmocast": {
3
- "version": "1.0",
4
- "credit": "closing"
5
- },
6
- "title": "Sample Title",
7
- "lang": "en",
8
- "canvasSize": {
9
- "width": 1536,
10
- "height": 1024
11
- },
12
- "imageParams": {
13
- "style": "<style>A multi panel comic strips. 1990s American workplace humor. Clean, minimalist line art with muted colors. One character is a nerdy office worker with glasses</style>"
14
- },
15
- "references": [
16
- {
17
- "url": "https://www.somegreatwebsite.com/article/123",
18
- "title": "Title of the article we are referencing",
19
- "type": "article"
20
- }
21
- ],
22
- "beats": [
23
- {
24
- "text": "Today we're exploring a fascinating concept that has shaped some of the most innovative companies and leaders of our time. This story is based on an Awesome News articled, titled 'The reality distortion field'. This term has become synonymous with visionary leadership and the ability to accomplish seemingly impossible goals."
25
- },
26
- {
27
- "text": "The Reality Distortion Field is a concept that was first introduced by Steve Jobs, the co-founder of Apple. It refers to the ability of a leader to convince people that something is possible, even if it seems impossible."
28
- }
29
- ]
30
- }
@@ -1,30 +0,0 @@
1
- {
2
- "$mulmocast": {
3
- "version": "1.0",
4
- "credit": "closing"
5
- },
6
- "title": "Sample Title",
7
- "lang": "en",
8
- "canvasSize": {
9
- "width": 1536,
10
- "height": 1024
11
- },
12
- "imageParams": {
13
- "style": "<style>A multi panel comic strips. Ghibli style. The presenter is a young woman with a dark short hair with glasses.</style>"
14
- },
15
- "references": [
16
- {
17
- "url": "https://www.somegreatwebsite.com/article/123",
18
- "title": "The Awesome News: The reality distortion field",
19
- "type": "article"
20
- }
21
- ],
22
- "beats": [
23
- {
24
- "text": "Today we're exploring a fascinating concept that has shaped some of the most innovative companies and leaders of our time. This story is based on an Awesome News articled, titled 'The reality distortion field'. This term has become synonymous with visionary leadership and the ability to accomplish seemingly impossible goals."
25
- },
26
- {
27
- "text": "The Reality Distortion Field is a concept that was first introduced by Steve Jobs, the co-founder of Apple. It refers to the ability of a leader to convince people that something is possible, even if it seems impossible."
28
- }
29
- ]
30
- }