Skip to content
Open
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
[reforge]: https://github.com/Panchovix/stable-diffusion-webui-reForge
[simplesdxl]: https://github.com/metercai/SimpleSDXL/
[fluxgym]: https://github.com/cocktailpeanut/fluxgym
[fizgig]: https://github.com/shootthesound/Fizgig
[cogvideo]: https://github.com/THUDM/CogVideo
[cogstudio]: https://github.com/pinokiofactory/cogstudio
[amdforge]: https://github.com/lshqqytiger/stable-diffusion-webui-amdgpu-forge
Expand Down Expand Up @@ -63,6 +64,7 @@ See the [documentation index](docs/README.md) for installation, package manageme
- [Kohya's GUI][kohya-ss]
- [OneTrainer][onetrainer]
- [FluxGym][fluxgym]
- [Fizgig][fizgig]
- [CogVideo][cogvideo] via [CogStudio][cogstudio]
- Manage plugins / extensions for supported packages ([Automatic1111][auto1111], [Comfy UI][comfy], [SD Web UI-UX][webui-ux], and [SD.Next][sdnext])
- Easily install or update Python dependencies for each package
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ private void OnRunningPackageStatusChanged(object? sender, RunningPackageStatusC

var packageTitle = args.CurrentPackagePair.BasePackage switch
{
Fizgig => "Fizgig",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally optional and fine as is: this switch just repeats each package's DisplayName, so a _ => args.CurrentPackagePair.BasePackage.DisplayName default would remove the need for this arm (and fix packages like AI-Toolkit showing "Running Stable Diffusion"). Happy to leave that for a follow-up on our side.

FluxGym => "FluxGym",
Fooocus => "Fooocus",
Reforge => "SD WebUI reForge",
Expand Down
8 changes: 8 additions & 0 deletions StabilityMatrix.Core/Helper/Factory/PackageFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,14 @@ public BasePackage GetNewBasePackage(InstalledPackage installedPackage)
pyInstallationManager,
pipWheelService
),
"Fizgig" => new Fizgig(
githubApiCache,
settingsManager,
downloadService,
prerequisiteHelper,
pyInstallationManager,
pipWheelService
),
"ai-toolkit" => new AiToolkit(
githubApiCache,
settingsManager,
Expand Down
214 changes: 214 additions & 0 deletions StabilityMatrix.Core/Models/Packages/Fizgig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
using System.Text.RegularExpressions;
using Injectio.Attributes;
using StabilityMatrix.Core.Helper;
using StabilityMatrix.Core.Helper.Cache;
using StabilityMatrix.Core.Helper.HardwareInfo;
using StabilityMatrix.Core.Models.Progress;
using StabilityMatrix.Core.Processes;
using StabilityMatrix.Core.Python;
using StabilityMatrix.Core.Services;

namespace StabilityMatrix.Core.Models.Packages;

[RegisterSingleton<BasePackage, Fizgig>(Duplicate = DuplicateStrategy.Append)]
public partial class Fizgig(
IGithubApiCache githubApi,
ISettingsManager settingsManager,
IDownloadService downloadService,
IPrerequisiteHelper prerequisiteHelper,
IPyInstallationManager pyInstallationManager,
IPipWheelService pipWheelService
)
: BaseGitPackage(
githubApi,
settingsManager,
downloadService,
prerequisiteHelper,
pyInstallationManager,
pipWheelService
)
{
public override string Name => "Fizgig";
public override string DisplayName { get; set; } = "Fizgig";
public override string Author => "shootthesound";

public override string Blurb =>
"LoRA training studio for Flux 2 Klein 9B, Krea 2, MiniMax H3 and Qwen Image 2.1. Train, profile, repair and extract";

// Shown in the install browser before the user commits to installing.
public override string Disclaimer =>
Compat.IsWindows
? "Visual Studio Build Tools for C++ Desktop Development will be installed system-wide if not already present (may require admin privileges). "
+ "They are shared with other software and remain installed after Fizgig is uninstalled."
: string.Empty;

public override string LicenseType => "Apache-2.0";
public override string LicenseUrl => "https://github.com/shootthesound/Fizgig/blob/master/LICENSE";

// NOT launch.pyw: that launcher re-spawns itself under venv/Scripts/pythonw.exe and exits,
// which would drop the process we track (no console output, no working Stop button) and
// leave the GUI orphaned. lora_trainer_gui.py has a standalone main() and is what upstream's
// run_fizgig.sh invokes directly.
public override string LaunchCommand => "lora_trainer_gui.py";

public override Uri PreviewImageUri =>
new("https://github.com/shootthesound/Fizgig/blob/master/icon.png?raw=true");

public override string MainBranch => "master";
public override PackageType PackageType => PackageType.SdTraining;
public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Advanced;
public override bool OfferInOneClickInstaller => false;
public override bool IsCompatible => HardwareHelper.HasNvidiaGpu();
public override IEnumerable<TorchIndex> AvailableTorchIndices => [TorchIndex.Cuda];

public override TorchIndex GetRecommendedTorchVersion() => TorchIndex.Cuda;

public override PyVersion RecommendedPythonVersion => Python.PyInstallationManager.Python_3_12_10;

// Tkinter for the GUI itself; VcBuildTools for triton / torch.compile's inductor backend,
// which the Compile Blocks speedup needs on Windows.
public override IEnumerable<PackagePrerequisite> Prerequisites =>
base.Prerequisites.Concat([PackagePrerequisite.Tkinter, PackagePrerequisite.VcBuildTools]);

public override List<LaunchOptionDefinition> LaunchOptions => [LaunchOptionDefinition.Extras];

// Trained LoRAs, not images.
public override string OutputFolderName => string.Empty;
public override Dictionary<SharedOutputType, IReadOnlyList<string>>? SharedOutputFolders => null;

/// <remarks>
/// None only, like the other trainers. output_loras also receives sample images and multi-GB
/// resume-state folders, so linking it into the shared Lora folder would leak those into other
/// packages. Users who want trained LoRAs there can point Fizgig's Output Directory at it.
/// models/ can't be shared either: Fizgig flattens every weight it downloads into that one
/// directory, which doesn't map onto the per-type shared folders.
/// </remarks>
public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.None;

public override IEnumerable<SharedFolderMethod> AvailableSharedFolderMethods => [SharedFolderMethod.None];

public override async Task InstallPackage(
string installLocation,
InstalledPackage installedPackage,
InstallPackageOptions options,
IProgress<ProgressReport>? progress = null,
Action<ProcessOutput>? onConsoleOutput = null,
CancellationToken cancellationToken = default
)
{
progress?.Report(new ProgressReport(-1f, "Setting up venv", isIndeterminate: true));

await using var venvRunner = await SetupVenvPure(
installLocation,
pythonVersion: options.PythonOptions.PythonVersion
)
.ConfigureAwait(false);

// hqq ships as an sdist whose setup.py kicks off a CUDA kernel build during egg_info
// unless DISABLE_CUDA is set. Fizgig only uses its pure-PyTorch path, and its own
// requirements.txt warns never to install that line without this.
venvRunner.UpdateEnvironmentVariables(env => env.SetItem("DISABLE_CUDA", "1"));

// Mirrors upstream's uv_install_deps.py: torch goes in first from the CUDA index, then
// the rest of requirements.txt without that index. The torch pins stay in the second
// step so nothing can swap the CUDA build for a PyPI one.
var (extraIndexUrl, torchSpecs) = await ParseRequirementsAsync(
Path.Combine(installLocation, "requirements.txt"),
cancellationToken
)
.ConfigureAwait(false);

var config = new PipInstallConfig
{
RequirementsFilePaths = ["requirements.txt"],
RequirementsExcludePattern = "--extra-index-url.*",
PrePipInstallArgs =
extraIndexUrl is not null && torchSpecs.Count > 0
? [.. torchSpecs, "--extra-index-url", extraIndexUrl]
: [],
SkipTorchInstall = true,
};

await StandardPipInstallProcessAsync(
venvRunner,
options,
installedPackage,
config,
onConsoleOutput,
progress,
cancellationToken
)
.ConfigureAwait(false);
}

private static readonly string[] TorchEcosystem = ["torch", "torchvision", "torchaudio"];

/// <summary>
/// Port of _parse_requirements in upstream's uv_install_deps.py: returns the single
/// --extra-index-url and the torch-ecosystem requirement lines.
/// </summary>
private static async Task<(string? ExtraIndexUrl, List<string> TorchSpecs)> ParseRequirementsAsync(
string requirementsPath,
CancellationToken cancellationToken
)
{
string? extraIndexUrl = null;
var torchSpecs = new List<string>();

var lines = await File.ReadAllLinesAsync(requirementsPath, cancellationToken).ConfigureAwait(false);
foreach (var raw in lines)
{
var code = raw.Split('#', 2)[0].Trim();
if (code.StartsWith("--extra-index-url", StringComparison.Ordinal))
{
if (extraIndexUrl is not null)
{
throw new InvalidOperationException(
"Fizgig's requirements.txt declares more than one --extra-index-url"
);
}

var parts = code.Split((char[]?)null, 2, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 2)
{
extraIndexUrl = parts[1];
}
continue;
}

if (code.Length > 0)
{
var pkg = RequirementNameEndRegex().Split(code, 2)[0];
if (TorchEcosystem.Contains(pkg))
{
torchSpecs.Add(code);
}
}
}

return (extraIndexUrl, torchSpecs);
}

[GeneratedRegex(@"[=<>!~\s\[;]")]
private static partial Regex RequirementNameEndRegex();

public override async Task RunPackage(
string installLocation,
InstalledPackage installedPackage,
RunPackageOptions options,
Action<ProcessOutput>? onConsoleOutput = null,
CancellationToken cancellationToken = default
)
{
await SetupVenv(installLocation, pythonVersion: PyVersion.Parse(installedPackage.PythonVersion))
.ConfigureAwait(false);

// Desktop Tkinter app - there is no local URL to wait for, so startup is complete
// as soon as the process is up.
VenvRunner.RunDetached(
[Path.Combine(installLocation, options.Command ?? LaunchCommand), .. options.Arguments],
onConsoleOutput,
OnExit
);
}
}
2 changes: 1 addition & 1 deletion docs/advanced/hardware-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ The lists below describe what the code checks for. Because hardware detection wo
- **Caveats:**
- The `cu130` wheels require an NVIDIA driver of version 580 or newer. ComfyUI checks the installed driver on launch and warns if it is older than 580.x while `cu130` torch is installed, suggesting either a driver update or manually downgrading to an older torch index such as `cu128`.
- Turing (RTX 2000-series) or newer is the practical recommendation; older cards may still work but are treated as legacy.
- **Packages:** CUDA is the most broadly supported backend. Every inference package that lists a GPU backend supports CUDA, and CUDA-only packages include Fooocus, SimpleSDXL, ForgeClassic, FramePack, and the training tools (Kohya's GUI, OneTrainer, FluxGym, AI Toolkit).
- **Packages:** CUDA is the most broadly supported backend. Every inference package that lists a GPU backend supports CUDA, and CUDA-only packages include Fooocus, SimpleSDXL, ForgeClassic, FramePack, and the training tools (Kohya's GUI, OneTrainer, FluxGym, AI Toolkit, Fizgig).

## AMD on Windows

Expand Down
3 changes: 2 additions & 1 deletion docs/package-manager/supported-packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ Training packages are used to fine-tune or train AI models such as LoRAs, checkp
|---|---|
| **AI-Toolkit** | An all-in-one training suite for diffusion models supporting LoRA, full fine-tune, and more. |
| **OneTrainer** | A comprehensive one-stop solution for Stable Diffusion model training with a graphical interface. |
| **kohya_ss** | A Windows-focused Gradio GUI wrapping Kohya's popular Stable Diffusion trainer scripts. Windows only.|
| **kohya_ss** | A Windows-focused Gradio GUI wrapping Kohya's popular Stable Diffusion trainer scripts. Windows only. |
| **FluxGym** | A simple, low-VRAM Flux LoRA training UI designed for quick fine-tuning workflows. |
| **Fizgig** | A LoRA training studio for Flux 2 Klein 9B, Krea 2, MiniMax H3 and Qwen Image 2.1, with block profiling, repair and extraction tools. NVIDIA only, on Windows and Linux. |

---

Expand Down
Loading