aboutsummaryrefslogtreecommitdiff
path: root/converter
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-20 23:50:37 -0400
committerhistoria <historiavg@proton.me>2026-08-20 23:50:37 -0400
commit38c8fdcba7ce54ad0ad76be9ef0748df1c55ebc1 (patch)
tree911e031ee0e4b902fcd3954df3838a920416e8a3 /converter
parent5c3df0a434059bd0d541bda35a51e49e3c44dd55 (diff)
downloadtts-audiobook-generator-38c8fdcba7ce54ad0ad76be9ef0748df1c55ebc1.tar.gz
feat: make_audiocpp_server_json.py takes an argument. remove chunk wording with audiocpp backend.
Diffstat (limited to 'converter')
-rw-r--r--converter/audio.py14
-rw-r--r--converter/converter.py40
-rw-r--r--converter/tts.py16
3 files changed, 52 insertions, 18 deletions
diff --git a/converter/audio.py b/converter/audio.py
index 01f78ab..d1dc28b 100644
--- a/converter/audio.py
+++ b/converter/audio.py
@@ -425,11 +425,19 @@ def combine_chunks(total_chunks: int, output_path: Path,
if intermediate:
logger.info("Chapter audio saved (intermediate): %s (%d/%d chunks)",
output_path, len(chunk_files), total_chunks)
- print(f"[INFO] Saved chapter audio (intermediate): {output_path.name} "
- f"({len(chunk_files)}/{total_chunks} chunks)")
+ if len(chunk_files) == 1 and total_chunks == 1:
+ print(f"[INFO] Saved chapter audio (intermediate): "
+ f"{output_path.name}")
+ else:
+ print(f"[INFO] Saved chapter audio (intermediate): {output_path.name} "
+ f"({len(chunk_files)}/{total_chunks} chunks)")
else:
logger.info("Audiobook saved: %s (%d/%d chunks)", output_path, len(chunk_files), total_chunks)
- print(f"[INFO] Saved audiobook: {output_path.name} ({len(chunk_files)}/{total_chunks} chunks)")
+ if len(chunk_files) == 1 and total_chunks == 1:
+ print(f"[INFO] Saved audiobook: {output_path.name}")
+ else:
+ print(f"[INFO] Saved audiobook: {output_path.name} "
+ f"({len(chunk_files)}/{total_chunks} chunks)")
if speed_path is not None:
logger.info("Saved speed-adjusted audiobook (%gx): %s", speed, speed_path)
diff --git a/converter/converter.py b/converter/converter.py
index de302ad..0ae1506 100644
--- a/converter/converter.py
+++ b/converter/converter.py
@@ -410,9 +410,10 @@ class AudiobookConverter:
also dumped there, and every request/response is logged.
"""
total_chunks = len(chunks)
- print(f"\n{'=' * 50}")
- print(f"PROCESSING {total_chunks} CHUNKS")
- print(f"{'=' * 50}")
+ if self.client_chunks:
+ print(f"\n{'=' * 50}")
+ print(f"PROCESSING {total_chunks} CHUNKS")
+ print(f"{'=' * 50}")
results: Dict[int, Optional[Path]] = {}
for chunk_num, chunk_text in enumerate(chunks, 1):
@@ -433,7 +434,8 @@ class AudiobookConverter:
destination = f" -> {copied.name}" if copied else ""
logger.debug("Chunk %d/%d response in %.1fs%s",
chunk_num, total_chunks, elapsed, destination)
- print(f"[OK] Chunk {chunk_num:3d}/{total_chunks} completed")
+ if self.client_chunks:
+ print(f"[OK] Chunk {chunk_num:3d}/{total_chunks} completed")
logger.info("+ Chunk %d/%d completed", chunk_num, total_chunks)
else:
logger.error("Chunk %d/%d failed", chunk_num, total_chunks)
@@ -443,10 +445,11 @@ class AudiobookConverter:
logger.error("Chunk %d/%d error: %s", chunk_num, total_chunks, exc)
successful_chunks = sum(1 for path in results.values() if path)
- print(f"\n{'=' * 50}")
- print("CHUNK PROCESSING COMPLETE")
- print(f"Successful: {successful_chunks}/{total_chunks}")
- print(f"{'=' * 50}")
+ if self.client_chunks:
+ print(f"\n{'=' * 50}")
+ print("CHUNK PROCESSING COMPLETE")
+ print(f"Successful: {successful_chunks}/{total_chunks}")
+ print(f"{'=' * 50}")
logger.info("Chunk processing completed: %d/%d chunks", successful_chunks, total_chunks)
return results
@@ -508,7 +511,19 @@ class AudiobookConverter:
BACKEND_AUDIOCPP: "audio.cpp server",
}
backend = backend_labels.get(self.backend, "Qwen API")
- print(f"[INFO] Processing {total_chunks} chunks via {backend}...")
+ if self.client_chunks:
+ print(f"[INFO] Processing {total_chunks} chunks via {backend}...")
+ else:
+ # The whole request is sent at once and the server does its
+ # own long-form chunking, so the chunk vocabulary does not
+ # apply; warn that this one request can take a very long time.
+ subject = (f"chapter {chapter[0]}/{chapter[1]}"
+ if chapter is not None else "text")
+ print(f"[INFO] Sending the {subject} to the {backend} as a "
+ "single request...")
+ print("[NOTE] It is expected for this to take a very long "
+ "time: the server synthesizes the entire request before "
+ "returning any audio.")
results = self._synthesize_chunks(chunks, debug_dir=debug_dir)
successful_chunks = sum(1 for path in results.values() if path)
@@ -534,8 +549,11 @@ class AudiobookConverter:
logger.info("Chapter %d/%d converted in %dm %ds (%d/%d chunks)",
chapter[0], chapter[1], minutes, seconds,
successful_chunks, total_chunks)
- print(f"[INFO] Chapter {chapter[0]}/{chapter[1]} converted "
- f"({successful_chunks}/{total_chunks} chunks)")
+ if self.client_chunks:
+ print(f"[INFO] Chapter {chapter[0]}/{chapter[1]} converted "
+ f"({successful_chunks}/{total_chunks} chunks)")
+ else:
+ print(f"[INFO] Chapter {chapter[0]}/{chapter[1]} converted")
else:
logger.info("Conversion completed in %dm %ds: %s", minutes, seconds, output_path)
else:
diff --git a/converter/tts.py b/converter/tts.py
index 1a41643..0d867a2 100644
--- a/converter/tts.py
+++ b/converter/tts.py
@@ -363,15 +363,21 @@ class _BaseTTSClient:
return None
@contextlib.contextmanager
- def _chunk_heartbeat(self, chunk_num: int):
- """Print a periodic "still working" message while a chunk generates."""
+ def _chunk_heartbeat(self, chunk_num: int, label: Optional[str] = None):
+ """Print a periodic "still working" message while a request generates.
+
+ ``label`` overrides the default "Chunk {chunk_num}" subject, for
+ backends that send one request per chapter without client-side
+ chunking (the audio.cpp default) where "chunk" would be misleading.
+ """
stop = threading.Event()
+ subject = label if label is not None else f"Chunk {chunk_num}"
def _beat():
start = time.time()
while not stop.wait(config.HEARTBEAT_INTERVAL_SECONDS):
elapsed = time.time() - start
- print(f"[...] Chunk {chunk_num} still generating — "
+ print(f"[...] {subject} still generating — "
f"{int(elapsed // 60)}m {int(elapsed % 60)}s elapsed", flush=True)
thread = threading.Thread(target=_beat, daemon=True)
@@ -1170,7 +1176,9 @@ class AudioCppTTSClient(_BaseTTSClient):
output_path: Optional[Path] = None
with tempfile.TemporaryDirectory(prefix="tts_parts_") as parts_dir, \
- self._chunk_heartbeat(chunk_num):
+ self._chunk_heartbeat(
+ chunk_num,
+ label=None if self.chunk_text else "Request"):
part_paths = []
for sub_num, sub_text in enumerate(sub_texts, 1):
wav = self._request_wav_with_retry(