Skip to content

Commit 6e37343

Browse files
committed
Use AiServerClient.cs for image generation.
1 parent 7e35efc commit 6e37343

File tree

4 files changed

+1548
-9
lines changed

4 files changed

+1548
-9
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ coverage/
99
blog/
1010
package-lock.json
1111
App_Data/
12+
BlazorDiffusion/Configure.Secrets.cs
1213

1314
# User-specific files
1415
*.suo
+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using AiServer.ServiceModel;
2+
using AiServer.ServiceModel.Types;
3+
using BlazorDiffusion.ServiceInterface;
4+
using BlazorDiffusion.ServiceModel;
5+
using ServiceStack.IO;
6+
using ServiceStack.Text;
7+
using JsonApiClient = ServiceStack.JsonApiClient;
8+
9+
namespace BlazorDiffusion.AiServer;
10+
public class AiServerClient: IStableDiffusionClient
11+
{
12+
public JsonApiClient Client { get; set; }
13+
public IVirtualFiles VirtualFiles { get; set; }
14+
15+
public string? OutputPathPrefix { get; set; }
16+
17+
private object seedLock = new();
18+
19+
public async Task<ImageGenerationResponse> GenerateImageAsync(ImageGeneration request)
20+
{
21+
var req = request.ToComfy();
22+
var res = await Client.PostAsync(req);
23+
if (res == null)
24+
throw new Exception("Failed to generate image.");
25+
var now = DateTime.UtcNow;
26+
var key = $"{now:yyyy/MM/dd}/{(long)now.TimeOfDay.TotalMilliseconds}";
27+
28+
var results = new List<ImageGenerationResult>();
29+
var seed = (res?.Request?.Seed ?? 0).ConvertTo<uint>();
30+
await Parallel.ForEachAsync(res.Images, async (item, token) =>
31+
{
32+
var artifactUrl = $"{Client.BaseUri.TrimEnd('/')}/uploads{item.Url}";
33+
var bytes = await artifactUrl.GetBytesFromUrlAsync(token: token);
34+
var imageDetails = ImageDetails.Calculate(bytes);
35+
var uuid = Guid.NewGuid().ToString("N");
36+
lock (seedLock)
37+
{
38+
results.Add(new()
39+
{
40+
Prompt = request.Prompt,
41+
Seed = seed,
42+
AnswerId = res.PromptId,
43+
FilePath = $"/artifacts/{key}/output_{uuid}.png",
44+
FileName = $"output_{uuid}.png",
45+
ContentLength = bytes.Length,
46+
Width = request.Width,
47+
Height = request.Height,
48+
ImageDetails = imageDetails,
49+
});
50+
// Assume incremental seeds for multiple images as comfyui does not provide the specific image seed back
51+
seed++;
52+
}
53+
var output = Path.Join(OutputPathPrefix, key, $"output_{uuid}.png");
54+
await VirtualFiles.WriteFileAsync(output, bytes, token);
55+
});
56+
57+
return new ImageGenerationResponse
58+
{
59+
RequestId = res.PromptId,
60+
EngineId = "comfy",
61+
Key = key,
62+
Results = results,
63+
};
64+
}
65+
66+
public string GetMetadataPath(Creative creative) => OutputPathPrefix.CombineWith(creative.Key, "metadata.json");
67+
public IVirtualFile GetMetadataFile(Creative creative) => VirtualFiles.GetFile(GetMetadataPath(creative));
68+
69+
public async Task SaveMetadataAsync(Creative creative)
70+
{
71+
var vfsPathSuffix = creative.Key;
72+
var outputDir = Path.Join(OutputPathPrefix, vfsPathSuffix);
73+
await VirtualFiles.WriteFileAsync(Path.Join(outputDir, "metadata.json"), creative.ToJson().IndentJson());
74+
}
75+
76+
public Task DeleteFolderAsync(Creative creative)
77+
{
78+
var vfsPathSuffix = creative.Key;
79+
var directory = VirtualFiles.GetDirectory(Path.Join(OutputPathPrefix, vfsPathSuffix));
80+
var allFiles = directory.GetAllFiles();
81+
VirtualFiles.DeleteFiles(allFiles);
82+
return Task.CompletedTask;
83+
}
84+
}
85+
86+
public static class StableDiffusionClientExtensions
87+
{
88+
public static ComfyTextToImage ToComfy(this ImageGeneration request)
89+
{
90+
return new ComfyTextToImage
91+
{
92+
Height = request.Height,
93+
Width = request.Width,
94+
Seed = request.Seed ?? Random.Shared.Next(),
95+
BatchSize = request.Images,
96+
PositivePrompt = request.Prompt,
97+
};
98+
}
99+
}

0 commit comments

Comments
 (0)