feat: Flask web UI on port 9000 with upload, job status, API endpoints

This commit is contained in:
jetson committed 2026-09-16 15:04:49 +07:00
1 parent f38c9708f6
commit eb77e5be8a
6 files changed
+373

No files matched your search

+21
View File
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Feedmill Recounter{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<header>
<h1>Feedmill Recounter</h1>
<nav>
<a href="/">Upload</a>
<a href="/jobs">Jobs</a>
</nav>
</header>
<main>
{% block content %}{% endblock %}
</main>
</body>
</html>
+48
View File
@@ -0,0 +1,48 @@
{% extends "base.html" %}
{% block title %}Upload - Feedmill Recounter{% endblock %}
{% block content %}
<h2>Upload Video & Select Models</h2>
<form action="/upload" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="video">Video File:</label>
<input type="file" name="video" id="video" accept="video/*" required>
</div>
<div class="form-group">
<label>Models to Run:</label>
{% if models %}
<div class="model-list">
{% for model in models %}
<div class="model-item">
<input type="checkbox" name="models" value="{{ model.filename }}" id="m-{{ loop.index }}">
<label for="m-{{ loop.index }}">
<strong>{{ model.filename }}</strong>
{% if model.known_classes %}
<span class="classes">[{{ model.known_classes | join(', ') }}]</span>
{% else %}
<span class="classes unknown">[no class info]</span>
{% endif %}
</label>
<div class="filter-group">
<label>Class filter:</label>
<select name="filter_{{ model.filename }}">
<option value="default">Use model defaults</option>
<option value="sack">sack only</option>
<option value="box">box only</option>
<option value="sack,box">sack + box</option>
<option value="all">all classes</option>
</select>
</div>
</div>
{% endfor %}
</div>
{% else %}
<p class="warning">No models found in {{ models_dir }}. Place model files in the models/ directory.</p>
{% endif %}
</div>
<div class="form-group">
<button type="submit" {% if not models %}disabled{% endif %}>Start Processing</button>
</div>
</form>
{% endblock %}
+35
View File
@@ -0,0 +1,35 @@
{% extends "base.html" %}
{% block title %}Jobs - Feedmill Recounter{% endblock %}
{% block content %}
<h2>All Jobs</h2>
{% if jobs %}
<table class="results-table">
<thead>
<tr>
<th>Job ID</th>
<th>Status</th>
<th>Progress</th>
<th>Models</th>
<th>Created</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{% for job in jobs %}
<tr>
<td><a href="/status/{{ job.job_id }}">{{ job.job_id }}</a></td>
<td class="status-{{ job.status|lower }}">{{ job.status.name }}</td>
<td>{{ "%.0f"|format(job.progress * 100) }}%</td>
<td>{{ job.model_configs|length }} model(s)</td>
<td>{{ "%.1f"|format(job.created_at) }}</td>
<td>
<a href="/status/{{ job.job_id }}">View</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No jobs yet. <a href="/">Upload a video</a></p>
{% endif %}
{% endblock %}
+63
View File
@@ -0,0 +1,63 @@
{% extends "base.html" %}
{% block title %}Job {{ job.job_id }} - Feedmill Recounter{% endblock %}
{% block content %}
<h2>Job: {{ job.job_id }}</h2>
<div class="job-info">
<p><strong>Status:</strong> <span class="status-{{ job.status|lower }}">{{ job.status }}</span></p>
<p><strong>Video:</strong> {{ job.video_path }}</p>
<p><strong>Progress:</strong> {{ "%.0f"|format(job.progress * 100) }}%</p>
{% if job.current_model %}
<p><strong>Current Model:</strong> {{ job.current_model }}</p>
{% endif %}
{% if job.error %}
<p class="error"><strong>Error:</strong> {{ job.error }}</p>
{% endif %}
</div>
{% if job.results %}
<h3>Results</h3>
<table class="results-table">
<thead>
<tr>
<th>Model</th>
<th>Loading</th>
<th>Unloading</th>
<th>Net</th>
<th>Batches</th>
<th>Frames</th>
<th>Duration</th>
<th>Output</th>
</tr>
</thead>
<tbody>
{% for r in job.results %}
<tr>
<td>{{ r.model_name }}</td>
<td>{{ r.loading_count }}</td>
<td>{{ r.unloading_count }}</td>
<td>{{ r.net_count }}</td>
<td>{{ r.batch_count }}</td>
<td>{{ r.frame_count }}</td>
<td>{{ "%.1f"|format(r.duration_seconds) }}s</td>
<td>
{% if r.output_path %}
<a href="/download/{{ job.job_id }}/{{ r.output_path | basename }}"
class="download-btn">Download</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% if job.status == "RUNNING" or job.status == "PENDING" %}
<div class="auto-refresh">
<p>Status will auto-refresh...</p>
</div>
<script>
setTimeout(function() { location.reload(); }, 2000);
</script>
{% endif %}
{% endblock %}