feat: add custom image inputs

This commit is contained in:
BennyKok 2023-12-15 11:14:21 +08:00
parent c791f5d0a6
commit 1ea80e5e84
11 changed files with 631 additions and 7 deletions

View File

@ -0,0 +1,51 @@
import folder_paths
from PIL import Image, ImageOps
import numpy as np
import torch
class ComfyUIDeployExternalImage:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"name": (
"STRING",
{"multiline": False, "default": "input_image"},
),
},
"optional": {
"default_image": ("IMAGE",),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("image",)
FUNCTION = "run"
CATEGORY = "image"
def run(self, name, default_image=None):
image = default_image
try:
if name.startswith('http'):
import requests
from io import BytesIO
print("Fetching image from url: ", name)
response = requests.get(name)
image = Image.open(BytesIO(response.content))
else:
raise ValueError("Invalid image url provided.")
# image_path = folder_paths.get_annotated_filepath(name)
# image = Image.open(image_path)
image = ImageOps.exif_transpose(image)
# image = image.convert("RGB")
image = np.array(image).astype(np.float32) / 255.0
image = torch.from_numpy(image)[None,]
return [image]
except:
return [image]
NODE_CLASS_MAPPINGS = {"ComfyUIDeployExternalImage": ComfyUIDeployExternalImage}
NODE_DISPLAY_NAME_MAPPINGS = {"ComfyUIDeployExternalImage": "External Image (ComfyUI Deploy)"}

View File

@ -22,6 +22,7 @@ const ext = {
this.properties = {}; this.properties = {};
this.properties.workflow_name = ""; this.properties.workflow_name = "";
this.properties.workflow_id = ""; this.properties.workflow_id = "";
this.properties.version = "";
} }
ComfyWidgets.STRING( ComfyWidgets.STRING(
@ -38,6 +39,13 @@ const ext = {
app, app,
); );
ComfyWidgets.STRING(
this,
"version",
["", { default: this.properties.version, multiline: false }],
app,
);
// this.widgets.forEach((w) => { // this.widgets.forEach((w) => {
// // w.computeSize = () => [200,10] // // w.computeSize = () => [200,10]
// w.computedHeight = 2; // w.computedHeight = 2;
@ -150,6 +158,7 @@ function addButton() {
deploy.style.color = "green"; deploy.style.color = "green";
deployMetaNode.widgets[1].value = data.workflow_id; deployMetaNode.widgets[1].value = data.workflow_id;
deployMetaNode.widgets[2].value = data.version;
graph.change(); graph.change();
infoDialog.show( infoDialog.show(

View File

@ -0,0 +1 @@
ALTER TABLE "comfy_deploy"."workflow_runs" ADD COLUMN "workflow_inputs" jsonb;

View File

@ -0,0 +1,537 @@
{
"id": "621d6c47-6ecb-4dcd-8478-a3721b7accee",
"prevId": "c68b3727-5154-41eb-b44e-d5f26b72be44",
"version": "5",
"dialect": "pg",
"tables": {
"deployments": {
"name": "deployments",
"schema": "comfy_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"environment": {
"name": "environment",
"type": "deployment_environment",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"deployments_user_id_users_id_fk": {
"name": "deployments_user_id_users_id_fk",
"tableFrom": "deployments",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_workflow_version_id_workflow_versions_id_fk": {
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "deployments",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"deployments_workflow_id_workflows_id_fk": {
"name": "deployments_workflow_id_workflows_id_fk",
"tableFrom": "deployments",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"deployments_machine_id_machines_id_fk": {
"name": "deployments_machine_id_machines_id_fk",
"tableFrom": "deployments",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"machines": {
"name": "machines",
"schema": "comfy_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"endpoint": {
"name": "endpoint",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"machines_user_id_users_id_fk": {
"name": "machines_user_id_users_id_fk",
"tableFrom": "machines",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"users": {
"name": "users",
"schema": "comfy_deploy",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_run_outputs": {
"name": "workflow_run_outputs",
"schema": "comfy_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"run_id": {
"name": "run_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"data": {
"name": "data",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
"tableFrom": "workflow_run_outputs",
"tableTo": "workflow_runs",
"columnsFrom": [
"run_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_runs": {
"name": "workflow_runs",
"schema": "comfy_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"workflow_inputs": {
"name": "workflow_inputs",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "workflow_run_status",
"primaryKey": false,
"notNull": true,
"default": "'not-started'"
},
"ended_at": {
"name": "ended_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
},
"workflow_runs_workflow_id_workflows_id_fk": {
"name": "workflow_runs_workflow_id_workflows_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"workflow_runs_machine_id_machines_id_fk": {
"name": "workflow_runs_machine_id_machines_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflows": {
"name": "workflows",
"schema": "comfy_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflows_user_id_users_id_fk": {
"name": "workflows_user_id_users_id_fk",
"tableFrom": "workflows",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_versions": {
"name": "workflow_versions",
"schema": "comfy_deploy",
"columns": {
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"workflow": {
"name": "workflow",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"workflow_api": {
"name": "workflow_api",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_versions_workflow_id_workflows_id_fk": {
"name": "workflow_versions_workflow_id_workflows_id_fk",
"tableFrom": "workflow_versions",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {
"deployment_environment": {
"name": "deployment_environment",
"values": {
"staging": "staging",
"production": "production"
}
},
"workflow_run_status": {
"name": "workflow_run_status",
"values": {
"not-started": "not-started",
"running": "running",
"success": "success",
"failed": "failed"
}
}
},
"schemas": {
"comfy_deploy": "comfy_deploy"
},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
}
}

View File

@ -50,6 +50,13 @@
"when": 1702556119574, "when": 1702556119574,
"tag": "0006_chief_mariko_yashida", "tag": "0006_chief_mariko_yashida",
"breakpoints": true "breakpoints": true
},
{
"idx": 7,
"version": "5",
"when": 1702609665746,
"tag": "0007_thin_greymalkin",
"breakpoints": true
} }
] ]
} }

View File

@ -9,7 +9,7 @@
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "next lint",
"generate": "bunx drizzle-kit generate:pg", "generate": "bunx drizzle-kit generate:pg",
"migrate-production": "cp .env.local .env.local.bak && vercel env pull --environment=production && bun run migrate.mts && mv .env.local.bak .env.local", "migrate-production": "bun run migrate.mts",
"migrate-local": "SSL=false LOCAL=true bun run migrate.mts", "migrate-local": "SSL=false LOCAL=true bun run migrate.mts",
"db-up": "docker-compose up", "db-up": "docker-compose up",
"db-dev": "bun run db-up && bun run migrate-local" "db-dev": "bun run db-up && bun run migrate-local"

View File

@ -10,6 +10,7 @@ import { z } from "zod";
const Request = z.object({ const Request = z.object({
deployment_id: z.string(), deployment_id: z.string(),
inputs: z.record(z.string()).optional(),
}); });
const Request2 = z.object({ const Request2 = z.object({
@ -48,7 +49,7 @@ export async function POST(request: Request) {
const origin = new URL(request.url).origin; const origin = new URL(request.url).origin;
const { deployment_id } = data; const { deployment_id, inputs } = data;
try { try {
const deploymentData = await db.query.deploymentsTable.findFirst({ const deploymentData = await db.query.deploymentsTable.findFirst({
@ -60,7 +61,8 @@ export async function POST(request: Request) {
const run_id = await createRun( const run_id = await createRun(
origin, origin,
deploymentData.workflow_version_id, deploymentData.workflow_version_id,
deploymentData.machine_id deploymentData.machine_id,
inputs
); );
return NextResponse.json( return NextResponse.json(

View File

@ -1,9 +1,10 @@
import { replaceCDNUrl } from "@/server/resource";
import { NextResponse, type NextRequest } from "next/server"; import { NextResponse, type NextRequest } from "next/server";
export async function GET(request: NextRequest) { export async function GET(request: NextRequest) {
const file = new URL(request.url).searchParams.get("file"); const file = new URL(request.url).searchParams.get("file");
console.log(`${process.env.SPACES_ENDPOINT}/comfyui-deploy/${file}`); // console.log(`${process.env.SPACES_ENDPOINT}/comfyui-deploy/${file}`);
return NextResponse.redirect( return NextResponse.redirect(
`${process.env.SPACES_ENDPOINT}/comfyui-deploy/${file}` replaceCDNUrl(`${process.env.SPACES_ENDPOINT}/comfyui-deploy/${file}`)
); );
} }

View File

@ -82,6 +82,7 @@ export const workflowRunsTable = dbSchema.table("workflow_runs", {
onDelete: "set null", onDelete: "set null",
} }
), ),
workflow_inputs: jsonb("workflow_inputs").$type<Record<string, string>>(),
workflow_id: uuid("workflow_id") workflow_id: uuid("workflow_id")
.notNull() .notNull()
.references(() => workflowTable.id, { .references(() => workflowTable.id, {

View File

@ -10,7 +10,8 @@ import "server-only";
export async function createRun( export async function createRun(
origin: string, origin: string,
workflow_version_id: string, workflow_version_id: string,
machine_id: string machine_id: string,
inputs?: Record<string, string>
) { ) {
const machine = await db.query.machinesTable.findFirst({ const machine = await db.query.machinesTable.findFirst({
where: eq(workflowRunsTable.id, machine_id), where: eq(workflowRunsTable.id, machine_id),
@ -46,6 +47,15 @@ export async function createRun(
const comfyui_endpoint = `${machine.endpoint}/comfyui-deploy/run`; const comfyui_endpoint = `${machine.endpoint}/comfyui-deploy/run`;
let workflow_api = workflow_version_data.workflow_api;
// Replace the inputs
if (inputs) {
for (const key in inputs) {
workflow_api = workflow_api.replace(`"${key}"`, `"${inputs[key]}"`);
}
}
// Sending to comfyui // Sending to comfyui
const result = await fetch(comfyui_endpoint, { const result = await fetch(comfyui_endpoint, {
method: "POST", method: "POST",
@ -53,9 +63,10 @@ export async function createRun(
// "Content-Type": "application/json", // "Content-Type": "application/json",
// }, // },
body: JSON.stringify({ body: JSON.stringify({
workflow_api: workflow_version_data.workflow_api, workflow_api: workflow_api,
status_endpoint: `${origin}/api/update-run`, status_endpoint: `${origin}/api/update-run`,
file_upload_endpoint: `${origin}/api/file-upload`, file_upload_endpoint: `${origin}/api/file-upload`,
inputs: inputs,
}), }),
}).then(async (res) => ComfyAPI_Run.parseAsync(await res.json())); }).then(async (res) => ComfyAPI_Run.parseAsync(await res.json()));
// .catch((error) => { // .catch((error) => {
@ -79,6 +90,7 @@ export async function createRun(
id: result.prompt_id, id: result.prompt_id,
workflow_id: workflow_version_data.workflow_id, workflow_id: workflow_version_data.workflow_id,
workflow_version_id: workflow_version_data.id, workflow_version_id: workflow_version_data.id,
workflow_inputs: inputs,
machine_id, machine_id,
}) })
.returning(); .returning();

View File

@ -43,4 +43,7 @@ export async function createDeployments(
}); });
} }
revalidatePath(`/${workflow_id}`); revalidatePath(`/${workflow_id}`);
return {
message: `Successfully created deployment for ${environment}`,
};
} }