mulmocast 1.1.0 → 1.1.1
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/assets/templates/ani.json +2 -2
- package/assets/templates/ani_ja.json +2 -2
- package/lib/actions/image_agents.d.ts +21 -0
- package/lib/actions/image_agents.js +7 -0
- package/lib/actions/images.js +33 -4
- package/lib/actions/movie.js +3 -2
- package/lib/agents/index.d.ts +2 -1
- package/lib/agents/index.js +2 -1
- package/lib/agents/lipsync_replicate_agent.d.ts +5 -0
- package/lib/agents/lipsync_replicate_agent.js +57 -0
- package/lib/data/index.d.ts +2 -0
- package/lib/data/index.js +2 -0
- package/lib/data/promptTemplates.d.ts +695 -0
- package/lib/data/promptTemplates.js +957 -0
- package/lib/data/scriptTemplates.d.ts +233 -0
- package/lib/data/scriptTemplates.js +580 -0
- package/lib/index.browser.d.ts +2 -1
- package/lib/index.browser.js +2 -1
- package/lib/methods/mulmo_presentation_style.d.ts +8 -0
- package/lib/methods/mulmo_presentation_style.js +8 -1
- package/lib/tools/story_to_script.js +2 -2
- package/lib/types/agent.d.ts +10 -0
- package/lib/types/schema.d.ts +230 -0
- package/lib/types/schema.js +9 -0
- package/lib/types/type.d.ts +1 -1
- package/lib/utils/context.d.ts +15 -0
- package/lib/utils/context.js +1 -0
- package/lib/utils/file.d.ts +8 -3
- package/lib/utils/file.js +46 -20
- package/lib/utils/preprocess.d.ts +10 -0
- package/lib/utils/provider2agent.d.ts +11 -0
- package/lib/utils/provider2agent.js +13 -0
- package/lib/utils/utils.js +3 -0
- package/package.json +8 -4
- package/scripts/templates/business.json +1 -1
- package/scripts/templates/children_book.json +1 -1
- package/scripts/templates/coding.json +1 -1
- package/scripts/templates/html.json +1 -1
- package/scripts/templates/image_prompt_only_template.json +1 -1
- package/scripts/templates/image_prompts_template.json +1 -1
- package/scripts/templates/image_refs.json +1 -1
- package/scripts/templates/movie_prompts_no_text_template.json +1 -1
- package/scripts/templates/movie_prompts_template.json +1 -1
- package/scripts/templates/presentation.json +1 -1
- package/scripts/templates/sensei_and_taro.json +1 -1
- package/scripts/templates/shorts_template.json +1 -1
- package/scripts/templates/text_only_template.json +1 -1
- package/scripts/templates/voice_over.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"title": "Presentation with Ani
|
|
3
|
-
"description": "Template for presentation with Ani
|
|
2
|
+
"title": "Presentation with Ani",
|
|
3
|
+
"description": "Template for presentation with Ani.",
|
|
4
4
|
"systemPrompt": "Generate a script for a presentation of the given topic. 言葉づかいは少しツンデレにして。Another AI will generate comic for each beat based on the image prompt of that beat. You don't need to specify the style of the image, just describe the scene. Mention the reference in one of beats, if it exists. Use the JSON below as a template. Create appropriate amount of beats, and make sure the beats are coherent and flow well.",
|
|
5
5
|
"presentationStyle": {
|
|
6
6
|
"$mulmocast": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"title": "Presentation with Ani",
|
|
3
|
-
"description": "Template for presentation with Ani.",
|
|
2
|
+
"title": "Presentation with Ani in Japanese",
|
|
3
|
+
"description": "Template for presentation with Ani in Japanese.",
|
|
4
4
|
"systemPrompt": "Generate a Japanese script for a presentation of the given topic. 言葉づかいは少しツンデレにして。Another AI will generate comic for each beat based on the image prompt of that beat. You don't need to specify the style of the image, just describe the scene. Mention the reference in one of beats, if it exists. Use the JSON below as a template. Create appropriate amount of beats, and make sure the beats are coherent and flow well.",
|
|
5
5
|
"presentationStyle": {
|
|
6
6
|
"$mulmocast": {
|
|
@@ -21,6 +21,13 @@ export declare const imagePreprocessAgent: (namedInputs: {
|
|
|
21
21
|
agentName: string;
|
|
22
22
|
defaultModel: string;
|
|
23
23
|
};
|
|
24
|
+
lipSyncFile?: string;
|
|
25
|
+
lipSyncModel?: string;
|
|
26
|
+
lipSyncAgentInfo?: {
|
|
27
|
+
agentName: string;
|
|
28
|
+
defaultModel: string;
|
|
29
|
+
};
|
|
30
|
+
audioFile?: string;
|
|
24
31
|
htmlPrompt?: undefined;
|
|
25
32
|
htmlPath?: undefined;
|
|
26
33
|
htmlImageSystemPrompt?: undefined;
|
|
@@ -51,6 +58,13 @@ export declare const imagePreprocessAgent: (namedInputs: {
|
|
|
51
58
|
agentName: string;
|
|
52
59
|
defaultModel: string;
|
|
53
60
|
};
|
|
61
|
+
lipSyncFile?: string;
|
|
62
|
+
lipSyncModel?: string;
|
|
63
|
+
lipSyncAgentInfo?: {
|
|
64
|
+
agentName: string;
|
|
65
|
+
defaultModel: string;
|
|
66
|
+
};
|
|
67
|
+
audioFile?: string;
|
|
54
68
|
htmlPrompt?: undefined;
|
|
55
69
|
htmlPath?: undefined;
|
|
56
70
|
htmlImageSystemPrompt?: undefined;
|
|
@@ -84,6 +98,13 @@ export declare const imagePreprocessAgent: (namedInputs: {
|
|
|
84
98
|
agentName: string;
|
|
85
99
|
defaultModel: string;
|
|
86
100
|
};
|
|
101
|
+
lipSyncFile?: string;
|
|
102
|
+
lipSyncModel?: string;
|
|
103
|
+
lipSyncAgentInfo?: {
|
|
104
|
+
agentName: string;
|
|
105
|
+
defaultModel: string;
|
|
106
|
+
};
|
|
107
|
+
audioFile?: string;
|
|
87
108
|
htmlPrompt?: undefined;
|
|
88
109
|
htmlPath?: undefined;
|
|
89
110
|
htmlImageSystemPrompt?: undefined;
|
|
@@ -30,6 +30,13 @@ export const imagePreprocessAgent = async (namedInputs) => {
|
|
|
30
30
|
returnValue.soundEffectFile = moviePaths.soundEffectFile;
|
|
31
31
|
returnValue.soundEffectPrompt = beat.soundEffectPrompt;
|
|
32
32
|
}
|
|
33
|
+
if (beat.enableLipSync) {
|
|
34
|
+
returnValue.lipSyncAgentInfo = MulmoPresentationStyleMethods.getLipSyncAgentInfo(context.presentationStyle, beat);
|
|
35
|
+
returnValue.lipSyncModel = beat.lipSyncParams?.model ?? context.presentationStyle.lipSyncParams?.model ?? returnValue.lipSyncAgentInfo.defaultModel;
|
|
36
|
+
returnValue.lipSyncFile = moviePaths.lipSyncFile;
|
|
37
|
+
// Audio file will be set from the beat's audio file when available
|
|
38
|
+
returnValue.audioFile = context.studio.beats[index]?.audioFile;
|
|
39
|
+
}
|
|
33
40
|
if (beat.image) {
|
|
34
41
|
const plugin = MulmoBeatMethods.getPlugin(beat);
|
|
35
42
|
const pluginPath = plugin.path({ beat, context, imagePath, ...htmlStyle(context, beat) });
|
package/lib/actions/images.js
CHANGED
|
@@ -6,7 +6,7 @@ import * as vanilla from "@graphai/vanilla";
|
|
|
6
6
|
import { openAIAgent } from "@graphai/openai_agent";
|
|
7
7
|
import { anthropicAgent } from "@graphai/anthropic_agent";
|
|
8
8
|
import { fileWriteAgent } from "@graphai/vanilla_node_agents";
|
|
9
|
-
import { imageGoogleAgent, imageOpenaiAgent, movieGoogleAgent, movieReplicateAgent, mediaMockAgent, soundEffectReplicateAgent } from "../agents/index.js";
|
|
9
|
+
import { imageGoogleAgent, imageOpenaiAgent, movieGoogleAgent, movieReplicateAgent, mediaMockAgent, soundEffectReplicateAgent, lipSyncReplicateAgent, } from "../agents/index.js";
|
|
10
10
|
import { MulmoPresentationStyleMethods, MulmoStudioContextMethods } from "../methods/index.js";
|
|
11
11
|
import { getOutputStudioFilePath, mkdir } from "../utils/file.js";
|
|
12
12
|
import { fileCacheAgentFilter } from "../utils/filters.js";
|
|
@@ -26,11 +26,15 @@ const movieAgents = {
|
|
|
26
26
|
const soundEffectAgents = {
|
|
27
27
|
soundEffectReplicateAgent,
|
|
28
28
|
};
|
|
29
|
+
const lipSyncAgents = {
|
|
30
|
+
lipSyncReplicateAgent,
|
|
31
|
+
};
|
|
29
32
|
const defaultAgents = {
|
|
30
33
|
...vanillaAgents,
|
|
31
34
|
...imageAgents,
|
|
32
35
|
...movieAgents,
|
|
33
36
|
...soundEffectAgents,
|
|
37
|
+
...lipSyncAgents,
|
|
34
38
|
mediaMockAgent,
|
|
35
39
|
fileWriteAgent,
|
|
36
40
|
openAIAgent,
|
|
@@ -172,6 +176,7 @@ const beat_graph_data = {
|
|
|
172
176
|
audioChecker: {
|
|
173
177
|
agent: async (namedInputs) => {
|
|
174
178
|
if (namedInputs.soundEffectFile) {
|
|
179
|
+
// NOTE: We intentinonally don't check lipSyncFile here.
|
|
175
180
|
return { hasMovieAudio: true };
|
|
176
181
|
}
|
|
177
182
|
const sourceFile = namedInputs.movieFile || namedInputs.imageFile;
|
|
@@ -182,7 +187,7 @@ const beat_graph_data = {
|
|
|
182
187
|
return { hasMovieAudio: hasAudio };
|
|
183
188
|
},
|
|
184
189
|
inputs: {
|
|
185
|
-
onComplete: [":movieGenerator", ":htmlImageGenerator", ":soundEffectGenerator"], // to wait for movieGenerator and
|
|
190
|
+
onComplete: [":movieGenerator", ":htmlImageGenerator", ":soundEffectGenerator"], // to wait for movieGenerator, htmlImageGenerator, soundEffectGenerator, and lipSyncGenerator to finish
|
|
186
191
|
movieFile: ":preprocessor.movieFile",
|
|
187
192
|
imageFile: ":preprocessor.imagePath",
|
|
188
193
|
soundEffectFile: ":preprocessor.soundEffectFile",
|
|
@@ -210,19 +215,43 @@ const beat_graph_data = {
|
|
|
210
215
|
},
|
|
211
216
|
defaultValue: {},
|
|
212
217
|
},
|
|
218
|
+
lipSyncGenerator: {
|
|
219
|
+
if: ":beat.enableLipSync",
|
|
220
|
+
agent: ":preprocessor.lipSyncAgentInfo.agentName",
|
|
221
|
+
inputs: {
|
|
222
|
+
onComplete: [":soundEffectGenerator"], // to wait for soundEffectGenerator to finish
|
|
223
|
+
movieFile: ":preprocessor.movieFile",
|
|
224
|
+
audioFile: ":preprocessor.audioFile",
|
|
225
|
+
lipSyncFile: ":preprocessor.lipSyncFile",
|
|
226
|
+
params: {
|
|
227
|
+
model: ":preprocessor.lipSyncModel",
|
|
228
|
+
duration: ":beat.duration",
|
|
229
|
+
},
|
|
230
|
+
cache: {
|
|
231
|
+
force: [":context.force"],
|
|
232
|
+
file: ":preprocessor.lipSyncFile",
|
|
233
|
+
index: ":__mapIndex",
|
|
234
|
+
sessionType: "lipSync",
|
|
235
|
+
mulmoContext: ":context",
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
defaultValue: {},
|
|
239
|
+
},
|
|
213
240
|
output: {
|
|
214
241
|
agent: "copyAgent",
|
|
215
242
|
inputs: {
|
|
216
|
-
onComplete: [":imageFromMovie", ":htmlImageGenerator", ":audioChecker", ":soundEffectGenerator"], // to wait for imageFromMovie to finish
|
|
243
|
+
onComplete: [":imageFromMovie", ":htmlImageGenerator", ":audioChecker", ":soundEffectGenerator", ":lipSyncGenerator"], // to wait for imageFromMovie, soundEffectGenerator, and lipSyncGenerator to finish
|
|
217
244
|
imageFile: ":preprocessor.imagePath",
|
|
218
245
|
movieFile: ":preprocessor.movieFile",
|
|
219
246
|
soundEffectFile: ":preprocessor.soundEffectFile",
|
|
247
|
+
lipSyncFile: ":preprocessor.lipSyncFile",
|
|
220
248
|
hasMovieAudio: ":audioChecker.hasMovieAudio",
|
|
221
249
|
},
|
|
222
250
|
output: {
|
|
223
251
|
imageFile: ".imageFile",
|
|
224
252
|
movieFile: ".movieFile",
|
|
225
253
|
soundEffectFile: ".soundEffectFile",
|
|
254
|
+
lipSyncFile: ".lipSyncFile",
|
|
226
255
|
hasMovieAudio: ".hasMovieAudio",
|
|
227
256
|
},
|
|
228
257
|
isResult: true,
|
|
@@ -316,7 +345,7 @@ export const graphOption = async (context, settings) => {
|
|
|
316
345
|
{
|
|
317
346
|
name: "fileCacheAgentFilter",
|
|
318
347
|
agent: fileCacheAgentFilter,
|
|
319
|
-
nodeIds: ["imageGenerator", "movieGenerator", "htmlImageAgent", "soundEffectGenerator"],
|
|
348
|
+
nodeIds: ["imageGenerator", "movieGenerator", "htmlImageAgent", "soundEffectGenerator", "lipSyncGenerator"],
|
|
320
349
|
},
|
|
321
350
|
],
|
|
322
351
|
taskManager: new TaskManager(MulmoPresentationStyleMethods.getConcurrency(context.presentationStyle)),
|
package/lib/actions/movie.js
CHANGED
|
@@ -162,7 +162,7 @@ const createVideo = async (audioArtifactFilePath, outputVideoPath, context) => {
|
|
|
162
162
|
beatTimestamps.push(timestamp);
|
|
163
163
|
return timestamp; // Skip voice-over beats.
|
|
164
164
|
}
|
|
165
|
-
const sourceFile = studioBeat.soundEffectFile ?? studioBeat.movieFile ?? studioBeat.imageFile;
|
|
165
|
+
const sourceFile = studioBeat.lipSyncFile ?? studioBeat.soundEffectFile ?? studioBeat.movieFile ?? studioBeat.imageFile;
|
|
166
166
|
assert(!!sourceFile, `studioBeat.imageFile or studioBeat.movieFile is not set: index=${index}`);
|
|
167
167
|
assert(!!studioBeat.duration, `studioBeat.duration is not set: index=${index}`);
|
|
168
168
|
const extraPadding = (() => {
|
|
@@ -183,7 +183,7 @@ const createVideo = async (audioArtifactFilePath, outputVideoPath, context) => {
|
|
|
183
183
|
const defaultFillOption = mulmoFillOptionSchema.parse({}); // let the schema infer the default value
|
|
184
184
|
const fillOption = { ...defaultFillOption, ...globalFillOption, ...beatFillOption };
|
|
185
185
|
const inputIndex = FfmpegContextAddInput(ffmpegContext, sourceFile);
|
|
186
|
-
const mediaType = studioBeat.movieFile ? "movie" : MulmoPresentationStyleMethods.getImageType(context.presentationStyle, beat);
|
|
186
|
+
const mediaType = studioBeat.lipSyncFile || studioBeat.movieFile ? "movie" : MulmoPresentationStyleMethods.getImageType(context.presentationStyle, beat);
|
|
187
187
|
const speed = beat.movieParams?.speed ?? 1.0;
|
|
188
188
|
const { videoId, videoPart } = getVideoPart(inputIndex, mediaType, duration, canvasInfo, fillOption, speed);
|
|
189
189
|
ffmpegContext.filterComplex.push(videoPart);
|
|
@@ -206,6 +206,7 @@ const createVideo = async (audioArtifactFilePath, outputVideoPath, context) => {
|
|
|
206
206
|
// NOTE: We don't support audio if the speed is not 1.0.
|
|
207
207
|
const movieVolume = beat.audioParams?.movieVolume ?? 1.0;
|
|
208
208
|
if (studioBeat.hasMovieAudio && movieVolume > 0.0 && speed === 1.0) {
|
|
209
|
+
// TODO: Handle a special case where it has lipSyncFile AND hasMovieAudio is on (the source file has an audio, such as sound effect).
|
|
209
210
|
const { audioId, audioPart } = getAudioPart(inputIndex, duration, timestamp, movieVolume);
|
|
210
211
|
audioIdsFromMovieBeats.push(audioId);
|
|
211
212
|
ffmpegContext.filterComplex.push(audioPart);
|
package/lib/agents/index.d.ts
CHANGED
|
@@ -11,8 +11,9 @@ import ttsNijivoiceAgent from "./tts_nijivoice_agent.js";
|
|
|
11
11
|
import ttsOpenaiAgent from "./tts_openai_agent.js";
|
|
12
12
|
import validateSchemaAgent from "./validate_schema_agent.js";
|
|
13
13
|
import soundEffectReplicateAgent from "./sound_effect_replicate_agent.js";
|
|
14
|
+
import lipSyncReplicateAgent from "./lipsync_replicate_agent.js";
|
|
14
15
|
import { browserlessAgent } from "@graphai/browserless_agent";
|
|
15
16
|
import { textInputAgent } from "@graphai/input_agents";
|
|
16
17
|
import { openAIAgent } from "@graphai/openai_agent";
|
|
17
18
|
import { fileWriteAgent } from "@graphai/vanilla_node_agents";
|
|
18
|
-
export { openAIAgent, fileWriteAgent, browserlessAgent, textInputAgent, addBGMAgent, combineAudioFilesAgent, imageGoogleAgent, imageOpenaiAgent, tavilySearchAgent, movieGoogleAgent, movieReplicateAgent, mediaMockAgent, ttsElevenlabsAgent, ttsNijivoiceAgent, ttsOpenaiAgent, validateSchemaAgent, soundEffectReplicateAgent, };
|
|
19
|
+
export { openAIAgent, fileWriteAgent, browserlessAgent, textInputAgent, addBGMAgent, combineAudioFilesAgent, imageGoogleAgent, imageOpenaiAgent, tavilySearchAgent, movieGoogleAgent, movieReplicateAgent, mediaMockAgent, ttsElevenlabsAgent, ttsNijivoiceAgent, ttsOpenaiAgent, validateSchemaAgent, soundEffectReplicateAgent, lipSyncReplicateAgent, };
|
package/lib/agents/index.js
CHANGED
|
@@ -11,9 +11,10 @@ import ttsNijivoiceAgent from "./tts_nijivoice_agent.js";
|
|
|
11
11
|
import ttsOpenaiAgent from "./tts_openai_agent.js";
|
|
12
12
|
import validateSchemaAgent from "./validate_schema_agent.js";
|
|
13
13
|
import soundEffectReplicateAgent from "./sound_effect_replicate_agent.js";
|
|
14
|
+
import lipSyncReplicateAgent from "./lipsync_replicate_agent.js";
|
|
14
15
|
import { browserlessAgent } from "@graphai/browserless_agent";
|
|
15
16
|
import { textInputAgent } from "@graphai/input_agents";
|
|
16
17
|
import { openAIAgent } from "@graphai/openai_agent";
|
|
17
18
|
// import * as vanilla from "@graphai/vanilla";
|
|
18
19
|
import { fileWriteAgent } from "@graphai/vanilla_node_agents";
|
|
19
|
-
export { openAIAgent, fileWriteAgent, browserlessAgent, textInputAgent, addBGMAgent, combineAudioFilesAgent, imageGoogleAgent, imageOpenaiAgent, tavilySearchAgent, movieGoogleAgent, movieReplicateAgent, mediaMockAgent, ttsElevenlabsAgent, ttsNijivoiceAgent, ttsOpenaiAgent, validateSchemaAgent, soundEffectReplicateAgent, };
|
|
20
|
+
export { openAIAgent, fileWriteAgent, browserlessAgent, textInputAgent, addBGMAgent, combineAudioFilesAgent, imageGoogleAgent, imageOpenaiAgent, tavilySearchAgent, movieGoogleAgent, movieReplicateAgent, mediaMockAgent, ttsElevenlabsAgent, ttsNijivoiceAgent, ttsOpenaiAgent, validateSchemaAgent, soundEffectReplicateAgent, lipSyncReplicateAgent, };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AgentFunction, AgentFunctionInfo } from "graphai";
|
|
2
|
+
import type { AgentBufferResult, LipSyncAgentInputs, ReplicateLipSyncAgentParams, ReplicateLipSyncAgentConfig } from "../types/agent.js";
|
|
3
|
+
export declare const lipSyncReplicateAgent: AgentFunction<ReplicateLipSyncAgentParams, AgentBufferResult, LipSyncAgentInputs, ReplicateLipSyncAgentConfig>;
|
|
4
|
+
declare const lipSyncReplicateAgentInfo: AgentFunctionInfo;
|
|
5
|
+
export default lipSyncReplicateAgentInfo;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import { GraphAILogger } from "graphai";
|
|
3
|
+
import Replicate from "replicate";
|
|
4
|
+
import { provider2LipSyncAgent } from "../utils/provider2agent.js";
|
|
5
|
+
export const lipSyncReplicateAgent = async ({ namedInputs, params, config, }) => {
|
|
6
|
+
const { movieFile, audioFile } = namedInputs;
|
|
7
|
+
const apiKey = config?.apiKey;
|
|
8
|
+
const model = params.model ?? provider2LipSyncAgent.replicate.defaultModel;
|
|
9
|
+
if (!apiKey) {
|
|
10
|
+
throw new Error("REPLICATE_API_TOKEN environment variable is required");
|
|
11
|
+
}
|
|
12
|
+
const replicate = new Replicate({
|
|
13
|
+
auth: apiKey,
|
|
14
|
+
});
|
|
15
|
+
const videoBuffer = readFileSync(movieFile);
|
|
16
|
+
const audioBuffer = readFileSync(audioFile);
|
|
17
|
+
const videoUri = `data:video/quicktime;base64,${videoBuffer.toString("base64")}`;
|
|
18
|
+
const audioUri = `data:audio/wav;base64,${audioBuffer.toString("base64")}`;
|
|
19
|
+
const input = {
|
|
20
|
+
video: videoUri,
|
|
21
|
+
audio: audioUri,
|
|
22
|
+
duration: params.duration,
|
|
23
|
+
};
|
|
24
|
+
try {
|
|
25
|
+
const model_identifier = provider2LipSyncAgent.replicate.modelParams[model]?.identifier ?? model;
|
|
26
|
+
const output = await replicate.run(model_identifier, {
|
|
27
|
+
input,
|
|
28
|
+
});
|
|
29
|
+
if (output && typeof output === "object" && "url" in output) {
|
|
30
|
+
const videoUrl = output.url();
|
|
31
|
+
const videoResponse = await fetch(videoUrl);
|
|
32
|
+
if (!videoResponse.ok) {
|
|
33
|
+
throw new Error(`Error downloading video: ${videoResponse.status} - ${videoResponse.statusText}`);
|
|
34
|
+
}
|
|
35
|
+
const arrayBuffer = await videoResponse.arrayBuffer();
|
|
36
|
+
return { buffer: Buffer.from(arrayBuffer) };
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
GraphAILogger.info("Failed to generate lip sync:", error.message);
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const lipSyncReplicateAgentInfo = {
|
|
46
|
+
name: "lipSyncReplicateAgent",
|
|
47
|
+
agent: lipSyncReplicateAgent,
|
|
48
|
+
mock: lipSyncReplicateAgent,
|
|
49
|
+
samples: [],
|
|
50
|
+
description: "Replicate Lip Sync agent (video + audio to video)",
|
|
51
|
+
category: ["movie"],
|
|
52
|
+
author: "Receptron Team",
|
|
53
|
+
repository: "https://github.com/receptron/mulmocast-cli/",
|
|
54
|
+
license: "MIT",
|
|
55
|
+
environmentVariables: ["REPLICATE_API_TOKEN"],
|
|
56
|
+
};
|
|
57
|
+
export default lipSyncReplicateAgentInfo;
|