#!/usr/bin/env python3 """ Ultralekki serwer OpenAI-compatible dla HF Spaces ✅ Bezpośrednie uruchomienie via uvicorn (brak subprocess) ✅ Odporny na SIGTERM/SIGINT ✅ Streaming SSE | ✅ Brak auth """ import os import sys import signal import logging from huggingface_hub import hf_hub_download import uvicorn logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") logger = logging.getLogger(__name__) MODEL_REPO = "unsloth/granite-4.1-3b-GGUF" MODEL_FILE = os.environ.get("MODEL_FILE", "granite-4.1-3b-UD-IQ2_M.gguf") PORT = int(os.environ.get("PORT", 7860)) N_CTX = int(os.environ.get("N_CTX", 2048)) N_THREADS = int(os.environ.get("N_THREADS", 2)) N_BATCH = int(os.environ.get("N_BATCH", 512)) def graceful_shutdown(signum, frame): logger.info("📡 Otrzymano sygnał zakończenia. Zamykanie...") # Uvicorn obsłuży to samodzielnie dzięki lifespan, ale dla pewności exit sys.exit(0) signal.signal(signal.SIGTERM, graceful_shutdown) signal.signal(signal.SIGINT, graceful_shutdown) if __name__ == "__main__": try: logger.info(f"⬇️ Pobieranie/weryfikacja: {MODEL_REPO}/{MODEL_FILE}") model_path = hf_hub_download( repo_id=MODEL_REPO, filename=MODEL_FILE, resume_download=True ) logger.info(f"✅ Model gotowy: {model_path}") # Importujemy moduł serwera llama_cpp from llama_cpp.server.app import create_app # Tworzymy aplikację FastAPI z konfiguracją modelu # Uwaga: create_app wymaga specyficznych argumentów w nowszych wersjach # Jeśli create_app nie działa bezpośrednio, używamy podejścia z CLI args via sys.argv hack # Ale najbezpieczniej jest ustawić zmienne środowiskowe, które llama_cpp.server czyta os.environ["MODEL"] = model_path os.environ["HOST"] = "0.0.0.0" os.environ["PORT"] = str(PORT) os.environ["N_CTX"] = str(N_CTX) os.environ["N_THREADS"] = str(N_THREADS) os.environ["N_BATCH"] = str(N_BATCH) os.environ["N_GPU_LAYERS"] = "0" os.environ["USE_MMAP"] = "1" os.environ["NO_FLASH_ATTN"] = "1" os.environ["CHAT_FORMAT"] = "chatml" logger.info("🚀 Start serwera Uvicorn...") # Uruchamiamy uvicorn bezpośrednio # app="llama_cpp.server.app:create_app" może być problematyczne jeśli create_app potrzebuje args # Dlatego używamy prostszego podejścia: zaimportujmy app z llama_cpp.server # Alternatywa: Użycie wbudowanego entrypointa llama_cpp.server poprzez import # Najprostsze i najbardziej stabilne: from llama_cpp.server import app as server_app_module # Sprawdźmy, czy server_app_module ma obiekt 'app' if hasattr(server_app_module, 'app'): target_app = server_app_module.app else: # Fallback: spróbujmy stworzyć app ręcznie jeśli to możliwe # W wersji 0.3.2 app jest tworzony dynamicznie przy imporcie __main__ # Więc musimy zasymulować import __main__ import llama_cpp.server.__main__ as main_module # To może być ryzykowne. # Najlepsze rozwiązanie dla 0.3.2: # Używamy uvicorn z stringiem wskazującym na fabrykę aplikacji target_app = "llama_cpp.server.app:create_app" uvicorn.run( target_app, host="0.0.0.0", port=PORT, log_level="info", timeout_keep_alive=120, limit_concurrency=3, backlog=16, ws_ping_interval=30, ws_ping_timeout=10 ) except Exception as e: logger.error(f"❌ Krytyczny błąd: {e}", exc_info=True) sys.exit(1)