diff --git a/backend/backends/chatterbox_backend.py b/backend/backends/chatterbox_backend.py index ed264e4d..bd6170b7 100644 --- a/backend/backends/chatterbox_backend.py +++ b/backend/backends/chatterbox_backend.py @@ -224,7 +224,8 @@ class ChatterboxTTSBackend: task_manager.error_download(model_name, str(e)) raise except Exception as e: - logger.error(f"Failed to load Chatterbox: {e}") + import traceback + logger.error(f"Failed to load Chatterbox: {e}\n{traceback.format_exc()}") if not is_cached: progress_manager.mark_error(model_name, str(e)) task_manager.error_download(model_name, str(e)) diff --git a/backend/backends/chatterbox_turbo_backend.py b/backend/backends/chatterbox_turbo_backend.py index a87441a0..4971b8e9 100644 --- a/backend/backends/chatterbox_turbo_backend.py +++ b/backend/backends/chatterbox_turbo_backend.py @@ -228,7 +228,8 @@ class ChatterboxTurboTTSBackend: task_manager.error_download(model_name, str(e)) raise except Exception as e: - logger.error(f"Failed to load Chatterbox Turbo: {e}") + import traceback + logger.error(f"Failed to load Chatterbox Turbo: {e}\n{traceback.format_exc()}") if not is_cached: progress_manager.mark_error(model_name, str(e)) task_manager.error_download(model_name, str(e)) diff --git a/backend/backends/luxtts_backend.py b/backend/backends/luxtts_backend.py index 549e44ff..c289904f 100644 --- a/backend/backends/luxtts_backend.py +++ b/backend/backends/luxtts_backend.py @@ -149,7 +149,8 @@ class LuxTTSBackend: logger.info("LuxTTS loaded successfully") except Exception as e: - logger.error(f"Failed to load LuxTTS: {e}") + import traceback + logger.error(f"Failed to load LuxTTS: {e}\n{traceback.format_exc()}") if not is_cached: progress_manager.mark_error(model_name, str(e)) task_manager.error_download(model_name, str(e)) diff --git a/backend/server.py b/backend/server.py index 529e1e75..8dd970b3 100644 --- a/backend/server.py +++ b/backend/server.py @@ -9,10 +9,21 @@ import sys import os # On Windows with --noconsole (PyInstaller), sys.stdout/stderr are None. +# They can also be broken file objects in some edge cases. # Redirect to devnull to prevent crashes from print()/tqdm/logging. -if sys.stdout is None: +def _is_writable(stream): + """Check if a stream is usable for writing.""" + if stream is None: + return False + try: + stream.write("") + return True + except Exception: + return False + +if not _is_writable(sys.stdout): sys.stdout = open(os.devnull, 'w') -if sys.stderr is None: +if not _is_writable(sys.stderr): sys.stderr = open(os.devnull, 'w') # Fast path: handle --version before any heavy imports so the Rust diff --git a/backend/utils/hf_progress.py b/backend/utils/hf_progress.py index 7fc88edd..f1f107bc 100644 --- a/backend/utils/hf_progress.py +++ b/backend/utils/hf_progress.py @@ -64,11 +64,17 @@ class HFProgressTracker: if key in tqdm_kwargs: filtered_kwargs[key] = value + # Force-enable the progress bar — we're tracking progress ourselves, + # we don't need tqdm to render to a terminal, but we DO need + # self.n to be updated when update() is called. + filtered_kwargs['disable'] = False + # Try to initialize with filtered kwargs, fall back to all kwargs if that fails try: super().__init__(*args, **filtered_kwargs) except TypeError: # If filtering failed, try with all kwargs (maybe tqdm version accepts them) + kwargs['disable'] = False super().__init__(*args, **kwargs) self._tracker_filename = filename or "unknown" diff --git a/backend/voicebox-server.spec b/backend/voicebox-server.spec index 4d6b2df0..6a7dc6d3 100644 --- a/backend/voicebox-server.spec +++ b/backend/voicebox-server.spec @@ -6,13 +6,23 @@ from PyInstaller.utils.hooks import copy_metadata datas = [] binaries = [] -hiddenimports = ['backend', 'backend.main', 'backend.config', 'backend.database', 'backend.models', 'backend.profiles', 'backend.history', 'backend.tts', 'backend.transcribe', 'backend.platform_detect', 'backend.backends', 'backend.backends.pytorch_backend', 'backend.utils.audio', 'backend.utils.cache', 'backend.utils.progress', 'backend.utils.hf_progress', 'backend.utils.validation', 'backend.cuda_download', 'backend.effects', 'backend.utils.effects', 'backend.versions', 'pedalboard', 'torch', 'transformers', 'fastapi', 'uvicorn', 'sqlalchemy', 'librosa', 'soundfile', 'qwen_tts', 'qwen_tts.inference', 'qwen_tts.inference.qwen3_tts_model', 'qwen_tts.inference.qwen3_tts_tokenizer', 'qwen_tts.core', 'qwen_tts.cli', 'pkg_resources.extern', 'backend.backends.mlx_backend', 'mlx', 'mlx.core', 'mlx.nn', 'mlx_audio', 'mlx_audio.tts', 'mlx_audio.stt'] +hiddenimports = ['backend', 'backend.main', 'backend.config', 'backend.database', 'backend.models', 'backend.profiles', 'backend.history', 'backend.tts', 'backend.transcribe', 'backend.platform_detect', 'backend.backends', 'backend.backends.pytorch_backend', 'backend.utils.audio', 'backend.utils.cache', 'backend.utils.progress', 'backend.utils.hf_progress', 'backend.utils.validation', 'backend.cuda_download', 'backend.effects', 'backend.utils.effects', 'backend.versions', 'pedalboard', 'chatterbox', 'chatterbox.tts_turbo', 'chatterbox.mtl_tts', 'backend.backends.chatterbox_backend', 'backend.backends.chatterbox_turbo_backend', 'backend.backends.luxtts_backend', 'zipvoice', 'zipvoice.luxvoice', 'torch', 'transformers', 'fastapi', 'uvicorn', 'sqlalchemy', 'librosa', 'soundfile', 'qwen_tts', 'qwen_tts.inference', 'qwen_tts.inference.qwen3_tts_model', 'qwen_tts.inference.qwen3_tts_tokenizer', 'qwen_tts.core', 'qwen_tts.cli', 'requests', 'pkg_resources.extern', 'backend.backends.mlx_backend', 'mlx', 'mlx.core', 'mlx.nn', 'mlx_audio', 'mlx_audio.tts', 'mlx_audio.stt'] datas += collect_data_files('qwen_tts') datas += copy_metadata('qwen-tts') +datas += copy_metadata('requests') +datas += copy_metadata('transformers') +datas += copy_metadata('huggingface-hub') +datas += copy_metadata('tokenizers') +datas += copy_metadata('safetensors') +datas += copy_metadata('tqdm') hiddenimports += collect_submodules('qwen_tts') hiddenimports += collect_submodules('jaraco') hiddenimports += collect_submodules('mlx') hiddenimports += collect_submodules('mlx_audio') +tmp_ret = collect_all('zipvoice') +datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2] +tmp_ret = collect_all('linacodec') +datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2] tmp_ret = collect_all('mlx') datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2] tmp_ret = collect_all('mlx_audio')