from fastapi import FastAPI, File, UploadFile , Request from fastapi.routing import APIRoute from fastapi.responses import HTMLResponse, JSONResponse from fastapi.middleware import Middleware from fastapi.middleware.cors import CORSMiddleware from starlette.middleware.base import BaseHTTPMiddleware from fastapi.staticfiles import StaticFiles import os, pandas as pd from typing import List from langchain_community.embeddings import OpenAIEmbeddings from langchain_community.vectorstores import FAISS from langchain_openai import ChatOpenAI from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate from datetime import datetime, timedelta, timezone from dotenv import load_dotenv import io from starlette.responses import Response class CaseInsensitiveRoute(APIRoute): def matches(self, scope: dict) -> tuple[bool, dict]: # Only lowercase if it's not a static file if scope["type"] == "http" and not scope["path"].startswith("/static"): scope["path"] = scope["path"].lower() return super().matches(scope) load_dotenv() app = FastAPI() app.mount("/static", StaticFiles(directory="static"), name="static") middleware = [ Middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"]) ] app.router.route_class = CaseInsensitiveRoute PERSISTENT_FAISS_PATH = "/tmp/faiss_store" os.makedirs(PERSISTENT_FAISS_PATH, exist_ok=True) vector_store = None @app.get("/bs-nagesh") async def serve_index(): return HTMLResponse(content=""" AI Receptionist Idle Avatar Talking Avatar
Idle. Please say "hello" to begin.
""") @app.post("/upload_file") async def upload_file(file: UploadFile = File(...)): global vector_store # βœ… Get API key at runtime inside endpoint openai_key = os.getenv("OPENAI_API_KEY") if not openai_key: return JSONResponse(status_code=500, content={"error": "OPENAI_API_KEY not found in environment."}) # βœ… Load uploaded file try: if file.filename.endswith("xlsx"): contents = await file.read() df = pd.read_excel(io.BytesIO(contents)) elif file.filename.endswith("csv"): df = pd.read_csv(file.file) else: return JSONResponse(status_code=400, content={"error": "Unsupported file format. Use .csv or .xlsx"}) except Exception as e: return JSONResponse(status_code=500, content={"error": f"File parsing failed: {str(e)}"}) # βœ… Convert DataFrame to document strings try: docs = [", ".join(f"{col}: {val}" for col, val in row.items()) for _, row in df.iterrows()] except Exception as e: return JSONResponse(status_code=500, content={"error": f"Data conversion failed: {str(e)}"}) # βœ… Create and persist vector store try: embeddings = OpenAIEmbeddings(openai_api_key=openai_key) vector_store = FAISS.from_texts(docs, embedding=embeddings) vector_store.save_local(PERSISTENT_FAISS_PATH) except Exception as e: return JSONResponse(status_code=500, content={"error": f"Vector store error: {str(e)}"}) return {"message": "Data indexed successfully."} @app.post("/ask") async def ask_question(payload: dict): global vector_store query = payload.get("query") if not query: return JSONResponse(status_code=400, content={"error": "Query missing."}) if vector_store is None: if os.path.exists(os.path.join(PERSISTENT_FAISS_PATH, "index.faiss")): vector_store = FAISS.load_local( PERSISTENT_FAISS_PATH, OpenAIEmbeddings(), allow_dangerous_deserialization=True ) else: return JSONResponse(status_code=500, content={"error": "Vector store not initialized."}) ist = timezone(timedelta(hours=5, minutes=30)) current_time = datetime.now(ist).strftime("%A, %d %B %Y, %I:%M %p") prompt_template = PromptTemplate( input_variables=["context", "question"], template=f""" You are an intelligent AI UnoAvatar for Mr. BS Nagesh. You give very crisp and short answers. You talk as him in first person. You answer in brief and short sentences You are trained on his life and you know everything about him. You are a participant at the the Food Forum 2025. Answer user queries based on the provided context below. Use natural tone, be helpful and factual. Today’s IST date and time is: {current_time}. Context: {{context}} Question: {{question}} Answer:""" ) llm = ChatOpenAI(model_name="gpt-4o-mini-2024-07-18", temperature=0.3) retriever = vector_store.as_retriever() qa = RetrievalQA.from_chain_type( llm=llm, retriever=retriever, chain_type="stuff", chain_type_kwargs={"prompt": prompt_template} ) result = qa.run(query) return {"answer": result} @app.post("/ask_foodforum") async def ask_foodforum(payload: dict): global vector_store query = payload.get("query") if not query: return JSONResponse(status_code=400, content={"error": "Query missing."}) if vector_store is None: if os.path.exists(os.path.join(PERSISTENT_FAISS_PATH, "index.faiss")): vector_store = FAISS.load_local( PERSISTENT_FAISS_PATH, OpenAIEmbeddings(), allow_dangerous_deserialization=True ) else: return JSONResponse(status_code=500, content={"error": "Vector store not initialized."}) ist = timezone(timedelta(hours=5, minutes=30)) current_time = datetime.now(ist).strftime("%A, %d %B %Y, %I:%M %p") # 🌐 Food Forum 2025 Prompt prompt_template = PromptTemplate( input_variables=["context", "question"], template=f""" You are the AI Concierge for **Food Forum 2025**, India’s most influential summit on food, beverage, and hospitality innovation. You are informative, helpful, and polite β€” designed to guide participants, media, and partners through the event experience. Answer briefly and clearly in **English** unless asked otherwise. Only use the context provided to you β€” do not guess. If unsure, say: "Please check with the Food Forum Help Desk for the latest details." Date & Time (IST): {current_time} Context: {{context}} Question: {{question}} Answer: """ ) llm = ChatOpenAI(model_name="gpt-4o-mini-2024-07-18", temperature=0.3) retriever = vector_store.as_retriever() qa = RetrievalQA.from_chain_type( llm=llm, retriever=retriever, chain_type="stuff", chain_type_kwargs={"prompt": prompt_template} ) result = qa.run(query) return {"answer": result} @app.get("/welcome", response_class=HTMLResponse) async def food_forum(): return HTMLResponse(content=""" Food Forum 2025 """) # Endpoint to render the video playback page @app.get("/food-forum", response_class=HTMLResponse) async def food_forum(): return HTMLResponse(content=""" Food Forum 2025 """) @app.get("/jewellery") async def serve_index(): return HTMLResponse(content=""" AD Yogesh – AI Receptionist
Avatar
Idle. Please say "hello" to begin.
""")