Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b2e44b7

Browse files
committedDec 30, 2024·
Add a package for Fooocus-API.
1 parent d34603c commit b2e44b7

File tree

2 files changed

+403
-0
lines changed

2 files changed

+403
-0
lines changed
 

‎StabilityMatrix.Core/Helper/Factory/PackageFactory.cs

+2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ public BasePackage GetNewBasePackage(InstalledPackage installedPackage)
9696
=> new Cogstudio(githubApiCache, settingsManager, downloadService, prerequisiteHelper),
9797
"ComfyUI-Zluda"
9898
=> new ComfyZluda(githubApiCache, settingsManager, downloadService, prerequisiteHelper),
99+
"Fooocus-API"
100+
=> new FooocusAPI(githubApiCache, settingsManager, downloadService, prerequisiteHelper),
99101
_ => throw new ArgumentOutOfRangeException(nameof(installedPackage))
100102
};
101103
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,401 @@
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.Progress;
8+
using StabilityMatrix.Core.Processes;
9+
using StabilityMatrix.Core.Python;
10+
using StabilityMatrix.Core.Services;
11+
12+
namespace StabilityMatrix.Core.Models.Packages;
13+
14+
[RegisterSingleton<BasePackage, FooocusAPI>(Duplicate = DuplicateStrategy.Append)]
15+
public class FooocusAPI(
16+
IGithubApiCache githubApi,
17+
ISettingsManager settingsManager,
18+
IDownloadService downloadService,
19+
IPrerequisiteHelper prerequisiteHelper
20+
)
21+
: BaseGitPackage(githubApi, settingsManager, downloadService, prerequisiteHelper),
22+
ISharedFolderLayoutPackage
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 = "Host",
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 Dictionary<SharedFolderType, IReadOnlyList<string>> SharedFolders =>
152+
((ISharedFolderLayoutPackage)this).LegacySharedFolders;
153+
154+
public virtual SharedFolderLayout SharedFolderLayout =>
155+
new()
156+
{
157+
RelativeConfigPath = "config.txt",
158+
Rules =
159+
[
160+
new SharedFolderLayoutRule
161+
{
162+
SourceTypes = [SharedFolderType.StableDiffusion],
163+
TargetRelativePaths = ["models/checkpoints"],
164+
ConfigDocumentPaths = ["path_checkpoints"]
165+
},
166+
new SharedFolderLayoutRule
167+
{
168+
SourceTypes = [SharedFolderType.Diffusers],
169+
TargetRelativePaths = ["models/diffusers"]
170+
},
171+
new SharedFolderLayoutRule
172+
{
173+
SourceTypes = [SharedFolderType.CLIP],
174+
TargetRelativePaths = ["models/clip"]
175+
},
176+
new SharedFolderLayoutRule
177+
{
178+
SourceTypes = [SharedFolderType.GLIGEN],
179+
TargetRelativePaths = ["models/gligen"]
180+
},
181+
new SharedFolderLayoutRule
182+
{
183+
SourceTypes = [SharedFolderType.ESRGAN],
184+
TargetRelativePaths = ["models/upscale_models"]
185+
},
186+
new SharedFolderLayoutRule
187+
{
188+
SourceTypes = [SharedFolderType.Hypernetwork],
189+
TargetRelativePaths = ["models/hypernetworks"]
190+
},
191+
new SharedFolderLayoutRule
192+
{
193+
SourceTypes = [SharedFolderType.TextualInversion],
194+
TargetRelativePaths = ["models/embeddings"],
195+
ConfigDocumentPaths = ["path_embeddings"]
196+
},
197+
new SharedFolderLayoutRule
198+
{
199+
SourceTypes = [SharedFolderType.VAE],
200+
TargetRelativePaths = ["models/vae"],
201+
ConfigDocumentPaths = ["path_vae"]
202+
},
203+
new SharedFolderLayoutRule
204+
{
205+
SourceTypes = [SharedFolderType.ApproxVAE],
206+
TargetRelativePaths = ["models/vae_approx"],
207+
ConfigDocumentPaths = ["path_vae_approx"]
208+
},
209+
new SharedFolderLayoutRule
210+
{
211+
SourceTypes = [SharedFolderType.Lora, SharedFolderType.LyCORIS],
212+
TargetRelativePaths = ["models/loras"],
213+
ConfigDocumentPaths = ["path_loras"]
214+
},
215+
new SharedFolderLayoutRule
216+
{
217+
SourceTypes = [SharedFolderType.InvokeClipVision],
218+
TargetRelativePaths = ["models/clip_vision"],
219+
ConfigDocumentPaths = ["path_clip_vision"]
220+
},
221+
new SharedFolderLayoutRule
222+
{
223+
SourceTypes = [SharedFolderType.ControlNet],
224+
TargetRelativePaths = ["models/controlnet"],
225+
ConfigDocumentPaths = ["path_controlnet"]
226+
},
227+
new SharedFolderLayoutRule
228+
{
229+
TargetRelativePaths = ["models/inpaint"],
230+
ConfigDocumentPaths = ["path_inpaint"]
231+
},
232+
new SharedFolderLayoutRule
233+
{
234+
TargetRelativePaths = ["models/prompt_expansion/fooocus_expansion"],
235+
ConfigDocumentPaths = ["path_fooocus_expansion"]
236+
},
237+
new SharedFolderLayoutRule
238+
{
239+
TargetRelativePaths = [OutputFolderName],
240+
ConfigDocumentPaths = ["path_outputs"]
241+
}
242+
]
243+
};
244+
245+
public override Dictionary<SharedOutputType, IReadOnlyList<string>> SharedOutputFolders =>
246+
new() { [SharedOutputType.Text2Img] = new[] { "outputs" } };
247+
248+
public override IEnumerable<TorchIndex> AvailableTorchIndices =>
249+
new[] { TorchIndex.Cpu, TorchIndex.Cuda, TorchIndex.DirectMl, TorchIndex.Rocm, TorchIndex.Mps };
250+
251+
public override string MainBranch => "main";
252+
253+
public override bool ShouldIgnoreReleases => true;
254+
255+
public override string OutputFolderName => "outputs";
256+
257+
public override PackageDifficulty InstallerSortOrder => PackageDifficulty.Simple;
258+
259+
public override async Task InstallPackage(
260+
string installLocation,
261+
InstalledPackage installedPackage,
262+
InstallPackageOptions options,
263+
IProgress<ProgressReport>? progress = null,
264+
Action<ProcessOutput>? onConsoleOutput = null,
265+
CancellationToken cancellationToken = default
266+
)
267+
{
268+
await using var venvRunner = await SetupVenvPure(installLocation).ConfigureAwait(false);
269+
270+
progress?.Report(new ProgressReport(-1f, "Installing requirements...", isIndeterminate: true));
271+
272+
// Pip version 24.1 deprecated numpy requirement spec used by torchsde 0.2.5
273+
await venvRunner.PipInstall(["pip==23.3.2"], onConsoleOutput).ConfigureAwait(false);
274+
275+
var torchVersion = options.PythonOptions.TorchIndex ?? GetRecommendedTorchVersion();
276+
277+
var pipArgs = new PipInstallArgs();
278+
279+
if (torchVersion == TorchIndex.DirectMl)
280+
{
281+
pipArgs = pipArgs.WithTorchDirectML();
282+
}
283+
else
284+
{
285+
pipArgs = pipArgs
286+
.WithTorch("==2.1.0")
287+
.WithTorchVision("==0.16.0")
288+
.WithTorchExtraIndex(
289+
torchVersion switch
290+
{
291+
TorchIndex.Cpu => "cpu",
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+
348+
public override Task SetupModelFolders(
349+
DirectoryPath installDirectory,
350+
SharedFolderMethod sharedFolderMethod
351+
)
352+
{
353+
return sharedFolderMethod switch
354+
{
355+
SharedFolderMethod.Symlink
356+
=> base.SetupModelFolders(installDirectory, SharedFolderMethod.Symlink),
357+
SharedFolderMethod.Configuration => SetupModelFoldersConfig(installDirectory),
358+
SharedFolderMethod.None => Task.CompletedTask,
359+
_ => throw new ArgumentOutOfRangeException(nameof(sharedFolderMethod), sharedFolderMethod, null)
360+
};
361+
}
362+
363+
public override Task RemoveModelFolderLinks(
364+
DirectoryPath installDirectory,
365+
SharedFolderMethod sharedFolderMethod
366+
)
367+
{
368+
return sharedFolderMethod switch
369+
{
370+
SharedFolderMethod.Symlink => base.RemoveModelFolderLinks(installDirectory, sharedFolderMethod),
371+
SharedFolderMethod.Configuration => WriteDefaultConfig(installDirectory),
372+
SharedFolderMethod.None => Task.CompletedTask,
373+
_ => throw new ArgumentOutOfRangeException(nameof(sharedFolderMethod), sharedFolderMethod, null)
374+
};
375+
}
376+
377+
private async Task SetupModelFoldersConfig(DirectoryPath installDirectory)
378+
{
379+
// doesn't always exist on first install
380+
installDirectory.JoinDir(OutputFolderName).Create();
381+
382+
await SharedFoldersConfigHelper
383+
.UpdateJsonConfigFileForSharedAsync(
384+
SharedFolderLayout,
385+
installDirectory,
386+
SettingsManager.ModelsDirectory
387+
)
388+
.ConfigureAwait(false);
389+
}
390+
391+
private Task WriteDefaultConfig(DirectoryPath installDirectory)
392+
{
393+
// doesn't always exist on first install
394+
installDirectory.JoinDir(OutputFolderName).Create();
395+
396+
return SharedFoldersConfigHelper.UpdateJsonConfigFileForDefaultAsync(
397+
SharedFolderLayout,
398+
installDirectory
399+
);
400+
}
401+
}

0 commit comments

Comments
 (0)
Please sign in to comment.