Jaita's picture
Rename main.py to main1.py
170f828 verified
# main.py
import os
os.environ["POSTHOG_DISABLED"] = "true"
import requests
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from dotenv import load_dotenv
from kb_embed import search_knowledge_base, ingest_documents, collection, DOCS_DIR
import logging
logging.basicConfig(level=logging.INFO)
load_dotenv()
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=[
"https://jaita-chatbot-react-frontend-v1.hf.space", # frontend space origin
"https://jaita-chatbot-fastapi-backend.hf.space", # backend space origin
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
class ChatInput(BaseModel):
user_message: str
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
GEMINI_URL = (
f"https://generativelanguage.googleapis.com/v1beta/models/"
f"gemini-2.5-flash-lite:generateContent?key={GEMINI_API_KEY}"
)
@app.on_event("startup")
def startup_ingest():
try:
# Make sure DOCS_DIR exists and has .docx files, then ingest
if DOCS_DIR.exists():
logging.info(f"Starting KB ingestion from: {DOCS_DIR}")
ingest_documents(str(DOCS_DIR))
else:
logging.warning(f"Docs directory not found: {DOCS_DIR}")
logging.info(f"Chroma collection count after startup: {collection.count()}")
except Exception as e:
logging.exception(f"KB ingestion failed: {e}")
@app.get("/")
async def health_check():
return {
"status": "ok",
"kb_count": collection.count(),
"docs_dir_exists": DOCS_DIR.exists()
}
@app.post("/chat")
async def chat_with_gemini(input_data: ChatInput):
# 1. Search Knowledge Base
kb_results = search_knowledge_base(input_data.user_message, top_k=10)
logging.info(f"KB query results keys: {list(kb_results.keys()) if kb_results else 'None'}")
context = ""
relevant_docs = []
# 2. Extract relevant KB docs if present
if kb_results and kb_results.get("documents") and len(kb_results["documents"]) > 0:
# kb_results["documents"] is a list of lists (one per query)
first_query_docs = kb_results["documents"][0]
relevant_docs = first_query_docs[:2]
context = "\n\n".join(relevant_docs)
# 3. If KB contains direct answer → RETURN it (No LLM call)
if context.strip():
kb_answer = f"From knowledge base:\n\n{context}"
return {
"bot_response": kb_answer,
"debug_info": f"Context found: YES, docs used: {len(relevant_docs)}, kb_count: {collection.count()}"
}
# 4. If KB empty → fallback to Gemini
enhanced_prompt = (
f"User question: {input_data.user_message}\n\n"
"No relevant KB found. You must raise a ticket.\n"
"Say: 'I'm raising a ticket. Ticket# 12345'."
)
headers = {"Content-Type": "application/json"}
payload = {"contents": [{"parts": [{"text": enhanced_prompt}]}]}
try:
response = requests.post(GEMINI_URL, headers=headers, json=payload)
result = response.json()
bot_response = result["candidates"][0]["content"]["parts"][0]["text"]
except Exception as e:
logging.exception(f"Gemini call failed: {e}")
raise HTTPException(status_code=500, detail="LLM call failed")
return {
"bot_response": bot_response,
"debug_info": f"Context found: NO, kb_count: {collection.count()}"
}