github-actions[bot] commited on
Commit
249f430
Β·
1 Parent(s): 444be0b

Auto-deploy from GitHub: 8986b16862923441dcd086b63345a47c011d42b5

Browse files
Files changed (2) hide show
  1. app.py +27 -2
  2. index.html +79 -3
app.py CHANGED
@@ -201,11 +201,25 @@ def get_files():
201
  c = conn.cursor()
202
  c.execute('SELECT * FROM tasks ORDER BY created_at DESC')
203
  rows = c.fetchall()
 
 
 
 
 
 
 
 
 
 
 
204
  conn.close()
205
 
 
 
 
206
  files = []
207
  for row in rows:
208
- files.append({
209
  'id': row['id'],
210
  'text': row['text'],
211
  'status': row['status'],
@@ -213,7 +227,18 @@ def get_files():
213
  'created_at': row['created_at'],
214
  'processed_at': row['processed_at'],
215
  'error': row['error']
216
- })
 
 
 
 
 
 
 
 
 
 
 
217
 
218
  return jsonify(files)
219
 
 
201
  c = conn.cursor()
202
  c.execute('SELECT * FROM tasks ORDER BY created_at DESC')
203
  rows = c.fetchall()
204
+
205
+ # Get queue order for not_started tasks (oldest first = position 1)
206
+ c.execute('''SELECT id FROM tasks
207
+ WHERE status = 'not_started'
208
+ ORDER BY created_at ASC''')
209
+ queue_order = [r['id'] for r in c.fetchall()]
210
+
211
+ # Check if any task is currently processing
212
+ c.execute('SELECT COUNT(*) as count FROM tasks WHERE status = "processing"')
213
+ processing_count = c.fetchone()['count']
214
+
215
  conn.close()
216
 
217
+ # Average processing time in seconds (can be adjusted based on actual metrics)
218
+ AVG_PROCESSING_TIME = 30
219
+
220
  files = []
221
  for row in rows:
222
+ file_data = {
223
  'id': row['id'],
224
  'text': row['text'],
225
  'status': row['status'],
 
227
  'created_at': row['created_at'],
228
  'processed_at': row['processed_at'],
229
  'error': row['error']
230
+ }
231
+
232
+ # Add queue position for not_started tasks
233
+ if row['status'] == 'not_started' and row['id'] in queue_order:
234
+ queue_position = queue_order.index(row['id']) + 1 # 1-indexed
235
+ file_data['queue_position'] = queue_position
236
+ # Estimated time = (position - 1 + processing_count) * avg_time
237
+ # If something is processing, add that to the wait
238
+ tasks_ahead = queue_position - 1 + processing_count
239
+ file_data['estimated_start_seconds'] = tasks_ahead * AVG_PROCESSING_TIME
240
+
241
+ files.append(file_data)
242
 
243
  return jsonify(files)
244
 
index.html CHANGED
@@ -524,9 +524,15 @@
524
  </div>
525
  </div>
526
 
527
- <button class="btn" id="generateBtn">
528
- πŸš€ Generate Audio
529
- </button>
 
 
 
 
 
 
530
  </div>
531
 
532
  <div class="table-section">
@@ -571,6 +577,8 @@
571
  const voiceSelect = document.getElementById('voiceSelect');
572
  const speedInput = document.getElementById('speedInput');
573
  const generateBtn = document.getElementById('generateBtn');
 
 
574
  const loader = document.getElementById('loader');
575
  const refreshBtn = document.getElementById('refreshBtn');
576
 
@@ -620,6 +628,74 @@
620
  }
621
  });
622
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
623
  // Load files
624
  async function loadFiles() {
625
  try {
 
524
  </div>
525
  </div>
526
 
527
+ <div style="display: flex; gap: 1rem; flex-wrap: wrap;">
528
+ <button class="btn" id="generateBtn" style="flex: 1; min-width: 200px;">
529
+ πŸš€ Generate Audio
530
+ </button>
531
+ <button class="btn btn-secondary" id="uploadBtn" style="flex: 1; min-width: 200px;">
532
+ πŸ“ Upload File
533
+ </button>
534
+ <input type="file" id="fileInput" accept=".txt,.md,.text" style="display: none;">
535
+ </div>
536
  </div>
537
 
538
  <div class="table-section">
 
577
  const voiceSelect = document.getElementById('voiceSelect');
578
  const speedInput = document.getElementById('speedInput');
579
  const generateBtn = document.getElementById('generateBtn');
580
+ const uploadBtn = document.getElementById('uploadBtn');
581
+ const fileInput = document.getElementById('fileInput');
582
  const loader = document.getElementById('loader');
583
  const refreshBtn = document.getElementById('refreshBtn');
584
 
 
628
  }
629
  });
630
 
631
+ // Upload button - opens file picker
632
+ uploadBtn.addEventListener('click', () => {
633
+ fileInput.click();
634
+ });
635
+
636
+ // File input change - auto-submit for TTS
637
+ fileInput.addEventListener('change', async (e) => {
638
+ const file = e.target.files[0];
639
+ if (!file) return;
640
+
641
+ // Read file content
642
+ const reader = new FileReader();
643
+ reader.onload = async (event) => {
644
+ const text = event.target.result.trim();
645
+
646
+ if (!text) {
647
+ showNotification('File is empty!', 'error');
648
+ fileInput.value = ''; // Reset file input
649
+ return;
650
+ }
651
+
652
+ const voice = voiceSelect.value;
653
+ const speed = parseFloat(speedInput.value);
654
+
655
+ // Show loader
656
+ loader.style.display = 'flex';
657
+ uploadBtn.disabled = true;
658
+ generateBtn.disabled = true;
659
+
660
+ try {
661
+ const response = await fetch(`${API_URL}/generate`, {
662
+ method: 'POST',
663
+ headers: {
664
+ 'Content-Type': 'application/json'
665
+ },
666
+ body: JSON.stringify({
667
+ text,
668
+ voice,
669
+ speed
670
+ })
671
+ });
672
+
673
+ const data = await response.json();
674
+
675
+ if (response.ok) {
676
+ showNotification(`File "${file.name}" queued for TTS! πŸŽ‰`);
677
+ loadFiles();
678
+ } else {
679
+ showNotification(data.error || 'Upload failed', 'error');
680
+ }
681
+ } catch (error) {
682
+ showNotification('Network error: ' + error.message, 'error');
683
+ } finally {
684
+ loader.style.display = 'none';
685
+ uploadBtn.disabled = false;
686
+ generateBtn.disabled = false;
687
+ fileInput.value = ''; // Reset file input for next upload
688
+ }
689
+ };
690
+
691
+ reader.onerror = () => {
692
+ showNotification('Error reading file!', 'error');
693
+ fileInput.value = '';
694
+ };
695
+
696
+ reader.readAsText(file);
697
+ });
698
+
699
  // Load files
700
  async function loadFiles() {
701
  try {