absiitr commited on
Commit
c0e1610
·
verified ·
1 Parent(s): cc598bb

Delete backend.py

Browse files
Files changed (1) hide show
  1. backend.py +0 -214
backend.py DELETED
@@ -1,214 +0,0 @@
1
- import os
2
- import tempfile
3
- import gc
4
- import logging
5
- from fastapi import FastAPI, UploadFile, File, HTTPException
6
- from pydantic import BaseModel
7
- import torch
8
- from dotenv import load_dotenv
9
-
10
- # ---------------- CORS IMPORT ----------------
11
- from fastapi.middleware.cors import CORSMiddleware # ADD THIS
12
- # ---------------------------------------------
13
-
14
- # ---------------- Groq API ----------------
15
- from groq import Groq, APIError
16
-
17
- # ---------------- LangChain ----------------
18
- from langchain_community.document_loaders import PyPDFLoader
19
- from langchain_text_splitters import RecursiveCharacterTextSplitter
20
- from langchain_community.embeddings import HuggingFaceEmbeddings
21
- from langchain_community.vectorstores import Chroma
22
-
23
- # ---------------- CONFIGURATION ----------------
24
- logging.basicConfig(level=logging.INFO)
25
- load_dotenv()
26
-
27
- # Initialize FastAPI with CORS
28
- app = FastAPI()
29
-
30
- # ============== CORS MIDDLEWARE - MUST ADD THIS ==============
31
- app.add_middleware(
32
- CORSMiddleware,
33
- allow_origins=["*"], # Allows all origins
34
- allow_credentials=True,
35
- allow_methods=["*"], # Allows all methods
36
- allow_headers=["*"], # Allows all headers
37
- )
38
- # ==============================================================
39
-
40
- # API Configuration
41
- GROQ_API_KEY = os.environ.get("GROQ_API_KEY", st.secrets.get("GROQ_API_KEY") if 'st' in locals() else None)
42
- GROQ_MODEL = "llama-3.1-8b-instant"
43
-
44
- # Initialize Groq Client
45
- client = None
46
- if GROQ_API_KEY:
47
- try:
48
- client = Groq(api_key=GROQ_API_KEY)
49
- logging.info("✅ Groq client initialized successfully.")
50
- except Exception as e:
51
- logging.error(f"❌ Failed to initialize Groq client: {e}")
52
- client = None
53
- else:
54
- logging.warning("⚠️ GROQ_API_KEY not found in environment.")
55
-
56
- # Global state
57
- retriever = None
58
- vectorstore = None
59
-
60
- # ---------------- Input Schema ----------------
61
- class Query(BaseModel):
62
- question: str
63
-
64
- # ==================================================
65
- # ROOT ENDPOINT (For health check)
66
- # ==================================================
67
- @app.get("/")
68
- async def root():
69
- return {"message": "FastAPI Backend is running", "status": "healthy"}
70
-
71
- # ==================================================
72
- # PDF Upload → Chunk → Embed → Vectorstore
73
- # ==================================================
74
- @app.post("/upload")
75
- async def upload_pdf(file: UploadFile = File(...)):
76
- """Handles PDF upload and processing."""
77
- global retriever, vectorstore
78
-
79
- if not file.filename.endswith(".pdf"):
80
- raise HTTPException(400, "Only PDF files allowed")
81
-
82
- if not client:
83
- raise HTTPException(500, "Groq API key is missing or invalid.")
84
-
85
- path = None
86
- try:
87
- # 1. Save file temporarily
88
- with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp:
89
- tmp.write(await file.read())
90
- path = tmp.name
91
-
92
- logging.info(f"Processing PDF: {path}")
93
-
94
- # 2. Load PDF
95
- loader = PyPDFLoader(path)
96
- docs = loader.load()
97
-
98
- # 3. Split into chunks
99
- splitter = RecursiveCharacterTextSplitter(
100
- chunk_size=800,
101
- chunk_overlap=50
102
- )
103
- chunks = splitter.split_documents(docs)
104
-
105
- # 4. Create embeddings
106
- embeddings = HuggingFaceEmbeddings(
107
- model_name="sentence-transformers/all-MiniLM-L6-v2",
108
- model_kwargs={"device": "cpu"},
109
- encode_kwargs={"normalize_embeddings": True}
110
- )
111
-
112
- # 5. Clear previous vectorstore
113
- if vectorstore:
114
- del vectorstore
115
- gc.collect()
116
-
117
- # 6. Create Vectorstore and Retriever
118
- vectorstore = Chroma.from_documents(chunks, embeddings)
119
- retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
120
-
121
- logging.info(f"PDF processed. Chunks created: {len(chunks)}")
122
-
123
- return {"message": "PDF processed", "chunks": len(chunks)}
124
-
125
- except Exception as e:
126
- logging.error(f"Error during PDF processing: {e}")
127
- raise HTTPException(500, f"Error: {str(e)}")
128
- finally:
129
- # 7. Cleanup
130
- if path and os.path.exists(path):
131
- os.unlink(path)
132
- gc.collect()
133
-
134
- # ==================================================
135
- # ASK → RETRIEVE → GROQ → ANSWER
136
- # ==================================================
137
- @app.post("/ask")
138
- async def ask(req: Query):
139
- global retriever
140
-
141
- if client is None:
142
- raise HTTPException(500, "Groq client is not initialized. Check API key setup.")
143
-
144
- if retriever is None:
145
- raise HTTPException(400, "Upload PDF first to initialize the knowledge base.")
146
-
147
- try:
148
- # 1. Retrieve relevant chunks
149
- docs = retriever.invoke(req.question)
150
- context = "\n\n".join(d.page_content for d in docs)
151
-
152
- # 2. Build prompt
153
- prompt = f"""
154
- You are a strict RAG Q&A assistant.
155
- Use ONLY the context provided. If the answer is not found, reply:
156
- "I cannot find this in the PDF."
157
-
158
- ---------------- CONTEXT ----------------
159
- {context}
160
- -----------------------------------------
161
-
162
- QUESTION: {req.question}
163
-
164
- FINAL ANSWER:
165
- """
166
-
167
- # 3. Call Groq
168
- response = client.chat.completions.create(
169
- model=GROQ_MODEL,
170
- messages=[
171
- {"role": "system",
172
- "content": "Use only the PDF content. If answer not found, say: 'I cannot find this in the PDF.'"},
173
- {"role": "user", "content": prompt}
174
- ],
175
- temperature=0.0
176
- )
177
-
178
- answer = response.choices[0].message.content.strip()
179
- return {"answer": answer, "sources": len(docs)}
180
-
181
- except APIError as e:
182
- logging.error(f"Groq API Error: {e}")
183
- raise HTTPException(500, f"Groq API Error: {str(e)}")
184
- except Exception as e:
185
- logging.error(f"General error in /ask: {e}")
186
- raise HTTPException(500, f"General error: {str(e)}")
187
-
188
- # ==================================================
189
- # HEALTH & CLEAR
190
- # ==================================================
191
- @app.get("/health")
192
- async def health():
193
- """Endpoint for checking service status."""
194
- return {
195
- "status": "running",
196
- "pdf_loaded": retriever is not None,
197
- "groq_client_ok": client is not None
198
- }
199
-
200
- @app.post("/clear")
201
- async def clear():
202
- """Clears the current RAG components from memory."""
203
- global retriever, vectorstore
204
-
205
- if vectorstore:
206
- del vectorstore
207
- retriever = None
208
- vectorstore = None
209
-
210
- gc.collect()
211
- if torch.cuda.is_available():
212
- torch.cuda.empty_cache()
213
-
214
- return {"message": "Memory cleared. Upload a new PDF."}