mulmocast 1.1.11 → 1.2.0

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.
@@ -2,5 +2,16 @@
2
2
  "title": "Business presentation in HTML",
3
3
  "description": "Template for business presentation in HTML.",
4
4
  "systemPrompt": "Generate a script for a business presentation of the given topic. Another LLM will generate actual slides from the prompt and data for each beat. Adding optional data would help it to generate more compelling slide. Mention the reference in one of beats, if it exists. The valid type of reference is 'article', 'paper', 'image', 'video', 'audio'. Use the JSON below as a template.",
5
+ "presentationStyle": {
6
+ "$mulmocast": {
7
+ "version": "1.1",
8
+ "credit": "closing"
9
+ },
10
+ "lang": "en",
11
+ "canvasSize": {
12
+ "width": 1536,
13
+ "height": 1024
14
+ }
15
+ },
5
16
  "scriptName": "html.json"
6
17
  }
@@ -8,7 +8,7 @@ export declare const imagePreprocessAgent: (namedInputs: {
8
8
  imagePath: string;
9
9
  htmlPrompt: string | undefined;
10
10
  htmlPath: string;
11
- htmlImageSystemPrompt: string[];
11
+ htmlImageSystemPrompt: string;
12
12
  } | {
13
13
  imagePath: string | undefined;
14
14
  referenceImageForMovie: string | undefined;
@@ -4,7 +4,7 @@ import { getReferenceImagePath } from "../utils/file.js";
4
4
  import { getExtention } from "../utils/utils.js";
5
5
  import { graphOption } from "./images.js";
6
6
  import { MulmoPresentationStyleMethods, MulmoStudioContextMethods } from "../methods/index.js";
7
- import { imageGoogleAgent, imageOpenaiAgent, mediaMockAgent } from "../agents/index.js";
7
+ import { imageOpenaiAgent, mediaMockAgent, imageGenAIAgent } from "../agents/index.js";
8
8
  // public api
9
9
  // Application may call this function directly to generate reference image.
10
10
  export const generateReferenceImage = async (inputs) => {
@@ -39,7 +39,7 @@ export const generateReferenceImage = async (inputs) => {
39
39
  },
40
40
  };
41
41
  const options = await graphOption(context);
42
- const graph = new GraphAI(image_graph_data, { imageGoogleAgent, imageOpenaiAgent, mediaMockAgent }, options);
42
+ const graph = new GraphAI(image_graph_data, { imageGenAIAgent, imageOpenaiAgent, mediaMockAgent }, options);
43
43
  await graph.run();
44
44
  return imagePath;
45
45
  };
@@ -1,26 +1,25 @@
1
1
  import dotenv from "dotenv";
2
2
  import fs from "fs";
3
3
  import { GraphAI, GraphAILogger, TaskManager } from "graphai";
4
- import { GoogleAuth } from "google-auth-library";
5
4
  import * as vanilla from "@graphai/vanilla";
6
5
  import { openAIAgent } from "@graphai/openai_agent";
7
6
  import { anthropicAgent } from "@graphai/anthropic_agent";
8
7
  import { fileWriteAgent } from "@graphai/vanilla_node_agents";
9
- import { imageGoogleAgent, imageOpenaiAgent, movieGoogleAgent, movieReplicateAgent, mediaMockAgent, soundEffectReplicateAgent, lipSyncReplicateAgent, } from "../agents/index.js";
8
+ import { imageGenAIAgent, imageOpenaiAgent, movieGenAIAgent, movieReplicateAgent, mediaMockAgent, soundEffectReplicateAgent, lipSyncReplicateAgent, } from "../agents/index.js";
10
9
  import { MulmoPresentationStyleMethods, MulmoStudioContextMethods } from "../methods/index.js";
11
10
  import { getOutputStudioFilePath, mkdir } from "../utils/file.js";
12
11
  import { fileCacheAgentFilter } from "../utils/filters.js";
13
- import { userAssert, settings2GraphAIConfig } from "../utils/utils.js";
12
+ import { settings2GraphAIConfig } from "../utils/utils.js";
14
13
  import { extractImageFromMovie, ffmpegGetMediaDuration } from "../utils/ffmpeg_utils.js";
15
14
  import { getImageRefs } from "./image_references.js";
16
15
  import { imagePreprocessAgent, imagePluginAgent, htmlImageGeneratorAgent } from "./image_agents.js";
17
16
  const vanillaAgents = vanilla.default ?? vanilla;
18
17
  const imageAgents = {
19
- imageGoogleAgent,
18
+ imageGenAIAgent,
20
19
  imageOpenaiAgent,
21
20
  };
22
21
  const movieAgents = {
23
- movieGoogleAgent,
22
+ movieGenAIAgent,
24
23
  movieReplicateAgent,
25
24
  mediaMockAgent,
26
25
  };
@@ -151,6 +150,7 @@ const beat_graph_data = {
151
150
  onComplete: [":imageGenerator", ":imagePlugin"], // to wait for imageGenerator to finish
152
151
  prompt: ":beat.moviePrompt",
153
152
  imagePath: ":preprocessor.referenceImageForMovie",
153
+ movieFile: ":preprocessor.movieFile", // for google genai agent
154
154
  cache: {
155
155
  force: [":context.force", ":forceMovie"],
156
156
  file: ":preprocessor.movieFile",
@@ -331,20 +331,6 @@ const graph_data = {
331
331
  },
332
332
  },
333
333
  };
334
- const googleAuth = async () => {
335
- try {
336
- const auth = new GoogleAuth({
337
- scopes: ["https://www.googleapis.com/auth/cloud-platform"],
338
- });
339
- const client = await auth.getClient();
340
- const accessToken = await client.getAccessToken();
341
- return accessToken.token;
342
- }
343
- catch (error) {
344
- GraphAILogger.info("install gcloud and run 'gcloud auth application-default login'");
345
- throw error;
346
- }
347
- };
348
334
  export const graphOption = async (context, settings) => {
349
335
  const options = {
350
336
  agentFilters: [
@@ -356,17 +342,7 @@ export const graphOption = async (context, settings) => {
356
342
  ],
357
343
  taskManager: new TaskManager(MulmoPresentationStyleMethods.getConcurrency(context.presentationStyle)),
358
344
  };
359
- const provider = MulmoPresentationStyleMethods.getText2ImageProvider(context.presentationStyle.imageParams?.provider);
360
- const config = settings2GraphAIConfig(settings, process.env);
361
- // We need to get google's auth token only if the google is the text2image provider.
362
- if (provider === "google" || context.presentationStyle.movieParams?.provider === "google") {
363
- userAssert(!!config.movieGoogleAgent || !!config.imageGoogleAgent, "GOOGLE_PROJECT_ID is not set");
364
- GraphAILogger.log("google was specified as text2image engine");
365
- const token = await googleAuth();
366
- config["imageGoogleAgent"].token = token;
367
- config["movieGoogleAgent"].token = token;
368
- }
369
- options.config = config;
345
+ options.config = settings2GraphAIConfig(settings, process.env);
370
346
  return options;
371
347
  };
372
348
  const prepareGenerateImages = async (context) => {
@@ -0,0 +1,5 @@
1
+ import type { AgentFunction, AgentFunctionInfo } from "graphai";
2
+ import type { AgentBufferResult, ImageAgentInputs, ImageAgentParams, GenAIImageAgentConfig } from "../types/agent.js";
3
+ export declare const imageGenAIAgent: AgentFunction<ImageAgentParams, AgentBufferResult, ImageAgentInputs, GenAIImageAgentConfig>;
4
+ declare const imageGenAIAgentInfo: AgentFunctionInfo;
5
+ export default imageGenAIAgentInfo;
@@ -0,0 +1,52 @@
1
+ import { GraphAILogger } from "graphai";
2
+ import { getAspectRatio } from "./movie_google_agent.js";
3
+ import { provider2ImageAgent } from "../utils/provider2agent.js";
4
+ import { GoogleGenAI, PersonGeneration } from "@google/genai";
5
+ export const imageGenAIAgent = async ({ namedInputs, params, config, }) => {
6
+ const { prompt } = namedInputs;
7
+ const aspectRatio = getAspectRatio(params.canvasSize);
8
+ const model = params.model ?? provider2ImageAgent["google"].defaultModel;
9
+ const apiKey = config?.apiKey;
10
+ if (!apiKey) {
11
+ throw new Error("API key is required for Google GenAI agent");
12
+ }
13
+ try {
14
+ const ai = new GoogleGenAI({ apiKey });
15
+ const response = await ai.models.generateImages({
16
+ model,
17
+ prompt,
18
+ config: {
19
+ numberOfImages: 1, // default is 4!
20
+ aspectRatio,
21
+ personGeneration: PersonGeneration.ALLOW_ALL,
22
+ // safetyFilterLevel: SafetyFilterLevel.BLOCK_ONLY_HIGH,
23
+ },
24
+ });
25
+ if (!response.generatedImages || response.generatedImages.length === 0) {
26
+ throw new Error("ERROR: generateImage returned no generated images");
27
+ }
28
+ const image = response.generatedImages[0].image;
29
+ if (image && image.imageBytes) {
30
+ return { buffer: Buffer.from(image.imageBytes, "base64") };
31
+ }
32
+ throw new Error("ERROR: generateImage returned no image bytes");
33
+ }
34
+ catch (error) {
35
+ GraphAILogger.info("Failed to generate image:", error);
36
+ throw error;
37
+ }
38
+ };
39
+ const imageGenAIAgentInfo = {
40
+ name: "imageGenAIAgent",
41
+ agent: imageGenAIAgent,
42
+ mock: imageGenAIAgent,
43
+ samples: [],
44
+ description: "Google Image agent",
45
+ category: ["image"],
46
+ author: "Receptron Team",
47
+ repository: "https://github.com/receptron/mulmocast-cli/",
48
+ // source: "https://github.com/receptron/mulmocast-cli/blob/main/src/agents/image_google_agent.ts",
49
+ license: "MIT",
50
+ environmentVariables: [],
51
+ };
52
+ export default imageGenAIAgentInfo;
@@ -1,9 +1,9 @@
1
1
  import addBGMAgent from "./add_bgm_agent.js";
2
2
  import combineAudioFilesAgent from "./combine_audio_files_agent.js";
3
- import imageGoogleAgent from "./image_google_agent.js";
3
+ import imageGenAIAgent from "./image_genai_agent.js";
4
4
  import imageOpenaiAgent from "./image_openai_agent.js";
5
5
  import tavilySearchAgent from "./tavily_agent.js";
6
- import movieGoogleAgent from "./movie_google_agent.js";
6
+ import movieGenAIAgent from "./movie_genai_agent.js";
7
7
  import movieReplicateAgent from "./movie_replicate_agent.js";
8
8
  import mediaMockAgent from "./media_mock_agent.js";
9
9
  import ttsElevenlabsAgent from "./tts_elevenlabs_agent.js";
@@ -17,4 +17,4 @@ import { browserlessAgent } from "@graphai/browserless_agent";
17
17
  import { textInputAgent } from "@graphai/input_agents";
18
18
  import { openAIAgent } from "@graphai/openai_agent";
19
19
  import { fileWriteAgent } from "@graphai/vanilla_node_agents";
20
- export { openAIAgent, fileWriteAgent, browserlessAgent, textInputAgent, addBGMAgent, combineAudioFilesAgent, imageGoogleAgent, imageOpenaiAgent, tavilySearchAgent, movieGoogleAgent, movieReplicateAgent, mediaMockAgent, ttsElevenlabsAgent, ttsNijivoiceAgent, ttsOpenaiAgent, ttsGoogleAgent, validateSchemaAgent, soundEffectReplicateAgent, lipSyncReplicateAgent, };
20
+ export { openAIAgent, fileWriteAgent, browserlessAgent, textInputAgent, addBGMAgent, combineAudioFilesAgent, imageGenAIAgent, imageOpenaiAgent, tavilySearchAgent, movieGenAIAgent, movieReplicateAgent, mediaMockAgent, ttsElevenlabsAgent, ttsNijivoiceAgent, ttsOpenaiAgent, ttsGoogleAgent, validateSchemaAgent, soundEffectReplicateAgent, lipSyncReplicateAgent, };
@@ -1,9 +1,9 @@
1
1
  import addBGMAgent from "./add_bgm_agent.js";
2
2
  import combineAudioFilesAgent from "./combine_audio_files_agent.js";
3
- import imageGoogleAgent from "./image_google_agent.js";
3
+ import imageGenAIAgent from "./image_genai_agent.js";
4
4
  import imageOpenaiAgent from "./image_openai_agent.js";
5
5
  import tavilySearchAgent from "./tavily_agent.js";
6
- import movieGoogleAgent from "./movie_google_agent.js";
6
+ import movieGenAIAgent from "./movie_genai_agent.js";
7
7
  import movieReplicateAgent from "./movie_replicate_agent.js";
8
8
  import mediaMockAgent from "./media_mock_agent.js";
9
9
  import ttsElevenlabsAgent from "./tts_elevenlabs_agent.js";
@@ -18,4 +18,4 @@ import { textInputAgent } from "@graphai/input_agents";
18
18
  import { openAIAgent } from "@graphai/openai_agent";
19
19
  // import * as vanilla from "@graphai/vanilla";
20
20
  import { fileWriteAgent } from "@graphai/vanilla_node_agents";
21
- export { openAIAgent, fileWriteAgent, browserlessAgent, textInputAgent, addBGMAgent, combineAudioFilesAgent, imageGoogleAgent, imageOpenaiAgent, tavilySearchAgent, movieGoogleAgent, movieReplicateAgent, mediaMockAgent, ttsElevenlabsAgent, ttsNijivoiceAgent, ttsOpenaiAgent, ttsGoogleAgent, validateSchemaAgent, soundEffectReplicateAgent, lipSyncReplicateAgent, };
21
+ export { openAIAgent, fileWriteAgent, browserlessAgent, textInputAgent, addBGMAgent, combineAudioFilesAgent, imageGenAIAgent, imageOpenaiAgent, tavilySearchAgent, movieGenAIAgent, movieReplicateAgent, mediaMockAgent, ttsElevenlabsAgent, ttsNijivoiceAgent, ttsOpenaiAgent, ttsGoogleAgent, validateSchemaAgent, soundEffectReplicateAgent, lipSyncReplicateAgent, };
@@ -0,0 +1,9 @@
1
+ import type { AgentFunction, AgentFunctionInfo } from "graphai";
2
+ import type { AgentBufferResult, GenAIImageAgentConfig, GoogleMovieAgentParams, MovieAgentInputs } from "../types/agent.js";
3
+ export declare const getAspectRatio: (canvasSize: {
4
+ width: number;
5
+ height: number;
6
+ }) => string;
7
+ export declare const movieGenAIAgent: AgentFunction<GoogleMovieAgentParams, AgentBufferResult, MovieAgentInputs, GenAIImageAgentConfig>;
8
+ declare const movieGenAIAgentInfo: AgentFunctionInfo;
9
+ export default movieGenAIAgentInfo;
@@ -0,0 +1,86 @@
1
+ import { readFileSync } from "fs";
2
+ import { GraphAILogger, sleep } from "graphai";
3
+ import { GoogleGenAI, PersonGeneration } from "@google/genai";
4
+ export const getAspectRatio = (canvasSize) => {
5
+ if (canvasSize.width > canvasSize.height) {
6
+ return "16:9";
7
+ }
8
+ else if (canvasSize.width < canvasSize.height) {
9
+ return "9:16";
10
+ }
11
+ else {
12
+ return "1:1";
13
+ }
14
+ };
15
+ export const movieGenAIAgent = async ({ namedInputs, params, config, }) => {
16
+ const { prompt, imagePath, movieFile } = namedInputs;
17
+ const aspectRatio = getAspectRatio(params.canvasSize);
18
+ const model = params.model ?? "veo-2.0-generate-001"; // "veo-3.0-generate-preview";
19
+ const duration = params.duration ?? 8;
20
+ const apiKey = config?.apiKey;
21
+ if (!apiKey) {
22
+ throw new Error("API key is required for Google GenAI agent");
23
+ }
24
+ try {
25
+ const ai = new GoogleGenAI({ apiKey });
26
+ const payload = {
27
+ model,
28
+ prompt,
29
+ config: {
30
+ durationSeconds: duration,
31
+ aspectRatio,
32
+ personGeneration: undefined,
33
+ },
34
+ image: undefined,
35
+ };
36
+ if (imagePath) {
37
+ const buffer = readFileSync(imagePath);
38
+ const imageBytes = buffer.toString("base64");
39
+ payload.image = {
40
+ imageBytes,
41
+ mimeType: "image/png",
42
+ };
43
+ }
44
+ else {
45
+ payload.config.personGeneration = PersonGeneration.ALLOW_ALL;
46
+ }
47
+ const operation = await ai.models.generateVideos(payload);
48
+ const response = { operation };
49
+ // Poll the operation status until the video is ready.
50
+ while (!response.operation.done) {
51
+ await sleep(5000);
52
+ response.operation = await ai.operations.getVideosOperation(response);
53
+ }
54
+ if (!response.operation.response?.generatedVideos) {
55
+ throw new Error(`No video: ${JSON.stringify(response.operation, null, 2)}`);
56
+ }
57
+ const video = response.operation.response.generatedVideos[0].video;
58
+ if (!video) {
59
+ throw new Error(`No video: ${JSON.stringify(response.operation, null, 2)}`);
60
+ }
61
+ await ai.files.download({
62
+ file: video,
63
+ downloadPath: movieFile,
64
+ });
65
+ await sleep(5000); // HACK: Without this, the file is not ready yet.
66
+ return { saved: movieFile };
67
+ }
68
+ catch (error) {
69
+ GraphAILogger.info("Failed to generate movie:", error.message);
70
+ throw error;
71
+ }
72
+ };
73
+ const movieGenAIAgentInfo = {
74
+ name: "movieGenAIAgent",
75
+ agent: movieGenAIAgent,
76
+ mock: movieGenAIAgent,
77
+ samples: [],
78
+ description: "Google Movie agent",
79
+ category: ["movie"],
80
+ author: "Receptron Team",
81
+ repository: "https://github.com/receptron/mulmocast-cli/",
82
+ // source: "https://github.com/receptron/mulmocast-cli/blob/main/src/agents/image_google_agent.ts",
83
+ license: "MIT",
84
+ environmentVariables: [],
85
+ };
86
+ export default movieGenAIAgentInfo;
@@ -37,9 +37,11 @@ export const getFileObject = (args) => {
37
37
  // We generate a new unique script file from clipboard text in the output directory
38
38
  const generatedFileName = generateTimestampedFileName("script");
39
39
  const clipboardText = clipboardy.readSync();
40
+ const json = JSON.parse(clipboardText);
41
+ const formattedText = JSON.stringify(json, null, 2);
40
42
  const resolvedFilePath = resolveDirPath(outDirPath, `${generatedFileName}.json`);
41
43
  mkdir(outDirPath);
42
- fs.writeFileSync(resolvedFilePath, clipboardText, "utf8");
44
+ fs.writeFileSync(resolvedFilePath, formattedText, "utf8");
43
45
  return { fileOrUrl: resolvedFilePath, fileName: generatedFileName };
44
46
  }
45
47
  const resolvedFileOrUrl = file ?? "";
@@ -2,7 +2,7 @@ import { findImagePlugin } from "../utils/image_plugins/index.js";
2
2
  export const MulmoBeatMethods = {
3
3
  getHtmlPrompt(beat) {
4
4
  if (beat?.htmlPrompt?.data) {
5
- return beat.htmlPrompt.prompt + "\n\n data\n" + JSON.stringify(beat.htmlPrompt.data, null, 2);
5
+ return beat.htmlPrompt.prompt + "\n\n[data]\n" + JSON.stringify(beat.htmlPrompt.data, null, 2);
6
6
  }
7
7
  return beat?.htmlPrompt?.prompt;
8
8
  },
@@ -10,7 +10,9 @@ export type OpenAIImageOptions = {
10
10
  quality?: OpenAIImageQuality;
11
11
  };
12
12
  export type AgentBufferResult = {
13
- buffer: Buffer;
13
+ buffer?: Buffer;
14
+ saved?: string;
15
+ text?: string;
14
16
  };
15
17
  export type AgentPromptInputs = {
16
18
  prompt: string;
@@ -47,8 +49,12 @@ export type GoogleImageAgentConfig = {
47
49
  projectId?: string;
48
50
  token?: string;
49
51
  };
52
+ export type GenAIImageAgentConfig = {
53
+ apiKey?: string;
54
+ };
50
55
  export type MovieAgentInputs = AgentPromptInputs & {
51
56
  imagePath?: string;
57
+ movieFile: string;
52
58
  };
53
59
  export type GoogleMovieAgentParams = ImageAgentParams & {
54
60
  duration?: number;