# app.py """ Точка входа для Hugging Face Spaces. Выполняет загрузку ассетов, вызывает штатный скрипт запуска vLLM и инициализирует Gradio-интерфейс. """ import sys import os import logging import subprocess from pathlib import Path from huggingface_hub import snapshot_download # Настройка логирования logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") logger: logging.Logger = logging.getLogger(__name__) def download_assets(repo_id: str, local_dir: Path, repo_type: str = "dataset") -> None: """Скачивает ассеты из указанного репозитория Hugging Face.""" if not local_dir.exists() or not any(local_dir.iterdir()): logger.info(f"📥 Начинаем загрузку ассетов из {repo_id}...") local_dir.mkdir(parents=True, exist_ok=True) try: snapshot_download( repo_id=repo_id, repo_type=repo_type, local_dir=str(local_dir), allow_patterns=["*.glb", "*.gltf", "*fake*"], local_dir_use_symlinks=False ) logger.info("✅ Ассеты успешно скачаны!") except Exception as e: logger.error(f"❌ Ошибка при скачивании ассетов: {e}") raise else: logger.info("⚡ Ассеты уже существуют локально, скачивание не требуется.") def init_space() -> None: """Инициализирует пути проекта, подготавливает ассеты и запускает сервисы.""" project_root: Path = Path(__file__).resolve().parent # 1. НАСТРАИВАЕМ ПУТИ if str(project_root) not in sys.path: sys.path.append(str(project_root)) src_dir: Path = project_root / "src" if str(src_dir) not in sys.path: sys.path.append(str(src_dir)) # 2. СКАЧИВАЕМ АССЕТЫ assets_dir: Path = project_root / "assets" download_assets( repo_id="emb-ai/RoboBenchMart_assets", local_dir=assets_dir, repo_type="dataset" ) # 3. ЗАПУСКАЕМ vLLM ЧЕРЕЗ ШТАТНЫЙ СКРИПТ logger.info("🚀 Запуск фонового сервера vLLM через launch_llm_server.py...") launcher_path = project_root / "scripts" / "launch_llm_server.py" if launcher_path.exists(): try: # subprocess.run заблокирует выполнение app.py, пока лаунчер не сделает exit() # Так как лаунчер ждет статуса 200 OK от health-эндпоинта, UI не запустится раньше времени. subprocess.run([sys.executable, str(launcher_path)], check=True) logger.info("✅ Лаунчер отработал успешно, бэкенд готов!") except subprocess.CalledProcessError as e: logger.error(f"❌ Ошибка при запуске сервера vLLM. Код возврата: {e.returncode}") sys.exit(1) else: logger.error(f"❌ Скрипт лаунчера не найден по пути: {launcher_path}") sys.exit(1) # 4. ЗАПУСКАЕМ UI from scripts.launch_ui import main logger.info("🎨 Запуск основного интерфейса Gradio...") main() if __name__ == "__main__": init_space()