mulmocast 1.2.62 → 1.2.64

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.
@@ -1,6 +1,5 @@
1
1
  import type { GraphData } from "graphai";
2
2
  import { MulmoStudioContext, MulmoBeat, PublicAPIArgs } from "../types/index.js";
3
- export declare const getBeatAudioPath: (text: string, context: MulmoStudioContext, beat: MulmoBeat, lang?: string) => string | undefined;
4
3
  export declare const getBeatAudioPathOrUrl: (text: string, context: MulmoStudioContext, beat: MulmoBeat, lang?: string) => string | undefined;
5
4
  export declare const localizedPath: (context: MulmoStudioContext, beat: MulmoBeat, index: number, lang: string) => string | undefined;
6
5
  export declare const listLocalizedAudioPaths: (context: MulmoStudioContext) => (string | undefined)[];
@@ -27,10 +27,6 @@ const getAudioPathOrUrl = (context, beat, maybeAudioFile) => {
27
27
  }
28
28
  return maybeAudioFile;
29
29
  };
30
- // for back forward compatible
31
- export const getBeatAudioPath = (text, context, beat, lang) => {
32
- return getBeatAudioPathOrUrl(text, context, beat, lang);
33
- };
34
30
  export const getBeatAudioPathOrUrl = (text, context, beat, lang) => {
35
31
  const audioDirPath = MulmoStudioContextMethods.getAudioDirPath(context);
36
32
  const { voiceId, provider, speechOptions, model } = MulmoStudioContextMethods.getAudioParam(context, beat, lang);
@@ -0,0 +1,2 @@
1
+ import { type MulmoStudioContext } from "../types/index.js";
2
+ export declare const mulmoViewerBundle: (context: MulmoStudioContext) => Promise<void>;
@@ -0,0 +1,66 @@
1
+ import path from "path";
2
+ import fs from "fs";
3
+ import { GraphAILogger } from "graphai";
4
+ import { listLocalizedAudioPaths } from "./audio.js";
5
+ import { imagePreprocessAgent } from "./image_agents.js";
6
+ import { mkdir } from "../utils/file.js";
7
+ import { ZipBuilder } from "../utils/zip.js";
8
+ const beatImage = (context) => {
9
+ return async (beat, index) => {
10
+ try {
11
+ const res = await imagePreprocessAgent({ context, beat, index, imageRefs: {} });
12
+ if ("htmlPrompt" in res) {
13
+ return { htmlImageFile: res.htmlImageFile, imagePath: res.imagePath };
14
+ }
15
+ const { imagePath, movieFile, lipSyncFile } = res;
16
+ return { imagePath, movieFile, lipSyncFile };
17
+ }
18
+ catch (e) {
19
+ GraphAILogger.log(e);
20
+ return {};
21
+ }
22
+ };
23
+ };
24
+ const viewJsonFileName = "mulmo_view.json";
25
+ const zipFileName = "mulmo.zip";
26
+ export const mulmoViewerBundle = async (context) => {
27
+ const isZip = true;
28
+ const audios = listLocalizedAudioPaths(context);
29
+ const images = await Promise.all(context.studio.script.beats.map(beatImage(context)));
30
+ const dir = path.resolve(context.fileDirs.fileName);
31
+ mkdir(dir);
32
+ const zipper = new ZipBuilder(path.resolve(dir, zipFileName));
33
+ const resultJson = [];
34
+ audios.forEach((audio) => {
35
+ if (audio) {
36
+ const fileName = path.basename(audio ?? "");
37
+ resultJson.push({ audio: fileName });
38
+ if (fs.existsSync(audio)) {
39
+ fs.copyFileSync(audio, path.resolve(dir, fileName));
40
+ zipper.addFile(audio, fileName);
41
+ }
42
+ }
43
+ else {
44
+ resultJson.push({});
45
+ }
46
+ });
47
+ images.forEach((image, index) => {
48
+ const data = resultJson[index];
49
+ const keys = ["htmlImageFile", "imagePath", "movieFile", "lipSyncFile"];
50
+ keys.forEach((key) => {
51
+ const value = image[key];
52
+ if (value) {
53
+ data[key] = path.basename(value);
54
+ if (fs.existsSync(value)) {
55
+ fs.copyFileSync(value, path.resolve(dir, path.basename(value)));
56
+ zipper.addFile(value);
57
+ }
58
+ }
59
+ });
60
+ });
61
+ fs.writeFileSync(path.resolve(dir, viewJsonFileName), JSON.stringify(resultJson, null, 2));
62
+ zipper.addFile(path.resolve(dir, viewJsonFileName));
63
+ if (isZip) {
64
+ await zipper.finalize();
65
+ }
66
+ };
@@ -1,51 +1,8 @@
1
- import { MulmoStudioContext, MulmoBeat, MulmoCanvasDimension, MulmoImageParams, MulmoMovieParams } from "../types/index.js";
2
- export declare const imagePreprocessAgent: (namedInputs: {
3
- context: MulmoStudioContext;
4
- beat: MulmoBeat;
5
- index: number;
6
- imageRefs: Record<string, string>;
7
- }) => Promise<{
8
- imagePath: string;
9
- htmlPrompt: string | undefined;
10
- htmlImageFile: string;
11
- htmlPath: string;
12
- htmlImageSystemPrompt: string;
13
- } | {
14
- imagePath: string | undefined;
15
- movieFile: string | undefined;
16
- referenceImageForMovie: string | undefined;
17
- imageParams: MulmoImageParams;
18
- soundEffectFile?: string;
19
- soundEffectPrompt?: string;
20
- soundEffectModel?: string;
21
- soundEffectAgentInfo?: {
22
- agentName: string;
23
- defaultModel: string;
24
- };
25
- lipSyncFile?: string;
26
- lipSyncModel?: string;
27
- lipSyncAgentName?: string;
28
- lipSyncTrimAudio?: boolean;
29
- bgmFile?: string | null;
30
- startAt?: number;
31
- duration?: number;
32
- audioFile?: string;
1
+ import { MulmoStudioContext, MulmoBeat, MulmoCanvasDimension, MulmoImageParams, MulmoMovieParams, Text2ImageAgentInfo } from "../types/index.js";
2
+ type ImagePreprocessAgentReturnValue = {
3
+ imageParams?: MulmoImageParams;
4
+ movieFile?: string;
33
5
  beatDuration?: number;
34
- movieAgentInfo?: {
35
- agent: string;
36
- movieParams: MulmoMovieParams;
37
- };
38
- markdown?: string;
39
- html?: string;
40
- htmlPrompt?: undefined;
41
- htmlImageFile?: undefined;
42
- htmlPath?: undefined;
43
- htmlImageSystemPrompt?: undefined;
44
- } | {
45
- imagePath: string;
46
- imageFromMovie: boolean;
47
- imageParams: MulmoImageParams;
48
- movieFile: string | undefined;
49
6
  soundEffectFile?: string;
50
7
  soundEffectPrompt?: string;
51
8
  soundEffectModel?: string;
@@ -57,56 +14,46 @@ export declare const imagePreprocessAgent: (namedInputs: {
57
14
  lipSyncModel?: string;
58
15
  lipSyncAgentName?: string;
59
16
  lipSyncTrimAudio?: boolean;
60
- bgmFile?: string | null;
61
17
  startAt?: number;
62
18
  duration?: number;
19
+ bgmFile?: string | null;
63
20
  audioFile?: string;
64
- beatDuration?: number;
65
21
  movieAgentInfo?: {
66
22
  agent: string;
67
23
  movieParams: MulmoMovieParams;
68
24
  };
69
- markdown?: string;
70
- html?: string;
71
- htmlPrompt?: undefined;
72
- htmlImageFile?: undefined;
73
- htmlPath?: undefined;
74
- htmlImageSystemPrompt?: undefined;
75
- } | {
76
- imagePath: string;
77
- referenceImageForMovie: string;
78
- imageAgentInfo: import("../types/type.js").Text2ImageAgentInfo;
25
+ };
26
+ type ImagePreprocessAgentResponseBase = ImagePreprocessAgentReturnValue & {
27
+ imagePath?: string;
28
+ };
29
+ type ImageGenearalPreprocessAgentResponse = ImagePreprocessAgentResponseBase & {
30
+ imageAgentInfo: Text2ImageAgentInfo;
79
31
  prompt: string;
80
32
  referenceImages: string[];
81
- imageParams: MulmoImageParams;
82
- movieFile: string | undefined;
83
- soundEffectFile?: string;
84
- soundEffectPrompt?: string;
85
- soundEffectModel?: string;
86
- soundEffectAgentInfo?: {
87
- agentName: string;
88
- defaultModel: string;
89
- };
90
- lipSyncFile?: string;
91
- lipSyncModel?: string;
92
- lipSyncAgentName?: string;
93
- lipSyncTrimAudio?: boolean;
94
- bgmFile?: string | null;
95
- startAt?: number;
96
- duration?: number;
97
- audioFile?: string;
98
- beatDuration?: number;
99
- movieAgentInfo?: {
100
- agent: string;
101
- movieParams: MulmoMovieParams;
102
- };
103
- markdown?: string;
104
- html?: string;
105
- htmlPrompt?: undefined;
106
- htmlImageFile?: undefined;
107
- htmlPath?: undefined;
108
- htmlImageSystemPrompt?: undefined;
109
- }>;
33
+ referenceImageForMovie: string;
34
+ };
35
+ type ImageHtmlPreprocessAgentResponse = {
36
+ imagePath: string;
37
+ htmlPrompt: string;
38
+ htmlPath: string;
39
+ htmlImageSystemPrompt: string;
40
+ htmlImageFile: string;
41
+ };
42
+ type ImageOnlyMoviePreprocessAgentResponse = ImagePreprocessAgentResponseBase & {
43
+ imageFromMovie: boolean;
44
+ };
45
+ type ImagePluginPreprocessAgentResponse = ImagePreprocessAgentResponseBase & {
46
+ referenceImageForMovie: string;
47
+ markdown: string;
48
+ html: string;
49
+ };
50
+ type ImagePreprocessAgentResponse = ImagePreprocessAgentResponseBase | ImageHtmlPreprocessAgentResponse | ImagePluginPreprocessAgentResponse | ImageOnlyMoviePreprocessAgentResponse | ImageGenearalPreprocessAgentResponse;
51
+ export declare const imagePreprocessAgent: (namedInputs: {
52
+ context: MulmoStudioContext;
53
+ beat: MulmoBeat;
54
+ index: number;
55
+ imageRefs: Record<string, string>;
56
+ }) => Promise<ImagePreprocessAgentResponse>;
110
57
  export declare const imagePluginAgent: (namedInputs: {
111
58
  context: MulmoStudioContext;
112
59
  beat: MulmoBeat;
@@ -117,3 +64,4 @@ export declare const htmlImageGeneratorAgent: (namedInputs: {
117
64
  canvasSize: MulmoCanvasDimension;
118
65
  htmlText: string;
119
66
  }) => Promise<void>;
67
+ export {};
@@ -17,6 +17,7 @@ export const imagePreprocessAgent = async (namedInputs) => {
17
17
  if (beat.htmlPrompt) {
18
18
  const htmlPrompt = MulmoBeatMethods.getHtmlPrompt(beat);
19
19
  const htmlPath = imagePath.replace(/\.[^/.]+$/, ".html");
20
+ // ImageHtmlPreprocessAgentResponse
20
21
  return { imagePath, htmlPrompt, htmlImageFile, htmlPath, htmlImageSystemPrompt: htmlImageSystemPrompt(context.presentationStyle.canvasSize) };
21
22
  }
22
23
  const imageAgentInfo = MulmoPresentationStyleMethods.getImageAgentInfo(context.presentationStyle, beat);
@@ -62,27 +63,28 @@ export const imagePreprocessAgent = async (namedInputs) => {
62
63
  if (beat.image) {
63
64
  const plugin = MulmoBeatMethods.getPlugin(beat);
64
65
  const pluginPath = plugin.path({ beat, context, imagePath, ...htmlStyle(context, beat) });
65
- if (plugin.markdown) {
66
- returnValue.markdown = plugin.markdown({ beat, context, imagePath, ...htmlStyle(context, beat) });
67
- }
68
- if (plugin.html) {
69
- returnValue.html = await plugin.html({ beat, context, imagePath, ...htmlStyle(context, beat) });
70
- }
66
+ const markdown = plugin.markdown ? plugin.markdown({ beat, context, imagePath, ...htmlStyle(context, beat) }) : undefined;
67
+ const html = plugin.html ? await plugin.html({ beat, context, imagePath, ...htmlStyle(context, beat) }) : undefined;
71
68
  const isTypeMovie = beat.image.type === "movie";
72
69
  // undefined prompt indicates that image generation is not needed
70
+ // ImagePluginPreprocessAgentResponse
73
71
  return {
74
72
  ...returnValue,
75
73
  imagePath: isTypeMovie ? undefined : pluginPath,
76
74
  movieFile: isTypeMovie ? pluginPath : undefined,
77
75
  referenceImageForMovie: pluginPath,
76
+ markdown,
77
+ html,
78
78
  };
79
79
  }
80
80
  if (beat.moviePrompt && !beat.imagePrompt) {
81
+ // ImageOnlyMoviePreprocessAgentResponse
81
82
  return { ...returnValue, imagePath, imageFromMovie: true }; // no image prompt, only movie prompt
82
83
  }
83
84
  // referenceImages for "edit_image", openai agent.
84
85
  const referenceImages = MulmoBeatMethods.getImageReferenceForImageGenerator(beat, imageRefs);
85
86
  const prompt = imagePrompt(beat, imageAgentInfo.imageParams.style);
87
+ // ImageGenearalPreprocessAgentResponse
86
88
  return { ...returnValue, imagePath, referenceImageForMovie: imagePath, imageAgentInfo, prompt, referenceImages };
87
89
  };
88
90
  export const imagePluginAgent = async (namedInputs) => {
@@ -27,17 +27,10 @@ export declare const beat_graph_data: {
27
27
  beat: import("../types/type.js").MulmoBeat;
28
28
  index: number;
29
29
  imageRefs: Record<string, string>;
30
- }) => Promise<{
31
- imagePath: string;
32
- htmlPrompt: string | undefined;
33
- htmlImageFile: string;
34
- htmlPath: string;
35
- htmlImageSystemPrompt: string;
36
- } | {
37
- imagePath: string | undefined;
38
- movieFile: string | undefined;
39
- referenceImageForMovie: string | undefined;
40
- imageParams: MulmoImageParams;
30
+ }) => Promise<({
31
+ imageParams?: MulmoImageParams;
32
+ movieFile?: string;
33
+ beatDuration?: number;
41
34
  soundEffectFile?: string;
42
35
  soundEffectPrompt?: string;
43
36
  soundEffectModel?: string;
@@ -49,26 +42,20 @@ export declare const beat_graph_data: {
49
42
  lipSyncModel?: string;
50
43
  lipSyncAgentName?: string;
51
44
  lipSyncTrimAudio?: boolean;
52
- bgmFile?: string | null;
53
45
  startAt?: number;
54
46
  duration?: number;
47
+ bgmFile?: string | null;
55
48
  audioFile?: string;
56
- beatDuration?: number;
57
49
  movieAgentInfo?: {
58
50
  agent: string;
59
51
  movieParams: import("../types/type.js").MulmoMovieParams;
60
52
  };
61
- markdown?: string;
62
- html?: string;
63
- htmlPrompt?: undefined;
64
- htmlImageFile?: undefined;
65
- htmlPath?: undefined;
66
- htmlImageSystemPrompt?: undefined;
67
- } | {
68
- imagePath: string;
69
- imageFromMovie: boolean;
70
- imageParams: MulmoImageParams;
71
- movieFile: string | undefined;
53
+ } & {
54
+ imagePath?: string;
55
+ }) | ({
56
+ imageParams?: MulmoImageParams;
57
+ movieFile?: string;
58
+ beatDuration?: number;
72
59
  soundEffectFile?: string;
73
60
  soundEffectPrompt?: string;
74
61
  soundEffectModel?: string;
@@ -80,29 +67,31 @@ export declare const beat_graph_data: {
80
67
  lipSyncModel?: string;
81
68
  lipSyncAgentName?: string;
82
69
  lipSyncTrimAudio?: boolean;
83
- bgmFile?: string | null;
84
70
  startAt?: number;
85
71
  duration?: number;
72
+ bgmFile?: string | null;
86
73
  audioFile?: string;
87
- beatDuration?: number;
88
74
  movieAgentInfo?: {
89
75
  agent: string;
90
76
  movieParams: import("../types/type.js").MulmoMovieParams;
91
77
  };
92
- markdown?: string;
93
- html?: string;
94
- htmlPrompt?: undefined;
95
- htmlImageFile?: undefined;
96
- htmlPath?: undefined;
97
- htmlImageSystemPrompt?: undefined;
98
- } | {
99
- imagePath: string;
100
- referenceImageForMovie: string;
78
+ } & {
79
+ imagePath?: string;
80
+ } & {
101
81
  imageAgentInfo: import("../types/type.js").Text2ImageAgentInfo;
102
82
  prompt: string;
103
83
  referenceImages: string[];
104
- imageParams: MulmoImageParams;
105
- movieFile: string | undefined;
84
+ referenceImageForMovie: string;
85
+ }) | {
86
+ imagePath: string;
87
+ htmlPrompt: string;
88
+ htmlPath: string;
89
+ htmlImageSystemPrompt: string;
90
+ htmlImageFile: string;
91
+ } | ({
92
+ imageParams?: MulmoImageParams;
93
+ movieFile?: string;
94
+ beatDuration?: number;
106
95
  soundEffectFile?: string;
107
96
  soundEffectPrompt?: string;
108
97
  soundEffectModel?: string;
@@ -114,22 +103,48 @@ export declare const beat_graph_data: {
114
103
  lipSyncModel?: string;
115
104
  lipSyncAgentName?: string;
116
105
  lipSyncTrimAudio?: boolean;
117
- bgmFile?: string | null;
118
106
  startAt?: number;
119
107
  duration?: number;
108
+ bgmFile?: string | null;
120
109
  audioFile?: string;
110
+ movieAgentInfo?: {
111
+ agent: string;
112
+ movieParams: import("../types/type.js").MulmoMovieParams;
113
+ };
114
+ } & {
115
+ imagePath?: string;
116
+ } & {
117
+ imageFromMovie: boolean;
118
+ }) | ({
119
+ imageParams?: MulmoImageParams;
120
+ movieFile?: string;
121
121
  beatDuration?: number;
122
+ soundEffectFile?: string;
123
+ soundEffectPrompt?: string;
124
+ soundEffectModel?: string;
125
+ soundEffectAgentInfo?: {
126
+ agentName: string;
127
+ defaultModel: string;
128
+ };
129
+ lipSyncFile?: string;
130
+ lipSyncModel?: string;
131
+ lipSyncAgentName?: string;
132
+ lipSyncTrimAudio?: boolean;
133
+ startAt?: number;
134
+ duration?: number;
135
+ bgmFile?: string | null;
136
+ audioFile?: string;
122
137
  movieAgentInfo?: {
123
138
  agent: string;
124
139
  movieParams: import("../types/type.js").MulmoMovieParams;
125
140
  };
126
- markdown?: string;
127
- html?: string;
128
- htmlPrompt?: undefined;
129
- htmlImageFile?: undefined;
130
- htmlPath?: undefined;
131
- htmlImageSystemPrompt?: undefined;
132
- }>;
141
+ } & {
142
+ imagePath?: string;
143
+ } & {
144
+ referenceImageForMovie: string;
145
+ markdown: string;
146
+ html: string;
147
+ })>;
133
148
  inputs: {
134
149
  context: string;
135
150
  beat: string;
@@ -8,3 +8,4 @@ export * from "./pdf.js";
8
8
  export * from "./translate.js";
9
9
  export * from "./markdown.js";
10
10
  export * from "./html.js";
11
+ export * from "./bundle.js";
@@ -8,3 +8,4 @@ export * from "./pdf.js";
8
8
  export * from "./translate.js";
9
9
  export * from "./markdown.js";
10
10
  export * from "./html.js";
11
+ export * from "./bundle.js";
@@ -1,9 +1,9 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import { GraphAILogger } from "graphai";
4
- import OpenAI, { toFile, AuthenticationError, RateLimitError } from "openai";
4
+ import OpenAI, { toFile, AuthenticationError, RateLimitError, APIError } from "openai";
5
5
  import { provider2ImageAgent } from "../utils/provider2agent.js";
6
- import { apiKeyMissingError, agentGenerationError, agentIncorrectAPIKeyError, agentAPIRateLimitError, agentInvalidResponseError, imageAction, imageFileTarget, } from "../utils/error_cause.js";
6
+ import { apiKeyMissingError, agentGenerationError, openAIAgentGenerationError, agentIncorrectAPIKeyError, agentAPIRateLimitError, agentInvalidResponseError, imageAction, imageFileTarget, } from "../utils/error_cause.js";
7
7
  // https://platform.openai.com/docs/guides/image-generation
8
8
  export const imageOpenaiAgent = async ({ namedInputs, params, config, }) => {
9
9
  const { prompt, referenceImages } = namedInputs;
@@ -80,6 +80,18 @@ export const imageOpenaiAgent = async ({ namedInputs, params, config, }) => {
80
80
  cause: agentAPIRateLimitError("imageOpenaiAgent", imageAction, imageFileTarget),
81
81
  });
82
82
  }
83
+ if (error instanceof APIError) {
84
+ if (error.code && error.type) {
85
+ throw new Error("Failed to generate image with OpenAI", {
86
+ cause: openAIAgentGenerationError("imageOpenaiAgent", imageAction, error.code, error.type),
87
+ });
88
+ }
89
+ if (error.type === "invalid_request_error" && error?.error?.message?.includes("Your organization must be verified")) {
90
+ throw new Error("Failed to generate image with OpenAI", {
91
+ cause: openAIAgentGenerationError("imageOpenaiAgent", imageAction, "need_verified_organization", error.type),
92
+ });
93
+ }
94
+ }
83
95
  throw new Error("Failed to generate image with OpenAI", {
84
96
  cause: agentGenerationError("imageOpenaiAgent", imageAction, imageFileTarget),
85
97
  });
package/lib/cli/bin.js CHANGED
@@ -11,6 +11,7 @@ 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
13
  import * as markdownCmd from "./commands/markdown/index.js";
14
+ import * as bundleCmd from "./commands/bundle/index.js";
14
15
  import * as htmlCmd from "./commands/html/index.js";
15
16
  import * as toolCmd from "./commands/tool/index.js";
16
17
  import { GraphAILogger } from "graphai";
@@ -36,6 +37,7 @@ export const main = async () => {
36
37
  .command(movieCmd)
37
38
  .command(pdfCmd)
38
39
  .command(markdownCmd)
40
+ .command(bundleCmd)
39
41
  .command(htmlCmd)
40
42
  .command(toolCmd)
41
43
  .demandCommand()
@@ -0,0 +1,14 @@
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
+ }>;
@@ -0,0 +1,4 @@
1
+ import { commonOptions } from "../../common.js";
2
+ export const builder = (yargs) =>
3
+ // zip
4
+ commonOptions(yargs);
@@ -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,10 @@
1
+ import { mulmoViewerBundle, audio, images } 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, true);
9
+ await audio(context).then(images).then(mulmoViewerBundle);
10
+ };
@@ -0,0 +1,4 @@
1
+ export declare const command = "bundle <file>";
2
+ export declare const desc = "Generate bundle files";
3
+ export { builder } from "./builder.js";
4
+ export { handler } from "./handler.js";
@@ -0,0 +1,4 @@
1
+ export const command = "bundle <file>";
2
+ export const desc = "Generate bundle files";
3
+ export { builder } from "./builder.js";
4
+ export { handler } from "./handler.js";
@@ -54,6 +54,7 @@ export declare const speechOptionsSchema: z.ZodObject<{
54
54
  speed?: number | undefined;
55
55
  instruction?: string | undefined;
56
56
  }>;
57
+ export declare const defaultSpeaker = "Presenter";
57
58
  export declare const text2SpeechProviderSchema: z.ZodDefault<z.ZodEnum<[string, ...string[]]>>;
58
59
  export declare const speakerDataSchema: z.ZodObject<{
59
60
  displayName: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -92,6 +93,103 @@ export declare const speakerDataSchema: z.ZodObject<{
92
93
  provider?: string | undefined;
93
94
  model?: string | undefined;
94
95
  }>;
96
+ export declare const speakerSchema: z.ZodObject<{
97
+ displayName: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
98
+ voiceId: z.ZodString;
99
+ isDefault: z.ZodOptional<z.ZodBoolean>;
100
+ speechOptions: z.ZodOptional<z.ZodObject<{
101
+ speed: z.ZodOptional<z.ZodNumber>;
102
+ instruction: z.ZodOptional<z.ZodString>;
103
+ }, "strict", z.ZodTypeAny, {
104
+ speed?: number | undefined;
105
+ instruction?: string | undefined;
106
+ }, {
107
+ speed?: number | undefined;
108
+ instruction?: string | undefined;
109
+ }>>;
110
+ provider: z.ZodOptional<z.ZodDefault<z.ZodEnum<[string, ...string[]]>>>;
111
+ model: z.ZodOptional<z.ZodString>;
112
+ } & {
113
+ lang: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
114
+ displayName: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
115
+ voiceId: z.ZodString;
116
+ isDefault: z.ZodOptional<z.ZodBoolean>;
117
+ speechOptions: z.ZodOptional<z.ZodObject<{
118
+ speed: z.ZodOptional<z.ZodNumber>;
119
+ instruction: z.ZodOptional<z.ZodString>;
120
+ }, "strict", z.ZodTypeAny, {
121
+ speed?: number | undefined;
122
+ instruction?: string | undefined;
123
+ }, {
124
+ speed?: number | undefined;
125
+ instruction?: string | undefined;
126
+ }>>;
127
+ provider: z.ZodOptional<z.ZodDefault<z.ZodEnum<[string, ...string[]]>>>;
128
+ model: z.ZodOptional<z.ZodString>;
129
+ }, "strict", z.ZodTypeAny, {
130
+ voiceId: string;
131
+ displayName?: Record<string, string> | undefined;
132
+ isDefault?: boolean | undefined;
133
+ speechOptions?: {
134
+ speed?: number | undefined;
135
+ instruction?: string | undefined;
136
+ } | undefined;
137
+ provider?: string | undefined;
138
+ model?: string | undefined;
139
+ }, {
140
+ voiceId: string;
141
+ displayName?: Record<string, string> | undefined;
142
+ isDefault?: boolean | undefined;
143
+ speechOptions?: {
144
+ speed?: number | undefined;
145
+ instruction?: string | undefined;
146
+ } | undefined;
147
+ provider?: string | undefined;
148
+ model?: string | undefined;
149
+ }>>>;
150
+ }, "strict", z.ZodTypeAny, {
151
+ voiceId: string;
152
+ lang?: Record<string, {
153
+ voiceId: string;
154
+ displayName?: Record<string, string> | undefined;
155
+ isDefault?: boolean | undefined;
156
+ speechOptions?: {
157
+ speed?: number | undefined;
158
+ instruction?: string | undefined;
159
+ } | undefined;
160
+ provider?: string | undefined;
161
+ model?: string | undefined;
162
+ }> | undefined;
163
+ displayName?: Record<string, string> | undefined;
164
+ isDefault?: boolean | undefined;
165
+ speechOptions?: {
166
+ speed?: number | undefined;
167
+ instruction?: string | undefined;
168
+ } | undefined;
169
+ provider?: string | undefined;
170
+ model?: string | undefined;
171
+ }, {
172
+ voiceId: string;
173
+ lang?: Record<string, {
174
+ voiceId: string;
175
+ displayName?: Record<string, string> | undefined;
176
+ isDefault?: boolean | undefined;
177
+ speechOptions?: {
178
+ speed?: number | undefined;
179
+ instruction?: string | undefined;
180
+ } | undefined;
181
+ provider?: string | undefined;
182
+ model?: string | undefined;
183
+ }> | undefined;
184
+ displayName?: Record<string, string> | undefined;
185
+ isDefault?: boolean | undefined;
186
+ speechOptions?: {
187
+ speed?: number | undefined;
188
+ instruction?: string | undefined;
189
+ } | undefined;
190
+ provider?: string | undefined;
191
+ model?: string | undefined;
192
+ }>;
95
193
  export declare const speakerDictionarySchema: z.ZodRecord<z.ZodString, z.ZodObject<{
96
194
  displayName: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
97
195
  voiceId: z.ZodString;
@@ -189,6 +287,151 @@ export declare const speakerDictionarySchema: z.ZodRecord<z.ZodString, z.ZodObje
189
287
  provider?: string | undefined;
190
288
  model?: string | undefined;
191
289
  }>>;
290
+ export declare const mulmoSpeechParamsSchema: z.ZodDefault<z.ZodObject<{
291
+ speakers: z.ZodRecord<z.ZodString, z.ZodObject<{
292
+ displayName: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
293
+ voiceId: z.ZodString;
294
+ isDefault: z.ZodOptional<z.ZodBoolean>;
295
+ speechOptions: z.ZodOptional<z.ZodObject<{
296
+ speed: z.ZodOptional<z.ZodNumber>;
297
+ instruction: z.ZodOptional<z.ZodString>;
298
+ }, "strict", z.ZodTypeAny, {
299
+ speed?: number | undefined;
300
+ instruction?: string | undefined;
301
+ }, {
302
+ speed?: number | undefined;
303
+ instruction?: string | undefined;
304
+ }>>;
305
+ provider: z.ZodOptional<z.ZodDefault<z.ZodEnum<[string, ...string[]]>>>;
306
+ model: z.ZodOptional<z.ZodString>;
307
+ } & {
308
+ lang: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
309
+ displayName: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
310
+ voiceId: z.ZodString;
311
+ isDefault: z.ZodOptional<z.ZodBoolean>;
312
+ speechOptions: z.ZodOptional<z.ZodObject<{
313
+ speed: z.ZodOptional<z.ZodNumber>;
314
+ instruction: z.ZodOptional<z.ZodString>;
315
+ }, "strict", z.ZodTypeAny, {
316
+ speed?: number | undefined;
317
+ instruction?: string | undefined;
318
+ }, {
319
+ speed?: number | undefined;
320
+ instruction?: string | undefined;
321
+ }>>;
322
+ provider: z.ZodOptional<z.ZodDefault<z.ZodEnum<[string, ...string[]]>>>;
323
+ model: z.ZodOptional<z.ZodString>;
324
+ }, "strict", z.ZodTypeAny, {
325
+ voiceId: string;
326
+ displayName?: Record<string, string> | undefined;
327
+ isDefault?: boolean | undefined;
328
+ speechOptions?: {
329
+ speed?: number | undefined;
330
+ instruction?: string | undefined;
331
+ } | undefined;
332
+ provider?: string | undefined;
333
+ model?: string | undefined;
334
+ }, {
335
+ voiceId: string;
336
+ displayName?: Record<string, string> | undefined;
337
+ isDefault?: boolean | undefined;
338
+ speechOptions?: {
339
+ speed?: number | undefined;
340
+ instruction?: string | undefined;
341
+ } | undefined;
342
+ provider?: string | undefined;
343
+ model?: string | undefined;
344
+ }>>>;
345
+ }, "strict", z.ZodTypeAny, {
346
+ voiceId: string;
347
+ lang?: Record<string, {
348
+ voiceId: string;
349
+ displayName?: Record<string, string> | undefined;
350
+ isDefault?: boolean | undefined;
351
+ speechOptions?: {
352
+ speed?: number | undefined;
353
+ instruction?: string | undefined;
354
+ } | undefined;
355
+ provider?: string | undefined;
356
+ model?: string | undefined;
357
+ }> | undefined;
358
+ displayName?: Record<string, string> | undefined;
359
+ isDefault?: boolean | undefined;
360
+ speechOptions?: {
361
+ speed?: number | undefined;
362
+ instruction?: string | undefined;
363
+ } | undefined;
364
+ provider?: string | undefined;
365
+ model?: string | undefined;
366
+ }, {
367
+ voiceId: string;
368
+ lang?: Record<string, {
369
+ voiceId: string;
370
+ displayName?: Record<string, string> | undefined;
371
+ isDefault?: boolean | undefined;
372
+ speechOptions?: {
373
+ speed?: number | undefined;
374
+ instruction?: string | undefined;
375
+ } | undefined;
376
+ provider?: string | undefined;
377
+ model?: string | undefined;
378
+ }> | undefined;
379
+ displayName?: Record<string, string> | undefined;
380
+ isDefault?: boolean | undefined;
381
+ speechOptions?: {
382
+ speed?: number | undefined;
383
+ instruction?: string | undefined;
384
+ } | undefined;
385
+ provider?: string | undefined;
386
+ model?: string | undefined;
387
+ }>>;
388
+ }, "strip", z.ZodTypeAny, {
389
+ speakers: Record<string, {
390
+ voiceId: string;
391
+ lang?: Record<string, {
392
+ voiceId: string;
393
+ displayName?: Record<string, string> | undefined;
394
+ isDefault?: boolean | undefined;
395
+ speechOptions?: {
396
+ speed?: number | undefined;
397
+ instruction?: string | undefined;
398
+ } | undefined;
399
+ provider?: string | undefined;
400
+ model?: string | undefined;
401
+ }> | undefined;
402
+ displayName?: Record<string, string> | undefined;
403
+ isDefault?: boolean | undefined;
404
+ speechOptions?: {
405
+ speed?: number | undefined;
406
+ instruction?: string | undefined;
407
+ } | undefined;
408
+ provider?: string | undefined;
409
+ model?: string | undefined;
410
+ }>;
411
+ }, {
412
+ speakers: Record<string, {
413
+ voiceId: string;
414
+ lang?: Record<string, {
415
+ voiceId: string;
416
+ displayName?: Record<string, string> | undefined;
417
+ isDefault?: boolean | undefined;
418
+ speechOptions?: {
419
+ speed?: number | undefined;
420
+ instruction?: string | undefined;
421
+ } | undefined;
422
+ provider?: string | undefined;
423
+ model?: string | undefined;
424
+ }> | undefined;
425
+ displayName?: Record<string, string> | undefined;
426
+ isDefault?: boolean | undefined;
427
+ speechOptions?: {
428
+ speed?: number | undefined;
429
+ instruction?: string | undefined;
430
+ } | undefined;
431
+ provider?: string | undefined;
432
+ model?: string | undefined;
433
+ }>;
434
+ }>>;
192
435
  export declare const mediaSourceSchema: z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
193
436
  kind: z.ZodLiteral<"url">;
194
437
  url: z.ZodString;
@@ -2410,7 +2653,6 @@ export declare const mulmoMovieParamsSchema: z.ZodObject<{
2410
2653
  duration?: number | undefined;
2411
2654
  } | undefined;
2412
2655
  }>;
2413
- export declare const defaultSpeaker = "Presenter";
2414
2656
  export declare const mulmoPresentationStyleSchema: z.ZodObject<{
2415
2657
  $mulmocast: z.ZodObject<{
2416
2658
  version: z.ZodLiteral<"1.1">;
@@ -23,6 +23,7 @@ export const speechOptionsSchema = z
23
23
  })
24
24
  .strict();
25
25
  const speakerIdSchema = z.string();
26
+ export const defaultSpeaker = "Presenter";
26
27
  export const text2SpeechProviderSchema = z.enum(Object.keys(provider2TTSAgent)).default(defaultProviders.tts);
27
28
  export const speakerDataSchema = z
28
29
  .object({
@@ -34,9 +35,25 @@ export const speakerDataSchema = z
34
35
  model: z.string().optional().describe("TTS model to use for this speaker"),
35
36
  })
36
37
  .strict();
37
- export const speakerDictionarySchema = z.record(speakerIdSchema, speakerDataSchema.extend({
38
+ export const speakerSchema = speakerDataSchema.extend({
38
39
  lang: z.record(langSchema, speakerDataSchema).optional(),
39
- }));
40
+ });
41
+ export const speakerDictionarySchema = z.record(speakerIdSchema, speakerSchema);
42
+ export const mulmoSpeechParamsSchema = z
43
+ .object({
44
+ speakers: speakerDictionarySchema,
45
+ })
46
+ .default({
47
+ speakers: {
48
+ [defaultSpeaker]: {
49
+ provider: defaultProviders.tts,
50
+ voiceId: "shimmer",
51
+ displayName: {
52
+ en: defaultSpeaker,
53
+ },
54
+ },
55
+ },
56
+ });
40
57
  export const mediaSourceSchema = z.discriminatedUnion("kind", [
41
58
  z.object({ kind: z.literal("url"), url: URLStringSchema }).strict(), // https://example.com/foo.pdf
42
59
  z.object({ kind: z.literal("base64"), data: z.string().min(1) }).strict(), // base64
@@ -335,25 +352,10 @@ export const mulmoMovieParamsSchema = z
335
352
  fillOption: mulmoFillOptionSchema.optional(), // for movie.ts
336
353
  })
337
354
  .strict();
338
- export const defaultSpeaker = "Presenter";
339
355
  export const mulmoPresentationStyleSchema = z.object({
340
356
  $mulmocast: mulmoCastCreditSchema,
341
357
  canvasSize: mulmoCanvasDimensionSchema, // has default value
342
- speechParams: z
343
- .object({
344
- speakers: speakerDictionarySchema,
345
- })
346
- .default({
347
- speakers: {
348
- [defaultSpeaker]: {
349
- provider: defaultProviders.tts,
350
- voiceId: "shimmer",
351
- displayName: {
352
- en: defaultSpeaker,
353
- },
354
- },
355
- },
356
- }),
358
+ speechParams: mulmoSpeechParamsSchema,
357
359
  imageParams: mulmoImageParamsSchema.optional().default({
358
360
  provider: defaultProviders.text2image,
359
361
  images: {},
@@ -1,10 +1,12 @@
1
1
  import { type CallbackFunction } from "graphai";
2
- import { langSchema, localizedTextSchema, mulmoBeatSchema, mulmoScriptSchema, mulmoStudioSchema, mulmoStudioBeatSchema, mulmoStoryboardSchema, mulmoStoryboardSceneSchema, mulmoStudioMultiLingualSchema, mulmoStudioMultiLingualArraySchema, mulmoStudioMultiLingualDataSchema, mulmoStudioMultiLingualFileSchema, speakerDictionarySchema, mulmoImageParamsSchema, mulmoImageParamsImagesValueSchema, mulmoImageParamsImagesSchema, mulmoFillOptionSchema, mulmoMovieParamsSchema, textSlideParamsSchema, speechOptionsSchema, speakerDataSchema, mulmoCanvasDimensionSchema, mulmoPromptTemplateSchema, mulmoPromptTemplateFileSchema, text2ImageProviderSchema, text2HtmlImageProviderSchema, text2MovieProviderSchema, text2SpeechProviderSchema, mulmoPresentationStyleSchema, multiLingualTextsSchema, mulmoImageAssetSchema, mulmoMermaidMediaSchema, mulmoTextSlideMediaSchema, mulmoMarkdownMediaSchema, mulmoImageMediaSchema, mulmoChartMediaSchema, mediaSourceSchema, mediaSourceMermaidSchema, mulmoSessionStateSchema, mulmoOpenAIImageModelSchema, mulmoGoogleImageModelSchema, mulmoGoogleMovieModelSchema, mulmoReplicateMovieModelSchema, mulmoImagePromptMediaSchema } from "./schema.js";
2
+ import { langSchema, localizedTextSchema, mulmoBeatSchema, mulmoScriptSchema, mulmoStudioSchema, mulmoStudioBeatSchema, mulmoStoryboardSchema, mulmoStoryboardSceneSchema, mulmoStudioMultiLingualSchema, mulmoStudioMultiLingualArraySchema, mulmoStudioMultiLingualDataSchema, mulmoStudioMultiLingualFileSchema, speakerDictionarySchema, speakerSchema, mulmoSpeechParamsSchema, mulmoImageParamsSchema, mulmoImageParamsImagesValueSchema, mulmoImageParamsImagesSchema, mulmoFillOptionSchema, mulmoMovieParamsSchema, textSlideParamsSchema, speechOptionsSchema, speakerDataSchema, mulmoCanvasDimensionSchema, mulmoPromptTemplateSchema, mulmoPromptTemplateFileSchema, text2ImageProviderSchema, text2HtmlImageProviderSchema, text2MovieProviderSchema, text2SpeechProviderSchema, mulmoPresentationStyleSchema, multiLingualTextsSchema, mulmoImageAssetSchema, mulmoMermaidMediaSchema, mulmoTextSlideMediaSchema, mulmoMarkdownMediaSchema, mulmoImageMediaSchema, mulmoChartMediaSchema, mediaSourceSchema, mediaSourceMermaidSchema, mulmoSessionStateSchema, mulmoOpenAIImageModelSchema, mulmoGoogleImageModelSchema, mulmoGoogleMovieModelSchema, mulmoReplicateMovieModelSchema, mulmoImagePromptMediaSchema } from "./schema.js";
3
3
  import { pdf_modes, pdf_sizes, storyToScriptGenerateMode } from "../utils/const.js";
4
4
  import type { LLM } from "../utils/provider2agent.js";
5
5
  import { z } from "zod";
6
6
  export type LANG = z.infer<typeof langSchema>;
7
7
  export type MulmoBeat = z.infer<typeof mulmoBeatSchema>;
8
+ export type MulmoSpeechParams = z.infer<typeof mulmoSpeechParamsSchema>;
9
+ export type Speaker = z.infer<typeof speakerSchema>;
8
10
  export type SpeakerDictonary = z.infer<typeof speakerDictionarySchema>;
9
11
  export type SpeechOptions = z.infer<typeof speechOptionsSchema>;
10
12
  export type SpeakerData = z.infer<typeof speakerDataSchema>;
@@ -159,6 +159,14 @@ export declare const agentGenerationError: (agentName: string, action: string, t
159
159
  target: string;
160
160
  agentName: string;
161
161
  };
162
+ export declare const openAIAgentGenerationError: (agentName: string, action: string, errorCode: string, errorType: string, beatIndex?: number) => {
163
+ beatIndex?: number | undefined;
164
+ type: string;
165
+ action: string;
166
+ agentName: string;
167
+ errorCode: string;
168
+ errorType: string;
169
+ };
162
170
  export declare const agentIncorrectAPIKeyError: (agentName: string, action: string, target: string, beatIndex?: number) => {
163
171
  beatIndex?: number | undefined;
164
172
  type: string;
@@ -173,6 +173,17 @@ export const agentGenerationError = (agentName, action, target, beatIndex) => {
173
173
  ...(beatIndex !== undefined && { beatIndex }),
174
174
  };
175
175
  };
176
+ // OpenAI Agent API/Generation Errors
177
+ export const openAIAgentGenerationError = (agentName, action, errorCode, errorType, beatIndex) => {
178
+ return {
179
+ type: apiErrorType,
180
+ action,
181
+ agentName,
182
+ errorCode,
183
+ errorType,
184
+ ...(beatIndex !== undefined && { beatIndex }),
185
+ };
186
+ };
176
187
  // Agent API/Incorrect Key Errors
177
188
  export const agentIncorrectAPIKeyError = (agentName, action, target, beatIndex) => {
178
189
  return {
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Promise-based ZIP archive builder
3
+ *
4
+ * @example
5
+ * const zipper = new ZipBuilder("output.zip");
6
+ * zipper.addFile("file1.txt", "renamed.txt");
7
+ * zipper.addFile("file2.txt");
8
+ * await zipper.finalize();
9
+ */
10
+ export declare class ZipBuilder {
11
+ private archive;
12
+ private output;
13
+ private outputPath;
14
+ private finalized;
15
+ constructor(outputPath: string);
16
+ /**
17
+ * Add a file to the archive
18
+ * @param filePath - Path to the file to add
19
+ * @param nameInZip - Optional name for the file inside the ZIP (defaults to basename)
20
+ */
21
+ addFile(filePath: string, nameInZip?: string): void;
22
+ /**
23
+ * Add multiple files to the archive
24
+ * @param files - Array of file paths or objects with path and name
25
+ */
26
+ addFiles(files: Array<string | {
27
+ path: string;
28
+ name?: string;
29
+ }>): void;
30
+ /**
31
+ * Add a directory to the archive
32
+ * @param dirPath - Path to the directory to add
33
+ * @param destPath - Optional destination path inside the ZIP
34
+ */
35
+ addDirectory(dirPath: string, destPath?: string): void;
36
+ /**
37
+ * Add content from a string or buffer
38
+ * @param content - String or Buffer content
39
+ * @param nameInZip - Name for the file inside the ZIP
40
+ */
41
+ addContent(content: string | Buffer, nameInZip: string): void;
42
+ /**
43
+ * Finalize the archive and return a promise that resolves when complete
44
+ * @returns Promise that resolves with the output file path
45
+ */
46
+ finalize(): Promise<string>;
47
+ /**
48
+ * Get the output file path
49
+ */
50
+ getOutputPath(): string;
51
+ }
@@ -0,0 +1,119 @@
1
+ import fs from "fs";
2
+ import archiver from "archiver";
3
+ import path from "path";
4
+ /**
5
+ * Promise-based ZIP archive builder
6
+ *
7
+ * @example
8
+ * const zipper = new ZipBuilder("output.zip");
9
+ * zipper.addFile("file1.txt", "renamed.txt");
10
+ * zipper.addFile("file2.txt");
11
+ * await zipper.finalize();
12
+ */
13
+ export class ZipBuilder {
14
+ archive;
15
+ output;
16
+ outputPath;
17
+ finalized = false;
18
+ constructor(outputPath) {
19
+ this.outputPath = outputPath;
20
+ this.output = fs.createWriteStream(outputPath);
21
+ this.archive = archiver("zip", {
22
+ zlib: { level: 9 }, // Maximum compression level
23
+ });
24
+ // Pipe archive data to the file
25
+ this.archive.pipe(this.output);
26
+ // Error handling
27
+ this.archive.on("error", (err) => {
28
+ throw err;
29
+ });
30
+ this.archive.on("warning", (err) => {
31
+ if (err.code !== "ENOENT") {
32
+ throw err;
33
+ }
34
+ // console.warn("ZIP warning:", err);
35
+ });
36
+ }
37
+ /**
38
+ * Add a file to the archive
39
+ * @param filePath - Path to the file to add
40
+ * @param nameInZip - Optional name for the file inside the ZIP (defaults to basename)
41
+ */
42
+ addFile(filePath, nameInZip) {
43
+ if (this.finalized) {
44
+ throw new Error("Cannot add files after finalize() has been called");
45
+ }
46
+ if (!fs.existsSync(filePath)) {
47
+ throw new Error(`File not found: ${filePath}`);
48
+ }
49
+ const name = nameInZip ?? path.basename(filePath);
50
+ this.archive.file(filePath, { name });
51
+ }
52
+ /**
53
+ * Add multiple files to the archive
54
+ * @param files - Array of file paths or objects with path and name
55
+ */
56
+ addFiles(files) {
57
+ files.forEach((file) => {
58
+ if (typeof file === "string") {
59
+ this.addFile(file);
60
+ }
61
+ else {
62
+ this.addFile(file.path, file.name);
63
+ }
64
+ });
65
+ }
66
+ /**
67
+ * Add a directory to the archive
68
+ * @param dirPath - Path to the directory to add
69
+ * @param destPath - Optional destination path inside the ZIP
70
+ */
71
+ addDirectory(dirPath, destPath) {
72
+ if (this.finalized) {
73
+ throw new Error("Cannot add directory after finalize() has been called");
74
+ }
75
+ if (!fs.existsSync(dirPath)) {
76
+ throw new Error(`Directory not found: ${dirPath}`);
77
+ }
78
+ const dest = destPath ?? path.basename(dirPath);
79
+ this.archive.directory(dirPath, dest);
80
+ }
81
+ /**
82
+ * Add content from a string or buffer
83
+ * @param content - String or Buffer content
84
+ * @param nameInZip - Name for the file inside the ZIP
85
+ */
86
+ addContent(content, nameInZip) {
87
+ if (this.finalized) {
88
+ throw new Error("Cannot add content after finalize() has been called");
89
+ }
90
+ this.archive.append(content, { name: nameInZip });
91
+ }
92
+ /**
93
+ * Finalize the archive and return a promise that resolves when complete
94
+ * @returns Promise that resolves with the output file path
95
+ */
96
+ async finalize() {
97
+ if (this.finalized) {
98
+ throw new Error("Archive has already been finalized");
99
+ }
100
+ this.finalized = true;
101
+ return new Promise((resolve, reject) => {
102
+ this.output.on("close", () => {
103
+ // const bytes = this.archive.pointer();
104
+ // console.log(`ZIP archive created: ${this.outputPath} (${bytes} bytes)`);
105
+ resolve(this.outputPath);
106
+ });
107
+ this.output.on("error", reject);
108
+ this.archive.on("error", reject);
109
+ // Finalize the archive
110
+ this.archive.finalize();
111
+ });
112
+ }
113
+ /**
114
+ * Get the output file path
115
+ */
116
+ getOutputPath() {
117
+ return this.outputPath;
118
+ }
119
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mulmocast",
3
- "version": "1.2.62",
3
+ "version": "1.2.64",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "lib/index.node.js",
@@ -71,8 +71,8 @@
71
71
  },
72
72
  "homepage": "https://github.com/receptron/mulmocast-cli#readme",
73
73
  "dependencies": {
74
- "@google-cloud/text-to-speech": "^6.3.0",
75
- "@google/genai": "^1.22.0",
74
+ "@google-cloud/text-to-speech": "^6.3.1",
75
+ "@google/genai": "^1.25.0",
76
76
  "@graphai/anthropic_agent": "^2.0.11",
77
77
  "@graphai/browserless_agent": "^2.0.1",
78
78
  "@graphai/gemini_agent": "^2.0.1",
@@ -82,21 +82,22 @@
82
82
  "@graphai/stream_agent_filter": "^2.0.2",
83
83
  "@graphai/vanilla": "^2.0.12",
84
84
  "@graphai/vanilla_node_agents": "^2.0.4",
85
- "@inquirer/input": "^4.2.4",
86
- "@inquirer/select": "^4.3.4",
87
- "@modelcontextprotocol/sdk": "^1.19.1",
85
+ "@inquirer/input": "^4.2.5",
86
+ "@inquirer/select": "^4.4.0",
87
+ "@modelcontextprotocol/sdk": "^1.20.0",
88
88
  "@mozilla/readability": "^0.6.0",
89
89
  "@tavily/core": "^0.5.11",
90
+ "archiver": "^7.0.1",
90
91
  "clipboardy": "^4.0.0",
91
92
  "dotenv": "^17.2.3",
92
93
  "fluent-ffmpeg": "^2.1.3",
93
94
  "graphai": "^2.0.16",
94
95
  "jsdom": "^27.0.0",
95
- "marked": "^16.3.0",
96
+ "marked": "^16.4.0",
96
97
  "mulmocast-vision": "^1.0.4",
97
98
  "ora": "^9.0.0",
98
- "puppeteer": "^24.23.0",
99
- "replicate": "^1.2.0",
99
+ "puppeteer": "^24.24.1",
100
+ "replicate": "^1.3.0",
100
101
  "yaml": "^2.8.1",
101
102
  "yargs": "^18.0.0",
102
103
  "zod": "^3.25.76",
@@ -104,6 +105,7 @@
104
105
  },
105
106
  "devDependencies": {
106
107
  "@receptron/test_utils": "^2.0.3",
108
+ "@types/archiver": "^6.0.3",
107
109
  "@types/fluent-ffmpeg": "^2.1.26",
108
110
  "@types/jsdom": "^27.0.0",
109
111
  "@types/yargs": "^17.0.33",
@@ -114,7 +116,7 @@
114
116
  "prettier": "^3.6.2",
115
117
  "tsx": "^4.20.6",
116
118
  "typescript": "^5.9.3",
117
- "typescript-eslint": "^8.46.0"
119
+ "typescript-eslint": "^8.46.1"
118
120
  },
119
121
  "engines": {
120
122
  "node": ">=20.0.0"