rag-based-app / app.py
viraj
chat questions and answer retains.
0cb2687
from rag_pipeline import process_file, answer_query
from pydantic import BaseModel
from typing import List, Dict, Optional
from datetime import datetime
class ChatMessage(BaseModel):
question: str
answer: str
timestamp: datetime
class QueryRequest(BaseModel):
file_id: str
question: str
page: int
explainLike5: bool = False
from fastapi import FastAPI, UploadFile, File, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from dotenv import load_dotenv
from fastapi import Body
import uuid
import os
from langchain_chroma import Chroma
from langchain_huggingface import HuggingFaceEmbeddings
import re
load_dotenv()
CHROMA_DIR = "./chroma_db"
embedding_model = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
app = FastAPI()
BASE_DIR = "files"
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
file_store = {}
# Add chat memory store
chat_memory: Dict[str, List[ChatMessage]] = {}
@app.get("/test")
async def test():
return {"message": "hello world!"}
@app.post("/upload")
async def upload(file: UploadFile = File(...)):
content = await file.read()
file_id = str(uuid.uuid4())
safe_filename = file.filename.replace(" ", "_")
full_filename = f"{file_id}_{safe_filename}"
save_path = os.path.join(BASE_DIR, full_filename)
os.makedirs(BASE_DIR, exist_ok=True)
with open(save_path, "wb") as f:
f.write(content)
retriever = process_file(content, safe_filename, file_id)
file_store[file_id] = retriever
return {"message": "File processed", "file_id": file_id}
@app.post("/query")
async def query_endpoint(request = Body(...)):
file_id = request.get("file_id")
question = request.get("question")
selected_text = request.get("selectedText")
explain_like_5 = request.get("explainLike5", False)
if not file_id or not question:
raise HTTPException(status_code=422, detail="Missing file_id or question")
retriever_path = f"{CHROMA_DIR}/{file_id}"
if not os.path.exists(retriever_path):
raise HTTPException(status_code=404, detail="Vectorstore for this file_id not found.")
try:
# Initialize vectorstore with metadata filtering
vectorstore = Chroma(
embedding_function=embedding_model,
persist_directory=retriever_path
)
# Configure retriever with MMR search
retriever = vectorstore.as_retriever(
search_type="mmr",
search_kwargs={
"k": 4,
"fetch_k": 8,
"lambda_mult": 0.7,
}
)
# First, get context around selected text if it exists
contexts = []
if selected_text:
selected_results = retriever.invoke(selected_text)
contexts.extend([doc.page_content for doc in selected_results])
# Then get context for the question
question_results = retriever.invoke(question)
contexts.extend([doc.page_content for doc in question_results])
# Remove duplicates while preserving order
contexts = list(dict.fromkeys(contexts))
# Format the context with clear section separation
formatted_context = ""
if selected_text:
formatted_context += f"Selected Text Context:\n{selected_text}\n\n"
formatted_context += "Related Document Contexts:\n" + "\n---\n".join(
re.sub(r"\s+", " ", context.strip())
for context in contexts
)
# Add chat history to context if it exists
if file_id in chat_memory and chat_memory[file_id]:
chat_history = "\n\nPrevious Conversation:\n"
for msg in chat_memory[file_id][-3:]: # Include last 3 exchanges
chat_history += f"Q: {msg.question}\nA: {msg.answer}\n\n"
formatted_context = chat_history + formatted_context
# Get the answer using the enhanced context
answer = answer_query(question, formatted_context, explain_like_5)
# Store the Q&A in chat memory
if file_id not in chat_memory:
chat_memory[file_id] = []
chat_memory[file_id].append(ChatMessage(
question=question,
answer=answer,
timestamp=datetime.now()
))
return {
"answer": answer,
"context_used": formatted_context # Optionally return context for debugging
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error processing query: {str(e)}")
@app.delete("/delete/{file_id}")
async def delete_file(file_id: str):
try:
# 1. Delete from Chroma DB
chroma_path = f"{CHROMA_DIR}/{file_id}"
if os.path.exists(chroma_path):
try:
# Load and delete the collection
vectorstore = Chroma(
embedding_function=embedding_model,
persist_directory=chroma_path
)
vectorstore.delete_collection()
# Delete the directory
import shutil
shutil.rmtree(chroma_path)
except Exception as e:
print(f"Error deleting Chroma DB: {str(e)}")
# 2. Delete the actual file from disk
file_pattern = f"{file_id}_*"
matching_files = []
for filename in os.listdir(BASE_DIR):
if filename.startswith(file_id):
file_path = os.path.join(BASE_DIR, filename)
try:
os.remove(file_path)
matching_files.append(filename)
except Exception as e:
print(f"Error deleting file {filename}: {str(e)}")
# 3. Clear chat memory for this file
if file_id in chat_memory:
del chat_memory[file_id]
if not matching_files and not os.path.exists(chroma_path):
raise HTTPException(
status_code=404,
detail=f"No files found for file_id: {file_id}"
)
return {
"message": "File, embeddings, and chat history deleted successfully",
"deleted_files": matching_files,
"embeddings_deleted": os.path.exists(chroma_path)
}
except Exception as e:
if isinstance(e, HTTPException):
raise e
raise HTTPException(
status_code=500,
detail=f"Error during deletion: {str(e)}"
)