using System.Diagnostics; using System.Text.RegularExpressions; using NLog; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Helper.Cache; using StabilityMatrix.Core.Models.Progress; using StabilityMatrix.Core.Processes; using StabilityMatrix.Core.Services; namespace StabilityMatrix.Core.Models.Packages; public class ComfyUI : BaseGitPackage { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); public override string Name => "ComfyUI"; public override string DisplayName { get; set; } = "ComfyUI"; public override string Author => "comfyanonymous"; public override string LaunchCommand => "main.py"; public override Uri PreviewImageUri => new("https://github.com/comfyanonymous/ComfyUI/raw/master/comfyui_screenshot.png"); public override bool ShouldIgnoreReleases => true; public ComfyUI(IGithubApiCache githubApi, ISettingsManager settingsManager, IDownloadService downloadService, IPrerequisiteHelper prerequisiteHelper) : base(githubApi, settingsManager, downloadService, prerequisiteHelper) { } // https://github.com/comfyanonymous/ComfyUI/blob/master/folder_paths.py#L11 public override Dictionary SharedFolders => new() { [SharedFolderType.StableDiffusion] = "models/checkpoints", [SharedFolderType.Diffusers] = "models/diffusers", [SharedFolderType.Lora] = "models/loras", [SharedFolderType.CLIP] = "models/clip", [SharedFolderType.TextualInversion] = "models/embeddings", [SharedFolderType.VAE] = "models/vae", [SharedFolderType.ApproxVAE] = "models/vae_approx", [SharedFolderType.ControlNet] = "models/controlnet", [SharedFolderType.GLIGEN] = "models/gligen", [SharedFolderType.ESRGAN] = "models/upscale_models", [SharedFolderType.Hypernetwork] = "models/hypernetworks", }; public override List LaunchOptions => new() { new() { Name = "VRAM", InitialValue = HardwareHelper.IterGpuInfo().Select(gpu => gpu.MemoryLevel).Max() switch { Level.Low => "--lowvram", Level.Medium => "--normalvram", _ => null }, Options = new() { "--highvram", "--normalvram", "--lowvram", "--novram" } }, new() { Name = "Use CPU only", InitialValue = !HardwareHelper.HasNvidiaGpu(), Options = new() {"--cpu"} }, new() { Name = "Disable Xformers", InitialValue = !HardwareHelper.HasNvidiaGpu(), Options = new() { "--disable-xformers" } }, new() { Name = "Auto-Launch", Options = new() { "--auto-launch" } }, LaunchOptionDefinition.Extras }; public override Task GetLatestVersion() => Task.FromResult("master"); public override async Task> GetAllVersions(bool isReleaseMode = true) { var allBranches = await GetAllBranches(); return allBranches.Select(b => new PackageVersion { TagName = $"{b.Name}", ReleaseNotesMarkdown = string.Empty }); } public override async Task InstallPackage(IProgress? progress = null) { await UnzipPackage(progress); await PrerequisiteHelper.SetupPythonDependencies(InstallLocation, "requirements.txt", progress, OnConsoleOutput); } public override async Task RunPackage(string installedPackagePath, string arguments) { await SetupVenv(installedPackagePath); PrerequisiteHelper.UpdatePathExtensions(); void HandleConsoleOutput(ProcessOutput s) { if (s.Text.Contains("To see the GUI go to", StringComparison.OrdinalIgnoreCase)) { var regex = new Regex(@"(https?:\/\/)([^:\s]+):(\d+)"); var match = regex.Match(s.Text); if (match.Success) { WebUrl = match.Value; } OnStartupComplete(WebUrl); } Debug.WriteLine($"process stdout: {s}"); OnConsoleOutput(s); } void HandleExit(int i) { Debug.WriteLine($"Venv process exited with code {i}"); OnExit(i); } var args = $"\"{Path.Combine(installedPackagePath, LaunchCommand)}\" {arguments}"; VenvRunner?.RunDetached(args.TrimEnd(), HandleConsoleOutput, HandleExit, workingDirectory: installedPackagePath); } }