Fred808 commited on
Commit
f3af125
·
verified ·
1 Parent(s): 3400cb7

Upload dashboard.html

Browse files
Files changed (1) hide show
  1. templates/dashboard.html +321 -0
templates/dashboard.html ADDED
@@ -0,0 +1,321 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Caption Flow Server Dashboard - {{ flow_id }}</title>
7
+ <style>
8
+ body {
9
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
10
+ margin: 0;
11
+ padding: 20px;
12
+ background-color: #f4f7f9;
13
+ color: #333;
14
+ }
15
+ .container {
16
+ max-width: 1200px;
17
+ margin: auto;
18
+ background: #fff;
19
+ padding: 30px;
20
+ border-radius: 12px;
21
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
22
+ }
23
+ h1 {
24
+ color: #1e3a8a;
25
+ border-bottom: 2px solid #eff6ff;
26
+ padding-bottom: 10px;
27
+ margin-bottom: 20px;
28
+ }
29
+ h2 {
30
+ color: #3b82f6;
31
+ margin-top: 30px;
32
+ border-left: 4px solid #93c5fd;
33
+ padding-left: 10px;
34
+ }
35
+ .status-box {
36
+ padding: 15px;
37
+ border-radius: 8px;
38
+ font-weight: bold;
39
+ margin-bottom: 20px;
40
+ display: inline-block;
41
+ }
42
+ .status-ready { background-color: #d1fae5; color: #065f46; }
43
+ .status-processing { background-color: #fef3c7; color: #b45309; }
44
+ .form-group {
45
+ margin-bottom: 15px;
46
+ }
47
+ label {
48
+ display: block;
49
+ margin-bottom: 5px;
50
+ font-weight: 600;
51
+ }
52
+ input[type="text"], input[type="number"] {
53
+ width: 100%;
54
+ padding: 10px;
55
+ border: 1px solid #ccc;
56
+ border-radius: 6px;
57
+ box-sizing: border-box;
58
+ font-size: 16px;
59
+ }
60
+ button {
61
+ background-color: #3b82f6;
62
+ color: white;
63
+ padding: 10px 15px;
64
+ border: none;
65
+ border-radius: 6px;
66
+ cursor: pointer;
67
+ font-size: 16px;
68
+ transition: background-color 0.2s;
69
+ }
70
+ button:hover {
71
+ background-color: #2563eb;
72
+ }
73
+ .server-list {
74
+ list-style: none;
75
+ padding: 0;
76
+ }
77
+ .server-item {
78
+ background-color: #f9fafb;
79
+ border: 1px solid #eee;
80
+ padding: 15px;
81
+ margin-bottom: 10px;
82
+ border-radius: 8px;
83
+ display: flex;
84
+ justify-content: space-between;
85
+ align-items: center;
86
+ }
87
+ .server-item .url {
88
+ flex-grow: 1;
89
+ font-family: monospace;
90
+ font-size: 14px;
91
+ }
92
+ .server-item .stats {
93
+ margin-left: 20px;
94
+ font-size: 0.9em;
95
+ color: #6b7280;
96
+ }
97
+ .server-item .status {
98
+ font-weight: bold;
99
+ color: #10b981;
100
+ margin-right: 10px;
101
+ }
102
+ .server-item .status.busy {
103
+ color: #f59e0b;
104
+ }
105
+ .remove-btn {
106
+ background-color: #ef4444;
107
+ }
108
+ .remove-btn:hover {
109
+ background-color: #dc2626;
110
+ }
111
+ .message-area {
112
+ margin-top: 20px;
113
+ padding: 10px;
114
+ border-radius: 6px;
115
+ display: none;
116
+ }
117
+ .message-success { background-color: #d1fae5; color: #065f46; }
118
+ .message-error { background-color: #fee2e2; color: #991b1b; }
119
+ .grid {
120
+ display: grid;
121
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
122
+ gap: 20px;
123
+ }
124
+ .card {
125
+ background: #fff;
126
+ padding: 20px;
127
+ border-radius: 8px;
128
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
129
+ border: 1px solid #e5e7eb;
130
+ }
131
+ .card-header {
132
+ font-size: 1.1em;
133
+ font-weight: 600;
134
+ margin-bottom: 15px;
135
+ color: #1f2937;
136
+ }
137
+ </style>
138
+ </head>
139
+ <body>
140
+ <div class="container">
141
+ <h1>Caption Flow Server: {{ flow_id }}</h1>
142
+
143
+ <div class="status-box status-{{ 'processing' if status == 'processing' else 'ready' }}">
144
+ System Status: {{ status.capitalize() }}
145
+ </div>
146
+
147
+ <div class="grid">
148
+ <div class="card">
149
+ <div class="card-header">Processing State</div>
150
+ <p><strong>Manager URL:</strong> <a href="{{ manager_url }}" target="_blank">{{ manager_url }}</a></p>
151
+ <p><strong>Processed Files Count:</strong> {{ processed_files_count }}</p>
152
+ <p><strong>Last Processed Course:</strong> {{ last_course if last_course else 'N/A' }}</p>
153
+ <p><strong>Last Processed Index:</strong> {{ last_index }}</p>
154
+ </div>
155
+
156
+ <div class="card">
157
+ <div class="card-header">Start New Course Processing</div>
158
+ <form id="process-form">
159
+ <div class="form-group">
160
+ <label for="course_name">Course Name Prefix (e.g., DAREEFSA)</label>
161
+ <input type="text" id="course_name" name="course_name" required>
162
+ </div>
163
+ <div class="form-group">
164
+ <label for="start_index">Start Image Index (0 to start from beginning)</label>
165
+ <input type="number" id="start_index" name="start_index" value="0" min="0">
166
+ </div>
167
+ <button type="submit">Start Processing</button>
168
+ </form>
169
+ </div>
170
+ </div>
171
+
172
+ <h2>Caption Servers (Total: {{ total_servers }}, Busy: {{ busy_servers }})</h2>
173
+ <div id="message-server" class="message-area"></div>
174
+
175
+ <div class="card">
176
+ <div class="card-header">Add New Server</div>
177
+ <form id="add-server-form" style="display: flex; gap: 10px;">
178
+ <input type="text" id="new_server_url" name="server_url" placeholder="Enter server URL (e.g., https://user-space.hf.space/analyze)" required style="flex-grow: 1;">
179
+ <button type="submit">Add Server</button>
180
+ </form>
181
+ </div>
182
+
183
+ <ul class="server-list" id="server-list">
184
+ {% for server in servers %}
185
+ <li class="server-item" data-url="{{ server.url }}">
186
+ <span class="url">{{ server.url }}</span>
187
+ <span class="stats">
188
+ <span class="status {% if server.busy %}busy{% endif %}">{{ 'BUSY' if server.busy else 'READY' }}</span>
189
+ | Processed: {{ server.total_processed }}
190
+ | FPS: {{ "%.2f"|format(server.fps) }}
191
+ </span>
192
+ <button class="remove-btn" onclick="removeServer('{{ server.url }}')">Remove</button>
193
+ </li>
194
+ {% endfor %}
195
+ </ul>
196
+ </div>
197
+
198
+ <script>
199
+ const serverList = document.getElementById('server-list');
200
+ const messageServer = document.getElementById('message-server');
201
+ const messageProcess = document.getElementById('message-process');
202
+
203
+ function showMessage(element, type, message) {
204
+ element.className = `message-area message-${type}`;
205
+ element.textContent = message;
206
+ element.style.display = 'block';
207
+ setTimeout(() => {
208
+ element.style.display = 'none';
209
+ }, 5000);
210
+ }
211
+
212
+ document.getElementById('add-server-form').addEventListener('submit', async function(e) {
213
+ e.preventDefault();
214
+ const urlInput = document.getElementById('new_server_url');
215
+ const serverUrl = urlInput.value.trim();
216
+
217
+ try {
218
+ const response = await fetch('/add_server', {
219
+ method: 'POST',
220
+ headers: {
221
+ 'Content-Type': 'application/x-www-form-urlencoded',
222
+ },
223
+ body: new URLSearchParams({ server_url: serverUrl })
224
+ });
225
+
226
+ const result = await response.json();
227
+
228
+ if (response.ok) {
229
+ showMessage(messageServer, 'success', result.message);
230
+ // Add the new server to the list dynamically
231
+ const newItem = document.createElement('li');
232
+ newItem.className = 'server-item';
233
+ newItem.setAttribute('data-url', result.server.url);
234
+ newItem.innerHTML = `
235
+ <span class="url">${result.server.url}</span>
236
+ <span class="stats">
237
+ <span class="status">READY</span>
238
+ | Processed: 0
239
+ | FPS: 0.00
240
+ </span>
241
+ <button class="remove-btn" onclick="removeServer('${result.server.url}')">Remove</button>
242
+ `;
243
+ serverList.appendChild(newItem);
244
+ urlInput.value = ''; // Clear input
245
+ } else {
246
+ showMessage(messageServer, 'error', result.detail || 'Failed to add server.');
247
+ }
248
+ } catch (error) {
249
+ showMessage(messageServer, 'error', 'Network error or server unreachable.');
250
+ }
251
+ });
252
+
253
+ async function removeServer(serverUrl) {
254
+ if (!confirm(`Are you sure you want to remove server: ${serverUrl}?`)) {
255
+ return;
256
+ }
257
+
258
+ try {
259
+ const response = await fetch('/remove_server', {
260
+ method: 'POST',
261
+ headers: {
262
+ 'Content-Type': 'application/x-www-form-urlencoded',
263
+ },
264
+ body: new URLSearchParams({ server_url: serverUrl })
265
+ });
266
+
267
+ const result = await response.json();
268
+
269
+ if (response.ok) {
270
+ showMessage(messageServer, 'success', result.message);
271
+ // Remove the item from the list dynamically
272
+ const itemToRemove = document.querySelector(`.server-item[data-url="${serverUrl}"]`);
273
+ if (itemToRemove) {
274
+ itemToRemove.remove();
275
+ }
276
+ } else {
277
+ showMessage(messageServer, 'error', result.detail || 'Failed to remove server.');
278
+ }
279
+ } catch (error) {
280
+ showMessage(messageServer, 'error', 'Network error or server unreachable.');
281
+ }
282
+ }
283
+
284
+ document.getElementById('process-form').addEventListener('submit', async function(e) {
285
+ e.preventDefault();
286
+ const courseName = document.getElementById('course_name').value.trim();
287
+ const startIndex = parseInt(document.getElementById('start_index').value, 10);
288
+
289
+ try {
290
+ const response = await fetch('/process_course', {
291
+ method: 'POST',
292
+ headers: {
293
+ 'Content-Type': 'application/json',
294
+ },
295
+ body: JSON.stringify({ course_name: courseName, start_index: startIndex })
296
+ });
297
+
298
+ const result = await response.json();
299
+ const processMessageArea = document.querySelector('.card:nth-child(2) .form-group').parentElement.querySelector('#message-process') || document.createElement('div');
300
+ processMessageArea.id = 'message-process';
301
+ if (!processMessageArea.parentElement) {
302
+ document.querySelector('.card:nth-child(2)').appendChild(processMessageArea);
303
+ }
304
+
305
+ if (response.ok) {
306
+ showMessage(processMessageArea, 'success', `Processing started for course: ${result.course_name} from index: ${result.start_index}.`);
307
+ } else {
308
+ showMessage(processMessageArea, 'error', result.detail || 'Failed to start processing.');
309
+ }
310
+ } catch (error) {
311
+ const processMessageArea = document.querySelector('.card:nth-child(2) .form-group').parentElement.querySelector('#message-process') || document.createElement('div');
312
+ processMessageArea.id = 'message-process';
313
+ if (!processMessageArea.parentElement) {
314
+ document.querySelector('.card:nth-child(2)').appendChild(processMessageArea);
315
+ }
316
+ showMessage(processMessageArea, 'error', 'Network error or server unreachable.');
317
+ }
318
+ });
319
+ </script>
320
+ </body>
321
+ </html>