diff --git a/DataAccess/Data/BildInfoData.cs b/DataAccess/Data/BildInfoData.cs new file mode 100644 index 0000000..e2def08 --- /dev/null +++ b/DataAccess/Data/BildInfoData.cs @@ -0,0 +1,48 @@ +using DataAccess.DbAccess; +using DataAccess.Models; + +namespace DataAccess.Data; + +/// +/// Ermöglicht den Zugriff auf die BildInfo Datenbank. +/// +public class BildInfoData +{ + private readonly ISqlDataAccess _db; + + public BildInfoData(ISqlDataAccess db) + { + _db = db; + } + + /// + /// Fügt die gegebene BildInfo zur Datenbank hinzu und aktualisiert das -Feld mit dem entsprechenden Wert. + /// + /// Die BildInfo, die zur Datenbank hinzugefügt werden soll. + public async Task AddBildInfoAsync(BildInfoModel bildInfo) + { + var id = await _db.LoadData("dbo.spBildInfo_Insert", bildInfo); + bildInfo.Id = id.Single(); + } + + /// + /// Aktualisiert das Dateiname-Feld der übergebenen BildInfo in der Datenbank. + /// + /// Die BildInfo deren Dateiname aktualisiert werden soll. + public Task UpdateBildInfoDateinameAsync(BildInfoModel bildInfo) + { + return _db.SaveData("dbo.spBildInfo_UpdateFileName", + new { + Id = bildInfo.Id, + Dateiname = bildInfo.Dateiname, + }); + } + + /// + /// Gibt alle Bild Infos der Datenbank zurück. + /// + public Task> GetAllBildInfosAsync() + { + return _db.LoadData("dbo.spBildInfo_GetAll", new { }); + } +} diff --git a/DataAccess/Data/WunschInfoData.cs b/DataAccess/Data/WunschInfoData.cs new file mode 100644 index 0000000..26e0854 --- /dev/null +++ b/DataAccess/Data/WunschInfoData.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DataAccess.DbAccess; +using DataAccess.Models; + +namespace DataAccess.Data; + +public class WunschInfoData +{ + private readonly ISqlDataAccess _db; + + public WunschInfoData(ISqlDataAccess db) + { + _db = db; + } + + public async Task AddWunschInfoAsync(WunschInfoModel wunschInfo) + { + var id = await _db.LoadData("dbo.spWunschInfo_Insert", wunschInfo); + wunschInfo.Id = id.Single(); + } + + /// + /// Gibt die WunschInfo mit der gegebenen Id zurück. + /// + /// Die Id der zu ladenen WunschInfo + /// Die WunschInfo mit der gegebenen Id + public async Task GetWunschInfoAsync(int wunschId) + { + var wunschInfo = await _db.LoadData("dbo.spWunschInfo_Get", new { Id = wunschId }); + return wunschInfo.Single(); + } +} diff --git a/DataAccess/DataAccess.csproj b/DataAccess/DataAccess.csproj new file mode 100644 index 0000000..810ea4c --- /dev/null +++ b/DataAccess/DataAccess.csproj @@ -0,0 +1,15 @@ + + + + net7.0 + enable + enable + + + + + + + + + diff --git a/DataAccess/DbAccess/ISqlDataAccess.cs b/DataAccess/DbAccess/ISqlDataAccess.cs new file mode 100644 index 0000000..c1a2103 --- /dev/null +++ b/DataAccess/DbAccess/ISqlDataAccess.cs @@ -0,0 +1,26 @@ +namespace DataAccess.DbAccess; + +/// +/// Bietet lesenden und schreibenden Zugriff auf eine Datenbank. +/// +public interface ISqlDataAccess +{ + /// + /// Führt die angegebene Stored Procedure aus. Diese Prozedur nimmt Parameter des Typs engegen und gibt ein Enumerable des Typs zurück. + /// + /// Der Typ der Parameter + /// Der Typ der Rückgabewerte + /// Der Name der Prozedur + /// Die Parameter für die Prozedur. + /// Die optionale Id des zu verwendenen Connection Strings. + Task> LoadData(string storedProcedure, TParameter parameters, string connectionId = "Default"); + + /// + /// Führt die angegebene Stored Procedure aus. Diese Prozedur nimmt Parameter des Typs engegen und gibt nichts zurück. + /// + /// Der Typ der Parameter + /// Der Name der Prozedur + /// Die Parameter für die Prozedur. + /// Die optionale Id des zu verwendenen Connection Strings. + Task SaveData(string storedProcedure, TParameter parameters, string connectionId = "Default"); +} \ No newline at end of file diff --git a/DataAccess/DbAccess/SqlDataAccess.cs b/DataAccess/DbAccess/SqlDataAccess.cs new file mode 100644 index 0000000..1a331aa --- /dev/null +++ b/DataAccess/DbAccess/SqlDataAccess.cs @@ -0,0 +1,33 @@ +using Microsoft.Extensions.Configuration; +using System.Data.SqlClient; +using System.Data; +using Dapper; + +namespace DataAccess.DbAccess; + +/// +/// Bietet lesenden und schreibenden Zugriff auf eine Datenbank. +/// +public class SqlDataAccess : ISqlDataAccess +{ + private readonly IConfiguration _config; + + public SqlDataAccess(IConfiguration config) + { + _config = config; + } + + public async Task> LoadData(string storedProcedure, TParameter parameters, string connectionId = "Default") + { + using IDbConnection connection = new SqlConnection(_config.GetConnectionString(connectionId)); + + return await connection.QueryAsync(storedProcedure, parameters, commandType: CommandType.StoredProcedure); + } + + public async Task SaveData(string storedProcedure, TParameter parameters, string connectionId = "Default") + { + using IDbConnection connection = new SqlConnection(_config.GetConnectionString(connectionId)); + + await connection.ExecuteAsync(storedProcedure, parameters, commandType: CommandType.StoredProcedure); + } +} diff --git a/DataAccess/Models/BildInfoModel.cs b/DataAccess/Models/BildInfoModel.cs new file mode 100644 index 0000000..7bb6368 --- /dev/null +++ b/DataAccess/Models/BildInfoModel.cs @@ -0,0 +1,10 @@ +namespace DataAccess.Models; + +public class BildInfoModel +{ + public int Id { get; set; } + public DateTime Datum { get; set; } + public string Dateiname { get; set; } + public string ImageModel { get; set; } + public int WunschId { get; set; } +} diff --git a/DataAccess/Models/WunschInfoModel.cs b/DataAccess/Models/WunschInfoModel.cs new file mode 100644 index 0000000..85d191c --- /dev/null +++ b/DataAccess/Models/WunschInfoModel.cs @@ -0,0 +1,11 @@ +namespace DataAccess.Models; + +public class WunschInfoModel +{ + public int Id { get; set; } + public string BildPrompt { get; set; } + public string Wunsch { get; set; } + public string BildBeschreibung { get; set; } + public DateTime Datum { get; set; } + public string GPTModel { get; set; } +} diff --git a/KIKunstKirstenKlöckner.sln b/KIKunstKirstenKlöckner.sln index ff37735..8d4d872 100644 --- a/KIKunstKirstenKlöckner.sln +++ b/KIKunstKirstenKlöckner.sln @@ -5,6 +5,10 @@ VisualStudioVersion = 17.6.33829.357 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KIKunstKirstenKlöckner", "KIKunstKirstenKlöckner\KIKunstKirstenKlöckner.csproj", "{0085541E-50D4-42A5-9BFD-6CE402FB8B26}" EndProject +Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "KiKunstDatenbank", "KiKunstDatenbank\KiKunstDatenbank.sqlproj", "{A19CD19A-FE5B-4D4E-896B-DCC43B45F734}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataAccess", "DataAccess\DataAccess.csproj", "{0880FD07-236B-42C1-9CA3-2A6F695A623C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +19,16 @@ Global {0085541E-50D4-42A5-9BFD-6CE402FB8B26}.Debug|Any CPU.Build.0 = Debug|Any CPU {0085541E-50D4-42A5-9BFD-6CE402FB8B26}.Release|Any CPU.ActiveCfg = Release|Any CPU {0085541E-50D4-42A5-9BFD-6CE402FB8B26}.Release|Any CPU.Build.0 = Release|Any CPU + {A19CD19A-FE5B-4D4E-896B-DCC43B45F734}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A19CD19A-FE5B-4D4E-896B-DCC43B45F734}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A19CD19A-FE5B-4D4E-896B-DCC43B45F734}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {A19CD19A-FE5B-4D4E-896B-DCC43B45F734}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A19CD19A-FE5B-4D4E-896B-DCC43B45F734}.Release|Any CPU.Build.0 = Release|Any CPU + {A19CD19A-FE5B-4D4E-896B-DCC43B45F734}.Release|Any CPU.Deploy.0 = Release|Any CPU + {0880FD07-236B-42C1-9CA3-2A6F695A623C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0880FD07-236B-42C1-9CA3-2A6F695A623C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0880FD07-236B-42C1-9CA3-2A6F695A623C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0880FD07-236B-42C1-9CA3-2A6F695A623C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/KIKunstKirstenKlöckner/.config/dotnet-tools.json b/KIKunstKirstenKlöckner/.config/dotnet-tools.json new file mode 100644 index 0000000..2be6730 --- /dev/null +++ b/KIKunstKirstenKlöckner/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "7.0.9", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/KIKunstKirstenKlöckner/KIKunstKirstenKlöckner.csproj b/KIKunstKirstenKlöckner/KIKunstKirstenKlöckner.csproj index 03f043e..3c666a9 100644 --- a/KIKunstKirstenKlöckner/KIKunstKirstenKlöckner.csproj +++ b/KIKunstKirstenKlöckner/KIKunstKirstenKlöckner.csproj @@ -20,4 +20,8 @@ + + + + diff --git a/KIKunstKirstenKlöckner/Pages/AiArt.razor b/KIKunstKirstenKlöckner/Pages/AiArt.razor index caa394b..a863aa9 100644 --- a/KIKunstKirstenKlöckner/Pages/AiArt.razor +++ b/KIKunstKirstenKlöckner/Pages/AiArt.razor @@ -4,11 +4,16 @@ @using OpenAI_API.Chat @using OpenAI_API.Models @using System.Diagnostics +@using DataAccess.Data +@using DataAccess.Models @inject IConfiguration Config @inject TooltipService TooltipService @inject DialogService DialogService +@inject BildInfoData BildInfoData; +@inject WunschInfoData WunschInfoData; + AiArt
@@ -244,7 +249,7 @@ private string _inferenceApiKey = ""; private string _openAiApiKey = ""; - protected override Task OnInitializedAsync() + protected override async Task OnInitializedAsync() { _inferenceApiKey = Config.GetValue("API:HF_Inference"); _openAiApiKey = Config.GetValue("API:OpenAI"); @@ -258,74 +263,37 @@ _client.DefaultRequestHeaders.Clear(); _client.DefaultRequestHeaders.Add("Authorization", $"Bearer {_inferenceApiKey}"); - return base.OnInitializedAsync(); + + // BildInfoModel bildInfo = new() + // { + // BildBeschreibung = "Test", + // BildPrompt = "Tost", + // Dateiname = "Task", + // Datum = DateTime.Now, + // GPTModel = "Geht dich nichts an", + // ImageModel = "Jup", + // Wunsch = request + // }; + + // try + // { + + // //await BildInfoData.AddBildInfo(bildInfo); + + // } + // catch (Exception e) + // { + // Console.WriteLine(e); + // throw; + // } + + await base.OnInitializedAsync(); } /// /// Geneiert das Bild für den aktuellen /// - public async Task GenerateImageAsync() - { - var postData = new - { - inputs = _imagePrompt - }; - - JsonContent content = JsonContent.Create(postData); - - async Task FailedToDrawImage() - { - bool? retry = await DialogService.Confirm("Leider konnte das Bild nicht gemalt werden. Möchtest du es noch eimal versuchen?", "Ups, ein Fehler ist aufgetreten...", - new ConfirmOptions { OkButtonText = "Ja", CancelButtonText = "Nein" }); - - if (retry == true) - await GenerateImageAsync(); - } - - try - { - var inferenceModelUrl = "https://api-inference.huggingface.co/models/Nacken/kkkk-sdxl-5000"; - - var response = await _client.PostAsync(inferenceModelUrl, content); - - if (response?.IsSuccessStatusCode == true) - { - await using Stream imageStream = await response.Content.ReadAsStreamAsync(); - - using Image image = await Image.LoadAsync(imageStream); - - string imgUrl = $"generated_images/{DateTime.Now:dd_MM_yyyy_hh_mm_s}.jpg"; - - string mapPath = $"./wwwroot/{imgUrl}"; - await image.SaveAsJpegAsync(mapPath); - - _imageUrl = imgUrl; - } - else - { - Console.WriteLine($"Image conversion failed: {response}"); - - if (Debugger.IsAttached) - Debugger.Break(); - - await FailedToDrawImage(); - } - } - catch (Exception exception) - { - Console.WriteLine($"Image request failed: {exception}"); - - if (Debugger.IsAttached) - Debugger.Break(); - - await FailedToDrawImage(); - } - } - - /// - /// Geneiert das Bild für den aktuellen - /// - public async Task GenerateImageAsync(string prompt, bool isRetry = false) + public async Task GenerateImageAsync(string prompt, WunschInfoModel wunschInfo, bool isRetry = false) { var postData = new { @@ -354,7 +322,7 @@ if (retry == true) { - return await GenerateImageAsync(prompt, true); + return await GenerateImageAsync(prompt, wunschInfo, true); } return null; @@ -362,7 +330,9 @@ try { - var inferenceModelUrl = "https://api-inference.huggingface.co/models/Nacken/kkkk-sdxl-5000"; + const string modelName = "Nacken/kkkk-sdxl-5000"; + + var inferenceModelUrl = $"https://api-inference.huggingface.co/models/{modelName}"; var response = await _client.PostAsync(inferenceModelUrl, content); @@ -372,16 +342,25 @@ using Image image = await Image.LoadAsync(imageStream); - string imgUrl = $"generated_images/{DateTime.Now:dd_MM_yyyy_hh_mm_s_fffffff}.jpg"; + DateTime imageDate = DateTime.Now; + + BildInfoModel bildInfo = new() + { + Dateiname = "PlaceHolder", + Datum = imageDate, + ImageModel = modelName, + WunschId = wunschInfo.Id + }; + + await BildInfoData.AddBildInfoAsync(bildInfo); + + string imgUrl = $"generated_images/Image_{bildInfo.Id}.jpg"; string mapPath = $"./wwwroot/{imgUrl}"; await image.SaveAsJpegAsync(mapPath); - // Hier speichern wir die Daten in die 'info_texts.txt'-Datei - string infoTextsPath = Path.Combine(_environment.WebRootPath, "generated_images", "info_texts.txt"); - string desc = _imageDescription.Replace("\r\n", "").Replace("\n", "").Replace("\r", ""); - string newLine = $"{imgUrl}: {request}, {desc}\n"; - await File.AppendAllTextAsync(infoTextsPath, newLine); + bildInfo.Dateiname = imgUrl; + await BildInfoData.UpdateBildInfoDateinameAsync(bildInfo); return imgUrl; } @@ -463,11 +442,23 @@ _imageDescription = await converse.GetResponseFromChatbotAsync(); await UpdateBusyMessage("Kirstens Assistent hat eine Idee! Er wird sie nun malen..."); + + WunschInfoModel wunschInfo = new() + { + BildBeschreibung = _imageDescription, + BildPrompt = _imagePrompt, + Datum = DateTime.Now, + GPTModel = converse.Model, + Wunsch = request + }; + + // TODO: Try + await WunschInfoData.AddWunschInfoAsync(wunschInfo); // Vier Bilder generieren for (int i = 0; i < 4; i++) { - _imageUrls[i] = await GenerateImageAsync(_imagePrompt); + _imageUrls[i] = await GenerateImageAsync(_imagePrompt, wunschInfo); _imageStates[i] = ImageState.FadeIn; await InvokeAsync(StateHasChanged); } diff --git a/KIKunstKirstenKlöckner/Pages/Gallery.razor b/KIKunstKirstenKlöckner/Pages/Gallery.razor index 94554da..9196388 100644 --- a/KIKunstKirstenKlöckner/Pages/Gallery.razor +++ b/KIKunstKirstenKlöckner/Pages/Gallery.razor @@ -1,5 +1,11 @@ @page "/gallery" +@using DataAccess.Data +@using DataAccess.Models + +@inject BildInfoData BildInfoData; +@inject WunschInfoData WunschInfoData; +
- -