mulmocast 0.0.10 → 0.0.12

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 (62) hide show
  1. package/README.md +18 -3
  2. package/assets/templates/ghibli_shorts.json +34 -0
  3. package/assets/templates/shorts.json +18 -0
  4. package/assets/templates/trailer.json +25 -0
  5. package/lib/actions/audio.d.ts +2 -1
  6. package/lib/actions/audio.js +35 -17
  7. package/lib/actions/captions.js +5 -5
  8. package/lib/actions/images.d.ts +2 -1
  9. package/lib/actions/images.js +90 -58
  10. package/lib/actions/movie.js +53 -16
  11. package/lib/actions/pdf.js +3 -3
  12. package/lib/actions/translate.d.ts +2 -1
  13. package/lib/actions/translate.js +21 -16
  14. package/lib/agents/combine_audio_files_agent.js +4 -0
  15. package/lib/agents/image_google_agent.d.ts +4 -1
  16. package/lib/agents/image_google_agent.js +3 -2
  17. package/lib/agents/image_openai_agent.d.ts +5 -3
  18. package/lib/agents/image_openai_agent.js +35 -7
  19. package/lib/agents/index.d.ts +2 -1
  20. package/lib/agents/index.js +2 -1
  21. package/lib/agents/movie_google_agent.d.ts +9 -2
  22. package/lib/agents/movie_google_agent.js +24 -16
  23. package/lib/agents/tts_elevenlabs_agent.d.ts +4 -0
  24. package/lib/agents/tts_elevenlabs_agent.js +60 -0
  25. package/lib/agents/tts_google_agent.js +1 -1
  26. package/lib/agents/tts_nijivoice_agent.js +3 -2
  27. package/lib/agents/tts_openai_agent.js +1 -1
  28. package/lib/cli/commands/audio/handler.js +4 -1
  29. package/lib/cli/commands/image/handler.js +4 -1
  30. package/lib/cli/commands/movie/handler.js +4 -1
  31. package/lib/cli/commands/pdf/handler.js +4 -1
  32. package/lib/cli/commands/translate/handler.js +4 -1
  33. package/lib/cli/helpers.d.ts +3 -3
  34. package/lib/cli/helpers.js +38 -20
  35. package/lib/index.d.ts +5 -0
  36. package/lib/index.js +5 -0
  37. package/lib/methods/mulmo_media_source.d.ts +1 -0
  38. package/lib/methods/mulmo_media_source.js +12 -0
  39. package/lib/methods/mulmo_script.d.ts +1 -1
  40. package/lib/methods/mulmo_script.js +9 -5
  41. package/lib/methods/mulmo_studio_context.d.ts +5 -0
  42. package/lib/methods/mulmo_studio_context.js +23 -0
  43. package/lib/types/index.d.ts +1 -0
  44. package/lib/types/index.js +1 -0
  45. package/lib/types/schema.d.ts +1513 -290
  46. package/lib/types/schema.js +26 -35
  47. package/lib/types/type.d.ts +4 -1
  48. package/lib/utils/file.d.ts +5 -15
  49. package/lib/utils/file.js +14 -21
  50. package/lib/utils/filters.js +4 -4
  51. package/lib/utils/image_plugins/beat.d.ts +4 -0
  52. package/lib/utils/image_plugins/beat.js +7 -0
  53. package/lib/utils/image_plugins/image.d.ts +1 -1
  54. package/lib/utils/image_plugins/index.d.ts +2 -1
  55. package/lib/utils/image_plugins/index.js +2 -1
  56. package/lib/utils/image_plugins/movie.d.ts +1 -1
  57. package/lib/utils/image_plugins/source.js +2 -2
  58. package/lib/utils/preprocess.d.ts +26 -23
  59. package/lib/utils/preprocess.js +4 -0
  60. package/package.json +8 -8
  61. package/scripts/templates/movie_prompts_no_text_template.json +50 -0
  62. package/scripts/templates/shorts_template.json +52 -0
@@ -20,11 +20,13 @@ export const speechOptionsSchema = z
20
20
  })
21
21
  .strict();
22
22
  const speakerIdSchema = z.string();
23
+ export const text2SpeechProviderSchema = z.union([z.literal("openai"), z.literal("nijivoice"), z.literal("google"), z.literal("elevenlabs")]).default("openai");
23
24
  const speakerDataSchema = z
24
25
  .object({
25
26
  displayName: z.record(langSchema, z.string()).optional(),
26
27
  voiceId: z.string(),
27
28
  speechOptions: speechOptionsSchema.optional(),
29
+ provider: text2SpeechProviderSchema.optional(),
28
30
  })
29
31
  .strict();
30
32
  export const speakerDictionarySchema = z.record(speakerIdSchema, speakerDataSchema);
@@ -103,6 +105,12 @@ export const mulmoHtmlTailwindMediaSchema = z
103
105
  html: stringOrStringArray,
104
106
  })
105
107
  .strict();
108
+ export const mulmoBeatReferenceMediaSchema = z
109
+ .object({
110
+ type: z.literal("beat"),
111
+ id: z.string().optional().describe("Specifies the beat to reference."),
112
+ })
113
+ .strict();
106
114
  export const mulmoImageAssetSchema = z.union([
107
115
  mulmoMarkdownMediaSchema,
108
116
  mulmoWebMediaSchema,
@@ -116,6 +124,7 @@ export const mulmoImageAssetSchema = z.union([
116
124
  mulmoChartMediaSchema,
117
125
  mulmoMermaidMediaSchema,
118
126
  mulmoHtmlTailwindMediaSchema,
127
+ mulmoBeatReferenceMediaSchema,
119
128
  ]);
120
129
  const mulmoAudioMediaSchema = z
121
130
  .object({
@@ -134,7 +143,6 @@ const imageIdSchema = z.string();
134
143
  export const mulmoImageParamsSchema = z
135
144
  .object({
136
145
  model: z.string().optional(), // default: provider specific
137
- size: z.string().optional(), // default: provider specific
138
146
  style: z.string().optional(), // optional image style
139
147
  moderation: z.string().optional(), // optional image style
140
148
  images: z.record(imageIdSchema, mulmoImageMediaSchema).optional(),
@@ -145,13 +153,6 @@ export const textSlideParamsSchema = z
145
153
  cssStyles: stringOrStringArray,
146
154
  })
147
155
  .strict();
148
- /* TODO: Add something later
149
- export const videoParamsSchema = z
150
- .object({
151
- padding: z.number().optional(), // msec
152
- })
153
- .strict();
154
- */
155
156
  export const beatAudioParamsSchema = z
156
157
  .object({
157
158
  padding: z.number().optional().describe("Padding between beats"), // seconds
@@ -164,12 +165,15 @@ export const audioParamsSchema = z
164
165
  introPadding: z.number().describe("Padding at the beginning of the audio"), // seconds
165
166
  closingPadding: z.number().describe("Padding before the last beat"), // seconds
166
167
  outroPadding: z.number().describe("Padding at the end of the audio"), // seconds
168
+ bgm: mediaSourceSchema.optional(),
167
169
  })
168
170
  .strict();
169
171
  export const mulmoBeatSchema = z
170
172
  .object({
171
173
  speaker: speakerIdSchema.default("Presenter"),
172
- text: z.string().describe("Text to be spoken. If empty, the audio is not generated."),
174
+ text: z.string().default("").describe("Text to be spoken. If empty, the audio is not generated."),
175
+ id: z.string().optional().describe("Unique identifier for the beat."),
176
+ description: z.string().optional(),
173
177
  image: mulmoImageAssetSchema.optional(),
174
178
  audio: mulmoAudioAssetSchema.optional(),
175
179
  duration: z.number().optional().describe("Duration of the beat. Used only when the text is empty"),
@@ -195,7 +199,6 @@ export const mulmoCastCreditSchema = z
195
199
  credit: z.literal("closing").optional(),
196
200
  })
197
201
  .strict();
198
- export const text2SpeechProviderSchema = z.union([z.literal("openai"), z.literal("nijivoice"), z.literal("google")]).default("openai");
199
202
  export const mulmoSpeechParamsSchema = z
200
203
  .object({
201
204
  provider: text2SpeechProviderSchema, // has default value
@@ -204,10 +207,15 @@ export const mulmoSpeechParamsSchema = z
204
207
  .strict();
205
208
  export const text2ImageProviderSchema = z.union([z.literal("openai"), z.literal("google")]).default("openai");
206
209
  export const text2MovieProviderSchema = z.union([z.literal("openai"), z.literal("google")]).default("google");
210
+ export const mulmoTransitionSchema = z.object({
211
+ type: z.enum(["fade"]),
212
+ duration: z.number().min(0).max(2).default(0.3), // transition duration in seconds
213
+ });
207
214
  export const mulmoMovieParamsSchema = z
208
215
  .object({
209
216
  provider: text2MovieProviderSchema.optional(),
210
217
  model: z.string().optional(), // default: provider specific
218
+ transition: mulmoTransitionSchema.optional(),
211
219
  })
212
220
  .strict();
213
221
  export const mulmoPresentationStyleSchema = z.object({
@@ -231,15 +239,12 @@ export const mulmoPresentationStyleSchema = z.object({
231
239
  movieParams: mulmoMovieParamsSchema.optional(),
232
240
  // for textSlides
233
241
  textSlideParams: textSlideParamsSchema.optional(),
234
- // videoParams: videoParamsSchema.optional(),
235
242
  audioParams: audioParamsSchema.default({
236
243
  introPadding: 1.0,
237
244
  padding: 0.3,
238
245
  closingPadding: 0.8,
239
246
  outroPadding: 1.0,
240
247
  }),
241
- // TODO: Switch to showCaptions later
242
- omitCaptions: z.boolean().optional(), // default is false
243
248
  });
244
249
  export const mulmoReferenceSchema = z.object({
245
250
  url: URLStringSchema,
@@ -284,11 +289,11 @@ export const mulmoSessionStateSchema = z.object({
284
289
  pdf: z.boolean(),
285
290
  }),
286
291
  inBeatSession: z.object({
287
- audio: z.set(z.number()),
288
- image: z.set(z.number()),
289
- movie: z.set(z.number()),
290
- multiLingual: z.set(z.number()),
291
- caption: z.set(z.number()),
292
+ audio: z.record(z.number().int(), z.boolean()),
293
+ image: z.record(z.number().int(), z.boolean()),
294
+ movie: z.record(z.number().int(), z.boolean()),
295
+ multiLingual: z.record(z.number().int(), z.boolean()),
296
+ caption: z.record(z.number().int(), z.boolean()),
292
297
  }),
293
298
  });
294
299
  export const mulmoStudioSchema = z
@@ -297,23 +302,6 @@ export const mulmoStudioSchema = z
297
302
  filename: z.string(),
298
303
  beats: z.array(mulmoStudioBeatSchema).min(1),
299
304
  multiLingual: mulmoStudioMultiLingualSchema,
300
- state: mulmoSessionStateSchema.default({
301
- inSession: {
302
- audio: false,
303
- image: false,
304
- video: false,
305
- multiLingual: false,
306
- caption: false,
307
- pdf: false,
308
- },
309
- inBeatSession: {
310
- audio: new Set(),
311
- image: new Set(),
312
- movie: new Set(),
313
- multiLingual: new Set(),
314
- caption: new Set(),
315
- },
316
- }),
317
305
  })
318
306
  .strict();
319
307
  export const mulmoScriptTemplateSchema = z
@@ -325,6 +313,9 @@ export const mulmoScriptTemplateSchema = z
325
313
  presentationStyle: mulmoPresentationStyleSchema.optional(),
326
314
  })
327
315
  .strict();
316
+ export const mulmoScriptTemplateFileSchema = mulmoScriptTemplateSchema.extend({
317
+ filename: z.string(),
318
+ });
328
319
  export const mulmoStoryboardSceneSchema = z
329
320
  .object({
330
321
  description: z.string(),
@@ -1,4 +1,4 @@
1
- import { langSchema, localizedTextSchema, mulmoBeatSchema, mulmoScriptSchema, mulmoStudioSchema, mulmoStudioBeatSchema, mulmoStoryboardSchema, mulmoStoryboardSceneSchema, mulmoStudioMultiLingualSchema, mulmoStudioMultiLingualDataSchema, speakerDictionarySchema, mulmoImageParamsSchema, mulmoMovieParamsSchema, mulmoSpeechParamsSchema, textSlideParamsSchema, speechOptionsSchema, mulmoCanvasDimensionSchema, mulmoScriptTemplateSchema, text2ImageProviderSchema, text2MovieProviderSchema, text2SpeechProviderSchema, mulmoPresentationStyleSchema, multiLingualTextsSchema, mulmoMermaidMediaSchema, mulmoTextSlideMediaSchema, mulmoMarkdownMediaSchema, mulmoImageMediaSchema, mulmoChartMediaSchema, mediaSourceSchema } from "./schema.js";
1
+ import { langSchema, localizedTextSchema, mulmoBeatSchema, mulmoScriptSchema, mulmoStudioSchema, mulmoStudioBeatSchema, mulmoStoryboardSchema, mulmoStoryboardSceneSchema, mulmoStudioMultiLingualSchema, mulmoStudioMultiLingualDataSchema, speakerDictionarySchema, mulmoImageParamsSchema, mulmoMovieParamsSchema, mulmoSpeechParamsSchema, textSlideParamsSchema, speechOptionsSchema, mulmoCanvasDimensionSchema, mulmoScriptTemplateSchema, mulmoScriptTemplateFileSchema, text2ImageProviderSchema, text2MovieProviderSchema, text2SpeechProviderSchema, mulmoPresentationStyleSchema, multiLingualTextsSchema, mulmoMermaidMediaSchema, mulmoTextSlideMediaSchema, mulmoMarkdownMediaSchema, mulmoImageMediaSchema, mulmoChartMediaSchema, mediaSourceSchema, mulmoSessionStateSchema } from "./schema.js";
2
2
  import { pdf_modes, pdf_sizes, storyToScriptGenerateMode } from "../utils/const.js";
3
3
  import { LLM } from "../utils/utils.js";
4
4
  import { z } from "zod";
@@ -22,6 +22,7 @@ export type MulmoStudioBeat = z.infer<typeof mulmoStudioBeatSchema>;
22
22
  export type MulmoMediaSource = z.infer<typeof mediaSourceSchema>;
23
23
  export type MulmoStudio = z.infer<typeof mulmoStudioSchema>;
24
24
  export type MulmoScriptTemplate = z.infer<typeof mulmoScriptTemplateSchema>;
25
+ export type MulmoScriptTemplateFile = z.infer<typeof mulmoScriptTemplateFileSchema>;
25
26
  export type MulmoStudioMultiLingual = z.infer<typeof mulmoStudioMultiLingualSchema>;
26
27
  export type MulmoStudioMultiLingualData = z.infer<typeof mulmoStudioMultiLingualDataSchema>;
27
28
  export type MultiLingualTexts = z.infer<typeof multiLingualTextsSchema>;
@@ -31,6 +32,7 @@ export type MulmoMarkdownMedia = z.infer<typeof mulmoMarkdownMediaSchema>;
31
32
  export type MulmoImageMedia = z.infer<typeof mulmoImageMediaSchema>;
32
33
  export type MulmoChartMedia = z.infer<typeof mulmoChartMediaSchema>;
33
34
  export type MulmoMermaidMedia = z.infer<typeof mulmoMermaidMediaSchema>;
35
+ export type MulmoSessionState = z.infer<typeof mulmoSessionStateSchema>;
34
36
  export type FileDirs = {
35
37
  mulmoFilePath: string;
36
38
  mulmoFileDirPath: string;
@@ -45,6 +47,7 @@ export type MulmoStudioContext = {
45
47
  lang?: string;
46
48
  force: boolean;
47
49
  caption?: string;
50
+ sessionState: MulmoSessionState;
48
51
  };
49
52
  export type ScriptingParams = {
50
53
  urls: string[];
@@ -1,6 +1,7 @@
1
- import { MulmoScript, MulmoScriptTemplate, MulmoMediaSource, MulmoStudioContext } from "../types/index.js";
1
+ import { MulmoScript, MulmoScriptTemplateFile } from "../types/index.js";
2
2
  import { PDFMode } from "../types/index.js";
3
3
  import { ZodSchema } from "zod";
4
+ export declare const updateNpmRoot: (_npmRoot: string) => void;
4
5
  export declare function readMulmoScriptFile<T = MulmoScript>(path: string, errorMessage: string): {
5
6
  mulmoData: T;
6
7
  mulmoDataPath: string;
@@ -13,16 +14,8 @@ export declare function readMulmoScriptFile<T = MulmoScript>(path: string): {
13
14
  } | null;
14
15
  export declare const fetchMulmoScriptFile: (url: string) => Promise<{
15
16
  result: boolean;
16
- status: number;
17
- script?: undefined;
18
- } | {
19
- result: boolean;
20
- script: any;
21
- status?: undefined;
22
- } | {
23
- result: boolean;
24
- status: string;
25
- script?: undefined;
17
+ script?: MulmoScript;
18
+ status: string | number;
26
19
  }>;
27
20
  export declare const getOutputStudioFilePath: (outDirPath: string, fileName: string) => string;
28
21
  export declare const resolveDirPath: (dirPath: string, studioFileName: string) => string;
@@ -43,9 +36,6 @@ export declare const getBaseDirPath: (basedir?: string) => string;
43
36
  export declare const getFullPath: (baseDirPath: string | undefined, file: string) => string;
44
37
  export declare const readScriptTemplateFile: (scriptName: string) => any;
45
38
  export declare const readTemplatePrompt: (templateName: string) => string;
46
- export declare const getAvailableTemplates: () => (MulmoScriptTemplate & {
47
- filename: string;
48
- })[];
39
+ export declare const getAvailableTemplates: () => MulmoScriptTemplateFile[];
49
40
  export declare const writingMessage: (filePath: string) => void;
50
- export declare const resolveMediaSource: (source: MulmoMediaSource, context: MulmoStudioContext) => string | null;
51
41
  export declare const readAndParseJson: <S extends ZodSchema<any>>(filePath: string, schema: S) => ReturnType<S["parse"]>;
package/lib/utils/file.js CHANGED
@@ -4,16 +4,18 @@ import { parse as yamlParse } from "yaml";
4
4
  import { fileURLToPath } from "url";
5
5
  import { GraphAILogger } from "graphai";
6
6
  import { MulmoScriptTemplateMethods } from "../methods/mulmo_script_template.js";
7
- import { MulmoStudioContextMethods } from "../methods/index.js";
8
7
  import { mulmoScriptTemplateSchema } from "../types/schema.js";
9
8
  const __filename = fileURLToPath(import.meta.url);
10
9
  const __dirname = path.dirname(__filename);
10
+ let npmRoot = path.resolve(__dirname, "../../");
11
+ export const updateNpmRoot = (_npmRoot) => {
12
+ npmRoot = _npmRoot;
13
+ };
11
14
  export function readMulmoScriptFile(arg2, errorMessage) {
12
15
  const scriptPath = path.resolve(arg2);
13
16
  if (!fs.existsSync(scriptPath)) {
14
17
  if (errorMessage) {
15
18
  GraphAILogger.info(errorMessage);
16
- process.exit(1);
17
19
  }
18
20
  return null;
19
21
  }
@@ -30,7 +32,6 @@ export function readMulmoScriptFile(arg2, errorMessage) {
30
32
  catch (__error) {
31
33
  if (errorMessage) {
32
34
  GraphAILogger.info("read file format is broken.");
33
- process.exit(1);
34
35
  }
35
36
  return null;
36
37
  }
@@ -41,10 +42,11 @@ export const fetchMulmoScriptFile = async (url) => {
41
42
  if (!res.ok) {
42
43
  return { result: false, status: res.status };
43
44
  }
44
- const script = await res.json();
45
+ const script = (await res.json());
45
46
  return {
46
47
  result: true,
47
48
  script,
49
+ status: 200,
48
50
  };
49
51
  }
50
52
  catch {
@@ -85,7 +87,7 @@ export const getOutputPdfFilePath = (outDirPath, fileName, pdfMode, lang) => {
85
87
  return path.resolve(outDirPath, `${fileName}_${pdfMode}.pdf`);
86
88
  };
87
89
  export const getTemplateFilePath = (templateName) => {
88
- return path.resolve(__dirname, "../../assets/templates/" + templateName + ".json");
90
+ return path.resolve(npmRoot, "./assets/templates/" + templateName + ".json");
89
91
  };
90
92
  export const mkdir = (dirPath) => {
91
93
  if (!fs.existsSync(dirPath)) {
@@ -93,12 +95,12 @@ export const mkdir = (dirPath) => {
93
95
  fs.mkdirSync(dirPath, { recursive: true });
94
96
  }
95
97
  };
96
- export const silentPath = path.resolve(__dirname, "../../assets/audio/silent300.mp3");
97
- export const silentLastPath = path.resolve(__dirname, "../../assets/audio/silent800.mp3");
98
- export const silent60secPath = path.resolve(__dirname, "../../assets/audio/silent60sec.mp3");
99
- export const defaultBGMPath = path.resolve(__dirname, "../../assets/music/StarsBeyondEx.mp3");
98
+ export const silentPath = path.resolve(npmRoot, "./assets/audio/silent300.mp3");
99
+ export const silentLastPath = path.resolve(npmRoot, "./assets/audio/silent800.mp3");
100
+ export const silent60secPath = path.resolve(npmRoot, "./assets/audio/silent60sec.mp3");
101
+ export const defaultBGMPath = path.resolve(npmRoot, "./assets/music/StarsBeyondEx.mp3");
100
102
  export const getHTMLFile = (filename) => {
101
- const htmlPath = path.resolve(__dirname, `../../assets/html/${filename}.html`);
103
+ const htmlPath = path.resolve(npmRoot, `./assets/html/${filename}.html`);
102
104
  return fs.readFileSync(htmlPath, "utf-8");
103
105
  };
104
106
  // for cli
@@ -121,7 +123,7 @@ export const getFullPath = (baseDirPath, file) => {
121
123
  return path.resolve(file);
122
124
  };
123
125
  export const readScriptTemplateFile = (scriptName) => {
124
- const scriptPath = path.resolve(__dirname, "../../scripts/templates", scriptName);
126
+ const scriptPath = path.resolve(npmRoot, "./scripts/templates", scriptName);
125
127
  const scriptData = fs.readFileSync(scriptPath, "utf-8");
126
128
  // NOTE: We don't want to schema parse the script here to eliminate default values.
127
129
  return JSON.parse(scriptData);
@@ -142,7 +144,7 @@ export const readTemplatePrompt = (templateName) => {
142
144
  return prompt;
143
145
  };
144
146
  export const getAvailableTemplates = () => {
145
- const templatesDir = path.resolve(__dirname, "../../assets/templates");
147
+ const templatesDir = path.resolve(npmRoot, "./assets/templates");
146
148
  if (!fs.existsSync(templatesDir)) {
147
149
  return [];
148
150
  }
@@ -158,15 +160,6 @@ export const getAvailableTemplates = () => {
158
160
  export const writingMessage = (filePath) => {
159
161
  GraphAILogger.debug(`writing: ${filePath}`);
160
162
  };
161
- export const resolveMediaSource = (source, context) => {
162
- if (source.kind === "path") {
163
- return MulmoStudioContextMethods.resolveAssetPath(context, source.path);
164
- }
165
- if (source.kind === "url") {
166
- return source.url;
167
- }
168
- return null;
169
- };
170
163
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
171
164
  export const readAndParseJson = (filePath, schema) => {
172
165
  const fileContent = fs.readFileSync(filePath, "utf-8");
@@ -5,10 +5,10 @@ import fsPromise from "fs/promises";
5
5
  import { GraphAILogger } from "graphai";
6
6
  import { writingMessage } from "./file.js";
7
7
  import { text2hash } from "./utils.js";
8
- import { MulmoStudioMethods } from "../methods/mulmo_studio.js";
8
+ import { MulmoStudioContextMethods } from "../methods/mulmo_studio_context.js";
9
9
  export const fileCacheAgentFilter = async (context, next) => {
10
10
  const { namedInputs } = context;
11
- const { file, force, studio, index, sessionType } = namedInputs;
11
+ const { file, force, mulmoContext, index, sessionType } = namedInputs;
12
12
  const shouldUseCache = async () => {
13
13
  if (force) {
14
14
  return false;
@@ -25,7 +25,7 @@ export const fileCacheAgentFilter = async (context, next) => {
25
25
  return true;
26
26
  }
27
27
  try {
28
- MulmoStudioMethods.setBeatSessionState(studio, sessionType, index, true);
28
+ MulmoStudioContextMethods.setBeatSessionState(mulmoContext, sessionType, index, true);
29
29
  const output = (await next(context));
30
30
  const buffer = output ? output["buffer"] : undefined;
31
31
  if (buffer) {
@@ -37,7 +37,7 @@ export const fileCacheAgentFilter = async (context, next) => {
37
37
  return false;
38
38
  }
39
39
  finally {
40
- MulmoStudioMethods.setBeatSessionState(studio, sessionType, index, false);
40
+ MulmoStudioContextMethods.setBeatSessionState(mulmoContext, sessionType, index, false);
41
41
  }
42
42
  };
43
43
  export const browserlessCacheGenerator = (cacheDir) => {
@@ -0,0 +1,4 @@
1
+ import { ImageProcessorParams } from "../../types/index.js";
2
+ export declare const imageType = "beat";
3
+ export declare const processBeatReference: (__: ImageProcessorParams) => Promise<undefined>;
4
+ export declare const process: (__: ImageProcessorParams) => Promise<undefined>;
@@ -0,0 +1,7 @@
1
+ export const imageType = "beat";
2
+ export const processBeatReference = async (__) => {
3
+ // For beat reference, return undefined to indicate no image should be generated
4
+ // The actual reference will be resolved in mergeResult
5
+ return undefined;
6
+ };
7
+ export const process = processBeatReference;
@@ -1,2 +1,2 @@
1
1
  export declare const imageType = "image";
2
- export declare const process: (params: import("../../types/type.js").ImageProcessorParams) => string | undefined;
2
+ export declare const process: (params: import("../../index.js").ImageProcessorParams) => string | undefined;
@@ -5,4 +5,5 @@ import * as pluginChart from "./chart.js";
5
5
  import * as pluginMermaid from "./mermaid.js";
6
6
  import * as pluginMovie from "./movie.js";
7
7
  import * as pluginHtmlTailwind from "./html_tailwind.js";
8
- export declare const imagePlugins: (typeof pluginTextSlide | typeof pluginMarkdown | typeof pluginImage | typeof pluginChart | typeof pluginMermaid | typeof pluginMovie | typeof pluginHtmlTailwind)[];
8
+ import * as pluginBeat from "./beat.js";
9
+ export declare const imagePlugins: (typeof pluginTextSlide | typeof pluginMarkdown | typeof pluginImage | typeof pluginChart | typeof pluginMermaid | typeof pluginMovie | typeof pluginHtmlTailwind | typeof pluginBeat)[];
@@ -5,4 +5,5 @@ import * as pluginChart from "./chart.js";
5
5
  import * as pluginMermaid from "./mermaid.js";
6
6
  import * as pluginMovie from "./movie.js";
7
7
  import * as pluginHtmlTailwind from "./html_tailwind.js";
8
- export const imagePlugins = [pluginTextSlide, pluginMarkdown, pluginImage, pluginChart, pluginMermaid, pluginMovie, pluginHtmlTailwind];
8
+ import * as pluginBeat from "./beat.js";
9
+ export const imagePlugins = [pluginTextSlide, pluginMarkdown, pluginImage, pluginChart, pluginMermaid, pluginMovie, pluginHtmlTailwind, pluginBeat];
@@ -1,2 +1,2 @@
1
1
  export declare const imageType = "movie";
2
- export declare const process: (params: import("../../types/type.js").ImageProcessorParams) => string | undefined;
2
+ export declare const process: (params: import("../../index.js").ImageProcessorParams) => string | undefined;
@@ -1,11 +1,11 @@
1
1
  import { GraphAILogger } from "graphai";
2
- import { resolveMediaSource } from "../../utils/file.js";
2
+ import { MulmoMediaSourceMethods } from "../../methods/mulmo_media_source.js";
3
3
  export const processSource = (imageType) => {
4
4
  return (params) => {
5
5
  const { beat, context } = params;
6
6
  if (!beat.image || beat.image.type !== imageType)
7
7
  return;
8
- const path = resolveMediaSource(beat.image.source, context);
8
+ const path = MulmoMediaSourceMethods.resolve(beat.image.source, context);
9
9
  if (path) {
10
10
  return path;
11
11
  }
@@ -23,6 +23,19 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
23
23
  introPadding: number;
24
24
  closingPadding: number;
25
25
  outroPadding: number;
26
+ bgm?: {
27
+ url: string;
28
+ kind: "url";
29
+ } | {
30
+ kind: "base64";
31
+ data: string;
32
+ } | {
33
+ text: string;
34
+ kind: "text";
35
+ } | {
36
+ path: string;
37
+ kind: "path";
38
+ } | undefined;
26
39
  };
27
40
  $mulmocast: {
28
41
  version: "1.0";
@@ -33,7 +46,7 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
33
46
  height: number;
34
47
  };
35
48
  speechParams: {
36
- provider: "openai" | "nijivoice" | "google";
49
+ provider: "openai" | "nijivoice" | "google" | "elevenlabs";
37
50
  speakers: Record<string, {
38
51
  voiceId: string;
39
52
  displayName?: Record<string, string> | undefined;
@@ -41,6 +54,7 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
41
54
  speed?: number | undefined;
42
55
  instruction?: string | undefined;
43
56
  } | undefined;
57
+ provider?: "openai" | "nijivoice" | "google" | "elevenlabs" | undefined;
44
58
  }>;
45
59
  };
46
60
  beats: {
@@ -133,6 +147,9 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
133
147
  } | {
134
148
  type: "html_tailwind";
135
149
  html: string | string[];
150
+ } | {
151
+ type: "beat";
152
+ id?: string | undefined;
136
153
  } | {
137
154
  type: "movie";
138
155
  source: {
@@ -150,6 +167,7 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
150
167
  };
151
168
  mixAudio: number;
152
169
  } | undefined;
170
+ id?: string | undefined;
153
171
  audio?: {
154
172
  type: "audio";
155
173
  source: {
@@ -169,9 +187,9 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
169
187
  type: "midi";
170
188
  source: string;
171
189
  } | undefined;
190
+ description?: string | undefined;
172
191
  imageParams?: {
173
192
  model?: string | undefined;
174
- size?: string | undefined;
175
193
  style?: string | undefined;
176
194
  moderation?: string | undefined;
177
195
  images?: Record<string, {
@@ -203,10 +221,10 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
203
221
  }[];
204
222
  lang?: string | undefined;
205
223
  title?: string | undefined;
224
+ description?: string | undefined;
206
225
  imageParams?: {
207
226
  provider: "openai" | "google";
208
227
  model?: string | undefined;
209
- size?: string | undefined;
210
228
  style?: string | undefined;
211
229
  moderation?: string | undefined;
212
230
  images?: Record<string, {
@@ -230,11 +248,13 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
230
248
  cssStyles: string | string[];
231
249
  } | undefined;
232
250
  movieParams?: {
233
- model?: string | undefined;
234
251
  provider?: "openai" | "google" | undefined;
252
+ model?: string | undefined;
253
+ transition?: {
254
+ type: "fade";
255
+ duration: number;
256
+ } | undefined;
235
257
  } | undefined;
236
- omitCaptions?: boolean | undefined;
237
- description?: string | undefined;
238
258
  references?: {
239
259
  type: "image" | "audio" | "article" | "paper" | "video";
240
260
  url: string;
@@ -245,21 +265,4 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
245
265
  __test_invalid__?: boolean | undefined;
246
266
  };
247
267
  filename: string;
248
- state: {
249
- inSession: {
250
- pdf: boolean;
251
- image: boolean;
252
- audio: boolean;
253
- video: boolean;
254
- multiLingual: boolean;
255
- caption: boolean;
256
- };
257
- inBeatSession: {
258
- image: Set<number>;
259
- movie: Set<number>;
260
- audio: Set<number>;
261
- multiLingual: Set<number>;
262
- caption: Set<number>;
263
- };
264
- };
265
268
  };
@@ -1,9 +1,13 @@
1
+ import { GraphAILogger } from "graphai";
1
2
  import { mulmoScriptSchema, mulmoBeatSchema, mulmoStudioSchema } from "../types/index.js";
2
3
  const rebuildStudio = (currentStudio, mulmoScript, fileName) => {
3
4
  const parsed = mulmoStudioSchema.safeParse(currentStudio);
4
5
  if (parsed.success) {
5
6
  return parsed.data;
6
7
  }
8
+ if (currentStudio) {
9
+ GraphAILogger.info("currentStudio is invalid", parsed.error);
10
+ }
7
11
  // We need to parse it to fill default values
8
12
  return mulmoStudioSchema.parse({
9
13
  script: mulmoScript,
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "mulmocast",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "",
5
5
  "type": "module",
6
- "main": "lib/cli/bin.js",
6
+ "main": "lib/index.js",
7
7
  "bin": {
8
8
  "mulmo": "lib/cli/bin.js"
9
9
  },
@@ -69,27 +69,27 @@
69
69
  "google-auth-library": "^9.15.1",
70
70
  "graphai": "^2.0.5",
71
71
  "inquirer": "^12.6.1",
72
- "marked": "^15.0.11",
72
+ "marked": "^15.0.12",
73
73
  "ora": "^8.2.0",
74
74
  "pdf-lib": "^1.17.1",
75
- "puppeteer": "^24.8.1",
75
+ "puppeteer": "^24.10.0",
76
76
  "yaml": "^2.8.0",
77
77
  "yargs": "^17.7.2",
78
- "zod": "^3.24.4",
78
+ "zod": "^3.25.51",
79
79
  "zod-to-json-schema": "^3.24.5"
80
80
  },
81
81
  "devDependencies": {
82
82
  "@receptron/test_utils": "^2.0.0",
83
83
  "@types/fluent-ffmpeg": "^2.1.26",
84
84
  "@types/yargs": "^17.0.33",
85
- "eslint": "^9.27.0",
85
+ "eslint": "^9.28.0",
86
86
  "eslint-config-prettier": "^10.1.5",
87
- "eslint-plugin-prettier": "^5.4.0",
87
+ "eslint-plugin-prettier": "^5.4.1",
88
88
  "prettier": "^3.3.3",
89
89
  "ts-node": "^10.9.2",
90
90
  "tsx": "^4.19.4",
91
91
  "typescript": "^5.7.3",
92
- "typescript-eslint": "^8.32.1"
92
+ "typescript-eslint": "^8.33.1"
93
93
  },
94
94
  "engines": {
95
95
  "node": ">=16.0.0"
@@ -0,0 +1,50 @@
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
+ "movieParams": {
16
+ "provider": "google"
17
+ },
18
+ "beats": [
19
+ {
20
+ "duration": 5.0,
21
+ "imagePrompt": "[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]",
22
+ "moviePrompt": "[MOVIE_PROMPT: A movie prompt for that image.]"
23
+ },
24
+ {
25
+ "duration": 5.0,
26
+ "imagePrompt": "[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]",
27
+ "moviePrompt": "[MOVIE_PROMPT: A movie prompt for that image.]"
28
+ },
29
+ {
30
+ "duration": 5.0,
31
+ "imagePrompt": "[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]",
32
+ "moviePrompt": "[MOVIE_PROMPT: A movie prompt for that image.]"
33
+ },
34
+ {
35
+ "duration": 5.0,
36
+ "imagePrompt": "[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]",
37
+ "moviePrompt": "[MOVIE_PROMPT: A movie prompt for that image.]"
38
+ },
39
+ {
40
+ "duration": 5.0,
41
+ "imagePrompt": "[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]",
42
+ "moviePrompt": "[MOVIE_PROMPT: A movie prompt for that image.]"
43
+ },
44
+ {
45
+ "duration": 5.0,
46
+ "imagePrompt": "[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]",
47
+ "moviePrompt": "[MOVIE_PROMPT: A movie prompt for that image.]"
48
+ }
49
+ ]
50
+ }