Skip to content

Commit 737d989

Browse files
committed
Add a package for Fooocus-API.
1 parent e1dc6e5 commit 737d989

File tree

2 files changed

+340
-0
lines changed

2 files changed

+340
-0
lines changed

StabilityMatrix.Core/Helper/Factory/PackageFactory.cs

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

0 commit comments

Comments
 (0)