from fastapi import FastAPI, Query from fastapi.middleware.cors import CORSMiddleware import pandas as pd from filtered_search_engine import SmartRecommender from reranker import Reranker from intent_classifier import IntentClassifier from keyword_boosting_layer import apply_keyword_boost from cache_manager import CacheManager # ------------------------------ # Initialize App # ------------------------------ app = FastAPI( title="Salahkar AI Recommender", description="Smart cultural, heritage & food recommendation engine for BharatVerse", version="1.0.0" ) from fastapi.staticfiles import StaticFiles # CORS Support (allows frontend browser access) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Mount images folder to serve static files with Cache-Control class CachedStaticFiles(StaticFiles): def file_response(self, *args, **kwargs): response = super().file_response(*args, **kwargs) response.headers["Cache-Control"] = "public, max-age=31536000" return response app.mount("/images", CachedStaticFiles(directory="images"), name="images") # ------------------------------ # Load Core Components Once # ------------------------------ print("šŸ“Œ Loading dataset...") df = pd.read_csv("salahkar_enhanced.csv") # Optimization: Create O(1) lookup map name_to_row = df.set_index("name").to_dict('index') print("šŸ“Œ Loading smart recommendation engine...") engine = SmartRecommender() print("šŸ“Œ Loading reranker model...") reranker = Reranker() print("šŸ“Œ Loading intent recognizer...") intent_detector = IntentClassifier() print("šŸ“Œ Initializing Cache Manager...") cache = CacheManager(capacity=200, ttl_seconds=3600) print("šŸš€ Salahkar AI Ready!") # ------------------------------ # Routes # ------------------------------ @app.get("/") def root(): return { "message": "šŸ‡®šŸ‡³ Welcome to Salahkar AI – BharatVerse Intelligent Recommendation System", "usage": "/recommend?query=your text" } @app.get("/recommend") def get_recommendation(query: str = Query(..., description="User's search text"), k: int = 7): print(f"\nšŸ” User Query: {query}") # 0ļøāƒ£ Check Cache cached_response = cache.get(query) if cached_response: return cached_response # 1ļøāƒ£ Detect intent detected_intent = intent_detector.predict_intent(query) print(f"🧠 Intent Detected: {detected_intent}") # 2ļøāƒ£ FAISS + Filter Search # engine.recommend returns (results_list, intent) # Optimization: Pass detected_intent to avoid re-running classification rec_results, _ = engine.recommend(query, k=k, intent=detected_intent) # 3ļøāƒ£ Prepare results for reranker prepared = [] for item in rec_results: name = item["name"] domain = item["domain"] category = item["category"] region = item["region"] score = item["score"] # Optimization: O(1) lookup instead of O(N) dataframe filter row = name_to_row.get(name) if not row: continue prepared.append({ "name": name, "domain": domain, "category": category, "region": region, "embedding_score": float(score), "text": row["search_embedding_text"], "image": row["image_file"] }) # 4ļøāƒ£ Re-rank using cross encoder reranked_results = reranker.rerank(query, prepared) # 5ļøāƒ£ Apply keyword boosting final_results = apply_keyword_boost(query, reranked_results) # 6ļøāƒ£ Format response for frontend response = [ { "name": item["name"], "category": item["category"], "domain": item["domain"], "region": item["region"], "score": float(item["final_score"]), "image": f"/images/{item['image']}" if item.get("image") else None } for item in final_results[:k] ] final_response = { "query": query, "intent": detected_intent, "results": response } # 7ļøāƒ£ Save to Cache cache.set(query, final_response) return final_response # ------------------------------------------- # Run (Ignored by HuggingFace — needed only for local testing) # ------------------------------------------- if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=7860)