feat: Enhance voice resolution and logging in conversion job for improved feedback and performance

This commit is contained in:
JB
2025-10-06 14:04:17 -07:00
parent b75e1c1b2e
commit 7d132e6fcc
+52 -14
View File
@@ -79,11 +79,15 @@ def run_conversion_job(job: Job) -> None:
chapter_dir = audio_dir / "chapters" chapter_dir = audio_dir / "chapters"
chapter_dir.mkdir(parents=True, exist_ok=True) chapter_dir.mkdir(parents=True, exist_ok=True)
voice = _resolve_voice(pipeline, job) voice_spec = job.voice or ""
cached_voice = None
if "*" not in voice_spec:
cached_voice = _resolve_voice(pipeline, voice_spec, job.use_gpu)
processed_chars = 0 processed_chars = 0
subtitle_index = 1 subtitle_index = 1
current_time = 0.0 current_time = 0.0
total_chapters = len(extraction.chapters) total_chapters = len(extraction.chapters)
job.add_log(f"Detected {total_chapters} chapter{'s' if total_chapters != 1 else ''}")
for idx, chapter in enumerate(extraction.chapters, start=1): for idx, chapter in enumerate(extraction.chapters, start=1):
canceller() canceller()
@@ -106,18 +110,27 @@ def run_conversion_job(job: Job) -> None:
fmt=job.separate_chapters_format, fmt=job.separate_chapters_format,
) )
voice_choice = cached_voice if cached_voice is not None else _resolve_voice(
pipeline, voice_spec, job.use_gpu
)
segments_emitted = 0
for segment in pipeline( for segment in pipeline(
chapter.text, chapter.text,
voice=voice, voice=voice_choice,
speed=job.speed, speed=job.speed,
split_pattern=SPLIT_PATTERN, split_pattern=SPLIT_PATTERN,
): ):
canceller() canceller()
graphemes = segment.graphemes.strip() graphemes_raw = getattr(segment, "graphemes", "") or ""
if not graphemes: graphemes = graphemes_raw.strip()
audio = _to_float32(getattr(segment, "audio", None))
if audio.size == 0:
continue continue
audio = _to_float32(segment.audio) segments_emitted += 1
if chapter_sink: if chapter_sink:
chapter_sink.write(audio) chapter_sink.write(audio)
if audio_sink: if audio_sink:
@@ -128,9 +141,13 @@ def run_conversion_job(job: Job) -> None:
job.processed_characters = processed_chars job.processed_characters = processed_chars
if job.total_characters: if job.total_characters:
job.progress = min(processed_chars / job.total_characters, 0.999) job.progress = min(processed_chars / job.total_characters, 0.999)
job.add_log(f"{processed_chars:,}/{job.total_characters or ''}: {graphemes[:80]}") else:
job.progress = 0.0 if processed_chars == 0 else 0.999
if subtitle_writer and audio_sink: preview_text = graphemes or (graphemes_raw[:80] if graphemes_raw else "[silence]")
job.add_log(f"{processed_chars:,}/{job.total_characters or ''}: {preview_text[:80]}")
if subtitle_writer and audio_sink and graphemes:
subtitle_writer.write_segment( subtitle_writer.write_segment(
index=subtitle_index, index=subtitle_index,
text=graphemes, text=graphemes,
@@ -144,9 +161,19 @@ def run_conversion_job(job: Job) -> None:
if chapter_sink: if chapter_sink:
chapter_sink_stack.close() chapter_sink_stack.close()
if chapter_audio_path is not None:
job.result.artifacts[f"chapter_{idx:02d}"] = chapter_audio_path job.result.artifacts[f"chapter_{idx:02d}"] = chapter_audio_path
chapter_paths.append(chapter_audio_path) chapter_paths.append(chapter_audio_path)
if segments_emitted == 0:
job.add_log(
f"No audio segments were generated for chapter {idx}.",
level="warning",
)
else:
job.add_log(f"Finished chapter {idx} with {segments_emitted} segments.")
if ( if (
audio_sink audio_sink
and job.merge_chapters_at_end and job.merge_chapters_at_end
@@ -340,16 +367,27 @@ def _build_ffmpeg_command(path: Path, fmt: str, metadata: Optional[Dict[str, str
return base return base
def _resolve_voice(pipeline, job: Job): def _resolve_voice(pipeline, voice_spec: str, use_gpu: bool):
if "*" in job.voice: if "*" in voice_spec:
return get_new_voice(pipeline, job.voice, job.use_gpu) return get_new_voice(pipeline, voice_spec, use_gpu)
return job.voice return voice_spec
def _to_float32(audio_segment) -> np.ndarray: def _to_float32(audio_segment) -> np.ndarray:
if hasattr(audio_segment, "numpy"): if audio_segment is None:
return audio_segment.numpy().astype("float32") return np.zeros(0, dtype="float32")
return np.asarray(audio_segment, dtype="float32")
tensor = audio_segment
if hasattr(tensor, "detach"):
tensor = tensor.detach()
if hasattr(tensor, "cpu"):
try:
tensor = tensor.cpu()
except Exception:
pass
if hasattr(tensor, "numpy"):
return np.asarray(tensor.numpy(), dtype="float32").reshape(-1)
return np.asarray(tensor, dtype="float32").reshape(-1)
class SubtitleWriter: class SubtitleWriter: