diff --git a/package.json b/package.json index 86c39768..e02b4c6f 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "ComfyUI", "repository": "github:comfy-org/electron", "copyright": "Copyright © 2024 Comfy Org", - "version": "0.1.26", + "version": "0.1.27", "description": "The best modular GUI to run AI diffusion models.", "main": ".vite/build/main.js", "packageManager": "yarn@4.5.0", diff --git a/src/config/extra_model_config.ts b/src/config/extra_model_config.ts index 237f7ec0..1e391d9a 100644 --- a/src/config/extra_model_config.ts +++ b/src/config/extra_model_config.ts @@ -1,7 +1,6 @@ import * as fsPromises from 'node:fs/promises'; -import path from 'path'; import log from 'electron-log/main'; -import { stringify } from 'yaml'; +import { stringify, parse } from 'yaml'; interface ModelPaths { comfyui: { @@ -85,3 +84,24 @@ export async function createModelConfigFiles(extraModelConfigPath: string, custo return false; } } + +export async function readBasePathFromConfig(configPath: string): Promise { + try { + const fileContent = await fsPromises.readFile(configPath, 'utf8'); + const config = parse(fileContent); + + if (config && config.comfyui && config.comfyui.base_path) { + return config.comfyui.base_path; + } else { + log.warn(`No base_path found in ${configPath}`); + return null; + } + } catch (error) { + if ((error as NodeJS.ErrnoException).code === 'ENOENT') { + log.info(`Config file not found at ${configPath}`); + } else { + log.error(`Error reading config file ${configPath}:`, error); + } + return null; + } +} diff --git a/src/main.ts b/src/main.ts index fb5f8127..4215201a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -11,7 +11,6 @@ import { IPCChannel, SENTRY_URL_ENDPOINT, } from './constants'; -import dotenv from 'dotenv'; import { app, BrowserWindow, dialog, screen, ipcMain, Menu, MenuItem } from 'electron'; import tar from 'tar'; import log from 'electron-log/main'; @@ -20,27 +19,31 @@ import Store from 'electron-store'; import { updateElectronApp, UpdateSourceType } from 'update-electron-app'; import * as net from 'net'; import { graphics } from 'systeminformation'; -import { createModelConfigFiles } from './config/extra_model_config'; +import { createModelConfigFiles, readBasePathFromConfig } from './config/extra_model_config'; let comfyServerProcess: ChildProcess | null = null; const host = '127.0.0.1'; let port = 8188; let mainWindow: BrowserWindow | null; +let store: Store | null; const messageQueue: Array = []; // Stores mesaages before renderer is ready. import { StoreType } from './store'; log.initialize(); // Handle creating/removing shortcuts on Windows when installing/uninstalling. // Run this as early in the main process as possible. -if (require('electron-squirrel-startup')) app.quit(); - -const store = new Store(); +if (require('electron-squirrel-startup')) { + log.info('App already being set up by squirrel. Exiting...'); + app.quit(); +} const gotTheLock = app.requestSingleInstanceLock(); if (!gotTheLock) { + log.info('App already running. Exiting...'); app.quit(); } else { + store = new Store(); app.on('second-instance', (event, commandLine, workingDirectory, additionalData) => { log.info('Received second instance message!'); log.info(additionalData); @@ -137,7 +140,7 @@ if (!gotTheLock) { }); }); await handleFirstTimeSetup(); - const { userResourcesPath, appResourcesPath, pythonInstallPath, modelConfigPath } = + const { userResourcesPath, appResourcesPath, pythonInstallPath, modelConfigPath, basePath } = await determineResourcesPaths(); SetupTray(mainWindow, userResourcesPath); port = await findAvailablePort(8000, 9999).catch((err) => { @@ -148,7 +151,7 @@ if (!gotTheLock) { sendProgressUpdate('Setting up Python Environment...'); const pythonInterpreterPath = await setupPythonEnvironment(appResourcesPath, pythonInstallPath); sendProgressUpdate('Starting Comfy Server...'); - await launchPythonServer(pythonInterpreterPath, appResourcesPath, userResourcesPath, modelConfigPath); + await launchPythonServer(pythonInterpreterPath, appResourcesPath, modelConfigPath, basePath); updateElectronApp({ updateSource: { type: UpdateSourceType.StaticStorage, @@ -202,6 +205,7 @@ if (!gotTheLock) { app.on('window-all-closed', () => { log.info('Window all closed'); if (process.platform !== 'darwin') { + log.info('Quitting ComfyUI because window all closed'); app.quit(); } }); @@ -374,8 +378,8 @@ let spawnServerTimeout: NodeJS.Timeout = null; const launchPythonServer = async ( pythonInterpreterPath: string, appResourcesPath: string, - userResourcesPath: string, - modelConfigPath: string + modelConfigPath: string, + basePath: string ) => { const isServerRunning = await isComfyServerReady(host, port); if (isServerRunning) { @@ -388,9 +392,9 @@ const launchPythonServer = async ( return new Promise(async (resolve, reject) => { const scriptPath = path.join(appResourcesPath, 'ComfyUI', 'main.py'); - const userDirectoryPath = path.join(userResourcesPath, 'user'); - const inputDirectoryPath = path.join(userResourcesPath, 'input'); - const outputDirectoryPath = path.join(userResourcesPath, 'output'); + const userDirectoryPath = path.join(basePath, 'user'); + const inputDirectoryPath = path.join(basePath, 'input'); + const outputDirectoryPath = path.join(basePath, 'output'); const comfyMainCmd = [ scriptPath, '--user-directory', @@ -544,16 +548,6 @@ const spawnPython = ( mainWindow.webContents.send(IPC_CHANNELS.LOG_MESSAGE, message); } }); - - const signalHandler = (signal: NodeJS.Signals) => { - log.warn(`Received ${signal}, terminating Python process`); - if (!pythonProcess.killed) { - pythonProcess.kill(signal); // Send the signal to the Python process - } - }; - - process.on('SIGINT', signalHandler); - process.on('SIGTERM', signalHandler); } return pythonProcess; @@ -569,15 +563,8 @@ const spawnPythonAsync = ( log.info(`Spawning python process with command: ${cmd.join(' ')} in directory: ${cwd}`); const pythonProcess: ChildProcess = spawn(pythonInterpreterPath, cmd, { cwd }); - let timeoutId: NodeJS.Timeout | null = null; - const cleanup = () => { - if (timeoutId) clearTimeout(timeoutId); pythonProcess.removeAllListeners(); - if (!pythonProcess.killed) { - pythonProcess.kill(); - } - process.exit(); }; if (options.stdx) { @@ -609,18 +596,6 @@ const spawnPythonAsync = ( log.error(`Failed to start Python process: ${err}`); reject(err); }); - - const signalHandler = (signal: NodeJS.Signals) => { - log.warn(`Received ${signal}, terminating Python process`); - cleanup(); - if (!pythonProcess.killed) { - pythonProcess.kill(signal); - } - process.exit(); - }; - - process.on('SIGINT', signalHandler); - process.on('SIGTERM', signalHandler); }); }; @@ -865,8 +840,10 @@ async function determineResourcesPaths(): Promise<{ pythonInstallPath: string; appResourcesPath: string; modelConfigPath: string; + basePath: string | null; }> { const modelConfigPath = path.join(app.getPath('userData'), 'extra_models_config.yaml'); + const basePath = await readBasePathFromConfig(modelConfigPath); if (!app.isPackaged) { return { // development: install python to in-tree assets dir @@ -874,6 +851,7 @@ async function determineResourcesPaths(): Promise<{ pythonInstallPath: path.join(app.getAppPath(), 'assets'), appResourcesPath: path.join(app.getAppPath(), 'assets'), modelConfigPath: modelConfigPath, + basePath: basePath, }; } @@ -891,6 +869,7 @@ async function determineResourcesPaths(): Promise<{ pythonInstallPath: defaultPythonInstallPath, appResourcesPath: appResourcePath, modelConfigPath: modelConfigPath, + basePath: basePath, }; } diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx index 0dedf85b..7b8bd0f2 100644 --- a/src/renderer/index.tsx +++ b/src/renderer/index.tsx @@ -49,7 +49,7 @@ const Home: React.FC = () => {
setShowSetup(false)} />
- ) + ); } return ( diff --git a/src/renderer/screens/FirstTimeSetup.tsx b/src/renderer/screens/FirstTimeSetup.tsx index 3bd3b4dc..151fd92a 100644 --- a/src/renderer/screens/FirstTimeSetup.tsx +++ b/src/renderer/screens/FirstTimeSetup.tsx @@ -38,17 +38,33 @@ const FirstTimeSetup: React.FC = ({ onComplete }) => { return (

Install ComfyUI

- {!selectedPath &&

- Please select a directory for where ComfyUI will store models, outputs, etc. If you already have a ComfyUI - setup, you can select that to reuse the model files. -

} - {!selectedPath && } + {!selectedPath && ( +

+ Please select a directory for where ComfyUI will store models, outputs, etc. If you already have a ComfyUI + setup, you can select that to reuse the model files. +

+ )} + {!selectedPath && ( + + )} {selectedPath && (
- - + +

{selectedPath}

@@ -56,16 +72,10 @@ const FirstTimeSetup: React.FC = ({ onComplete }) => { )} {selectedPath && (
- -
diff --git a/src/renderer/screens/ProgressOverlay.tsx b/src/renderer/screens/ProgressOverlay.tsx index 1470a058..5c2eaff0 100644 --- a/src/renderer/screens/ProgressOverlay.tsx +++ b/src/renderer/screens/ProgressOverlay.tsx @@ -93,7 +93,9 @@ function ProgressOverlay(): React.ReactElement {
{status}
-
{status !== COMFY_FINISHING_MESSAGE && status !== COMFY_ERROR_MESSAGE && }
+
+ {status !== COMFY_FINISHING_MESSAGE && status !== COMFY_ERROR_MESSAGE && } +
);