HuzaifaTech commited on
Commit
933c098
Β·
verified Β·
1 Parent(s): c789ee4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +106 -58
app.py CHANGED
@@ -10,7 +10,8 @@ from groq import Groq
10
  # =========================
11
  # πŸ”‘ GROQ API (HF SECRET)
12
  # =========================
13
- client = Groq(api_key=os.getenv("Multi_doc"))
 
14
 
15
  # =========================
16
  # πŸ“„ LOAD DOCUMENTS
@@ -24,14 +25,18 @@ def load_docx(path):
24
  return "\n".join([p.text for p in doc.paragraphs])
25
 
26
  def load_txt(path):
27
- return open(path, "r", encoding="utf-8").read()
 
28
 
29
  def load_document(path):
30
  ext = path.split(".")[-1].lower()
31
- if ext == "pdf": return load_pdf(path)
32
- if ext == "docx": return load_docx(path)
33
- if ext == "txt": return load_txt(path)
34
- raise ValueError("Unsupported file type")
 
 
 
35
 
36
  # =========================
37
  # βœ‚οΈ CHUNKING
@@ -45,7 +50,7 @@ def chunk_text(text, size=400, overlap=80):
45
  while i < len(words):
46
  chunks.append({
47
  "id": cid,
48
- "text": " ".join(words[i:i+size])
49
  })
50
  i += size - overlap
51
  cid += 1
@@ -55,36 +60,49 @@ def chunk_text(text, size=400, overlap=80):
55
  # =========================
56
  # 🧠 EMBEDDINGS (LOCAL)
57
  # =========================
58
- model = SentenceTransformer("all-MiniLM-L6-v2")
59
 
60
  def embed(texts):
61
- return model.encode(texts).tolist()
62
 
63
  # =========================
64
- # πŸ—„οΈ CHROMA DB (PERSISTENT)
 
65
  # =========================
66
- client_db = chromadb.PersistentClient(path="./chroma_db")
67
- collection = client_db.get_or_create_collection("rag")
68
 
69
  # =========================
70
  # πŸ“ PROCESS FILES
71
  # =========================
72
  def process_files(files):
73
-
74
  if not files:
75
- return "⚠️ No files uploaded"
76
 
77
  all_chunks = []
 
78
 
79
  for f in files:
80
- text = load_document(f.name)
81
- chunks = chunk_text(text)
82
-
83
- for c in chunks:
84
- all_chunks.append({
85
- "source": f.name,
86
- "text": c["text"]
87
- })
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
  texts = [c["text"] for c in all_chunks]
90
  embeddings = embed(texts)
@@ -96,13 +114,21 @@ def process_files(files):
96
  metadatas=[{"source": c["source"]} for c in all_chunks]
97
  )
98
 
99
- return f"βœ… Indexed {len(files)} file(s) successfully!"
 
 
 
100
 
101
  # =========================
102
  # πŸ” RETRIEVAL
103
  # =========================
104
  def retrieve(query, k=3):
 
 
 
 
105
 
 
106
  q_emb = embed([query])[0]
107
 
108
  results = collection.query(
@@ -123,18 +149,18 @@ def retrieve(query, k=3):
123
  # πŸ€– GROQ GENERATION
124
  # =========================
125
  def generate(query):
126
-
127
  docs = retrieve(query)
128
 
 
 
 
129
  context = "\n\n".join(
130
  [f"[{d['source']}]\n{d['text']}" for d in docs]
131
  )
132
 
133
- prompt = f"""
134
- You are a strict RAG assistant.
135
-
136
  Answer ONLY from the context below.
137
- If not found, say: "Not found in documents."
138
 
139
  CONTEXT:
140
  {context}
@@ -142,57 +168,79 @@ CONTEXT:
142
  QUESTION:
143
  {query}
144
 
145
- ANSWER:
146
- """
147
-
148
- response = client.chat.completions.create(
149
- model="llama3-8b-8192",
150
- messages=[
151
- {"role": "user", "content": prompt}
152
- ]
153
- )
154
 
155
- answer = response.choices[0].message.content
 
 
 
 
 
 
 
 
 
156
 
157
  sources = "\n\n".join(
158
- [f"πŸ“„ {d['source']}\n{d['text'][:200]}" for d in docs]
159
  )
160
 
161
- return answer + "\n\n---\nπŸ“š Sources:\n" + sources
162
 
163
  # =========================
164
  # πŸ’¬ CHAT FUNCTION
165
  # =========================
166
  def chat(message, history):
167
-
 
168
  reply = generate(message)
169
  history.append((message, reply))
170
-
171
  return "", history
172
 
173
  # =========================
174
- # 🎨 UI (HF GRADIO)
175
  # =========================
176
- with gr.Blocks() as app:
177
 
178
- gr.Markdown("# 🧠 Groq RAG Assistant (HF Deployable)")
 
 
 
 
 
179
 
180
  with gr.Row():
181
 
182
  with gr.Column(scale=1):
183
- files = gr.File(file_count="multiple", file_types=[".pdf", ".docx", ".txt"])
184
- process_btn = gr.Button("πŸš€ Process Files")
185
- status = gr.Textbox()
 
 
 
 
 
186
 
187
- process_btn.click(process_files, files, status)
188
 
189
  with gr.Column(scale=2):
190
- chatbot = gr.Chatbot(height=500)
191
- msg = gr.Textbox(placeholder="Ask your documents...")
192
-
193
- msg.submit(chat, [msg, chatbot], [msg, chatbot])
194
-
195
- # =========================
196
- # πŸš€ RUN
197
- # =========================
198
- app.launch()
 
 
 
 
 
 
 
 
 
 
 
 
10
  # =========================
11
  # πŸ”‘ GROQ API (HF SECRET)
12
  # =========================
13
+ # Set your secret as "GROQ_API_KEY" in HF Space Settings β†’ Variables and secrets
14
+ groq_client = Groq(api_key=os.getenv("GROQ_API_KEY"))
15
 
16
  # =========================
17
  # πŸ“„ LOAD DOCUMENTS
 
25
  return "\n".join([p.text for p in doc.paragraphs])
26
 
27
  def load_txt(path):
28
+ with open(path, "r", encoding="utf-8") as f:
29
+ return f.read()
30
 
31
  def load_document(path):
32
  ext = path.split(".")[-1].lower()
33
+ if ext == "pdf":
34
+ return load_pdf(path)
35
+ if ext == "docx":
36
+ return load_docx(path)
37
+ if ext == "txt":
38
+ return load_txt(path)
39
+ raise ValueError(f"Unsupported file type: .{ext}")
40
 
41
  # =========================
42
  # βœ‚οΈ CHUNKING
 
50
  while i < len(words):
51
  chunks.append({
52
  "id": cid,
53
+ "text": " ".join(words[i:i + size])
54
  })
55
  i += size - overlap
56
  cid += 1
 
60
  # =========================
61
  # 🧠 EMBEDDINGS (LOCAL)
62
  # =========================
63
+ embed_model = SentenceTransformer("all-MiniLM-L6-v2")
64
 
65
  def embed(texts):
66
+ return embed_model.encode(texts, show_progress_bar=False).tolist()
67
 
68
  # =========================
69
+ # πŸ—„οΈ CHROMA DB
70
+ # HF Spaces has a read-only root β€” use /tmp for writable storage
71
  # =========================
72
+ chroma_client = chromadb.PersistentClient(path="/tmp/chroma_db")
73
+ collection = chroma_client.get_or_create_collection("rag")
74
 
75
  # =========================
76
  # πŸ“ PROCESS FILES
77
  # =========================
78
  def process_files(files):
 
79
  if not files:
80
+ return "⚠️ No files uploaded."
81
 
82
  all_chunks = []
83
+ errors = []
84
 
85
  for f in files:
86
+ # Gradio on HF passes file path as a string or NamedString
87
+ file_path = f if isinstance(f, str) else f.name
88
+ if not file_path:
89
+ continue
90
+ try:
91
+ text = load_document(file_path)
92
+ if not text.strip():
93
+ errors.append(f"⚠️ {os.path.basename(file_path)} appears empty.")
94
+ continue
95
+ chunks = chunk_text(text)
96
+ for c in chunks:
97
+ all_chunks.append({
98
+ "source": os.path.basename(file_path),
99
+ "text": c["text"]
100
+ })
101
+ except Exception as e:
102
+ errors.append(f"❌ Error reading {os.path.basename(file_path)}: {e}")
103
+
104
+ if not all_chunks:
105
+ return "\n".join(errors) if errors else "⚠️ No content could be extracted."
106
 
107
  texts = [c["text"] for c in all_chunks]
108
  embeddings = embed(texts)
 
114
  metadatas=[{"source": c["source"]} for c in all_chunks]
115
  )
116
 
117
+ result = f"βœ… Indexed {len(files)} file(s) β€” {len(all_chunks)} chunks stored."
118
+ if errors:
119
+ result += "\n" + "\n".join(errors)
120
+ return result
121
 
122
  # =========================
123
  # πŸ” RETRIEVAL
124
  # =========================
125
  def retrieve(query, k=3):
126
+ # Guard: collection might be empty
127
+ count = collection.count()
128
+ if count == 0:
129
+ return []
130
 
131
+ k = min(k, count) # Can't retrieve more than what's stored
132
  q_emb = embed([query])[0]
133
 
134
  results = collection.query(
 
149
  # πŸ€– GROQ GENERATION
150
  # =========================
151
  def generate(query):
 
152
  docs = retrieve(query)
153
 
154
+ if not docs:
155
+ return "⚠️ No documents indexed yet. Please upload and process files first."
156
+
157
  context = "\n\n".join(
158
  [f"[{d['source']}]\n{d['text']}" for d in docs]
159
  )
160
 
161
+ prompt = f"""You are a strict RAG assistant.
 
 
162
  Answer ONLY from the context below.
163
+ If the answer is not found in the context, say: "Not found in documents."
164
 
165
  CONTEXT:
166
  {context}
 
168
  QUESTION:
169
  {query}
170
 
171
+ ANSWER:"""
 
 
 
 
 
 
 
 
172
 
173
+ try:
174
+ response = groq_client.chat.completions.create(
175
+ model="llama3-8b-8192",
176
+ messages=[{"role": "user", "content": prompt}],
177
+ temperature=0.2,
178
+ max_tokens=1024,
179
+ )
180
+ answer = response.choices[0].message.content
181
+ except Exception as e:
182
+ return f"❌ Groq API error: {e}"
183
 
184
  sources = "\n\n".join(
185
+ [f"πŸ“„ **{d['source']}**\n{d['text'][:200]}…" for d in docs]
186
  )
187
 
188
+ return f"{answer}\n\n---\nπŸ“š **Sources:**\n{sources}"
189
 
190
  # =========================
191
  # πŸ’¬ CHAT FUNCTION
192
  # =========================
193
  def chat(message, history):
194
+ if not message.strip():
195
+ return "", history
196
  reply = generate(message)
197
  history.append((message, reply))
 
198
  return "", history
199
 
200
  # =========================
201
+ # 🎨 GRADIO UI
202
  # =========================
203
+ with gr.Blocks(title="Groq RAG Assistant") as app:
204
 
205
+ gr.Markdown(
206
+ """# 🧠 Groq RAG Assistant
207
+ Upload your documents, then ask questions about them.
208
+ Powered by **Groq LLaMA3** + **ChromaDB** + **sentence-transformers**.
209
+ """
210
+ )
211
 
212
  with gr.Row():
213
 
214
  with gr.Column(scale=1):
215
+ gr.Markdown("### πŸ“‚ Upload Documents")
216
+ files = gr.File(
217
+ file_count="multiple",
218
+ file_types=[".pdf", ".docx", ".txt"],
219
+ label="Upload PDF / DOCX / TXT"
220
+ )
221
+ process_btn = gr.Button("πŸš€ Process Files", variant="primary")
222
+ status = gr.Textbox(label="Status", interactive=False)
223
 
224
+ process_btn.click(fn=process_files, inputs=files, outputs=status)
225
 
226
  with gr.Column(scale=2):
227
+ gr.Markdown("### πŸ’¬ Ask Your Documents")
228
+ chatbot = gr.Chatbot(height=480, bubble_full_width=False)
229
+ msg = gr.Textbox(
230
+ placeholder="Ask a question about your documents…",
231
+ label="Your question",
232
+ lines=2
233
+ )
234
+ with gr.Row():
235
+ submit_btn = gr.Button("Send", variant="primary")
236
+ clear_btn = gr.Button("Clear Chat")
237
+
238
+ submit_btn.click(fn=chat, inputs=[msg, chatbot], outputs=[msg, chatbot])
239
+ msg.submit(fn=chat, inputs=[msg, chatbot], outputs=[msg, chatbot])
240
+ clear_btn.click(fn=lambda: ([], ""), outputs=[chatbot, msg])
241
+
242
+ # =========================
243
+ # πŸš€ LAUNCH
244
+ # =========================
245
+ if __name__ == "__main__":
246
+ app.launch()