aboutsummaryrefslogtreecommitdiff
path: root/app/converter
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-24 16:08:33 -0400
committerhistoria <historiavg@proton.me>2026-08-24 16:08:33 -0400
commit1ff9a635bd9b033b631a6b525891b7eb44e189d3 (patch)
tree6dbcd7e682d516770be4c0724db793666c93dd5f /app/converter
parentafd1c67d92c7f32389d5f652b9fa71530538a16f (diff)
downloadtts-audiobook-generator-1ff9a635bd9b033b631a6b525891b7eb44e189d3.tar.gz
feat: clearer split between local (managed) and remote URLs and server status
Diffstat (limited to 'app/converter')
-rw-r--r--app/converter/config.py11
-rw-r--r--app/converter/converter.py16
-rw-r--r--app/converter/tts.py15
3 files changed, 32 insertions, 10 deletions
diff --git a/app/converter/config.py b/app/converter/config.py
index 5e35ee3..9f70a73 100644
--- a/app/converter/config.py
+++ b/app/converter/config.py
@@ -25,6 +25,15 @@ BACKEND = "audiocpp"
QWEN_API_URL = "http://127.0.0.1:7860" # CustomVoice model
CLONE_API_URL = "http://127.0.0.1:7861" # Base model
+# Remote (externally-run) server URLs. The hub probes these and offers a
+# "[remote]" backend entry when one answers with the expected backend, so an
+# externally-started server can be used alongside a locally-managed one.
+# Leave empty to disable remote probing for that backend. The defaults match
+# the local ports so an external server squatting the local port is found
+# without any configuration.
+QWEN_REMOTE_URL = "http://127.0.0.1:7860" # CustomVoice model
+CLONE_REMOTE_URL = "http://127.0.0.1:7861" # Base model
+
# Custom voice options
SPEAKER = "Vivian" #Vivian, Serena, Uncle_Fu, Dylan, Eric, Ryan, Aiden, Ono_Anna, Sohee
INSTRUCT = "Speak naturally and clearly, as if reading a dramatic book to an adult audience."
@@ -42,6 +51,7 @@ CONSTANT_SEED = False
# BACKEND 2: faster-qwen-tts options #
###############################################################################
FASTER_API_URL = "http://127.0.0.1:8000" # faster-qwen3-tts server (Base model only)
+FASTER_REMOTE_URL = "http://127.0.0.1:8000" # externally-run faster-qwen3-tts server ("" disables probing)
# Default voice if no --voice is passed
FASTER_VOICE = "default"
@@ -50,6 +60,7 @@ FASTER_VOICE = "default"
# BACKEND 3: audio.cpp options #
###############################################################################
AUDIOCPP_API_URL = "http://127.0.0.1:8080" # audio.cpp audiocpp_server
+AUDIOCPP_REMOTE_URL = "http://127.0.0.1:8080" # externally-run audiocpp_server ("" disables probing)
# Model ids in the audio.cpp server.json config. AUDIOCPP_MODEL_ID may point
# at any TTS model entry the server hosts (qwen3_tts, higgs_audio_tts,
diff --git a/app/converter/converter.py b/app/converter/converter.py
index 4c1ffad..5f67f4a 100644
--- a/app/converter/converter.py
+++ b/app/converter/converter.py
@@ -142,7 +142,8 @@ class AudiobookConverter:
voice: Optional[str] = None, debug: bool = False,
model_id: Optional[str] = None,
instructions: Optional[str] = None,
- request_options: Optional[Dict[str, str]] = None):
+ request_options: Optional[Dict[str, str]] = None,
+ api_url: Optional[str] = None):
if speed <= 0:
raise ValueError(f"Speed must be a positive number, got {speed}")
if output_format not in AUDIO_FORMATS:
@@ -171,7 +172,7 @@ class AudiobookConverter:
if backend == BACKEND_FASTER:
# The faster backend always voice-clones using a reference voice
# configured on the server, so no local reference audio is needed.
- self.tts = FasterTTSClient(voice=voice)
+ self.tts = FasterTTSClient(voice=voice, api_url=api_url)
elif backend == BACKEND_AUDIOCPP:
# Speaker mode (no voice) uses a built-in CustomVoice speaker;
# an explicit voice selects a server-side preset (cloning).
@@ -181,7 +182,8 @@ class AudiobookConverter:
self.tts = AudioCppTTSClient(voice=voice, language=self.language,
model_id=model_id,
instructions=instructions,
- request_options=self.request_options)
+ request_options=self.request_options,
+ api_url=api_url)
else:
self.tts = QwenTTSClient(
voice_mode=voice_mode,
@@ -189,6 +191,7 @@ class AudiobookConverter:
voice_clone_ref_text=voice_clone_ref_text,
skip_transcription=skip_transcription,
language=self.language,
+ api_url=api_url,
)
def _validate_configuration(self) -> None:
@@ -585,8 +588,11 @@ class AudiobookConverter:
print(f"Request options: {self.request_options}")
print(f"Language: {self.language}")
else:
- api_url = (config.CLONE_API_URL if self.voice_mode == VOICE_MODE_CLONE
- else config.QWEN_API_URL)
+ tts_client = getattr(self, "tts", None)
+ api_url = (getattr(tts_client, "api_url", None)
+ or (config.CLONE_API_URL
+ if self.voice_mode == VOICE_MODE_CLONE
+ else config.QWEN_API_URL))
print(f"Qwen API endpoint: {api_url}")
print(f"Voice mode: {self.voice_mode}")
print(f"Model size: {MODEL_SIZE} (always)")
diff --git a/app/converter/tts.py b/app/converter/tts.py
index a90dbbe..41e3aa5 100644
--- a/app/converter/tts.py
+++ b/app/converter/tts.py
@@ -348,7 +348,7 @@ class QwenTTSClient(_BaseTTSClient):
def __init__(self, voice_mode: str = "custom_voice", voice_clone_ref_audio: Optional[str] = None,
voice_clone_ref_text: Optional[str] = None, skip_transcription: bool = False,
- language: Optional[str] = None):
+ language: Optional[str] = None, api_url: Optional[str] = None):
if voice_mode not in VOICE_MODES:
raise ValueError(
f"Unknown voice mode: {voice_mode!r} (expected one of {VOICE_MODES})"
@@ -357,6 +357,9 @@ class QwenTTSClient(_BaseTTSClient):
self.voice_clone_ref_audio = voice_clone_ref_audio
self.voice_clone_ref_text = (voice_clone_ref_text or "").strip()
self.skip_transcription = skip_transcription
+ # api_url overrides the configured endpoint for the active voice mode
+ # (used by the hub's "[remote]" backend entries and --api-url).
+ self.api_url = (api_url or "").strip() or None
# Seed sent with every request: config.SEED as-is, or (with
# CONSTANT_SEED and SEED < 0) one random value drawn per run and
# reused for every request so the voice stays consistent across
@@ -379,16 +382,18 @@ class QwenTTSClient(_BaseTTSClient):
# ------------------------------------------------------------------
def _connect(self) -> None:
- api_url = config.CLONE_API_URL if self.voice_mode == VOICE_MODE_CLONE else config.QWEN_API_URL
+ api_url = self.api_url or (
+ config.CLONE_API_URL if self.voice_mode == VOICE_MODE_CLONE
+ else config.QWEN_API_URL)
try:
if self.voice_mode == VOICE_MODE_CLONE:
# Voice clone uses the Base-model demo, which is a separate server
# from the CustomVoice demo (that one only exposes /run_instruct).
- self._init_client(config.CLONE_API_URL, clone=True)
- print(f"[OK] Connected to Voice Clone API at {config.CLONE_API_URL}")
+ self._init_client(api_url, clone=True)
+ print(f"[OK] Connected to Voice Clone API at {api_url}")
self._resolve_reference_text()
else:
- self._init_client(config.QWEN_API_URL, clone=False)
+ self._init_client(api_url, clone=False)
print("[OK] Connected to Qwen API")
except Exception as exc:
raise RuntimeError(