| import os |
| import uuid |
| from typing import Optional |
| from fastapi import FastAPI, Depends, Header |
| from fastapi.middleware.cors import CORSMiddleware |
| from sqlalchemy.ext.asyncio import AsyncSession |
| from strawberry.fastapi import GraphQLRouter |
| from huggingface_hub import hf_hub_download |
|
|
| from prometheus_fastapi_instrumentator import Instrumentator |
|
|
| from backend.app.config.settings import settings |
| from backend.app.database.session import get_db |
| from backend.app.database import crud |
| from backend.app.graphql.schema import schema |
| from backend.app.api.endpoints import router as api_router, decode_access_token |
| from backend.app.services.gemini import init_onnx_session |
|
|
| app= FastAPI( |
| title= settings.PROJECT_NAME, |
| description= "Real-time event-driven stock intelligence dashboard backend.", |
| version="1.0.0" |
| ) |
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins= ["http://localhost:5173", "http://127.0.0.1:5173", "*"], |
| allow_credentials= True, |
| allow_methods= ["*"], |
| allow_headers= ["*"], |
| ) |
|
|
| from fastapi.security import HTTPBasic, HTTPBasicCredentials |
| from fastapi import HTTPException, status, Response |
| from prometheus_client import generate_latest, CONTENT_TYPE_LATEST |
| import secrets |
|
|
| security = HTTPBasic() |
|
|
| def authenticate_metrics(credentials: HTTPBasicCredentials = Depends(security)): |
| correct_username = secrets.compare_digest(credentials.username, "admin") |
| correct_password = secrets.compare_digest(credentials.password, "admin") |
| if not (correct_username and correct_password): |
| raise HTTPException( |
| status_code=status.HTTP_401_UNAUTHORIZED, |
| detail="Incorrect username or password", |
| headers={"WWW-Authenticate": "Basic"}, |
| ) |
| return credentials.username |
|
|
| |
| Instrumentator().instrument(app) |
|
|
| @app.get("/metrics") |
| async def metrics(username: str = Depends(authenticate_metrics)): |
| return Response(content=generate_latest(), media_type=CONTENT_TYPE_LATEST) |
|
|
| @app.on_event("startup") |
| async def startup_event(): |
| repo_id = os.getenv("HF_MODEL_REPO", "Karan6124/quantiq-model") |
| model_types = ["tech", "crypto", "index"] |
| |
| print(f"Starting application: checking for ONNX models...") |
| for m_type in model_types: |
| filename = f"model_{m_type}.onnx" |
| try: |
| local_path = filename |
| if os.path.exists(local_path): |
| print(f"Using local model found at {local_path} for '{m_type}'") |
| init_onnx_session(local_path, m_type) |
| else: |
| print(f"Downloading model '{filename}' from Hugging Face Hub: {repo_id}...") |
| model_path = hf_hub_download(repo_id=repo_id, filename=filename) |
| init_onnx_session(model_path, m_type) |
| except Exception as e: |
| print(f"Could not load specialized model '{filename}' from HF Hub: {e}") |
| |
| fallback_filename = "model.onnx" |
| try: |
| if os.path.exists(fallback_filename): |
| print(f"Falling back to local {fallback_filename} for '{m_type}'") |
| init_onnx_session(fallback_filename, m_type) |
| else: |
| print(f"Downloading fallback model.onnx from HF Hub for '{m_type}'...") |
| model_path = hf_hub_download(repo_id=repo_id, filename=fallback_filename) |
| init_onnx_session(model_path, m_type) |
| except Exception as fb_err: |
| print(f"Error loading fallback model for '{m_type}': {fb_err}") |
| |
| |
| async def get_graphql_context(db: AsyncSession= Depends(get_db), authorization: Optional[str]= Header(None)): |
| context= {"db": db, "user": None} |
| |
| if authorization and authorization.startswith("Bearer "): |
| token= authorization.split(" ")[1] |
| payload= decode_access_token(token) |
| if payload and "sub" in payload: |
| try: |
| user_id= uuid.UUID(payload["sub"]) |
| user= await crud.get_user(db, user_id) |
| if user: |
| context["user"]= user |
| except ValueError: |
| pass |
| |
| return context |
|
|
| |
| graphql_router= GraphQLRouter( |
| schema, |
| context_getter= get_graphql_context |
| ) |
|
|
| app.include_router(api_router, prefix= settings.API_V1_STR) |
| app.include_router(graphql_router, prefix= "/graphql") |
|
|
| @app.get("/") |
| async def root(): |
| return { |
| "status": "healthy", |
| "project": settings.PROJECT_NAME, |
| "graphql_endpoint": "/graphql", |
| "api_v1_endpoint": settings.API_V1_STR |
| } |