github-actions[bot]
commited on
Commit
·
5ed4c17
1
Parent(s):
aa3ab7e
Auto-deploy from GitHub: 5d667bf754bfbf65bb6436e5979903221a0ad738
Browse files- .gitattributes +1 -1
- app.py +58 -6
- index.html +62 -1
.gitattributes
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
|
|
| 1 |
*.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 2 |
*.flac filter=lfs diff=lfs merge=lfs -text
|
| 3 |
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 4 |
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.wav filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 1 |
+
*.wav filter=lfs diff=lfs merge=lfs -text
|
| 2 |
*.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 3 |
*.flac filter=lfs diff=lfs merge=lfs -text
|
| 4 |
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 5 |
*.bin filter=lfs diff=lfs merge=lfs -text
|
|
|
app.py
CHANGED
|
@@ -36,7 +36,10 @@ def init_db():
|
|
| 36 |
output_file TEXT,
|
| 37 |
created_at TEXT NOT NULL,
|
| 38 |
processed_at TEXT,
|
| 39 |
-
error TEXT
|
|
|
|
|
|
|
|
|
|
| 40 |
conn.commit()
|
| 41 |
conn.close()
|
| 42 |
|
|
@@ -147,10 +150,15 @@ def worker_loop():
|
|
| 147 |
"--speed", str(speed)
|
| 148 |
]
|
| 149 |
|
| 150 |
-
|
|
|
|
|
|
|
| 151 |
command,
|
| 152 |
-
|
|
|
|
| 153 |
cwd=CWD,
|
|
|
|
|
|
|
| 154 |
env={
|
| 155 |
**os.environ,
|
| 156 |
'PYTHONUNBUFFERED': '1',
|
|
@@ -158,6 +166,39 @@ def worker_loop():
|
|
| 158 |
}
|
| 159 |
)
|
| 160 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 161 |
# Check for output file
|
| 162 |
output_filename = "output_audio.wav"
|
| 163 |
if os.path.exists(output_filename):
|
|
@@ -186,6 +227,15 @@ def worker_loop():
|
|
| 186 |
print(f"⚠️ Worker error: {str(e)}")
|
| 187 |
time.sleep(POLL_INTERVAL)
|
| 188 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
def update_status(task_id, status, output_file=None, error=None):
|
| 190 |
"""Update the status of a task in the database"""
|
| 191 |
conn = sqlite3.connect('tts_tasks.db')
|
|
@@ -193,12 +243,12 @@ def update_status(task_id, status, output_file=None, error=None):
|
|
| 193 |
|
| 194 |
if status == 'completed':
|
| 195 |
c.execute('''UPDATE tasks
|
| 196 |
-
SET status = ?, output_file = ?, processed_at =
|
| 197 |
WHERE id = ?''',
|
| 198 |
(status, output_file, datetime.now().isoformat(), task_id))
|
| 199 |
elif status == 'failed':
|
| 200 |
c.execute('''UPDATE tasks
|
| 201 |
-
SET status = ?, error = ?, processed_at =
|
| 202 |
WHERE id = ?''',
|
| 203 |
(status, str(error), datetime.now().isoformat(), task_id))
|
| 204 |
else:
|
|
@@ -276,7 +326,9 @@ def get_files():
|
|
| 276 |
'output_file': row['output_file'],
|
| 277 |
'created_at': row['created_at'],
|
| 278 |
'processed_at': row['processed_at'],
|
| 279 |
-
'error': row['error']
|
|
|
|
|
|
|
| 280 |
}
|
| 281 |
|
| 282 |
# Add queue position for not_started tasks
|
|
|
|
| 36 |
output_file TEXT,
|
| 37 |
created_at TEXT NOT NULL,
|
| 38 |
processed_at TEXT,
|
| 39 |
+
error TEXT,
|
| 40 |
+
progress INTEGER DEFAULT 0,
|
| 41 |
+
progress_text TEXT)''')
|
| 42 |
+
|
| 43 |
conn.commit()
|
| 44 |
conn.close()
|
| 45 |
|
|
|
|
| 150 |
"--speed", str(speed)
|
| 151 |
]
|
| 152 |
|
| 153 |
+
# Run with output capture for progress tracking
|
| 154 |
+
import re
|
| 155 |
+
process = subprocess.Popen(
|
| 156 |
command,
|
| 157 |
+
stdout=subprocess.PIPE,
|
| 158 |
+
stderr=subprocess.STDOUT,
|
| 159 |
cwd=CWD,
|
| 160 |
+
text=True,
|
| 161 |
+
bufsize=1,
|
| 162 |
env={
|
| 163 |
**os.environ,
|
| 164 |
'PYTHONUNBUFFERED': '1',
|
|
|
|
| 166 |
}
|
| 167 |
)
|
| 168 |
|
| 169 |
+
total_sentences = 0
|
| 170 |
+
current_sentence = 0
|
| 171 |
+
|
| 172 |
+
for line in process.stdout:
|
| 173 |
+
print(line, end='') # Echo to console
|
| 174 |
+
|
| 175 |
+
# Parse "Sentence X processed" lines
|
| 176 |
+
match = re.search(r'Sentence\s+(\d+)\s+processed', line)
|
| 177 |
+
if match:
|
| 178 |
+
current_sentence = int(match.group(1))
|
| 179 |
+
# Try to get total from "Combining X audio files"
|
| 180 |
+
if total_sentences > 0:
|
| 181 |
+
progress = int((current_sentence / total_sentences) * 100)
|
| 182 |
+
update_progress(task_id, progress, f"Processing sentence {current_sentence}/{total_sentences}")
|
| 183 |
+
|
| 184 |
+
# Parse "Combining X audio files" to get total count
|
| 185 |
+
combine_match = re.search(r'Combining\s+(\d+)\s+audio\s+files', line)
|
| 186 |
+
if combine_match:
|
| 187 |
+
total_sentences = int(combine_match.group(1))
|
| 188 |
+
update_progress(task_id, 90, "Combining audio files...")
|
| 189 |
+
|
| 190 |
+
# Parse "Processing text sentences..." as start
|
| 191 |
+
if 'Processing text sentences' in line:
|
| 192 |
+
update_progress(task_id, 5, "Processing text sentences...")
|
| 193 |
+
|
| 194 |
+
# Parse model loading
|
| 195 |
+
if 'Model loaded successfully' in line:
|
| 196 |
+
update_progress(task_id, 10, "Model loaded, starting TTS...")
|
| 197 |
+
|
| 198 |
+
process.wait()
|
| 199 |
+
if process.returncode != 0:
|
| 200 |
+
raise Exception(f"TTS process failed with return code {process.returncode}")
|
| 201 |
+
|
| 202 |
# Check for output file
|
| 203 |
output_filename = "output_audio.wav"
|
| 204 |
if os.path.exists(output_filename):
|
|
|
|
| 227 |
print(f"⚠️ Worker error: {str(e)}")
|
| 228 |
time.sleep(POLL_INTERVAL)
|
| 229 |
|
| 230 |
+
def update_progress(task_id, progress, progress_text=None):
|
| 231 |
+
"""Update the progress of a task"""
|
| 232 |
+
conn = sqlite3.connect('tts_tasks.db')
|
| 233 |
+
c = conn.cursor()
|
| 234 |
+
c.execute('UPDATE tasks SET progress = ?, progress_text = ? WHERE id = ?',
|
| 235 |
+
(progress, progress_text, task_id))
|
| 236 |
+
conn.commit()
|
| 237 |
+
conn.close()
|
| 238 |
+
|
| 239 |
def update_status(task_id, status, output_file=None, error=None):
|
| 240 |
"""Update the status of a task in the database"""
|
| 241 |
conn = sqlite3.connect('tts_tasks.db')
|
|
|
|
| 243 |
|
| 244 |
if status == 'completed':
|
| 245 |
c.execute('''UPDATE tasks
|
| 246 |
+
SET status = ?, output_file = ?, processed_at = ?, progress = 100, progress_text = 'Completed'
|
| 247 |
WHERE id = ?''',
|
| 248 |
(status, output_file, datetime.now().isoformat(), task_id))
|
| 249 |
elif status == 'failed':
|
| 250 |
c.execute('''UPDATE tasks
|
| 251 |
+
SET status = ?, error = ?, processed_at = ?, progress_text = 'Failed'
|
| 252 |
WHERE id = ?''',
|
| 253 |
(status, str(error), datetime.now().isoformat(), task_id))
|
| 254 |
else:
|
|
|
|
| 326 |
'output_file': row['output_file'],
|
| 327 |
'created_at': row['created_at'],
|
| 328 |
'processed_at': row['processed_at'],
|
| 329 |
+
'error': row['error'],
|
| 330 |
+
'progress': row['progress'] or 0,
|
| 331 |
+
'progress_text': row['progress_text']
|
| 332 |
}
|
| 333 |
|
| 334 |
# Add queue position for not_started tasks
|
index.html
CHANGED
|
@@ -350,6 +350,49 @@
|
|
| 350 |
color: var(--text);
|
| 351 |
}
|
| 352 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 353 |
.text-cell {
|
| 354 |
max-width: 300px;
|
| 355 |
overflow: hidden;
|
|
@@ -798,6 +841,24 @@
|
|
| 798 |
const escapedText = escapeHtml(file.text);
|
| 799 |
const truncatedText = file.text.length > 50 ? file.text.substring(0, 50) + '...' : file.text;
|
| 800 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 801 |
return `
|
| 802 |
<tr>
|
| 803 |
<td>
|
|
@@ -806,7 +867,7 @@
|
|
| 806 |
<button class="btn btn-small btn-view-text" onclick="showTextPopup(${index})">👁️ View</button>
|
| 807 |
</div>
|
| 808 |
</td>
|
| 809 |
-
<td
|
| 810 |
<td>
|
| 811 |
${file.status === 'completed' && file.output_file ?
|
| 812 |
`<a href="${API_URL}/download/${file.id}" class="btn btn-small btn-secondary" target="_blank">⬇️</a>`
|
|
|
|
| 350 |
color: var(--text);
|
| 351 |
}
|
| 352 |
|
| 353 |
+
/* Progress display */
|
| 354 |
+
.status-progress {
|
| 355 |
+
display: flex;
|
| 356 |
+
flex-direction: column;
|
| 357 |
+
gap: 0.3rem;
|
| 358 |
+
min-width: 120px;
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
.progress-bar-container {
|
| 362 |
+
width: 100%;
|
| 363 |
+
height: 6px;
|
| 364 |
+
background: rgba(0, 212, 255, 0.2);
|
| 365 |
+
border: 1px solid var(--accent);
|
| 366 |
+
overflow: hidden;
|
| 367 |
+
}
|
| 368 |
+
|
| 369 |
+
.progress-bar {
|
| 370 |
+
height: 100%;
|
| 371 |
+
background: linear-gradient(90deg, var(--primary), var(--accent));
|
| 372 |
+
transition: width 0.3s ease;
|
| 373 |
+
animation: progressPulse 1.5s ease-in-out infinite;
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
@keyframes progressPulse {
|
| 377 |
+
|
| 378 |
+
0%,
|
| 379 |
+
100% {
|
| 380 |
+
opacity: 1;
|
| 381 |
+
}
|
| 382 |
+
|
| 383 |
+
50% {
|
| 384 |
+
opacity: 0.7;
|
| 385 |
+
}
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
.progress-text {
|
| 389 |
+
font-size: 0.7rem;
|
| 390 |
+
color: var(--accent);
|
| 391 |
+
white-space: nowrap;
|
| 392 |
+
overflow: hidden;
|
| 393 |
+
text-overflow: ellipsis;
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
.text-cell {
|
| 397 |
max-width: 300px;
|
| 398 |
overflow: hidden;
|
|
|
|
| 841 |
const escapedText = escapeHtml(file.text);
|
| 842 |
const truncatedText = file.text.length > 50 ? file.text.substring(0, 50) + '...' : file.text;
|
| 843 |
|
| 844 |
+
// Build status display with progress
|
| 845 |
+
let statusDisplay = '';
|
| 846 |
+
if (file.status === 'processing') {
|
| 847 |
+
const progressPercent = file.progress || 0;
|
| 848 |
+
const progressText = file.progress_text || 'Processing...';
|
| 849 |
+
statusDisplay = `
|
| 850 |
+
<div class="status-progress">
|
| 851 |
+
<span class="status status-${file.status}">${progressPercent}%</span>
|
| 852 |
+
<div class="progress-bar-container">
|
| 853 |
+
<div class="progress-bar" style="width: ${progressPercent}%"></div>
|
| 854 |
+
</div>
|
| 855 |
+
<span class="progress-text">${escapeHtml(progressText)}</span>
|
| 856 |
+
</div>
|
| 857 |
+
`;
|
| 858 |
+
} else {
|
| 859 |
+
statusDisplay = `<span class="status status-${file.status}">${file.status.replace('_', ' ')}</span>`;
|
| 860 |
+
}
|
| 861 |
+
|
| 862 |
return `
|
| 863 |
<tr>
|
| 864 |
<td>
|
|
|
|
| 867 |
<button class="btn btn-small btn-view-text" onclick="showTextPopup(${index})">👁️ View</button>
|
| 868 |
</div>
|
| 869 |
</td>
|
| 870 |
+
<td>${statusDisplay}</td>
|
| 871 |
<td>
|
| 872 |
${file.status === 'completed' && file.output_file ?
|
| 873 |
`<a href="${API_URL}/download/${file.id}" class="btn btn-small btn-secondary" target="_blank">⬇️</a>`
|