Upload /home/user/app/bck/templates/index.html with huggingface_hub
Browse files
home/user/app/bck/templates/index.html
ADDED
@@ -0,0 +1,371 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{% extends "base.html" %}
|
2 |
+
|
3 |
+
{% block title %}Flux Image Generator - Home{% endblock %}
|
4 |
+
|
5 |
+
{% block content %}
|
6 |
+
<h1>Flux Image Generator</h1>
|
7 |
+
<form id="generateForm" class="needs-validation custom-bg p-3 rounded" novalidate>
|
8 |
+
<!-- Prompt-Eingabe -->
|
9 |
+
<div class="mb-3">
|
10 |
+
<label for="prompt" class="form-label">Prompt:</label>
|
11 |
+
<textarea class="form-control" id="prompt" name="prompt" rows="4" required></textarea>
|
12 |
+
<div class="invalid-feedback">Bitte geben Sie einen Prompt ein.</div>
|
13 |
+
</div>
|
14 |
+
<!-- Album-Auswahl -->
|
15 |
+
<div class="mb-3">
|
16 |
+
<label for="album_id" class="form-label">Album:</label>
|
17 |
+
<input class="form-control" id="album_id" name="album_id" list="albums" placeholder="Wählen oder neues Album eingeben">
|
18 |
+
<datalist id="albums">
|
19 |
+
{% for album in albums %}
|
20 |
+
<option value="{{ album[1] }}">{{ album[0] }}</option>
|
21 |
+
{% endfor %}
|
22 |
+
</datalist>
|
23 |
+
</div>
|
24 |
+
<!-- Kategorie-Auswahl -->
|
25 |
+
<div class="mb-3">
|
26 |
+
<label for="category_id" class="form-label">Kategorie:</label>
|
27 |
+
<input class="form-control" id="category_id" name="category_id" list="categories" placeholder="Wählen oder neue Kategorie eingeben">
|
28 |
+
<datalist id="categories">
|
29 |
+
{% for category in categories %}
|
30 |
+
<option value="{{ category[1] }}">{{ category[0] }}</option>
|
31 |
+
{% endfor %}
|
32 |
+
</datalist>
|
33 |
+
</div>
|
34 |
+
<!-- Buttons zur Generierung und Optimierung -->
|
35 |
+
<button type="button" class="btn btn-primary mb-3" onclick="startGeneration()">Bild Generieren</button>
|
36 |
+
<button type="button" class="btn btn-secondary mb-3" onclick="optimizeOnly()">Nur Optimieren</button>
|
37 |
+
<button type="button" class="btn btn-secondary mb-3" onclick="copyPrompt()">Prompt Kopieren</button>
|
38 |
+
|
39 |
+
<!-- Fortschrittsanzeige -->
|
40 |
+
<div class="progress mb-3" id="progressContainer" style="display: none;">
|
41 |
+
<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>
|
42 |
+
</div>
|
43 |
+
|
44 |
+
<!-- Fortschrittsnachricht -->
|
45 |
+
<div id="progressMessage" class="mb-3" style="display: none;">
|
46 |
+
<p>Generiere Bilder, bitte warten...</p>
|
47 |
+
</div>
|
48 |
+
|
49 |
+
<!-- Erweiterte Einstellungen -->
|
50 |
+
<div class="accordion" id="advancedSettingsAccordion">
|
51 |
+
<div class="accordion-item custom-bg">
|
52 |
+
<h2 class="accordion-header" id="headingOne">
|
53 |
+
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
|
54 |
+
Erweiterte Einstellungen
|
55 |
+
</button>
|
56 |
+
</h2>
|
57 |
+
<div id="collapseOne" class="accordion-collapse collapse" aria-labelledby="headingOne" data-bs-parent="#advancedSettingsAccordion">
|
58 |
+
<div class="accordion-body">
|
59 |
+
<div class="row g-3">
|
60 |
+
<div class="col-12 col-md-6">
|
61 |
+
<label for="num_outputs" class="form-label">Anzahl der Ausgaben:</label>
|
62 |
+
<select class="form-control" id="num_outputs" name="num_outputs">
|
63 |
+
<option value="1">1</option>
|
64 |
+
<option value="2">2</option>
|
65 |
+
<option value="3">3</option>
|
66 |
+
<option value="4">4</option>
|
67 |
+
</select>
|
68 |
+
</div>
|
69 |
+
<div class="col-12 col-md-6">
|
70 |
+
<label for="aspect_ratio" class="form-label">Seitenverhältnis:</label>
|
71 |
+
<select class="form-control" id="aspect_ratio" name="aspect_ratio">
|
72 |
+
<option value="1:1">1:1</option>
|
73 |
+
<option value="16:9">16:9</option>
|
74 |
+
<option value="21:9">21:9</option>
|
75 |
+
<option value="3:2">3:2</option>
|
76 |
+
<option value="2:3">2:3</option>
|
77 |
+
<option value="4:5">4:5</option>
|
78 |
+
<option value="5:4">5:4</option>
|
79 |
+
<option value="3:4">3:4</option>
|
80 |
+
<option value="4:3">4:3</option>
|
81 |
+
<option value="9:16">9:16</option>
|
82 |
+
<option value="9:21">9:21</option>
|
83 |
+
</select>
|
84 |
+
</div>
|
85 |
+
<div class="col-12 col-md-6">
|
86 |
+
<label for="output_format" class="form-label">Ausgabeformat:</label>
|
87 |
+
<select class="form-control" id="output_format" name="output_format">
|
88 |
+
<option value="png">PNG</option>
|
89 |
+
<option value="jpg">JPG</option>
|
90 |
+
<option value="webp">WEBP</option>
|
91 |
+
</select>
|
92 |
+
</div>
|
93 |
+
<div class="col-12 col-md-6">
|
94 |
+
<label for="guidance_scale" class="form-label">Guidance Scale:</label>
|
95 |
+
<input type="number" step="0.1" class="form-control" id="guidance_scale" name="guidance_scale" value="3.5">
|
96 |
+
</div>
|
97 |
+
<div class="col-12 col-md-6">
|
98 |
+
<label for="output_quality" class="form-label">Ausgabequalität:</label>
|
99 |
+
<input type="number" class="form-control" id="output_quality" name="output_quality" value="80">
|
100 |
+
</div>
|
101 |
+
<div class="col-12 col-md-6">
|
102 |
+
<label for="prompt_strength" class="form-label">Prompt Strength:</label>
|
103 |
+
<input type="number" step="0.1" class="form-control" id="prompt_strength" name="prompt_strength" value="0.8">
|
104 |
+
</div>
|
105 |
+
<div class="col-12 col-md-6">
|
106 |
+
<label for="num_inference_steps" class="form-label">Anzahl der Inference Steps:</label>
|
107 |
+
<input type="number" class="form-control" id="num_inference_steps" name="num_inference_steps" value="28">
|
108 |
+
</div>
|
109 |
+
<div class="col-12 col-md-6">
|
110 |
+
<label for="lora_scale" class="form-label">LoRA Scale:</label>
|
111 |
+
<input type="number" step="0.1" class="form-control" id="lora_scale" name="lora_scale" value="0.8">
|
112 |
+
</div>
|
113 |
+
<div class="col-12 col-md-6 d-flex align-items-center">
|
114 |
+
<div class="form-switch mb-3">
|
115 |
+
<input class="form-check-input" type="checkbox" id="hf_lora_toggle" name="hf_lora_toggle" checked>
|
116 |
+
<label class="form-check-label" for="hf_lora_toggle">HF LoRA verwenden</label>
|
117 |
+
</div>
|
118 |
+
<div class="form-switch mb-3 ms-3">
|
119 |
+
<input class="form-check-input" type="checkbox" id="agent" name="agent" checked>
|
120 |
+
<label class="form-check-label" for="agent">Mistral Agent verwenden</label>
|
121 |
+
</div>
|
122 |
+
</div>
|
123 |
+
</div>
|
124 |
+
</div>
|
125 |
+
</div>
|
126 |
+
</div>
|
127 |
+
</div>
|
128 |
+
|
129 |
+
<!-- Batch-Optimierung -->
|
130 |
+
<div class="accordion mt-3" id="batchOptimizationAccordion">
|
131 |
+
<div class="accordion-item custom-bg">
|
132 |
+
<h2 class="accordion-header" id="headingTwo">
|
133 |
+
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
134 |
+
Batch-Optimierung
|
135 |
+
</button>
|
136 |
+
</h2>
|
137 |
+
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#batchOptimizationAccordion">
|
138 |
+
<div class="accordion-body">
|
139 |
+
<textarea id="batchPrompts" class="form-control" rows="10" placeholder="Mehrere Prompts eingeben, einer pro Zeile"></textarea>
|
140 |
+
<button type="button" class="btn btn-primary mt-2" onclick="batchOptimize()">Batch Optimieren</button>
|
141 |
+
</div>
|
142 |
+
</div>
|
143 |
+
</div>
|
144 |
+
</div>
|
145 |
+
</form>
|
146 |
+
|
147 |
+
<!-- Ausgabebereich -->
|
148 |
+
<div id="output" class="mt-3"></div>
|
149 |
+
{% endblock %}
|
150 |
+
|
151 |
+
{% block scripts %}
|
152 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.js"></script>
|
153 |
+
<script>
|
154 |
+
// Initialisierung des Croppers
|
155 |
+
let cropper;
|
156 |
+
function startCropper(imageElement) {
|
157 |
+
if (cropper) {
|
158 |
+
cropper.destroy();
|
159 |
+
}
|
160 |
+
cropper = new Cropper(imageElement, {
|
161 |
+
aspectRatio: 1,
|
162 |
+
viewMode: 1,
|
163 |
+
autoCropArea: 1,
|
164 |
+
responsive: true,
|
165 |
+
});
|
166 |
+
}
|
167 |
+
|
168 |
+
// Funktion zur Bildgenerierung
|
169 |
+
function startGeneration() {
|
170 |
+
const form = document.getElementById('generateForm');
|
171 |
+
if (!form.checkValidity()) {
|
172 |
+
form.classList.add('was-validated');
|
173 |
+
return;
|
174 |
+
}
|
175 |
+
|
176 |
+
// Fortschrittsanzeige einblenden
|
177 |
+
const progressContainer = document.getElementById('progressContainer');
|
178 |
+
progressContainer.style.display = 'block';
|
179 |
+
const progressBarInner = document.getElementById('progressBar');
|
180 |
+
progressBarInner.style.width = '0%';
|
181 |
+
progressBarInner.setAttribute('aria-valuenow', 0);
|
182 |
+
|
183 |
+
const progressMessage = document.getElementById('progressMessage');
|
184 |
+
progressMessage.style.display = 'block';
|
185 |
+
|
186 |
+
const outputDiv = document.getElementById('output');
|
187 |
+
outputDiv.innerHTML = '';
|
188 |
+
|
189 |
+
const formData = new FormData(form);
|
190 |
+
|
191 |
+
// HF LoRA-Einstellung hinzufügen
|
192 |
+
if (document.getElementById('hf_lora_toggle').checked) {
|
193 |
+
formData.append('hf_lora', 'Scalino84/my-flux-face');
|
194 |
+
} else {
|
195 |
+
formData.delete('hf_lora');
|
196 |
+
}
|
197 |
+
|
198 |
+
// Formulardaten in ein Objekt umwandeln
|
199 |
+
const formObject = Object.fromEntries(formData.entries());
|
200 |
+
|
201 |
+
// WebSocket-Verbindung öffnen
|
202 |
+
const socket = new WebSocket('ws://localhost:8000/ws');
|
203 |
+
|
204 |
+
socket.onopen = function (event) {
|
205 |
+
socket.send(JSON.stringify(formObject));
|
206 |
+
};
|
207 |
+
|
208 |
+
socket.onmessage = function (event) {
|
209 |
+
const data = JSON.parse(event.data);
|
210 |
+
if (data.optimized_prompt) {
|
211 |
+
document.getElementById('prompt').value = data.optimized_prompt;
|
212 |
+
}
|
213 |
+
if (data.progress !== undefined) {
|
214 |
+
progressBarInner.style.width = `${data.progress}%`;
|
215 |
+
progressBarInner.setAttribute('aria-valuenow', data.progress);
|
216 |
+
}
|
217 |
+
if (data.message) {
|
218 |
+
const message = document.createElement('div');
|
219 |
+
message.textContent = data.message;
|
220 |
+
outputDiv.appendChild(message);
|
221 |
+
}
|
222 |
+
if (data.generated_files) {
|
223 |
+
data.generated_files.forEach(file => {
|
224 |
+
const img = document.createElement('img');
|
225 |
+
img.src = file;
|
226 |
+
img.style.maxWidth = '100%';
|
227 |
+
outputDiv.appendChild(img);
|
228 |
+
const promptText = document.createElement('p');
|
229 |
+
promptText.textContent = `Prompt: ${formData.get('prompt')}`;
|
230 |
+
outputDiv.appendChild(promptText);
|
231 |
+
const copyButton = document.createElement('button');
|
232 |
+
copyButton.textContent = 'Prompt Kopieren';
|
233 |
+
copyButton.className = 'btn btn-secondary mt-2';
|
234 |
+
copyButton.onclick = function() { copyPrompt(formData.get('prompt')) };
|
235 |
+
outputDiv.appendChild(copyButton);
|
236 |
+
outputDiv.appendChild(document.createElement('br'));
|
237 |
+
});
|
238 |
+
// Fortschrittsanzeige ausblenden
|
239 |
+
progressContainer.style.display = 'none';
|
240 |
+
progressMessage.style.display = 'none';
|
241 |
+
}
|
242 |
+
};
|
243 |
+
|
244 |
+
socket.onerror = function (event) {
|
245 |
+
console.error('WebSocket error:', event);
|
246 |
+
// Fortschrittsanzeige ausblenden im Fehlerfall
|
247 |
+
progressContainer.style.display = 'none';
|
248 |
+
progressMessage.style.display = 'none';
|
249 |
+
};
|
250 |
+
|
251 |
+
socket.onclose = function (event) {
|
252 |
+
console.log('WebSocket connection closed:', event);
|
253 |
+
};
|
254 |
+
}
|
255 |
+
|
256 |
+
// Funktion zur Optimierung des Prompts
|
257 |
+
function optimizeOnly() {
|
258 |
+
const form = document.getElementById('generateForm');
|
259 |
+
if (!form.checkValidity()) {
|
260 |
+
form.classList.add('was-validated');
|
261 |
+
return;
|
262 |
+
}
|
263 |
+
|
264 |
+
const formData = new FormData(form);
|
265 |
+
|
266 |
+
// HF LoRA-Einstellung hinzufügen
|
267 |
+
if (document.getElementById('hf_lora_toggle').checked) {
|
268 |
+
formData.append('hf_lora', 'Scalino84/my-flux-face');
|
269 |
+
} else {
|
270 |
+
formData.delete('hf_lora');
|
271 |
+
}
|
272 |
+
|
273 |
+
// Formulardaten in ein Objekt umwandeln
|
274 |
+
const formObject = Object.fromEntries(formData.entries());
|
275 |
+
formObject.optimize_only = true;
|
276 |
+
|
277 |
+
// WebSocket-Verbindung öffnen
|
278 |
+
const socket = new WebSocket('ws://localhost:8000/ws');
|
279 |
+
|
280 |
+
socket.onopen = function (event) {
|
281 |
+
socket.send(JSON.stringify(formObject));
|
282 |
+
};
|
283 |
+
|
284 |
+
socket.onmessage = function (event) {
|
285 |
+
const data = JSON.parse(event.data);
|
286 |
+
if (data.optimized_prompt) {
|
287 |
+
document.getElementById('prompt').value = data.optimized_prompt;
|
288 |
+
}
|
289 |
+
};
|
290 |
+
|
291 |
+
socket.onerror = function (event) {
|
292 |
+
console.error('WebSocket error:', event);
|
293 |
+
};
|
294 |
+
|
295 |
+
socket.onclose = function (event) {
|
296 |
+
console.log('WebSocket connection closed:', event);
|
297 |
+
};
|
298 |
+
}
|
299 |
+
|
300 |
+
function batchOptimize() {
|
301 |
+
// Prompts aus dem Textbereich sammeln
|
302 |
+
const batchPrompts = document.getElementById('batchPrompts').value.split('\n').filter(prompt => prompt.trim() !== '');
|
303 |
+
if (batchPrompts.length === 0) {
|
304 |
+
alert("Bitte geben Sie mindestens einen Prompt ein.");
|
305 |
+
return;
|
306 |
+
}
|
307 |
+
|
308 |
+
// Formulardaten sammeln
|
309 |
+
const formData = new FormData(document.getElementById('generateForm'));
|
310 |
+
const prompts = batchPrompts.map(prompt => {
|
311 |
+
const data = Object.fromEntries(formData);
|
312 |
+
data.prompt = prompt;
|
313 |
+
return data;
|
314 |
+
});
|
315 |
+
|
316 |
+
// Add HF LoRA toggle value to each prompt
|
317 |
+
if (hf_lora_toggle.checked) {
|
318 |
+
formData.append('hf_lora', 'Scalino84/my-flux-face');
|
319 |
+
} else {
|
320 |
+
formData.delete('hf_lora');
|
321 |
+
}
|
322 |
+
|
323 |
+
// WebSocket-Verbindung öffnen
|
324 |
+
const socket = new WebSocket('ws://localhost:8000/ws');
|
325 |
+
|
326 |
+
socket.onopen = function () {
|
327 |
+
// Prompts an den Server senden
|
328 |
+
socket.send(JSON.stringify({ prompts }));
|
329 |
+
};
|
330 |
+
|
331 |
+
socket.onmessage = function (event) {
|
332 |
+
const data = JSON.parse(event.data);
|
333 |
+
if (data.optimized_prompt) {
|
334 |
+
document.getElementById('prompt').value = data.optimized_prompt;
|
335 |
+
}
|
336 |
+
if (data.generated_files) {
|
337 |
+
data.generated_files.forEach(file => {
|
338 |
+
const livePreviewImage = document.getElementById('livePreviewImage');
|
339 |
+
if (livePreviewImage) {
|
340 |
+
livePreviewImage.src = file;
|
341 |
+
} else {
|
342 |
+
const img = document.createElement('img');
|
343 |
+
img.id = 'livePreviewImage';
|
344 |
+
img.src = file;
|
345 |
+
img.style.maxWidth = '100%';
|
346 |
+
document.getElementById('output').appendChild(img);
|
347 |
+
}
|
348 |
+
});
|
349 |
+
}
|
350 |
+
};
|
351 |
+
|
352 |
+
socket.onerror = function (event) {
|
353 |
+
console.error('WebSocket error:', event);
|
354 |
+
alert('Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.');
|
355 |
+
};
|
356 |
+
|
357 |
+
socket.onclose = function (event) {
|
358 |
+
console.log('WebSocket connection closed:', event);
|
359 |
+
};
|
360 |
+
}
|
361 |
+
|
362 |
+
function copyPrompt() {
|
363 |
+
const promptText = document.getElementById('prompt').value;
|
364 |
+
navigator.clipboard.writeText(promptText).then(() => {
|
365 |
+
alert('Prompt in die Zwischenablage kopiert!');
|
366 |
+
}).catch(err => {
|
367 |
+
console.error('Fehler beim Kopieren des Prompts:', err);
|
368 |
+
});
|
369 |
+
}
|
370 |
+
</script>
|
371 |
+
{% endblock %}
|