-
-
Notifications
You must be signed in to change notification settings - Fork 200
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7fd6a60
commit 524e354
Showing
11 changed files
with
243 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,5 +41,8 @@ | |
"packages/broadway", | ||
"packages/clapper-services", | ||
"packages/app" | ||
] | ||
], | ||
"dependencies": { | ||
"lumaai": "^1.0.2" | ||
} | ||
} |
116 changes: 116 additions & 0 deletions
116
packages/app/src/app/api/resolve/providers/lumalabs/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import LumaAI from 'lumaai' | ||
|
||
import { ClapImageRatio, ClapSegmentCategory } from '@aitube/clap' | ||
import { ResolveRequest } from '@aitube/clapper-services' | ||
import { TimelineSegment } from '@aitube/timeline' | ||
import { getWorkflowInputValues } from '../getWorkflowInputValues' | ||
|
||
import { | ||
builtinProviderCredentialsLumalabs, | ||
clapperApiKeyToUseBuiltinCredentials, | ||
} from '@/app/api/globalSettings' | ||
|
||
export async function resolveSegment( | ||
request: ResolveRequest | ||
): Promise<TimelineSegment> { | ||
let apiKey = request.settings.lumaLabsApiKey | ||
|
||
if (!apiKey) { | ||
if (clapperApiKeyToUseBuiltinCredentials) { | ||
if ( | ||
request.settings.clapperApiKey !== clapperApiKeyToUseBuiltinCredentials | ||
) { | ||
throw new Error(`Missing API key for "LumaLabs"`) | ||
} else { | ||
// user has a valid Clapper API key, so they are allowed to use the built-in credentials | ||
apiKey = builtinProviderCredentialsLumalabs | ||
} | ||
} else { | ||
// no Clapper API key is defined, so we give free access to the built-in credentials | ||
apiKey = builtinProviderCredentialsLumalabs | ||
} | ||
} | ||
|
||
const luma = new LumaAI({ | ||
authToken: apiKey, | ||
}) | ||
|
||
const segment = request.segment | ||
|
||
if (request.segment.category === ClapSegmentCategory.VIDEO) { | ||
const { workflowValues } = getWorkflowInputValues( | ||
request.settings.videoGenerationWorkflow | ||
) | ||
|
||
// Luma accepts: | ||
// "1:1" | "9:16" | "16:9" | "4:3" | "3:4" | "21:9" | "9:21" | undefined | ||
const aspectRatio = | ||
request.meta.orientation === ClapImageRatio.SQUARE | ||
? '1:1' | ||
: request.meta.orientation === ClapImageRatio.PORTRAIT | ||
? '9:16' | ||
: '16:9' | ||
|
||
let params: LumaAI.GenerationCreateParams = { | ||
// apply the default values from the workflow | ||
...workflowValues, | ||
|
||
aspect_ratio: aspectRatio, | ||
prompt: request.prompts.image.positive || '', | ||
} | ||
|
||
if (request.prompts.video.image) { | ||
// If an image prompt is provided, add it to the parameters | ||
params.keyframes = { | ||
frame0: { | ||
type: 'image', | ||
url: request.prompts.video.image, | ||
}, | ||
} | ||
} | ||
|
||
// if we have neither a text prompt or a frame, | ||
// then there is no point in calling Luma Labs | ||
if (!request.prompts.image.positive && !request.prompts.video.image) { | ||
throw new Error('Cannot generate a video without a text or image') | ||
} | ||
|
||
try { | ||
// Create the generation | ||
const generation = await luma.generations.create(params) | ||
|
||
// Poll for completion | ||
let completedGeneration: LumaAI.Generation | null = null | ||
while (!completedGeneration) { | ||
if (!generation.id) { | ||
throw new Error(`Generation failed: missing generation id`) | ||
} | ||
const status = await luma.generations.get(generation.id) | ||
if (status.state === 'completed') { | ||
completedGeneration = status | ||
break | ||
} else if (status.state === 'failed') { | ||
throw new Error(`Generation failed: ${status.failure_reason}`) | ||
} | ||
// Wait for 5 seconds before polling again | ||
await new Promise((resolve) => setTimeout(resolve, 5000)) | ||
} | ||
|
||
// Store the URL of the final video | ||
if (completedGeneration.assets?.video) { | ||
segment.assetUrl = completedGeneration.assets.video | ||
} else { | ||
throw new Error('Generated video URL not found in the response') | ||
} | ||
} catch (error) { | ||
console.error('Error generating video with LumaAI:', error) | ||
throw error | ||
} | ||
} else { | ||
throw new Error( | ||
`Clapper doesn't support ${request.segment.category} generation for provider "LumaLabs". Please open a pull request with (working code) to solve this!` | ||
) | ||
} | ||
|
||
return segment | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
packages/app/src/services/editors/workflow-editor/workflows/lumalabs/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { | ||
ClapWorkflow, | ||
ClapWorkflowEngine, | ||
ClapWorkflowCategory, | ||
ClapWorkflowProvider, | ||
ClapInputCategory, | ||
} from '@aitube/clap' | ||
|
||
import { | ||
genericAspectRatio, | ||
genericAudio, | ||
genericBaseImageUrl, | ||
genericDrivingVideo, | ||
genericFaceImage, | ||
genericGuidanceScale, | ||
genericHeight1024, | ||
genericHeight2048, | ||
genericIdWeight, | ||
genericImage, | ||
genericImageUrl, | ||
genericInferenceSteps, | ||
genericKeyframes, | ||
genericLora, | ||
genericNegativePrompt, | ||
genericPrompt, | ||
genericReferenceImages, | ||
genericSeed, | ||
genericStartStep, | ||
genericSwapImage, | ||
genericSwapImageUrl, | ||
genericTargetImage, | ||
genericTrueCFG, | ||
genericVideo, | ||
genericWidth1024, | ||
genericWidth2048, | ||
} from '../common/defaultValues' | ||
import { sampleDrivingVideo } from '@/lib/core/constants' | ||
|
||
// ------------------------------------------------------------------------------ | ||
// if a user is already using one of those workflows and you change its settings, | ||
// they will have to reselect it in the UI for changes to be taken into account. | ||
// | ||
// -> we can create a ticket to fix this | ||
// ------------------------------------------------------------------------------ | ||
export const lumalabsWorkflows: ClapWorkflow[] = [ | ||
{ | ||
id: 'lumalabs://dream-machine/v1', | ||
label: 'Dream Machine', | ||
description: '', | ||
tags: ['LumaLabs', 'Dream Machine'], | ||
author: 'Luma Labs (https://lumalabs.ai)', | ||
thumbnailUrl: '', | ||
nonCommercial: false, | ||
engine: ClapWorkflowEngine.REST_API, | ||
provider: ClapWorkflowProvider.LUMALABS, | ||
category: ClapWorkflowCategory.VIDEO_GENERATION, | ||
data: '', | ||
schema: '', | ||
/** | ||
* Inputs of the workflow (this is used to build an UI for the workflow automatically) | ||
*/ | ||
inputFields: [genericPrompt, genericAspectRatio, genericKeyframes], | ||
inputValues: { | ||
[genericPrompt.id]: genericPrompt.defaultValue, | ||
[genericAspectRatio.id]: genericAspectRatio.defaultValue, | ||
[genericKeyframes.id]: genericKeyframes.defaultValue, | ||
}, | ||
}, | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters