also remove legacy sapi v1 while i'm at it
this is the old one that wasn't support anymore already anyway
This commit is contained in:
@@ -146,7 +146,6 @@ This project:
|
||||
- can automatically install [insightface](https://github.com/deepinsight/insightface) (MIT) for `IP Adapter - Face` support
|
||||
- uses [JSON.NET](https://github.com/JamesNK/Newtonsoft.Json) (MIT), [FreneticUtilities](https://github.com/FreneticLLC/FreneticUtilities) (MIT), [LiteDB](https://github.com/mbdavid/LiteDB) (MIT), [ImageSharp](https://github.com/SixLabors/ImageSharp/) (Apache2 under open-source Split License)
|
||||
- embeds copies of web assets from [BootStrap](https://getbootstrap.com/) (MIT), [Select2](https://select2.org/) (MIT), [JQuery](https://jquery.com/) (MIT), [exifr](https://github.com/MikeKovarik/exifr) (MIT).
|
||||
- has the option to connect to remote servers to use [the Stability AI API](https://platform.stability.ai/) as a backend.
|
||||
- supports user-built extensions which may have their own licenses or legal conditions.
|
||||
|
||||
SwarmUI itself is under the MIT license, however some usages may be affected by the GPL variant licenses of connected projects list above, and note that any models used have their own licenses.
|
||||
|
||||
@@ -12,9 +12,9 @@ It is also hoped that building Stable Diffusion tools in C# will enable a wider
|
||||
|
||||
## Modularity
|
||||
|
||||
The project was designed to be heavily modular, such that backends are fully separated from the middle-layer which is fully separated from the frontend UI, and all components are interswappable. This is to enable extensibility and customization. For example, an extension can easily provide alternative backend generators (this project comes with several built-in, such as ComfyUI, Auto WebUI, StabilityAPI, ...) without having to edit anything else to work.
|
||||
The project was designed to be heavily modular, such that backends are fully separated from the middle-layer which is fully separated from the frontend UI, and all components are interswappable. This is to enable extensibility and customization. For example, an extension can easily provide alternative backend generators (this project comes with several built-in, such as ComfyUI, Auto WebUI, ...) without having to edit anything else to work.
|
||||
|
||||
The limitation of this approach is some tools may not easily be intercompatible, eg the StabilityAPI backend has only a select few limited inputs, vs the local backends that have a wider range, and many parameters don't work with StabilityAPI.
|
||||
The limitation of this approach is some tools may not easily be intercompatible, limiting power users to only the most well supported tools.
|
||||
|
||||
## Comfy
|
||||
|
||||
@@ -24,6 +24,7 @@ For the goal of maximizing capabilities, a 'main' backend needed to be chosen to
|
||||
- The code inside is extremely clean and well written.
|
||||
- It provides bonus features that other UIs can't match (ie: the workflow node editor).
|
||||
- The lead developer of Comfy was hired to Stability, and was able to directly help in ensuring the SwarmUI-ComfyUI integration works as best it can.
|
||||
- (June 2024 note: we now continue to work together in the independent [Comfy Org](https://www.comfy.org/))
|
||||
|
||||
## Web Frontend
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# StabilityAPI Extension
|
||||
|
||||
Adds a backend that makes remote calls to the Stability API.
|
||||
|
||||
Requires an API key - refer to [the developer platform documentation](https://platform.stability.ai/docs/getting-started/authentication)
|
||||
|
||||
Currently requires selecting a local model, and then selecting the "Engine" as a parameter - TODO: the engines should be listed in the models UI instead.
|
||||
@@ -1,198 +0,0 @@
|
||||
|
||||
using FreneticUtilities.FreneticDataSyntax;
|
||||
using FreneticUtilities.FreneticExtensions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SwarmUI.Backends;
|
||||
using SwarmUI.Core;
|
||||
using SwarmUI.Text2Image;
|
||||
using SwarmUI.Utils;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace SwarmUI.Builtin_StabilityAPIExtension;
|
||||
|
||||
public class StabilityAPIBackend : AbstractT2IBackend
|
||||
{
|
||||
public class StabilityAPIBackendSettings : AutoConfiguration
|
||||
{
|
||||
[ConfigComment("The endpoint route for the API, normally do not change this.")]
|
||||
public string Endpoint = "https://api.stability.ai/v1";
|
||||
|
||||
[ConfigComment("The name of a file under your 'Data/' directory that is a plaintext file containing the SAPI key.")]
|
||||
public string KeyFile = "sapi_key.dat";
|
||||
}
|
||||
|
||||
private static string Key;
|
||||
|
||||
public static double Credits = -1;
|
||||
|
||||
public HttpClient WebClient;
|
||||
|
||||
public StabilityAPIBackendSettings Settings => SettingsRaw as StabilityAPIBackendSettings;
|
||||
|
||||
public override async Task Init()
|
||||
{
|
||||
string fn = Utilities.CombinePathWithAbsolute(Program.ServerSettings.Paths.DataPath, Settings.KeyFile);
|
||||
if (string.IsNullOrWhiteSpace(fn) || fn.Contains("..") || !File.Exists(fn))
|
||||
{
|
||||
Logs.Warning($"Refusing to initialize StabilityAPI backend because {fn} does not exist or is invalid.");
|
||||
Status = BackendStatus.DISABLED;
|
||||
return;
|
||||
}
|
||||
Key = File.ReadAllText(fn).Trim();
|
||||
WebClient = NetworkBackendUtils.MakeHttpClient();
|
||||
WebClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {Key}");
|
||||
await UpdateBalance();
|
||||
if (Credits == -1)
|
||||
{
|
||||
Logs.Warning($"StabilityAPI Backend init failed.");
|
||||
Status = BackendStatus.DISABLED;
|
||||
return;
|
||||
}
|
||||
await RefreshEngines();
|
||||
Status = BackendStatus.RUNNING;
|
||||
}
|
||||
|
||||
public override Task<bool> LoadModel(T2IModel model)
|
||||
{
|
||||
CurrentModelName = model.Name;
|
||||
// Nothing to do.
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
public override Task Shutdown()
|
||||
{
|
||||
NetworkBackendUtils.ClearOldHttpClient(WebClient);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task<JObject> Get(string url)
|
||||
{
|
||||
string data = await (await WebClient.GetAsync($"{Settings.Endpoint}/{url}")).Content.ReadAsStringAsync();
|
||||
if (data.StartsWith('['))
|
||||
{
|
||||
data = "{\"data\":" + data + "}";
|
||||
}
|
||||
return data.ParseToJson();
|
||||
}
|
||||
|
||||
public async Task RefreshEngines()
|
||||
{
|
||||
JObject engines = await Get("engines/list");
|
||||
List<string> engineIds = engines["data"].Select(o => o["id"].ToString()).ToList();
|
||||
Logs.Debug($"Engines: {engines}");
|
||||
lock (StabilityAPIExtension.TrackerLock)
|
||||
{
|
||||
foreach (string eng in engineIds)
|
||||
{
|
||||
if (!StabilityAPIExtension.Engines.Contains(eng))
|
||||
{
|
||||
StabilityAPIExtension.Engines.Add(eng);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateBalance()
|
||||
{
|
||||
JObject response = await Get("user/balance");
|
||||
if (!response.TryGetValue("credits", out JToken creditTok))
|
||||
{
|
||||
Logs.Error($"StabilityAPI gave unexpected response to balance check: {response}");
|
||||
return;
|
||||
}
|
||||
double _cred = (double)creditTok;
|
||||
lock (StabilityAPIExtension.TrackerLock)
|
||||
{
|
||||
Credits = _cred;
|
||||
}
|
||||
Logs.Info($"StabilityAPI balance: {Credits}");
|
||||
}
|
||||
|
||||
public override async Task<Image[]> Generate(T2IParamInput user_input)
|
||||
{
|
||||
user_input.ProcessPromptEmbeds(x => throw new InvalidDataException("Cannot use embeddings with StabilityAPI"));
|
||||
if (user_input.TryGet(T2IParamTypes.InitImage, out Image initImg))
|
||||
{
|
||||
// TODO: img2img
|
||||
}
|
||||
JArray prompts = [];
|
||||
if (!string.IsNullOrWhiteSpace(user_input.Get(T2IParamTypes.Prompt)))
|
||||
{
|
||||
prompts.Add(new JObject()
|
||||
{
|
||||
["text"] = user_input.Get(T2IParamTypes.Prompt),
|
||||
["weight"] = 1
|
||||
});
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(user_input.Get(T2IParamTypes.NegativePrompt)))
|
||||
{
|
||||
prompts.Add(new JObject()
|
||||
{
|
||||
["text"] = user_input.Get(T2IParamTypes.NegativePrompt),
|
||||
["weight"] = -1
|
||||
});
|
||||
}
|
||||
if (prompts.IsEmpty())
|
||||
{
|
||||
throw new InvalidDataException($"Invalid StabilityAPI generation input: missing prompt!");
|
||||
}
|
||||
JObject obj = new()
|
||||
{
|
||||
["cfg_scale"] = user_input.Get(T2IParamTypes.CFGScale),
|
||||
["height"] = user_input.GetImageHeight(),
|
||||
["width"] = user_input.Get(T2IParamTypes.Width),
|
||||
["samples"] = 1,
|
||||
["steps"] = user_input.Get(T2IParamTypes.Steps),
|
||||
["sampler"] = user_input.Get(StabilityAPIExtension.SamplerParam) ?? "K_EULER",
|
||||
["text_prompts"] = prompts,
|
||||
["seed"] = user_input.Get(T2IParamTypes.Seed)
|
||||
};
|
||||
T2IModel model = user_input.Get(T2IParamTypes.Model);
|
||||
string sapiEngineForModel = model.ModelClass?.ID switch
|
||||
{
|
||||
"stable-diffusion-xl-v1-base" or "stable-diffusion-xl-v1-refiner" => "stable-diffusion-xl-1024-v1-0",
|
||||
"stable-diffusion-v2-inpainting" => "stable-inpainting-512-v2-0",
|
||||
"stable-diffusion-v2-depth" => "stable-diffusion-depth-v2-0",
|
||||
"stable-diffusion-v1-inpainting" => "stable-inpainting-v1-0",
|
||||
"stable-diffusion-v2-768-v" => "stable-diffusion-768-v2-1",
|
||||
"stable-diffusion-v2-512" => "stable-diffusion-512-v2-1",
|
||||
_ => "stable-diffusion-v1-5"
|
||||
};
|
||||
string engine = user_input.Get(StabilityAPIExtension.EngineParam, sapiEngineForModel);
|
||||
// TODO: Model tracking.
|
||||
JObject response = null;
|
||||
try
|
||||
{
|
||||
response = await WebClient.PostJson($"{Settings.Endpoint}/generation/{engine}/text-to-image", obj);
|
||||
if (!response.ContainsKey("artifacts") && response.TryGetValue("message", out JToken message))
|
||||
{
|
||||
throw new InvalidDataException($"StabilityAPI refused to generate: {message}");
|
||||
}
|
||||
List<Image> images = [];
|
||||
foreach (JObject img in response["artifacts"].Cast<JObject>())
|
||||
{
|
||||
if (img["finishReason"].ToString() == "ERROR")
|
||||
{
|
||||
Logs.Error($"StabilityAPI returned error for request.");
|
||||
}
|
||||
else
|
||||
{
|
||||
images.Add(new(img["base64"].ToString(), Image.ImageType.IMAGE, "png"));
|
||||
}
|
||||
}
|
||||
_ = Utilities.RunCheckedTask(() => UpdateBalance().Wait());
|
||||
return [.. images];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logs.Error($"StabilityAPI request failed: {ex.GetType().Name}: {ex.Message}");
|
||||
Logs.Debug($"Raw StabilityAPI request input was: {obj}");
|
||||
Logs.Debug($"raw StabilityAPI response for above error was: {response}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<string> SupportedFeatures => StabilityAPIExtension.FeaturesSupported;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
|
||||
using FreneticUtilities.FreneticToolkit;
|
||||
using SwarmUI.Core;
|
||||
using SwarmUI.Text2Image;
|
||||
|
||||
namespace SwarmUI.Builtin_StabilityAPIExtension;
|
||||
|
||||
public class StabilityAPIExtension : Extension
|
||||
{
|
||||
public static List<string> Engines = ["stable-diffusion-v1-5"]; // Auto populated when it loads.
|
||||
|
||||
public static LockObject TrackerLock = new();
|
||||
|
||||
public static string[] Samplers = ["DDIM", "DDPM", "K_DPMPP_2M", "K_DPMPP_2S_ANCESTRAL", "K_DPM_2", "K_DPM_2_ANCESTRAL", "K_EULER", "K_EULER_ANCESTRAL", "K_HEUN", "K_LMS"];
|
||||
|
||||
/// <summary>Set of all feature-ids supported by StabilityAPI backends.</summary>
|
||||
public static HashSet<string> FeaturesSupported = ["sapi"];
|
||||
|
||||
public static T2IRegisteredParam<string> EngineParam, SamplerParam;
|
||||
|
||||
public override void OnInit()
|
||||
{
|
||||
T2IParamGroup sapiGroup = new("StabilityAPI", Toggles: false, Open: true);
|
||||
Program.Backends.RegisterBackendType<StabilityAPIBackend>("stability_api", "StabilityAPI", "A backend powered by the Stability API.", true);
|
||||
EngineParam = T2IParamTypes.Register<string>(new("[SAPI] Engine", "Engine for StabilityAPI to use.",
|
||||
"stable-diffusion-v1-5", Toggleable: true, FeatureFlag: "sapi", Group: sapiGroup, GetValues: (_) => Engines
|
||||
));
|
||||
SamplerParam = T2IParamTypes.Register<string>(new("[SAPI] Sampler", "Sampler for StabilityAPI to use.",
|
||||
"K_EULER", Toggleable: true, FeatureFlag: "sapi", Group: sapiGroup, GetValues: (_) => [.. Samplers]
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -195,14 +195,6 @@
|
||||
<a href="#" onclick="javascript:$('#gpu_check_modal').modal('show')">Do I?</a> You can learn more about <a href="https://github.com/comfyanonymous/ComfyUI">ComfyUI here</a>.
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="backend_radio" id="backend_radio_stabilityapi" value="stabilityapi">
|
||||
<label class="form-check-label" for="backend_radio_stabilityapi">Stability API (Remote)</label>
|
||||
<div class="install_hint">The Stability API powers DreamStudio and services like it. If you don't have a powerful local PC, you can use the Stability API to power your generations.
|
||||
You must have a valid API key to use this. <a href="https://platform.stability.ai/docs/getting-started/authentication" target="_blank" rel="noopener noreferrer">Click Here for info about the Stability API and how to get an API key.</a>
|
||||
</div>
|
||||
<input type="password" id="stability_api_key" name="Stability API Key" placeholder="Stability API Key">
|
||||
</div>
|
||||
<hr>
|
||||
<h3>For Experienced Users: Skip Backend Install</h3>
|
||||
<div class="install_hint">You can configure custom backends post-install.</div>
|
||||
@@ -217,7 +209,7 @@
|
||||
|
||||
<div id="installer_section_models" style="display: none;">
|
||||
<div class="install_q_head">Download Models</div>
|
||||
<div class="install_hint">You can select models to automatically download for local running here. If you selected 'Stability API' on the previous page, you can skip this page.</div>
|
||||
<div class="install_hint">You can select models to automatically download for local running here.</div>
|
||||
Note: by downloading Stable Diffusion models, you agree to the terms of <a href="https://github.com/Stability-AI/stablediffusion/blob/main/LICENSE-MODEL" target="_blank" rel="noopener noreferrer">The CreativeML Open RAIL++-M License</a>.
|
||||
<br>
|
||||
<fieldset class="form-group" id="models_fieldset">
|
||||
@@ -243,7 +235,7 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
<label>Or community models!</label>
|
||||
<div class="install_hint">You can download an endless variety of community-made models from online sites such as <a href="https://huggingface.co/spaces/huggingface-projects/diffusers-gallery" target="_blank" rel="noopener noreferrer">HuggingFace</a> or <a href="https://civitai.com/" target="_blank" rel="noopener noreferrer">Civitai</a>. (NOTICE: These are examples of third-party websites featuring user-submitted models, Stability.AI offers no guarantees about what content may exist there, browse with caution.) Remember to only download '.safetensors' files, never '.ckpt' ones.</div>
|
||||
<div class="install_hint">You can download an endless variety of community-made models from online sites such as <a href="https://huggingface.co/spaces/huggingface-projects/diffusers-gallery" target="_blank" rel="noopener noreferrer">HuggingFace</a> or <a href="https://civitai.com/" target="_blank" rel="noopener noreferrer">Civitai</a>. (NOTICE: These are examples of third-party websites featuring user-submitted models, We offer no guarantees about what content may exist there, browse with caution.) Remember to only download '.safetensors' files, never '.ckpt' ones.</div>
|
||||
</div>
|
||||
|
||||
<div id="installer_section_end" style="display: none;">
|
||||
|
||||
@@ -256,16 +256,6 @@ public static class BasicAPIFeatures
|
||||
Program.Backends.AddNewOfType(Program.Backends.BackendTypes["comfyui_selfstart"], new ComfyUISelfStartBackend.ComfyUISelfStartSettings() { StartScript = path, GPU_ID = gpu, ExtraArgs = extraArgs.Trim() });
|
||||
break;
|
||||
}
|
||||
case "stabilityapi":
|
||||
if (string.IsNullOrWhiteSpace(stability_api_key))
|
||||
{
|
||||
await output($"Invalid stability API key!");
|
||||
await socket.SendJson(new JObject() { ["error"] = $"Invalid stability API key!" }, API.WebsocketTimeout);
|
||||
return null;
|
||||
}
|
||||
File.WriteAllText("Data/sapi_key.dat", stability_api_key);
|
||||
Program.Backends.AddNewOfType(Program.Backends.BackendTypes["stability_api"]);
|
||||
break;
|
||||
case "none":
|
||||
await output("Not installing any backend.");
|
||||
break;
|
||||
|
||||
@@ -97,9 +97,6 @@ class InstallerClass {
|
||||
if (backend == null) {
|
||||
return false;
|
||||
}
|
||||
if (backend == 'stabilityapi') {
|
||||
return getRequiredElementById('stability_api_key').value != '';
|
||||
}
|
||||
return true;
|
||||
case 'models':
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user