Compare commits
2 Commits
5191576cdc
...
8295be40f0
Author | SHA1 | Date |
---|---|---|
Simon Lübeß | 8295be40f0 | |
Simon Lübeß | 27aa1cead7 |
|
@ -13,18 +13,6 @@
|
||||||
|
|
||||||
<h1>Wunschbilder von KI nur für dich</h1>
|
<h1>Wunschbilder von KI nur für dich</h1>
|
||||||
|
|
||||||
@*<EditForm Model="@exampleModel" OnSubmit="@DoStuff">
|
|
||||||
<InputText @bind-Value="exampleModel.Name" />
|
|
||||||
|
|
||||||
<button type="submit">Submit</button>
|
|
||||||
</EditForm>*@
|
|
||||||
|
|
||||||
<!-- Dies ist das Textfeld -->
|
|
||||||
@*<input type="text" @bind="request" placeholder="Text eingeben..." />
|
|
||||||
*@
|
|
||||||
<!-- Dies ist der Button -->
|
|
||||||
@*<button @onclick="DoStuff">Klick mich</button>*@
|
|
||||||
|
|
||||||
<RadzenStack Orientation="Orientation.Vertical" AlignItems="AlignItems.Center">
|
<RadzenStack Orientation="Orientation.Vertical" AlignItems="AlignItems.Center">
|
||||||
<RadzenButton Text="Zur Gallery" Click="@NavigateToGallery" /> <RadzenText TextStyle="TextStyle.H2">Nenne uns deinen Wunsch:</RadzenText>
|
<RadzenButton Text="Zur Gallery" Click="@NavigateToGallery" /> <RadzenText TextStyle="TextStyle.H2">Nenne uns deinen Wunsch:</RadzenText>
|
||||||
<RadzenTextBox @bind-Value=@request Placeholder="Dein Wunsch"/>
|
<RadzenTextBox @bind-Value=@request Placeholder="Dein Wunsch"/>
|
||||||
|
@ -81,6 +69,31 @@
|
||||||
<RadzenTextBox Visible=@_addonsVisible @bind-Value=@addons Placeholder="z.B. Mehr Farben" />
|
<RadzenTextBox Visible=@_addonsVisible @bind-Value=@addons Placeholder="z.B. Mehr Farben" />
|
||||||
<RadzenButton Visible=@_bothVisible Click=@(async ()=> await DoStuff(false))>Generate</RadzenButton>
|
<RadzenButton Visible=@_bothVisible Click=@(async ()=> await DoStuff(false))>Generate</RadzenButton>
|
||||||
|
|
||||||
|
<RadzenCard>
|
||||||
|
<RadzenRow Style="width:24.5em" Gap="0.5rem" RowGap="0.5rem">
|
||||||
|
<RadzenColumn Size="6">
|
||||||
|
<FlippingImage ImageUrl="@_imageUrls[0]" HideImage="false"
|
||||||
|
Show="@(_imageStates[0] == ImageState.FadeIn)" FlipTo="FlippingImage.FlipDirection.Up"
|
||||||
|
Click="() => ShowImageDialog(_imageUrls[0])" />
|
||||||
|
</RadzenColumn>
|
||||||
|
<RadzenColumn Size="6">
|
||||||
|
<FlippingImage ImageUrl="@_imageUrls[1]" HideImage="false"
|
||||||
|
Show="@(_imageStates[1] == ImageState.FadeIn)" FlipTo="FlippingImage.FlipDirection.Right" FlipDelay="200"
|
||||||
|
Click="() => ShowImageDialog(_imageUrls[1])" />
|
||||||
|
</RadzenColumn>
|
||||||
|
<RadzenColumn Size="6">
|
||||||
|
<FlippingImage ImageUrl="@_imageUrls[2]" HideImage="false"
|
||||||
|
Show="@(_imageStates[2] == ImageState.FadeIn)" FlipTo="FlippingImage.FlipDirection.Left" FlipDelay="600"
|
||||||
|
Click="() => ShowImageDialog(_imageUrls[2])" />
|
||||||
|
</RadzenColumn>
|
||||||
|
<RadzenColumn Size="6">
|
||||||
|
<FlippingImage ImageUrl="@_imageUrls[3]" HideImage="false"
|
||||||
|
Show="@(_imageStates[3] == ImageState.FadeIn)" FlipTo="FlippingImage.FlipDirection.Down" FlipDelay="400"
|
||||||
|
Click="() => ShowImageDialog(_imageUrls[3])" />
|
||||||
|
</RadzenColumn>
|
||||||
|
</RadzenRow>
|
||||||
|
</RadzenCard>
|
||||||
|
|
||||||
</RadzenStack>
|
</RadzenStack>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
@ -94,6 +107,17 @@
|
||||||
|
|
||||||
public string BusyMessage { get; set; } = "Initial Message";
|
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
|
// Busy dialog from markup
|
||||||
async Task ShowBusyDialog()
|
async Task ShowBusyDialog()
|
||||||
{
|
{
|
||||||
|
@ -104,6 +128,14 @@
|
||||||
</RadzenStack>, new DialogOptions() { ShowTitle = false, Style = "min-height:auto;min-width:auto;width:auto", CloseDialogOnEsc = false });
|
</RadzenStack>, 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 =>
|
||||||
|
@<div class="d-flex justify-content-center align-items-center" style="height:100%;">
|
||||||
|
<RadzenImage Path="@imageUrl"/>
|
||||||
|
</div>, new DialogOptions() { CloseDialogOnOverlayClick = true });
|
||||||
|
}
|
||||||
|
|
||||||
// Busy dialog from string
|
// Busy dialog from string
|
||||||
async Task BusyDialog(string message)
|
async Task BusyDialog(string message)
|
||||||
{
|
{
|
||||||
|
@ -268,9 +300,85 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Geneiert das Bild für den aktuellen <see cref="_imagePrompt"/>
|
||||||
|
/// </summary>
|
||||||
|
public async Task<string?> 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<string?> 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)
|
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...
|
// 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();
|
//Task busyDialog = ShowBusyDialog();
|
||||||
_progressVisible = true;
|
_progressVisible = true;
|
||||||
|
@ -315,18 +423,13 @@
|
||||||
|
|
||||||
await UpdateBusyMessage("Kirstens Assistent hat eine Idee! Er wird sie nun malen...");
|
await UpdateBusyMessage("Kirstens Assistent hat eine Idee! Er wird sie nun malen...");
|
||||||
|
|
||||||
Task makeImagesTask = GenerateImageAsync();
|
// Vier Bilder generieren
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
//CancellationTokenSource cancelFunnyMessages = new CancellationTokenSource();
|
{
|
||||||
|
_imageUrls[i] = await GenerateImageAsync(_imagePrompt);
|
||||||
//Task funnyMessagesTask = FunnyMessageSwitcher_ImageGen(cancelFunnyMessages.Token);
|
_imageStates[i] = ImageState.FadeIn;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
// Wichtig, erst Bilder awaiten, dann die lustingen Sprüche, sonst warten wir ewig...
|
}
|
||||||
await makeImagesTask;
|
|
||||||
|
|
||||||
//cancelFunnyMessages.Cancel();
|
|
||||||
|
|
||||||
//await funnyMessagesTask;
|
|
||||||
|
|
||||||
_progressVisible = false;
|
_progressVisible = false;
|
||||||
_buttonVisible = true;
|
_buttonVisible = true;
|
||||||
|
@ -352,3 +455,4 @@
|
||||||
private NavigationManager NavigationManager { get; set; }
|
private NavigationManager NavigationManager { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
<style>
|
||||||
|
.flip-card {
|
||||||
|
background-color: transparent;
|
||||||
|
width: 12em;
|
||||||
|
height: 12em;
|
||||||
|
perspective: 30em;
|
||||||
|
transition: transform 0.2s;
|
||||||
|
z-index: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flip-card:hover {
|
||||||
|
transform: scale(1.1, 1.1);
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flip-card-inner {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
text-align: center;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flip-card_up .flip-card-inner {
|
||||||
|
transition: transform 0.6s var(--delay);
|
||||||
|
transform: rotateX(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flip-card_down .flip-card-inner {
|
||||||
|
transition: transform 0.6s var(--delay);
|
||||||
|
transform: rotateX(-180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flip-card_left .flip-card-inner {
|
||||||
|
transition: transform 0.6s var(--delay);
|
||||||
|
transform: rotateY(-180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flip-card_right .flip-card-inner {
|
||||||
|
transition: transform 0.6s var(--delay);
|
||||||
|
transform: rotateY(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-out-flipped-5 {
|
||||||
|
animation: fadeOut 5s;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
transform: rotateY(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flip-card-front, .flip-card-back_up, .flip-card-back_down, .flip-card-back_left, .flip-card-back_right {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
/* Rückseite beider Karten-Seiten verstecken wird nicht angezeigt */
|
||||||
|
-webkit-backface-visibility: hidden;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
/* Rückseite der Karte ist 180 Grad gedreht */
|
||||||
|
.flip-card-front {
|
||||||
|
/*box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.flip-card-back_up {
|
||||||
|
transform: rotateX(-180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flip-card-back_down {
|
||||||
|
transform: rotateX(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flip-card-back_left {
|
||||||
|
transform: rotateY(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flip-card-back_right {
|
||||||
|
transform: rotateY(-180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flip-card-content {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="flip-card @(Show ? "" : _flipperClassName)">
|
||||||
|
<div class="flip-card-inner" style="--delay: @(FlipDelay)ms;">
|
||||||
|
<div class="@(Show ? "fade-out-5 flip-card-front" : _backClassName)" style="@(HideImage ? "opacity: 0;": "opacity: 1;")">
|
||||||
|
<div class="d-flex justify-content-center align-items-center flip-card-content">
|
||||||
|
<div class="d-flex justify-content-center align-items-center">
|
||||||
|
<RadzenProgressBarCircular ProgressBarStyle="ProgressBarStyle.Primary" ShowValue="false" Mode="ProgressBarMode.Indeterminate"
|
||||||
|
Style="width:12em;height:12em; " />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flip-card-front" style="@(HideImage ? "opacity: 0;": "opacity: 1;")">
|
||||||
|
<RadzenImage Path="@ImageUrl" Style="width:12em;height:12em;" Click="@Click" class="@(Show ? "fade-in-5" : "")" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@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;
|
||||||
|
|
||||||
|
/// <summary>Gets or sets the click callback.</summary>
|
||||||
|
/// <value>The click callback.</value>
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback<MouseEventArgs> Click { get; set; }
|
||||||
|
}
|
|
@ -63,6 +63,56 @@ a, .btn-link {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blazor-error-boundary::after {
|
.blazor-error-boundary::after {
|
||||||
content: "An error has occurred."
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
Loading…
Reference in New Issue