feat: initial live.f12.rocks SFTP → gmic/rembg → web pipeline
Event pep stack with SFTPGo inbox, sequential worker, FastAPI gallery/remix, and Traefik-ready compose. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block title %}{{ site_title }}{% endblock %}</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="site-header">
|
||||
<a class="brand" href="/">{{ site_title }}</a>
|
||||
</header>
|
||||
<main>
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,25 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{ site_title }}{% endblock %}
|
||||
{% block content %}
|
||||
{% if not jobs %}
|
||||
<p class="empty-state">Noch keine Jobs. Bild per SFTP hochladen, dann kurz warten.</p>
|
||||
{% else %}
|
||||
<ul class="job-grid">
|
||||
{% for job in jobs %}
|
||||
<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">
|
||||
{% else %}
|
||||
<span class="thumb thumb-placeholder status-{{ job.status }}">{{ job.status }}</span>
|
||||
{% endif %}
|
||||
<span class="job-meta">
|
||||
<span class="job-id">{{ job.job_id }}</span>
|
||||
<span class="job-status status-{{ job.status }}">{{ job.status }} · {{ job.variant_count }} Varianten</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,78 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Job {{ job_id }} — {{ site_title }}{% endblock %}
|
||||
{% block content %}
|
||||
<p class="back-link"><a href="/">← Alle Jobs</a></p>
|
||||
|
||||
<h1>Job {{ job_id }}</h1>
|
||||
<p class="job-status status-{{ status.status }}">Status: {{ status.status or "unbekannt" }}</p>
|
||||
{% if status.error %}
|
||||
<p class="error-box">Fehler: {{ status.error }}</p>
|
||||
{% endif %}
|
||||
|
||||
<section>
|
||||
<h2>Original & Rembg</h2>
|
||||
<div class="pair-grid">
|
||||
{% if original_name %}
|
||||
<figure>
|
||||
<img src="/jobs/{{ job_id }}/files/{{ original_name }}" alt="Original" loading="lazy">
|
||||
<figcaption>
|
||||
Original ·
|
||||
<a href="/jobs/{{ job_id }}/files/{{ original_name }}" download>Download</a>
|
||||
</figcaption>
|
||||
</figure>
|
||||
{% endif %}
|
||||
{% if has_rembg %}
|
||||
<figure>
|
||||
<img 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>
|
||||
</figcaption>
|
||||
</figure>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="section-header">
|
||||
<h2>Varianten</h2>
|
||||
{% if has_rembg %}
|
||||
<a class="button" href="/jobs/{{ job_id }}/remix">+ Remix</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if not manifest.variants %}
|
||||
<p class="empty-state">Noch keine Varianten fertig.</p>
|
||||
{% else %}
|
||||
<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">
|
||||
<div class="variant-meta">
|
||||
<strong>{{ v.id }}</strong> <span class="tag">{{ v.source }}</span>
|
||||
<dl>
|
||||
<dt>BG</dt><dd>{{ v.background_filter }} + {{ v.background_blend }}</dd>
|
||||
<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>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
{% if intermediates %}
|
||||
<section>
|
||||
<h2>Zwischenschritte</h2>
|
||||
<ul class="intermediate-grid">
|
||||
{% for name in intermediates %}
|
||||
<li>
|
||||
<img src="/jobs/{{ job_id }}/files/intermediates/{{ name }}" alt="{{ name }}" loading="lazy">
|
||||
<span>{{ name }}</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,50 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Remix {{ job_id }} — {{ site_title }}{% endblock %}
|
||||
{% block content %}
|
||||
<p class="back-link"><a href="/jobs/{{ job_id }}">← Zurueck zum Job</a></p>
|
||||
|
||||
<h1>Remix · Job {{ job_id }}</h1>
|
||||
|
||||
{% if error %}
|
||||
<p class="error-box">{{ error }}</p>
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="/jobs/{{ job_id }}/remix" class="remix-form">
|
||||
<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>
|
||||
{% 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>
|
||||
{% 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>
|
||||
{% 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>
|
||||
{% 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>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<button type="submit" class="button button-primary">Remix erzeugen</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user