feat: enhance video generation responses with database ID and update dashboard to display pending and completed videos

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-04-29 16:39:46 +02:00
parent 8e36f48527
commit cc96d26b08
4 changed files with 92 additions and 32 deletions
+2 -1
View File
@@ -91,7 +91,8 @@ class VideoFromImageRequest(BaseModel):
class VideoResponse(BaseModel):
id: str
id: str # This is the job_id from the provider
db_id: str | None = None # This is the UUID from our generated_videos table
model: str
status: str # "queued" | "processing" | "completed" | "failed"
polling_url: str | None = None
+14 -6
View File
@@ -234,18 +234,22 @@ async def generate_video(
polling_url = result.get("polling_url")
job_status = result.get("status", "pending")
now = datetime.now(timezone.utc).replace(tzinfo=None)
db_id = None
async with get_write_lock():
conn = get_conn()
conn.execute(
row = conn.execute(
"""INSERT INTO generated_videos (user_id, job_id, model_id, prompt, polling_url, status, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING id""",
[user_id, job_id, body.model, body.prompt,
polling_url, job_status, now, now],
)
).fetchone()
if row:
db_id = str(row[0])
urls = result.get("unsigned_urls") or result.get("video_urls")
return VideoResponse(
id=job_id,
db_id=db_id,
model=body.model,
status=job_status,
polling_url=polling_url,
@@ -287,18 +291,22 @@ async def generate_video_from_image(
polling_url = result.get("polling_url")
job_status = result.get("status", "pending")
now = datetime.now(timezone.utc).replace(tzinfo=None)
db_id = None
async with get_write_lock():
conn = get_conn()
conn.execute(
row = conn.execute(
"""INSERT INTO generated_videos (user_id, job_id, model_id, prompt, polling_url, status, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING id""",
[user_id, job_id, body.model, body.prompt,
polling_url, job_status, now, now],
)
).fetchone()
if row:
db_id = str(row[0])
urls = result.get("unsigned_urls") or result.get("video_urls")
return VideoResponse(
id=job_id,
db_id=db_id,
model=body.model,
status=job_status,
polling_url=polling_url,
+19 -4
View File
@@ -217,11 +217,16 @@ def dashboard():
images = img_resp.json() if img_resp.status_code == 200 else []
gen_resp = _api("GET", "/generate/images", token=token)
generated_images = gen_resp.json() if gen_resp.status_code == 200 else []
vid_resp = _api("GET", "/generate/videos", token=token)
generated_videos = vid_resp.json() if vid_resp.status_code == 200 else []
videos = vid_resp.json() if vid_resp.status_code == 200 else []
pending_videos = [v for v in videos if v.get("status") not in ("completed", "failed")]
completed_videos = [v for v in videos if v.get("status") == "completed"]
return render_template("dashboard.html", user=user, images=images,
generated_images=generated_images,
generated_videos=generated_videos)
pending_videos=pending_videos,
completed_videos=completed_videos)
@app.get("/gallery")
@@ -405,7 +410,7 @@ def generate_image():
@app.route("/generate/video", methods=["GET", "POST"])
@login_required
def generate_video():
result = error = None
error = None
token = session["access_token"]
if request.method == "POST":
mode = request.form.get("mode", "text")
@@ -413,6 +418,7 @@ def generate_video():
duration = int(
duration_raw) if duration_raw.strip().isdigit() else None
resolution = request.form.get("resolution", "").strip() or None
if mode == "image":
resp = _api("POST", "/generate/video/from-image", token=token, json={
"model": request.form.get("model", "").strip(),
@@ -430,12 +436,21 @@ def generate_video():
"duration_seconds": duration,
"resolution": resolution,
})
if resp.status_code == 200:
result = resp.json()
# On success, redirect to the detail page to monitor progress
db_id = result.get("db_id")
if db_id:
return redirect(url_for("video_detail", video_id=db_id))
# Fallback for older backend versions
flash("Video job started.", "success")
return redirect(url_for("gallery"))
else:
error = resp.json().get("detail", "Generation failed.")
models = _load_models(token, "video")
return render_template("generate_video.html", result=result, error=error, models=models)
return render_template("generate_video.html", error=error, models=models)
@app.get("/generate/video/status")
+45 -9
View File
@@ -6,12 +6,42 @@ endblock %} {% block content %}
<a href="{{ url_for('generate') }}" class="btn">Start generating</a>
</div>
{% if generated_images %}
{% if pending_videos %}
<div class="card mt-2">
<h2>Pending Video Jobs</h2>
<div class="image-grid">
{% for vid in pending_videos %}
<a
href="{{ url_for('video_detail', video_id=vid.id) }}"
class="image-grid-item"
>
<div
style="
background: #1a1a1a;
border-radius: 6px;
padding: 2rem;
text-align: center;
"
>
<span class="text-muted">{{ vid.status | capitalize }} &hellip;</span>
</div>
<p class="text-muted" style="font-size: 0.75rem; margin-top: 0.25rem">
<strong>{{ vid.model_id }}</strong><br />{{ vid.prompt[:80] }}{% if
vid.prompt|length > 80 %}…{% endif %}
</p>
</a>
{% endfor %}
</div>
</div>
{% endif %} {% if generated_images %}
<div class="card mt-2">
<h2>Generated images</h2>
<div class="image-grid">
{% for img in generated_images %}
<div class="image-grid-item">
<a
href="{{ url_for('image_detail', image_id=img.id) }}"
class="image-grid-item"
>
<img
src="{{ img.image_data }}"
alt="{{ img.prompt }}"
@@ -22,16 +52,19 @@ endblock %} {% block content %}
<strong>{{ img.model_id }}</strong><br />{{ img.prompt[:80] }}{% if
img.prompt|length > 80 %}…{% endif %}
</p>
</div>
</a>
{% endfor %}
</div>
</div>
{% endif %} {% if generated_videos %}
{% endif %} {% if completed_videos %}
<div class="card mt-2">
<h2>Generated videos</h2>
<div class="image-grid">
{% for vid in generated_videos %}
<div class="image-grid-item">
{% for vid in completed_videos %}
<a
href="{{ url_for('video_detail', video_id=vid.id) }}"
class="image-grid-item"
>
{% if vid.video_url %}
<video controls style="max-width: 100%; border-radius: 6px">
<source src="{{ vid.video_url }}" />
@@ -54,7 +87,7 @@ endblock %} {% block content %}
vid.prompt|length > 80 %}…{% endif %}<br />
<em>{{ vid.status }}</em>
</p>
</div>
</a>
{% endfor %}
</div>
</div>
@@ -63,7 +96,10 @@ endblock %} {% block content %}
<h2>Uploaded reference images</h2>
<div class="image-grid">
{% for img in images %}
<div class="image-grid-item">
<a
href="{{ url_for('upload_detail', image_id=img.id) }}"
class="image-grid-item"
>
<img
src="{{ url_for('serve_uploaded_image', image_id=img.id) }}"
alt="{{ img.filename }}"
@@ -73,7 +109,7 @@ endblock %} {% block content %}
<p class="text-muted" style="font-size: 0.75rem; margin-top: 0.25rem">
{{ img.filename }} &mdash; {{ (img.size_bytes / 1024) | round(1) }} KB
</p>
</div>
</a>
{% endfor %}
</div>
</div>