Skip to content

Commit c7d09af

Browse files
committed
feat: add C# implementation of image generation
1 parent 938785b commit c7d09af

File tree

11 files changed

+98604
-1
lines changed

11 files changed

+98604
-1
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
11+
<PackageReference Include="Microsoft.ML.OnnxRuntime" Version="1.23.0" />
12+
<PackageReference Include="NumSharp" Version="0.30.0" />
13+
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<Reference Include="StableDiffusion.ML.OnnxRuntime">
18+
<HintPath>StableDiffusion.ML.OnnxRuntime.dll</HintPath>
19+
</Reference>
20+
</ItemGroup>
21+
22+
</Project>

ImageGen/MaIN.ImageGen/Program.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using SixLabors.ImageSharp;
2+
3+
var builder = WebApplication.CreateBuilder(args);
4+
5+
// Add services to the container.
6+
7+
builder.Services.AddSingleton<StableDiffusionService>();
8+
builder.Services.AddCors(options =>
9+
{
10+
options.AddDefaultPolicy(policy =>
11+
{
12+
policy.AllowAnyOrigin()
13+
.AllowAnyHeader()
14+
.AllowAnyMethod();
15+
});
16+
});
17+
18+
var app = builder.Build();
19+
20+
// Configure the HTTP request pipeline.
21+
22+
app.UseCors();
23+
24+
app.MapPost("/generate", async (GenerateRequest request, StableDiffusionService sdService) =>
25+
{
26+
if (string.IsNullOrWhiteSpace(request?.Prompt))
27+
{
28+
return Results.BadRequest("Prompt cannot be empty.");
29+
}
30+
31+
Image image;
32+
33+
try
34+
{
35+
image = await Task.Run(() => sdService.GenerateImage(request.Prompt));
36+
}
37+
catch (Exception ex)
38+
{
39+
return Results.Problem($"Error generating image: {ex.Message}");
40+
}
41+
42+
var memoryStream = new MemoryStream();
43+
await image.SaveAsPngAsync(memoryStream);
44+
memoryStream.Position = 0;
45+
46+
var safeFileName = new string(request.Prompt.Take(20).Where(c => !Path.GetInvalidFileNameChars().Contains(c)).ToArray());
47+
return Results.File(memoryStream, "image/png", $"image-for-{safeFileName}.png");
48+
});
49+
50+
app.Run();
51+
52+
public record GenerateRequest(string? Prompt);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"$schema": "http://json.schemastore.org/launchsettings.json",
3+
"iisSettings": {
4+
"windowsAuthentication": false,
5+
"anonymousAuthentication": true,
6+
"iisExpress": {
7+
"applicationUrl": "http://localhost:11590",
8+
"sslPort": 44335
9+
}
10+
},
11+
"profiles": {
12+
"http": {
13+
"commandName": "Project",
14+
"dotnetRunMessages": true,
15+
"applicationUrl": "http://localhost:5015",
16+
"environmentVariables": {
17+
"ASPNETCORE_ENVIRONMENT": "Development"
18+
}
19+
},
20+
"https": {
21+
"commandName": "Project",
22+
"dotnetRunMessages": true,
23+
"applicationUrl": "https://localhost:7091;http://localhost:5015",
24+
"environmentVariables": {
25+
"ASPNETCORE_ENVIRONMENT": "Development"
26+
}
27+
},
28+
"IIS Express": {
29+
"commandName": "IISExpress",
30+
"environmentVariables": {
31+
"ASPNETCORE_ENVIRONMENT": "Development"
32+
}
33+
}
34+
}
35+
}
25 KB
Binary file not shown.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using SixLabors.ImageSharp;
2+
using StableDiffusion.ML.OnnxRuntime;
3+
using System.Globalization;
4+
5+
public class StableDiffusionService
6+
{
7+
private readonly StableDiffusionConfig _config;
8+
private readonly ILogger<StableDiffusionService> _logger;
9+
10+
public StableDiffusionService(IConfiguration configuration, ILogger<StableDiffusionService> logger)
11+
{
12+
_logger = logger;
13+
var sdConfigSection = configuration.GetSection("StableDiffusionConfig");
14+
var configModelPath = sdConfigSection["ModelPath"];
15+
16+
var modelPath = string.IsNullOrEmpty(configModelPath) ?
17+
throw new ArgumentNullException("Model path is not configured.") :
18+
configModelPath;
19+
20+
_config = new StableDiffusionConfig
21+
{
22+
NumInferenceSteps = int.Parse(sdConfigSection["NumInferenceSteps"]!),
23+
GuidanceScale = double.Parse(sdConfigSection["GuidanceScale"]!, CultureInfo.InvariantCulture),
24+
ExecutionProviderTarget = Enum.Parse<StableDiffusionConfig.ExecutionProvider>(sdConfigSection["ExecutionProviderTarget"]!),
25+
TextEncoderOnnxPath = Path.Combine(modelPath, "text_encoder", "model.onnx"),
26+
UnetOnnxPath = Path.Combine(modelPath, "unet", "model.onnx"),
27+
VaeDecoderOnnxPath = Path.Combine(modelPath, "vae_decoder", "model.onnx"),
28+
TokenizerOnnxPath = Path.Combine(Directory.GetCurrentDirectory(), "cliptokenizer.onnx"),
29+
OrtExtensionsPath = Path.Combine(Directory.GetCurrentDirectory(), "ortextensions.dll"),
30+
};
31+
}
32+
33+
public Image GenerateImage(string prompt)
34+
{
35+
try
36+
{
37+
_logger.LogInformation("Generating image for prompt: {Prompt}", prompt);
38+
return UNet.Inference(prompt, _config);
39+
}
40+
catch (Exception ex)
41+
{
42+
_logger.LogError(ex, "Error generating image for prompt: {Prompt}", prompt);
43+
throw;
44+
}
45+
}
46+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
}
8+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
},
8+
"AllowedHosts": "*",
9+
"StableDiffusionConfig": {
10+
"NumInferenceSteps": 8,
11+
"GuidanceScale": 7.5,
12+
"ExecutionProviderTarget": "Cpu", // Options: "Cpu", "DirectML"
13+
"ModelPath": "C:\\Users\\examplePath\\CompVis"
14+
// Folder hierarchy should look like:
15+
// CompVis
16+
// ├── text_encoder
17+
// ├── model.onnx
18+
// ├── unet
19+
// ├── model.onnx
20+
// ├── weights.pb
21+
// ├── vae_decoder
22+
// ├── model.onnx
23+
// link to the model: https://huggingface.co/CompVis/stable-diffusion-v1-4/tree/onnx
24+
}
25+
}

0 commit comments

Comments
 (0)