feat: add comfy namespace and update comfy examples

This commit is contained in:
badayvedat 2024-06-06 18:34:57 +03:00
parent f7d9dec1aa
commit fc461ed48b
7 changed files with 43 additions and 336 deletions

View File

@ -2,7 +2,6 @@
import * as fal from '@fal-ai/serverless-client'; import * as fal from '@fal-ai/serverless-client';
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import getWorkflow from './workflow';
// @snippet:start(client.config) // @snippet:start(client.config)
fal.config({ fal.config({
@ -84,23 +83,26 @@ export default function ComfyImageToImagePage() {
setLoading(true); setLoading(true);
const start = Date.now(); const start = Date.now();
try { try {
const result: Result = await fal.subscribe('fal-ai/comfy-server', { const result: Result = await fal.subscribe(
input: getWorkflow({ 'comfy/fal-ai/image-to-image',
prompt: prompt, {
loadimage_1: imageFile, input: {
}), prompt: prompt,
pollInterval: 3000, // Default is 1000 (every 1s) loadimage_1: imageFile,
logs: true, },
onQueueUpdate(update) { pollInterval: 3000, // Default is 1000 (every 1s)
setElapsedTime(Date.now() - start); logs: true,
if ( onQueueUpdate(update) {
update.status === 'IN_PROGRESS' || setElapsedTime(Date.now() - start);
update.status === 'COMPLETED' if (
) { update.status === 'IN_PROGRESS' ||
setLogs((update.logs || []).map((log) => log.message)); update.status === 'COMPLETED'
} ) {
}, setLogs((update.logs || []).map((log) => log.message));
}); }
},
}
);
setResult(getImageURL(result)); setResult(getImageURL(result));
} catch (error: any) { } catch (error: any) {
setError(error); setError(error);

View File

@ -1,102 +0,0 @@
// This workflow is generated with ComfyUI-fal
const WORKFLOW = {
prompt: {
'3': {
inputs: {
seed: 280823642470253,
steps: 20,
cfg: 8,
sampler_name: 'dpmpp_2m',
scheduler: 'normal',
denoise: 0.8700000000000001,
model: ['14', 0],
positive: ['6', 0],
negative: ['7', 0],
latent_image: ['12', 0],
},
class_type: 'KSampler',
},
'6': {
inputs: {
text: ['15', 0],
clip: ['14', 1],
},
class_type: 'CLIPTextEncode',
},
'7': {
inputs: {
text: 'watermark, text\n',
clip: ['14', 1],
},
class_type: 'CLIPTextEncode',
},
'8': {
inputs: {
samples: ['3', 0],
vae: ['14', 2],
},
class_type: 'VAEDecode',
},
'9': {
inputs: {
filename_prefix: 'ComfyUI',
images: ['8', 0],
},
class_type: 'SaveImage',
},
'10': {
inputs: {
image: 'example.png',
upload: 'image',
},
class_type: 'LoadImage',
},
'12': {
inputs: {
pixels: ['10', 0],
vae: ['14', 2],
},
class_type: 'VAEEncode',
},
'14': {
inputs: {
ckpt_name: 'v1-5-pruned-emaonly.ckpt',
},
class_type: 'CheckpointLoaderSimple',
},
'15': {
inputs: {
name: 'prompt',
value:
'photograph of victorian woman with wings, sky clouds, meadow grass\n',
},
class_type: 'StringInput_fal',
},
},
extra_data: {},
fal_inputs_dev_info: {
loadimage_1: {
key: ['10', 'inputs', 'image'],
class_type: 'LoadImage',
},
prompt: {
key: ['15', 'inputs', 'value'],
class_type: 'StringInput_fal',
},
},
fal_inputs: {
loadimage_1: 'example_url',
prompt:
'photograph of victorian woman with wings, sky clouds, meadow grass\n',
},
};
export default function getWorkflow(object: any) {
const newWorkflow = JSON.parse(JSON.stringify(WORKFLOW));
newWorkflow.fal_inputs = {
...newWorkflow.fal_inputs,
...object,
};
return newWorkflow;
}

View File

@ -2,7 +2,6 @@
import * as fal from '@fal-ai/serverless-client'; import * as fal from '@fal-ai/serverless-client';
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import getWorkflow from './workflow';
// @snippet:start(client.config) // @snippet:start(client.config)
fal.config({ fal.config({
@ -80,22 +79,25 @@ export default function ComfyImageToVideoPage() {
setLoading(true); setLoading(true);
const start = Date.now(); const start = Date.now();
try { try {
const result: Result = await fal.subscribe('fal-ai/comfy-server', { const result: Result = await fal.subscribe(
input: getWorkflow({ 'comfy/fal-ai/image-to-video',
loadimage_1: imageFile, {
}), input: {
pollInterval: 3000, // Default is 1000 (every 1s) loadimage_1: imageFile,
logs: true, },
onQueueUpdate(update) { pollInterval: 3000, // Default is 1000 (every 1s)
setElapsedTime(Date.now() - start); logs: true,
if ( onQueueUpdate(update) {
update.status === 'IN_PROGRESS' || setElapsedTime(Date.now() - start);
update.status === 'COMPLETED' if (
) { update.status === 'IN_PROGRESS' ||
setLogs((update.logs || []).map((log) => log.message)); update.status === 'COMPLETED'
} ) {
}, setLogs((update.logs || []).map((log) => log.message));
}); }
},
}
);
setResult(getImageURL(result)); setResult(getImageURL(result));
} catch (error: any) { } catch (error: any) {
setError(error); setError(error);

View File

@ -1,91 +0,0 @@
const WORKFLOW = {
prompt: {
'3': {
inputs: {
seed: 351912937281939,
steps: 20,
cfg: 2.5,
sampler_name: 'euler',
scheduler: 'karras',
denoise: 1,
model: ['14', 0],
positive: ['12', 0],
negative: ['12', 1],
latent_image: ['12', 2],
},
class_type: 'KSampler',
},
'8': {
inputs: {
samples: ['3', 0],
vae: ['15', 2],
},
class_type: 'VAEDecode',
},
'10': {
inputs: {
filename_prefix: 'ComfyUI',
fps: 10,
lossless: false,
quality: 85,
method: 'default',
images: ['8', 0],
},
class_type: 'SaveAnimatedWEBP',
},
'12': {
inputs: {
width: 1024,
height: 576,
video_frames: 14,
motion_bucket_id: 127,
fps: 6,
augmentation_level: 0,
clip_vision: ['15', 1],
init_image: ['23', 0],
vae: ['15', 2],
},
class_type: 'SVD_img2vid_Conditioning',
},
'14': {
inputs: {
min_cfg: 1,
model: ['15', 0],
},
class_type: 'VideoLinearCFGGuidance',
},
'15': {
inputs: {
ckpt_name: 'svd.safetensors',
},
class_type: 'ImageOnlyCheckpointLoader',
},
'23': {
inputs: {
image: '18.png',
upload: 'image',
},
class_type: 'LoadImage',
},
},
extra_data: {},
fal_inputs_dev_info: {
loadimage_1: {
key: ['23', 'inputs', 'image'],
class_type: 'LoadImage',
},
},
fal_inputs: {
loadimage_1: 'example_url',
},
};
export default function getWorkflow(object: any) {
const newWorkflow = JSON.parse(JSON.stringify(WORKFLOW));
newWorkflow.fal_inputs = {
...newWorkflow.fal_inputs,
...object,
};
return newWorkflow;
}

View File

@ -2,7 +2,6 @@
import * as fal from '@fal-ai/serverless-client'; import * as fal from '@fal-ai/serverless-client';
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import getWorkflow from './workflow';
// @snippet:start(client.config) // @snippet:start(client.config)
fal.config({ fal.config({
@ -83,10 +82,10 @@ export default function ComfyTextToImagePage() {
setLoading(true); setLoading(true);
const start = Date.now(); const start = Date.now();
try { try {
const result: Result = await fal.subscribe('fal-ai/comfy-server', { const result: Result = await fal.subscribe('comfy/fal-ai/text-to-image', {
input: getWorkflow({ input: {
prompt: prompt, prompt: prompt,
}), },
pollInterval: 3000, // Default is 1000 (every 1s) pollInterval: 3000, // Default is 1000 (every 1s)
logs: true, logs: true,
onQueueUpdate(update) { onQueueUpdate(update) {

View File

@ -1,103 +0,0 @@
// This workflow is generated with ComfyUI-fal
const WORKFLOW = {
prompt: {
'3': {
inputs: {
seed: 704126934460886,
steps: 20,
cfg: 8,
sampler_name: 'euler',
scheduler: 'normal',
denoise: 1,
model: ['4', 0],
positive: ['6', 0],
negative: ['7', 0],
latent_image: ['5', 0],
},
class_type: 'KSampler',
},
'4': {
inputs: {
ckpt_name: 'sd_xl_1.0.safetensors',
},
class_type: 'CheckpointLoaderSimple',
},
'5': {
inputs: {
width: 1024,
height: 1024,
batch_size: 1,
},
class_type: 'EmptyLatentImage',
},
'6': {
inputs: {
text: ['10', 0],
clip: ['4', 1],
},
class_type: 'CLIPTextEncode',
},
'7': {
inputs: {
text: ['11', 0],
clip: ['4', 1],
},
class_type: 'CLIPTextEncode',
},
'8': {
inputs: {
samples: ['3', 0],
vae: ['4', 2],
},
class_type: 'VAEDecode',
},
'9': {
inputs: {
filename_prefix: 'ComfyUI',
images: ['8', 0],
},
class_type: 'SaveImage',
},
'10': {
inputs: {
name: 'prompt',
value:
'beautiful scenery nature glass bottle landscape, , purple galaxy bottle,',
},
class_type: 'StringInput_fal',
},
'11': {
inputs: {
name: 'negative_prompt',
value: 'text, watermark',
},
class_type: 'StringInput_fal',
},
},
extra_data: {},
fal_inputs_dev_info: {
prompt: {
key: ['10', 'inputs', 'value'],
class_type: 'StringInput_fal',
},
negative_prompt: {
key: ['11', 'inputs', 'value'],
class_type: 'StringInput_fal',
},
},
fal_inputs: {
prompt:
'beautiful scenery nature glass bottle landscape, , purple galaxy bottle,',
negative_prompt: 'text, watermark',
},
};
export default function getWorkflow(object: any) {
const newWorkflow = JSON.parse(JSON.stringify(WORKFLOW));
newWorkflow.fal_inputs = {
...newWorkflow.fal_inputs,
...object,
};
return newWorkflow;
}

View File

@ -21,7 +21,7 @@ export function ensureAppIdFormat(id: string): string {
); );
} }
const APP_NAMESPACES = ['workflows'] as const; const APP_NAMESPACES = ['workflows', 'comfy'] as const;
type AppNamespace = (typeof APP_NAMESPACES)[number]; type AppNamespace = (typeof APP_NAMESPACES)[number];