mulmocast 1.2.5 → 1.2.6
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/assets/templates/sifi_story.json +29 -0
- package/lib/actions/image_agents.d.ts +4 -0
- package/lib/actions/image_agents.js +3 -3
- package/lib/actions/images.js +4 -2
- package/lib/actions/movie.js +1 -1
- package/lib/agents/lipsync_replicate_agent.js +9 -3
- package/lib/cli/commands/tool/index.js +2 -1
- package/lib/cli/commands/tool/whisper/builder.d.ts +4 -0
- package/lib/cli/commands/tool/whisper/builder.js +7 -0
- package/lib/cli/commands/tool/whisper/handler.d.ts +5 -0
- package/lib/cli/commands/tool/whisper/handler.js +100 -0
- package/lib/cli/commands/tool/whisper/index.d.ts +4 -0
- package/lib/cli/commands/tool/whisper/index.js +4 -0
- package/lib/data/promptTemplates.d.ts +76 -0
- package/lib/data/promptTemplates.js +55 -0
- package/lib/data/scriptTemplates.d.ts +20 -0
- package/lib/data/scriptTemplates.js +26 -0
- package/lib/data/templateDataSet.d.ts +1 -0
- package/lib/data/templateDataSet.js +4 -0
- package/lib/types/schema.d.ts +8 -0
- package/lib/types/schema.js +1 -0
- package/lib/utils/context.d.ts +2 -0
- package/lib/utils/file.d.ts +4 -1
- package/lib/utils/file.js +4 -4
- package/package.json +8 -7
- package/scripts/templates/story_with_characters.json +25 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Multi-character Story",
|
|
3
|
+
"description": "Template for Multi-character Story.",
|
|
4
|
+
"systemPrompt": "Break the story into multiple beats, and put the story text in 'text' field. Generate image prompt for each character in the imageParams.images. Another AI will generate image for each beat based on its imagePrompt and specified characters in 'imageNames'. You don't need to repeat the image style in those image prompts. Use the JSON below as a template.",
|
|
5
|
+
"presentationStyle": {
|
|
6
|
+
"$mulmocast": {
|
|
7
|
+
"version": "1.1",
|
|
8
|
+
"credit": "closing"
|
|
9
|
+
},
|
|
10
|
+
"canvasSize": {
|
|
11
|
+
"width": 1536,
|
|
12
|
+
"height": 1024
|
|
13
|
+
},
|
|
14
|
+
"imageParams": {
|
|
15
|
+
"style": "<style>A dreamy, hyper-detailed anime style that blends photorealistic backgrounds with vibrant, saturated colors. The skies are often filled with luminous clouds, dazzling sunsets, or star-filled nights, rendered with a glowing, almost ethereal quality. Urban landscapes and rural scenery are meticulously illustrated, with attention to tiny details like reflections in puddles, neon lights, or the texture of grass swaying in the wind. Characters are drawn with soft, expressive features, standing out against the breathtaking environments, creating a sense of emotional depth and lyrical atmosphere. The overall mood is cinematic, romantic, and filled with a sense of fleeting beauty and longing.</style>",
|
|
16
|
+
"images": {
|
|
17
|
+
"[CHARACTER_1_ID]": {
|
|
18
|
+
"type": "imagePrompt",
|
|
19
|
+
"prompt": "[IMAGE PROMPT FOR THIS CHARACTER]"
|
|
20
|
+
},
|
|
21
|
+
"[CHARACTER_2_ID]": {
|
|
22
|
+
"type": "imagePrompt",
|
|
23
|
+
"prompt": "[IMAGE PROMPT FOR THIS CHARACTER]"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"scriptName": "story_with_characters.json"
|
|
29
|
+
}
|
|
@@ -7,6 +7,7 @@ export declare const imagePreprocessAgent: (namedInputs: {
|
|
|
7
7
|
}) => Promise<{
|
|
8
8
|
imagePath: string;
|
|
9
9
|
htmlPrompt: string | undefined;
|
|
10
|
+
htmlImageFile: string;
|
|
10
11
|
htmlPath: string;
|
|
11
12
|
htmlImageSystemPrompt: string;
|
|
12
13
|
} | {
|
|
@@ -27,6 +28,7 @@ export declare const imagePreprocessAgent: (namedInputs: {
|
|
|
27
28
|
audioFile?: string;
|
|
28
29
|
beatDuration?: number;
|
|
29
30
|
htmlPrompt?: undefined;
|
|
31
|
+
htmlImageFile?: undefined;
|
|
30
32
|
htmlPath?: undefined;
|
|
31
33
|
htmlImageSystemPrompt?: undefined;
|
|
32
34
|
} | {
|
|
@@ -62,6 +64,7 @@ export declare const imagePreprocessAgent: (namedInputs: {
|
|
|
62
64
|
audioFile?: string;
|
|
63
65
|
beatDuration?: number;
|
|
64
66
|
htmlPrompt?: undefined;
|
|
67
|
+
htmlImageFile?: undefined;
|
|
65
68
|
htmlPath?: undefined;
|
|
66
69
|
htmlImageSystemPrompt?: undefined;
|
|
67
70
|
} | {
|
|
@@ -100,6 +103,7 @@ export declare const imagePreprocessAgent: (namedInputs: {
|
|
|
100
103
|
audioFile?: string;
|
|
101
104
|
beatDuration?: number;
|
|
102
105
|
htmlPrompt?: undefined;
|
|
106
|
+
htmlImageFile?: undefined;
|
|
103
107
|
htmlPath?: undefined;
|
|
104
108
|
htmlImageSystemPrompt?: undefined;
|
|
105
109
|
}>;
|
|
@@ -12,11 +12,11 @@ const htmlStyle = (context, beat) => {
|
|
|
12
12
|
export const imagePreprocessAgent = async (namedInputs) => {
|
|
13
13
|
const { context, beat, index, imageRefs } = namedInputs;
|
|
14
14
|
const studioBeat = context.studio.beats[index];
|
|
15
|
-
const imagePath = getBeatPngImagePath(context, index);
|
|
15
|
+
const { imagePath, htmlImageFile } = getBeatPngImagePath(context, index);
|
|
16
16
|
if (beat.htmlPrompt) {
|
|
17
17
|
const htmlPrompt = MulmoBeatMethods.getHtmlPrompt(beat);
|
|
18
18
|
const htmlPath = imagePath.replace(/\.[^/.]+$/, ".html");
|
|
19
|
-
return { imagePath, htmlPrompt, htmlPath, htmlImageSystemPrompt: htmlImageSystemPrompt(context.presentationStyle.canvasSize) };
|
|
19
|
+
return { imagePath, htmlPrompt, htmlImageFile, htmlPath, htmlImageSystemPrompt: htmlImageSystemPrompt(context.presentationStyle.canvasSize) };
|
|
20
20
|
}
|
|
21
21
|
const imageAgentInfo = MulmoPresentationStyleMethods.getImageAgentInfo(context.presentationStyle, beat);
|
|
22
22
|
const moviePaths = getBeatMoviePaths(context, index);
|
|
@@ -61,7 +61,7 @@ export const imagePreprocessAgent = async (namedInputs) => {
|
|
|
61
61
|
};
|
|
62
62
|
export const imagePluginAgent = async (namedInputs) => {
|
|
63
63
|
const { context, beat, index } = namedInputs;
|
|
64
|
-
const imagePath = getBeatPngImagePath(context, index);
|
|
64
|
+
const { imagePath } = getBeatPngImagePath(context, index);
|
|
65
65
|
const plugin = MulmoBeatMethods.getPlugin(beat);
|
|
66
66
|
try {
|
|
67
67
|
MulmoStudioContextMethods.setBeatSessionState(context, "image", index, beat.id, true);
|
package/lib/actions/images.js
CHANGED
|
@@ -116,7 +116,7 @@ const beat_graph_data = {
|
|
|
116
116
|
inputs: {
|
|
117
117
|
htmlText: ":htmlReader.htmlText",
|
|
118
118
|
canvasSize: ":context.presentationStyle.canvasSize",
|
|
119
|
-
file: ":preprocessor.
|
|
119
|
+
file: ":preprocessor.htmlImageFile",
|
|
120
120
|
},
|
|
121
121
|
},
|
|
122
122
|
imageGenerator: {
|
|
@@ -188,7 +188,7 @@ const beat_graph_data = {
|
|
|
188
188
|
return { hasMovieAudio: true };
|
|
189
189
|
}
|
|
190
190
|
const sourceFile = namedInputs.movieFile || namedInputs.imageFile;
|
|
191
|
-
if (!sourceFile) {
|
|
191
|
+
if (!sourceFile || !fs.existsSync(sourceFile)) {
|
|
192
192
|
return { hasMovieAudio: false };
|
|
193
193
|
}
|
|
194
194
|
const { hasAudio } = await ffmpegGetMediaDuration(sourceFile);
|
|
@@ -257,6 +257,7 @@ const beat_graph_data = {
|
|
|
257
257
|
soundEffectFile: ":preprocessor.soundEffectFile",
|
|
258
258
|
lipSyncFile: ":preprocessor.lipSyncFile",
|
|
259
259
|
hasMovieAudio: ":audioChecker.hasMovieAudio",
|
|
260
|
+
htmlImageFile: ":preprocessor.htmlImageFile",
|
|
260
261
|
},
|
|
261
262
|
output: {
|
|
262
263
|
imageFile: ".imageFile",
|
|
@@ -264,6 +265,7 @@ const beat_graph_data = {
|
|
|
264
265
|
soundEffectFile: ".soundEffectFile",
|
|
265
266
|
lipSyncFile: ".lipSyncFile",
|
|
266
267
|
hasMovieAudio: ".hasMovieAudio",
|
|
268
|
+
htmlImageFile: ".htmlImageFile",
|
|
267
269
|
},
|
|
268
270
|
isResult: true,
|
|
269
271
|
},
|
package/lib/actions/movie.js
CHANGED
|
@@ -162,7 +162,7 @@ const createVideo = async (audioArtifactFilePath, outputVideoPath, context) => {
|
|
|
162
162
|
beatTimestamps.push(timestamp);
|
|
163
163
|
return timestamp; // Skip voice-over beats.
|
|
164
164
|
}
|
|
165
|
-
const sourceFile = studioBeat.lipSyncFile ?? studioBeat.soundEffectFile ?? studioBeat.movieFile ?? studioBeat.imageFile;
|
|
165
|
+
const sourceFile = studioBeat.lipSyncFile ?? studioBeat.soundEffectFile ?? studioBeat.movieFile ?? studioBeat.htmlImageFile ?? studioBeat.imageFile;
|
|
166
166
|
assert(!!sourceFile, `studioBeat.imageFile or studioBeat.movieFile is not set: index=${index}`);
|
|
167
167
|
assert(!!studioBeat.duration, `studioBeat.duration is not set: index=${index}`);
|
|
168
168
|
const extraPadding = (() => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
1
|
+
import { readFileSync, existsSync } from "fs";
|
|
2
2
|
import { GraphAILogger } from "graphai";
|
|
3
3
|
import Replicate from "replicate";
|
|
4
4
|
import { provider2LipSyncAgent } from "../utils/provider2agent.js";
|
|
@@ -12,11 +12,17 @@ export const lipSyncReplicateAgent = async ({ namedInputs, params, config, }) =>
|
|
|
12
12
|
const replicate = new Replicate({
|
|
13
13
|
auth: apiKey,
|
|
14
14
|
});
|
|
15
|
-
|
|
15
|
+
if (!audioFile || !existsSync(audioFile)) {
|
|
16
|
+
throw new Error(`lipSyncReplicateAgent audioFile not exist: ${audioFile}`);
|
|
17
|
+
}
|
|
16
18
|
const audioBuffer = readFileSync(audioFile);
|
|
19
|
+
const videoBuffer = movieFile ? readFileSync(movieFile) : undefined;
|
|
17
20
|
const imageBuffer = imageFile ? readFileSync(imageFile) : undefined;
|
|
18
|
-
|
|
21
|
+
if (!videoBuffer && !imageBuffer) {
|
|
22
|
+
throw new Error("lipSyncReplicateAgent Either movieFile or imageFile is required");
|
|
23
|
+
}
|
|
19
24
|
const audioUri = `data:audio/wav;base64,${audioBuffer.toString("base64")}`;
|
|
25
|
+
const videoUri = videoBuffer ? `data:video/quicktime;base64,${videoBuffer.toString("base64")}` : undefined;
|
|
20
26
|
const imageUri = imageBuffer ? `data:image/png;base64,${imageBuffer.toString("base64")}` : undefined;
|
|
21
27
|
const input = {
|
|
22
28
|
video: undefined,
|
|
@@ -2,7 +2,8 @@ import * as scriptingCmd from "./scripting/index.js";
|
|
|
2
2
|
import * as promptCmd from "./prompt/index.js";
|
|
3
3
|
import * as schemaCmd from "./schema/index.js";
|
|
4
4
|
import * as storyToScriptCmd from "./story_to_script/index.js";
|
|
5
|
+
import * as whisperCmd from "./whisper/index.js";
|
|
5
6
|
export const command = "tool <command>";
|
|
6
7
|
export const desc = "Generate Mulmo script and other tools";
|
|
7
|
-
export const builder = (y) => y.command(scriptingCmd).command(promptCmd).command(schemaCmd).command(storyToScriptCmd).demandCommand().strict();
|
|
8
|
+
export const builder = (y) => y.command(scriptingCmd).command(promptCmd).command(schemaCmd).command(storyToScriptCmd).command(whisperCmd).demandCommand().strict();
|
|
8
9
|
export const handler = (__argv) => { };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import { existsSync, createReadStream, writeFileSync, mkdirSync } from "fs";
|
|
3
|
+
import { resolve, basename, extname, join } from "path";
|
|
4
|
+
import OpenAI from "openai";
|
|
5
|
+
import { mulmoScriptSchema } from "../../../../types/index.js";
|
|
6
|
+
import { ffmpegGetMediaDuration } from "../../../../utils/ffmpeg_utils.js";
|
|
7
|
+
import { GraphAILogger } from "graphai";
|
|
8
|
+
const createMulmoScript = (fullPath, beats) => {
|
|
9
|
+
return mulmoScriptSchema.parse({
|
|
10
|
+
$mulmocast: {
|
|
11
|
+
version: "1.1",
|
|
12
|
+
credit: "closing",
|
|
13
|
+
},
|
|
14
|
+
canvasSize: {
|
|
15
|
+
width: 1536,
|
|
16
|
+
height: 1024,
|
|
17
|
+
},
|
|
18
|
+
lang: "en",
|
|
19
|
+
title: "Music Video",
|
|
20
|
+
captionParams: {
|
|
21
|
+
lang: "en",
|
|
22
|
+
styles: ["font-size: 64px", "width: 90%", "padding-left: 5%", "padding-right: 5%"],
|
|
23
|
+
},
|
|
24
|
+
beats,
|
|
25
|
+
audioParams: {
|
|
26
|
+
bgm: {
|
|
27
|
+
kind: "path",
|
|
28
|
+
path: fullPath,
|
|
29
|
+
},
|
|
30
|
+
padding: 0.0,
|
|
31
|
+
introPadding: 0.0,
|
|
32
|
+
closingPadding: 0.0,
|
|
33
|
+
outroPadding: 0.0,
|
|
34
|
+
bgmVolume: 1.0,
|
|
35
|
+
audioVolume: 0.0,
|
|
36
|
+
suppressSpeech: true,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
export const handler = async (argv) => {
|
|
41
|
+
const { file } = argv;
|
|
42
|
+
const fullPath = resolve(file);
|
|
43
|
+
const filename = basename(file, extname(file));
|
|
44
|
+
if (!existsSync(fullPath)) {
|
|
45
|
+
GraphAILogger.error(`Error: File '${fullPath}' does not exist.`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
49
|
+
if (!apiKey) {
|
|
50
|
+
GraphAILogger.error("Error: OPENAI_API_KEY environment variable is required");
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
// Get audio duration using FFmpeg
|
|
55
|
+
const { duration: audioDuration } = await ffmpegGetMediaDuration(fullPath);
|
|
56
|
+
GraphAILogger.info(`Audio duration: ${audioDuration.toFixed(2)} seconds`);
|
|
57
|
+
const openai = new OpenAI({ apiKey });
|
|
58
|
+
const transcription = await openai.audio.transcriptions.create({
|
|
59
|
+
file: createReadStream(fullPath),
|
|
60
|
+
model: "whisper-1",
|
|
61
|
+
response_format: "verbose_json",
|
|
62
|
+
timestamp_granularities: ["word", "segment"],
|
|
63
|
+
});
|
|
64
|
+
if (transcription.segments) {
|
|
65
|
+
const starts = transcription.segments.map((segment) => segment.start);
|
|
66
|
+
starts[0] = 0;
|
|
67
|
+
starts.push(audioDuration);
|
|
68
|
+
// Create beats from transcription segments
|
|
69
|
+
const beats = transcription.segments.map((segment, index) => {
|
|
70
|
+
const duration = Math.round((starts[index + 1] - starts[index]) * 100) / 100;
|
|
71
|
+
return {
|
|
72
|
+
text: segment.text,
|
|
73
|
+
duration,
|
|
74
|
+
/*
|
|
75
|
+
image: {
|
|
76
|
+
type: "textSlide",
|
|
77
|
+
slide: {
|
|
78
|
+
title: "Place Holder",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
*/
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
// Create the script with the processed beats
|
|
85
|
+
const script = createMulmoScript(fullPath, beats);
|
|
86
|
+
// Save script to output directory
|
|
87
|
+
const outputDir = "output";
|
|
88
|
+
if (!existsSync(outputDir)) {
|
|
89
|
+
mkdirSync(outputDir, { recursive: true });
|
|
90
|
+
}
|
|
91
|
+
const outputPath = join(outputDir, `${filename}.json`);
|
|
92
|
+
writeFileSync(outputPath, JSON.stringify(script, null, 2));
|
|
93
|
+
GraphAILogger.info(`Script saved to: ${outputPath}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
GraphAILogger.error("Error transcribing audio:", error);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
@@ -32,6 +32,8 @@ export declare const promptTemplates: ({
|
|
|
32
32
|
ani?: undefined;
|
|
33
33
|
presenter?: undefined;
|
|
34
34
|
optimus?: undefined;
|
|
35
|
+
"[CHARACTER_1_ID]"?: undefined;
|
|
36
|
+
"[CHARACTER_2_ID]"?: undefined;
|
|
35
37
|
};
|
|
36
38
|
style: string;
|
|
37
39
|
provider?: undefined;
|
|
@@ -99,6 +101,8 @@ export declare const promptTemplates: ({
|
|
|
99
101
|
girl?: undefined;
|
|
100
102
|
presenter?: undefined;
|
|
101
103
|
optimus?: undefined;
|
|
104
|
+
"[CHARACTER_1_ID]"?: undefined;
|
|
105
|
+
"[CHARACTER_2_ID]"?: undefined;
|
|
102
106
|
};
|
|
103
107
|
style: string;
|
|
104
108
|
provider?: undefined;
|
|
@@ -169,6 +173,8 @@ export declare const promptTemplates: ({
|
|
|
169
173
|
ani?: undefined;
|
|
170
174
|
presenter?: undefined;
|
|
171
175
|
optimus?: undefined;
|
|
176
|
+
"[CHARACTER_1_ID]"?: undefined;
|
|
177
|
+
"[CHARACTER_2_ID]"?: undefined;
|
|
172
178
|
};
|
|
173
179
|
provider: string;
|
|
174
180
|
style?: undefined;
|
|
@@ -286,6 +292,8 @@ export declare const promptTemplates: ({
|
|
|
286
292
|
girl?: undefined;
|
|
287
293
|
ani?: undefined;
|
|
288
294
|
optimus?: undefined;
|
|
295
|
+
"[CHARACTER_1_ID]"?: undefined;
|
|
296
|
+
"[CHARACTER_2_ID]"?: undefined;
|
|
289
297
|
};
|
|
290
298
|
style: string;
|
|
291
299
|
provider?: undefined;
|
|
@@ -356,6 +364,8 @@ export declare const promptTemplates: ({
|
|
|
356
364
|
};
|
|
357
365
|
girl?: undefined;
|
|
358
366
|
ani?: undefined;
|
|
367
|
+
"[CHARACTER_1_ID]"?: undefined;
|
|
368
|
+
"[CHARACTER_2_ID]"?: undefined;
|
|
359
369
|
};
|
|
360
370
|
style: string;
|
|
361
371
|
provider?: undefined;
|
|
@@ -503,6 +513,72 @@ export declare const promptTemplates: ({
|
|
|
503
513
|
scriptName: string;
|
|
504
514
|
systemPrompt: string;
|
|
505
515
|
title: string;
|
|
516
|
+
} | {
|
|
517
|
+
description: string;
|
|
518
|
+
filename: string;
|
|
519
|
+
presentationStyle: {
|
|
520
|
+
$mulmocast: {
|
|
521
|
+
credit: string;
|
|
522
|
+
version: string;
|
|
523
|
+
};
|
|
524
|
+
audioParams: {
|
|
525
|
+
audioVolume: number;
|
|
526
|
+
bgmVolume: number;
|
|
527
|
+
closingPadding: number;
|
|
528
|
+
introPadding: number;
|
|
529
|
+
outroPadding: number;
|
|
530
|
+
padding: number;
|
|
531
|
+
suppressSpeech: boolean;
|
|
532
|
+
bgm?: undefined;
|
|
533
|
+
};
|
|
534
|
+
canvasSize: {
|
|
535
|
+
height: number;
|
|
536
|
+
width: number;
|
|
537
|
+
};
|
|
538
|
+
imageParams: {
|
|
539
|
+
images: {
|
|
540
|
+
"[CHARACTER_1_ID]": {
|
|
541
|
+
prompt: string;
|
|
542
|
+
type: string;
|
|
543
|
+
};
|
|
544
|
+
"[CHARACTER_2_ID]": {
|
|
545
|
+
prompt: string;
|
|
546
|
+
type: string;
|
|
547
|
+
};
|
|
548
|
+
girl?: undefined;
|
|
549
|
+
ani?: undefined;
|
|
550
|
+
presenter?: undefined;
|
|
551
|
+
optimus?: undefined;
|
|
552
|
+
};
|
|
553
|
+
style: string;
|
|
554
|
+
provider?: undefined;
|
|
555
|
+
};
|
|
556
|
+
movieParams: {
|
|
557
|
+
provider: string;
|
|
558
|
+
model?: undefined;
|
|
559
|
+
};
|
|
560
|
+
soundEffectParams: {
|
|
561
|
+
provider: string;
|
|
562
|
+
};
|
|
563
|
+
speechParams: {
|
|
564
|
+
speakers: {
|
|
565
|
+
Presenter: {
|
|
566
|
+
displayName: {
|
|
567
|
+
en: string;
|
|
568
|
+
};
|
|
569
|
+
voiceId: string;
|
|
570
|
+
lang?: undefined;
|
|
571
|
+
speechOptions?: undefined;
|
|
572
|
+
};
|
|
573
|
+
Announcer?: undefined;
|
|
574
|
+
Student?: undefined;
|
|
575
|
+
Teacher?: undefined;
|
|
576
|
+
};
|
|
577
|
+
};
|
|
578
|
+
};
|
|
579
|
+
scriptName: string;
|
|
580
|
+
systemPrompt: string;
|
|
581
|
+
title: string;
|
|
506
582
|
} | {
|
|
507
583
|
description: string;
|
|
508
584
|
filename: string;
|
|
@@ -749,6 +749,61 @@ export const promptTemplates = [
|
|
|
749
749
|
systemPrompt: "This script is for YouTube shorts. The first beat should be a hook, which describes the topic. Another AI will generate images for each beat based on the image prompt of that beat. Movie prompts must be written in English.",
|
|
750
750
|
title: "Short movie template",
|
|
751
751
|
},
|
|
752
|
+
{
|
|
753
|
+
description: "Template for Multi-character Story.",
|
|
754
|
+
filename: "sifi_story",
|
|
755
|
+
presentationStyle: {
|
|
756
|
+
$mulmocast: {
|
|
757
|
+
credit: "closing",
|
|
758
|
+
version: "1.1",
|
|
759
|
+
},
|
|
760
|
+
audioParams: {
|
|
761
|
+
audioVolume: 1,
|
|
762
|
+
bgmVolume: 0.2,
|
|
763
|
+
closingPadding: 0.8,
|
|
764
|
+
introPadding: 1,
|
|
765
|
+
outroPadding: 1,
|
|
766
|
+
padding: 0.3,
|
|
767
|
+
suppressSpeech: false,
|
|
768
|
+
},
|
|
769
|
+
canvasSize: {
|
|
770
|
+
height: 1024,
|
|
771
|
+
width: 1536,
|
|
772
|
+
},
|
|
773
|
+
imageParams: {
|
|
774
|
+
images: {
|
|
775
|
+
"[CHARACTER_1_ID]": {
|
|
776
|
+
prompt: "[IMAGE PROMPT FOR THIS CHARACTER]",
|
|
777
|
+
type: "imagePrompt",
|
|
778
|
+
},
|
|
779
|
+
"[CHARACTER_2_ID]": {
|
|
780
|
+
prompt: "[IMAGE PROMPT FOR THIS CHARACTER]",
|
|
781
|
+
type: "imagePrompt",
|
|
782
|
+
},
|
|
783
|
+
},
|
|
784
|
+
style: "<style>A dreamy, hyper-detailed anime style that blends photorealistic backgrounds with vibrant, saturated colors. The skies are often filled with luminous clouds, dazzling sunsets, or star-filled nights, rendered with a glowing, almost ethereal quality. Urban landscapes and rural scenery are meticulously illustrated, with attention to tiny details like reflections in puddles, neon lights, or the texture of grass swaying in the wind. Characters are drawn with soft, expressive features, standing out against the breathtaking environments, creating a sense of emotional depth and lyrical atmosphere. The overall mood is cinematic, romantic, and filled with a sense of fleeting beauty and longing.</style>",
|
|
785
|
+
},
|
|
786
|
+
movieParams: {
|
|
787
|
+
provider: "replicate",
|
|
788
|
+
},
|
|
789
|
+
soundEffectParams: {
|
|
790
|
+
provider: "replicate",
|
|
791
|
+
},
|
|
792
|
+
speechParams: {
|
|
793
|
+
speakers: {
|
|
794
|
+
Presenter: {
|
|
795
|
+
displayName: {
|
|
796
|
+
en: "Presenter",
|
|
797
|
+
},
|
|
798
|
+
voiceId: "shimmer",
|
|
799
|
+
},
|
|
800
|
+
},
|
|
801
|
+
},
|
|
802
|
+
},
|
|
803
|
+
scriptName: "story_with_characters.json",
|
|
804
|
+
systemPrompt: "Break the story into multiple beats, and put the story text in 'text' field. Generate image prompt for each character in the imageParams.images. Another AI will generate image for each beat based on its imagePrompt and specified characters in 'imageNames'. You don't need to repeat the image style in those image prompts. Use the JSON below as a template.",
|
|
805
|
+
title: "Multi-character Story",
|
|
806
|
+
},
|
|
752
807
|
{
|
|
753
808
|
description: "Template for A Movie Trailer.",
|
|
754
809
|
filename: "trailer",
|
|
@@ -594,6 +594,26 @@ export declare const scriptTemplates: ({
|
|
|
594
594
|
description?: undefined;
|
|
595
595
|
canvasSize?: undefined;
|
|
596
596
|
captionParams?: undefined;
|
|
597
|
+
} | {
|
|
598
|
+
$mulmocast: {
|
|
599
|
+
credit: string;
|
|
600
|
+
version: string;
|
|
601
|
+
};
|
|
602
|
+
beats: {
|
|
603
|
+
imageNames: string[];
|
|
604
|
+
imagePrompt: string;
|
|
605
|
+
text: string;
|
|
606
|
+
}[];
|
|
607
|
+
filename: string;
|
|
608
|
+
lang: string;
|
|
609
|
+
title: string;
|
|
610
|
+
references?: undefined;
|
|
611
|
+
htmlImageParams?: undefined;
|
|
612
|
+
imageParams?: undefined;
|
|
613
|
+
movieParams?: undefined;
|
|
614
|
+
description?: undefined;
|
|
615
|
+
canvasSize?: undefined;
|
|
616
|
+
captionParams?: undefined;
|
|
597
617
|
} | {
|
|
598
618
|
$mulmocast: {
|
|
599
619
|
credit: string;
|
|
@@ -1001,6 +1001,32 @@ export const scriptTemplates = [
|
|
|
1001
1001
|
},
|
|
1002
1002
|
title: "[TITLE: Brief, engaging title for the topic]",
|
|
1003
1003
|
},
|
|
1004
|
+
{
|
|
1005
|
+
$mulmocast: {
|
|
1006
|
+
credit: "closing",
|
|
1007
|
+
version: "1.1",
|
|
1008
|
+
},
|
|
1009
|
+
beats: [
|
|
1010
|
+
{
|
|
1011
|
+
imageNames: ["[CHARACTER_ID_1]", "[CHARACTER_ID_2]"],
|
|
1012
|
+
imagePrompt: "[IMAGE_PROMPT FOR THIS BEAT with both characters]",
|
|
1013
|
+
text: "[STORY TEXT FOR THIS BEAT FOR THIS BEAT]",
|
|
1014
|
+
},
|
|
1015
|
+
{
|
|
1016
|
+
imageNames: ["[CHARACTER_ID_1]"],
|
|
1017
|
+
imagePrompt: "[IMAGE_PROMPT FOR THIS BEAT with a single character]",
|
|
1018
|
+
text: "[STORY TEXT FOR THIS BEAT FOR THIS BEAT]",
|
|
1019
|
+
},
|
|
1020
|
+
{
|
|
1021
|
+
imageNames: ["[CHARACTER_ID_2]"],
|
|
1022
|
+
imagePrompt: "[IMAGE_PROMPT FOR THIS BEAT with another character]",
|
|
1023
|
+
text: "[STORY TEXT FOR THIS BEAT FOR THIS BEAT]",
|
|
1024
|
+
},
|
|
1025
|
+
],
|
|
1026
|
+
filename: "story_with_characters",
|
|
1027
|
+
lang: "en",
|
|
1028
|
+
title: "[TITLE: Brief, engaging title for the topic]",
|
|
1029
|
+
},
|
|
1004
1030
|
{
|
|
1005
1031
|
$mulmocast: {
|
|
1006
1032
|
credit: "closing",
|
|
@@ -63,6 +63,10 @@ export const templateDataSet = {
|
|
|
63
63
|
"```JSON\n" +
|
|
64
64
|
`{"$mulmocast":{"version":"1.1"},"title":"[TITLE: Brief, engaging title for the topic]","lang":"en","references":[{"url":"[SOURCE_URL: URL of the source material]","title":"[SOURCE_TITLE: Title of the referenced article, or paper]","type":"[SOURCE_TYPE: article, paper]"}],"movieParams":{"provider":"google"},"beats":[{"text":"[OPENING_BEAT: Introduce the topic with a hook. Reference the source material and set up why this topic matters. Usually 2-3 sentences that grab attention and provide context.]","imagePrompt":"[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]","moviePrompt":"[MOVIE_PROMPT: A movie prompt for that image.]"},{"text":"[MAIN_CONCEPT: Define or explain the core concept/idea. This should be the central focus of your narrative. Keep it clear and accessible.]","imagePrompt":"[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]","moviePrompt":"[MOVIE_PROMPT: A movie prompt for that image.]"},{"text":"[SUPPORTING_DETAIL_1: Additional context, examples, or elaboration that helps illustrate the main concept. This could include how it works, why it's important, or real-world applications.]","imagePrompt":"[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]","moviePrompt":"[MOVIE_PROMPT: A movie prompt for that image.]"},{"text":"[SUPPORTING_DETAIL_2: Continue with more examples, deeper explanation, or different aspects of the topic if needed.]","imagePrompt":"[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]","moviePrompt":"[MOVIE_PROMPT: A movie prompt for that image.]"},{"text":"[ADDITIONAL_BEATS: Add more beats as necessary to fully explore the topic. Complex topics may require 6-10+ beats to cover adequately. Each beat should advance the narrative or provide valuable information.]","imagePrompt":"[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]","moviePrompt":"[MOVIE_PROMPT: A movie prompt for that image.]"},{"text":"[CONCLUSION/IMPACT: Wrap up with the significance, implications, or key takeaway. Help the audience understand why this matters to them.]","imagePrompt":"[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]","moviePrompt":"[MOVIE_PROMPT: A movie prompt for that image.]"}],"canvasSize":{"width":720,"height":1280},"imageParams":{"style":"<style>Photo realistic, cinematic.</style>"}}\n` +
|
|
65
65
|
"```",
|
|
66
|
+
sifi_story: "Break the story into multiple beats, and put the story text in 'text' field. Generate image prompt for each character in the imageParams.images. Another AI will generate image for each beat based on its imagePrompt and specified characters in 'imageNames'. You don't need to repeat the image style in those image prompts. Use the JSON below as a template.\n" +
|
|
67
|
+
"```JSON\n" +
|
|
68
|
+
'{"$mulmocast":{"version":"1.1","credit":"closing"},"title":"[TITLE: Brief, engaging title for the topic]","lang":"en","beats":[{"text":"[STORY TEXT FOR THIS BEAT FOR THIS BEAT]","imagePrompt":"[IMAGE_PROMPT FOR THIS BEAT with both characters]","imageNames":["[CHARACTER_ID_1]","[CHARACTER_ID_2]"]},{"text":"[STORY TEXT FOR THIS BEAT FOR THIS BEAT]","imagePrompt":"[IMAGE_PROMPT FOR THIS BEAT with a single character]","imageNames":["[CHARACTER_ID_1]"]},{"text":"[STORY TEXT FOR THIS BEAT FOR THIS BEAT]","imagePrompt":"[IMAGE_PROMPT FOR THIS BEAT with another character]","imageNames":["[CHARACTER_ID_2]"]}],"canvasSize":{"width":1536,"height":1024},"imageParams":{"style":"<style>A dreamy, hyper-detailed anime style that blends photorealistic backgrounds with vibrant, saturated colors. The skies are often filled with luminous clouds, dazzling sunsets, or star-filled nights, rendered with a glowing, almost ethereal quality. Urban landscapes and rural scenery are meticulously illustrated, with attention to tiny details like reflections in puddles, neon lights, or the texture of grass swaying in the wind. Characters are drawn with soft, expressive features, standing out against the breathtaking environments, creating a sense of emotional depth and lyrical atmosphere. The overall mood is cinematic, romantic, and filled with a sense of fleeting beauty and longing.</style>","images":{"[CHARACTER_1_ID]":{"type":"imagePrompt","prompt":"[IMAGE PROMPT FOR THIS CHARACTER]"},"[CHARACTER_2_ID]":{"type":"imagePrompt","prompt":"[IMAGE PROMPT FOR THIS CHARACTER]"}}}}\n' +
|
|
69
|
+
"```",
|
|
66
70
|
trailer: "This script is for a movie trailer. Another AI will generate images for each beat based on the image prompt of that beat. Movie prompts must be written in English.\n" +
|
|
67
71
|
"```JSON\n" +
|
|
68
72
|
'{"$mulmocast":{"version":"1.1"},"title":"[TITLE: Brief, engaging title for the topic]","lang":"en","references":[{"url":"[SOURCE_URL: URL of the source material]","title":"[SOURCE_TITLE: Title of the referenced article, or paper]","type":"[SOURCE_TYPE: article, paper]"}],"movieParams":{"provider":"google"},"beats":[{"duration":5,"imagePrompt":"[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]","moviePrompt":"[MOVIE_PROMPT: A movie prompt for that image.]"},{"duration":5,"imagePrompt":"[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]","moviePrompt":"[MOVIE_PROMPT: A movie prompt for that image.]"},{"duration":5,"imagePrompt":"[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]","moviePrompt":"[MOVIE_PROMPT: A movie prompt for that image.]"},{"duration":5,"imagePrompt":"[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]","moviePrompt":"[MOVIE_PROMPT: A movie prompt for that image.]"},{"duration":5,"imagePrompt":"[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]","moviePrompt":"[MOVIE_PROMPT: A movie prompt for that image.]"},{"duration":5,"imagePrompt":"[IMAGE_PROMPT: A prompt for the image to be generated for this beat.]","moviePrompt":"[MOVIE_PROMPT: A movie prompt for that image.]"}],"canvasSize":{"width":1280,"height":720},"imageParams":{"style":"<style>Photo realistic, cinematic.</style>"},"audioParams":{"padding":0,"introPadding":0,"closingPadding":0,"outroPadding":2.5,"bgm":{"kind":"url","url":"https://raw.githubusercontent.com/receptron/mulmocast-media/refs/heads/main/bgms/trailer_dramatic.mp3"}}}\n' +
|
package/lib/types/schema.d.ts
CHANGED
|
@@ -5702,6 +5702,7 @@ export declare const mulmoStudioBeatSchema: z.ZodObject<{
|
|
|
5702
5702
|
soundEffectFile: z.ZodOptional<z.ZodString>;
|
|
5703
5703
|
lipSyncFile: z.ZodOptional<z.ZodString>;
|
|
5704
5704
|
captionFile: z.ZodOptional<z.ZodString>;
|
|
5705
|
+
htmlImageFile: z.ZodOptional<z.ZodString>;
|
|
5705
5706
|
}, "strict", z.ZodTypeAny, {
|
|
5706
5707
|
duration?: number | undefined;
|
|
5707
5708
|
startAt?: number | undefined;
|
|
@@ -5716,6 +5717,7 @@ export declare const mulmoStudioBeatSchema: z.ZodObject<{
|
|
|
5716
5717
|
soundEffectFile?: string | undefined;
|
|
5717
5718
|
lipSyncFile?: string | undefined;
|
|
5718
5719
|
captionFile?: string | undefined;
|
|
5720
|
+
htmlImageFile?: string | undefined;
|
|
5719
5721
|
}, {
|
|
5720
5722
|
duration?: number | undefined;
|
|
5721
5723
|
startAt?: number | undefined;
|
|
@@ -5730,6 +5732,7 @@ export declare const mulmoStudioBeatSchema: z.ZodObject<{
|
|
|
5730
5732
|
soundEffectFile?: string | undefined;
|
|
5731
5733
|
lipSyncFile?: string | undefined;
|
|
5732
5734
|
captionFile?: string | undefined;
|
|
5735
|
+
htmlImageFile?: string | undefined;
|
|
5733
5736
|
}>;
|
|
5734
5737
|
export declare const mulmoStudioMultiLingualDataSchema: z.ZodObject<{
|
|
5735
5738
|
multiLingualTexts: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
@@ -8325,6 +8328,7 @@ export declare const mulmoStudioSchema: z.ZodObject<{
|
|
|
8325
8328
|
soundEffectFile: z.ZodOptional<z.ZodString>;
|
|
8326
8329
|
lipSyncFile: z.ZodOptional<z.ZodString>;
|
|
8327
8330
|
captionFile: z.ZodOptional<z.ZodString>;
|
|
8331
|
+
htmlImageFile: z.ZodOptional<z.ZodString>;
|
|
8328
8332
|
}, "strict", z.ZodTypeAny, {
|
|
8329
8333
|
duration?: number | undefined;
|
|
8330
8334
|
startAt?: number | undefined;
|
|
@@ -8339,6 +8343,7 @@ export declare const mulmoStudioSchema: z.ZodObject<{
|
|
|
8339
8343
|
soundEffectFile?: string | undefined;
|
|
8340
8344
|
lipSyncFile?: string | undefined;
|
|
8341
8345
|
captionFile?: string | undefined;
|
|
8346
|
+
htmlImageFile?: string | undefined;
|
|
8342
8347
|
}, {
|
|
8343
8348
|
duration?: number | undefined;
|
|
8344
8349
|
startAt?: number | undefined;
|
|
@@ -8353,6 +8358,7 @@ export declare const mulmoStudioSchema: z.ZodObject<{
|
|
|
8353
8358
|
soundEffectFile?: string | undefined;
|
|
8354
8359
|
lipSyncFile?: string | undefined;
|
|
8355
8360
|
captionFile?: string | undefined;
|
|
8361
|
+
htmlImageFile?: string | undefined;
|
|
8356
8362
|
}>, "many">;
|
|
8357
8363
|
}, "strict", z.ZodTypeAny, {
|
|
8358
8364
|
beats: {
|
|
@@ -8369,6 +8375,7 @@ export declare const mulmoStudioSchema: z.ZodObject<{
|
|
|
8369
8375
|
soundEffectFile?: string | undefined;
|
|
8370
8376
|
lipSyncFile?: string | undefined;
|
|
8371
8377
|
captionFile?: string | undefined;
|
|
8378
|
+
htmlImageFile?: string | undefined;
|
|
8372
8379
|
}[];
|
|
8373
8380
|
script: {
|
|
8374
8381
|
lang: string;
|
|
@@ -8710,6 +8717,7 @@ export declare const mulmoStudioSchema: z.ZodObject<{
|
|
|
8710
8717
|
soundEffectFile?: string | undefined;
|
|
8711
8718
|
lipSyncFile?: string | undefined;
|
|
8712
8719
|
captionFile?: string | undefined;
|
|
8720
|
+
htmlImageFile?: string | undefined;
|
|
8713
8721
|
}[];
|
|
8714
8722
|
script: {
|
|
8715
8723
|
lang: string;
|
package/lib/types/schema.js
CHANGED
|
@@ -396,6 +396,7 @@ export const mulmoStudioBeatSchema = z
|
|
|
396
396
|
soundEffectFile: z.string().optional(), // path to the sound effect file
|
|
397
397
|
lipSyncFile: z.string().optional(), // path to the lip sync file
|
|
398
398
|
captionFile: z.string().optional(), // path to the caption image
|
|
399
|
+
htmlImageFile: z.string().optional(), // path to the html image
|
|
399
400
|
})
|
|
400
401
|
.strict();
|
|
401
402
|
export const mulmoStudioMultiLingualDataSchema = z.object({
|
package/lib/utils/context.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare const createStudioData: (_mulmoScript: MulmoScript, fileName: str
|
|
|
14
14
|
soundEffectFile?: string | undefined;
|
|
15
15
|
lipSyncFile?: string | undefined;
|
|
16
16
|
captionFile?: string | undefined;
|
|
17
|
+
htmlImageFile?: string | undefined;
|
|
17
18
|
}[];
|
|
18
19
|
script: {
|
|
19
20
|
lang: string;
|
|
@@ -360,6 +361,7 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
|
|
|
360
361
|
soundEffectFile?: string | undefined;
|
|
361
362
|
lipSyncFile?: string | undefined;
|
|
362
363
|
captionFile?: string | undefined;
|
|
364
|
+
htmlImageFile?: string | undefined;
|
|
363
365
|
}[];
|
|
364
366
|
script: {
|
|
365
367
|
lang: string;
|
package/lib/utils/file.d.ts
CHANGED
|
@@ -24,7 +24,10 @@ export declare const getAudioFilePath: (audioDirPath: string, dirName: string, f
|
|
|
24
24
|
export declare const getAudioArtifactFilePath: (context: MulmoStudioContext) => string;
|
|
25
25
|
export declare const getOutputVideoFilePath: (outDirPath: string, fileName: string, lang?: string, caption?: string) => string;
|
|
26
26
|
export declare const imageSuffix = "p";
|
|
27
|
-
export declare const getBeatPngImagePath: (context: MulmoStudioContext, index: number) =>
|
|
27
|
+
export declare const getBeatPngImagePath: (context: MulmoStudioContext, index: number) => {
|
|
28
|
+
imagePath: string;
|
|
29
|
+
htmlImageFile: string;
|
|
30
|
+
};
|
|
28
31
|
export declare const getBeatMoviePaths: (context: MulmoStudioContext, index: number) => {
|
|
29
32
|
movieFile: string;
|
|
30
33
|
soundEffectFile: string;
|
package/lib/utils/file.js
CHANGED
|
@@ -89,10 +89,10 @@ export const imageSuffix = "p";
|
|
|
89
89
|
export const getBeatPngImagePath = (context, index) => {
|
|
90
90
|
const imageProjectDirPath = MulmoStudioContextMethods.getImageProjectDirPath(context);
|
|
91
91
|
const beat = context.studio.script.beats[index]; // beat could be undefined only in a test case.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
return
|
|
92
|
+
const filename = beat?.id ? `${beat.id}` : `${index}${imageSuffix}`;
|
|
93
|
+
const imagePath = `${imageProjectDirPath}/${filename}.png`;
|
|
94
|
+
const htmlImageFile = `${imageProjectDirPath}/${filename}_html.png`;
|
|
95
|
+
return { imagePath, htmlImageFile };
|
|
96
96
|
};
|
|
97
97
|
export const getBeatMoviePaths = (context, index) => {
|
|
98
98
|
const imageProjectDirPath = MulmoStudioContextMethods.getImageProjectDirPath(context);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mulmocast",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.6",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.node.js",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"prompt": "npx tsx ./src/cli/bin.ts tool prompt",
|
|
51
51
|
"schema": "npx tsx ./src/cli/bin.ts tool schema",
|
|
52
52
|
"story_to_script": "npx tsx ./src/cli/bin.ts tool story_to_script",
|
|
53
|
+
"whisper": "npx tsx ./src/cli/bin.ts tool whisper",
|
|
53
54
|
"latest": "yarn upgrade-interactive --latest",
|
|
54
55
|
"format": "prettier --write '{src,scripts,assets/templates,assets/styles,draft,ideason,scripts_mag2,proto,test,batch,graphai,output,docs/scripts}/**/*.{ts,json,yaml}'",
|
|
55
56
|
"deep_research": "npx tsx ./src/tools/deep_research.ts",
|
|
@@ -66,20 +67,20 @@
|
|
|
66
67
|
"homepage": "https://github.com/receptron/mulmocast-cli#readme",
|
|
67
68
|
"dependencies": {
|
|
68
69
|
"@google-cloud/text-to-speech": "^6.2.0",
|
|
69
|
-
"@google/genai": "^1.
|
|
70
|
+
"@google/genai": "^1.15.0",
|
|
70
71
|
"@graphai/anthropic_agent": "^2.0.11",
|
|
71
72
|
"@graphai/browserless_agent": "^2.0.1",
|
|
72
73
|
"@graphai/gemini_agent": "^2.0.1",
|
|
73
74
|
"@graphai/groq_agent": "^2.0.2",
|
|
74
75
|
"@graphai/input_agents": "^1.0.2",
|
|
75
|
-
"@graphai/openai_agent": "^2.0.
|
|
76
|
+
"@graphai/openai_agent": "^2.0.7",
|
|
76
77
|
"@graphai/stream_agent_filter": "^2.0.2",
|
|
77
78
|
"@graphai/vanilla": "^2.0.12",
|
|
78
79
|
"@graphai/vanilla_node_agents": "^2.0.4",
|
|
79
80
|
"@inquirer/input": "^4.2.1",
|
|
80
81
|
"@inquirer/select": "^4.3.1",
|
|
81
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
82
|
-
"@tavily/core": "^0.5.
|
|
82
|
+
"@modelcontextprotocol/sdk": "^1.17.3",
|
|
83
|
+
"@tavily/core": "^0.5.11",
|
|
83
84
|
"canvas": "^3.2.0",
|
|
84
85
|
"clipboardy": "^4.0.0",
|
|
85
86
|
"dotenv": "^17.2.1",
|
|
@@ -87,8 +88,8 @@
|
|
|
87
88
|
"graphai": "^2.0.14",
|
|
88
89
|
"marked": "^16.2.0",
|
|
89
90
|
"ora": "^8.2.0",
|
|
90
|
-
"puppeteer": "^24.
|
|
91
|
-
"replicate": "^1.0
|
|
91
|
+
"puppeteer": "^24.17.0",
|
|
92
|
+
"replicate": "^1.1.0",
|
|
92
93
|
"yaml": "^2.8.1",
|
|
93
94
|
"yargs": "^18.0.0",
|
|
94
95
|
"zod": "^3.25.76",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$mulmocast": {
|
|
3
|
+
"version": "1.1",
|
|
4
|
+
"credit": "closing"
|
|
5
|
+
},
|
|
6
|
+
"title": "[TITLE: Brief, engaging title for the topic]",
|
|
7
|
+
"lang": "en",
|
|
8
|
+
"beats": [
|
|
9
|
+
{
|
|
10
|
+
"text": "[STORY TEXT FOR THIS BEAT FOR THIS BEAT]",
|
|
11
|
+
"imagePrompt": "[IMAGE_PROMPT FOR THIS BEAT with both characters]",
|
|
12
|
+
"imageNames": ["[CHARACTER_ID_1]", "[CHARACTER_ID_2]"]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"text": "[STORY TEXT FOR THIS BEAT FOR THIS BEAT]",
|
|
16
|
+
"imagePrompt": "[IMAGE_PROMPT FOR THIS BEAT with a single character]",
|
|
17
|
+
"imageNames": ["[CHARACTER_ID_1]"]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"text": "[STORY TEXT FOR THIS BEAT FOR THIS BEAT]",
|
|
21
|
+
"imagePrompt": "[IMAGE_PROMPT FOR THIS BEAT with another character]",
|
|
22
|
+
"imageNames": ["[CHARACTER_ID_2]"]
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|