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.
- package/README.md +5 -1
- package/assets/html/pdf_handout.html +85 -0
- package/assets/html/pdf_slide.html +55 -0
- package/assets/html/pdf_talk.html +76 -0
- package/assets/templates/text_and_image.json +6 -0
- package/assets/templates/text_only.json +6 -0
- package/lib/actions/audio.d.ts +3 -1
- package/lib/actions/audio.js +84 -45
- package/lib/actions/captions.js +1 -1
- package/lib/actions/images.d.ts +89 -1
- package/lib/actions/images.js +160 -99
- package/lib/actions/movie.js +28 -21
- package/lib/actions/pdf.d.ts +1 -0
- package/lib/actions/pdf.js +134 -204
- package/lib/actions/translate.js +1 -1
- package/lib/agents/add_bgm_agent.js +3 -3
- package/lib/agents/combine_audio_files_agent.js +11 -9
- package/lib/agents/image_mock_agent.d.ts +4 -0
- package/lib/agents/image_mock_agent.js +18 -0
- package/lib/agents/index.d.ts +4 -1
- package/lib/agents/index.js +4 -1
- package/lib/agents/media_mock_agent.d.ts +4 -0
- package/lib/agents/media_mock_agent.js +18 -0
- package/lib/agents/tavily_agent.d.ts +15 -0
- package/lib/agents/tavily_agent.js +130 -0
- package/lib/agents/tts_openai_agent.js +9 -1
- package/lib/cli/commands/audio/builder.d.ts +4 -0
- package/lib/cli/commands/image/builder.d.ts +4 -0
- package/lib/cli/commands/movie/builder.d.ts +4 -0
- package/lib/cli/commands/pdf/builder.d.ts +4 -0
- package/lib/cli/commands/translate/builder.d.ts +4 -0
- package/lib/cli/common.d.ts +4 -0
- package/lib/cli/common.js +11 -0
- package/lib/cli/helpers.d.ts +5 -1
- package/lib/cli/helpers.js +19 -2
- package/lib/methods/index.d.ts +1 -1
- package/lib/methods/index.js +1 -1
- package/lib/methods/mulmo_presentation_style.d.ts +14 -0
- package/lib/methods/mulmo_presentation_style.js +70 -0
- package/lib/methods/mulmo_script.d.ts +1 -1
- package/lib/methods/mulmo_script.js +2 -2
- package/lib/methods/mulmo_studio_context.d.ts +14 -0
- package/lib/methods/mulmo_studio_context.js +20 -2
- package/lib/tools/deep_research.d.ts +2 -0
- package/lib/tools/deep_research.js +265 -0
- package/lib/types/schema.d.ts +31 -0
- package/lib/types/schema.js +1 -1
- package/lib/types/type.d.ts +4 -1
- package/lib/utils/ffmpeg_utils.d.ts +1 -0
- package/lib/utils/ffmpeg_utils.js +10 -0
- package/lib/utils/file.d.ts +1 -3
- package/lib/utils/file.js +4 -11
- package/lib/utils/filters.js +1 -0
- package/lib/utils/markdown.js +1 -1
- package/lib/utils/preprocess.js +1 -0
- package/lib/utils/prompt.d.ts +3 -0
- package/lib/utils/prompt.js +52 -0
- package/package.json +10 -10
- package/assets/font/NotoSansJP-Regular.ttf +0 -0
- 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.
|
|
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
|
};
|
package/lib/cli/common.d.ts
CHANGED
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",
|
package/lib/cli/helpers.d.ts
CHANGED
|
@@ -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: {
|
package/lib/cli/helpers.js
CHANGED
|
@@ -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) {
|
package/lib/methods/index.d.ts
CHANGED
package/lib/methods/index.js
CHANGED
|
@@ -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
|
|
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
|
|
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);
|