File size: 6,785 Bytes
6203f3a 9722770 6203f3a 9722770 6203f3a 9722770 6203f3a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | import asyncio
import os
import subprocess
import re
import shutil
from app.core.config import settings
from app.db import crud
from custom_logger import logger_config as logger
_worker_task = None
async def start_worker():
global _worker_task
if _worker_task is None or _worker_task.done():
_worker_task = asyncio.create_task(worker_loop())
logger.info("TTS Worker background task started")
def is_worker_running():
return _worker_task is not None and not _worker_task.done()
async def worker_loop():
global _worker_task
logger.info("TTS Worker loop started. Monitoring for new tasks...")
while True:
try:
# Cleanup old entries
await crud.cleanup_old_entries()
# Get next unprocessed task
task = await crud.get_next_not_started()
if task:
task_id = task['id']
text = task['text']
filename = task['filename']
voice = task['voice'] or '4'
speed = task['speed'] or 1.0
logger.info(f"\n{'='*60}\nProcessing: {filename}\nID: {task_id}\n{'='*60}")
await crud.update_status(task_id, 'processing')
try:
await crud.update_progress(task_id, 5, "Initializing TTS...")
# Write text to content.txt
content_path = os.path.join(settings.CWD, 'content.txt')
with open(content_path, 'w', encoding='utf-8') as f:
f.write(text)
# Run TTS command
command = [
settings.PYTHON_PATH, "-m", "tts_runner.runner",
"--model", "chatterbox",
"--voice", str(voice),
"--speed", str(speed)
]
logger.debug(f"Executing command: {' '.join(command)}")
process = await asyncio.create_subprocess_exec(
*command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
cwd=settings.CWD,
env={
**os.environ,
'PYTHONUNBUFFERED': '1',
'CUDA_LAUNCH_BLOCKING': '1'
}
)
total_sentences = 0
current_sentence = 0
async for line in process.stdout:
line_str = line.decode('utf-8', errors='replace').strip()
if line_str:
logger.info(f"[TTS] {line_str}")
# Parse "Processing X text sentences"
total_match = re.search(r'Processing\s+(\d+)\s+text\s+sentences', line_str)
if total_match:
total_sentences = int(total_match.group(1))
# Parse "Sentence X processed" lines (handles both "X" and "X/Y" formats)
match = re.search(r'Sentence\s+(\d+)(?:/(\d+))?\s+processed', line_str)
if match:
current_sentence = int(match.group(1))
if match.group(2):
total_sentences = int(match.group(2))
if total_sentences > 0:
# Progress scales from 10% (model loaded) to 90% (start of combining)
progress = 10 + int((current_sentence / total_sentences) * 80)
await crud.update_progress(task_id, min(progress, 90), f"Processing sentence {current_sentence}/{total_sentences}")
# Parse "Sampling: X%" for granular progress
sampling_match = re.search(r'Sampling:\s+(\d+)%', line_str)
if sampling_match and total_sentences > 0:
sampling_pct = int(sampling_match.group(1))
progress = 10 + int((current_sentence / total_sentences) * 80) + int((sampling_pct / 100) * (1 / total_sentences) * 80)
await crud.update_progress(task_id, min(progress, 89), f"Synthesizing sentence {current_sentence + 1}/{total_sentences} ({sampling_pct}%)")
# Parse "Combining X audio files"
combine_match = re.search(r'Combining\s+(\d+)\s+audio\s+files', line_str)
if combine_match:
total_sentences = int(combine_match.group(1))
await crud.update_progress(task_id, 90, "Combining audio files...")
if 'Model loaded successfully' in line_str:
await crud.update_progress(task_id, 10, "Model ready, starting synthesis...")
await process.wait()
if process.returncode == 0:
output_filename = "output_audio.wav"
if os.path.exists(output_filename):
target_filename = f"{task_id}.wav"
target_path = os.path.join(settings.UPLOAD_FOLDER, target_filename)
shutil.move(output_filename, target_path)
logger.success(f"Successfully processed: {filename}")
await crud.update_status(task_id, 'completed', output_file=target_filename)
else:
raise Exception("Output audio file not found")
else:
raise Exception(f"TTS process failed with return code {process.returncode}")
except Exception as e:
logger.error(f"Failed to process {filename}: {str(e)}")
await crud.update_status(task_id, 'failed', error=str(e))
else:
await asyncio.sleep(settings.POLL_INTERVAL)
except Exception as e:
logger.error(f"Worker error: {str(e)}")
await asyncio.sleep(settings.POLL_INTERVAL)
|