mulmocast 0.0.22 → 0.0.24
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 +5 -0
- package/assets/html/caption.html +2 -0
- package/lib/actions/audio.d.ts +2 -2
- package/lib/actions/audio.js +8 -7
- package/lib/actions/captions.js +7 -5
- package/lib/actions/images.d.ts +9 -5
- package/lib/actions/images.js +73 -36
- package/lib/actions/movie.d.ts +2 -2
- package/lib/actions/movie.js +24 -9
- package/lib/agents/combine_audio_files_agent.js +9 -5
- package/lib/agents/image_openai_agent.d.ts +2 -0
- package/lib/agents/image_openai_agent.js +3 -2
- package/lib/agents/index.d.ts +2 -1
- package/lib/agents/index.js +2 -1
- package/lib/agents/movie_replicate_agent.d.ts +23 -0
- package/lib/agents/movie_replicate_agent.js +93 -0
- package/lib/agents/tts_elevenlabs_agent.js +2 -2
- package/lib/agents/tts_nijivoice_agent.js +3 -2
- package/lib/agents/tts_openai_agent.js +3 -2
- package/lib/cli/commands/tool/scripting/builder.d.ts +3 -1
- package/lib/cli/commands/tool/scripting/builder.js +5 -0
- package/lib/cli/commands/tool/scripting/handler.d.ts +1 -0
- package/lib/cli/commands/tool/scripting/handler.js +13 -4
- package/lib/cli/commands/tool/story_to_script/builder.d.ts +1 -1
- package/lib/cli/helpers.js +8 -3
- package/lib/methods/mulmo_presentation_style.d.ts +2 -1
- package/lib/methods/mulmo_presentation_style.js +21 -2
- package/lib/methods/mulmo_studio_context.js +1 -1
- package/lib/tools/create_mulmo_script_from_url.d.ts +1 -0
- package/lib/tools/create_mulmo_script_from_url.js +129 -43
- package/lib/types/schema.d.ts +793 -163
- package/lib/types/schema.js +32 -1
- package/lib/types/type.d.ts +9 -2
- package/lib/utils/ffmpeg_utils.d.ts +1 -1
- package/lib/utils/ffmpeg_utils.js +2 -2
- package/lib/utils/preprocess.d.ts +29 -6
- package/lib/utils/prompt.d.ts +2 -1
- package/lib/utils/prompt.js +10 -0
- package/lib/utils/utils.d.ts +3 -0
- package/lib/utils/utils.js +47 -0
- package/package.json +3 -2
- package/scripts/templates/presentation.json +123 -0
- package/scripts/templates/presentation.json~ +119 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import { GraphAILogger } from "graphai";
|
|
3
|
+
import Replicate from "replicate";
|
|
4
|
+
async function generateMovie(model, apiKey, prompt, imagePath, aspectRatio, duration) {
|
|
5
|
+
const replicate = new Replicate({
|
|
6
|
+
auth: apiKey,
|
|
7
|
+
});
|
|
8
|
+
const input = {
|
|
9
|
+
prompt: prompt,
|
|
10
|
+
duration: duration,
|
|
11
|
+
image: undefined,
|
|
12
|
+
start_image: undefined,
|
|
13
|
+
aspect_ratio: aspectRatio, // only for bytedance/seedance-1-lite
|
|
14
|
+
// resolution: "720p", // only for bytedance/seedance-1-lite
|
|
15
|
+
// fps: 24, // only for bytedance/seedance-1-lite
|
|
16
|
+
// camera_fixed: false, // only for bytedance/seedance-1-lite
|
|
17
|
+
// mode: "standard" // only for kwaivgi/kling-v2.1
|
|
18
|
+
// negative_prompt: "" // only for kwaivgi/kling-v2.1
|
|
19
|
+
};
|
|
20
|
+
// Add image if provided (for image-to-video generation)
|
|
21
|
+
if (imagePath) {
|
|
22
|
+
const buffer = readFileSync(imagePath);
|
|
23
|
+
const base64Image = `data:image/png;base64,${buffer.toString("base64")}`;
|
|
24
|
+
if (model === "kwaivgi/kling-v2.1") {
|
|
25
|
+
input.start_image = base64Image;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
input.image = base64Image;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const output = await replicate.run(model ?? "bytedance/seedance-1-lite", { input });
|
|
33
|
+
// Download the generated video
|
|
34
|
+
if (output && typeof output === "object" && "url" in output) {
|
|
35
|
+
const videoUrl = output.url();
|
|
36
|
+
const videoResponse = await fetch(videoUrl);
|
|
37
|
+
if (!videoResponse.ok) {
|
|
38
|
+
throw new Error(`Error downloading video: ${videoResponse.status} - ${videoResponse.statusText}`);
|
|
39
|
+
}
|
|
40
|
+
const arrayBuffer = await videoResponse.arrayBuffer();
|
|
41
|
+
return Buffer.from(arrayBuffer);
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
GraphAILogger.info("Replicate generation error:", error);
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export const getAspectRatio = (canvasSize) => {
|
|
51
|
+
if (canvasSize.width > canvasSize.height) {
|
|
52
|
+
return "16:9";
|
|
53
|
+
}
|
|
54
|
+
else if (canvasSize.width < canvasSize.height) {
|
|
55
|
+
return "9:16";
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
return "1:1";
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
export const movieReplicateAgent = async ({ namedInputs, params, config }) => {
|
|
62
|
+
const { prompt, imagePath } = namedInputs;
|
|
63
|
+
const aspectRatio = getAspectRatio(params.canvasSize);
|
|
64
|
+
const duration = params.duration ?? 5;
|
|
65
|
+
const apiKey = config?.apiKey ?? process.env.REPLICATE_API_TOKEN;
|
|
66
|
+
if (!apiKey) {
|
|
67
|
+
throw new Error("REPLICATE_API_TOKEN environment variable is required");
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const buffer = await generateMovie(params.model, apiKey, prompt, imagePath, aspectRatio, duration);
|
|
71
|
+
if (buffer) {
|
|
72
|
+
return { buffer };
|
|
73
|
+
}
|
|
74
|
+
throw new Error("ERROR: generateMovie returned undefined");
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
GraphAILogger.info("Failed to generate movie:", error.message);
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const movieReplicateAgentInfo = {
|
|
82
|
+
name: "movieReplicateAgent",
|
|
83
|
+
agent: movieReplicateAgent,
|
|
84
|
+
mock: movieReplicateAgent,
|
|
85
|
+
samples: [],
|
|
86
|
+
description: "Replicate Movie agent using seedance-1-lite",
|
|
87
|
+
category: ["movie"],
|
|
88
|
+
author: "Receptron Team",
|
|
89
|
+
repository: "https://github.com/receptron/mulmocast-cli/",
|
|
90
|
+
license: "MIT",
|
|
91
|
+
environmentVariables: ["REPLICATE_API_TOKEN"],
|
|
92
|
+
};
|
|
93
|
+
export default movieReplicateAgentInfo;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { GraphAILogger } from "graphai";
|
|
2
|
-
export const ttsElevenlabsAgent = async ({ namedInputs, params }) => {
|
|
2
|
+
export const ttsElevenlabsAgent = async ({ namedInputs, params, config }) => {
|
|
3
3
|
const { text } = namedInputs;
|
|
4
4
|
const { voice, model, stability, similarityBoost, suppressError } = params;
|
|
5
|
-
const apiKey = process.env.ELEVENLABS_API_KEY;
|
|
5
|
+
const apiKey = config?.apiKey ?? process.env.ELEVENLABS_API_KEY;
|
|
6
6
|
if (!apiKey) {
|
|
7
7
|
throw new Error("ELEVENLABS_API_KEY environment variable is required");
|
|
8
8
|
}
|
|
@@ -6,8 +6,9 @@ const errorMessage = [
|
|
|
6
6
|
"1. Obtain an API key from Niji Voice (https://platform.nijivoice.com/) and set it as the NIJIVOICE_API_KEY environment variable.",
|
|
7
7
|
'2. Use OpenAI\'s TTS instead of Niji Voice by changing speechParams.provider from "nijivoice" to "openai".',
|
|
8
8
|
].join("\n");
|
|
9
|
-
export const ttsNijivoiceAgent = async ({ params, namedInputs }) => {
|
|
10
|
-
const {
|
|
9
|
+
export const ttsNijivoiceAgent = async ({ params, namedInputs, config }) => {
|
|
10
|
+
const { suppressError, voice, speed, speed_global } = params;
|
|
11
|
+
const { apiKey } = config ?? {};
|
|
11
12
|
const { text } = namedInputs;
|
|
12
13
|
assert(apiKey ?? nijovoiceApiKey, errorMessage);
|
|
13
14
|
const url = `https://api.nijivoice.com/api/platform/v1/voice-actors/${voice}/generate-voice`;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { GraphAILogger } from "graphai";
|
|
2
2
|
import OpenAI from "openai";
|
|
3
|
-
export const ttsOpenaiAgent = async ({ namedInputs, params }) => {
|
|
3
|
+
export const ttsOpenaiAgent = async ({ namedInputs, params, config }) => {
|
|
4
4
|
const { text } = namedInputs;
|
|
5
|
-
const {
|
|
5
|
+
const { model, voice, suppressError, instructions } = params;
|
|
6
|
+
const { apiKey } = config ?? {};
|
|
6
7
|
const openai = new OpenAI({ apiKey });
|
|
7
8
|
try {
|
|
8
9
|
const tts_options = {
|
|
@@ -5,6 +5,8 @@ export declare const builder: (yargs: Argv) => Argv<{
|
|
|
5
5
|
b: string | undefined;
|
|
6
6
|
} & {
|
|
7
7
|
u: string[] | never[];
|
|
8
|
+
} & {
|
|
9
|
+
"input-file": string | undefined;
|
|
8
10
|
} & {
|
|
9
11
|
i: boolean | undefined;
|
|
10
12
|
} & {
|
|
@@ -14,7 +16,7 @@ export declare const builder: (yargs: Argv) => Argv<{
|
|
|
14
16
|
} & {
|
|
15
17
|
s: string;
|
|
16
18
|
} & {
|
|
17
|
-
llm: "
|
|
19
|
+
llm: "anthropic" | "openAI" | "gemini" | "groq" | undefined;
|
|
18
20
|
} & {
|
|
19
21
|
llm_model: string | undefined;
|
|
20
22
|
}>;
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import { getBaseDirPath, getFullPath } from "../../../../utils/file.js";
|
|
2
2
|
import { outDirName, cacheDirName } from "../../../../utils/const.js";
|
|
3
3
|
import { getUrlsIfNeeded, selectTemplate } from "../../../../utils/inquirer.js";
|
|
4
|
-
import { createMulmoScriptFromUrl } from "../../../../tools/create_mulmo_script_from_url.js";
|
|
4
|
+
import { createMulmoScriptFromUrl, createMulmoScriptFromFile } from "../../../../tools/create_mulmo_script_from_url.js";
|
|
5
5
|
import { createMulmoScriptInteractively } from "../../../../tools/create_mulmo_script_interactively.js";
|
|
6
6
|
import { setGraphAILogger } from "../../../../cli/helpers.js";
|
|
7
7
|
export const handler = async (argv) => {
|
|
8
|
-
const { o: outdir, b: basedir, v: verbose, i: interactive, c: cache, s: filename, llm, llm_model } = argv;
|
|
8
|
+
const { o: outdir, b: basedir, "input-file": inputFile, v: verbose, i: interactive, c: cache, s: filename, llm, llm_model } = argv;
|
|
9
9
|
let { t: template } = argv;
|
|
10
10
|
const urls = argv.u || [];
|
|
11
11
|
const baseDirPath = getBaseDirPath(basedir);
|
|
12
12
|
const outDirPath = getFullPath(baseDirPath, outdir ?? outDirName);
|
|
13
13
|
const cacheDirPath = getFullPath(outDirPath, cache ?? cacheDirName);
|
|
14
14
|
if (!template) {
|
|
15
|
-
|
|
15
|
+
if (interactive) {
|
|
16
|
+
template = await selectTemplate();
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
template = "business";
|
|
20
|
+
}
|
|
16
21
|
}
|
|
17
22
|
setGraphAILogger(verbose, {
|
|
18
23
|
baseDirPath,
|
|
@@ -22,13 +27,17 @@ export const handler = async (argv) => {
|
|
|
22
27
|
urls,
|
|
23
28
|
interactive,
|
|
24
29
|
filename,
|
|
30
|
+
inputFile,
|
|
25
31
|
llm,
|
|
26
32
|
llm_model,
|
|
27
33
|
});
|
|
28
|
-
const context = { outDirPath, templateName: template, urls, filename: filename, cacheDirPath, llm_model, llm };
|
|
34
|
+
const context = { outDirPath, templateName: template, urls, filename: filename, cacheDirPath, llm_model, llm, verbose };
|
|
29
35
|
if (interactive) {
|
|
30
36
|
await createMulmoScriptInteractively(context);
|
|
31
37
|
}
|
|
38
|
+
if (inputFile) {
|
|
39
|
+
await createMulmoScriptFromFile(inputFile, context);
|
|
40
|
+
}
|
|
32
41
|
else {
|
|
33
42
|
context.urls = await getUrlsIfNeeded(urls);
|
|
34
43
|
await createMulmoScriptFromUrl(context);
|
|
@@ -10,7 +10,7 @@ export declare const builder: (yargs: Argv) => Argv<{
|
|
|
10
10
|
} & {
|
|
11
11
|
beats_per_scene: number;
|
|
12
12
|
} & {
|
|
13
|
-
llm: "
|
|
13
|
+
llm: "anthropic" | "openAI" | "gemini" | "groq" | undefined;
|
|
14
14
|
} & {
|
|
15
15
|
llm_model: string | undefined;
|
|
16
16
|
} & {
|
package/lib/cli/helpers.js
CHANGED
|
@@ -7,7 +7,7 @@ import { isHttp } from "../utils/utils.js";
|
|
|
7
7
|
import { createOrUpdateStudioData } from "../utils/preprocess.js";
|
|
8
8
|
import { outDirName, imageDirName, audioDirName } from "../utils/const.js";
|
|
9
9
|
import { translate } from "../actions/translate.js";
|
|
10
|
-
import { mulmoPresentationStyleSchema, mulmoStudioMultiLingualSchema } from "../types/schema.js";
|
|
10
|
+
import { mulmoCaptionParamsSchema, mulmoPresentationStyleSchema, mulmoStudioMultiLingualSchema } from "../types/schema.js";
|
|
11
11
|
export const setGraphAILogger = (verbose, logValues) => {
|
|
12
12
|
if (verbose) {
|
|
13
13
|
if (logValues) {
|
|
@@ -126,13 +126,18 @@ export const initializeContext = async (argv) => {
|
|
|
126
126
|
// validate mulmoStudioSchema. skip if __test_invalid__ is true
|
|
127
127
|
const studio = createOrUpdateStudioData(mulmoScript, currentStudio?.mulmoData, fileName);
|
|
128
128
|
const multiLingual = getMultiLingual(outputMultilingualFilePath, studio.beats.length);
|
|
129
|
+
if (argv.c) {
|
|
130
|
+
studio.script.captionParams = mulmoCaptionParamsSchema.parse({
|
|
131
|
+
...(studio.script.captionParams ?? {}),
|
|
132
|
+
lang: argv.c,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
129
135
|
return {
|
|
130
136
|
studio,
|
|
131
137
|
fileDirs: files,
|
|
132
138
|
force: Boolean(argv.f),
|
|
133
139
|
dryRun: Boolean(argv.dryRun),
|
|
134
140
|
lang: argv.l,
|
|
135
|
-
caption: argv.c,
|
|
136
141
|
sessionState: {
|
|
137
142
|
inSession: {
|
|
138
143
|
audio: false,
|
|
@@ -160,7 +165,7 @@ export const initializeContext = async (argv) => {
|
|
|
160
165
|
}
|
|
161
166
|
};
|
|
162
167
|
export const runTranslateIfNeeded = async (context, argv) => {
|
|
163
|
-
if (argv.l ||
|
|
168
|
+
if (argv.l || context.studio.script.captionParams?.lang) {
|
|
164
169
|
GraphAILogger.log("run translate");
|
|
165
170
|
await translate(context);
|
|
166
171
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
|
-
import { MulmoCanvasDimension, MulmoBeat, SpeechOptions, Text2SpeechProvider, Text2ImageAgentInfo, BeatMediaType, MulmoPresentationStyle, SpeakerData } from "../types/index.js";
|
|
2
|
+
import { MulmoCanvasDimension, MulmoBeat, SpeechOptions, Text2SpeechProvider, Text2ImageAgentInfo, Text2HtmlAgentInfo, BeatMediaType, MulmoPresentationStyle, SpeakerData } from "../types/index.js";
|
|
3
3
|
export declare const MulmoPresentationStyleMethods: {
|
|
4
4
|
getCanvasSize(presentationStyle: MulmoPresentationStyle): MulmoCanvasDimension;
|
|
5
5
|
getSpeechProvider(presentationStyle: MulmoPresentationStyle): Text2SpeechProvider;
|
|
@@ -10,5 +10,6 @@ export declare const MulmoPresentationStyleMethods: {
|
|
|
10
10
|
getProvider(presentationStyle: MulmoPresentationStyle, beat: MulmoBeat): Text2SpeechProvider;
|
|
11
11
|
getVoiceId(presentationStyle: MulmoPresentationStyle, beat: MulmoBeat): string;
|
|
12
12
|
getImageAgentInfo(presentationStyle: MulmoPresentationStyle, dryRun?: boolean): Text2ImageAgentInfo;
|
|
13
|
+
getHtmlImageAgentInfo(presentationStyle: MulmoPresentationStyle): Text2HtmlAgentInfo;
|
|
13
14
|
getImageType(_: MulmoPresentationStyle, beat: MulmoBeat): BeatMediaType;
|
|
14
15
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
|
-
import {
|
|
2
|
+
import { userAssert } from "../utils/utils.js";
|
|
3
|
+
import { text2ImageProviderSchema, text2HtmlImageProviderSchema, text2SpeechProviderSchema, mulmoCanvasDimensionSchema } from "../types/schema.js";
|
|
3
4
|
import { defaultOpenAIImageModel } from "../utils/const.js";
|
|
4
5
|
const defaultTextSlideStyles = [
|
|
5
6
|
'*,*::before,*::after{box-sizing:border-box}body,h1,h2,h3,h4,p,figure,blockquote,dl,dd{margin:0}ul[role="list"],ol[role="list"]{list-style:none}html:focus-within{scroll-behavior:smooth}body{min-height:100vh;text-rendering:optimizeSpeed;line-height:1.5}a:not([class]){text-decoration-skip-ink:auto}img,picture{max-width:100%;display:block}input,button,textarea,select{font:inherit}@media(prefers-reduced-motion:reduce){html:focus-within{scroll-behavior:auto}*,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important;scroll-behavior:auto !important}}',
|
|
@@ -42,7 +43,11 @@ export const MulmoPresentationStyleMethods = {
|
|
|
42
43
|
return { ...presentationStyle.speechParams.speakers[beat.speaker].speechOptions, ...beat.speechOptions };
|
|
43
44
|
},
|
|
44
45
|
getSpeaker(presentationStyle, beat) {
|
|
45
|
-
|
|
46
|
+
userAssert(!!presentationStyle?.speechParams?.speakers, "presentationStyle.speechParams.speakers is not set!!");
|
|
47
|
+
userAssert(!!beat?.speaker, "beat.speaker is not set");
|
|
48
|
+
const speaker = presentationStyle.speechParams.speakers[beat.speaker];
|
|
49
|
+
userAssert(!!speaker, `speaker is not set: speaker "${beat.speaker}"`);
|
|
50
|
+
return speaker;
|
|
46
51
|
},
|
|
47
52
|
getProvider(presentationStyle, beat) {
|
|
48
53
|
const speaker = MulmoPresentationStyleMethods.getSpeaker(presentationStyle, beat);
|
|
@@ -65,6 +70,20 @@ export const MulmoPresentationStyleMethods = {
|
|
|
65
70
|
imageParams: { ...defaultImageParams, ...presentationStyle.imageParams },
|
|
66
71
|
};
|
|
67
72
|
},
|
|
73
|
+
getHtmlImageAgentInfo(presentationStyle) {
|
|
74
|
+
const provider = text2HtmlImageProviderSchema.parse(presentationStyle.htmlImageParams?.provider);
|
|
75
|
+
const agent = provider === "anthropic" ? "anthropicAgent" : "openAIAgent";
|
|
76
|
+
const model = presentationStyle.htmlImageParams?.model
|
|
77
|
+
? presentationStyle.htmlImageParams?.model
|
|
78
|
+
: provider === "anthropic"
|
|
79
|
+
? "claude-3-7-sonnet-20250219"
|
|
80
|
+
: "gpt-4o-mini";
|
|
81
|
+
return {
|
|
82
|
+
provider,
|
|
83
|
+
agent,
|
|
84
|
+
model,
|
|
85
|
+
};
|
|
86
|
+
},
|
|
68
87
|
getImageType(_, beat) {
|
|
69
88
|
return beat.image?.type == "movie" ? "movie" : "image";
|
|
70
89
|
},
|
|
@@ -44,7 +44,7 @@ export const MulmoStudioContextMethods = {
|
|
|
44
44
|
return context.studio.filename;
|
|
45
45
|
},
|
|
46
46
|
getCaption(context) {
|
|
47
|
-
return context.
|
|
47
|
+
return context.studio.script.captionParams?.lang;
|
|
48
48
|
},
|
|
49
49
|
setSessionState(context, sessionType, value) {
|
|
50
50
|
context.sessionState.inSession[sessionType] = value;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
2
|
import { ScriptingParams } from "../types/index.js";
|
|
3
3
|
export declare const createMulmoScriptFromUrl: ({ urls, templateName, outDirPath, filename, cacheDirPath, llm, llm_model }: ScriptingParams) => Promise<void>;
|
|
4
|
+
export declare const createMulmoScriptFromFile: (fileName: string, { templateName, outDirPath, filename, cacheDirPath, llm, llm_model, verbose }: ScriptingParams) => Promise<void>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
|
+
import path from "path";
|
|
2
3
|
import { GraphAI } from "graphai";
|
|
3
4
|
import { openAIAgent } from "@graphai/openai_agent";
|
|
4
5
|
import { anthropicAgent } from "@graphai/anthropic_agent";
|
|
@@ -14,7 +15,56 @@ import { mulmoScriptSchema, urlsSchema } from "../types/schema.js";
|
|
|
14
15
|
import { cliLoadingPlugin } from "../utils/plugins.js";
|
|
15
16
|
import { graphDataScriptFromUrlPrompt } from "../utils/prompt.js";
|
|
16
17
|
import { llmPair } from "../utils/utils.js";
|
|
18
|
+
import { readFileSync } from "fs";
|
|
17
19
|
const vanillaAgents = agents.default ?? agents;
|
|
20
|
+
const graphMulmoScript = {
|
|
21
|
+
version: 0.5,
|
|
22
|
+
loop: {
|
|
23
|
+
// If the script is not valid and the counter is less than 3, continue the loop
|
|
24
|
+
while: ":continue",
|
|
25
|
+
},
|
|
26
|
+
nodes: {
|
|
27
|
+
sourceText: {},
|
|
28
|
+
systemPrompt: {},
|
|
29
|
+
llmAgent: {},
|
|
30
|
+
llmModel: {},
|
|
31
|
+
maxTokens: {},
|
|
32
|
+
counter: {
|
|
33
|
+
value: 0,
|
|
34
|
+
update: ":counter.add(1)",
|
|
35
|
+
},
|
|
36
|
+
llm: {
|
|
37
|
+
agent: ":llmAgent",
|
|
38
|
+
// console: { before: true },
|
|
39
|
+
inputs: {
|
|
40
|
+
system: ":systemPrompt",
|
|
41
|
+
prompt: graphDataScriptFromUrlPrompt("${:sourceText.text}"),
|
|
42
|
+
params: {
|
|
43
|
+
model: ":llmModel",
|
|
44
|
+
system: ":systemPrompt",
|
|
45
|
+
max_tokens: ":maxTokens",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
validateSchemaAgent: {
|
|
50
|
+
agent: "validateSchemaAgent",
|
|
51
|
+
inputs: {
|
|
52
|
+
text: ":llm.text.codeBlock()",
|
|
53
|
+
schema: mulmoScriptSchema,
|
|
54
|
+
},
|
|
55
|
+
isResult: true,
|
|
56
|
+
},
|
|
57
|
+
continue: {
|
|
58
|
+
agent: ({ isValid, counter }) => {
|
|
59
|
+
return !isValid && counter < 3;
|
|
60
|
+
},
|
|
61
|
+
inputs: {
|
|
62
|
+
isValid: ":validateSchemaAgent.isValid",
|
|
63
|
+
counter: ":counter",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
18
68
|
const graphData = {
|
|
19
69
|
version: 0.5,
|
|
20
70
|
// Execute sequentially because the free version of browserless API doesn't support concurrent execution.
|
|
@@ -23,7 +73,7 @@ const graphData = {
|
|
|
23
73
|
urls: {
|
|
24
74
|
value: [],
|
|
25
75
|
},
|
|
26
|
-
|
|
76
|
+
systemPrompt: {
|
|
27
77
|
value: "",
|
|
28
78
|
},
|
|
29
79
|
outdir: {
|
|
@@ -87,52 +137,60 @@ const graphData = {
|
|
|
87
137
|
agent: "nestedAgent",
|
|
88
138
|
inputs: {
|
|
89
139
|
sourceText: ":sourceText",
|
|
90
|
-
|
|
140
|
+
systemPrompt: ":systemPrompt",
|
|
91
141
|
llmAgent: ":llmAgent",
|
|
92
142
|
llmModel: ":llmModel",
|
|
93
143
|
maxTokens: ":maxTokens",
|
|
94
144
|
},
|
|
95
|
-
graph:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
145
|
+
graph: graphMulmoScript,
|
|
146
|
+
},
|
|
147
|
+
writeJSON: {
|
|
148
|
+
if: ":mulmoScript.validateSchemaAgent.isValid",
|
|
149
|
+
agent: "fileWriteAgent",
|
|
150
|
+
inputs: {
|
|
151
|
+
file: "${:outdir}/${:fileName}-${@now}.json",
|
|
152
|
+
text: ":mulmoScript.validateSchemaAgent.data.toJSON()",
|
|
153
|
+
},
|
|
154
|
+
isResult: true,
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
const graphDataText = {
|
|
159
|
+
version: 0.5,
|
|
160
|
+
// Execute sequentially because the free version of browserless API doesn't support concurrent execution.
|
|
161
|
+
concurrency: 1,
|
|
162
|
+
nodes: {
|
|
163
|
+
systemPrompt: {
|
|
164
|
+
value: "",
|
|
165
|
+
},
|
|
166
|
+
outdir: {
|
|
167
|
+
value: "",
|
|
168
|
+
},
|
|
169
|
+
fileName: {
|
|
170
|
+
value: "",
|
|
171
|
+
},
|
|
172
|
+
llmAgent: {
|
|
173
|
+
value: "",
|
|
174
|
+
},
|
|
175
|
+
llmModel: {
|
|
176
|
+
value: "",
|
|
177
|
+
},
|
|
178
|
+
maxTokens: {
|
|
179
|
+
value: 0,
|
|
180
|
+
},
|
|
181
|
+
sourceText: {},
|
|
182
|
+
// generate the mulmo script
|
|
183
|
+
mulmoScript: {
|
|
184
|
+
agent: "nestedAgent",
|
|
185
|
+
// console: { before: true },
|
|
186
|
+
inputs: {
|
|
187
|
+
sourceText: ":sourceText",
|
|
188
|
+
systemPrompt: ":systemPrompt",
|
|
189
|
+
llmAgent: ":llmAgent",
|
|
190
|
+
llmModel: ":llmModel",
|
|
191
|
+
maxTokens: ":maxTokens",
|
|
135
192
|
},
|
|
193
|
+
graph: graphMulmoScript,
|
|
136
194
|
},
|
|
137
195
|
writeJSON: {
|
|
138
196
|
if: ":mulmoScript.validateSchemaAgent.isValid",
|
|
@@ -169,7 +227,7 @@ export const createMulmoScriptFromUrl = async ({ urls, templateName, outDirPath,
|
|
|
169
227
|
fileWriteAgent,
|
|
170
228
|
}, { agentFilters });
|
|
171
229
|
graph.injectValue("urls", parsedUrls);
|
|
172
|
-
graph.injectValue("
|
|
230
|
+
graph.injectValue("systemPrompt", readTemplatePrompt(templateName));
|
|
173
231
|
graph.injectValue("outdir", outDirPath);
|
|
174
232
|
graph.injectValue("fileName", filename);
|
|
175
233
|
graph.injectValue("llmAgent", agent);
|
|
@@ -179,3 +237,31 @@ export const createMulmoScriptFromUrl = async ({ urls, templateName, outDirPath,
|
|
|
179
237
|
const result = await graph.run();
|
|
180
238
|
writingMessage(result?.writeJSON?.path ?? "");
|
|
181
239
|
};
|
|
240
|
+
export const createMulmoScriptFromFile = async (fileName, { templateName, outDirPath, filename, cacheDirPath, llm, llm_model, verbose }) => {
|
|
241
|
+
mkdir(outDirPath);
|
|
242
|
+
mkdir(cacheDirPath);
|
|
243
|
+
const filePath = path.resolve(process.cwd(), fileName);
|
|
244
|
+
const text = readFileSync(filePath, "utf-8");
|
|
245
|
+
const { agent, model, max_tokens } = llmPair(llm, llm_model);
|
|
246
|
+
const graph = new GraphAI(graphDataText, {
|
|
247
|
+
...vanillaAgents,
|
|
248
|
+
openAIAgent,
|
|
249
|
+
anthropicAgent,
|
|
250
|
+
geminiAgent,
|
|
251
|
+
groqAgent,
|
|
252
|
+
validateSchemaAgent,
|
|
253
|
+
fileWriteAgent,
|
|
254
|
+
});
|
|
255
|
+
graph.injectValue("sourceText", { text });
|
|
256
|
+
graph.injectValue("systemPrompt", readTemplatePrompt(templateName));
|
|
257
|
+
graph.injectValue("outdir", outDirPath);
|
|
258
|
+
graph.injectValue("fileName", filename);
|
|
259
|
+
graph.injectValue("llmAgent", agent);
|
|
260
|
+
graph.injectValue("llmModel", model);
|
|
261
|
+
graph.injectValue("maxTokens", max_tokens);
|
|
262
|
+
if (!verbose) {
|
|
263
|
+
graph.registerCallback(cliLoadingPlugin({ nodeId: "mulmoScript", message: "Generating script..." }));
|
|
264
|
+
}
|
|
265
|
+
const result = await graph.run();
|
|
266
|
+
writingMessage(result?.writeJSON?.path ?? "");
|
|
267
|
+
};
|