import os import json import faiss import numpy as np from fastapi import FastAPI, HTTPException, Depends from fastapi.responses import JSONResponse from fastapi.middleware.cors import CORSMiddleware from fastapi.security import HTTPBasic, HTTPBasicCredentials from pydantic import BaseModel from sentence_transformers import SentenceTransformer from starlette.status import HTTP_401_UNAUTHORIZED app = FastAPI() security = HTTPBasic() # CORS support app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Auth config USERNAME = os.getenv("API_USER", "bodha") PASSWORD = os.getenv("API_PASS", "securepass123") def authenticate(credentials: HTTPBasicCredentials = Depends(security)): if credentials.username != USERNAME or credentials.password != PASSWORD: raise HTTPException( status_code=HTTP_401_UNAUTHORIZED, detail="Incorrect username or password", headers={"WWW-Authenticate": "Basic"}, ) # Load model and vector index model = SentenceTransformer("./local_model") faiss_index = faiss.read_index("index_combined.faiss") with open("metadata_combined.json", "r", encoding="utf-8") as f: metadata = json.load(f) # JSON schema for request body class SearchBody(BaseModel): query: str @app.get("/") def root(): return {"message": "BodhaGPT Vector API is live!"} @app.post("/vector-api/search") def search(body: SearchBody, credentials: HTTPBasicCredentials = Depends(authenticate)): query = body.query.strip() if not query: return JSONResponse(status_code=400, content={"error": "Query is required"}) embedding = model.encode([query])[0] D, I = faiss_index.search(np.array([embedding]), k=5) results = [metadata[idx] for idx in I[0] if idx < len(metadata)] return results