Spaces:
Sleeping
Sleeping
| # app.py | |
| from app.gradio_app import build_demo | |
| from models.tts_router import cleanup_old_audio | |
| import os | |
| import shutil | |
| import stat | |
| import huggingface_hub | |
| from shutil import which | |
| # ----------------------------- | |
| # Model: ensure GGUF is present | |
| # ----------------------------- | |
| def ensure_model() -> str: | |
| """ | |
| Download the GGUF model into ./models if not already present. | |
| Requires in environment: | |
| - LLAMACPP_MODEL_PATH (target path including filename) | |
| - HF_MODEL_REPO (e.g. Qwen/Qwen2.5-1.5B-Instruct-GGUF) | |
| - HF_MODEL_FILE (e.g. qwen2.5-1.5b-instruct-q4_k_m.gguf) | |
| """ | |
| model_path = os.getenv("LLAMACPP_MODEL_PATH") | |
| repo_id = os.getenv("HF_MODEL_REPO") | |
| filename = os.getenv("HF_MODEL_FILE") or (os.path.basename(model_path) if model_path else None) | |
| if not model_path or not repo_id or not filename: | |
| raise RuntimeError("Missing config: set LLAMACPP_MODEL_PATH and HF_MODEL_REPO (optionally HF_MODEL_FILE).") | |
| if os.path.exists(model_path): | |
| print(f"[MODEL] Found existing model at {model_path}") | |
| return model_path | |
| os.makedirs(os.path.dirname(model_path), exist_ok=True) | |
| print(f"[MODEL] Downloading {filename} from {repo_id} …") | |
| local_path = huggingface_hub.hf_hub_download( | |
| repo_id=repo_id, | |
| filename=filename, | |
| local_dir=os.path.dirname(model_path), | |
| local_dir_use_symlinks=False, | |
| ) | |
| # If hf_hub_download wrote elsewhere (cache), move/rename into desired path | |
| if os.path.abspath(local_path) != os.path.abspath(model_path): | |
| shutil.copyfile(local_path, model_path) | |
| print(f"[MODEL] Ready at {model_path}") | |
| return model_path | |
| def _ensure_exec(fp: str): | |
| if fp and os.path.exists(fp): | |
| try: | |
| os.chmod(fp, 0o755) | |
| except Exception as e: | |
| print("[WARN] chmod failed for", fp, e) | |
| def log_env_for_audio(): | |
| print("[ENV] TTS_ENGINE =", os.getenv("TTS_ENGINE", "(unset)")) | |
| print("[ENV] PIPER_MODEL=", os.getenv("PIPER_MODEL", "(unset)")) | |
| print("[ENV] PIPER_BIN =", os.getenv("PIPER_BIN", "(unset)")) | |
| import os, stat | |
| def ensure_piper_ready(): | |
| bin_path = os.getenv("PIPER_BIN", "piper") | |
| model = os.getenv("PIPER_MODEL") | |
| espeak = os.getenv("ESPEAK_DATA_PATH") | |
| print(f"[PIPER] BIN={bin_path} exists={os.path.exists(bin_path)}") | |
| print(f"[PIPER] MODEL={model} exists={os.path.exists(model) if model else None}") | |
| print(f"[PIPER] ESPEAK_DATA_PATH={espeak} exists={os.path.exists(espeak) if espeak else None}") | |
| # If PIPER_BIN is an absolute/relative file in repo, make it executable. | |
| if bin_path and os.path.isfile(bin_path): | |
| try: | |
| st = os.stat(bin_path) | |
| os.chmod(bin_path, st.st_mode | stat.S_IEXEC) | |
| print("[PIPER] chmod +x applied to binary") | |
| except Exception as e: | |
| print("[PIPER] chmod failed:", e) | |
| # ------------- | |
| # Application | |
| # ------------- | |
| def main(): | |
| # Log a few envs to help debug Spaces | |
| log_env_for_audio() | |
| # Clean runtime/audio on boot | |
| cleanup_old_audio(keep_latest=None) | |
| # Ensure model exists locally | |
| # ensure_model() | |
| # Make sure bundled Piper can run (no downloads on Spaces) | |
| ensure_piper_ready() | |
| # Launch Gradio | |
| demo = build_demo() | |
| # On Spaces, share=True is ignored (safe locally) | |
| demo.launch(share=True) | |
| if __name__ == "__main__": | |
| main() |