Refactored ImageGenerator
Option "StableDiffusionModel" zu AppSettings hinzugefügt
This commit is contained in:
parent
80c7dca613
commit
fa75985014
|
@ -19,7 +19,7 @@ public class BildInfoData
|
||||||
/// Fügt die gegebene BildInfo zur Datenbank hinzu und aktualisiert das <see cref="BildInfoModel.Id"/>-Feld mit dem entsprechenden Wert.
|
/// Fügt die gegebene BildInfo zur Datenbank hinzu und aktualisiert das <see cref="BildInfoModel.Id"/>-Feld mit dem entsprechenden Wert.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bildInfo">Die BildInfo, die zur Datenbank hinzugefügt werden soll.</param>
|
/// <param name="bildInfo">Die BildInfo, die zur Datenbank hinzugefügt werden soll.</param>
|
||||||
public async Task AddBildInfoAsync(BildInfoModel bildInfo)
|
public async Task InsertBildInfoAsync(BildInfoModel bildInfo)
|
||||||
{
|
{
|
||||||
var id = await _db.LoadData<int, BildInfoModel>("dbo.spBildInfo_Insert", bildInfo);
|
var id = await _db.LoadData<int, BildInfoModel>("dbo.spBildInfo_Insert", bildInfo);
|
||||||
bildInfo.Id = id.Single();
|
bildInfo.Id = id.Single();
|
||||||
|
|
|
@ -10,8 +10,13 @@ public class ImageGenerator
|
||||||
private readonly HttpClient _client = new();
|
private readonly HttpClient _client = new();
|
||||||
private readonly BildInfoData _bildInfoData;
|
private readonly BildInfoData _bildInfoData;
|
||||||
|
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
|
||||||
|
private string ModelName => _config.GetValue<string>("StableDiffusionModel") ?? "No Model Defined";
|
||||||
|
|
||||||
public ImageGenerator(IConfiguration config, BildInfoData bildInfoData)
|
public ImageGenerator(IConfiguration config, BildInfoData bildInfoData)
|
||||||
{
|
{
|
||||||
|
_config = config;
|
||||||
_bildInfoData = bildInfoData;
|
_bildInfoData = bildInfoData;
|
||||||
|
|
||||||
string? inferenceApiKey = config.GetValue<string>("API:HF_Inference");
|
string? inferenceApiKey = config.GetValue<string>("API:HF_Inference");
|
||||||
|
@ -21,13 +26,18 @@ public class ImageGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Geneiert das Bild für den aktuellen <see cref="_imagePrompt"/>
|
/// Geneiert ein Bild für den gegebenen Wunsch.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<string?> GenerateImageAsync(string prompt, string negativePromt, int? width, int? height, WunschInfoModel wunschInfo, bool isRetry = false)
|
/// <param name="wunschInfo">Der Wunsch zu dem ein Bild generiert werden soll.</param>
|
||||||
|
/// <param name="width">Die breite des zu generierenden Bildes. <see langword="null"/> für Standardbreite des Modells</param>
|
||||||
|
/// <param name="height">Die höhe des zu generierenden Bildes. <see langword="null"/> für Standardhöhe des Modells</param>
|
||||||
|
/// <param name="negativePromt">Begriffe, die explizit nicht generiert werden sollen.</param>
|
||||||
|
/// <returns>Die BildInfo des generierten Bildes; oder null, wenn ein Fehler auftrat.</returns>
|
||||||
|
public async Task<BildInfoModel?> GenerateImageAsync(WunschInfoModel wunschInfo, int? width = null, int? height = null, string negativePromt = "")
|
||||||
{
|
{
|
||||||
var postData = new
|
var postData = new
|
||||||
{
|
{
|
||||||
inputs = prompt,
|
inputs = wunschInfo.BildPrompt,
|
||||||
parameters = new
|
parameters = new
|
||||||
{
|
{
|
||||||
negative_prompt = negativePromt, //"photorealistic, highly detailed, 8K, portrait",
|
negative_prompt = negativePromt, //"photorealistic, highly detailed, 8K, portrait",
|
||||||
|
@ -36,9 +46,11 @@ public class ImageGenerator
|
||||||
},
|
},
|
||||||
options = new
|
options = new
|
||||||
{
|
{
|
||||||
|
// https://huggingface.co/docs/api-inference/detailed_parameters
|
||||||
// Cache deaktivieren, damit Huggingface für den selben Prompt unterschiedliche Ergebnisse liefert
|
// Cache deaktivieren, damit Huggingface für den selben Prompt unterschiedliche Ergebnisse liefert
|
||||||
use_cache = false,
|
use_cache = false,
|
||||||
// Erst wenn wir bereits in einem retry sind warten wir implizit auf das Model. (ignoriert quasi 503-Fehler)
|
// Ignoriert 503-Fehler. Diese treten auf wenn Hugging Face das Model noch nicht geladen hat.
|
||||||
|
// Mit true ignorieren wir den Fehler und schlagen erst fehl, wenn wir einen timeout haben.
|
||||||
wait_for_model = true
|
wait_for_model = true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -47,10 +59,7 @@ public class ImageGenerator
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//const string modelName = "Nacken/kkkk-sdxl-5000";
|
var inferenceModelUrl = $"https://api-inference.huggingface.co/models/{ModelName}";
|
||||||
const string modelName = "Nacken/kkk-sdxl-18000";
|
|
||||||
|
|
||||||
var inferenceModelUrl = $"https://api-inference.huggingface.co/models/{modelName}";
|
|
||||||
|
|
||||||
var response = await _client.PostAsync(inferenceModelUrl, content);
|
var response = await _client.PostAsync(inferenceModelUrl, content);
|
||||||
|
|
||||||
|
@ -58,29 +67,20 @@ public class ImageGenerator
|
||||||
{
|
{
|
||||||
await using Stream imageStream = await response.Content.ReadAsStreamAsync();
|
await using Stream imageStream = await response.Content.ReadAsStreamAsync();
|
||||||
|
|
||||||
using Image image = await Image.LoadAsync(imageStream);
|
|
||||||
|
|
||||||
DateTime imageDate = DateTime.Now;
|
DateTime imageDate = DateTime.Now;
|
||||||
|
|
||||||
BildInfoModel bildInfo = new()
|
BildInfoModel bildInfo = new()
|
||||||
{
|
{
|
||||||
|
// Die tatsächliche Url wird in SaveImageStreamAsync gesetzt.
|
||||||
Dateiname = "PlaceHolder",
|
Dateiname = "PlaceHolder",
|
||||||
Datum = imageDate,
|
Datum = imageDate,
|
||||||
ImageModel = modelName,
|
ImageModel = ModelName,
|
||||||
WunschId = wunschInfo.Id
|
WunschId = wunschInfo.Id
|
||||||
};
|
};
|
||||||
|
|
||||||
await _bildInfoData.AddBildInfoAsync(bildInfo);
|
await SaveImageStreamAsync(imageStream, bildInfo);
|
||||||
|
|
||||||
string imgUrl = $"generated_images/Image_{bildInfo.Id}.jpg";
|
return bildInfo;
|
||||||
|
|
||||||
string mapPath = $"./wwwroot/{imgUrl}";
|
|
||||||
await image.SaveAsJpegAsync(mapPath);
|
|
||||||
|
|
||||||
bildInfo.Dateiname = imgUrl;
|
|
||||||
await _bildInfoData.UpdateBildInfoDateinameAsync(bildInfo);
|
|
||||||
|
|
||||||
return imgUrl;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -102,4 +102,26 @@ public class ImageGenerator
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Speichert den Inhalt des gegebenen Datenstroms als Bild ab.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dataStream">Der Datenstrom, der das Bild enthält.</param>
|
||||||
|
/// <param name="bildInfo">Die BildInfo des Bildes. Der Dateiname wird nach dem Speichern aktualisiert.</param>
|
||||||
|
private async Task SaveImageStreamAsync(Stream dataStream, BildInfoModel bildInfo)
|
||||||
|
{
|
||||||
|
using Image image = await Image.LoadAsync(dataStream);
|
||||||
|
|
||||||
|
// Speichert BildInfo in der Datenbank, aktualisiert Id der bildInfo
|
||||||
|
await _bildInfoData.InsertBildInfoAsync(bildInfo);
|
||||||
|
|
||||||
|
string imageUrl = $"generated_images/Image_{bildInfo.Id}.jpg";
|
||||||
|
|
||||||
|
string imageFilePath = $"./wwwroot/{imageUrl}";
|
||||||
|
await image.SaveAsJpegAsync(imageFilePath);
|
||||||
|
|
||||||
|
// Speichert den geänderten Dateinamen in der Datenbank
|
||||||
|
bildInfo.Dateiname = imageUrl;
|
||||||
|
await _bildInfoData.UpdateBildInfoDateinameAsync(bildInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,7 +305,7 @@
|
||||||
// Vier Bilder generieren
|
// Vier Bilder generieren
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
_imageUrls[i] = await ImageGenerator.GenerateImageAsync(_imagePrompt, "", width, height, wunschInfo);
|
_imageUrls[i] = (await ImageGenerator.GenerateImageAsync(wunschInfo, width, height))?.Dateiname;
|
||||||
|
|
||||||
// Kein Bild -> Fehler
|
// Kein Bild -> Fehler
|
||||||
if (_imageUrls[i] == null)
|
if (_imageUrls[i] == null)
|
||||||
|
@ -317,12 +317,14 @@
|
||||||
|
|
||||||
if (retry == true)
|
if (retry == true)
|
||||||
{
|
{
|
||||||
await ImageGenerator.GenerateImageAsync(_imagePrompt, "", width, height, wunschInfo);
|
_imageUrls[i] = (await ImageGenerator.GenerateImageAsync(wunschInfo, width, height))?.Dateiname;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
generatedImages++;
|
if (_imageUrls[i] != null)
|
||||||
|
generatedImages++;
|
||||||
|
|
||||||
|
// TODO: Fehler anzeigen
|
||||||
_imageStates[i] = ImageState.FadeIn;
|
_imageStates[i] = ImageState.FadeIn;
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
{
|
{
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"API": {
|
"API": {
|
||||||
"OpenAI": "<put OpenAI Key here>",
|
"OpenAI": "<put OpenAI Key here>",
|
||||||
"HF_Inference": "<put Hugging Face inference API Key here>"
|
"HF_Inference": "<put Hugging Face inference API Key here>"
|
||||||
},
|
},
|
||||||
|
"StableDiffusionModel": "Nacken/kkk-sdxl-18000",
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"Default": "<put Connection String here>"
|
"Default": "<put Connection String here>"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue