feat: harden pipeline UX — preprocess, rembg alpha, remix/lightbox
Downscale to 2000px JPEG before rembg, random blend opacity, timeout retries, per-variant remix prefill, lightbox, and longer SFTP idle. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -13,5 +13,50 @@
|
||||
<main>
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<div id="lightbox" class="lightbox" hidden>
|
||||
<button type="button" class="lightbox-close" aria-label="Schliessen">×</button>
|
||||
<img id="lightbox-img" alt="">
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var box = document.getElementById("lightbox");
|
||||
var img = document.getElementById("lightbox-img");
|
||||
if (!box || !img) return;
|
||||
|
||||
function openLightbox(src, alt) {
|
||||
img.src = src;
|
||||
img.alt = alt || "";
|
||||
box.hidden = false;
|
||||
document.body.classList.add("lightbox-open");
|
||||
}
|
||||
|
||||
function closeLightbox() {
|
||||
box.hidden = true;
|
||||
img.removeAttribute("src");
|
||||
document.body.classList.remove("lightbox-open");
|
||||
}
|
||||
|
||||
document.addEventListener("click", function (e) {
|
||||
var target = e.target;
|
||||
if (!(target instanceof HTMLImageElement)) return;
|
||||
if (!target.classList.contains("lightboxable")) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
openLightbox(target.currentSrc || target.src, target.alt);
|
||||
});
|
||||
|
||||
box.addEventListener("click", function (e) {
|
||||
if (e.target === box || (e.target && e.target.classList.contains("lightbox-close"))) {
|
||||
closeLightbox();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", function (e) {
|
||||
if (e.key === "Escape" && !box.hidden) closeLightbox();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<li class="job-card">
|
||||
<a href="/jobs/{{ job.job_id }}">
|
||||
{% if job.thumbnail %}
|
||||
<img class="thumb" src="/jobs/{{ job.job_id }}/files/{{ job.thumbnail }}" alt="Variante von Job {{ job.job_id }}" loading="lazy">
|
||||
<img class="thumb lightboxable" src="/jobs/{{ job.job_id }}/files/{{ job.thumbnail }}" alt="Variante von Job {{ job.job_id }}" loading="lazy">
|
||||
{% else %}
|
||||
<span class="thumb thumb-placeholder status-{{ job.status }}">{{ job.status }}</span>
|
||||
{% endif %}
|
||||
|
||||
+10
-5
@@ -14,7 +14,7 @@
|
||||
<div class="pair-grid">
|
||||
{% if original_name %}
|
||||
<figure>
|
||||
<img src="/jobs/{{ job_id }}/files/{{ original_name }}" alt="Original" loading="lazy">
|
||||
<img class="lightboxable" src="/jobs/{{ job_id }}/files/{{ original_name }}" alt="Original" loading="lazy">
|
||||
<figcaption>
|
||||
Original ·
|
||||
<a href="/jobs/{{ job_id }}/files/{{ original_name }}" download>Download</a>
|
||||
@@ -23,7 +23,7 @@
|
||||
{% endif %}
|
||||
{% if has_rembg %}
|
||||
<figure>
|
||||
<img src="/jobs/{{ job_id }}/files/rembg.png" alt="Freigestellt (rembg)" loading="lazy">
|
||||
<img class="lightboxable" src="/jobs/{{ job_id }}/files/rembg.png" alt="Freigestellt (rembg)" loading="lazy">
|
||||
<figcaption>
|
||||
Rembg ·
|
||||
<a href="/jobs/{{ job_id }}/files/rembg.png" download>Download</a>
|
||||
@@ -46,7 +46,7 @@
|
||||
<ul class="variant-grid">
|
||||
{% for v in manifest.variants %}
|
||||
<li class="variant-card">
|
||||
<img src="/jobs/{{ job_id }}/files/{{ v.file }}" alt="Variante {{ v.id }}" loading="lazy">
|
||||
<img class="lightboxable" src="/jobs/{{ job_id }}/files/{{ v.file }}" alt="Variante {{ v.id }}" loading="lazy">
|
||||
<div class="variant-meta">
|
||||
<strong>{{ v.id }}</strong> <span class="tag">{{ v.source }}</span>
|
||||
<dl>
|
||||
@@ -54,7 +54,12 @@
|
||||
<dt>FG</dt><dd>{{ v.foreground_filter }} + {{ v.foreground_blend }}</dd>
|
||||
<dt>Opacity</dt><dd>{{ v.blend_opacity }}</dd>
|
||||
</dl>
|
||||
<a href="/jobs/{{ job_id }}/files/{{ v.file }}" download>Download</a>
|
||||
<div class="variant-actions">
|
||||
{% if has_rembg %}
|
||||
<a class="button" href="/jobs/{{ job_id }}/remix?from={{ v.id }}">Remix</a>
|
||||
{% endif %}
|
||||
<a href="/jobs/{{ job_id }}/files/{{ v.file }}" download>Download</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
@@ -68,7 +73,7 @@
|
||||
<ul class="intermediate-grid">
|
||||
{% for name in intermediates %}
|
||||
<li>
|
||||
<img src="/jobs/{{ job_id }}/files/intermediates/{{ name }}" alt="{{ name }}" loading="lazy">
|
||||
<img class="lightboxable" src="/jobs/{{ job_id }}/files/intermediates/{{ name }}" alt="{{ name }}" loading="lazy">
|
||||
<span>{{ name }}</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
<p class="back-link"><a href="/jobs/{{ job_id }}">← Zurueck zum Job</a></p>
|
||||
|
||||
<h1>Remix · Job {{ job_id }}</h1>
|
||||
{% if from_variant %}
|
||||
<p class="job-status">Vorausgefüllt von {{ from_variant }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% if error %}
|
||||
<p class="error-box">{{ error }}</p>
|
||||
@@ -13,35 +16,35 @@
|
||||
<label for="bg_filter">Background-Filter</label>
|
||||
<select name="bg_filter" id="bg_filter" required>
|
||||
{% for name in options.background_filters %}
|
||||
<option value="{{ name }}">{{ name }}</option>
|
||||
<option value="{{ name }}" {% if name == prefill.bg_filter %}selected{% endif %}>{{ name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<label for="bg_blend">Background-Blend</label>
|
||||
<select name="bg_blend" id="bg_blend" required>
|
||||
{% for mode in options.blend_modes %}
|
||||
<option value="{{ mode }}">{{ mode }}</option>
|
||||
<option value="{{ mode }}" {% if mode == prefill.bg_blend %}selected{% endif %}>{{ mode }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<label for="fg_filter">Foreground-Filter</label>
|
||||
<select name="fg_filter" id="fg_filter" required>
|
||||
{% for name in options.foreground_filters %}
|
||||
<option value="{{ name }}">{{ name }}</option>
|
||||
<option value="{{ name }}" {% if name == prefill.fg_filter %}selected{% endif %}>{{ name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<label for="fg_blend">Foreground-Blend</label>
|
||||
<select name="fg_blend" id="fg_blend" required>
|
||||
{% for mode in options.blend_modes %}
|
||||
<option value="{{ mode }}">{{ mode }}</option>
|
||||
<option value="{{ mode }}" {% if mode == prefill.fg_blend %}selected{% endif %}>{{ mode }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<label for="opacity">Blend-Opacity</label>
|
||||
<select name="opacity" id="opacity" required>
|
||||
{% for value in opacity_choices %}
|
||||
<option value="{{ value }}" {% if value == "30%" %}selected{% endif %}>{{ value }}</option>
|
||||
<option value="{{ value }}" {% if value == prefill.opacity %}selected{% endif %}>{{ value }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user