mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-04-25 11:18:22 +00:00
fix: add error handling for podcast generation failures (#1257)
* fix: add error handling for podcast generation failures When TTS processing fails, the system was generating 0-second audio files without any error indication. This fix adds: 1. Track failed TTS lines and log warning with indices 2. Raise ValueError when all TTS generation fails with helpful message 3. Check for empty audio output in mix_audio and raise error 4. Log success/failure ratio for debugging Fixes #30 * fix: address Copilot review feedback - Use `not audio` to catch both None and empty bytes - Log failed lines with 1-based indices for user-friendly output - Handle empty script case with clear error message - Validate env vars before ThreadPoolExecutor for fast-fail on config errors --------- Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
parent
3be1d841aa
commit
79acc3939a
@ -123,15 +123,37 @@ def tts_node(script: Script, max_workers: int = 4) -> list[bytes]:
|
|||||||
logger.info(f"Converting script to audio using {max_workers} workers...")
|
logger.info(f"Converting script to audio using {max_workers} workers...")
|
||||||
|
|
||||||
total = len(script.lines)
|
total = len(script.lines)
|
||||||
|
|
||||||
|
# Handle empty script case
|
||||||
|
if total == 0:
|
||||||
|
raise ValueError("Script contains no lines to process")
|
||||||
|
|
||||||
|
# Validate required environment variables before starting TTS
|
||||||
|
if not os.getenv("VOLCENGINE_TTS_APPID") or not os.getenv("VOLCENGINE_TTS_ACCESS_TOKEN"):
|
||||||
|
raise ValueError(
|
||||||
|
"Missing required environment variables: VOLCENGINE_TTS_APPID and VOLCENGINE_TTS_ACCESS_TOKEN must be set"
|
||||||
|
)
|
||||||
|
|
||||||
tasks = [(i, line, total) for i, line in enumerate(script.lines)]
|
tasks = [(i, line, total) for i, line in enumerate(script.lines)]
|
||||||
|
|
||||||
# Use ThreadPoolExecutor for parallel TTS generation
|
# Use ThreadPoolExecutor for parallel TTS generation
|
||||||
results: dict[int, Optional[bytes]] = {}
|
results: dict[int, Optional[bytes]] = {}
|
||||||
|
failed_indices: list[int] = []
|
||||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||||
futures = {executor.submit(_process_line, task): task[0] for task in tasks}
|
futures = {executor.submit(_process_line, task): task[0] for task in tasks}
|
||||||
for future in as_completed(futures):
|
for future in as_completed(futures):
|
||||||
idx, audio = future.result()
|
idx, audio = future.result()
|
||||||
results[idx] = audio
|
results[idx] = audio
|
||||||
|
# Use `not audio` to catch both None and empty bytes
|
||||||
|
if not audio:
|
||||||
|
failed_indices.append(idx)
|
||||||
|
|
||||||
|
# Log failed lines with 1-based indices for user-friendly output
|
||||||
|
if failed_indices:
|
||||||
|
logger.warning(
|
||||||
|
f"Failed to generate audio for {len(failed_indices)}/{total} lines: "
|
||||||
|
f"line numbers {sorted(i + 1 for i in failed_indices)}"
|
||||||
|
)
|
||||||
|
|
||||||
# Collect results in order, skipping failed ones
|
# Collect results in order, skipping failed ones
|
||||||
audio_chunks = []
|
audio_chunks = []
|
||||||
@ -140,15 +162,30 @@ def tts_node(script: Script, max_workers: int = 4) -> list[bytes]:
|
|||||||
if audio:
|
if audio:
|
||||||
audio_chunks.append(audio)
|
audio_chunks.append(audio)
|
||||||
|
|
||||||
logger.info(f"Generated {len(audio_chunks)} audio chunks")
|
logger.info(f"Generated {len(audio_chunks)}/{total} audio chunks successfully")
|
||||||
|
|
||||||
|
if not audio_chunks:
|
||||||
|
raise ValueError(
|
||||||
|
f"TTS generation failed for all {total} lines. "
|
||||||
|
"Please check VOLCENGINE_TTS_APPID and VOLCENGINE_TTS_ACCESS_TOKEN environment variables."
|
||||||
|
)
|
||||||
|
|
||||||
return audio_chunks
|
return audio_chunks
|
||||||
|
|
||||||
|
|
||||||
def mix_audio(audio_chunks: list[bytes]) -> bytes:
|
def mix_audio(audio_chunks: list[bytes]) -> bytes:
|
||||||
"""Combine audio chunks into a single audio file."""
|
"""Combine audio chunks into a single audio file."""
|
||||||
logger.info("Mixing audio chunks...")
|
logger.info("Mixing audio chunks...")
|
||||||
|
|
||||||
|
if not audio_chunks:
|
||||||
|
raise ValueError("No audio chunks to mix - TTS generation may have failed")
|
||||||
|
|
||||||
output = b"".join(audio_chunks)
|
output = b"".join(audio_chunks)
|
||||||
logger.info("Audio mixing complete")
|
|
||||||
|
if len(output) == 0:
|
||||||
|
raise ValueError("Mixed audio is empty - TTS generation may have failed")
|
||||||
|
|
||||||
|
logger.info(f"Audio mixing complete: {len(output)} bytes")
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user