mulmocast 1.1.5 → 1.1.7
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/lib/actions/audio.js +10 -1
- package/lib/actions/image_agents.d.ts +3 -12
- package/lib/actions/image_agents.js +12 -8
- package/lib/actions/images.js +2 -1
- package/lib/actions/translate.d.ts +51 -2
- package/lib/actions/translate.js +193 -148
- package/lib/agents/combine_audio_files_agent.js +1 -1
- package/lib/agents/lipsync_replicate_agent.js +10 -3
- package/lib/agents/tts_nijivoice_agent.js +1 -1
- package/lib/cli/commands/audio/handler.js +1 -1
- package/lib/cli/commands/image/handler.js +1 -1
- package/lib/cli/commands/movie/handler.js +1 -1
- package/lib/cli/commands/pdf/handler.js +1 -1
- package/lib/cli/helpers.d.ts +1 -4
- package/lib/cli/helpers.js +3 -2
- package/lib/index.common.d.ts +1 -0
- package/lib/index.common.js +1 -0
- package/lib/mcp/server.js +1 -1
- package/lib/methods/mulmo_presentation_style.d.ts +3 -2
- package/lib/methods/mulmo_script.d.ts +4 -1
- package/lib/methods/mulmo_script.js +18 -2
- package/lib/methods/mulmo_studio_context.d.ts +1 -0
- package/lib/methods/mulmo_studio_context.js +8 -0
- package/lib/types/agent.d.ts +1 -0
- package/lib/types/schema.d.ts +326 -230
- package/lib/types/schema.js +10 -3
- package/lib/types/type.d.ts +3 -2
- package/lib/utils/const.d.ts +1 -0
- package/lib/utils/const.js +2 -1
- package/lib/utils/context.d.ts +393 -50
- package/lib/utils/context.js +90 -57
- package/lib/utils/filters.d.ts +1 -0
- package/lib/utils/filters.js +8 -0
- package/lib/utils/image_plugins/mermaid.js +1 -1
- package/lib/utils/image_plugins/source.js +1 -1
- package/lib/utils/preprocess.d.ts +2 -2
- package/lib/utils/preprocess.js +3 -3
- package/lib/utils/provider2agent.d.ts +3 -2
- package/lib/utils/provider2agent.js +20 -2
- package/lib/utils/string.d.ts +1 -1
- package/lib/utils/string.js +12 -8
- package/lib/utils/utils.js +2 -6
- package/package.json +2 -2
- package/scripts/templates/image_refs.json +1 -0
- package/scripts/templates/voice_over.json +1 -0
- package/scripts/test/gpt.json +1 -0
- package/scripts/test/test1.json +1 -0
- package/scripts/test/test_audio.json +1 -0
- package/scripts/test/test_audio_instructions.json +1 -0
- package/scripts/test/test_beats.json +1 -0
- package/scripts/test/test_captions.json +1 -0
- package/scripts/test/test_elevenlabs_models.json +1 -0
- package/scripts/test/test_hello.json +1 -0
- package/scripts/test/test_hello_google.json +1 -0
- package/scripts/test/test_html.json +1 -0
- package/scripts/test/test_image_refs.json +1 -0
- package/scripts/test/test_images.json +1 -0
- package/scripts/test/test_lang.json +58 -2
- package/scripts/test/test_layout.json +1 -0
- package/scripts/test/test_lipsync.json +9 -0
- package/scripts/test/test_loop.json +1 -0
- package/scripts/test/test_media.json +1 -0
- package/scripts/test/test_mixed_providers.json +1 -0
- package/scripts/test/test_movie.json +1 -0
- package/scripts/test/test_no_audio.json +1 -0
- package/scripts/test/test_no_audio_with_credit.json +1 -0
- package/scripts/test/test_order.json +1 -0
- package/scripts/test/test_order_portrait.json +1 -0
- package/scripts/test/test_replicate.json +19 -0
- package/scripts/test/test_slideout_left_no_audio.json +1 -0
- package/scripts/test/test_spillover.json +1 -0
- package/scripts/test/test_transition.json +1 -0
- package/scripts/test/test_transition_no_audio.json +1 -0
- package/scripts/test/test_video_speed.json +1 -0
- package/scripts/test/test_voice_over.json +1 -0
- package/scripts/test/test_voices.json +1 -0
- package/scripts/templates/image_prompt_only_template.ts +0 -95
package/lib/utils/context.js
CHANGED
|
@@ -1,44 +1,27 @@
|
|
|
1
1
|
import { GraphAILogger } from "graphai";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import { readMulmoScriptFile, fetchMulmoScriptFile } from "./file.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
while (dataSet.length < studioBeatsLength) {
|
|
26
|
-
dataSet.push({ multiLingualTexts: {} });
|
|
27
|
-
}
|
|
28
|
-
dataSet.length = studioBeatsLength;
|
|
29
|
-
return dataSet;
|
|
30
|
-
}
|
|
31
|
-
return [...Array(studioBeatsLength)].map(() => ({ multiLingualTexts: {} }));
|
|
32
|
-
};
|
|
33
|
-
export const getPresentationStyle = (presentationStylePath) => {
|
|
34
|
-
if (presentationStylePath) {
|
|
35
|
-
if (!fs.existsSync(presentationStylePath)) {
|
|
36
|
-
throw new Error(`ERROR: File not exists ${presentationStylePath}`);
|
|
37
|
-
}
|
|
38
|
-
const jsonData = readMulmoScriptFile(presentationStylePath, "ERROR: File does not exist " + presentationStylePath)?.mulmoData ?? null;
|
|
39
|
-
return mulmoPresentationStyleSchema.parse(jsonData);
|
|
40
|
-
}
|
|
41
|
-
return null;
|
|
4
|
+
import { mulmoStudioSchema, mulmoCaptionParamsSchema, mulmoPresentationStyleSchema } from "../types/schema.js";
|
|
5
|
+
import { MulmoPresentationStyleMethods, MulmoScriptMethods, MulmoStudioMultiLingualMethod } from "../methods/index.js";
|
|
6
|
+
const mulmoCredit = (speaker) => {
|
|
7
|
+
return {
|
|
8
|
+
speaker,
|
|
9
|
+
text: "",
|
|
10
|
+
image: {
|
|
11
|
+
type: "image",
|
|
12
|
+
source: {
|
|
13
|
+
kind: "url",
|
|
14
|
+
url: "https://github.com/receptron/mulmocast-cli/raw/refs/heads/main/assets/images/mulmocast_credit.png",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
audio: {
|
|
18
|
+
type: "audio",
|
|
19
|
+
source: {
|
|
20
|
+
kind: "url",
|
|
21
|
+
url: "https://github.com/receptron/mulmocast-cli/raw/refs/heads/main/assets/audio/silent300.mp3",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
42
25
|
};
|
|
43
26
|
const initSessionState = () => {
|
|
44
27
|
return {
|
|
@@ -63,32 +46,82 @@ const initSessionState = () => {
|
|
|
63
46
|
},
|
|
64
47
|
};
|
|
65
48
|
};
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
49
|
+
export const createStudioData = (_mulmoScript, fileName, videoCaptionLang, presentationStyle) => {
|
|
50
|
+
// validate and insert default value
|
|
51
|
+
const mulmoScript = _mulmoScript.__test_invalid__ ? _mulmoScript : MulmoScriptMethods.validate(_mulmoScript);
|
|
52
|
+
// We need to parse it to fill default values
|
|
53
|
+
const studio = mulmoStudioSchema.parse({
|
|
54
|
+
script: mulmoScript,
|
|
55
|
+
filename: fileName,
|
|
56
|
+
beats: [...Array(mulmoScript.beats.length)].map(() => ({})),
|
|
57
|
+
});
|
|
58
|
+
// TODO: Move this code out of this function later
|
|
59
|
+
// Addition cloing credit
|
|
60
|
+
if (mulmoScript.$mulmocast.credit === "closing") {
|
|
61
|
+
const defaultSpeaker = MulmoPresentationStyleMethods.getDefaultSpeaker(presentationStyle ?? studio.script);
|
|
62
|
+
mulmoScript.beats.push(mulmoCredit(mulmoScript.beats[0].speaker ?? defaultSpeaker)); // First speaker
|
|
63
|
+
}
|
|
64
|
+
studio.script = MulmoScriptMethods.validate(mulmoScript); // update the script
|
|
65
|
+
studio.beats = studio.script.beats.map((_, index) => studio.beats[index] ?? {});
|
|
66
|
+
if (videoCaptionLang) {
|
|
67
|
+
studio.script.captionParams = mulmoCaptionParamsSchema.parse({
|
|
68
|
+
...(studio.script.captionParams ?? {}),
|
|
69
|
+
lang: videoCaptionLang,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return studio;
|
|
73
|
+
};
|
|
74
|
+
export const fetchScript = async (isHttpPath, mulmoFilePath, fileOrUrl) => {
|
|
75
|
+
if (isHttpPath) {
|
|
76
|
+
const res = await fetchMulmoScriptFile(fileOrUrl);
|
|
77
|
+
if (!res.result || !res.script) {
|
|
78
|
+
GraphAILogger.info(`ERROR: HTTP error! ${res.status} ${fileOrUrl}`);
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return res.script;
|
|
82
|
+
}
|
|
83
|
+
if (!fs.existsSync(mulmoFilePath)) {
|
|
84
|
+
GraphAILogger.info(`ERROR: File not exists ${mulmoFilePath}`);
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return readMulmoScriptFile(mulmoFilePath, "ERROR: File does not exist " + mulmoFilePath)?.mulmoData ?? null;
|
|
88
|
+
};
|
|
89
|
+
export const getMultiLingual = (multilingualFilePath, studioBeatsLength) => {
|
|
90
|
+
if (!fs.existsSync(multilingualFilePath)) {
|
|
91
|
+
return [...Array(studioBeatsLength)].map(() => ({ multiLingualTexts: {} }));
|
|
92
|
+
}
|
|
93
|
+
const jsonData = readMulmoScriptFile(multilingualFilePath, "ERROR: File does not exist " + multilingualFilePath)?.mulmoData ?? null;
|
|
94
|
+
return MulmoStudioMultiLingualMethod.validate(jsonData, studioBeatsLength);
|
|
95
|
+
};
|
|
96
|
+
export const getPresentationStyle = (presentationStylePath) => {
|
|
97
|
+
if (!presentationStylePath) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
if (!fs.existsSync(presentationStylePath)) {
|
|
101
|
+
throw new Error(`ERROR: File not exists ${presentationStylePath}`);
|
|
102
|
+
}
|
|
103
|
+
const jsonData = readMulmoScriptFile(presentationStylePath, "ERROR: File does not exist " + presentationStylePath)?.mulmoData ?? null;
|
|
104
|
+
return mulmoPresentationStyleSchema.parse(jsonData);
|
|
76
105
|
};
|
|
77
|
-
export const initializeContextFromFiles = async (files, raiseError, force,
|
|
78
|
-
const { fileName, isHttpPath, fileOrUrl, mulmoFilePath,
|
|
79
|
-
// read mulmoScript, presentationStyle, currentStudio from files
|
|
106
|
+
export const initializeContextFromFiles = async (files, raiseError, force, captionLang, targetLang) => {
|
|
107
|
+
const { fileName, isHttpPath, fileOrUrl, mulmoFilePath, presentationStylePath, outputMultilingualFilePath } = files;
|
|
80
108
|
const mulmoScript = await fetchScript(isHttpPath, mulmoFilePath, fileOrUrl);
|
|
81
109
|
if (!mulmoScript) {
|
|
82
110
|
return null;
|
|
83
111
|
}
|
|
84
|
-
const presentationStyle = getPresentationStyle(presentationStylePath);
|
|
85
|
-
// Create or update MulmoStudio file with MulmoScript
|
|
86
|
-
const currentStudio = readMulmoScriptFile(outputStudioFilePath);
|
|
87
112
|
try {
|
|
88
|
-
|
|
89
|
-
const studio =
|
|
113
|
+
const presentationStyle = getPresentationStyle(presentationStylePath);
|
|
114
|
+
const studio = createStudioData(mulmoScript, fileName, captionLang, presentationStyle);
|
|
90
115
|
const multiLingual = getMultiLingual(outputMultilingualFilePath, studio.beats.length);
|
|
91
|
-
return
|
|
116
|
+
return {
|
|
117
|
+
studio,
|
|
118
|
+
multiLingual,
|
|
119
|
+
fileDirs: files,
|
|
120
|
+
presentationStyle: presentationStyle ?? studio.script,
|
|
121
|
+
sessionState: initSessionState(),
|
|
122
|
+
force: Boolean(force),
|
|
123
|
+
lang: targetLang ?? studio.script.lang, // This lang is target Language. studio.lang is default Language
|
|
124
|
+
};
|
|
92
125
|
}
|
|
93
126
|
catch (error) {
|
|
94
127
|
GraphAILogger.info(`Error: invalid MulmoScript Schema: ${isHttpPath ? fileOrUrl : mulmoFilePath} \n ${error}`);
|
package/lib/utils/filters.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
2
|
import type { AgentFilterFunction } from "graphai";
|
|
3
|
+
export declare const nijovoiceTextAgentFilter: AgentFilterFunction;
|
|
3
4
|
export declare const fileCacheAgentFilter: AgentFilterFunction;
|
|
4
5
|
export declare const browserlessCacheGenerator: (cacheDir: string) => AgentFilterFunction;
|
package/lib/utils/filters.js
CHANGED
|
@@ -6,6 +6,14 @@ import { GraphAILogger } from "graphai";
|
|
|
6
6
|
import { writingMessage } from "./file.js";
|
|
7
7
|
import { text2hash } from "./utils.js";
|
|
8
8
|
import { MulmoStudioContextMethods } from "../methods/mulmo_studio_context.js";
|
|
9
|
+
import { replacementsJa, replacePairsJa } from "../utils/string.js";
|
|
10
|
+
export const nijovoiceTextAgentFilter = async (context, next) => {
|
|
11
|
+
const { text, provider, lang } = context.namedInputs;
|
|
12
|
+
if (provider === "nijivoice" && lang === "ja") {
|
|
13
|
+
context.namedInputs.text = replacePairsJa(replacementsJa)(text);
|
|
14
|
+
}
|
|
15
|
+
return next(context);
|
|
16
|
+
};
|
|
9
17
|
export const fileCacheAgentFilter = async (context, next) => {
|
|
10
18
|
const { force, file, index, mulmoContext, sessionType } = context.namedInputs.cache;
|
|
11
19
|
const shouldUseCache = async () => {
|
|
@@ -5,7 +5,7 @@ import { parrotingImagePath } from "./utils.js";
|
|
|
5
5
|
export const imageType = "mermaid";
|
|
6
6
|
const processMermaid = async (params) => {
|
|
7
7
|
const { beat, imagePath, canvasSize, context, textSlideStyle } = params;
|
|
8
|
-
if (!beat
|
|
8
|
+
if (!beat?.image || beat.image.type !== imageType)
|
|
9
9
|
return;
|
|
10
10
|
const template = getHTMLFile("mermaid");
|
|
11
11
|
const diagram_code = await MulmoMediaSourceMethods.getText(beat.image.code, context);
|
|
@@ -3,7 +3,7 @@ import { MulmoMediaSourceMethods } from "../../methods/mulmo_media_source.js";
|
|
|
3
3
|
export const processSource = (imageType) => {
|
|
4
4
|
return (params) => {
|
|
5
5
|
const { beat, context } = params;
|
|
6
|
-
if (!beat
|
|
6
|
+
if (!beat?.image || beat.image.type !== imageType)
|
|
7
7
|
return;
|
|
8
8
|
const path = MulmoMediaSourceMethods.resolve(beat.image.source, context);
|
|
9
9
|
if (path) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MulmoStudio, MulmoScript, MulmoPresentationStyle } from "../types/index.js";
|
|
2
|
-
export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, currentStudio: MulmoStudio | undefined, fileName: string,
|
|
2
|
+
export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, currentStudio: MulmoStudio | undefined, fileName: string, videoCaptionLang?: string, presentationStyle?: MulmoPresentationStyle | null) => {
|
|
3
3
|
beats: {
|
|
4
4
|
duration?: number | undefined;
|
|
5
5
|
startAt?: number | undefined;
|
|
@@ -16,6 +16,7 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
|
|
|
16
16
|
captionFile?: string | undefined;
|
|
17
17
|
}[];
|
|
18
18
|
script: {
|
|
19
|
+
lang: string;
|
|
19
20
|
imageParams: {
|
|
20
21
|
provider: string;
|
|
21
22
|
model?: string | undefined;
|
|
@@ -312,7 +313,6 @@ export declare const createOrUpdateStudioData: (_mulmoScript: MulmoScript, curre
|
|
|
312
313
|
} | undefined;
|
|
313
314
|
enableLipSync?: boolean | undefined;
|
|
314
315
|
}[];
|
|
315
|
-
lang?: string | undefined;
|
|
316
316
|
title?: string | undefined;
|
|
317
317
|
description?: string | undefined;
|
|
318
318
|
lipSyncParams?: {
|
package/lib/utils/preprocess.js
CHANGED
|
@@ -37,7 +37,7 @@ const mulmoCredit = (speaker) => {
|
|
|
37
37
|
},
|
|
38
38
|
};
|
|
39
39
|
};
|
|
40
|
-
export const createOrUpdateStudioData = (_mulmoScript, currentStudio, fileName,
|
|
40
|
+
export const createOrUpdateStudioData = (_mulmoScript, currentStudio, fileName, videoCaptionLang, presentationStyle) => {
|
|
41
41
|
const mulmoScript = _mulmoScript.__test_invalid__ ? _mulmoScript : MulmoScriptMethods.validate(_mulmoScript); // validate and insert default value
|
|
42
42
|
const studio = rebuildStudio(currentStudio, mulmoScript, fileName);
|
|
43
43
|
// TODO: Move this code out of this function later
|
|
@@ -48,10 +48,10 @@ export const createOrUpdateStudioData = (_mulmoScript, currentStudio, fileName,
|
|
|
48
48
|
}
|
|
49
49
|
studio.script = MulmoScriptMethods.validate(mulmoScript); // update the script
|
|
50
50
|
studio.beats = studio.script.beats.map((_, index) => studio.beats[index] ?? {});
|
|
51
|
-
if (
|
|
51
|
+
if (videoCaptionLang) {
|
|
52
52
|
studio.script.captionParams = mulmoCaptionParamsSchema.parse({
|
|
53
53
|
...(studio.script.captionParams ?? {}),
|
|
54
|
-
lang:
|
|
54
|
+
lang: videoCaptionLang,
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
return studio;
|
|
@@ -67,9 +67,10 @@ export declare const provider2LipSyncAgent: {
|
|
|
67
67
|
defaultModel: ReplicateModel;
|
|
68
68
|
models: ReplicateModel[];
|
|
69
69
|
modelParams: Record<ReplicateModel, {
|
|
70
|
-
identifier?: `${string}/${string}:${string}`;
|
|
71
|
-
video
|
|
70
|
+
identifier?: `${string}/${string}:${string}` | `${string}/${string}`;
|
|
71
|
+
video?: string;
|
|
72
72
|
audio: string;
|
|
73
|
+
image?: string;
|
|
73
74
|
}>;
|
|
74
75
|
};
|
|
75
76
|
};
|
|
@@ -50,6 +50,8 @@ export const provider2MovieAgent = {
|
|
|
50
50
|
"minimax/video-01",
|
|
51
51
|
"minimax/hailuo-02",
|
|
52
52
|
"pixverse/pixverse-v4.5",
|
|
53
|
+
"wan-video/wan-2.2-i2v-480p-fast",
|
|
54
|
+
"wan-video/wan-2.2-t2v-480p-fast",
|
|
53
55
|
],
|
|
54
56
|
modelParams: {
|
|
55
57
|
"bytedance/seedance-1-lite": {
|
|
@@ -110,6 +112,16 @@ export const provider2MovieAgent = {
|
|
|
110
112
|
last_image: "last_frame_image",
|
|
111
113
|
price_per_sec: 0.12,
|
|
112
114
|
},
|
|
115
|
+
"wan-video/wan-2.2-i2v-480p-fast": {
|
|
116
|
+
durations: [5],
|
|
117
|
+
start_image: "image",
|
|
118
|
+
price_per_sec: 0.012,
|
|
119
|
+
},
|
|
120
|
+
"wan-video/wan-2.2-t2v-480p-fast": {
|
|
121
|
+
durations: [5],
|
|
122
|
+
start_image: undefined,
|
|
123
|
+
price_per_sec: 0.012,
|
|
124
|
+
},
|
|
113
125
|
},
|
|
114
126
|
},
|
|
115
127
|
google: {
|
|
@@ -133,8 +145,8 @@ export const provider2SoundEffectAgent = {
|
|
|
133
145
|
export const provider2LipSyncAgent = {
|
|
134
146
|
replicate: {
|
|
135
147
|
agentName: "lipSyncReplicateAgent",
|
|
136
|
-
defaultModel: "bytedance/
|
|
137
|
-
models: ["bytedance/latentsync", "tmappdev/lipsync"],
|
|
148
|
+
defaultModel: "bytedance/omni-human",
|
|
149
|
+
models: ["bytedance/latentsync", "tmappdev/lipsync", "bytedance/omni-human"],
|
|
138
150
|
modelParams: {
|
|
139
151
|
"bytedance/latentsync": {
|
|
140
152
|
identifier: "bytedance/latentsync:637ce1919f807ca20da3a448ddc2743535d2853649574cd52a933120e9b9e293",
|
|
@@ -146,6 +158,12 @@ export const provider2LipSyncAgent = {
|
|
|
146
158
|
video: "video_input",
|
|
147
159
|
audio: "audio_input",
|
|
148
160
|
},
|
|
161
|
+
"bytedance/omni-human": {
|
|
162
|
+
identifier: "bytedance/omni-human",
|
|
163
|
+
image: "image",
|
|
164
|
+
audio: "audio",
|
|
165
|
+
price_per_sec: 0.14,
|
|
166
|
+
},
|
|
149
167
|
/* NOTE: This model does not work with large base64 urls.
|
|
150
168
|
"sync/lipsync-2": {
|
|
151
169
|
video: "video",
|
package/lib/utils/string.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ interface Replacement {
|
|
|
4
4
|
from: string;
|
|
5
5
|
to: string;
|
|
6
6
|
}
|
|
7
|
-
export declare function replacePairsJa(
|
|
7
|
+
export declare function replacePairsJa(replacements: Replacement[]): (str: string) => string;
|
|
8
8
|
export declare const replacementsJa: Replacement[];
|
|
9
9
|
export {};
|
package/lib/utils/string.js
CHANGED
|
@@ -24,14 +24,16 @@ export const recursiveSplitJa = (text) => {
|
|
|
24
24
|
}, [text])
|
|
25
25
|
.flat(1);
|
|
26
26
|
};
|
|
27
|
-
export function replacePairsJa(
|
|
28
|
-
return
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
export function replacePairsJa(replacements) {
|
|
28
|
+
return (str) => {
|
|
29
|
+
return replacements.reduce((tmp, current) => {
|
|
30
|
+
const { from, to } = current;
|
|
31
|
+
// Escape any special regex characters in the 'from' string.
|
|
32
|
+
const escapedFrom = from.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
33
|
+
const regex = new RegExp(escapedFrom, "g");
|
|
34
|
+
return tmp.replace(regex, to);
|
|
35
|
+
}, str);
|
|
36
|
+
};
|
|
35
37
|
}
|
|
36
38
|
export const replacementsJa = [
|
|
37
39
|
{ from: "Anthropic", to: "アンスロピック" },
|
|
@@ -51,4 +53,6 @@ export const replacementsJa = [
|
|
|
51
53
|
{ from: "5つ", to: "いつつ" },
|
|
52
54
|
{ from: "危険な面", to: "危険なめん" },
|
|
53
55
|
{ from: "その通り!", to: "その通り。" },
|
|
56
|
+
{ from: "%", to: "パーセント" },
|
|
57
|
+
{ from: "IPO", to: "アイピーオー" },
|
|
54
58
|
];
|
package/lib/utils/utils.js
CHANGED
|
@@ -21,12 +21,8 @@ export const text2hash = (input) => {
|
|
|
21
21
|
return crypto.createHash("sha256").update(input).digest("hex");
|
|
22
22
|
};
|
|
23
23
|
export const localizedText = (beat, multiLingualData, lang) => {
|
|
24
|
-
if (lang &&
|
|
25
|
-
multiLingualData
|
|
26
|
-
multiLingualData?.multiLingualTexts &&
|
|
27
|
-
multiLingualData?.multiLingualTexts[lang] &&
|
|
28
|
-
multiLingualData?.multiLingualTexts[lang].text) {
|
|
29
|
-
return multiLingualData?.multiLingualTexts[lang].text;
|
|
24
|
+
if (lang && multiLingualData?.multiLingualTexts?.[lang]?.text) {
|
|
25
|
+
return multiLingualData.multiLingualTexts[lang].text;
|
|
30
26
|
}
|
|
31
27
|
return beat.text;
|
|
32
28
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mulmocast",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.node.js",
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"prettier": "^3.6.2",
|
|
106
106
|
"ts-node": "^10.9.2",
|
|
107
107
|
"tsx": "^4.20.3",
|
|
108
|
-
"typescript": "^5.
|
|
108
|
+
"typescript": "^5.9.2",
|
|
109
109
|
"typescript-eslint": "^8.37.0"
|
|
110
110
|
},
|
|
111
111
|
"engines": {
|
package/scripts/test/gpt.json
CHANGED
package/scripts/test/test1.json
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"version": "1.1",
|
|
4
4
|
"credit": "closing"
|
|
5
5
|
},
|
|
6
|
+
"lang": "en",
|
|
6
7
|
"title": "The Honey Trap vs. The Frontier: Engineering at Tesla and SpaceX",
|
|
7
8
|
"description": "We dive into Elon Musk's philosophy on building environments where engineers can truly flourish, contrasting the comfort-focused 'honey trap' with the high-expectation culture at Tesla and SpaceX.",
|
|
8
9
|
"speechParams": {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$mulmocast": {
|
|
3
3
|
"version": "1.1"
|
|
4
4
|
},
|
|
5
|
-
"lang": "
|
|
5
|
+
"lang": "en",
|
|
6
6
|
"speechParams": {
|
|
7
7
|
"speakers": {
|
|
8
8
|
"Presenter": {
|
|
@@ -19,13 +19,69 @@
|
|
|
19
19
|
},
|
|
20
20
|
"beats": [
|
|
21
21
|
{
|
|
22
|
-
"text": "
|
|
22
|
+
"text": "Hello World",
|
|
23
23
|
"image": {
|
|
24
24
|
"type": "textSlide",
|
|
25
25
|
"slide": {
|
|
26
26
|
"title": "Hello World"
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"text": "Switching Language and Switching Screen should match.",
|
|
32
|
+
"image": {
|
|
33
|
+
"type": "textSlide",
|
|
34
|
+
"slide": {
|
|
35
|
+
"title": "Switching Language"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"text": "May the force be with you.",
|
|
41
|
+
"image": {
|
|
42
|
+
"type": "textSlide",
|
|
43
|
+
"slide": {
|
|
44
|
+
"title": "May the force be with you"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"text": "Switching Language and Switching Screen should match even with a short duration.",
|
|
50
|
+
"duration": 1,
|
|
51
|
+
"image": {
|
|
52
|
+
"type": "textSlide",
|
|
53
|
+
"slide": {
|
|
54
|
+
"title": "Switching Language (short duration)"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"text": "Switching Language and Switching Screen should match even with a long duration.",
|
|
60
|
+
"duration": 8,
|
|
61
|
+
"image": {
|
|
62
|
+
"type": "textSlide",
|
|
63
|
+
"slide": {
|
|
64
|
+
"title": "Switching Language (long duration)"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"text": "The yield of TSMC's 3nm process exceeds 70%.",
|
|
70
|
+
"image": {
|
|
71
|
+
"type": "textSlide",
|
|
72
|
+
"slide": {
|
|
73
|
+
"title": "Text replacement test for nijivoice"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"text": "Goodbye",
|
|
79
|
+
"image": {
|
|
80
|
+
"type": "textSlide",
|
|
81
|
+
"slide": {
|
|
82
|
+
"title": "Goodbye"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
29
85
|
}
|
|
30
86
|
]
|
|
31
87
|
}
|
|
@@ -33,6 +33,15 @@
|
|
|
33
33
|
"model": "tmappdev/lipsync"
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
|
+
{
|
|
37
|
+
"id": "future_omni_human_photo_realistic",
|
|
38
|
+
"text": "In the future, advancements in AI could revolutionize industries like healthcare, education, and transportation.",
|
|
39
|
+
"imagePrompt": "A female presenter is standing in front of a futuristic cityscape with AI-powered hospital and an autonomous vehicle. Photo realistic.",
|
|
40
|
+
"enableLipSync": true,
|
|
41
|
+
"lipSyncParams": {
|
|
42
|
+
"model": "bytedance/omni-human"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
36
45
|
{
|
|
37
46
|
"id": "future_possibilities",
|
|
38
47
|
"text": "In the future, advancements in AI could revolutionize industries like healthcare, education, and transportation.",
|