github-actions[bot] commited on
Commit
53878a2
·
1 Parent(s): eec3fb0

Auto-deploy from GitHub: dc2dcd799144f3d7cf9e0b0bef529a1486c14375

Browse files
Files changed (2) hide show
  1. app.py +81 -3
  2. index.html +27 -2
app.py CHANGED
@@ -203,24 +203,75 @@ def upload_audio():
203
  'message': 'File uploaded successfully'
204
  }), 201
205
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  @app.route('/api/files', methods=['GET'])
207
  def get_files():
208
  conn = sqlite3.connect('audio_captions.db')
209
  conn.row_factory = sqlite3.Row
210
  c = conn.cursor()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  c.execute('SELECT * FROM audio_files ORDER BY created_at DESC')
212
  rows = c.fetchall()
213
  conn.close()
214
 
215
  files = []
216
  for row in rows:
 
 
 
 
 
 
 
 
 
 
217
  files.append({
218
  'id': row['id'],
219
  'filename': row['filename'],
220
  'status': row['status'],
221
  'caption': row['caption'],
222
  'created_at': row['created_at'],
223
- 'processed_at': row['processed_at']
 
 
224
  })
225
 
226
  return jsonify(files)
@@ -232,18 +283,45 @@ def get_file(file_id):
232
  c = conn.cursor()
233
  c.execute('SELECT * FROM audio_files WHERE id = ?', (file_id,))
234
  row = c.fetchone()
235
- conn.close()
236
 
237
  if row is None:
 
238
  return jsonify({'error': 'File not found'}), 404
239
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  return jsonify({
241
  'id': row['id'],
242
  'filename': row['filename'],
243
  'status': row['status'],
244
  'caption': row['caption'],
245
  'created_at': row['created_at'],
246
- 'processed_at': row['processed_at']
 
 
247
  })
248
 
249
  @app.route('/health', methods=['GET'])
 
203
  'message': 'File uploaded successfully'
204
  }), 201
205
 
206
+ def get_average_processing_time(cursor):
207
+ """Calculate average processing time from completed files in seconds"""
208
+ cursor.execute('''SELECT created_at, processed_at FROM audio_files
209
+ WHERE status = 'completed' AND processed_at IS NOT NULL
210
+ ORDER BY processed_at DESC LIMIT 20''')
211
+ completed_rows = cursor.fetchall()
212
+
213
+ if not completed_rows:
214
+ return 30.0 # Default estimate: 30 seconds per file
215
+
216
+ total_seconds = 0
217
+ count = 0
218
+ for r in completed_rows:
219
+ try:
220
+ created = datetime.fromisoformat(r['created_at'])
221
+ processed = datetime.fromisoformat(r['processed_at'])
222
+ duration = (processed - created).total_seconds()
223
+ if duration > 0:
224
+ total_seconds += duration
225
+ count += 1
226
+ except:
227
+ continue
228
+
229
+ return total_seconds / count if count > 0 else 30.0
230
+
231
  @app.route('/api/files', methods=['GET'])
232
  def get_files():
233
  conn = sqlite3.connect('audio_captions.db')
234
  conn.row_factory = sqlite3.Row
235
  c = conn.cursor()
236
+
237
+ # Get average processing time
238
+ avg_time = get_average_processing_time(c)
239
+
240
+ # Get queue (files waiting to be processed, ordered by creation time)
241
+ c.execute('''SELECT id FROM audio_files
242
+ WHERE status = 'not_started'
243
+ ORDER BY created_at ASC''')
244
+ queue_ids = [row['id'] for row in c.fetchall()]
245
+
246
+ # Check if there's a file currently processing
247
+ c.execute('''SELECT COUNT(*) as count FROM audio_files WHERE status = 'processing' ''')
248
+ processing_count = c.fetchone()['count']
249
+
250
  c.execute('SELECT * FROM audio_files ORDER BY created_at DESC')
251
  rows = c.fetchall()
252
  conn.close()
253
 
254
  files = []
255
  for row in rows:
256
+ # Calculate queue position (1-based) for files in queue
257
+ queue_position = None
258
+ estimated_start_seconds = None
259
+
260
+ if row['status'] == 'not_started' and row['id'] in queue_ids:
261
+ queue_position = queue_ids.index(row['id']) + 1
262
+ # Estimate = (files ahead + currently processing) * avg time
263
+ files_ahead = queue_position - 1 + processing_count
264
+ estimated_start_seconds = round(files_ahead * avg_time)
265
+
266
  files.append({
267
  'id': row['id'],
268
  'filename': row['filename'],
269
  'status': row['status'],
270
  'caption': row['caption'],
271
  'created_at': row['created_at'],
272
+ 'processed_at': row['processed_at'],
273
+ 'queue_position': queue_position,
274
+ 'estimated_start_seconds': estimated_start_seconds
275
  })
276
 
277
  return jsonify(files)
 
283
  c = conn.cursor()
284
  c.execute('SELECT * FROM audio_files WHERE id = ?', (file_id,))
285
  row = c.fetchone()
 
286
 
287
  if row is None:
288
+ conn.close()
289
  return jsonify({'error': 'File not found'}), 404
290
 
291
+ # Calculate queue position and estimated time if file is waiting
292
+ queue_position = None
293
+ estimated_start_seconds = None
294
+
295
+ if row['status'] == 'not_started':
296
+ # Get average processing time
297
+ avg_time = get_average_processing_time(c)
298
+
299
+ # Count files ahead in queue
300
+ c.execute('''SELECT COUNT(*) as position FROM audio_files
301
+ WHERE status = 'not_started' AND created_at < ?''',
302
+ (row['created_at'],))
303
+ position_row = c.fetchone()
304
+ queue_position = position_row['position'] + 1 # 1-based position
305
+
306
+ # Check if there's a file currently processing
307
+ c.execute('''SELECT COUNT(*) as count FROM audio_files WHERE status = 'processing' ''')
308
+ processing_count = c.fetchone()['count']
309
+
310
+ # Estimate = (files ahead + currently processing) * avg time
311
+ files_ahead = queue_position - 1 + processing_count
312
+ estimated_start_seconds = round(files_ahead * avg_time)
313
+
314
+ conn.close()
315
+
316
  return jsonify({
317
  'id': row['id'],
318
  'filename': row['filename'],
319
  'status': row['status'],
320
  'caption': row['caption'],
321
  'created_at': row['created_at'],
322
+ 'processed_at': row['processed_at'],
323
+ 'queue_position': queue_position,
324
+ 'estimated_start_seconds': estimated_start_seconds
325
  })
326
 
327
  @app.route('/health', methods=['GET'])
index.html CHANGED
@@ -627,6 +627,7 @@
627
  <tr>
628
  <th>Filename</th>
629
  <th>Status</th>
 
630
  <th>Caption</th>
631
  <th>Created</th>
632
  <th>Processed</th>
@@ -634,7 +635,7 @@
634
  </thead>
635
  <tbody id="filesTable">
636
  <tr>
637
- <td colspan="5" class="empty-state">No files uploaded yet. Start by uploading an audio file!
638
  </td>
639
  </tr>
640
  </tbody>
@@ -754,7 +755,7 @@
754
  const tbody = document.getElementById('filesTable');
755
 
756
  if (files.length === 0) {
757
- tbody.innerHTML = '<tr><td colspan="5" class="empty-state">No files uploaded yet. Start by uploading an audio file!</td></tr>';
758
  return;
759
  }
760
 
@@ -762,11 +763,35 @@
762
  const captionPreview = file.caption ?
763
  (file.caption.length > 50 ? file.caption.substring(0, 50) + '...' : file.caption) :
764
  '—';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
765
 
766
  return `
767
  <tr>
768
  <td><strong>${file.filename}</strong></td>
769
  <td><span class="status status-${file.status}">${file.status.replace('_', ' ')}</span></td>
 
770
  <td class="caption-cell">
771
  ${file.caption ?
772
  `<button class="btn btn-small btn-secondary" onclick='showCaption(${JSON.stringify(file.caption)})' style="margin-left: 0.5rem;">Show</button>`
 
627
  <tr>
628
  <th>Filename</th>
629
  <th>Status</th>
630
+ <th>Est. Wait</th>
631
  <th>Caption</th>
632
  <th>Created</th>
633
  <th>Processed</th>
 
635
  </thead>
636
  <tbody id="filesTable">
637
  <tr>
638
+ <td colspan="6" class="empty-state">No files uploaded yet. Start by uploading an audio file!
639
  </td>
640
  </tr>
641
  </tbody>
 
755
  const tbody = document.getElementById('filesTable');
756
 
757
  if (files.length === 0) {
758
+ tbody.innerHTML = '<tr><td colspan="6" class="empty-state">No files uploaded yet. Start by uploading an audio file!</td></tr>';
759
  return;
760
  }
761
 
 
763
  const captionPreview = file.caption ?
764
  (file.caption.length > 50 ? file.caption.substring(0, 50) + '...' : file.caption) :
765
  '—';
766
+
767
+ // Format estimated wait time
768
+ let estWait = '—';
769
+ if (file.status === 'not_started' && file.estimated_start_seconds !== null) {
770
+ const seconds = file.estimated_start_seconds;
771
+ if (seconds < 60) {
772
+ estWait = `${seconds}s`;
773
+ } else if (seconds < 3600) {
774
+ const mins = Math.floor(seconds / 60);
775
+ const secs = seconds % 60;
776
+ estWait = secs > 0 ? `${mins}m ${secs}s` : `${mins}m`;
777
+ } else {
778
+ const hours = Math.floor(seconds / 3600);
779
+ const mins = Math.floor((seconds % 3600) / 60);
780
+ estWait = mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
781
+ }
782
+ // Add queue position
783
+ if (file.queue_position) {
784
+ estWait = `#${file.queue_position} (${estWait})`;
785
+ }
786
+ } else if (file.status === 'processing') {
787
+ estWait = '⏳ Processing...';
788
+ }
789
 
790
  return `
791
  <tr>
792
  <td><strong>${file.filename}</strong></td>
793
  <td><span class="status status-${file.status}">${file.status.replace('_', ' ')}</span></td>
794
+ <td>${estWait}</td>
795
  <td class="caption-cell">
796
  ${file.caption ?
797
  `<button class="btn btn-small btn-secondary" onclick='showCaption(${JSON.stringify(file.caption)})' style="margin-left: 0.5rem;">Show</button>`