Skip to content

Commit a89287c

Browse files
committed
Add a package for Fooocus-API.
1 parent c908973 commit a89287c

File tree

2 files changed

+349
-0
lines changed

2 files changed

+349
-0
lines changed

StabilityMatrix.Core/Helper/Factory/PackageFactory.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ public BasePackage GetNewBasePackage(InstalledPackage installedPackage)
100100
=> new ForgeAmdGpu(githubApiCache, settingsManager, downloadService, prerequisiteHelper),
101101
"forge-classic"
102102
=> new ForgeClassic(githubApiCache, settingsManager, downloadService, prerequisiteHelper),
103+
"Fooocus-API"
104+
=> new FooocusAPI(githubApiCache, settingsManager, downloadService, prerequisiteHelper),
103105
_ => throw new ArgumentOutOfRangeException(nameof(installedPackage))
104106
};
105107
}
Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
using System.Text.RegularExpressions;
2+
using Injectio.Attributes;
3+
using StabilityMatrix.Core.Helper;
4+
using StabilityMatrix.Core.Helper.Cache;
5+
using StabilityMatrix.Core.Helper.HardwareInfo;
6+
using StabilityMatrix.Core.Models.FileInterfaces;
7+
using StabilityMatrix.Core.Models.Packages.Config;
8+
using StabilityMatrix.Core.Models.Progress;
9+
using StabilityMatrix.Core.Processes;
10+
using StabilityMatrix.Core.Python;
11+
using StabilityMatrix.Core.Services;
12+
13+
namespace StabilityMatrix.Core.Models.Packages;
14+
15+
[RegisterSingleton<BasePackage, FooocusAPI>(Duplicate = DuplicateStrategy.Append)]
16+
public class FooocusAPI(
17+
IGithubApiCache githubApi,
18+
ISettingsManager settingsManager,
19+
IDownloadService downloadService,
20+
IPrerequisiteHelper prerequisiteHelper
21+
) : BaseGitPackage(githubApi, settingsManager, downloadService, prerequisiteHelper)
22+
{
23+
public override string Name => "Fooocus-API";
24+
public override string DisplayName { get; set; } = "Fooocus-API";
25+
public override string Author => "mrhan1993";
26+
27+
public override string Blurb => "Fooocus is a rethinking of Stable Diffusion and Midjourney’s designs";
28+
public override string LicenseType => "GPL-3.0";
29+
public override string LicenseUrl => "https://github.com/mrhan1993/Fooocus-API/blob/main/LICENSE";
30+
public override string LaunchCommand => "main.py";
31+
32+
public override Uri PreviewImageUri =>
33+
new("https://github.com/mrhan1993/Fooocus-API/assets/820530/952c9777-8d57-4b7e-8bd3-f574d508ebee");
34+
35+
public override List<LaunchOptionDefinition> LaunchOptions =>
36+
new()
37+
{
38+
new LaunchOptionDefinition
39+
{
40+
Name = "Preset",
41+
Type = LaunchOptionType.Bool,
42+
Options = { "--preset anime", "--preset realistic" }
43+
},
44+
new LaunchOptionDefinition
45+
{
46+
Name = "Port",
47+
Type = LaunchOptionType.String,
48+
Description = "Sets the listen port",
49+
Options = { "--port" }
50+
},
51+
new LaunchOptionDefinition
52+
{
53+
Name = "Share",
54+
Type = LaunchOptionType.Bool,
55+
Description = "Set whether to share on Gradio",
56+
Options = { "--share" }
57+
},
58+
new LaunchOptionDefinition
59+
{
60+
Name = "Host",
61+
Type = LaunchOptionType.String,
62+
Description = "Set the listen host",
63+
Options = { "--host" }
64+
},
65+
new LaunchOptionDefinition
66+
{
67+
Name = "Output Directory",
68+
Type = LaunchOptionType.String,
69+
Description = "Override the output directory",
70+
Options = { "--output-path" }
71+
},
72+
new LaunchOptionDefinition
73+
{
74+
Name = "Language",
75+
Type = LaunchOptionType.String,
76+
Description = "Change the language of the UI",
77+
Options = { "--language" }
78+
},
79+
new LaunchOptionDefinition
80+
{
81+
Name = "Auto-Launch",
82+
Type = LaunchOptionType.Bool,
83+
Options = { "--auto-launch" }
84+
},
85+
new LaunchOptionDefinition
86+
{
87+
Name = "Disable Image Log",
88+
Type = LaunchOptionType.Bool,
89+
Options = { "--disable-image-log" }
90+
},
91+
new LaunchOptionDefinition
92+
{
93+
Name = "Disable Analytics",
94+
Type = LaunchOptionType.Bool,
95+
Options = { "--disable-analytics" }
96+
},
97+
new LaunchOptionDefinition
98+
{
99+
Name = "Disable Preset Model Downloads",
100+
Type = LaunchOptionType.Bool,
101+
Options = { "--disable-preset-download" }
102+
},
103+
new LaunchOptionDefinition
104+
{
105+
Name = "Always Download Newer Models",
106+
Type = LaunchOptionType.Bool,
107+
Options = { "--always-download-new-model" }
108+
},
109+
new()
110+
{
111+
Name = "VRAM",
112+
Type = LaunchOptionType.Bool,
113+
InitialValue = HardwareHelper.IterGpuInfo().Select(gpu => gpu.MemoryLevel).Max() switch
114+
{
115+
MemoryLevel.Low => "--always-low-vram",
116+
MemoryLevel.Medium => "--always-normal-vram",
117+
_ => null
118+
},
119+
Options =
120+
{
121+
"--always-high-vram",
122+
"--always-normal-vram",
123+
"--always-low-vram",
124+
"--always-no-vram"
125+
}
126+
},
127+
new LaunchOptionDefinition
128+
{
129+
Name = "Use DirectML",
130+
Type = LaunchOptionType.Bool,
131+
Description = "Use pytorch with DirectML support",
132+
InitialValue = HardwareHelper.PreferDirectMLOrZluda(),
133+
Options = { "--directml" }
134+
},
135+
new LaunchOptionDefinition
136+
{
137+
Name = "Disable Xformers",
138+
Type = LaunchOptionType.Bool,
139+
InitialValue = !HardwareHelper.HasNvidiaGpu(),
140+
Options = { "--disable-xformers" }
141+
},
142+
LaunchOptionDefinition.Extras
143+
};
144+
145+
public override SharedFolderMethod RecommendedSharedFolderMethod => SharedFolderMethod.Configuration;
146+
147+
public override IEnumerable<SharedFolderMethod> AvailableSharedFolderMethods =>
148+
new[] { SharedFolderMethod.Symlink, SharedFolderMethod.Configuration, SharedFolderMethod.None };
149+
150+
public override SharedFolderLayout SharedFolderLayout =>
151+
new()
152+
{
153+
RelativeConfigPath = "config.txt",
154+
ConfigFileType = ConfigFileType.Json,
155+
Rules =
156+
[
157+
new SharedFolderLayoutRule
158+
{
159+
SourceTypes = [SharedFolderType.StableDiffusion],
160+
TargetRelativePaths = ["models/checkpoints"],
161+
ConfigDocumentPaths = ["path_checkpoints"]
162+
},
163+
new SharedFolderLayoutRule
164+
{
165+
SourceTypes = [SharedFolderType.Diffusers],
166+
TargetRelativePaths = ["models/diffusers"]
167+
},
168+
new SharedFolderLayoutRule
169+
{
170+
SourceTypes = [SharedFolderType.TextEncoders],
171+
TargetRelativePaths = ["models/clip"]
172+
},
173+
new SharedFolderLayoutRule
174+
{
175+
SourceTypes = [SharedFolderType.GLIGEN],
176+
TargetRelativePaths = ["models/gligen"]
177+
},
178+
new SharedFolderLayoutRule
179+
{
180+
SourceTypes = [SharedFolderType.ESRGAN],
181+
TargetRelativePaths = ["models/upscale_models"]
182+
},
183+
new SharedFolderLayoutRule
184+
{
185+
SourceTypes = [SharedFolderType.Hypernetwork],
186+
TargetRelativePaths = ["models/hypernetworks"]
187+
},
188+
new SharedFolderLayoutRule
189+
{
190+
SourceTypes = [SharedFolderType.Embeddings],
191+
TargetRelativePaths = ["models/embeddings"],
192+
ConfigDocumentPaths = ["path_embeddings"]
193+
},
194+
new SharedFolderLayoutRule
195+
{
196+
SourceTypes = [SharedFolderType.VAE],
197+
TargetRelativePaths = ["models/vae"],
198+
ConfigDocumentPaths = ["path_vae"]
199+
},
200+
new SharedFolderLayoutRule
201+
{
202+
SourceTypes = [SharedFolderType.ApproxVAE],
203+
TargetRelativePaths = ["models/vae_approx"],
204+
ConfigDocumentPaths = ["path_vae_approx"]
205+
},
206+
new SharedFolderLayoutRule
207+
{
208+
SourceTypes = [SharedFolderType.Lora, SharedFolderType.LyCORIS],
209+
TargetRelativePaths = ["models/loras"],
210+
ConfigDocumentPaths = ["path_loras"]
211+
},
212+
new SharedFolderLayoutRule
213+
{
214+
SourceTypes = [SharedFolderType.ClipVision],
215+
TargetRelativePaths = ["models/clip_vision"],
216+
ConfigDocumentPaths = ["path_clip_vision"]
217+
},
218+
new SharedFolderLayoutRule
219+
{
220+
SourceTypes = [SharedFolderType.ControlNet],
221+
TargetRelativePaths = ["models/controlnet"],
222+
ConfigDocumentPaths = ["path_controlnet"]
223+
},
224+
new SharedFolderLayoutRule
225+
{
226+
TargetRelativePaths = ["models/inpaint"],
227+
ConfigDocumentPaths = ["path_inpaint"]
228+
},
229+
new SharedFolderLayoutRule
230+
{
231+
TargetRelativePaths = ["models/prompt_expansion/fooocus_expansion"],
232+
ConfigDocumentPaths = ["path_fooocus_expansion"]
233+
},
234+
new SharedFolderLayoutRule
235+
{
236+
TargetRelativePaths = [OutputFolderName],
237+
ConfigDocumentPaths = ["path_outputs"]
238+
}
239+
]
240+
};
241+
242+
public override Dictionary<SharedOutputType, IReadOnlyList<string>> SharedOutputFolders =>
243+
new() { [SharedOutputType.Text2Img] = new[] { "outputs" } };
244+
245+
public override IEnumerable<TorchIndex> AvailableTorchIndices =>
246+
new[] { TorchIndex.Cpu, TorchIndex.Cuda, TorchIndex.DirectMl, TorchIndex.Rocm, TorchIndex.Mps };
247+
248+
public override string MainBranch => "main";
249+
250+
public override bool ShouldIgnoreReleases => true;
251+
252+
public override string OutputFolderName => "outputs";
253+
254+
public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Simple;
255+
256+
public override async Task InstallPackage(
257+
string installLocation,
258+
InstalledPackage installedPackage,
259+
InstallPackageOptions options,
260+
IProgress<ProgressReport>? progress = null,
261+
Action<ProcessOutput>? onConsoleOutput = null,
262+
CancellationToken cancellationToken = default
263+
)
264+
{
265+
await using var venvRunner = await SetupVenvPure(installLocation).ConfigureAwait(false);
266+
267+
progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true));
268+
269+
// Pip version 24.1 deprecated numpy requirement spec used by torchsde 0.2.5
270+
await venvRunner.PipInstall(["pip==23.3.2"], onConsoleOutput).ConfigureAwait(false);
271+
272+
var isBlackwell =
273+
SettingsManager.Settings.PreferredGpu?.IsBlackwellGpu() ?? HardwareHelper.HasBlackwellGpu();
274+
var torchVersion = options.PythonOptions.TorchIndex ?? GetRecommendedTorchVersion();
275+
276+
var pipArgs = new PipInstallArgs();
277+
278+
if (torchVersion == TorchIndex.DirectMl)
279+
{
280+
pipArgs = pipArgs.WithTorchDirectML();
281+
}
282+
else
283+
{
284+
pipArgs = pipArgs
285+
.WithTorch(isBlackwell ? string.Empty : "==2.1.0")
286+
.WithTorchVision(isBlackwell ? string.Empty : "==0.16.0")
287+
.WithTorchExtraIndex(
288+
torchVersion switch
289+
{
290+
TorchIndex.Cpu => "cpu",
291+
TorchIndex.Cuda when isBlackwell => "cu128",
292+
TorchIndex.Cuda => "cu121",
293+
TorchIndex.Rocm => "rocm5.6",
294+
TorchIndex.Mps => "cpu",
295+
_ => throw new ArgumentOutOfRangeException(nameof(torchVersion), torchVersion, null)
296+
}
297+
);
298+
}
299+
300+
var requirements = new FilePath(installLocation, "requirements.txt");
301+
302+
pipArgs = pipArgs.WithParsedFromRequirementsTxt(
303+
await requirements.ReadAllTextAsync().ConfigureAwait(false),
304+
excludePattern: "torch"
305+
);
306+
307+
if (installedPackage.PipOverrides != null)
308+
{
309+
pipArgs = pipArgs.WithUserOverrides(installedPackage.PipOverrides);
310+
}
311+
312+
await venvRunner.PipInstall(pipArgs, onConsoleOutput).ConfigureAwait(false);
313+
}
314+
315+
public override async Task RunPackage(
316+
string installLocation,
317+
InstalledPackage installedPackage,
318+
RunPackageOptions options,
319+
Action<ProcessOutput>? onConsoleOutput = null,
320+
CancellationToken cancellationToken = default
321+
)
322+
{
323+
await SetupVenv(installLocation).ConfigureAwait(false);
324+
325+
void HandleConsoleOutput(ProcessOutput s)
326+
{
327+
onConsoleOutput?.Invoke(s);
328+
329+
if (s.Text.Contains("Use the app with", StringComparison.OrdinalIgnoreCase))
330+
{
331+
var regex = new Regex(@"(https?:\/\/)([^:\s]+):(\d+)");
332+
var match = regex.Match(s.Text);
333+
if (match.Success)
334+
{
335+
WebUrl = match.Value;
336+
}
337+
OnStartupComplete(WebUrl);
338+
}
339+
}
340+
341+
VenvRunner.RunDetached(
342+
[Path.Combine(installLocation, options.Command ?? LaunchCommand), ..options.Arguments],
343+
HandleConsoleOutput,
344+
OnExit
345+
);
346+
}
347+
}

0 commit comments

Comments
 (0)