mulmocast 0.0.14 → 0.0.16

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.
Files changed (60) hide show
  1. package/README.md +5 -1
  2. package/assets/html/pdf_handout.html +85 -0
  3. package/assets/html/pdf_slide.html +55 -0
  4. package/assets/html/pdf_talk.html +76 -0
  5. package/assets/templates/text_and_image.json +6 -0
  6. package/assets/templates/text_only.json +6 -0
  7. package/lib/actions/audio.d.ts +3 -1
  8. package/lib/actions/audio.js +84 -45
  9. package/lib/actions/captions.js +1 -1
  10. package/lib/actions/images.d.ts +89 -1
  11. package/lib/actions/images.js +160 -99
  12. package/lib/actions/movie.js +28 -21
  13. package/lib/actions/pdf.d.ts +1 -0
  14. package/lib/actions/pdf.js +134 -204
  15. package/lib/actions/translate.js +1 -1
  16. package/lib/agents/add_bgm_agent.js +3 -3
  17. package/lib/agents/combine_audio_files_agent.js +11 -9
  18. package/lib/agents/image_mock_agent.d.ts +4 -0
  19. package/lib/agents/image_mock_agent.js +18 -0
  20. package/lib/agents/index.d.ts +4 -1
  21. package/lib/agents/index.js +4 -1
  22. package/lib/agents/media_mock_agent.d.ts +4 -0
  23. package/lib/agents/media_mock_agent.js +18 -0
  24. package/lib/agents/tavily_agent.d.ts +15 -0
  25. package/lib/agents/tavily_agent.js +130 -0
  26. package/lib/agents/tts_openai_agent.js +9 -1
  27. package/lib/cli/commands/audio/builder.d.ts +4 -0
  28. package/lib/cli/commands/image/builder.d.ts +4 -0
  29. package/lib/cli/commands/movie/builder.d.ts +4 -0
  30. package/lib/cli/commands/pdf/builder.d.ts +4 -0
  31. package/lib/cli/commands/translate/builder.d.ts +4 -0
  32. package/lib/cli/common.d.ts +4 -0
  33. package/lib/cli/common.js +11 -0
  34. package/lib/cli/helpers.d.ts +5 -1
  35. package/lib/cli/helpers.js +19 -2
  36. package/lib/methods/index.d.ts +1 -1
  37. package/lib/methods/index.js +1 -1
  38. package/lib/methods/mulmo_presentation_style.d.ts +14 -0
  39. package/lib/methods/mulmo_presentation_style.js +70 -0
  40. package/lib/methods/mulmo_script.d.ts +1 -1
  41. package/lib/methods/mulmo_script.js +2 -2
  42. package/lib/methods/mulmo_studio_context.d.ts +14 -0
  43. package/lib/methods/mulmo_studio_context.js +20 -2
  44. package/lib/tools/deep_research.d.ts +2 -0
  45. package/lib/tools/deep_research.js +265 -0
  46. package/lib/types/schema.d.ts +31 -0
  47. package/lib/types/schema.js +1 -1
  48. package/lib/types/type.d.ts +4 -1
  49. package/lib/utils/ffmpeg_utils.d.ts +1 -0
  50. package/lib/utils/ffmpeg_utils.js +10 -0
  51. package/lib/utils/file.d.ts +1 -3
  52. package/lib/utils/file.js +4 -11
  53. package/lib/utils/filters.js +1 -0
  54. package/lib/utils/markdown.js +1 -1
  55. package/lib/utils/preprocess.js +1 -0
  56. package/lib/utils/prompt.d.ts +3 -0
  57. package/lib/utils/prompt.js +52 -0
  58. package/package.json +10 -10
  59. package/assets/font/NotoSansJP-Regular.ttf +0 -0
  60. package/assets/music/StarsBeyondEx.mp3 +0 -0
@@ -0,0 +1,130 @@
1
+ import { assert } from "graphai";
2
+ import { tavily } from "@tavily/core";
3
+ const getTavilyApiKey = (params, config) => {
4
+ if (params?.apiKey) {
5
+ return params.apiKey;
6
+ }
7
+ if (config?.apiKey) {
8
+ return config.apiKey;
9
+ }
10
+ return typeof process !== "undefined" ? process?.env?.TAVILY_API_KEY : null;
11
+ };
12
+ export const tavilySearchAgent = async ({ namedInputs, params, config, }) => {
13
+ const { query } = namedInputs;
14
+ assert(!!query, "tavilySearchAgent: query is required! set inputs: { query: 'search terms' }");
15
+ try {
16
+ const apiKey = getTavilyApiKey(params, config);
17
+ assert(apiKey, "Tavily API key is required. Please set the TAVILY_API_KEY environment variable or provide it in params/config.");
18
+ const tvly = tavily({ apiKey });
19
+ // Convert params to SDK options format
20
+ const sdkOptions = {};
21
+ if (params?.max_results !== undefined)
22
+ sdkOptions.maxResults = params.max_results;
23
+ if (params?.search_depth !== undefined)
24
+ sdkOptions.searchDepth = params.search_depth;
25
+ if (params?.include_answer !== undefined)
26
+ sdkOptions.includeAnswer = params.include_answer;
27
+ if (params?.include_raw_content !== undefined)
28
+ sdkOptions.includeRawContent = params.include_raw_content;
29
+ const response = await tvly.search(query, sdkOptions);
30
+ return response;
31
+ }
32
+ catch (error) {
33
+ throw new Error(`Tavily search failed: ${error instanceof Error ? error.message : String(error)}`);
34
+ }
35
+ };
36
+ const tavilySearchAgentInfo = {
37
+ name: "tavilySearchAgent",
38
+ agent: tavilySearchAgent,
39
+ mock: tavilySearchAgent,
40
+ params: {
41
+ type: "object",
42
+ properties: {
43
+ apiKey: {
44
+ type: "string",
45
+ description: "Tavily API key",
46
+ },
47
+ max_results: {
48
+ type: "number",
49
+ description: "Maximum number of search results to return (default: 5)",
50
+ },
51
+ search_depth: {
52
+ type: "string",
53
+ enum: ["basic", "advanced"],
54
+ description: "Search depth - basic for faster results, advanced for more comprehensive results",
55
+ },
56
+ include_answer: {
57
+ type: "boolean",
58
+ description: "Include a direct answer to the query when available",
59
+ },
60
+ include_raw_content: {
61
+ type: "string",
62
+ enum: ["boolean", "markdown", "text"],
63
+ description: "Include raw content from search results (boolean, markdown, text)",
64
+ },
65
+ },
66
+ },
67
+ inputs: {
68
+ type: "object",
69
+ properties: {
70
+ query: {
71
+ type: "string",
72
+ description: "Search query string",
73
+ },
74
+ },
75
+ required: ["query"],
76
+ },
77
+ output: {
78
+ type: "object",
79
+ properties: {
80
+ query: { type: "string" },
81
+ answer: { type: ["string", "null"] },
82
+ results: {
83
+ type: "array",
84
+ items: {
85
+ type: "object",
86
+ properties: {
87
+ title: { type: "string" },
88
+ url: { type: "string" },
89
+ content: { type: "string" },
90
+ rawContent: { type: ["string", "null"] },
91
+ score: { type: "number" },
92
+ },
93
+ },
94
+ },
95
+ },
96
+ },
97
+ samples: [
98
+ {
99
+ inputs: {
100
+ query: "latest AI developments 2024",
101
+ },
102
+ params: {
103
+ max_results: 3,
104
+ include_answer: true,
105
+ },
106
+ result: {
107
+ query: "latest AI developments 2024",
108
+ answer: "Recent AI developments in 2024 include...",
109
+ results: [
110
+ {
111
+ title: "Major AI Breakthroughs in 2024",
112
+ url: "https://example.com/ai-2024",
113
+ content: "The year 2024 has seen significant advances in artificial intelligence...",
114
+ rawContent: null,
115
+ score: 0.95,
116
+ },
117
+ ],
118
+ },
119
+ },
120
+ ],
121
+ description: "Performs web search using Tavily API and returns relevant search results with optional AI-generated answers",
122
+ category: ["search", "web"],
123
+ author: "Receptron Team",
124
+ repository: "https://github.com/receptron/mulmocast-cli/tree/main/src/agents/tavily_agent.ts",
125
+ source: "https://github.com/receptron/mulmocast-cli/tree/main/src/agents/tavily_agent.ts",
126
+ package: "@receptron/mulmocast-cli",
127
+ license: "MIT",
128
+ environmentVariables: ["TAVILY_API_KEY"],
129
+ };
130
+ export default tavilySearchAgentInfo;
@@ -24,7 +24,15 @@ export const ttsOpenaiAgent = async ({ namedInputs, params }) => {
24
24
  error: e,
25
25
  };
26
26
  }
27
- GraphAILogger.info(e);
27
+ GraphAILogger.error(e);
28
+ if (e && typeof e === "object" && "error" in e) {
29
+ GraphAILogger.info("tts_openai_agent: ");
30
+ GraphAILogger.info(e.error);
31
+ }
32
+ else if (e instanceof Error) {
33
+ GraphAILogger.info("tts_openai_agent: ");
34
+ GraphAILogger.info(e.message);
35
+ }
28
36
  throw new Error("TTS OpenAI Error");
29
37
  }
30
38
  };
@@ -7,6 +7,10 @@ export declare const builder: (yargs: Argv) => Argv<{
7
7
  l: string | undefined;
8
8
  } & {
9
9
  f: boolean;
10
+ } & {
11
+ dryRun: boolean;
12
+ } & {
13
+ p: string | undefined;
10
14
  } & {
11
15
  file: string | undefined;
12
16
  } & {
@@ -7,6 +7,10 @@ export declare const builder: (yargs: Argv) => Argv<{
7
7
  l: string | undefined;
8
8
  } & {
9
9
  f: boolean;
10
+ } & {
11
+ dryRun: boolean;
12
+ } & {
13
+ p: string | undefined;
10
14
  } & {
11
15
  file: string | undefined;
12
16
  } & {
@@ -7,6 +7,10 @@ export declare const builder: (yargs: Argv) => Argv<{
7
7
  l: string | undefined;
8
8
  } & {
9
9
  f: boolean;
10
+ } & {
11
+ dryRun: boolean;
12
+ } & {
13
+ p: string | undefined;
10
14
  } & {
11
15
  file: string | undefined;
12
16
  } & {
@@ -7,6 +7,10 @@ export declare const builder: (yargs: Argv) => Argv<{
7
7
  l: string | undefined;
8
8
  } & {
9
9
  f: boolean;
10
+ } & {
11
+ dryRun: boolean;
12
+ } & {
13
+ p: string | undefined;
10
14
  } & {
11
15
  file: string | undefined;
12
16
  } & {
@@ -7,6 +7,10 @@ export declare const builder: (yargs: Argv) => Argv<import("yargs").Omit<{
7
7
  l: string | undefined;
8
8
  } & {
9
9
  f: boolean;
10
+ } & {
11
+ dryRun: boolean;
12
+ } & {
13
+ p: string | undefined;
10
14
  } & {
11
15
  file: string | undefined;
12
16
  }, "file"> & {
@@ -7,6 +7,10 @@ export declare const commonOptions: (yargs: Argv) => Argv<{
7
7
  l: string | undefined;
8
8
  } & {
9
9
  f: boolean;
10
+ } & {
11
+ dryRun: boolean;
12
+ } & {
13
+ p: string | undefined;
10
14
  } & {
11
15
  file: string | undefined;
12
16
  }>;
package/lib/cli/common.js CHANGED
@@ -25,6 +25,17 @@ export const commonOptions = (yargs) => {
25
25
  describe: "Force regenerate",
26
26
  type: "boolean",
27
27
  default: false,
28
+ })
29
+ .option("dryRun", {
30
+ describe: "Dry run",
31
+ type: "boolean",
32
+ default: false,
33
+ })
34
+ .option("p", {
35
+ alias: "presentationStyle",
36
+ describe: "Presentation Style",
37
+ demandOption: false,
38
+ type: "string",
28
39
  })
29
40
  .positional("file", {
30
41
  describe: "Mulmo Script File",
@@ -1,4 +1,4 @@
1
- import type { MulmoScript, MulmoStudioContext } from "../types/type.js";
1
+ import type { MulmoScript, MulmoStudioContext, MulmoPresentationStyle } from "../types/type.js";
2
2
  import type { CliArgs } from "../types/cli_types.js";
3
3
  export declare const setGraphAILogger: (verbose: boolean | undefined, logValues?: Record<string, unknown>) => void;
4
4
  export interface FileObject {
@@ -11,6 +11,7 @@ export interface FileObject {
11
11
  isHttpPath: boolean;
12
12
  fileOrUrl: string;
13
13
  outputStudioFilePath: string;
14
+ presentationStylePath: string | undefined;
14
15
  fileName: string;
15
16
  }
16
17
  export declare const getFileObject: (args: {
@@ -18,9 +19,11 @@ export declare const getFileObject: (args: {
18
19
  outdir?: string;
19
20
  imagedir?: string;
20
21
  audiodir?: string;
22
+ presentationStyle?: string;
21
23
  file: string;
22
24
  }) => FileObject;
23
25
  export declare const fetchScript: (isHttpPath: boolean, mulmoFilePath: string, fileOrUrl: string) => Promise<MulmoScript | null>;
26
+ export declare const getPresentationStyle: (presentationStylePath: string | undefined) => MulmoPresentationStyle | null;
24
27
  type InitOptions = {
25
28
  b?: string;
26
29
  o?: string;
@@ -29,6 +32,7 @@ type InitOptions = {
29
32
  file?: string;
30
33
  l?: string;
31
34
  c?: string;
35
+ p?: string;
32
36
  };
33
37
  export declare const initializeContext: (argv: CliArgs<InitOptions>) => Promise<MulmoStudioContext | null>;
34
38
  export declare const runTranslateIfNeeded: (context: MulmoStudioContext, argv: {
@@ -7,6 +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 } from "../types/schema.js";
10
11
  export const setGraphAILogger = (verbose, logValues) => {
11
12
  if (verbose) {
12
13
  if (logValues) {
@@ -22,7 +23,7 @@ export const setGraphAILogger = (verbose, logValues) => {
22
23
  }
23
24
  };
24
25
  export const getFileObject = (args) => {
25
- const { basedir, outdir, imagedir, audiodir, file } = args;
26
+ const { basedir, outdir, imagedir, audiodir, file, presentationStyle } = args;
26
27
  const baseDirPath = getBaseDirPath(basedir);
27
28
  const outDirPath = getFullPath(baseDirPath, outdir ?? outDirName);
28
29
  const { fileOrUrl, fileName } = (() => {
@@ -47,6 +48,7 @@ export const getFileObject = (args) => {
47
48
  const imageDirPath = getFullPath(outDirPath, imagedir ?? imageDirName);
48
49
  const audioDirPath = getFullPath(outDirPath, audiodir ?? audioDirName);
49
50
  const outputStudioFilePath = getOutputStudioFilePath(outDirPath, fileName);
51
+ const presentationStylePath = presentationStyle ? getFullPath(baseDirPath, presentationStyle) : undefined;
50
52
  return {
51
53
  baseDirPath,
52
54
  mulmoFilePath,
@@ -57,6 +59,7 @@ export const getFileObject = (args) => {
57
59
  isHttpPath,
58
60
  fileOrUrl,
59
61
  outputStudioFilePath,
62
+ presentationStylePath,
60
63
  fileName,
61
64
  };
62
65
  };
@@ -75,15 +78,26 @@ export const fetchScript = async (isHttpPath, mulmoFilePath, fileOrUrl) => {
75
78
  }
76
79
  return readMulmoScriptFile(mulmoFilePath, "ERROR: File does not exist " + mulmoFilePath)?.mulmoData ?? null;
77
80
  };
81
+ export const getPresentationStyle = (presentationStylePath) => {
82
+ if (presentationStylePath) {
83
+ if (!fs.existsSync(presentationStylePath)) {
84
+ throw new Error(`ERROR: File not exists ${presentationStylePath}`);
85
+ }
86
+ const jsonData = readMulmoScriptFile(presentationStylePath, "ERROR: File does not exist " + presentationStylePath)?.mulmoData ?? null;
87
+ return mulmoPresentationStyleSchema.parse(jsonData);
88
+ }
89
+ return null;
90
+ };
78
91
  export const initializeContext = async (argv) => {
79
92
  const files = getFileObject({
80
93
  basedir: argv.b,
81
94
  outdir: argv.o,
82
95
  imagedir: argv.i,
83
96
  audiodir: argv.a,
97
+ presentationStyle: argv.p,
84
98
  file: argv.file ?? "",
85
99
  });
86
- const { fileName, isHttpPath, fileOrUrl, mulmoFilePath, outputStudioFilePath } = files;
100
+ const { fileName, isHttpPath, fileOrUrl, mulmoFilePath, outputStudioFilePath, presentationStylePath } = files;
87
101
  setGraphAILogger(argv.v, {
88
102
  files,
89
103
  });
@@ -91,6 +105,7 @@ export const initializeContext = async (argv) => {
91
105
  if (!mulmoScript) {
92
106
  return null;
93
107
  }
108
+ const presentationStyle = getPresentationStyle(presentationStylePath);
94
109
  // Create or update MulmoStudio file with MulmoScript
95
110
  const currentStudio = readMulmoScriptFile(outputStudioFilePath);
96
111
  try {
@@ -100,6 +115,7 @@ export const initializeContext = async (argv) => {
100
115
  studio,
101
116
  fileDirs: files,
102
117
  force: Boolean(argv.f),
118
+ dryRun: Boolean(argv.dryRun),
103
119
  lang: argv.l,
104
120
  caption: argv.c,
105
121
  sessionState: {
@@ -119,6 +135,7 @@ export const initializeContext = async (argv) => {
119
135
  caption: {},
120
136
  },
121
137
  },
138
+ presentationStyle: presentationStyle ?? studio.script,
122
139
  };
123
140
  }
124
141
  catch (error) {
@@ -1,4 +1,4 @@
1
- export * from "./mulmo_script.js";
1
+ export * from "./mulmo_presentation_style.js";
2
2
  export * from "./mulmo_script_template.js";
3
3
  export * from "./mulmo_studio_context.js";
4
4
  export * from "./mulmo_media_source.js";
@@ -1,4 +1,4 @@
1
- export * from "./mulmo_script.js";
1
+ export * from "./mulmo_presentation_style.js";
2
2
  export * from "./mulmo_script_template.js";
3
3
  export * from "./mulmo_studio_context.js";
4
4
  export * from "./mulmo_media_source.js";
@@ -0,0 +1,14 @@
1
+ import "dotenv/config";
2
+ import { MulmoCanvasDimension, MulmoBeat, SpeechOptions, Text2SpeechProvider, Text2ImageAgentInfo, BeatMediaType, MulmoPresentationStyle, SpeakerData } from "../types/index.js";
3
+ export declare const MulmoPresentationStyleMethods: {
4
+ getCanvasSize(presentationStyle: MulmoPresentationStyle): MulmoCanvasDimension;
5
+ getSpeechProvider(presentationStyle: MulmoPresentationStyle): Text2SpeechProvider;
6
+ getAllSpeechProviders(presentationStyle: MulmoPresentationStyle): Set<Text2SpeechProvider>;
7
+ getTextSlideStyle(presentationStyle: MulmoPresentationStyle, beat: MulmoBeat): string;
8
+ getSpeechOptions(presentationStyle: MulmoPresentationStyle, beat: MulmoBeat): SpeechOptions | undefined;
9
+ getSpeaker(presentationStyle: MulmoPresentationStyle, beat: MulmoBeat): SpeakerData;
10
+ getProvider(presentationStyle: MulmoPresentationStyle, beat: MulmoBeat): Text2SpeechProvider;
11
+ getVoiceId(presentationStyle: MulmoPresentationStyle, beat: MulmoBeat): string;
12
+ getImageAgentInfo(presentationStyle: MulmoPresentationStyle, dryRun?: boolean): Text2ImageAgentInfo;
13
+ getImageType(_: MulmoPresentationStyle, beat: MulmoBeat): BeatMediaType;
14
+ };
@@ -0,0 +1,70 @@
1
+ import "dotenv/config";
2
+ import { text2ImageProviderSchema, text2SpeechProviderSchema, mulmoCanvasDimensionSchema } from "../types/schema.js";
3
+ const defaultTextSlideStyles = [
4
+ '*,*::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}}',
5
+ "body { margin: 60px; margin-top: 40px; color:#333; font-size: 30px; font-family: Arial, sans-serif; box-sizing: border-box; height: 100vh }",
6
+ "h1 { font-size: 56px; margin-bottom: 20px; text-align: center }",
7
+ "h2 { font-size: 48px; text-align: center }",
8
+ "h3 { font-size: 36px }",
9
+ "ul { margin-left: 40px } ",
10
+ "pre { background: #eeeecc; font-size: 16px; padding:4px }",
11
+ "p { margin-left: 40px }",
12
+ "table { font-size: 36px; margin: auto; border: 1px solid gray; border-collapse: collapse }",
13
+ "th { border-bottom: 1px solid gray }",
14
+ "td, th { padding: 8px }",
15
+ "tr:nth-child(even) { background-color: #eee }",
16
+ ];
17
+ export const MulmoPresentationStyleMethods = {
18
+ getCanvasSize(presentationStyle) {
19
+ return mulmoCanvasDimensionSchema.parse(presentationStyle.canvasSize);
20
+ },
21
+ getSpeechProvider(presentationStyle) {
22
+ return text2SpeechProviderSchema.parse(presentationStyle.speechParams?.provider);
23
+ },
24
+ getAllSpeechProviders(presentationStyle) {
25
+ const providers = new Set();
26
+ const defaultProvider = this.getSpeechProvider(presentationStyle);
27
+ Object.values(presentationStyle.speechParams.speakers).forEach((speaker) => {
28
+ const provider = speaker.provider ?? defaultProvider;
29
+ providers.add(provider);
30
+ });
31
+ return providers;
32
+ },
33
+ getTextSlideStyle(presentationStyle, beat) {
34
+ const styles = presentationStyle.textSlideParams?.cssStyles ?? [];
35
+ // NOTES: Taking advantage of CSS override rule (you can redefine it to override)
36
+ const extraStyles = beat.textSlideParams?.cssStyles ?? [];
37
+ // This code allows us to support both string and array of strings for cssStyles
38
+ return [...defaultTextSlideStyles, ...[styles], ...[extraStyles]].flat().join("\n");
39
+ },
40
+ getSpeechOptions(presentationStyle, beat) {
41
+ return { ...presentationStyle.speechParams.speakers[beat.speaker].speechOptions, ...beat.speechOptions };
42
+ },
43
+ getSpeaker(presentationStyle, beat) {
44
+ return presentationStyle.speechParams.speakers[beat.speaker];
45
+ },
46
+ getProvider(presentationStyle, beat) {
47
+ const speaker = MulmoPresentationStyleMethods.getSpeaker(presentationStyle, beat);
48
+ return speaker.provider ?? presentationStyle.speechParams.provider;
49
+ },
50
+ getVoiceId(presentationStyle, beat) {
51
+ const speaker = MulmoPresentationStyleMethods.getSpeaker(presentationStyle, beat);
52
+ return speaker.voiceId;
53
+ },
54
+ getImageAgentInfo(presentationStyle, dryRun = false) {
55
+ // Notice that we copy imageParams from presentationStyle and update
56
+ // provider and model appropriately.
57
+ const provider = text2ImageProviderSchema.parse(presentationStyle.imageParams?.provider);
58
+ const defaultImageParams = {
59
+ model: provider === "openai" ? process.env.DEFAULT_OPENAI_IMAGE_MODEL : undefined,
60
+ };
61
+ return {
62
+ provider,
63
+ agent: dryRun ? "mediaMockAgent" : provider === "google" ? "imageGoogleAgent" : "imageOpenaiAgent",
64
+ imageParams: { ...defaultImageParams, ...presentationStyle.imageParams },
65
+ };
66
+ },
67
+ getImageType(_, beat) {
68
+ return beat.image?.type == "movie" ? "movie" : "image";
69
+ },
70
+ };
@@ -6,6 +6,6 @@ export declare const MulmoScriptMethods: {
6
6
  getAllSpeechProviders(script: MulmoScript): Set<Text2SpeechProvider>;
7
7
  getTextSlideStyle(script: MulmoScript, beat: MulmoBeat): string;
8
8
  getSpeechOptions(script: MulmoScript, beat: MulmoBeat): SpeechOptions | undefined;
9
- getImageAgentInfo(script: MulmoScript): Text2ImageAgentInfo;
9
+ getImageAgentInfo(script: MulmoScript, dryRun?: boolean): Text2ImageAgentInfo;
10
10
  getImageType(_: MulmoScript, beat: MulmoBeat): BeatMediaType;
11
11
  };
@@ -40,7 +40,7 @@ export const MulmoScriptMethods = {
40
40
  getSpeechOptions(script, beat) {
41
41
  return { ...script.speechParams.speakers[beat.speaker].speechOptions, ...beat.speechOptions };
42
42
  },
43
- getImageAgentInfo(script) {
43
+ getImageAgentInfo(script, dryRun = false) {
44
44
  // Notice that we copy imageParams from script and update
45
45
  // provider and model appropriately.
46
46
  const provider = text2ImageProviderSchema.parse(script.imageParams?.provider);
@@ -49,7 +49,7 @@ export const MulmoScriptMethods = {
49
49
  };
50
50
  return {
51
51
  provider,
52
- agent: provider === "google" ? "imageGoogleAgent" : "imageOpenaiAgent",
52
+ agent: dryRun ? "mediaMockAgent" : provider === "google" ? "imageGoogleAgent" : "imageOpenaiAgent",
53
53
  imageParams: { ...defaultImageParams, ...script.imageParams },
54
54
  };
55
55
  },
@@ -1,8 +1,22 @@
1
1
  import { MulmoStudioContext } from "../types/index.js";
2
2
  type SessionType = "audio" | "image" | "video" | "multiLingual" | "caption" | "pdf";
3
3
  type BeatSessionType = "audio" | "image" | "multiLingual" | "caption" | "movie";
4
+ type SessionProgressEvent = {
5
+ kind: "session";
6
+ sessionType: SessionType;
7
+ inSession: boolean;
8
+ } | {
9
+ kind: "beat";
10
+ sessionType: BeatSessionType;
11
+ index: number;
12
+ inSession: boolean;
13
+ };
14
+ type SessionProgressCallback = (change: SessionProgressEvent) => void;
15
+ export declare const addSessionProgressCallback: (cb: SessionProgressCallback) => void;
16
+ export declare const removeSessionProgressCallback: (cb: SessionProgressCallback) => void;
4
17
  export declare const MulmoStudioContextMethods: {
5
18
  resolveAssetPath(context: MulmoStudioContext, relativePath: string): string;
19
+ getAudioDirPath(context: MulmoStudioContext): string;
6
20
  setSessionState(context: MulmoStudioContext, sessionType: SessionType, value: boolean): void;
7
21
  setBeatSessionState(context: MulmoStudioContext, sessionType: BeatSessionType, index: number, value: boolean): void;
8
22
  };
@@ -1,17 +1,35 @@
1
1
  import path from "path";
2
2
  import { GraphAILogger } from "graphai";
3
+ const sessionProgressCallbacks = new Set();
4
+ export const addSessionProgressCallback = (cb) => {
5
+ sessionProgressCallbacks.add(cb);
6
+ };
7
+ export const removeSessionProgressCallback = (cb) => {
8
+ sessionProgressCallbacks.delete(cb);
9
+ };
3
10
  const notifyStateChange = (context, sessionType) => {
4
- const prefix = context.sessionState.inSession[sessionType] ? "<" : " >";
11
+ const inSession = context.sessionState.inSession[sessionType] ?? false;
12
+ const prefix = inSession ? "<" : " >";
5
13
  GraphAILogger.info(`${prefix} ${sessionType}`);
14
+ for (const callback of sessionProgressCallbacks) {
15
+ callback({ kind: "session", sessionType, inSession });
16
+ }
6
17
  };
7
18
  const notifyBeatStateChange = (context, sessionType, index) => {
8
- const prefix = context.sessionState.inBeatSession[sessionType][index] ? "{" : " }";
19
+ const inSession = context.sessionState.inBeatSession[sessionType][index] ?? false;
20
+ const prefix = inSession ? "{" : " }";
9
21
  GraphAILogger.info(`${prefix} ${sessionType} ${index}`);
22
+ for (const callback of sessionProgressCallbacks) {
23
+ callback({ kind: "beat", sessionType, index, inSession });
24
+ }
10
25
  };
11
26
  export const MulmoStudioContextMethods = {
12
27
  resolveAssetPath(context, relativePath) {
13
28
  return path.resolve(context.fileDirs.mulmoFileDirPath, relativePath);
14
29
  },
30
+ getAudioDirPath(context) {
31
+ return context.fileDirs.audioDirPath;
32
+ },
15
33
  setSessionState(context, sessionType, value) {
16
34
  context.sessionState.inSession[sessionType] = value;
17
35
  notifyStateChange(context, sessionType);
@@ -0,0 +1,2 @@
1
+ import "dotenv/config";
2
+ export declare const deepResearch: () => Promise<void>;