Skip to content

Commit c4a6f3d

Browse files
committed
feat: add C# implementation of image generation as a service
1 parent c7d09af commit c4a6f3d

File tree

10 files changed

+98441
-10
lines changed

10 files changed

+98441
-10
lines changed

ImageGen/MaIN.ImageGen/appsettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"NumInferenceSteps": 8,
1111
"GuidanceScale": 7.5,
1212
"ExecutionProviderTarget": "Cpu", // Options: "Cpu", "DirectML"
13-
"ModelPath": "C:\\Users\\examplePath\\CompVis"
13+
"ModelPath": "C:\\Users\\zlote\\Desktop\\MAIN\\ImageGeneration\\ImageGeneration\\OnnxModels\\CompVis"
1414
// Folder hierarchy should look like:
1515
// CompVis
1616
// ├── text_encoder

MaIN.sln

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 17
4-
VisualStudioVersion = 17.14.36429.23 d17.14
4+
VisualStudioVersion = 17.14.36429.23
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaIN", "src\MaIN\MaIN.csproj", "{7E8DD6E0-F9A8-4BD0-8733-49F0F2F4FCA0}"
77
EndProject
@@ -29,8 +29,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaIN.InferPage", "src\MaIN.
2929
EndProject
3030
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaIN.Core.IntegrationTests", "MaIN.Core.IntegrationTests\MaIN.Core.IntegrationTests.csproj", "{2C15062A-E9F6-47FC-A4CD-1190A49E3FE3}"
3131
EndProject
32-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaIN.ImageGen", "ImageGen\MaIN.ImageGen\MaIN.ImageGen.csproj", "{2345FAF2-6462-465B-8D80-7BD2819D66CF}"
33-
EndProject
3432
Global
3533
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3634
Debug|Any CPU = Debug|Any CPU
@@ -81,10 +79,6 @@ Global
8179
{2C15062A-E9F6-47FC-A4CD-1190A49E3FE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
8280
{2C15062A-E9F6-47FC-A4CD-1190A49E3FE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
8381
{2C15062A-E9F6-47FC-A4CD-1190A49E3FE3}.Release|Any CPU.Build.0 = Release|Any CPU
84-
{2345FAF2-6462-465B-8D80-7BD2819D66CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
85-
{2345FAF2-6462-465B-8D80-7BD2819D66CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
86-
{2345FAF2-6462-465B-8D80-7BD2819D66CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
87-
{2345FAF2-6462-465B-8D80-7BD2819D66CF}.Release|Any CPU.Build.0 = Release|Any CPU
8882
EndGlobalSection
8983
GlobalSection(SolutionProperties) = preSolution
9084
HideSolutionNode = FALSE

src/MaIN.Domain/Configuration/MaINSettings.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public class MaINSettings
1313
public string? DeepSeekKey { get; set; }
1414
public string? AnthropicKey { get; set; }
1515
public string? GroqCloudKey { get; set; }
16+
public ImageGenSettings? ImageGenSettings { get; set; }
1617
public MongoDbSettings? MongoDbSettings { get; set; }
1718
public FileSystemSettings? FileSystemSettings { get; set; }
1819
public SqliteSettings? SqliteSettings { get; set; }
@@ -28,4 +29,13 @@ public enum BackendType
2829
DeepSeek = 3,
2930
GroqCloud = 4,
3031
Anthropic = 5,
32+
ONNX = 6,
33+
}
34+
35+
public class ImageGenSettings
36+
{
37+
public string ExecutionProviderTarget { get; set; } = "Cpu"; // Options: "Cpu", "DirectML"
38+
public int NumInferenceSteps { get; set; } = 8;
39+
public double GuidanceScale { get; set; } = 7.5;
40+
public string ModelPath { get; set; } = string.Empty;
3141
}

src/MaIN.Services/MaIN.Services.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<PackageReference Include="LLamaSharp.Backend.Cuda12" Version="0.25.0" />
2121
<PackageReference Include="LLamaSharp.kernel-memory" Version="0.25.0" />
2222
<PackageReference Include="LLamaSharp.semantic-kernel" Version="0.25.0" />
23+
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
2324
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.4" />
2425
<PackageReference Include="Microsoft.KernelMemory" Version="0.98.250508.3" />
2526
<PackageReference Include="Microsoft.KernelMemory.SemanticKernelPlugin" Version="0.98.250508.3" />
@@ -29,9 +30,16 @@
2930
<PackageReference Include="ModelContextProtocol.AspNetCore" Version="0.2.0-preview.1" />
3031
<PackageReference Include="NAudio" Version="2.2.1" />
3132
<PackageReference Include="NumSharp" Version="0.30.0" />
33+
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
3234
<PackageReference Include="System.Data.SqlClient" Version="4.8.6" />
3335
<PackageReference Include="Tesseract" Version="5.2.0" />
3436
<PackageReference Include="Tesseract.Data.English" Version="4.0.0" />
3537
</ItemGroup>
3638

39+
<ItemGroup>
40+
<Reference Include="StableDiffusion.ML.OnnxRuntime">
41+
<HintPath>Services\ImageGenServices\StableDiffusion.ML.OnnxRuntime.dll</HintPath>
42+
</Reference>
43+
</ItemGroup>
44+
3745
</Project>

src/MaIN.Services/Services/ChatService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public async Task<ChatResult> Completions(
5959
}
6060

6161
var result = chat.Visual
62-
? await imageGenServiceFactory.CreateService(chat.Backend.Value)!.Send(chat)
62+
? await imageGenServiceFactory.CreateService(BackendType.ONNX)!.Send(chat)
6363
: await llmServiceFactory.CreateService(chat.Backend.Value).Send(chat, new ChatRequestOptions()
6464
{
6565
InteractiveUpdates = interactiveUpdates,
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
using MaIN.Domain.Configuration;
2+
using MaIN.Domain.Entities;
3+
using MaIN.Services.Constants;
4+
using MaIN.Services.Services.Abstract;
5+
using MaIN.Services.Services.Models;
6+
using SixLabors.ImageSharp;
7+
using StableDiffusion.ML.OnnxRuntime;
8+
using MathNet.Numerics;
9+
using MathNet.Numerics.LinearAlgebra;
10+
11+
namespace MaIN.Services.Services.ImageGenServices;
12+
13+
public class ImageGenONNXService(MaINSettings settings) : IImageGenService
14+
{
15+
private readonly MaINSettings _settings = settings ?? throw new ArgumentNullException(nameof(settings));
16+
public Task<ChatResult?> Send(Chat chat)
17+
{
18+
var matrixCheck = Matrix<double>.Build.Dense(1, 1); // Ensures MathNet.Numerics is referenced
19+
StableDiffusionConfig config = GetStableDiffusionConfig();
20+
21+
string prompt = chat.Messages
22+
.Select((msg, index) => index == 0 ? msg.Content : $"&& {msg.Content}")
23+
.Aggregate((current, next) => $"{current} {next}");
24+
25+
try
26+
{
27+
Image image = GenerateImage(prompt, config);
28+
using var ms = new MemoryStream();
29+
image.SaveAsPng(ms);
30+
byte[] imageBytes = ms.ToArray();
31+
return Task.FromResult<ChatResult?>(CreateChatResult(imageBytes));
32+
}
33+
catch (Exception ex)
34+
{
35+
throw new InvalidOperationException("Error generating image with ONNX", ex);
36+
}
37+
}
38+
39+
private StableDiffusionConfig GetStableDiffusionConfig()
40+
{
41+
ImageGenSettings imgSettings = new()
42+
{
43+
ExecutionProviderTarget = "Cpu",
44+
NumInferenceSteps = 8,
45+
GuidanceScale = 7.5,
46+
ModelPath = "C:\\Users\\zlote\\Desktop\\MAIN\\ImageGeneration\\ImageGeneration\\OnnxModels\\CompVis"
47+
};
48+
//ImageGenSettings imgSettings = _settings.ImageGenSettings
49+
// ?? throw new InvalidOperationException("Image generation settings are not configured.");
50+
51+
return new StableDiffusionConfig
52+
{
53+
NumInferenceSteps = imgSettings.NumInferenceSteps,
54+
GuidanceScale = imgSettings.GuidanceScale,
55+
ExecutionProviderTarget = Enum.Parse<StableDiffusionConfig.ExecutionProvider>(imgSettings.ExecutionProviderTarget),
56+
TextEncoderOnnxPath = Path.Combine(imgSettings.ModelPath, "text_encoder", "model.onnx"),
57+
UnetOnnxPath = Path.Combine(imgSettings.ModelPath, "unet", "model.onnx"),
58+
VaeDecoderOnnxPath = Path.Combine(imgSettings.ModelPath, "vae_decoder", "model.onnx"),
59+
TokenizerOnnxPath = Path.Combine(imgSettings.ModelPath, "cliptokenizer.onnx"),
60+
OrtExtensionsPath = Path.Combine(imgSettings.ModelPath, "ortextensions.dll"),
61+
};
62+
}
63+
64+
private Image GenerateImage(string prompt, StableDiffusionConfig config)
65+
{
66+
try
67+
{
68+
return UNet.Inference(prompt, config);
69+
}
70+
catch (Exception)
71+
{
72+
throw;
73+
}
74+
}
75+
76+
private ChatResult CreateChatResult(byte[] imageBytes)
77+
{
78+
return new ChatResult
79+
{
80+
Done = true,
81+
Message = new Message
82+
{
83+
Content = ServiceConstants.Messages.GeneratedImageContent,
84+
Role = ServiceConstants.Roles.Assistant,
85+
Image = imageBytes,
86+
Type = MessageType.Image
87+
},
88+
Model = "CompVis", //Path.GetFileName(_settings.ImageGenSettings!.ModelPath),
89+
CreatedAt = DateTime.UtcNow
90+
};
91+
}
92+
}
Binary file not shown.

0 commit comments

Comments
 (0)