Spaces:
Runtime error
Runtime error
{% extends "base.html" %} | |
{% block title %}Flux Image Generator - Home{% endblock %} | |
{% block content %} | |
<!-- <h1>Flux Image Generator</h1> --> | |
<form id="generateForm" class="needs-validation custom-bg p-3 rounded" novalidate> | |
<!-- Prompt-Eingabe --> | |
<div class="mb-3"> | |
<label for="prompt" class="form-label">Prompt:</label> | |
<textarea class="form-control" id="prompt" name="prompt" rows="4" required></textarea> | |
<div class="invalid-feedback">Bitte geben Sie einen Prompt ein.</div> | |
</div> | |
<!-- Fortschrittsanzeige --> | |
<div class="progress mb-3" id="progressContainer" style="display: none;"> | |
<div id="progressBar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div> | |
</div> | |
<!-- Fortschrittsnachricht --> | |
<div id="progressMessage" class="mb-3 blink-text" style="display: none;"> | |
<p></h4>Generiere Bilder, bitte warten...</h4></p> | |
</div> | |
<!-- Album-Auswahl --> | |
<div class="mb-3"> | |
<label for="album_id" class="form-label">Album:</label> | |
<input class="form-control" id="album_id" name="album_id" list="albums" placeholder="Wählen oder neues Album eingeben"> | |
<datalist id="albums"> | |
{% for album in albums %} | |
<option value="{{ album[1] }}">{{ album[0] }}</option> | |
{% endfor %} | |
</datalist> | |
</div> | |
<!-- Kategorie-Auswahl --> | |
<div class="mb-3"> | |
<label for="category_id" class="form-label">Kategorie:</label> | |
<input class="form-control" id="category_id" name="category_id" list="categories" placeholder="Wählen oder neue Kategorie eingeben"> | |
<datalist id="categories"> | |
{% for category in categories %} | |
<option value="{{ category[1] }}">{{ category[0] }}</option> | |
{% endfor %} | |
</datalist> | |
</div> | |
<div class="btn-group d-flex flex-wrap"> | |
<button type="button" class="btn btn-primary flex-fill mb-3" onclick="startGeneration()">ERSTELLEN</button> | |
<button type="button" class="btn btn-secondary flex-fill mb-3" onclick="optimizeOnly()">OPTIMIEREN</button> | |
<button type="button" class="btn btn-secondary flex-fill mb-3" onclick="copyPrompt()">ZURÜCKSETZEN</button> | |
</div> | |
<!-- | |
Buttons zur Generierung und Optimierung | |
<button type="button" class="btn btn-primary mb-3" onclick="startGeneration()">Bild Generieren</button> | |
<button type="button" class="btn btn-secondary mb-3" onclick="optimizeOnly()">Nur Optimieren</button> | |
<button type="button" class="btn btn-secondary mb-3" onclick="copyPrompt()">Prompt Kopieren</button> | |
--> | |
<!-- Erweiterte Einstellungen --> | |
<div class="accordion" id="advancedSettingsAccordion"> | |
<div class="accordion-item custom-bg"> | |
<h2 class="accordion-header" id="headingOne"> | |
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne"> | |
Erweiterte Einstellungen | |
</button> | |
</h2> | |
<div id="collapseOne" class="accordion-collapse collapse" aria-labelledby="headingOne" data-bs-parent="#advancedSettingsAccordion"> | |
<div class="accordion-body"> | |
<div class="row g-3"> | |
<div class="col-12 col-md-6"> | |
<label for="num_outputs" class="form-label">Anzahl der Ausgaben:</label> | |
<select class="form-select" id="num_outputs" name="num_outputs"> | |
<option value="1">1</option> | |
<option value="2">2</option> | |
<option value="3">3</option> | |
<option value="4">4</option> | |
</select> | |
</div> | |
<div class="col-12 col-md-6"> | |
<label for="aspect_ratio" class="form-label">Seitenverhältnis:</label> | |
<select class="form-select" id="aspect_ratio" name="aspect_ratio"> | |
<option value="1:1">1:1</option> | |
<option value="16:9">16:9</option> | |
<option value="21:9">21:9</option> | |
<option value="3:2">3:2</option> | |
<option value="2:3">2:3</option> | |
<option value="4:5">4:5</option> | |
<option value="5:4">5:4</option> | |
<option value="3:4">3:4</option> | |
<option value="4:3">4:3</option> | |
<option value="9:16">9:16</option> | |
<option value="9:21">9:21</option> | |
</select> | |
</div> | |
<div class="col-12 col-md-6"> | |
<label for="output_format" class="form-label">Ausgabeformat:</label> | |
<select class="form-select" id="output_format" name="output_format"> | |
<option value="png">PNG</option> | |
<option value="jpg">JPG</option> | |
<option value="webp">WEBP</option> | |
</select> | |
</div> | |
<div class="col-12 col-md-6"> | |
<label for="guidance_scale" class="form-label">Guidance Scale:</label> | |
<input type="number" step="0.1" class="form-control" id="guidance_scale" name="guidance_scale" value="3.5"> | |
</div> | |
<div class="col-12 col-md-6"> | |
<label for="output_quality" class="form-label">Ausgabequalität:</label> | |
<input type="number" class="form-control" id="output_quality" name="output_quality" value="80"> | |
</div> | |
<div class="col-12 col-md-6"> | |
<label for="prompt_strength" class="form-label">Prompt Strength:</label> | |
<input type="number" step="0.1" class="form-control" id="prompt_strength" name="prompt_strength" value="0.8"> | |
</div> | |
<div class="col-12 col-md-6"> | |
<label for="num_inference_steps" class="form-label">Anzahl der Inference Steps:</label> | |
<input type="number" class="form-control" id="num_inference_steps" name="num_inference_steps" value="28"> | |
</div> | |
<div class="col-12 col-md-6"> | |
<label for="lora_scale" class="form-label">LoRA Scale:</label> | |
<input type="number" step="0.1" class="form-control" id="lora_scale" name="lora_scale" value="0.8"> | |
</div> | |
<!-- <div class="col-12 col-md-6 d-flex align-items-center"> | |
<div class="col-12 col-md-6"> | |
<input class="form-check-input" type="checkbox" id="hf_lora_toggle" name="hf_lora_toggle" checked> | |
<label class="form-check-label" for="hf_lora_toggle">HF LoRA verwenden</label> | |
</div> --> | |
<div class="col-12 col-md-6"> | |
<label class="form-check-label" for="hf_lora_toggle">HF LoRA verwenden:</label> | |
<input class="form-control" type="text" id="hf_lora_toggle" name="hf_lora_toggle" value="Scalino84/my-flux-face"> | |
</div> | |
<div class="col-12 col-md-6"> | |
<label class="form-check-label" for="agent">Mistral Agent verwenden:</label> | |
<input class="form-check-input" type="checkbox" id="agent" name="agent" checked> | |
</div> | |
<!-- </div> --> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Batch-Optimierung --> | |
<div class="accordion mt-3" id="batchOptimizationAccordion"> | |
<div class="accordion-item custom-bg"> | |
<h2 class="accordion-header" id="headingTwo"> | |
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"> | |
Batch-Optimierung | |
</button> | |
</h2> | |
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#batchOptimizationAccordion"> | |
<div class="accordion-body"> | |
<textarea id="batchPrompts" class="form-control" rows="10" placeholder="Mehrere Prompts eingeben, einer pro Zeile"></textarea> | |
<button type="button" class="btn btn-primary mt-2" onclick="batchOptimize()">Batch Optimieren</button> | |
</div> | |
</div> | |
<!-- Bildausgabebereich --> | |
<div id="output" class="mt-4 p-2 border rounded bg-light"> | |
<!--<h5>Generierte Bilder:</h5>--> | |
<!-- Bilder werden hier dynamisch hinzugefügt --> | |
</div> | |
</div> | |
</div> | |
</form> | |
<!-- Ausgabebereich --> | |
<div id="output" class="mt-3"></div> | |
{% endblock %} | |
{% block scripts %} | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.js"></script> | |
<script> | |
// Initialisierung des Croppers | |
let cropper; | |
function startCropper(imageElement) { | |
if (cropper) { | |
cropper.destroy(); | |
} | |
cropper = new Cropper(imageElement, { | |
aspectRatio: 1, | |
viewMode: 1, | |
autoCropArea: 1, | |
responsive: true, | |
}); | |
} | |
// Funktion zur Bildgenerierung | |
function startGeneration() { | |
const form = document.getElementById('generateForm'); | |
if (!form.checkValidity()) { | |
form.classList.add('was-validated'); | |
return; | |
} | |
// Fortschrittsanzeige einblenden | |
const progressContainer = document.getElementById('progressContainer'); | |
progressContainer.style.display = 'block'; | |
const progressBarInner = document.getElementById('progressBar'); | |
progressBarInner.style.width = '0%'; | |
progressBarInner.setAttribute('aria-valuenow', 0); | |
const progressMessage = document.getElementById('progressMessage'); | |
progressMessage.style.display = 'block'; | |
const outputDiv = document.getElementById('output'); | |
outputDiv.innerHTML = ''; | |
const formData = new FormData(form); | |
// HF LoRA-Einstellung hinzufügen | |
const hfLoraInput = document.getElementById('hf_lora_toggle'); | |
const hfLoraValue = hfLoraInput.value.trim(); | |
if (hfLoraValue) { | |
formData.append('hf_lora', hfLoraValue); | |
} else { | |
formData.delete('hf_lora'); | |
} | |
// Formulardaten in ein Objekt umwandeln | |
const formObject = Object.fromEntries(formData.entries()); | |
// WebSocket-Verbindung öffnen | |
const socket = new WebSocket('wss://scalino84-fluxinator.hf.space/ws'); | |
socket.onopen = function (event) { | |
socket.send(JSON.stringify(formObject)); | |
}; | |
socket.onmessage = function (event) { | |
const data = JSON.parse(event.data); | |
if (data.optimized_prompt) { | |
document.getElementById('prompt').value = data.optimized_prompt; | |
} | |
if (data.progress !== undefined) { | |
progressBarInner.style.width = `${data.progress}%`; | |
progressBarInner.setAttribute('aria-valuenow', data.progress); | |
} | |
if (data.message) { | |
const message = document.createElement('div'); | |
message.textContent = data.message; | |
outputDiv.appendChild(message); | |
} | |
if (data.generated_files) { | |
data.generated_files.forEach(file => { | |
const img = document.createElement('img'); | |
img.src = file; | |
img.style.maxWidth = '100%'; | |
outputDiv.appendChild(img); | |
const promptText = document.createElement('p'); | |
promptText.textContent = `Prompt: ${formData.get('prompt')}`; | |
outputDiv.appendChild(promptText); | |
const copyButton = document.createElement('button'); | |
copyButton.textContent = 'Prompt Kopieren'; | |
copyButton.className = 'btn btn-secondary mt-2'; | |
copyButton.onclick = function() { copyPrompt(formData.get('prompt')) }; | |
outputDiv.appendChild(copyButton); | |
outputDiv.appendChild(document.createElement('br')); | |
}); | |
// Fortschrittsanzeige ausblenden | |
progressContainer.style.display = 'none'; | |
progressMessage.style.display = 'none'; | |
} | |
}; | |
socket.onerror = function (event) { | |
console.error('WebSocket error:', event); | |
// Fortschrittsanzeige ausblenden im Fehlerfall | |
progressContainer.style.display = 'none'; | |
progressMessage.style.display = 'none'; | |
}; | |
socket.onclose = function (event) { | |
console.log('WebSocket connection closed:', event); | |
}; | |
// Alle Buttons auf der Seite deaktivieren | |
const buttons = document.querySelectorAll('button'); | |
buttons.forEach(button => { | |
button.disabled = true; | |
}); | |
} | |
// Funktion zur Optimierung des Prompts | |
function optimizeOnly() { | |
const form = document.getElementById('generateForm'); | |
if (!form.checkValidity()) { | |
form.classList.add('was-validated'); | |
return; | |
} | |
const formData = new FormData(form); | |
// HF LoRA-Einstellung hinzufügen | |
if (document.getElementById('hf_lora_toggle').checked) { | |
formData.append('hf_lora', 'Scalino84/my-flux-face'); | |
} else { | |
formData.delete('hf_lora'); | |
} | |
// Formulardaten in ein Objekt umwandeln | |
const formObject = Object.fromEntries(formData.entries()); | |
formObject.optimize_only = true; | |
// WebSocket-Verbindung öffnen | |
const socket = new WebSocket('ws://localhost:8000/ws'); | |
socket.onopen = function (event) { | |
socket.send(JSON.stringify(formObject)); | |
}; | |
socket.onmessage = function (event) { | |
const data = JSON.parse(event.data); | |
if (data.optimized_prompt) { | |
document.getElementById('prompt').value = data.optimized_prompt; | |
} | |
}; | |
socket.onerror = function (event) { | |
console.error('WebSocket error:', event); | |
}; | |
socket.onclose = function (event) { | |
console.log('WebSocket connection closed:', event); | |
}; | |
} | |
function batchOptimize() { | |
// Prompts aus dem Textbereich sammeln | |
const batchPrompts = document.getElementById('batchPrompts').value.split('\n').filter(prompt => prompt.trim() !== ''); | |
if (batchPrompts.length === 0) { | |
alert("Bitte geben Sie mindestens einen Prompt ein."); | |
return; | |
} | |
// Formulardaten sammeln | |
const formData = new FormData(document.getElementById('generateForm')); | |
const prompts = batchPrompts.map(prompt => { | |
const data = Object.fromEntries(formData); | |
data.prompt = prompt; | |
return data; | |
}); | |
// Add HF LoRA toggle value to each prompt | |
if (hf_lora_toggle.checked) { | |
formData.append('hf_lora', 'Scalino84/my-flux-face'); | |
} else { | |
formData.delete('hf_lora'); | |
} | |
// WebSocket-Verbindung öffnen | |
const socket = new WebSocket('ws://localhost:8000/ws'); | |
socket.onopen = function () { | |
// Prompts an den Server senden | |
socket.send(JSON.stringify({ prompts })); | |
}; | |
socket.onmessage = function (event) { | |
const data = JSON.parse(event.data); | |
if (data.optimized_prompt) { | |
document.getElementById('prompt').value = data.optimized_prompt; | |
} | |
if (data.generated_files) { | |
data.generated_files.forEach(file => { | |
const livePreviewImage = document.getElementById('livePreviewImage'); | |
if (livePreviewImage) { | |
livePreviewImage.src = file; | |
} else { | |
const img = document.createElement('img'); | |
img.id = 'livePreviewImage'; | |
img.src = file; | |
img.style.maxWidth = '100%'; | |
document.getElementById('output').appendChild(img); | |
} | |
}); | |
} | |
}; | |
socket.onerror = function (event) { | |
console.error('WebSocket error:', event); | |
alert('Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.'); | |
}; | |
socket.onclose = function (event) { | |
console.log('WebSocket connection closed:', event); | |
}; | |
} | |
function copyPrompt() { | |
const promptText = document.getElementById('prompt').value; | |
navigator.clipboard.writeText(promptText).then(() => { | |
alert('Prompt in die Zwischenablage kopiert!'); | |
}).catch(err => { | |
console.error('Fehler beim Kopieren des Prompts:', err); | |
}); | |
} | |
</script> | |
{% endblock %} |