File size: 3,846 Bytes
c2f3a1e
 
296f03f
 
 
 
c2f3a1e
 
 
 
 
 
296f03f
c2f3a1e
 
 
 
f3bc30f
 
296f03f
 
 
 
c2f3a1e
 
 
296f03f
c2f3a1e
 
 
 
 
 
8524a15
 
 
 
 
 
 
 
f3bc30f
296f03f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f3bc30f
296f03f
 
 
 
 
 
 
 
8524a15
296f03f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8524a15
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#!/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)