Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, Depends, Header | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from contextlib import asynccontextmanager | |
| import os, json, base64, time | |
| import firebase_admin | |
| from firebase_admin import credentials, firestore | |
| from sentence_transformers import CrossEncoder | |
| from community import router as community_router | |
| from algorithm import UpnisoAlgorithmPipeline | |
| from auth import verify_api_key | |
| from rate_limit import rate_limiter | |
| from logs import log_request | |
| # -------- GLOBALS -------- | |
| db = None | |
| pipeline = None | |
| ranker = None | |
| # -------- LIFESPAN -------- | |
| async def lifespan(app: FastAPI): | |
| global db, pipeline, ranker | |
| # Firebase init | |
| key = os.getenv("FIREBASE_KEY_B64") | |
| if key and not firebase_admin._apps: | |
| cred = credentials.Certificate(json.loads(base64.b64decode(key))) | |
| firebase_admin.initialize_app(cred) | |
| db = firestore.client() | |
| print("β Firebase connected") | |
| # Algorithm | |
| pipeline = UpnisoAlgorithmPipeline() | |
| print("β Algorithm loaded") | |
| # AI ranker | |
| ranker = CrossEncoder("cross-encoder/ms-marco-MiniLM-L6-v2") | |
| print("β AI model loaded") | |
| yield | |
| # -------- APP -------- | |
| app = FastAPI( | |
| title="Upniso Backend", | |
| version="2.0", | |
| lifespan=lifespan | |
| ) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # -------- HEALTH -------- | |
| def health(): | |
| return { | |
| "status": "live", | |
| "service": "Upniso API", | |
| "time": time.time() | |
| } | |
| # -------- COMMUNITY ROUTES -------- | |
| app.include_router(community_router, prefix="/api/v1") | |
| # -------- CORE FEED API (PAID) -------- | |
| async def feed( | |
| x_api_key: str = Header(...), | |
| key_data: dict = Depends(verify_api_key) | |
| ): | |
| # Rate limit based on plan | |
| rate_limiter( | |
| x_api_key, | |
| limit=key_data.get("limit", 50000) | |
| ) | |
| log_request(x_api_key, "/feed") | |
| if not db or not pipeline: | |
| return {"status": "error", "feed": []} | |
| creators = { | |
| d.id: d.to_dict() | |
| for d in db.collection("creators").stream() | |
| } | |
| posts = { | |
| d.id: d.to_dict() | |
| for d in db.collection("posts") | |
| .where("is_draft", "==", False) | |
| .limit(50) | |
| .stream() | |
| } | |
| ranked = pipeline.run_simulation(creators, posts) | |
| if ranker and ranked: | |
| query = "High quality merit-based content" | |
| pairs = [[query, r.get("description", "")] for r in ranked] | |
| scores = ranker.predict(pairs) | |
| for i, r in enumerate(ranked): | |
| r["ai_score"] = float(scores[i]) | |
| return { | |
| "status": "success", | |
| "plan": key_data.get("plan"), | |
| "count": len(ranked), | |
| "feed": ranked | |
| } | |