diff --git a/js/button/actions.js b/js/button/actions.js index a3ad7f9..abfaab2 100644 --- a/js/button/actions.js +++ b/js/button/actions.js @@ -27,7 +27,6 @@ import { import { logger } from '../logger.js'; import { authDialog } from '../node/auth.ui.js'; - export async function onGeneration() { logger.newLog(); try { @@ -72,18 +71,16 @@ export async function onGeneration() { // sync workflow if(!isWorkflowUpToDate(diffDeps)) { setMessage("Syncing dependencies..."); - const s = await syncDependencies(diffDeps) - if(s?.taskId) { - await pollSyncDependencies(s.taskId) + const { taskId:uploadTaskId, dependencies, workflow_patch } = await syncDependencies(diffDeps) + if(uploadTaskId) { + await pollSyncDependencies(uploadTaskId) } setMessage("Updating workflow..."); - await uploadLocalWorkflow(s) + await uploadLocalWorkflow(dependencies, workflow_patch) } - // @todo patch workflow inputs - // Beyond this point, we assume all dependencies // and workflow api is synced to the cloud @@ -95,9 +92,7 @@ export async function onGeneration() { ) } catch (e) { // handle error - // @todo - log to error logger logger.error("onGeneration error", e) - infoDialog.showMessage("Error", e); } finally { await logger.saveLog() diff --git a/js/client.js b/js/client.js index cefedf5..53633f3 100644 --- a/js/client.js +++ b/js/client.js @@ -228,22 +228,7 @@ export const createEmptyWorkflow = async () => { try { const { apiKey } = getData(); const apiRoute = endpoint + "/workflow"; - /* - const apiRoute = endpoint + "/api/workflow"; - const body = { - workflow_name: getWorkflowName(), - workflow_id: getWorkflowId(), - workflow: {}, - workflow_api: {}, - snapshot: { - comfyui: "", - git_custom_nodes: {}, - file_custom_nodes: [], - }, - }; - */ - //let data = { status: 200 } const body = { name: getWorkflowName(), } @@ -261,11 +246,6 @@ export const createEmptyWorkflow = async () => { logger.info("Successfully uploaded local workflow to cloud") } catch (e) { - // @todo - // Handle potential reasons: - // - user has no network connection - // - user auth token expired - // - server not responsive logger.error("Failed to upload workflow API to cloud",e) throw new Error("Failed to upload workflow API to cloud") } @@ -274,7 +254,7 @@ export const createEmptyWorkflow = async () => { /** * Sends local workflow to the cloud to be stored */ -export const uploadLocalWorkflow = async (dependencies) => { +export const uploadLocalWorkflow = async (dependencies, workflow_patch) => { logger.info("Uploading local workflow to cloud") try { const { apiKey } = getData(); @@ -286,6 +266,7 @@ export const uploadLocalWorkflow = async (dependencies) => { name: getWorkflowName(), workflow: prompt.workflow, workflow_api: prompt.output, + workflow_patch: workflow_patch, dependencies: dependencies, }; //let data = { status: 200 } @@ -299,7 +280,6 @@ export const uploadLocalWorkflow = async (dependencies) => { }, 2); setWorkflowId(data.id) - //setVersion(data.version) logger.info("Successfully uploaded local workflow to cloud") } catch (e) { @@ -333,7 +313,8 @@ export const syncDependencies = async (diff) => { let modelsToUpload = [] let dependenciesToUpload = [] let filesToUpload = [] - let pathChanges = [] + //let pathChanges = [] + let patch = {} for (const [k, v] of Object.entries(diff)) { // Upload necessary images if (v?.class_type == 'LoadImage') { @@ -351,13 +332,17 @@ export const syncDependencies = async (diff) => { z.endsWith('.mkv') || z.endsWith('.gif') ) { - filesToUpload.push(z) - pathChanges.push({ - key: k, - node: v, - input_property: l, - input_value: z, - }) + const filename = extractFilename(z) + filesToUpload.push(filename) + + + // Patch input for files like VHS node + let mendedNode = { + ...v, + } + console.log(mendedNode) + mendedNode["inputs"][l] = `/vol/vol/${workflow_id}/comfyui/input/${filename}` + patch[k] = mendedNode } // Handle models, LoRAs, and checkpoints @@ -388,6 +373,14 @@ export const syncDependencies = async (diff) => { } } + // send api req to python server to check if + // it is in input. if not error out and let user + // know + const invalid = await validateInputPath(filesToUpload) + if(invalid.length > 0){ + throw new Error("Got invalid input paths") + } + if(filesToUpload.length > 0 || modelsToUpload.length > 0 || dependenciesToUpload.length > 0) { const body = { workflow_id, @@ -410,11 +403,15 @@ export const syncDependencies = async (diff) => { if (data?.success) { logger.info("Successfully synced dependencies") - return { + + return { taskId: data?.task_id, - modelsToUpload, - filesToUpload, - nodesToUpload: dependenciesToUpload, + dependencies: { + modelsToUpload, + filesToUpload, + nodesToUpload: dependenciesToUpload, + }, + workflow_patch: patch, } } else { logger.error(`Error syncing dependencies. Failed to upload: @@ -478,12 +475,37 @@ export async function addPing() { const userId = user?.id; if(userId) { - const menu = document.querySelector(".comfy-menu"); - const i = document.createElement('img'); - i.src = `${endpoint}/api/p?e=${userId}` - menu.appendChild(i); + await fetch( + `${endpoint}/auth?i=${userId}` + ).then((x) => x.json()) } } +export async function validateInputPath(paths) { + const body = { + paths: paths, + } + const res = await fetch("/comfy-cloud/validate-input-path", { + method: "POST", + body: JSON.stringify(body), + headers: { + "Content-Type": "application/json", + }, + }).then(x=>x.json()); + + console.log("Got invalid", res.invalid_paths) + return res.invalid_paths +} + + +function extractFilename(filepath) { + // Split the filepath by '/' + const parts = filepath.split('/'); + // Take the last part which represents the filename + const filename = parts[parts.length - 1]; + return filename; +} + + diff --git a/js/comfy/ext.js b/js/comfy/ext.js index 901fd90..455c8b9 100644 --- a/js/comfy/ext.js +++ b/js/comfy/ext.js @@ -2,6 +2,7 @@ import { app } from './comfy.js'; import { addButton } from '../button/index.js'; import { endpoint } from '../constants.js'; import { ComfyCloud } from '../node/index.js'; +import { addPing } from '../client.js'; export const ext = { name: "nathannlu.ComfyCloud", @@ -29,17 +30,4 @@ export const ext = { app.registerExtension(ext); -async function addPing() { - const { user } = await fetch( - '/comfy-cloud/user', - ).then((x) => x.json()) - const userId = user?.id; - - if(userId) { - const menu = document.querySelector(".comfy-menu"); - const i = document.createElement('img'); - i.src = `${endpoint}/api/p?e=${userId}` - menu.appendChild(i); - } -} diff --git a/js/logger.js b/js/logger.js index 02dd766..2f0b71d 100644 --- a/js/logger.js +++ b/js/logger.js @@ -6,7 +6,7 @@ import { /** * Basic error logger for customer service debugging -/* creates log.txt files in /logs dir + * creates log.txt files in /logs dir */ diff --git a/python/custom_routes.py b/python/custom_routes.py index 6e6a0f5..739543d 100644 --- a/python/custom_routes.py +++ b/python/custom_routes.py @@ -71,6 +71,27 @@ async def comfy_cloud_save_log(request): print("Error:", e) return web.json_response({ "error": e }, status=400) + +@server.PromptServer.instance.routes.post("/comfy-cloud/validate-input-path") +async def validate_input_path(request): + try: + data = await request.json() + input_paths = data.get("paths") + + paths_not_found = [] + base = folder_paths.base_path + for path in input_paths: + full_path = os.path.join(base, 'input', path) + + if not os.path.exists(full_path): + paths_not_found.append(path) + + return web.json_response({ "invalid_paths": paths_not_found }, status=200) + except Exception as e: + print("Error:", e) + return web.json_response({ "error": e }, status=400) + + @server.PromptServer.instance.routes.post("/comfy-cloud/validate-prompt") async def comfy_cloud_validate_prompt(request): data = await request.json()