mulmocast 1.2.63 → 1.2.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/actions/audio.d.ts +0 -1
- package/lib/actions/audio.js +0 -4
- package/lib/actions/bundle.d.ts +2 -0
- package/lib/actions/bundle.js +79 -0
- package/lib/actions/image_agents.d.ts +36 -88
- package/lib/actions/image_agents.js +11 -7
- package/lib/actions/images.d.ts +60 -45
- package/lib/actions/index.d.ts +1 -0
- package/lib/actions/index.js +1 -0
- package/lib/actions/pdf.js +6 -6
- package/lib/agents/image_openai_agent.js +14 -2
- package/lib/cli/bin.js +2 -0
- package/lib/cli/commands/bundle/builder.d.ts +14 -0
- package/lib/cli/commands/bundle/builder.js +4 -0
- package/lib/cli/commands/bundle/handler.d.ts +4 -0
- package/lib/cli/commands/bundle/handler.js +14 -0
- package/lib/cli/commands/bundle/index.d.ts +4 -0
- package/lib/cli/commands/bundle/index.js +4 -0
- package/lib/utils/const.d.ts +1 -0
- package/lib/utils/const.js +1 -0
- package/lib/utils/error_cause.d.ts +8 -0
- package/lib/utils/error_cause.js +11 -0
- package/lib/utils/zip.d.ts +51 -0
- package/lib/utils/zip.js +119 -0
- package/package.json +13 -11
package/lib/actions/audio.d.ts
CHANGED
|
@@ -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)[];
|
package/lib/actions/audio.js
CHANGED
|
@@ -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,79 @@
|
|
|
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
|
+
import { bundleTargetLang } from "../utils/const.js";
|
|
9
|
+
const beatImage = (context) => {
|
|
10
|
+
return async (beat, index) => {
|
|
11
|
+
try {
|
|
12
|
+
const res = await imagePreprocessAgent({ context, beat, index, imageRefs: {} });
|
|
13
|
+
if ("htmlPrompt" in res) {
|
|
14
|
+
return { htmlImageSource: res.htmlImageFile, imageSource: res.imagePath };
|
|
15
|
+
}
|
|
16
|
+
const { imagePath, movieFile, lipSyncFile } = res;
|
|
17
|
+
return { imageSource: imagePath, videoSource: movieFile, videoWithAudioSource: lipSyncFile };
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
GraphAILogger.log(e);
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
// TODO reference
|
|
26
|
+
const viewJsonFileName = "mulmo_view.json";
|
|
27
|
+
const zipFileName = "mulmo.zip";
|
|
28
|
+
export const mulmoViewerBundle = async (context) => {
|
|
29
|
+
const isZip = true;
|
|
30
|
+
const dir = path.resolve(context.fileDirs.fileName);
|
|
31
|
+
mkdir(dir);
|
|
32
|
+
const zipper = new ZipBuilder(path.resolve(dir, zipFileName));
|
|
33
|
+
const resultJson = [];
|
|
34
|
+
context.studio.script.beats.forEach((beat) => {
|
|
35
|
+
resultJson.push({ text: beat.text, duration: beat.duration, audioSources: {}, multiLinguals: {} });
|
|
36
|
+
});
|
|
37
|
+
for (const lang of bundleTargetLang) {
|
|
38
|
+
const audios = listLocalizedAudioPaths({ ...context, lang });
|
|
39
|
+
audios.forEach((audio, index) => {
|
|
40
|
+
if (audio) {
|
|
41
|
+
const fileName = path.basename(audio ?? "");
|
|
42
|
+
if (resultJson[index] && resultJson[index].audioSources) {
|
|
43
|
+
resultJson[index].audioSources[lang] = fileName;
|
|
44
|
+
}
|
|
45
|
+
if (fs.existsSync(audio)) {
|
|
46
|
+
fs.copyFileSync(audio, path.resolve(dir, fileName));
|
|
47
|
+
zipper.addFile(audio, fileName);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const images = await Promise.all(context.studio.script.beats.map(beatImage(context)));
|
|
53
|
+
images.forEach((image, index) => {
|
|
54
|
+
const data = resultJson[index];
|
|
55
|
+
const keys = ["htmlImageSource", "imageSource", "videoSource", "videoWithAudioSource"];
|
|
56
|
+
keys.forEach((key) => {
|
|
57
|
+
const value = image[key];
|
|
58
|
+
if (value) {
|
|
59
|
+
data[key] = path.basename(value);
|
|
60
|
+
if (fs.existsSync(value)) {
|
|
61
|
+
fs.copyFileSync(value, path.resolve(dir, path.basename(value)));
|
|
62
|
+
zipper.addFile(value);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
context.multiLingual.forEach((beat, index) => {
|
|
68
|
+
bundleTargetLang.forEach((lang) => {
|
|
69
|
+
if (resultJson[index] && resultJson[index].multiLinguals) {
|
|
70
|
+
resultJson[index].multiLinguals[lang] = beat.multiLingualTexts[lang].text;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
fs.writeFileSync(path.resolve(dir, viewJsonFileName), JSON.stringify({ beats: resultJson, bgmSource: context.studio?.script.audioParams?.bgm }, null, 2));
|
|
75
|
+
zipper.addFile(path.resolve(dir, viewJsonFileName));
|
|
76
|
+
if (isZip) {
|
|
77
|
+
await zipper.finalize();
|
|
78
|
+
}
|
|
79
|
+
};
|
|
@@ -1,51 +1,8 @@
|
|
|
1
|
-
import { MulmoStudioContext, MulmoBeat, MulmoCanvasDimension, MulmoImageParams, MulmoMovieParams } from "../types/index.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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,30 @@ 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
|
-
|
|
66
|
-
|
|
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
|
-
imagePath: isTypeMovie ? undefined : pluginPath,
|
|
73
|
+
// imagePath: isTypeMovie ? undefined : pluginPath,
|
|
74
|
+
imagePath: isTypeMovie ? imagePath : pluginPath,
|
|
76
75
|
movieFile: isTypeMovie ? pluginPath : undefined,
|
|
76
|
+
imageFromMovie: isTypeMovie,
|
|
77
77
|
referenceImageForMovie: pluginPath,
|
|
78
|
+
markdown,
|
|
79
|
+
html,
|
|
78
80
|
};
|
|
79
81
|
}
|
|
80
82
|
if (beat.moviePrompt && !beat.imagePrompt) {
|
|
83
|
+
// ImageOnlyMoviePreprocessAgentResponse
|
|
81
84
|
return { ...returnValue, imagePath, imageFromMovie: true }; // no image prompt, only movie prompt
|
|
82
85
|
}
|
|
83
86
|
// referenceImages for "edit_image", openai agent.
|
|
84
87
|
const referenceImages = MulmoBeatMethods.getImageReferenceForImageGenerator(beat, imageRefs);
|
|
85
88
|
const prompt = imagePrompt(beat, imageAgentInfo.imageParams.style);
|
|
89
|
+
// ImageGenearalPreprocessAgentResponse
|
|
86
90
|
return { ...returnValue, imagePath, referenceImageForMovie: imagePath, imageAgentInfo, prompt, referenceImages };
|
|
87
91
|
};
|
|
88
92
|
export const imagePluginAgent = async (namedInputs) => {
|
package/lib/actions/images.d.ts
CHANGED
|
@@ -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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
105
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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;
|
package/lib/actions/index.d.ts
CHANGED
package/lib/actions/index.js
CHANGED
package/lib/actions/pdf.js
CHANGED
|
@@ -4,14 +4,14 @@ import puppeteer from "puppeteer";
|
|
|
4
4
|
import { GraphAILogger, sleep } from "graphai";
|
|
5
5
|
import { MulmoPresentationStyleMethods } from "../methods/index.js";
|
|
6
6
|
import { localizedText, isHttp } from "../utils/utils.js";
|
|
7
|
-
import { getOutputPdfFilePath, writingMessage, getHTMLFile } from "../utils/file.js";
|
|
7
|
+
import { getOutputPdfFilePath, writingMessage, getHTMLFile, mulmoCreditPath } from "../utils/file.js";
|
|
8
8
|
import { interpolate } from "../utils/markdown.js";
|
|
9
9
|
import { MulmoStudioContextMethods } from "../methods/mulmo_studio_context.js";
|
|
10
10
|
const isCI = process.env.CI === "true";
|
|
11
11
|
const getPdfSize = (pdfSize) => {
|
|
12
12
|
return pdfSize === "a4" ? "A4" : "Letter";
|
|
13
13
|
};
|
|
14
|
-
const loadImage = async (imagePath) => {
|
|
14
|
+
const loadImage = async (imagePath, index) => {
|
|
15
15
|
try {
|
|
16
16
|
const imageData = isHttp(imagePath) ? Buffer.from(await (await fetch(imagePath)).arrayBuffer()) : fs.readFileSync(imagePath);
|
|
17
17
|
const ext = path.extname(imagePath).toLowerCase().replace(".", "");
|
|
@@ -19,8 +19,8 @@ const loadImage = async (imagePath) => {
|
|
|
19
19
|
return `data:image/${mimeType};base64,${imageData.toString("base64")}`;
|
|
20
20
|
}
|
|
21
21
|
catch (error) {
|
|
22
|
-
GraphAILogger.info(
|
|
23
|
-
const placeholderData = fs.readFileSync(
|
|
22
|
+
GraphAILogger.info(`loadImage failed: file: ${imagePath} index: ${index}`, error);
|
|
23
|
+
const placeholderData = fs.readFileSync(mulmoCreditPath());
|
|
24
24
|
return `data:image/png;base64,${placeholderData.toString("base64")}`;
|
|
25
25
|
}
|
|
26
26
|
};
|
|
@@ -100,9 +100,9 @@ const generatePDFHTML = async (context, pdfMode, pdfSize) => {
|
|
|
100
100
|
const { studio, multiLingual, lang = "en" } = context;
|
|
101
101
|
const { width: imageWidth, height: imageHeight } = MulmoPresentationStyleMethods.getCanvasSize(context.presentationStyle);
|
|
102
102
|
const isLandscapeImage = imageWidth > imageHeight;
|
|
103
|
-
const
|
|
103
|
+
const imageFiles = studio.beats.map((beat) => beat.htmlImageFile ?? beat.imageFile);
|
|
104
104
|
const texts = studio.script.beats.map((beat, index) => localizedText(beat, multiLingual?.[index], lang));
|
|
105
|
-
const imageDataUrls = await Promise.all(
|
|
105
|
+
const imageDataUrls = await Promise.all(imageFiles.map(loadImage));
|
|
106
106
|
const defaultPageSize = `${getPdfSize(pdfSize)} ${isLandscapeImage ? "landscape" : "portrait"}`;
|
|
107
107
|
const pageSize = pdfMode === "handout" ? `${getPdfSize(pdfSize)} portrait` : defaultPageSize;
|
|
108
108
|
const pagesHTML = generatePagesHTML(pdfMode, imageDataUrls, texts);
|
|
@@ -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,14 @@
|
|
|
1
|
+
import { mulmoViewerBundle, audio, images, translate } from "../../../actions/index.js";
|
|
2
|
+
import { initializeContext } from "../../helpers.js";
|
|
3
|
+
import { bundleTargetLang } from "../../../utils/const.js";
|
|
4
|
+
export const handler = async (argv) => {
|
|
5
|
+
const context = await initializeContext(argv);
|
|
6
|
+
if (!context) {
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
await translate(context, { targetLangs: bundleTargetLang });
|
|
10
|
+
for (const lang of bundleTargetLang.filter((_lang) => _lang !== context.lang)) {
|
|
11
|
+
await audio({ ...context, lang });
|
|
12
|
+
}
|
|
13
|
+
await audio(context).then(images).then(mulmoViewerBundle);
|
|
14
|
+
};
|
package/lib/utils/const.d.ts
CHANGED
package/lib/utils/const.js
CHANGED
|
@@ -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;
|
package/lib/utils/error_cause.js
CHANGED
|
@@ -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
|
+
}
|
package/lib/utils/zip.js
ADDED
|
@@ -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.
|
|
3
|
+
"version": "1.2.65",
|
|
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.
|
|
75
|
-
"@google/genai": "^1.
|
|
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.
|
|
86
|
-
"@inquirer/select": "^4.
|
|
87
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
85
|
+
"@inquirer/input": "^4.2.5",
|
|
86
|
+
"@inquirer/select": "^4.4.0",
|
|
87
|
+
"@modelcontextprotocol/sdk": "^1.20.1",
|
|
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.
|
|
96
|
+
"marked": "^16.4.1",
|
|
96
97
|
"mulmocast-vision": "^1.0.4",
|
|
97
98
|
"ora": "^9.0.0",
|
|
98
|
-
"puppeteer": "^24.
|
|
99
|
-
"replicate": "^1.
|
|
99
|
+
"puppeteer": "^24.25.0",
|
|
100
|
+
"replicate": "^1.3.0",
|
|
100
101
|
"yaml": "^2.8.1",
|
|
101
102
|
"yargs": "^18.0.0",
|
|
102
103
|
"zod": "^3.25.76",
|
|
@@ -104,17 +105,18 @@
|
|
|
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",
|
|
110
|
-
"eslint": "^9.
|
|
112
|
+
"eslint": "^9.38.0",
|
|
111
113
|
"eslint-config-prettier": "^10.1.8",
|
|
112
114
|
"eslint-plugin-prettier": "^5.5.4",
|
|
113
115
|
"eslint-plugin-sonarjs": "^3.0.5",
|
|
114
116
|
"prettier": "^3.6.2",
|
|
115
117
|
"tsx": "^4.20.6",
|
|
116
118
|
"typescript": "^5.9.3",
|
|
117
|
-
"typescript-eslint": "^8.46.
|
|
119
|
+
"typescript-eslint": "^8.46.1"
|
|
118
120
|
},
|
|
119
121
|
"engines": {
|
|
120
122
|
"node": ">=20.0.0"
|