Bromeo777 commited on
Commit
7fea2dc
·
unverified ·
1 Parent(s): 9a38def

Update deps.py

Browse files
Files changed (1) hide show
  1. app/api/deps.py +38 -36
app/api/deps.py CHANGED
@@ -1,6 +1,7 @@
1
  # app/api/deps.py
2
- # Romeo AI Research Assistant - Ultimate Production Dependencies
3
- # Version: 2026.03.20.FastBoot
 
4
 
5
  import logging
6
  import asyncio
@@ -26,6 +27,7 @@ from app.core.hf_sync import (
26
  stop_backup_scheduler
27
  )
28
 
 
29
  from app.services.veritas.engine import VeritasEngine
30
  from app.services.veritas.shield_one import SemanticFingerprinterAsync
31
  from app.services.veritas.shield_two import ParaphraseDetector
@@ -36,21 +38,24 @@ from app.models.user import User
36
  logger = logging.getLogger("romeo_research.deps")
37
 
38
  # -----------------------------------------------------------------------------
39
- # 🛡️ 1. GLOBAL AI ENGINE SINGLETON
40
  # -----------------------------------------------------------------------------
41
  _veritas_engine: Optional[VeritasEngine] = None
42
  _engine_lock = asyncio.Lock()
43
- _engine_ready = asyncio.Event() # Signals when engine is ready
44
 
45
  def _load_veritas_engine_background():
46
- """🔥 Load heavy ML models in background thread (non-blocking)"""
47
  global _veritas_engine
48
 
49
  if _veritas_engine is not None:
50
  return
51
 
52
  try:
53
- logger.info("🔄 Background: Loading Veritas Engine ML models...")
 
 
 
54
 
55
  semantic_svc = SemanticFingerprinterAsync(index_path=settings.VERITAS_LOCAL_INDEX_PATH)
56
  structural_svc = ParaphraseDetector()
@@ -63,12 +68,12 @@ def _load_veritas_engine_background():
63
  )
64
 
65
  _engine_ready.set()
66
- logger.info("✅ Background: Veritas Engine ready")
67
  except Exception as e:
68
- logger.error(f"❌ Background engine load failed: {e}")
69
 
70
  async def get_veritas_engine() -> VeritasEngine:
71
- """Get Veritas Engine - waits for background loading if needed"""
72
  global _veritas_engine
73
 
74
  if _veritas_engine is not None:
@@ -78,15 +83,15 @@ async def get_veritas_engine() -> VeritasEngine:
78
  await asyncio.wait_for(_engine_ready.wait(), timeout=60.0)
79
  return _veritas_engine
80
  except asyncio.TimeoutError:
81
- logger.warning("⚠️ Background timeout, loading synchronously...")
82
  return await _load_veritas_engine_sync()
83
 
84
  async def _load_veritas_engine_sync() -> VeritasEngine:
85
- """Synchronous fallback loader"""
86
  global _veritas_engine
87
  async with _engine_lock:
88
  if _veritas_engine is None:
89
- logger.info("⚡ Veritas Engine: Warming up ML models...")
90
  semantic_svc = SemanticFingerprinterAsync(index_path=settings.VERITAS_LOCAL_INDEX_PATH)
91
  structural_svc = ParaphraseDetector()
92
  fact_svc = ClaimVerifier()
@@ -96,57 +101,57 @@ async def _load_veritas_engine_sync() -> VeritasEngine:
96
  fact_service=fact_svc
97
  )
98
  _engine_ready.set()
99
- logger.info("✅ Veritas Engine: All Shields Online.")
100
  return _veritas_engine
101
 
102
  # -----------------------------------------------------------------------------
103
- # 🔄 2. LIFESPAN MANAGER (Fast Boot)
104
  # -----------------------------------------------------------------------------
105
-
106
  @asynccontextmanager
107
  async def lifespan(app: FastAPI):
108
  """
109
- 🔥 FAST BOOT: Start API immediately, load heavy stuff in background.
110
  """
111
  try:
112
  Path("./data/veritas_index").mkdir(parents=True, exist_ok=True)
113
- logger.info("🚀 Romeo AI: Fast Boot initiated...")
114
 
115
- # B. Background DB sync (non-blocking)
116
  if os.getenv("SKIP_HF_PULL_ON_START") != "1":
117
  loop = asyncio.get_event_loop()
118
  await loop.run_in_executor(None, download_db_from_hf)
 
119
  else:
120
- logger.info("⏭️ Skipped HF DB pull (SKIP_HF_PULL_ON_START=1)")
121
 
122
- # C. 🔥 BACKGROUND: Start ML model loading in thread (DON'T BLOCK)
123
  threading.Thread(target=_load_veritas_engine_background, daemon=True).start()
124
 
125
  # D. Start backup scheduler
126
  start_backup_scheduler()
127
 
128
- logger.info("🏁 Fast Boot complete. API ready. Models loading in background...")
 
129
 
130
  except Exception as e:
131
- logger.critical(f"❌ Startup error: {str(e)}", exc_info=True)
132
 
133
  yield
134
 
135
  # SHUTDOWN
136
  try:
137
- logger.info("🛑 Shutdown: Saving data...")
138
  stop_backup_scheduler()
139
  backup_db_to_hf()
140
- logger.info("💾 Data saved to HF Hub.")
141
  except Exception as e:
142
- logger.error(f"⚠️ Shutdown backup error: {e}")
143
 
144
  # -----------------------------------------------------------------------------
145
- # 💾 3. DATABASE DEPENDENCY
146
  # -----------------------------------------------------------------------------
147
-
148
  async def get_db() -> AsyncGenerator[AsyncSession, None]:
149
- """Provides an async database session with automatic cleanup."""
150
  async with async_session_factory() as session:
151
  try:
152
  yield session
@@ -154,15 +159,13 @@ async def get_db() -> AsyncGenerator[AsyncSession, None]:
154
  await session.close()
155
 
156
  # -----------------------------------------------------------------------------
157
- # 🔑 4. AUTHENTICATION & SECURITY
158
  # -----------------------------------------------------------------------------
159
-
160
  reusable_oauth2 = OAuth2PasswordBearer(
161
  tokenUrl=f"{settings.API_V1_STR.rstrip('/')}/auth/login"
162
  )
163
 
164
  async def _get_user_by_email(db: AsyncSession, email: str) -> Optional[User]:
165
- """Internal helper to avoid circular imports."""
166
  result = await db.execute(select(User).where(User.email == email))
167
  return result.scalars().first()
168
 
@@ -170,7 +173,7 @@ async def get_current_user(
170
  db: AsyncSession = Depends(get_db),
171
  token: str = Depends(reusable_oauth2)
172
  ) -> User:
173
- """JWT Validator with 5-second database circuit breaker."""
174
  credentials_exception = HTTPException(
175
  status_code=status.HTTP_401_UNAUTHORIZED,
176
  detail="Could not validate credentials",
@@ -188,15 +191,14 @@ async def get_current_user(
188
  try:
189
  user = await asyncio.wait_for(_get_user_by_email(db, email), timeout=5.0)
190
  except asyncio.TimeoutError:
191
- logger.error(f"Timeout: Auth lookup for {email} failed")
192
- raise HTTPException(status_code=503, detail="System busy. Try again.")
193
 
194
  if not user:
195
  raise credentials_exception
196
  return user
197
 
198
  async def get_current_active_user(user: User = Depends(get_current_user)) -> User:
199
- """Check if the user account is enabled."""
200
  if not user.is_active:
201
- raise HTTPException(status_code=400, detail="Account disabled.")
202
  return user
 
1
  # app/api/deps.py
2
+ # Romeo AI Research Assistant - MAI Veritas Dependencies
3
+ # Version: 2026.03.20.Veritas
4
+ # Description: Full shield with background loading for fast boot
5
 
6
  import logging
7
  import asyncio
 
27
  stop_backup_scheduler
28
  )
29
 
30
+ # Veritas Engine Imports
31
  from app.services.veritas.engine import VeritasEngine
32
  from app.services.veritas.shield_one import SemanticFingerprinterAsync
33
  from app.services.veritas.shield_two import ParaphraseDetector
 
38
  logger = logging.getLogger("romeo_research.deps")
39
 
40
  # -----------------------------------------------------------------------------
41
+ # 🛡️ GLOBAL VERITAS ENGINE SINGLETON
42
  # -----------------------------------------------------------------------------
43
  _veritas_engine: Optional[VeritasEngine] = None
44
  _engine_lock = asyncio.Lock()
45
+ _engine_ready = asyncio.Event()
46
 
47
  def _load_veritas_engine_background():
48
+ """🔥 Load MAI Veritas shields in background (non-blocking)"""
49
  global _veritas_engine
50
 
51
  if _veritas_engine is not None:
52
  return
53
 
54
  try:
55
+ logger.info("🛡️ MAI Background: Initializing Veritas Shields...")
56
+ logger.info(" └─ Shield One: Semantic Fingerprinter")
57
+ logger.info(" └─ Shield Two: Paraphrase Detector")
58
+ logger.info(" └─ Shield Three: Claim Verifier")
59
 
60
  semantic_svc = SemanticFingerprinterAsync(index_path=settings.VERITAS_LOCAL_INDEX_PATH)
61
  structural_svc = ParaphraseDetector()
 
68
  )
69
 
70
  _engine_ready.set()
71
+ logger.info("✅ MAI Veritas: All Shields Online")
72
  except Exception as e:
73
+ logger.error(f"❌ MAI Veritas initialization failed: {e}")
74
 
75
  async def get_veritas_engine() -> VeritasEngine:
76
+ """Get MAI Veritas Engine - waits for background init if needed"""
77
  global _veritas_engine
78
 
79
  if _veritas_engine is not None:
 
83
  await asyncio.wait_for(_engine_ready.wait(), timeout=60.0)
84
  return _veritas_engine
85
  except asyncio.TimeoutError:
86
+ logger.warning("⚠️ MAI background timeout, loading synchronously...")
87
  return await _load_veritas_engine_sync()
88
 
89
  async def _load_veritas_engine_sync() -> VeritasEngine:
90
+ """Synchronous fallback for MAI Veritas"""
91
  global _veritas_engine
92
  async with _engine_lock:
93
  if _veritas_engine is None:
94
+ logger.info("⚡ MAI Veritas: Synchronous initialization...")
95
  semantic_svc = SemanticFingerprinterAsync(index_path=settings.VERITAS_LOCAL_INDEX_PATH)
96
  structural_svc = ParaphraseDetector()
97
  fact_svc = ClaimVerifier()
 
101
  fact_service=fact_svc
102
  )
103
  _engine_ready.set()
104
+ logger.info("✅ MAI Veritas: All Shields Online")
105
  return _veritas_engine
106
 
107
  # -----------------------------------------------------------------------------
108
+ # 🔄 LIFESPAN MANAGER (MAI Fast Boot)
109
  # -----------------------------------------------------------------------------
 
110
  @asynccontextmanager
111
  async def lifespan(app: FastAPI):
112
  """
113
+ 🔥 MAI FAST BOOT: API starts in ~5s, heavy shields load in background
114
  """
115
  try:
116
  Path("./data/veritas_index").mkdir(parents=True, exist_ok=True)
117
+ logger.info("🚀 MAI: Fast Boot initiated...")
118
 
119
+ # B. Background HF DB sync (non-blocking)
120
  if os.getenv("SKIP_HF_PULL_ON_START") != "1":
121
  loop = asyncio.get_event_loop()
122
  await loop.run_in_executor(None, download_db_from_hf)
123
+ logger.info("💾 Database synchronized")
124
  else:
125
+ logger.info("⏭️ HF DB pull skipped (SKIP_HF_PULL_ON_START=1)")
126
 
127
+ # C. 🔥 BACKGROUND: Start MAI Veritas initialization (DON'T BLOCK)
128
  threading.Thread(target=_load_veritas_engine_background, daemon=True).start()
129
 
130
  # D. Start backup scheduler
131
  start_backup_scheduler()
132
 
133
+ logger.info("🏁 MAI Fast Boot complete. API ready. Shields initializing...")
134
+ logger.info("⏳ Veritas will be ready in ~30-60 seconds...")
135
 
136
  except Exception as e:
137
+ logger.critical(f"❌ MAI startup error: {str(e)}", exc_info=True)
138
 
139
  yield
140
 
141
  # SHUTDOWN
142
  try:
143
+ logger.info("🛑 MAI Shutdown: Securing research data...")
144
  stop_backup_scheduler()
145
  backup_db_to_hf()
146
+ logger.info("💾 MAI: Database persisted to HF Hub")
147
  except Exception as e:
148
+ logger.error(f"⚠️ MAI shutdown error: {e}")
149
 
150
  # -----------------------------------------------------------------------------
151
+ # 💾 DATABASE DEPENDENCY
152
  # -----------------------------------------------------------------------------
 
153
  async def get_db() -> AsyncGenerator[AsyncSession, None]:
154
+ """Async database session with cleanup"""
155
  async with async_session_factory() as session:
156
  try:
157
  yield session
 
159
  await session.close()
160
 
161
  # -----------------------------------------------------------------------------
162
+ # 🔑 AUTHENTICATION & SECURITY
163
  # -----------------------------------------------------------------------------
 
164
  reusable_oauth2 = OAuth2PasswordBearer(
165
  tokenUrl=f"{settings.API_V1_STR.rstrip('/')}/auth/login"
166
  )
167
 
168
  async def _get_user_by_email(db: AsyncSession, email: str) -> Optional[User]:
 
169
  result = await db.execute(select(User).where(User.email == email))
170
  return result.scalars().first()
171
 
 
173
  db: AsyncSession = Depends(get_db),
174
  token: str = Depends(reusable_oauth2)
175
  ) -> User:
176
+ """JWT validator with 5s circuit breaker"""
177
  credentials_exception = HTTPException(
178
  status_code=status.HTTP_401_UNAUTHORIZED,
179
  detail="Could not validate credentials",
 
191
  try:
192
  user = await asyncio.wait_for(_get_user_by_email(db, email), timeout=5.0)
193
  except asyncio.TimeoutError:
194
+ logger.error(f"Auth timeout for {email}")
195
+ raise HTTPException(status_code=503, detail="System busy")
196
 
197
  if not user:
198
  raise credentials_exception
199
  return user
200
 
201
  async def get_current_active_user(user: User = Depends(get_current_user)) -> User:
 
202
  if not user.is_active:
203
+ raise HTTPException(status_code=400, detail="Account disabled")
204
  return user