mulmocast 0.0.2 → 0.0.4
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/README.md +27 -9
- package/assets/font/NotoSansJP-Regular.ttf +0 -0
- package/assets/html/chart.html +1 -10
- package/assets/html/mermaid.html +1 -13
- package/assets/templates/business.json +16 -27
- package/assets/templates/coding.json +58 -21
- package/lib/actions/audio.d.ts +1 -1
- package/lib/actions/audio.js +43 -27
- package/lib/actions/images.js +20 -26
- package/lib/actions/index.d.ts +5 -0
- package/lib/actions/index.js +5 -0
- package/lib/actions/movie.d.ts +9 -1
- package/lib/actions/movie.js +97 -38
- package/lib/actions/pdf.d.ts +2 -0
- package/lib/actions/pdf.js +211 -0
- package/lib/actions/translate.js +22 -9
- package/lib/agents/combine_audio_files_agent.js +13 -22
- package/lib/cli/args.d.ts +3 -1
- package/lib/cli/args.js +49 -34
- package/lib/cli/cli.d.ts +15 -0
- package/lib/cli/cli.js +44 -47
- package/lib/cli/run.d.ts +1 -0
- package/lib/cli/run.js +2 -0
- package/lib/cli/tool-args.d.ts +2 -0
- package/lib/cli/tool-args.js +12 -2
- package/lib/cli/tool-cli.js +6 -4
- package/lib/methods/index.d.ts +1 -0
- package/lib/methods/index.js +1 -0
- package/lib/methods/mulmo_media_source.d.ts +4 -0
- package/lib/methods/mulmo_media_source.js +21 -0
- package/lib/methods/mulmo_script.d.ts +2 -6
- package/lib/methods/mulmo_script.js +12 -5
- package/lib/tools/create_mulmo_script_interactively.d.ts +1 -1
- package/lib/tools/create_mulmo_script_interactively.js +61 -20
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.js +1 -0
- package/lib/types/schema.d.ts +3626 -3162
- package/lib/types/schema.js +75 -41
- package/lib/types/type.d.ts +28 -1
- package/lib/utils/const.d.ts +2 -0
- package/lib/utils/const.js +2 -0
- package/lib/utils/file.d.ts +4 -1
- package/lib/utils/file.js +15 -1
- package/lib/utils/filters.js +1 -1
- package/lib/utils/image_plugins/chart.d.ts +3 -0
- package/lib/utils/image_plugins/chart.js +18 -0
- package/lib/utils/image_plugins/image.d.ts +2 -0
- package/lib/utils/image_plugins/image.js +3 -0
- package/lib/utils/image_plugins/index.d.ts +7 -0
- package/lib/utils/image_plugins/index.js +7 -0
- package/lib/utils/image_plugins/markdown.d.ts +3 -0
- package/lib/utils/image_plugins/markdown.js +11 -0
- package/lib/utils/image_plugins/mermaid.d.ts +3 -0
- package/lib/utils/image_plugins/mermaid.js +21 -0
- package/lib/utils/image_plugins/movie.d.ts +2 -0
- package/lib/utils/image_plugins/movie.js +3 -0
- package/lib/utils/image_plugins/source.d.ts +4 -0
- package/lib/utils/image_plugins/source.js +15 -0
- package/lib/utils/image_plugins/text_slide.d.ts +3 -0
- package/lib/utils/image_plugins/text_slide.js +12 -0
- package/lib/utils/image_plugins/type_guards.d.ts +6 -0
- package/lib/utils/image_plugins/type_guards.js +21 -0
- package/lib/utils/markdown.js +4 -1
- package/lib/utils/pdf.d.ts +8 -0
- package/lib/utils/pdf.js +75 -0
- package/lib/utils/preprocess.d.ts +58 -128
- package/lib/utils/preprocess.js +37 -37
- package/lib/utils/utils.d.ts +12 -0
- package/lib/utils/utils.js +34 -0
- package/package.json +21 -12
- package/lib/tools/seed.d.ts +0 -3
- package/lib/tools/seed.js +0 -201
- package/lib/tools/seed_from_url.d.ts +0 -3
- package/lib/tools/seed_from_url.js +0 -178
- package/lib/tools/seed_from_url2.d.ts +0 -3
- package/lib/tools/seed_from_url2.js +0 -154
- package/lib/utils/image_preprocess.d.ts +0 -14
- package/lib/utils/image_preprocess.js +0 -52
- package/lib/utils/text_hash.d.ts +0 -1
- package/lib/utils/text_hash.js +0 -4
package/lib/types/schema.js
CHANGED
|
@@ -22,56 +22,57 @@ export const speechOptionsSchema = z
|
|
|
22
22
|
const speakerIdSchema = z.string();
|
|
23
23
|
const speakerDataSchema = z
|
|
24
24
|
.object({
|
|
25
|
-
displayName: z.record(langSchema, z.string()),
|
|
25
|
+
displayName: z.record(langSchema, z.string()).optional(),
|
|
26
26
|
voiceId: z.string(),
|
|
27
27
|
speechOptions: speechOptionsSchema.optional(),
|
|
28
28
|
})
|
|
29
29
|
.strict();
|
|
30
30
|
export const speakerDictionarySchema = z.record(speakerIdSchema, speakerDataSchema);
|
|
31
|
-
const mediaSourceSchema = z.discriminatedUnion("kind", [
|
|
31
|
+
export const mediaSourceSchema = z.discriminatedUnion("kind", [
|
|
32
32
|
z.object({ kind: z.literal("url"), url: URLStringSchema }).strict(), // https://example.com/foo.pdf
|
|
33
|
-
z.object({ kind: z.literal("
|
|
33
|
+
z.object({ kind: z.literal("base64"), data: z.string() }).strict(), // base64
|
|
34
|
+
z.object({ kind: z.literal("text"), text: z.string() }).strict(), // plain text
|
|
34
35
|
z.object({ kind: z.literal("path"), path: z.string() }).strict(), // foo.pdf
|
|
35
36
|
]);
|
|
36
37
|
// String is easier for AI, string array is easier for human
|
|
37
38
|
const stringOrStringArray = z.union([z.string(), z.array(z.string())]);
|
|
38
|
-
const
|
|
39
|
+
export const mulmoMarkdownMediaSchema = z
|
|
39
40
|
.object({
|
|
40
41
|
type: z.literal("markdown"),
|
|
41
42
|
markdown: stringOrStringArray,
|
|
42
43
|
})
|
|
43
44
|
.strict();
|
|
44
|
-
const
|
|
45
|
+
const mulmoWebMediaSchema = z
|
|
45
46
|
.object({
|
|
46
47
|
type: z.literal("web"),
|
|
47
48
|
url: URLStringSchema,
|
|
48
49
|
})
|
|
49
50
|
.strict();
|
|
50
|
-
const
|
|
51
|
+
const mulmoPdfMediaSchema = z
|
|
51
52
|
.object({
|
|
52
53
|
type: z.literal("pdf"),
|
|
53
54
|
source: mediaSourceSchema,
|
|
54
55
|
})
|
|
55
56
|
.strict();
|
|
56
|
-
const
|
|
57
|
+
export const mulmoImageMediaSchema = z
|
|
57
58
|
.object({
|
|
58
59
|
type: z.literal("image"),
|
|
59
60
|
source: mediaSourceSchema,
|
|
60
61
|
})
|
|
61
62
|
.strict();
|
|
62
|
-
const
|
|
63
|
+
const mulmoSvgMediaSchema = z
|
|
63
64
|
.object({
|
|
64
65
|
type: z.literal("svg"),
|
|
65
66
|
source: mediaSourceSchema,
|
|
66
67
|
})
|
|
67
68
|
.strict();
|
|
68
|
-
const
|
|
69
|
+
const mulmoMovieMediaSchema = z
|
|
69
70
|
.object({
|
|
70
71
|
type: z.literal("movie"),
|
|
71
72
|
source: mediaSourceSchema,
|
|
72
73
|
})
|
|
73
74
|
.strict();
|
|
74
|
-
const
|
|
75
|
+
export const mulmoTextSlideMediaSchema = z
|
|
75
76
|
.object({
|
|
76
77
|
type: z.literal("textSlide"),
|
|
77
78
|
slide: z.object({
|
|
@@ -80,44 +81,45 @@ const MulmoTextSlideMediaSchema = z
|
|
|
80
81
|
}),
|
|
81
82
|
})
|
|
82
83
|
.strict();
|
|
83
|
-
const
|
|
84
|
+
export const mulmoChartMediaSchema = z
|
|
84
85
|
.object({
|
|
85
86
|
type: z.literal("chart"),
|
|
86
87
|
title: z.string(),
|
|
87
88
|
chartData: z.record(z.any()),
|
|
88
89
|
})
|
|
89
90
|
.strict();
|
|
90
|
-
const
|
|
91
|
+
export const mulmoMermaidMediaSchema = z
|
|
91
92
|
.object({
|
|
92
93
|
type: z.literal("mermaid"),
|
|
93
94
|
title: z.string().describe("The title of the diagram"),
|
|
94
|
-
code:
|
|
95
|
+
code: mediaSourceSchema.describe("The code of the mermaid diagram"),
|
|
96
|
+
appendix: z.array(z.string()).optional().describe("The appendix of the mermaid diagram; typically, style information."),
|
|
95
97
|
})
|
|
96
98
|
.strict();
|
|
97
99
|
export const mulmoImageAssetSchema = z.union([
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
mulmoMarkdownMediaSchema,
|
|
101
|
+
mulmoWebMediaSchema,
|
|
102
|
+
mulmoPdfMediaSchema,
|
|
103
|
+
mulmoImageMediaSchema,
|
|
104
|
+
mulmoSvgMediaSchema,
|
|
105
|
+
mulmoMovieMediaSchema,
|
|
106
|
+
mulmoTextSlideMediaSchema,
|
|
107
|
+
mulmoChartMediaSchema,
|
|
108
|
+
mulmoMermaidMediaSchema,
|
|
107
109
|
]);
|
|
108
|
-
const
|
|
110
|
+
const mulmoAudioMediaSchema = z
|
|
109
111
|
.object({
|
|
110
112
|
type: z.literal("audio"),
|
|
111
113
|
source: mediaSourceSchema,
|
|
112
114
|
})
|
|
113
115
|
.strict();
|
|
114
|
-
const
|
|
116
|
+
const mulmoMidiMediaSchema = z
|
|
115
117
|
.object({
|
|
116
118
|
type: z.literal("midi"),
|
|
117
119
|
source: z.string(), // TODO: define it later
|
|
118
120
|
})
|
|
119
121
|
.strict();
|
|
120
|
-
export const mulmoAudioAssetSchema = z.union([
|
|
122
|
+
export const mulmoAudioAssetSchema = z.union([mulmoAudioMediaSchema, mulmoMidiMediaSchema]);
|
|
121
123
|
export const mulmoImageParamsSchema = z
|
|
122
124
|
.object({
|
|
123
125
|
model: z.string().optional(), // default: provider specific
|
|
@@ -128,7 +130,7 @@ export const mulmoImageParamsSchema = z
|
|
|
128
130
|
.strict();
|
|
129
131
|
export const textSlideParamsSchema = z
|
|
130
132
|
.object({
|
|
131
|
-
cssStyles:
|
|
133
|
+
cssStyles: stringOrStringArray,
|
|
132
134
|
})
|
|
133
135
|
.strict();
|
|
134
136
|
export const videoParamsSchema = z
|
|
@@ -138,7 +140,7 @@ export const videoParamsSchema = z
|
|
|
138
140
|
.strict();
|
|
139
141
|
export const mulmoBeatSchema = z
|
|
140
142
|
.object({
|
|
141
|
-
speaker: speakerIdSchema,
|
|
143
|
+
speaker: speakerIdSchema.default("Presenter"),
|
|
142
144
|
text: z.string(),
|
|
143
145
|
image: mulmoImageAssetSchema.optional(),
|
|
144
146
|
audio: mulmoAudioAssetSchema.optional(),
|
|
@@ -169,17 +171,19 @@ export const mulmoSpeechParamsSchema = z
|
|
|
169
171
|
})
|
|
170
172
|
.strict();
|
|
171
173
|
export const text2ImageProviderSchema = z.union([z.literal("openai"), z.literal("google")]).default("openai");
|
|
172
|
-
export const
|
|
173
|
-
.object({
|
|
174
|
-
// global settings
|
|
174
|
+
export const mulmoPresentationStyleSchema = z.object({
|
|
175
175
|
$mulmocast: mulmoCastCreditSchema,
|
|
176
|
-
title: z.string(),
|
|
177
|
-
description: z.string().optional(),
|
|
178
|
-
reference: z.string().optional(),
|
|
179
|
-
lang: langSchema.optional(), // default "en"
|
|
180
176
|
canvasSize: mulmoCanvasDimensionSchema, // has default value
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
speechParams: mulmoSpeechParamsSchema.default({
|
|
178
|
+
speakers: {
|
|
179
|
+
Presenter: {
|
|
180
|
+
voiceId: "shimmer",
|
|
181
|
+
displayName: {
|
|
182
|
+
en: "Presenter",
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
}),
|
|
183
187
|
imageParams: mulmoImageParamsSchema
|
|
184
188
|
.extend({
|
|
185
189
|
provider: text2ImageProviderSchema, // has default value
|
|
@@ -188,15 +192,30 @@ export const mulmoScriptSchema = z
|
|
|
188
192
|
// for textSlides
|
|
189
193
|
textSlideParams: textSlideParamsSchema.optional(),
|
|
190
194
|
videoParams: videoParamsSchema.optional(),
|
|
191
|
-
//
|
|
192
|
-
imagePath: z.string().optional(), // for keynote images movie ??
|
|
195
|
+
// TODO: Switch to showCaptions later
|
|
193
196
|
omitCaptions: z.boolean().optional(), // default is false
|
|
197
|
+
});
|
|
198
|
+
export const mulmoReferenceSchema = z.object({
|
|
199
|
+
url: URLStringSchema,
|
|
200
|
+
title: z.string().optional(),
|
|
201
|
+
description: z.string().optional(),
|
|
202
|
+
type: z.union([z.literal("article"), z.literal("image"), z.literal("video"), z.literal("audio")]).default("article"),
|
|
203
|
+
});
|
|
204
|
+
export const mulmoScriptSchema = mulmoPresentationStyleSchema
|
|
205
|
+
.extend({
|
|
206
|
+
title: z.string().optional(),
|
|
207
|
+
description: z.string().optional(),
|
|
208
|
+
references: z.array(mulmoReferenceSchema).optional(),
|
|
209
|
+
lang: langSchema.optional(), // default "en"
|
|
210
|
+
beats: z.array(mulmoBeatSchema).min(1),
|
|
211
|
+
// TODO: Delete it later
|
|
212
|
+
imagePath: z.string().optional(), // for keynote images movie ??
|
|
194
213
|
// for debugging
|
|
195
214
|
__test_invalid__: z.boolean().optional(),
|
|
196
215
|
})
|
|
197
216
|
.strict();
|
|
198
|
-
export const mulmoStudioBeatSchema =
|
|
199
|
-
.
|
|
217
|
+
export const mulmoStudioBeatSchema = z
|
|
218
|
+
.object({
|
|
200
219
|
multiLingualTexts: multiLingualTextsSchema.optional(),
|
|
201
220
|
hash: z.string().optional(),
|
|
202
221
|
duration: z.number().optional(),
|
|
@@ -208,7 +227,7 @@ export const mulmoStudioSchema = z
|
|
|
208
227
|
.object({
|
|
209
228
|
script: mulmoScriptSchema,
|
|
210
229
|
filename: z.string(),
|
|
211
|
-
beats: z.array(mulmoStudioBeatSchema),
|
|
230
|
+
beats: z.array(mulmoStudioBeatSchema).min(1),
|
|
212
231
|
})
|
|
213
232
|
.strict();
|
|
214
233
|
export const mulmoScriptTemplateSchema = z
|
|
@@ -219,4 +238,19 @@ export const mulmoScriptTemplateSchema = z
|
|
|
219
238
|
script: mulmoScriptSchema.optional(),
|
|
220
239
|
})
|
|
221
240
|
.strict();
|
|
241
|
+
export const mulmoStoryboardSceneSchema = z
|
|
242
|
+
.object({
|
|
243
|
+
description: z.string(),
|
|
244
|
+
references: z.array(mulmoReferenceSchema).optional(),
|
|
245
|
+
})
|
|
246
|
+
.describe("A detailed description of the content of the scene, not the presentation style")
|
|
247
|
+
.strict();
|
|
248
|
+
export const mulmoStoryboardSchema = z
|
|
249
|
+
.object({
|
|
250
|
+
title: z.string(),
|
|
251
|
+
references: z.array(mulmoReferenceSchema).optional(),
|
|
252
|
+
scenes: z.array(mulmoStoryboardSceneSchema),
|
|
253
|
+
})
|
|
254
|
+
.describe("A storyboard for a presentation, a story, a video, etc.")
|
|
255
|
+
.strict();
|
|
222
256
|
export const urlsSchema = z.array(z.string().url({ message: "Invalid URL format" }));
|
package/lib/types/type.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { langSchema, localizedTextSchema, mulmoBeatSchema, mulmoScriptSchema, mulmoStudioSchema, mulmoStudioBeatSchema, speakerDictionarySchema, mulmoImageParamsSchema, mulmoSpeechParamsSchema, textSlideParamsSchema, speechOptionsSchema, mulmoCanvasDimensionSchema, mulmoScriptTemplateSchema, text2ImageProviderSchema, text2SpeechProviderSchema } from "./schema.js";
|
|
1
|
+
import { langSchema, localizedTextSchema, mulmoBeatSchema, mulmoScriptSchema, mulmoStudioSchema, mulmoStudioBeatSchema, mulmoStoryboardSchema, mulmoStoryboardSceneSchema, speakerDictionarySchema, mulmoImageParamsSchema, mulmoSpeechParamsSchema, textSlideParamsSchema, speechOptionsSchema, mulmoCanvasDimensionSchema, mulmoScriptTemplateSchema, text2ImageProviderSchema, text2SpeechProviderSchema, mulmoPresentationStyleSchema, mulmoMermaidMediaSchema, mulmoTextSlideMediaSchema, mulmoMarkdownMediaSchema, mulmoImageMediaSchema, mulmoChartMediaSchema, mediaSourceSchema } from "./schema.js";
|
|
2
|
+
import { pdf_modes, pdf_sizes } from "../utils/const.js";
|
|
2
3
|
import { z } from "zod";
|
|
3
4
|
export type LANG = z.infer<typeof langSchema>;
|
|
4
5
|
export type MulmoBeat = z.infer<typeof mulmoBeatSchema>;
|
|
@@ -11,10 +12,19 @@ export type Text2ImageProvider = z.infer<typeof text2ImageProviderSchema>;
|
|
|
11
12
|
export type Text2SpeechProvider = z.infer<typeof text2SpeechProviderSchema>;
|
|
12
13
|
export type LocalizedText = z.infer<typeof localizedTextSchema>;
|
|
13
14
|
export type MulmoScript = z.infer<typeof mulmoScriptSchema>;
|
|
15
|
+
export type MulmoPresentationStyle = z.infer<typeof mulmoPresentationStyleSchema>;
|
|
14
16
|
export type MulmoCanvasDimension = z.infer<typeof mulmoCanvasDimensionSchema>;
|
|
17
|
+
export type MulmoStoryboardScene = z.infer<typeof mulmoStoryboardSceneSchema>;
|
|
18
|
+
export type MulmoStoryboard = z.infer<typeof mulmoStoryboardSchema>;
|
|
15
19
|
export type MulmoStudioBeat = z.infer<typeof mulmoStudioBeatSchema>;
|
|
20
|
+
export type MulmoMediaSource = z.infer<typeof mediaSourceSchema>;
|
|
16
21
|
export type MulmoStudio = z.infer<typeof mulmoStudioSchema>;
|
|
17
22
|
export type MulmoScriptTemplate = z.infer<typeof mulmoScriptTemplateSchema>;
|
|
23
|
+
export type MulmoTextSlideMedia = z.infer<typeof mulmoTextSlideMediaSchema>;
|
|
24
|
+
export type MulmoMarkdownMedia = z.infer<typeof mulmoMarkdownMediaSchema>;
|
|
25
|
+
export type MulmoImageMedia = z.infer<typeof mulmoImageMediaSchema>;
|
|
26
|
+
export type MulmoChartMedia = z.infer<typeof mulmoChartMediaSchema>;
|
|
27
|
+
export type MulmoMermaidMedia = z.infer<typeof mulmoMermaidMediaSchema>;
|
|
18
28
|
export type FileDirs = {
|
|
19
29
|
mulmoFilePath: string;
|
|
20
30
|
mulmoFileDirPath: string;
|
|
@@ -34,4 +44,21 @@ export type ScriptingParams = {
|
|
|
34
44
|
cacheDirPath: string;
|
|
35
45
|
templateName: string;
|
|
36
46
|
filename: string;
|
|
47
|
+
llm_model?: string;
|
|
48
|
+
llm_agent?: string;
|
|
37
49
|
};
|
|
50
|
+
export type ImageProcessorParams = {
|
|
51
|
+
beat: MulmoBeat;
|
|
52
|
+
context: MulmoStudioContext;
|
|
53
|
+
imagePath: string;
|
|
54
|
+
textSlideStyle: string;
|
|
55
|
+
canvasSize: MulmoCanvasDimension;
|
|
56
|
+
};
|
|
57
|
+
export type PDFMode = (typeof pdf_modes)[number];
|
|
58
|
+
export type PDFSize = (typeof pdf_sizes)[number];
|
|
59
|
+
export type Text2ImageAgentInfo = {
|
|
60
|
+
provider: Text2ImageProvider;
|
|
61
|
+
agent: string;
|
|
62
|
+
imageParams: MulmoImageParams;
|
|
63
|
+
};
|
|
64
|
+
export type BeatMediaType = "movie" | "image";
|
package/lib/utils/const.d.ts
CHANGED
package/lib/utils/const.js
CHANGED
package/lib/utils/file.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { MulmoScript, MulmoScriptTemplate } from "../types/index.js";
|
|
1
|
+
import { MulmoScript, MulmoScriptTemplate, MulmoMediaSource, MulmoStudioContext } from "../types/index.js";
|
|
2
|
+
import { PDFMode } from "../types/index.js";
|
|
2
3
|
export declare function readMulmoScriptFile<T = MulmoScript>(path: string, errorMessage: string): {
|
|
3
4
|
mulmoData: T;
|
|
4
5
|
mulmoDataPath: string;
|
|
@@ -28,6 +29,7 @@ export declare const getAudioSegmentFilePath: (audioDirPath: string, studioFileN
|
|
|
28
29
|
export declare const getAudioCombinedFilePath: (audioDirPath: string, fileName: string) => string;
|
|
29
30
|
export declare const getAudioArtifactFilePath: (outDirPath: string, fileName: string) => string;
|
|
30
31
|
export declare const getOutputVideoFilePath: (outDirPath: string, fileName: string) => string;
|
|
32
|
+
export declare const getOutputPdfFilePath: (outDirPath: string, fileName: string, pdfMode: PDFMode) => string;
|
|
31
33
|
export declare const getTemplateFilePath: (templateName: string) => string;
|
|
32
34
|
export declare const mkdir: (dirPath: string) => void;
|
|
33
35
|
export declare const silentPath: string;
|
|
@@ -41,3 +43,4 @@ export declare const getAvailableTemplates: () => (MulmoScriptTemplate & {
|
|
|
41
43
|
filename: string;
|
|
42
44
|
})[];
|
|
43
45
|
export declare const writingMessage: (filePath: string) => void;
|
|
46
|
+
export declare const resolveMediaSource: (source: MulmoMediaSource, context: MulmoStudioContext) => string | null;
|
package/lib/utils/file.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
+
import { parse as yamlParse } from "yaml";
|
|
3
4
|
import { fileURLToPath } from "url";
|
|
4
5
|
import { GraphAILogger } from "graphai";
|
|
5
6
|
import { MulmoScriptTemplateMethods } from "../methods/mulmo_script_template.js";
|
|
7
|
+
import { MulmoStudioContextMethods } from "../methods/index.js";
|
|
6
8
|
import { mulmoScriptTemplateSchema } from "../types/schema.js";
|
|
7
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
10
|
const __dirname = path.dirname(__filename);
|
|
@@ -16,7 +18,7 @@ export function readMulmoScriptFile(arg2, errorMessage) {
|
|
|
16
18
|
return null;
|
|
17
19
|
}
|
|
18
20
|
const scriptData = fs.readFileSync(scriptPath, "utf-8");
|
|
19
|
-
const script = JSON.parse(scriptData);
|
|
21
|
+
const script = ([".yaml", ".yml"].includes(path.extname(scriptPath).toLowerCase()) ? yamlParse(scriptData) : JSON.parse(scriptData));
|
|
20
22
|
const parsedPath = path.parse(scriptPath);
|
|
21
23
|
return {
|
|
22
24
|
mulmoData: script,
|
|
@@ -58,6 +60,9 @@ export const getAudioArtifactFilePath = (outDirPath, fileName) => {
|
|
|
58
60
|
export const getOutputVideoFilePath = (outDirPath, fileName) => {
|
|
59
61
|
return path.resolve(outDirPath, fileName + ".mp4");
|
|
60
62
|
};
|
|
63
|
+
export const getOutputPdfFilePath = (outDirPath, fileName, pdfMode) => {
|
|
64
|
+
return path.resolve(outDirPath, fileName + "_" + pdfMode + ".pdf");
|
|
65
|
+
};
|
|
61
66
|
export const getTemplateFilePath = (templateName) => {
|
|
62
67
|
return path.resolve(__dirname, "../../assets/templates/" + templateName + ".json");
|
|
63
68
|
};
|
|
@@ -117,3 +122,12 @@ export const getAvailableTemplates = () => {
|
|
|
117
122
|
export const writingMessage = (filePath) => {
|
|
118
123
|
GraphAILogger.info(`writing: ${filePath}`);
|
|
119
124
|
};
|
|
125
|
+
export const resolveMediaSource = (source, context) => {
|
|
126
|
+
if (source.kind === "path") {
|
|
127
|
+
return MulmoStudioContextMethods.resolveAssetPath(context, source.path);
|
|
128
|
+
}
|
|
129
|
+
if (source.kind === "url") {
|
|
130
|
+
return source.url;
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
};
|
package/lib/utils/filters.js
CHANGED
|
@@ -4,7 +4,7 @@ import path from "path";
|
|
|
4
4
|
import fsPromise from "fs/promises";
|
|
5
5
|
import { GraphAILogger } from "graphai";
|
|
6
6
|
import { writingMessage } from "./file.js";
|
|
7
|
-
import { text2hash } from "./
|
|
7
|
+
import { text2hash } from "./utils.js";
|
|
8
8
|
export const fileCacheAgentFilter = async (context, next) => {
|
|
9
9
|
const { namedInputs } = context;
|
|
10
10
|
const { file, text, force } = namedInputs;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getHTMLFile } from "../file.js";
|
|
2
|
+
import { renderHTMLToImage, interpolate } from "../markdown.js";
|
|
3
|
+
export const imageType = "chart";
|
|
4
|
+
const processChart = async (params) => {
|
|
5
|
+
const { beat, imagePath, canvasSize, textSlideStyle } = params;
|
|
6
|
+
if (!beat.image || beat.image.type !== imageType)
|
|
7
|
+
return;
|
|
8
|
+
const template = getHTMLFile("chart");
|
|
9
|
+
const htmlData = interpolate(template, {
|
|
10
|
+
title: beat.image.title,
|
|
11
|
+
style: textSlideStyle,
|
|
12
|
+
width: Math.round(canvasSize.width * 0.625).toString(),
|
|
13
|
+
chart_data: JSON.stringify(beat.image.chartData),
|
|
14
|
+
});
|
|
15
|
+
await renderHTMLToImage(htmlData, imagePath, canvasSize.width, canvasSize.height);
|
|
16
|
+
return imagePath;
|
|
17
|
+
};
|
|
18
|
+
export const process = processChart;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as pluginTextSlide from "./text_slide.js";
|
|
2
|
+
import * as pluginMarkdown from "./markdown.js";
|
|
3
|
+
import * as pluginImage from "./image.js";
|
|
4
|
+
import * as pluginChart from "./chart.js";
|
|
5
|
+
import * as pluginMermaid from "./mermaid.js";
|
|
6
|
+
import * as pluginMovie from "./movie.js";
|
|
7
|
+
export declare const imagePlugins: (typeof pluginTextSlide | typeof pluginMarkdown | typeof pluginImage | typeof pluginChart | typeof pluginMermaid | typeof pluginMovie)[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as pluginTextSlide from "./text_slide.js";
|
|
2
|
+
import * as pluginMarkdown from "./markdown.js";
|
|
3
|
+
import * as pluginImage from "./image.js";
|
|
4
|
+
import * as pluginChart from "./chart.js";
|
|
5
|
+
import * as pluginMermaid from "./mermaid.js";
|
|
6
|
+
import * as pluginMovie from "./movie.js";
|
|
7
|
+
export const imagePlugins = [pluginTextSlide, pluginMarkdown, pluginImage, pluginChart, pluginMermaid, pluginMovie];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { renderMarkdownToImage } from "../markdown.js";
|
|
2
|
+
export const imageType = "markdown";
|
|
3
|
+
const processMarkdown = async (params) => {
|
|
4
|
+
const { beat, imagePath, textSlideStyle, canvasSize } = params;
|
|
5
|
+
if (!beat.image || beat.image.type !== imageType)
|
|
6
|
+
return;
|
|
7
|
+
const markdown = Array.isArray(beat.image.markdown) ? beat.image.markdown.join("\n") : beat.image.markdown;
|
|
8
|
+
await renderMarkdownToImage(markdown, textSlideStyle, imagePath, canvasSize.width, canvasSize.height);
|
|
9
|
+
return imagePath;
|
|
10
|
+
};
|
|
11
|
+
export const process = processMarkdown;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { MulmoMediaSourceMethods } from "../../methods/index.js";
|
|
2
|
+
import { getHTMLFile } from "../file.js";
|
|
3
|
+
import { renderHTMLToImage, interpolate } from "../markdown.js";
|
|
4
|
+
export const imageType = "mermaid";
|
|
5
|
+
const processMermaid = async (params) => {
|
|
6
|
+
const { beat, imagePath, canvasSize, context, textSlideStyle } = params;
|
|
7
|
+
if (!beat.image || beat.image.type !== imageType)
|
|
8
|
+
return;
|
|
9
|
+
const template = getHTMLFile("mermaid");
|
|
10
|
+
const diagram_code = await MulmoMediaSourceMethods.getText(beat.image.code, context);
|
|
11
|
+
if (diagram_code) {
|
|
12
|
+
const htmlData = interpolate(template, {
|
|
13
|
+
title: beat.image.title,
|
|
14
|
+
style: textSlideStyle,
|
|
15
|
+
diagram_code: `${diagram_code}\n${beat.image.appendix?.join("\n") ?? ""}`,
|
|
16
|
+
});
|
|
17
|
+
await renderHTMLToImage(htmlData, imagePath, canvasSize.width, canvasSize.height);
|
|
18
|
+
}
|
|
19
|
+
return imagePath;
|
|
20
|
+
};
|
|
21
|
+
export const process = processMermaid;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { GraphAILogger } from "graphai";
|
|
2
|
+
import { resolveMediaSource } from "../../utils/file.js";
|
|
3
|
+
export const processSource = (imageType) => {
|
|
4
|
+
return (params) => {
|
|
5
|
+
const { beat, context } = params;
|
|
6
|
+
if (!beat.image || beat.image.type !== imageType)
|
|
7
|
+
return;
|
|
8
|
+
const path = resolveMediaSource(beat.image.source, context);
|
|
9
|
+
if (path) {
|
|
10
|
+
return path;
|
|
11
|
+
}
|
|
12
|
+
GraphAILogger.error(`Image Plugin unknown ${imageType} source type:`, beat.image);
|
|
13
|
+
throw new Error(`ERROR: unknown ${imageType} source type`);
|
|
14
|
+
};
|
|
15
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { renderMarkdownToImage } from "../markdown.js";
|
|
2
|
+
export const imageType = "textSlide";
|
|
3
|
+
const processTextSlide = async (params) => {
|
|
4
|
+
const { beat, imagePath, textSlideStyle, canvasSize } = params;
|
|
5
|
+
if (!beat.image || beat.image.type !== imageType)
|
|
6
|
+
return;
|
|
7
|
+
const slide = beat.image.slide;
|
|
8
|
+
const markdown = `# ${slide.title}\n` + slide.bullets.map((text) => `- ${text}`).join("\n");
|
|
9
|
+
await renderMarkdownToImage(markdown, textSlideStyle, imagePath, canvasSize.width, canvasSize.height);
|
|
10
|
+
return imagePath;
|
|
11
|
+
};
|
|
12
|
+
export const process = processTextSlide;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { MulmoTextSlideMedia, MulmoMarkdownMedia, MulmoImageMedia, MulmoChartMedia, MulmoMermaidMedia } from "../../types/index.js";
|
|
2
|
+
export declare const isMulmoImageTextSlide: (value: unknown) => value is MulmoTextSlideMedia;
|
|
3
|
+
export declare const isMulmoImageMarkdown: (value: unknown) => value is MulmoMarkdownMedia;
|
|
4
|
+
export declare const isMulmoImageImage: (value: unknown) => value is MulmoImageMedia;
|
|
5
|
+
export declare const isMulmoImageChart: (value: unknown) => value is MulmoChartMedia;
|
|
6
|
+
export declare const isMulmoImageMermaild: (value: unknown) => value is MulmoMermaidMedia;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { mulmoTextSlideMediaSchema, mulmoMarkdownMediaSchema, mulmoImageMediaSchema, mulmoChartMediaSchema, mulmoMermaidMediaSchema, } from "../../types/index.js";
|
|
2
|
+
export const isMulmoImageTextSlide = (value) => {
|
|
3
|
+
const result = mulmoTextSlideMediaSchema.safeParse(value);
|
|
4
|
+
return result.success;
|
|
5
|
+
};
|
|
6
|
+
export const isMulmoImageMarkdown = (value) => {
|
|
7
|
+
const result = mulmoMarkdownMediaSchema.safeParse(value);
|
|
8
|
+
return result.success;
|
|
9
|
+
};
|
|
10
|
+
export const isMulmoImageImage = (value) => {
|
|
11
|
+
const result = mulmoImageMediaSchema.safeParse(value);
|
|
12
|
+
return result.success;
|
|
13
|
+
};
|
|
14
|
+
export const isMulmoImageChart = (value) => {
|
|
15
|
+
const result = mulmoChartMediaSchema.safeParse(value);
|
|
16
|
+
return result.success;
|
|
17
|
+
};
|
|
18
|
+
export const isMulmoImageMermaild = (value) => {
|
|
19
|
+
const result = mulmoMermaidMediaSchema.safeParse(value);
|
|
20
|
+
return result.success;
|
|
21
|
+
};
|
package/lib/utils/markdown.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { GraphAILogger } from "graphai";
|
|
2
2
|
import { marked } from "marked";
|
|
3
3
|
import puppeteer from "puppeteer";
|
|
4
|
+
const isCI = process.env.CI === "true";
|
|
4
5
|
export const renderHTMLToImage = async (html, outputPath, width, height) => {
|
|
5
6
|
// Use Puppeteer to render HTML to an image
|
|
6
|
-
const browser = await puppeteer.launch(
|
|
7
|
+
const browser = await puppeteer.launch({
|
|
8
|
+
args: isCI ? ["--no-sandbox"] : [],
|
|
9
|
+
});
|
|
7
10
|
const page = await browser.newPage();
|
|
8
11
|
// Set the page content to the HTML generated from the Markdown
|
|
9
12
|
await page.setContent(html);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PDFFont } from "pdf-lib";
|
|
2
|
+
export declare const fontSize = 12;
|
|
3
|
+
export declare const textMargin = 6;
|
|
4
|
+
export declare const drawSize: (fitWidth: boolean, expectWidth: number, expectHeight: number, origWidth: number, origHeight: number) => {
|
|
5
|
+
drawWidth: number;
|
|
6
|
+
drawHeight: number;
|
|
7
|
+
};
|
|
8
|
+
export declare const wrapText: (text: string, font: PDFFont, fontSize: number, maxWidth: number) => string[];
|
package/lib/utils/pdf.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export const fontSize = 12;
|
|
2
|
+
export const textMargin = 6;
|
|
3
|
+
export const drawSize = (fitWidth, expectWidth, expectHeight, origWidth, origHeight) => {
|
|
4
|
+
if (fitWidth) {
|
|
5
|
+
const drawWidth = expectWidth;
|
|
6
|
+
const scale = drawWidth / origWidth;
|
|
7
|
+
const drawHeight = origHeight * scale;
|
|
8
|
+
return {
|
|
9
|
+
drawWidth,
|
|
10
|
+
drawHeight,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const drawHeight = expectHeight;
|
|
14
|
+
const scale = drawHeight / origHeight;
|
|
15
|
+
const drawWidth = origWidth * scale;
|
|
16
|
+
return {
|
|
17
|
+
drawWidth,
|
|
18
|
+
drawHeight,
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
const isFullwidth = (char) => {
|
|
22
|
+
const code = char.charCodeAt(0);
|
|
23
|
+
return ((code >= 0x3000 && code <= 0x9fff) || // CJK, punctuation, kana
|
|
24
|
+
(code >= 0xff00 && code <= 0xffef) // Fullwidth ASCII
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
export const wrapText = (text, font, fontSize, maxWidth) => {
|
|
28
|
+
const lines = [];
|
|
29
|
+
for (const rawLine of text.split("\n")) {
|
|
30
|
+
let line = "";
|
|
31
|
+
let buffer = "";
|
|
32
|
+
for (let i = 0; i < rawLine.length; i++) {
|
|
33
|
+
const char = rawLine[i];
|
|
34
|
+
buffer += char;
|
|
35
|
+
const width = font.widthOfTextAtSize(line + buffer, fontSize);
|
|
36
|
+
const nextChar = rawLine[i + 1];
|
|
37
|
+
const currentIsFull = isFullwidth(char);
|
|
38
|
+
const nextIsFull = nextChar && isFullwidth(nextChar);
|
|
39
|
+
const isBreakable = currentIsFull || (!currentIsFull && (char === " " || nextChar === " " || nextIsFull));
|
|
40
|
+
if (width > maxWidth && buffer) {
|
|
41
|
+
lines.push(line);
|
|
42
|
+
line = "";
|
|
43
|
+
buffer = char;
|
|
44
|
+
}
|
|
45
|
+
if (isBreakable || i === rawLine.length - 1) {
|
|
46
|
+
line += buffer;
|
|
47
|
+
buffer = "";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (line)
|
|
51
|
+
lines.push(line);
|
|
52
|
+
}
|
|
53
|
+
return lines;
|
|
54
|
+
};
|
|
55
|
+
/*
|
|
56
|
+
export const wrapText = (text: string, font: PDFFont, fontSize: number, maxWidth: number) => {
|
|
57
|
+
const words = text.split(" ");
|
|
58
|
+
const lines = [];
|
|
59
|
+
let currentLine = "";
|
|
60
|
+
|
|
61
|
+
for (const word of words) {
|
|
62
|
+
const nextLine = currentLine ? `${currentLine} ${word}` : word;
|
|
63
|
+
// console.log(nextLine);
|
|
64
|
+
const width = font.widthOfTextAtSize(nextLine ?? "", fontSize);
|
|
65
|
+
if (width <= maxWidth) {
|
|
66
|
+
currentLine = nextLine;
|
|
67
|
+
} else {
|
|
68
|
+
lines.push(currentLine);
|
|
69
|
+
currentLine = word;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (currentLine) lines.push(currentLine);
|
|
73
|
+
return lines;
|
|
74
|
+
};
|
|
75
|
+
*/
|