Skip to content
This repository was archived by the owner on Nov 27, 2024. It is now read-only.

Commit 3f99db5

Browse files
committed
Minimal WebUI added
1 parent b80207e commit 3f99db5

File tree

88 files changed

+75689
-5
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+75689
-5
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,3 +343,4 @@ test/TensorFlowNET.Examples/mnist
343343
# docs
344344
site/
345345

346+
/OnnxStack.WebUI/wwwroot/images/Results/*

OnnxStack.Core/Config/OnnxStackConfig.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ public class OnnxStackConfig : IConfigSection
2020
/// </summary>
2121
public ExecutionProvider ExecutionProviderTarget { get; set; } = ExecutionProvider.DirectML;
2222

23-
[JsonIgnore]
2423
public string OnnxTokenizerPath { get; set; }
2524
public string OnnxUnetPath { get; set; }
2625
public string OnnxVaeDecoderPath { get; set; }
@@ -34,7 +33,6 @@ public class OnnxStackConfig : IConfigSection
3433

3534
public void Initialize()
3635
{
37-
OnnxTokenizerPath = "cliptokenizer.onnx";
3836
}
3937
}
4038
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
using Microsoft.AspNetCore.SignalR;
2+
using OnnxStack.StableDiffusion.Common;
3+
using OnnxStack.StableDiffusion.Config;
4+
using OnnxStack.WebUI.Models;
5+
using System;
6+
using System.Runtime.CompilerServices;
7+
8+
namespace OnnxStack.Web.Hubs
9+
{
10+
public class StableDiffusionHub : Hub
11+
{
12+
private readonly ILogger<StableDiffusionHub> _logger;
13+
private readonly IStableDiffusionService _stableDiffusionService;
14+
private readonly IWebHostEnvironment _webHostEnvironment;
15+
public StableDiffusionHub(ILogger<StableDiffusionHub> logger, IStableDiffusionService stableDiffusionService, IWebHostEnvironment webHostEnvironment)
16+
{
17+
_logger = logger;
18+
_webHostEnvironment = webHostEnvironment;
19+
_stableDiffusionService = stableDiffusionService;
20+
}
21+
22+
public override async Task OnConnectedAsync()
23+
{
24+
_logger.Log(LogLevel.Information, "[OnConnectedAsync], Id: {0}", Context.ConnectionId);
25+
26+
await Clients.Caller.SendAsync("OnMessage", "OnConnectedAsync");
27+
await base.OnConnectedAsync();
28+
}
29+
30+
31+
public override async Task OnDisconnectedAsync(Exception exception)
32+
{
33+
_logger.Log(LogLevel.Information, "[OnDisconnectedAsync], Id: {0}", Context.ConnectionId);
34+
35+
await Clients.Caller.SendAsync("OnMessage", "OnDisconnectedAsync");
36+
await base.OnDisconnectedAsync(exception);
37+
}
38+
39+
40+
[HubMethodName("ExecuteTextToImage")]
41+
public async IAsyncEnumerable<DiffusionResult> OnExecuteTextToImage(TextToImageOptions options, [EnumeratorCancellation] CancellationToken cancellationToken)
42+
{
43+
_logger.Log(LogLevel.Information, "[OnExecuteTextToImage] - New prompt received, Connection: {0}", Context.ConnectionId);
44+
var linkedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(Context.ConnectionAborted, cancellationToken);
45+
46+
var promptOptions = new PromptOptions
47+
{
48+
Prompt = options.Prompt,
49+
NegativePrompt = options.NegativePrompt,
50+
SchedulerType = options.SchedulerType
51+
};
52+
53+
var schedulerOptions = new SchedulerOptions
54+
{
55+
Width = options.Width,
56+
Height = options.Height,
57+
Seed = GenerateSeed(options.Seed),
58+
InferenceSteps = options.InferenceSteps,
59+
GuidanceScale = options.GuidanceScale,
60+
Strength = options.Strength,
61+
InitialNoiseLevel = options.InitialNoiseLevel
62+
};
63+
64+
// TODO: Add support for multiple results
65+
var result = await GenerateTextToImage(promptOptions, schedulerOptions, cancellationToken);
66+
if(result is null)
67+
yield break;
68+
69+
yield return result;
70+
}
71+
72+
private async Task<DiffusionResult> GenerateTextToImage(PromptOptions promptOptions, SchedulerOptions schedulerOptions, CancellationToken cancellationToken)
73+
{
74+
var rand = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());
75+
var outputImage = $"{schedulerOptions.Seed}_{promptOptions.SchedulerType}_{rand}.png";
76+
var outputImageUrl = CreateOutputImageUrl("TextToImage", outputImage);
77+
var outputImageFile = CreateOutputImageFile(outputImageUrl);
78+
79+
try
80+
{
81+
await _stableDiffusionService.TextToImageFile(promptOptions, schedulerOptions, outputImageFile, ProgressCallback(), cancellationToken);
82+
return new DiffusionResult(outputImage, outputImageUrl);
83+
}
84+
catch (OperationCanceledException tex)
85+
{
86+
await Clients.Caller.SendAsync("OnCanceled", tex.Message);
87+
}
88+
catch (Exception ex)
89+
{
90+
await Clients.Caller.SendAsync("OnError", ex.Message);
91+
}
92+
return null;
93+
}
94+
95+
private int GenerateSeed(int seed)
96+
{
97+
if (seed > 0)
98+
return seed;
99+
100+
return Random.Shared.Next();
101+
}
102+
103+
private Action<int, int> ProgressCallback()
104+
{
105+
return async (progress, total) =>
106+
{
107+
_logger.Log(LogLevel.Information, "[OnExecuteTextToImage] - Progress: {0}/{1}, Connection: {2}", progress, total, Context.ConnectionId);
108+
await Clients.Caller.SendAsync("OnProgress", new ProgressResult(progress, total));
109+
};
110+
}
111+
112+
113+
private string CreateOutputImageFile(string url)
114+
{
115+
string webRootPath = _webHostEnvironment.WebRootPath;
116+
string physicalPath = Path.Combine(webRootPath, url.TrimStart('/').Replace('/', '\\'));
117+
return physicalPath;
118+
}
119+
120+
private string CreateOutputImageUrl(string folder, string imageName)
121+
{
122+
return $"/images/results/{folder}/{imageName}";
123+
}
124+
}
125+
126+
public record ProgressResult(int Progress, int Total);
127+
public record DiffusionResult(string OutputImage, string OutputImageUrl);
128+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using OnnxStack.StableDiffusion.Enums;
2+
using System.ComponentModel.DataAnnotations;
3+
4+
namespace OnnxStack.WebUI.Models
5+
{
6+
public class TextToImageOptions
7+
{
8+
[Required]
9+
[StringLength(512, MinimumLength = 2)]
10+
public string Prompt { get; set; }
11+
12+
[StringLength(512)]
13+
public string NegativePrompt { get; set; }
14+
public SchedulerType SchedulerType { get; set; }
15+
16+
[Range(64, 1024)]
17+
public int Width { get; set; } = 512;
18+
19+
[Range(64, 1024)]
20+
public int Height { get; set; } = 512;
21+
22+
[Range(0, int.MaxValue)]
23+
public int Seed { get; set; }
24+
25+
[Range(1, 100)]
26+
public int InferenceSteps { get; set; } = 30;
27+
28+
[Range(0f, 40f)]
29+
public float GuidanceScale { get; set; } = 7.5f;
30+
31+
[Range(0f, 1f)]
32+
public float Strength { get; set; } = 0.6f;
33+
34+
[Range(-1f, 1f)]
35+
public float InitialNoiseLevel { get; set; } = 0f;
36+
}
37+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net7.0</TargetFramework>
5+
<Nullable>disable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<PlatformTarget>x64</PlatformTarget>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.ML.OnnxRuntime.DirectML" Version="1.16.0" />
12+
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\OnnxStack.StableDiffusion\OnnxStack.StableDiffusion.csproj" />
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<None Include="wwwroot\Images\Results\TextToImage\TestImage.png" />
21+
</ItemGroup>
22+
23+
</Project>

OnnxStack.WebUI/Pages/Error.cshtml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@page
2+
@model ErrorModel
3+
@{
4+
ViewData["Title"] = "Error";
5+
}
6+
7+
<h1 class="text-danger">Error.</h1>
8+
<h2 class="text-danger">An error occurred while processing your request.</h2>
9+
10+
@if (Model.ShowRequestId)
11+
{
12+
<p>
13+
<strong>Request ID:</strong> <code>@Model.RequestId</code>
14+
</p>
15+
}
16+
17+
<h3>Development Mode</h3>
18+
<p>
19+
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
20+
</p>
21+
<p>
22+
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
23+
It can result in displaying sensitive information from exceptions to end users.
24+
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
25+
and restarting the app.
26+
</p>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using Microsoft.AspNetCore.Mvc.RazorPages;
3+
using System.Diagnostics;
4+
5+
namespace OnnxStack.WebUI.Pages
6+
{
7+
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
8+
[IgnoreAntiforgeryToken]
9+
public class ErrorModel : PageModel
10+
{
11+
public string? RequestId { get; set; }
12+
13+
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
14+
15+
private readonly ILogger<ErrorModel> _logger;
16+
17+
public ErrorModel(ILogger<ErrorModel> logger)
18+
{
19+
_logger = logger;
20+
}
21+
22+
public void OnGet()
23+
{
24+
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
25+
}
26+
}
27+
}

OnnxStack.WebUI/Pages/Index.cshtml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
@page
2+
@using OnnxStack.StableDiffusion.Enums;
3+
@model IndexModel
4+
@{
5+
ViewData["Title"] = "Home page";
6+
}
7+
8+
<style>
9+
10+
.card-group > .card {
11+
border-radius: 3px !important;
12+
border: solid 1px rgba(0,0,0,.125) !important;
13+
}
14+
15+
</style>
16+
17+
<div class="d-flex flex-row h-100 pt-1 pb-1">
18+
<div class="d-flex flex-fill flex-wrap justify-content-center align-content-center align-items-center">
19+
<div class="card-group gap-4">
20+
21+
<div class="card" style="width: 18rem;">
22+
<img src="~/images/placeholder.jpg" class="card-img-top" alt="...">
23+
<div class="card-body">
24+
<h5 class="card-title">Text To Image</h5>
25+
<p class="card-text">Text to image transforms textual descriptions into visual content</p>
26+
</div>
27+
<div class="card-footer">
28+
<a href="/StableDiffusion/TextToImage" class=" d-block btn btn-primary">Demo</a>
29+
</div>
30+
</div>
31+
32+
<div class="card" style="width: 18rem;">
33+
<img src="~/images/placeholder.jpg" class="card-img-top" alt="...">
34+
<div class="card-body">
35+
<h5 class="card-title">Image To Image</h5>
36+
<p class="card-text">Image to image transforms one image into another, preserving visual quality and structure.</p>
37+
</div>
38+
<div class="card-footer">
39+
<button href="#" class="d-block btn btn-primary w-100" disabled>Demo</button>
40+
</div>
41+
</div>
42+
43+
<div class="card border-1" style="width: 18rem;border-left:1px">
44+
<img src="~/images/placeholder.jpg" class="card-img-top" alt="...">
45+
<div class="card-body">
46+
<h5 class="card-title">In-Painting</h5>
47+
<p class="card-text">Inpainting is a computer vision technique that reconstructs missing or damaged parts of an image, seamlessly filling in the gaps to restore visual completeness</p>
48+
</div>
49+
<div class="card-footer">
50+
<button href="#" class="d-block btn btn-primary w-100" disabled>Demo</button>
51+
</div>
52+
</div>
53+
</div>
54+
</div>
55+
</div>
56+
57+
58+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using Microsoft.AspNetCore.Mvc.RazorPages;
3+
using OnnxStack.StableDiffusion.Config;
4+
5+
namespace OnnxStack.WebUI.Pages
6+
{
7+
public class IndexModel : PageModel
8+
{
9+
private readonly ILogger<IndexModel> _logger;
10+
11+
public IndexModel(ILogger<IndexModel> logger)
12+
{
13+
_logger = logger;
14+
}
15+
16+
[BindProperty]
17+
public PromptOptions PromptOptions { get; set; }
18+
19+
[BindProperty]
20+
public SchedulerOptions SchedulerOptions { get; set; }
21+
22+
public void OnGet()
23+
{
24+
25+
}
26+
}
27+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@page
2+
@model PrivacyModel
3+
@{
4+
ViewData["Title"] = "Privacy Policy";
5+
}
6+
<h1>@ViewData["Title"]</h1>
7+

0 commit comments

Comments
 (0)