Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd150aa20f | ||
|
|
17653508c5 | ||
|
|
ace12efd1a | ||
|
|
01e8668d1a | ||
|
|
8e58d962a7 | ||
|
|
c59c308d32 | ||
|
|
4560f2cca9 | ||
|
|
872752b820 | ||
|
|
97bb2b69c5 | ||
|
|
08fe87c8af | ||
|
|
d43e5fcefc | ||
|
|
65492a108c |
@@ -93,6 +93,10 @@ Major areas
|
||||
|
||||
# Self Hosting with Vercel
|
||||
|
||||
[](https://www.youtube.com/watch?v=hWvsEY1cS2M)
|
||||
Tutorial Created by [Ross](https://github.com/rossman22590) and [Syn](https://github.com/mortlsyn)
|
||||
|
||||
|
||||
Build command
|
||||
|
||||
```
|
||||
|
||||
@@ -361,13 +361,30 @@ async def send_json_override(self, event, data, sid=None):
|
||||
if event == 'executing' and data.get('node') is not None:
|
||||
node = data.get('node')
|
||||
|
||||
if 'prompt_id' in prompt_metadata:
|
||||
if prompt_id in prompt_metadata:
|
||||
if 'progress' not in prompt_metadata[prompt_id]:
|
||||
prompt_metadata[prompt_id]["progress"] = set()
|
||||
|
||||
prompt_metadata[prompt_id]["progress"].add(node)
|
||||
calculated_progress = len(prompt_metadata[prompt_id]["progress"]) / len(prompt_metadata[prompt_id]['workflow_api'])
|
||||
# print("calculated_progress", calculated_progress)
|
||||
|
||||
if 'last_updated_node' in prompt_metadata[prompt_id] and prompt_metadata[prompt_id]['last_updated_node'] == node:
|
||||
return
|
||||
prompt_metadata[prompt_id]['last_updated_node'] = node
|
||||
class_type = prompt_metadata[prompt_id]['workflow_api'][node]['class_type']
|
||||
print("updating run live status", class_type)
|
||||
await update_run_live_status(prompt_id, "Executing " + class_type)
|
||||
await update_run_live_status(prompt_id, "Executing " + class_type, calculated_progress)
|
||||
|
||||
if event == 'execution_cached' and data.get('nodes') is not None:
|
||||
if prompt_id in prompt_metadata:
|
||||
if 'progress' not in prompt_metadata[prompt_id]:
|
||||
prompt_metadata[prompt_id]["progress"] = set()
|
||||
|
||||
if 'nodes' in data:
|
||||
for node in data.get('nodes', []):
|
||||
prompt_metadata[prompt_id]["progress"].add(node)
|
||||
# prompt_metadata[prompt_id]["progress"].update(data.get('nodes'))
|
||||
|
||||
if event == 'execution_error':
|
||||
# Careful this might not be fully awaited.
|
||||
@@ -391,18 +408,22 @@ class Status(Enum):
|
||||
# Global variable to keep track of the last read line number
|
||||
last_read_line_number = 0
|
||||
|
||||
async def update_run_live_status(prompt_id, live_status):
|
||||
async def update_run_live_status(prompt_id, live_status, calculated_progress: float):
|
||||
if prompt_id not in prompt_metadata:
|
||||
return
|
||||
|
||||
print("progress", calculated_progress)
|
||||
|
||||
status_endpoint = prompt_metadata[prompt_id]['status_endpoint']
|
||||
body = {
|
||||
"run_id": prompt_id,
|
||||
"live_status": live_status,
|
||||
"progress": calculated_progress
|
||||
}
|
||||
# requests.post(status_endpoint, json=body)
|
||||
async with aiohttp.ClientSession() as session:
|
||||
await session.post(status_endpoint, json=body)
|
||||
async with session.post(status_endpoint, json=body) as response:
|
||||
pass
|
||||
|
||||
|
||||
def update_run(prompt_id, status: Status):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { app } from "./app.js";
|
||||
import { api } from "./api.js";
|
||||
import { ComfyWidgets, LGraphNode } from "./widgets.js";
|
||||
import { generateDependencyGraph } from "https://esm.sh/[email protected]4";
|
||||
import { generateDependencyGraph } from "https://esm.sh/[email protected]9";
|
||||
|
||||
/** @typedef {import('../../../web/types/comfy.js').ComfyExtension} ComfyExtension*/
|
||||
/** @type {ComfyExtension} */
|
||||
@@ -182,7 +182,7 @@ function showError(title, message) {
|
||||
function createDynamicUIHtml(data) {
|
||||
console.log(data);
|
||||
let html =
|
||||
'<div style="max-width: 1024px; margin: 14px auto; display: flex; flex-direction: column; gap: 24px;">';
|
||||
'<div style="min-width: 600px; max-width: 1024px; margin: 14px auto; display: flex; flex-direction: column; gap: 24px;">';
|
||||
const bgcolor = "var(--comfy-input-bg)";
|
||||
const evenBg = "var(--border-color)";
|
||||
const textColor = "var(--input-text)";
|
||||
@@ -284,8 +284,12 @@ function addButton() {
|
||||
}
|
||||
|
||||
const ok = await confirmDialog.confirm(
|
||||
"Confirm deployment -> " + displayName,
|
||||
`A new version will be deployed, are you conform? <br><br><input id="include-deps" type="checkbox" checked>Include dependence</input>`,
|
||||
"Confirm deployment -> " +
|
||||
displayName +
|
||||
"<br><br><small><div style='font-weight: normal;'>" +
|
||||
endpoint +
|
||||
"<div><br>",
|
||||
`A new version will be deployed, are you confirm? <br><br><input id="include-deps" type="checkbox" checked>Include dependence</input>`,
|
||||
);
|
||||
if (!ok) return;
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { LoadingPageWrapper } from "@/components/LoadingWrapper";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
export default function Loading() {
|
||||
const pathName = usePathname();
|
||||
return <LoadingPageWrapper className="h-full" tag={pathName.toLowerCase()} />;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Page() {
|
||||
return <Examples />;
|
||||
}
|
||||
|
||||
|
||||
type exampleWorkflow = {
|
||||
title: string;
|
||||
description: string;
|
||||
previewURL: string;
|
||||
image: {
|
||||
src: string,
|
||||
alt: string,
|
||||
};
|
||||
};
|
||||
|
||||
const exampleWorkflows: exampleWorkflow[] = [
|
||||
{
|
||||
title: "Txt2Img SDXL",
|
||||
description: "The basic workflow, type a prompt and generate images based on that.",
|
||||
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-txt2img-sdxl',
|
||||
image: {
|
||||
src: '/example-workflows/txt2img.webp',
|
||||
alt: 'IPAdapter workflow',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Txt2Img LCM SDXL",
|
||||
description: "Images in a couple of seconds, increase the speed of each generation using LCM Lora.",
|
||||
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-lcm-sdxl',
|
||||
image: {
|
||||
src: '/example-workflows/txt2img-lcm.webp',
|
||||
alt: 'txt2img LCM SDXL',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "IPAdapter SDXL",
|
||||
description: "Load images and use them as reference for new generations.",
|
||||
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-ip-adapter-sdxl',
|
||||
image: {
|
||||
src: '/example-workflows/ipadapter.webp',
|
||||
alt: 'IPAdapter workflow',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Upscale and Add Detail SDXL",
|
||||
description: "Upscale and Add Details to your creations.",
|
||||
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-upscale-and-add-detail-sdxl',
|
||||
image: {
|
||||
src: '/example-workflows/upscale.webp',
|
||||
alt: 'Upscale and Add Detail SDXL',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Txt2Img SDXL Turbo",
|
||||
description: "Try SDXL turbo and generate images since 1 step in seconds.",
|
||||
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-txt2img-sdxl-turbo',
|
||||
image: {
|
||||
src: '/example-workflows/txt2img-sdxl-turbo.webp',
|
||||
alt: 'Txt2Img SDXL Turbo',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Img2Img SDXL Controlnet",
|
||||
description: "This workflow uses canny. Generate lines of you original image and create variations.",
|
||||
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-img2-img-sdxl-controlnet',
|
||||
image: {
|
||||
src: '/example-workflows/txt2img-controlnet.webp',
|
||||
alt: 'Img2Img SDXL Controlnet',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Automatic Inpainting (SEG)",
|
||||
description: "Type what do you want to select and change that area with your prompt.",
|
||||
previewURL: 'https://www.comfydeploy.com/share/comfy-deploy-example-automatic-inpainting-clip-seg',
|
||||
image: {
|
||||
src: '/example-workflows/automatic-inpainting-seg.webp',
|
||||
alt: 'Img2Img SDXL Controlnet',
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
async function Examples() {
|
||||
return (
|
||||
<div className="w-full py-4">
|
||||
<section className="mx-auto flex max-w-[980px] flex-col items-center gap-2 py-8 md:py-12 md:pb-8 lg:py-24 lg:pb-20">
|
||||
<h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl text-center">
|
||||
Check out some examples
|
||||
</h1>
|
||||
<p className="max-w-[560px] text-center text-lg text-muted-foreground">Text to Image, Image to Image, IPAdapter, and more. Here are some examples that you can use to deploy your workflow.</p>
|
||||
</section>
|
||||
<section className="flex justify-center flex-wrap gap-5">
|
||||
{exampleWorkflows.map(workflow => {
|
||||
return <Card className="w-[350px]">
|
||||
<CardHeader>
|
||||
<CardTitle>{workflow.title}</CardTitle>
|
||||
<CardDescription>{workflow.description}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Image src={workflow.image.src} alt={workflow.image.alt} width={350} height={230} />
|
||||
</CardContent>
|
||||
<CardFooter className="flex justify-end gap-2">
|
||||
<Button asChild>
|
||||
<Link href={workflow.previewURL}>View Workflow</Link>
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>;
|
||||
})}
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useMediaQuery } from "usehooks-ts";
|
||||
|
||||
@@ -25,8 +24,6 @@ export function NavbarMenu({
|
||||
const pathnames = usePathname();
|
||||
const pathname = `/${pathnames.split("/")[1]}`;
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const pages = [
|
||||
{
|
||||
name: "Workflows",
|
||||
@@ -40,6 +37,10 @@ export function NavbarMenu({
|
||||
name: "API Keys",
|
||||
path: "/api-keys",
|
||||
},
|
||||
{
|
||||
name: "Examples",
|
||||
path: "/examples"
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
@@ -48,18 +49,15 @@ export function NavbarMenu({
|
||||
{isDesktop && (
|
||||
<Tabs
|
||||
defaultValue={pathname}
|
||||
className="w-[300px] flex pointer-events-auto"
|
||||
className="w-fit flex pointer-events-auto"
|
||||
>
|
||||
<TabsList className="grid w-full grid-cols-3">
|
||||
<TabsList className="w-full">
|
||||
{pages.map((page) => (
|
||||
<TabsTrigger
|
||||
key={page.name}
|
||||
value={page.path}
|
||||
onClick={() => {
|
||||
router.push(page.path);
|
||||
}}
|
||||
>
|
||||
{page.name}
|
||||
<Link href={page.path}>{page.name}</Link>
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
|
||||
@@ -328,7 +328,7 @@ export function RunWorkflowButton({
|
||||
className="px-1"
|
||||
>
|
||||
<div className="flex justify-end">
|
||||
<AutoFormSubmit>
|
||||
<AutoFormSubmit disabled={isLoading}>
|
||||
Run
|
||||
{isLoading ? <LoadingIcon /> : <Play size={14} />}
|
||||
</AutoFormSubmit>
|
||||
|
||||
@@ -90,12 +90,12 @@ export const createRun = withServerPromise(
|
||||
Object.entries(workflow_api).forEach(([_, node]) => {
|
||||
if (node.inputs["input_id"] === key) {
|
||||
node.inputs["input_id"] = inputs[key];
|
||||
// Fix for external text default value
|
||||
if (node.class_type == "ComfyUIDeployExternalText") {
|
||||
node.inputs["default_value"] = inputs[key];
|
||||
}
|
||||
}
|
||||
|
||||
// Fix for external text default value
|
||||
if (node.class_type == "ComfyUIDeployExternalText") {
|
||||
node.inputs["default_value"] = inputs[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||