diff --git a/KIKunstKirstenKlöckner/Pages/AiArt.razor b/KIKunstKirstenKlöckner/Pages/AiArt.razor index 7cff2e6..1bbb3b5 100644 --- a/KIKunstKirstenKlöckner/Pages/AiArt.razor +++ b/KIKunstKirstenKlöckner/Pages/AiArt.razor @@ -11,18 +11,6 @@

Wunschbilder von KI nur für dich

-@* - - - -*@ - - -@* -*@ - -@**@ - Nenne uns deinen Wunsch: @@ -72,6 +60,31 @@ await DoStuff(false))>Generate + + + + + + + + + + + + + + + + + @code { @@ -85,6 +98,17 @@ public string BusyMessage { get; set; } = "Initial Message"; + private string?[] _imageUrls = new string?[4]; + private ImageState[] _imageStates = new ImageState[4]; + + enum ImageState + { + //Hide = 0, + FadeOut, + FadeIn, + //Show, + } + // Busy dialog from markup async Task ShowBusyDialog() { @@ -95,6 +119,14 @@ , new DialogOptions() { ShowTitle = false, Style = "min-height:auto;min-width:auto;width:auto", CloseDialogOnEsc = false }); } + async Task ShowImageDialog(string imageUrl) + { + var result = await DialogService.OpenAsync("", ds => + @
+ +
, new DialogOptions() { CloseDialogOnOverlayClick = true }); + } + // Busy dialog from string async Task BusyDialog(string message) { @@ -258,9 +290,85 @@ } } + /// + /// Geneiert das Bild für den aktuellen + /// + public async Task GenerateImageAsync(string prompt, bool isRetry = false) + { + var postData = new + { + inputs = prompt, + options = new + { + // Cache deaktivieren, damit Huggingface für den selben Prompt unterschiedliche Ergebnisse liefert + use_cache = false, + // Erst wenn wir bereits in einem retry sind warten wir implizit auf das Model. (ignoriert quasi 503-Fehler) + wait_for_model = isRetry + } + }; + + 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) + { + return await GenerateImageAsync(prompt, true); + } + + return null; + } + + try + { + var inferenceModelUrl = "https://api-inference.huggingface.co/models/Nacken/ki-kunst-kirsten-kloeckner-colab"; + + 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_fffffff}.jpg"; + + string mapPath = $"./wwwroot/{imgUrl}"; + await image.SaveAsJpegAsync(mapPath); + + return imgUrl; + } + else + { + Console.WriteLine($"Image conversion failed: {response}"); + + if (Debugger.IsAttached) + Debugger.Break(); + + return await FailedToDrawImage(); + } + } + catch (Exception exception) + { + Console.WriteLine($"Image request failed: {exception}"); + + if (Debugger.IsAttached) + Debugger.Break(); + + return await FailedToDrawImage(); + } + + return null; + } private async Task DoStuff(bool newPic) { + for (int i = 0; i < 4; i++) + _imageStates[i] = ImageState.FadeOut; + // Der Dialog blokiert so lange, wie der er offen ist, deshalb dürfen wir hier nicht warten, da wir sonst nie mit der Arbeit anfangen... //Task busyDialog = ShowBusyDialog(); _progressVisible = true; @@ -304,19 +412,14 @@ await UpdateBusyMessage("Kirstens Assistent hat eine Idee! Er wird sie nun malen..."); - Task makeImagesTask = GenerateImageAsync(); - - //CancellationTokenSource cancelFunnyMessages = new CancellationTokenSource(); - - //Task funnyMessagesTask = FunnyMessageSwitcher_ImageGen(cancelFunnyMessages.Token); - - // Wichtig, erst Bilder awaiten, dann die lustingen Sprüche, sonst warten wir ewig... - await makeImagesTask; - - //cancelFunnyMessages.Cancel(); - - //await funnyMessagesTask; - + // Vier Bilder generieren + for (int i = 0; i < 4; i++) + { + _imageUrls[i] = await GenerateImageAsync(_imagePrompt); + _imageStates[i] = ImageState.FadeIn; + await InvokeAsync(StateHasChanged); + } + _progressVisible = false; _buttonVisible = true; if (amountOfAddons > 0) @@ -333,3 +436,4 @@ } } + diff --git a/KIKunstKirstenKlöckner/Pages/FlippingImage.razor b/KIKunstKirstenKlöckner/Pages/FlippingImage.razor new file mode 100644 index 0000000..60c85c8 --- /dev/null +++ b/KIKunstKirstenKlöckner/Pages/FlippingImage.razor @@ -0,0 +1,162 @@ + + +
+
+
+
+
+ +
+
+
+
+ +
+
+
+ +@code { + [Parameter] + public bool Show { get; set; } + + [Parameter] + public bool HideImage { get; set; } + + [Parameter] + public string ImageUrl { get; set; } = "images/robot_painting.jpg"; + + public enum FlipDirection + { + Up, + Down, + Left, + Right + } + + private string _flipperClassName; + private string _backClassName; + private FlipDirection _flipTo; + + [Parameter] + public FlipDirection FlipTo + { + get => _flipTo; + set + { + _flipTo = value; + _flipperClassName = _flipTo switch + { + FlipDirection.Up => "flip-card_up", + FlipDirection.Down => "flip-card_down", + FlipDirection.Left => "flip-card_left", + FlipDirection.Right => "flip-card_right", + _ => throw new ArgumentOutOfRangeException()}; + _backClassName = _flipTo switch + { + FlipDirection.Up => "flip-card-back_up", + FlipDirection.Down => "flip-card-back_down", + FlipDirection.Left => "flip-card-back_left", + FlipDirection.Right => "flip-card-back_right", + _ => throw new ArgumentOutOfRangeException()}; + } + } + + [Parameter] + public double FlipDelay { get; set; } = 0.0; + + /// Gets or sets the click callback. + /// The click callback. + [Parameter] + public EventCallback Click { get; set; } +} diff --git a/KIKunstKirstenKlöckner/wwwroot/css/site.css b/KIKunstKirstenKlöckner/wwwroot/css/site.css index 96b0583..7404feb 100644 --- a/KIKunstKirstenKlöckner/wwwroot/css/site.css +++ b/KIKunstKirstenKlöckner/wwwroot/css/site.css @@ -63,6 +63,56 @@ a, .btn-link { color: white; } - .blazor-error-boundary::after { - content: "An error has occurred." +.blazor-error-boundary::after { + content: "An error has occurred." +} + +.fade-in-5 { + animation: fadeIn 5s; + animation-fill-mode: forwards; +} +.fade-out-5 { + animation: fadeOut 5s; + animation-fill-mode: forwards; +} + + +@keyframes fadeIn { + 0% { + opacity: 0; } + + 100% { + opacity: 1; + } +} + +@keyframes fadeOut { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + +.flip-image { + animation: flip 0.6s; + animation-fill-mode: forwards; + -webkit-backface-visibility: hidden; + transition: transform 0.6s; + transform-style: preserve-3d; + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); + backface-visibility: hidden; +} + +@keyframes flip { + 0% { + transform: rotateY(0deg); + } + + 100% { + transform: rotateY(180deg); + } +} diff --git a/KIKunstKirstenKlöckner/wwwroot/images/robot_painting.jpg b/KIKunstKirstenKlöckner/wwwroot/images/robot_painting.jpg new file mode 100644 index 0000000..74a347e Binary files /dev/null and b/KIKunstKirstenKlöckner/wwwroot/images/robot_painting.jpg differ