@page "/aiart"
@using OpenAI_API
@using OpenAI_API.Chat
@using OpenAI_API.Models
@using DataAccess.Data
@using DataAccess.Models
@using KIKunstKirstenKlöckner.Data
@using System.Diagnostics
@inject IJSRuntime JSRuntime
@inject IConfiguration Config
@inject TooltipService TooltipService
@inject NotificationService NotificationService
@inject DialogService DialogService
@inject WunschInfoData WunschInfoData;
@inject ImageGenerator ImageGenerator;
AiArt
Wunschbilder von KI nur für dich
Nenne uns deinen Wunsch:
@* Zusätzliche Optionen *@
Temperature:
@_temperature
Resolution:
x
@* *@
Generate
@if (_imageSectionVisible)
{
Die Idee, die gemalt wird:
@_imageIdea
Verändere hier dein Bild durch Worte:
await UpdateImagesAsync())>Generate
@_imagePromts[0]
Model: @_bildInfos[0]?.ImageModel
@_imagePromts[1]
Model: @_bildInfos[1]?.ImageModel
@_imagePromts[2]
Model: @_bildInfos[2]?.ImageModel
@_imagePromts[3]
Model: @_bildInfos[3]?.ImageModel
}
@code {
///
/// Wenn wird GPT4 verwendet um die Idee zu interpretieren.
///
private bool _useGpt4;
private int maxAddons = 2;
private int amountOfAddons = 0; // wird später geändert
private bool _progressVisible = false;
private bool _buttonVisible = true;
private bool _addonsVisible = false;
private bool _bothVisible = false;
private bool _imageSectionVisible = false;
public string BusyMessage { get; set; } = "Initial Message";
private string?[] _imageUrls = new string?[4];
private string?[] _imagePromts = new string?[4];
private BildInfoModel?[] _bildInfos = new BildInfoModel?[4];
private ImageState[] _imageStates = new ImageState[4];
enum ImageState
{
FadeOut,
FadeIn
}
private async Task OnGenerateButtonClickAsync()
{
_imageSectionVisible = true;
StateHasChanged();
await Task.Delay(100);
await JSRuntime.InvokeVoidAsync("scrollToElement", "imageSection");
await GenerateImagesAsync();
}
async Task ShowImageDialog(string imageUrl)
{
var result = await DialogService.OpenAsync("", ds =>
@
, new DialogOptions() { CloseDialogOnOverlayClick = true });
}
void ShowTooltip(ElementReference elementReference, string text, TooltipOptions? options = null) => TooltipService.Open(elementReference, text, options);
void ShowTemperatureTooltip(ElementReference elementReference) => TooltipService.Open(elementReference, ds =>
@
Gibt an, wie kreativ ChatGPT sein soll.
,
new() { Position = TooltipPosition.Bottom, Duration = null});
private string _imageIdea = "";
private float _temperature = 0.9f;
private int? _imageWidth = null;
private int? _imageHeight = null;
private string _userIdea = "";
private string _updateRequest = "";
private OpenAIAPI _openAiApi;
private Conversation? _conversation;
private string _basePrompt;
private string _ideaPrompt;
private string _imageUrl;
private WunschInfoModel? _wunschInfo;
async Task UpdateBusyMessage(string newMessage)
{
BusyMessage = newMessage;
await InvokeAsync(StateHasChanged);
}
private string _openAiApiKey = "";
class ModelInfo
{
public string Name { get; set; }
public string StableDiffusionModel { get; set; }
public string PromptFormat { get; set; }
}
private List _imageModels;
private ModelInfo? _selectedImageModel = null;
protected override async Task OnInitializedAsync()
{
_openAiApiKey = Config.GetValue("API:OpenAI");
_openAiApi = new OpenAIAPI(_openAiApiKey);
_imageModels = Config.GetSection("ImageModels").Get>();
//_selectedImageModel = _imageModels[0];
await base.OnInitializedAsync();
}
///
/// Setzt alle Felder zurück, die zu einem bestimmten Wunsch gehören.
///
private void ClearOldGeneration()
{
// Bilder verbergen
for (int i = 0; i < 4; i++)
{
_imageStates[i] = ImageState.FadeOut;
_imagePromts[i] = null;
}
_imageIdea = "";
}
///
/// Gibt ChatGPT den Wunsch und erlangt die Bild Idee.
///
///
private async Task RequestImageIdeaAsync()
{
string ideaBasePrompt = await File.ReadAllTextAsync($"{Directory.GetCurrentDirectory()}{@"/wwwroot/idea_prompt.txt"}");
ChatRequest chatRequest = new ChatRequest
{
Temperature = _temperature,
Model = _useGpt4 ? Model.GPT4 : Model.ChatGPTTurbo
};
_conversation = _openAiApi.Chat.CreateConversation(chatRequest);
// Wunsch an GPT senden und Bild Idee anfordern
_conversation.AppendUserInput(ideaBasePrompt + " " + _userIdea);
_imageIdea = await _conversation.GetResponseFromChatbotAsync();
}
///
/// Fordert für mehrere Bilder Bild-Prompts an und generiert die dazugehörigen Bilder.
///
private async Task RequestImagesAsync(WunschInfoModel wunschInfo, string requestImagePrompt)
{
// Nachricht mit Bildpromt anfrage senden
_conversation!.AppendUserInput(requestImagePrompt);
// Task-Liste, damit wir parallel Prompts anfordern und Bilder generieren können.
Task[] imagePromts = new Task[4];
for (int i = 0; i < 4; i++)
{
imagePromts[i] = RequestImagePromptAndGenerateImageAsync(i, wunschInfo);
}
await Task.WhenAll(imagePromts);
}
///
/// Fordert einen Bild Prompt an und generiert ein Bild für diesen.
///
/// Der Index des Bildes (für UI zeug)
/// Der Wunsch für den ein Bild erzeugt wird.
private async Task RequestImagePromptAndGenerateImageAsync(int index, WunschInfoModel wunschInfo)
{
ModelInfo imageModel = _selectedImageModel ?? _imageModels[Random.Shared.Next(_imageModels.Count)];
// Bild Prompt von ChatGPT anfordern
string imagePrompt = await _conversation!.GetResponseFromChatbotAsync();
// Keywords anhängen um Kirstens Stil zu aktivieren.
// TODO: Gucken, ob wir dem Watercolor bums brauchen
imagePrompt = string.Format(imageModel.PromptFormat, imagePrompt);//"kkkk " + imagePrompt;// + " kkkk Watercolor + ink on paper, Pen drawing, wet-on-wet technique, dry-on-dry technique, dabbing technique. ";
// Debug only: Promt anzeigen
_imagePromts[index] = imagePrompt;
await InvokeAsync(StateHasChanged);
BildInfoModel? bildInfo = await GenerateImageAsync(imagePrompt, imageModel.StableDiffusionModel, wunschInfo);
// TODO: Fehler im UI anzeigen (zur Zeit bleibt einfach Ladebalken)
_imageUrls[index] = bildInfo?.Dateiname;
_bildInfos[index] = bildInfo;
_imageStates[index] = ImageState.FadeIn;
await InvokeAsync(StateHasChanged);
}
///
/// Erzeugt ein Bild für den gegebenen Prompt und Wunsch.
///
/// Der Bild Prompt
/// Der Wunsch.
/// Die URL, falls das Bild generiert wurde; oder null, wenn kein Bild generiert werden konnte.
private async Task GenerateImageAsync(string imagePrompt, string modelName, WunschInfoModel wunschInfo)
{
try
{
BildInfoModel? bildInfo = await ImageGenerator.GenerateImageAsync(imagePrompt, modelName, wunschInfo, _imageWidth, _imageHeight);
// Kein Bild -> Fehler
if (bildInfo == null)
{
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)
{
bildInfo = await ImageGenerator.GenerateImageAsync(imagePrompt, modelName, wunschInfo, _imageWidth, _imageHeight);
}
}
return bildInfo;
}
catch (Exception e)
{
NotificationService.Notify(new NotificationMessage()
{
Summary = "Es ist ein Fehler beim Erzeugen der Bilder aufgetreten, bitte versuche es erneut."
});
}
return null;
}
///
/// Generiert Bilder oder aktualisiert sie mit dem neuen Prompt.
///
private async Task GenerateImagesAsync()
{
_progressVisible = true;
_buttonVisible = false;
ClearOldGeneration();
amountOfAddons = maxAddons;
_addonsVisible = false;
_bothVisible = _buttonVisible && _addonsVisible;
await UpdateBusyMessage("Kirstens Assistent zerbricht sich über deine Idee den Kopf...");
await RequestImageIdeaAsync();
await UpdateBusyMessage("Kirstens Assistent hat eine Idee! Er wird sie nun malen...");
_wunschInfo = new()
{
BildBeschreibung = _imageIdea,
BildPrompt = "Individuelle Bild Prompts",
Datum = DateTime.Now,
GPTModel = _conversation!.Model,
Wunsch = _userIdea,
VorherigerWunsch = null
};
try
{
await WunschInfoData.AddWunschInfoAsync(_wunschInfo);
}
catch (Exception e)
{
NotificationService.Notify(new NotificationMessage()
{
Summary = "Es ist ein Fehler aufgetreten, bitte versuche es erneut."
});
return;
}
string requestImagePrompt = await File.ReadAllTextAsync($"{Directory.GetCurrentDirectory()}{@"/wwwroot/image_prompt.txt"}");
await RequestImagesAsync(_wunschInfo, requestImagePrompt);
_progressVisible = false;
_buttonVisible = true;
if (amountOfAddons > 0)
{
_addonsVisible = true;
_bothVisible = _buttonVisible && _addonsVisible;
await InvokeAsync(StateHasChanged);
}
else
{
_addonsVisible = false;
_bothVisible = false;
}
}
private async Task UpdateImagesAsync()
{
Debug.Assert(_conversation != null);
string updatePrompt = $"Gebe nun einen neuen Prompt unter berücksichtigung vorheriger Anweisungen und passe ihn folgender Maßen an: {_updateRequest}";
_wunschInfo = new()
{
BildBeschreibung = _updateRequest,
BildPrompt = "Individuelle Bild Prompts",
Datum = DateTime.Now,
GPTModel = _conversation.Model,
Wunsch = _userIdea,
VorherigerWunsch = _wunschInfo!.Id
};
try
{
await WunschInfoData.AddWunschInfoAsync(_wunschInfo);
}
catch (Exception e)
{
NotificationService.Notify(new NotificationMessage()
{
Summary = "Es ist ein Fehler aufgetreten, bitte versuche es erneut."
});
return;
}
await RequestImagesAsync(_wunschInfo, updatePrompt);
}
}