Skip to content

Commit 993b0f8

Browse files
committed
Add a package for Fooocus-API.
1 parent 387c7b9 commit 993b0f8

2 files changed

Lines changed: 351 additions & 0 deletions

File tree

StabilityMatrix.Core/Helper/Factory/PackageFactory.cs

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

0 commit comments

Comments
 (0)