1010from app .errors .handlers import register_handlers
1111from app .services import tts_service , clothing_detector
1212
13- logger = logging .getLogger (__name__ )
13+ # ── Logging config ─────────────────────────────────────────────────────────────
14+ # Show INFO+ from our code; suppress noisy third-party logs
15+ logging .basicConfig (
16+ level = logging .INFO ,
17+ format = "%(asctime)s [%(levelname)s] %(name)s: %(message)s" ,
18+ datefmt = "%H:%M:%S" ,
19+ )
20+ # Suppress library noise
21+ for _noisy in ("tensorflow" , "absl" , "h5py" , "keras" , "kokoro" , "torch" ,
22+ "urllib3" , "httpx" , "httpcore" , "uvicorn.access" ):
23+ logging .getLogger (_noisy ).setLevel (logging .ERROR )
24+
25+ logger = logging .getLogger ("rizzvision" )
1426
1527
1628@asynccontextmanager
1729async def lifespan (app : FastAPI ):
18- # Pre-load Kokoro pipelines in a thread so startup doesn't block the event loop.
19- # First real /tts request would trigger this anyway, but doing it at boot means
20- # the first user never waits 20-30s for model download.
21- # Pre-load Kokoro TTS
22- logger .info ("Warming up Kokoro TTS pipelines…" )
23- await asyncio .to_thread (tts_service .warmup )
24- logger .info ("TTS warmup complete." )
25-
26- # Pre-load clothing classifier so the first user request isn't slow
27- logger .info ("Loading clothing classifier…" )
28- await asyncio .to_thread (clothing_detector ._load )
29- logger .info ("Clothing classifier ready." )
30-
30+ logger .info ("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" )
31+ logger .info ("🚀 Rizzvision backend starting up" )
32+ logger .info ("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" )
33+
34+ # 1. TTS warmup
35+ logger .info ("[1/2] Loading Kokoro TTS pipelines (en + hi)…" )
36+ try :
37+ await asyncio .to_thread (tts_service .warmup )
38+ logger .info ("[1/2] ✓ TTS ready" )
39+ except Exception as exc :
40+ logger .error ("[1/2] ✗ TTS warmup failed: %s" , exc )
41+
42+ # 2. Clothing classifier
43+ logger .info ("[2/2] Loading clothing classifier v3 (EfficientNetB3, 115 MB)…" )
44+ try :
45+ await asyncio .to_thread (clothing_detector ._load )
46+ logger .info ("[2/2] ✓ Clothing classifier ready — thresholds: %s" , clothing_detector ._thresholds )
47+ except Exception as exc :
48+ logger .error ("[2/2] ✗ Clothing classifier failed to load: %s" , exc )
49+
50+ logger .info ("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" )
51+ logger .info ("✅ All models loaded — accepting requests" )
52+ logger .info ("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" )
3153 yield
54+ logger .info ("🛑 Rizzvision backend shutting down" )
3255
3356
3457app = FastAPI (title = "rizzvision-v2" , version = "2.0.0" , lifespan = lifespan )
3558
3659_ALLOWED_ORIGINS = [o .strip () for o in os .getenv ("ALLOWED_ORIGINS" , "" ).split ("," ) if o .strip ()]
3760if not _ALLOWED_ORIGINS :
38- # Default: allow Vercel preview URLs + localhost dev
3961 _ALLOWED_ORIGINS = [
4062 "https://rizzvision.vercel.app" ,
4163 "https://*.vercel.app" ,
@@ -60,7 +82,6 @@ def health():
6082 return {"status" : "ok" , "version" : "2.0.0" }
6183
6284
63- # HuggingFace Spaces pings /?logs=container — return 200 to suppress log noise
6485@app .get ("/" )
6586def root ():
6687 return {"status" : "ok" }
0 commit comments