singhankur01 commited on
Commit
458c72f
·
verified ·
1 Parent(s): 5eba371

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +11 -15
app.py CHANGED
@@ -10,6 +10,7 @@ from dotenv import load_dotenv
10
  from operator import itemgetter
11
  from fastapi import FastAPI, Depends, HTTPException, Header
12
  from fastapi.responses import JSONResponse
 
13
  from utils.DocsLoader import load_and_chunk
14
  from utils.Schemas import RunRequest, RunResponse
15
  from langchain_community.vectorstores import FAISS
@@ -19,6 +20,7 @@ from langchain_community.retrievers import BM25Retriever
19
  from langchain.retrievers import EnsembleRetriever
20
  from sklearn.metrics.pairwise import cosine_similarity
21
  from langchain.prompts import PromptTemplate
 
22
 
23
  # Load environment variables
24
  load_dotenv()
@@ -39,7 +41,6 @@ async def lifespan(app: FastAPI):
39
  if not GOOGLE_API_KEY:
40
  raise RuntimeError("CRITICAL: Missing GOOGLE_API_KEY in environment secrets!")
41
 
42
- # Optimized embedding model with batching
43
  ml_models["embedder"] = HuggingFaceEmbeddings(
44
  model_name="BAAI/bge-base-en-v1.5",
45
  encode_kwargs={
@@ -48,7 +49,6 @@ async def lifespan(app: FastAPI):
48
  }
49
  )
50
 
51
- # Faster LLM with constrained output
52
  ml_models["llm"] = ChatGoogleGenerativeAI(
53
  model="gemini-1.5-pro",
54
  api_key=GOOGLE_API_KEY,
@@ -56,7 +56,6 @@ async def lifespan(app: FastAPI):
56
  max_output_tokens=300
57
  )
58
 
59
- # Improved prompt template
60
  ml_models["prompt_template"] = PromptTemplate.from_template("""
61
  **Role**: Insurance Policy Expert
62
  **Context**:
@@ -85,6 +84,7 @@ async def lifespan(app: FastAPI):
85
  # --- 2. FastAPI App Instance ---
86
  app = FastAPI(title="HackRX RAG Server", lifespan=lifespan)
87
 
 
88
  # --- 3. API Key Verification ---
89
  TEAM_API_KEY = os.getenv("TEAM_API_KEY")
90
 
@@ -98,7 +98,6 @@ def verify_api_key(authorization: str = Header(...)):
98
  # --- 4. Parsing Helper ---
99
  def parse_llm_response(content: str) -> str:
100
  try:
101
- # Clean JSON response
102
  content_cleaned = re.sub(r"^```json|```$", "", content.strip(), flags=re.IGNORECASE).strip()
103
  data = json.loads(content_cleaned)
104
 
@@ -118,7 +117,6 @@ def parse_llm_response(content: str) -> str:
118
 
119
  # --- 5. Retrieval Optimization ---
120
  async def get_relevant_docs(question: str, vectorstore: FAISS, keyword_retriever: BM25Retriever):
121
- # Parallel retrieval
122
  dense_docs, sparse_docs = await asyncio.gather(
123
  vectorstore.asimilarity_search(question, k=6),
124
  asyncio.get_event_loop().run_in_executor(
@@ -128,11 +126,9 @@ async def get_relevant_docs(question: str, vectorstore: FAISS, keyword_retriever
128
  )
129
  )
130
 
131
- # Combine and deduplicate
132
  all_docs = dense_docs + sparse_docs
133
  unique_docs = {doc.page_content: doc for doc in all_docs}.values()
134
 
135
- # Fast reranking
136
  query_embedding = ml_models["embedder"].embed_query(question)
137
  doc_texts = [doc.page_content for doc in unique_docs]
138
  doc_embeddings = ml_models["embedder"].embed_documents(doc_texts)
@@ -147,14 +143,16 @@ async def get_relevant_docs(question: str, vectorstore: FAISS, keyword_retriever
147
  async def run_hackrx(req: RunRequest):
148
  start_time = time.time()
149
 
150
- # Cache document processing
151
  async with cache_lock:
152
- if req.documents in document_cache:
 
153
  print("♻️ Using cached document")
154
- chunks = document_cache[req.documents]
155
  else:
156
- chunks = load_and_chunk(str(req.documents))
157
- document_cache[req.documents] = chunks
 
 
158
 
159
  if not chunks:
160
  return JSONResponse({"error": "No documents processed"}, status_code=400)
@@ -169,7 +167,6 @@ async def run_hackrx(req: RunRequest):
169
  relevant_docs = await get_relevant_docs(q, vectorstore, keyword_retriever)
170
  context = "\n".join([d.page_content for d in relevant_docs])
171
 
172
- # Generate response
173
  prompt = ml_models["prompt_template"].format_prompt(
174
  full_query=q,
175
  context=context
@@ -179,7 +176,6 @@ async def run_hackrx(req: RunRequest):
179
 
180
  answers = await asyncio.gather(*(process_question(q) for q in req.questions))
181
 
182
- # Performance logging
183
  proc_time = time.time() - start_time
184
  print(f"⏱️ Processed {len(req.questions)} questions in {proc_time:.2f}s")
185
 
@@ -187,4 +183,4 @@ async def run_hackrx(req: RunRequest):
187
 
188
  @app.get("/", include_in_schema=False)
189
  def root():
190
- return {"message": "HackRX API operational. Use /api/v1/hackrx/run"}
 
10
  from operator import itemgetter
11
  from fastapi import FastAPI, Depends, HTTPException, Header
12
  from fastapi.responses import JSONResponse
13
+ from langchain_core.documents import Document
14
  from utils.DocsLoader import load_and_chunk
15
  from utils.Schemas import RunRequest, RunResponse
16
  from langchain_community.vectorstores import FAISS
 
20
  from langchain.retrievers import EnsembleRetriever
21
  from sklearn.metrics.pairwise import cosine_similarity
22
  from langchain.prompts import PromptTemplate
23
+ from fastapi.middleware.cors import CORSMiddleware # Optional, for external frontend
24
 
25
  # Load environment variables
26
  load_dotenv()
 
41
  if not GOOGLE_API_KEY:
42
  raise RuntimeError("CRITICAL: Missing GOOGLE_API_KEY in environment secrets!")
43
 
 
44
  ml_models["embedder"] = HuggingFaceEmbeddings(
45
  model_name="BAAI/bge-base-en-v1.5",
46
  encode_kwargs={
 
49
  }
50
  )
51
 
 
52
  ml_models["llm"] = ChatGoogleGenerativeAI(
53
  model="gemini-1.5-pro",
54
  api_key=GOOGLE_API_KEY,
 
56
  max_output_tokens=300
57
  )
58
 
 
59
  ml_models["prompt_template"] = PromptTemplate.from_template("""
60
  **Role**: Insurance Policy Expert
61
  **Context**:
 
84
  # --- 2. FastAPI App Instance ---
85
  app = FastAPI(title="HackRX RAG Server", lifespan=lifespan)
86
 
87
+
88
  # --- 3. API Key Verification ---
89
  TEAM_API_KEY = os.getenv("TEAM_API_KEY")
90
 
 
98
  # --- 4. Parsing Helper ---
99
  def parse_llm_response(content: str) -> str:
100
  try:
 
101
  content_cleaned = re.sub(r"^```json|```$", "", content.strip(), flags=re.IGNORECASE).strip()
102
  data = json.loads(content_cleaned)
103
 
 
117
 
118
  # --- 5. Retrieval Optimization ---
119
  async def get_relevant_docs(question: str, vectorstore: FAISS, keyword_retriever: BM25Retriever):
 
120
  dense_docs, sparse_docs = await asyncio.gather(
121
  vectorstore.asimilarity_search(question, k=6),
122
  asyncio.get_event_loop().run_in_executor(
 
126
  )
127
  )
128
 
 
129
  all_docs = dense_docs + sparse_docs
130
  unique_docs = {doc.page_content: doc for doc in all_docs}.values()
131
 
 
132
  query_embedding = ml_models["embedder"].embed_query(question)
133
  doc_texts = [doc.page_content for doc in unique_docs]
134
  doc_embeddings = ml_models["embedder"].embed_documents(doc_texts)
 
143
  async def run_hackrx(req: RunRequest):
144
  start_time = time.time()
145
 
 
146
  async with cache_lock:
147
+ doc_key = hash(str(req.documents)) # Hash key for safety
148
+ if doc_key in document_cache:
149
  print("♻️ Using cached document")
150
+ chunks = document_cache[doc_key]
151
  else:
152
+ raw_chunks = load_and_chunk(str(req.documents))
153
+ # 🔧 FIXED: Convert string chunks to Document objects
154
+ chunks = [Document(page_content=chunk) for chunk in raw_chunks]
155
+ document_cache[doc_key] = chunks
156
 
157
  if not chunks:
158
  return JSONResponse({"error": "No documents processed"}, status_code=400)
 
167
  relevant_docs = await get_relevant_docs(q, vectorstore, keyword_retriever)
168
  context = "\n".join([d.page_content for d in relevant_docs])
169
 
 
170
  prompt = ml_models["prompt_template"].format_prompt(
171
  full_query=q,
172
  context=context
 
176
 
177
  answers = await asyncio.gather(*(process_question(q) for q in req.questions))
178
 
 
179
  proc_time = time.time() - start_time
180
  print(f"⏱️ Processed {len(req.questions)} questions in {proc_time:.2f}s")
181
 
 
183
 
184
  @app.get("/", include_in_schema=False)
185
  def root():
186
+ return {"message": "HackRX API operational. Use /api/v1/hackrx/run"}