ZunairaHawwar commited on
Commit
50adcc7
Β·
verified Β·
1 Parent(s): 6e9c490

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +329 -58
app.py CHANGED
@@ -92,15 +92,15 @@ class LangChainRAGSystem:
92
  Use the following context to answer the user's question comprehensively and accurately.
93
  Always provide relevant video links, website links, or resources when available in the context.
94
  If you don't know the answer based on the context, say so clearly.
95
-
96
  Context: {context}
97
-
98
  Chat History: {chat_history}
99
-
100
  Human: {question}
101
-
102
  Assistant: I'll help you with that based on the iCodeGuru knowledge base.
103
-
104
  """
105
 
106
  PROMPT = PromptTemplate(
@@ -108,7 +108,8 @@ class LangChainRAGSystem:
108
  input_variables=["context", "chat_history", "question"]
109
  )
110
 
111
- if self.vectorstore and self.vectorstore._collection.count() > 0:
 
112
  # Create retriever
113
  retriever = self.vectorstore.as_retriever(
114
  search_type="similarity",
@@ -124,8 +125,11 @@ class LangChainRAGSystem:
124
  return_source_documents=True,
125
  verbose=True
126
  )
127
- else:
128
- st.warning("⚠️ No documents in knowledge base. Please refresh the knowledge base first.")
 
 
 
129
 
130
  def load_and_process_documents(self) -> List[Document]:
131
  """Load and process JSON documents from the docs directory."""
@@ -230,15 +234,22 @@ class LangChainRAGSystem:
230
 
231
  st.success(f"βœ… Successfully ingested {len(chunks)} document chunks!")
232
 
233
- # Recreate retrieval chain with new data
234
  self.setup_retrieval_chain()
235
 
 
 
 
 
 
 
 
236
  return True
237
 
238
  except Exception as e:
239
  st.error(f"❌ Error during ingestion: {str(e)}")
240
  return False
241
-
242
  def get_answer(self, question: str) -> dict:
243
  """Get answer for a user question."""
244
  if not self.retrieval_chain:
@@ -248,9 +259,28 @@ class LangChainRAGSystem:
248
  }
249
 
250
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  # Get response from the chain
252
  response = self.retrieval_chain({"question": question})
253
  return response
 
254
  except Exception as e:
255
  return {
256
  "answer": f"❌ Error getting answer: {str(e)}",
@@ -269,7 +299,7 @@ def get_rag_system():
269
  return LangChainRAGSystem()
270
 
271
  def main():
272
- """Main Streamlit application."""
273
  st.set_page_config(
274
  page_title="EduBot for iCodeGuru",
275
  page_icon="πŸŽ“",
@@ -277,89 +307,317 @@ def main():
277
  initial_sidebar_state="expanded"
278
  )
279
 
280
- # Header
281
- st.title("πŸŽ“ EduBot for @icodeguru0")
282
- st.markdown("**Powered by LangChain** | Ask anything based on pre-loaded iCodeGuru knowledge.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
 
284
  # Initialize RAG system
285
  rag_system = get_rag_system()
286
 
287
- # Sidebar for admin functions
288
  with st.sidebar:
289
- st.header("βš™οΈ Admin Panel")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
 
291
- if st.button("πŸ”„ Refresh Knowledge Base", type="primary"):
292
- success = rag_system.ingest_documents()
293
- if success:
294
- st.balloons()
 
295
 
296
- if st.button("πŸ—‘οΈ Clear Conversation"):
297
- rag_system.reset_conversation()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
 
299
  st.markdown("---")
300
- st.subheader("πŸ“Š System Info")
301
 
302
- # Show vectorstore stats
 
 
303
  if rag_system.vectorstore:
304
  try:
305
  doc_count = rag_system.vectorstore._collection.count()
306
- st.metric("Documents in KB", doc_count)
 
 
 
 
 
307
  except:
308
- st.metric("Documents in KB", "N/A")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
 
310
  st.markdown("---")
311
- st.caption("🧠 **ChromaDB** for vector storage")
312
- st.caption("⚑ **Groq LLM** for answers")
313
- st.caption("πŸ”— **LangChain** for orchestration")
314
-
315
- # Main chat interface
316
- st.markdown("---")
 
 
 
 
 
 
 
 
 
 
317
 
318
- # Initialize session state for chat history
 
319
  if "messages" not in st.session_state:
320
  st.session_state.messages = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321
 
322
- # Display chat history
323
- for message in st.session_state.messages:
324
- with st.chat_message(message["role"]):
325
- st.markdown(message["content"])
326
- if "sources" in message and message["sources"]:
327
- with st.expander("πŸ“š Sources"):
328
- for i, source in enumerate(message["sources"], 1):
329
- st.markdown(f"**Source {i}:** {source}")
330
 
331
- # User input
332
- if prompt := st.chat_input("πŸ’¬ Ask your question about iCodeGuru..."):
333
- # Add user message to chat history
334
- st.session_state.messages.append({"role": "user", "content": prompt})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
 
336
  # Display user message
337
  with st.chat_message("user"):
338
- st.markdown(prompt)
339
 
340
- # Get assistant response
341
  with st.chat_message("assistant"):
342
- with st.spinner("πŸ€” Thinking..."):
343
- response = rag_system.get_answer(prompt)
344
- answer = response.get("answer", "No answer available.")
345
  source_docs = response.get("source_documents", [])
346
 
347
  st.markdown(answer)
348
 
349
- # Show sources if available
350
  if source_docs:
351
  sources = []
352
- for doc in source_docs[:3]: # Show top 3 sources
353
- source = doc.metadata.get('source_file', 'Unknown source')
354
- content_preview = doc.page_content[:100] + "..." if len(doc.page_content) > 100 else doc.page_content
355
- sources.append(f"{source}: {content_preview}")
356
 
357
  if sources:
358
- with st.expander("πŸ“š Sources"):
359
  for i, source in enumerate(sources, 1):
360
- st.markdown(f"**Source {i}:** {source}")
 
 
 
 
 
361
 
362
- # Add to session state with sources
363
  st.session_state.messages.append({
364
  "role": "assistant",
365
  "content": answer,
@@ -369,6 +627,19 @@ def main():
369
  st.session_state.messages.append({"role": "assistant", "content": answer})
370
  else:
371
  st.session_state.messages.append({"role": "assistant", "content": answer})
 
 
 
 
 
 
 
 
 
 
 
 
 
372
 
373
  if __name__ == "__main__":
374
  main()
 
92
  Use the following context to answer the user's question comprehensively and accurately.
93
  Always provide relevant video links, website links, or resources when available in the context.
94
  If you don't know the answer based on the context, say so clearly.
95
+
96
  Context: {context}
97
+
98
  Chat History: {chat_history}
99
+
100
  Human: {question}
101
+
102
  Assistant: I'll help you with that based on the iCodeGuru knowledge base.
103
+
104
  """
105
 
106
  PROMPT = PromptTemplate(
 
108
  input_variables=["context", "chat_history", "question"]
109
  )
110
 
111
+ # Always try to create retriever - let it handle empty collections gracefully
112
+ try:
113
  # Create retriever
114
  retriever = self.vectorstore.as_retriever(
115
  search_type="similarity",
 
125
  return_source_documents=True,
126
  verbose=True
127
  )
128
+ st.success("βœ… Retrieval chain setup successfully!")
129
+
130
+ except Exception as e:
131
+ st.warning(f"⚠️ Retrieval chain setup issue: {str(e)}")
132
+ self.retrieval_chain = None
133
 
134
  def load_and_process_documents(self) -> List[Document]:
135
  """Load and process JSON documents from the docs directory."""
 
234
 
235
  st.success(f"βœ… Successfully ingested {len(chunks)} document chunks!")
236
 
237
+ # Force recreate retrieval chain with new data
238
  self.setup_retrieval_chain()
239
 
240
+ # Verify the setup worked
241
+ try:
242
+ doc_count = self.vectorstore._collection.count()
243
+ st.info(f"πŸ“Š Knowledge base now contains {doc_count} documents")
244
+ except:
245
+ st.info("πŸ“Š Knowledge base updated successfully")
246
+
247
  return True
248
 
249
  except Exception as e:
250
  st.error(f"❌ Error during ingestion: {str(e)}")
251
  return False
252
+
253
  def get_answer(self, question: str) -> dict:
254
  """Get answer for a user question."""
255
  if not self.retrieval_chain:
 
259
  }
260
 
261
  try:
262
+ # Check if vectorstore has documents before querying
263
+ doc_count = 0
264
+ try:
265
+ doc_count = self.vectorstore._collection.count()
266
+ except:
267
+ # If count fails, try a simple similarity search to test
268
+ try:
269
+ test_results = self.vectorstore.similarity_search("test", k=1)
270
+ doc_count = len(test_results) if test_results else 0
271
+ except:
272
+ doc_count = 0
273
+
274
+ if doc_count == 0:
275
+ return {
276
+ "answer": "⚠️ No documents found in knowledge base. Please refresh the knowledge base first.",
277
+ "source_documents": []
278
+ }
279
+
280
  # Get response from the chain
281
  response = self.retrieval_chain({"question": question})
282
  return response
283
+
284
  except Exception as e:
285
  return {
286
  "answer": f"❌ Error getting answer: {str(e)}",
 
299
  return LangChainRAGSystem()
300
 
301
  def main():
302
+ """Main Streamlit application with enhanced UI."""
303
  st.set_page_config(
304
  page_title="EduBot for iCodeGuru",
305
  page_icon="πŸŽ“",
 
307
  initial_sidebar_state="expanded"
308
  )
309
 
310
+ # Custom CSS for better styling
311
+ st.markdown("""
312
+ <style>
313
+ .main-header {
314
+ background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
315
+ padding: 2rem;
316
+ border-radius: 10px;
317
+ margin-bottom: 2rem;
318
+ text-align: center;
319
+ }
320
+ .main-header h1 {
321
+ color: white;
322
+ margin: 0;
323
+ font-size: 2.5rem;
324
+ }
325
+ .main-header p {
326
+ color: #f0f0f0;
327
+ margin: 0.5rem 0 0 0;
328
+ font-size: 1.1rem;
329
+ }
330
+ .metric-card {
331
+ background: #f8f9fa;
332
+ padding: 1rem;
333
+ border-radius: 10px;
334
+ border-left: 4px solid #667eea;
335
+ margin: 0.5rem 0;
336
+ }
337
+ .status-online {
338
+ color: #28a745;
339
+ font-weight: bold;
340
+ }
341
+ .status-offline {
342
+ color: #dc3545;
343
+ font-weight: bold;
344
+ }
345
+ .chat-input {
346
+ position: fixed;
347
+ bottom: 0;
348
+ background: white;
349
+ padding: 1rem;
350
+ border-top: 1px solid #e0e0e0;
351
+ }
352
+ .source-card {
353
+ background: #f8f9fa;
354
+ border: 1px solid #e9ecef;
355
+ border-radius: 8px;
356
+ padding: 0.8rem;
357
+ margin: 0.3rem 0;
358
+ }
359
+ .quick-action-btn {
360
+ background: linear-gradient(45deg, #667eea, #764ba2);
361
+ color: white;
362
+ border: none;
363
+ padding: 0.5rem 1rem;
364
+ border-radius: 20px;
365
+ margin: 0.2rem;
366
+ }
367
+ </style>
368
+ """, unsafe_allow_html=True)
369
+
370
+ # Enhanced Header
371
+ st.markdown("""
372
+ <div class="main-header">
373
+ <h1>πŸŽ“ EduBot for iCodeGuru</h1>
374
+ <p>Powered by LangChain | Your AI Programming Assistant</p>
375
+ </div>
376
+ """, unsafe_allow_html=True)
377
 
378
  # Initialize RAG system
379
  rag_system = get_rag_system()
380
 
381
+ # Enhanced Sidebar
382
  with st.sidebar:
383
+ st.markdown("### βš™οΈ Control Panel")
384
+
385
+ # Status indicator
386
+ if rag_system.vectorstore:
387
+ try:
388
+ doc_count = rag_system.vectorstore._collection.count()
389
+ if doc_count > 0:
390
+ st.markdown('<p class="status-online">🟒 System Online</p>', unsafe_allow_html=True)
391
+ else:
392
+ st.markdown('<p class="status-offline">πŸ”΄ No Knowledge Base</p>', unsafe_allow_html=True)
393
+ except:
394
+ st.markdown('<p class="status-offline">🟑 System Loading</p>', unsafe_allow_html=True)
395
+
396
+ st.markdown("---")
397
+
398
+ # Admin Actions
399
+ col1, col2 = st.columns(2)
400
+ with col1:
401
+ if st.button("πŸ”„ Refresh KB", type="primary", use_container_width=True):
402
+ with st.spinner("Loading documents..."):
403
+ success = rag_system.ingest_documents()
404
+ if success:
405
+ st.balloons()
406
+ st.success("Knowledge base updated!")
407
+ st.rerun()
408
 
409
+ with col2:
410
+ if st.button("πŸ—‘οΈ Clear Chat", use_container_width=True):
411
+ rag_system.reset_conversation()
412
+ st.session_state.messages = []
413
+ st.rerun()
414
 
415
+ # Quick Actions
416
+ st.markdown("### ⚑ Quick Actions")
417
+ if st.button("πŸ“š Show Available Topics", use_container_width=True):
418
+ st.session_state.show_topics = True
419
+
420
+ if st.button("πŸ’‘ Get Random Tip", use_container_width=True):
421
+ random_questions = [
422
+ "What are the best programming practices?",
423
+ "How to optimize code performance?",
424
+ "What are common coding mistakes?",
425
+ "Explain object-oriented programming",
426
+ "What is the difference between frontend and backend?"
427
+ ]
428
+ import random
429
+ random_q = random.choice(random_questions)
430
+ st.session_state.messages.append({"role": "user", "content": f"🎲 {random_q}"})
431
+ st.rerun()
432
 
433
  st.markdown("---")
 
434
 
435
+ # Enhanced System Info
436
+ st.markdown("### πŸ“Š System Statistics")
437
+
438
  if rag_system.vectorstore:
439
  try:
440
  doc_count = rag_system.vectorstore._collection.count()
441
+ st.markdown(f"""
442
+ <div class="metric-card">
443
+ <strong>πŸ“„ Documents:</strong><br>
444
+ <span style="font-size: 1.5rem; color: #667eea;">{doc_count}</span>
445
+ </div>
446
+ """, unsafe_allow_html=True)
447
  except:
448
+ st.markdown("""
449
+ <div class="metric-card">
450
+ <strong>πŸ“„ Documents:</strong><br>
451
+ <span style="color: #dc3545;">N/A</span>
452
+ </div>
453
+ """, unsafe_allow_html=True)
454
+
455
+ # Conversation count
456
+ chat_count = len([msg for msg in st.session_state.get("messages", []) if msg["role"] == "user"])
457
+ st.markdown(f"""
458
+ <div class="metric-card">
459
+ <strong>πŸ’¬ Questions Asked:</strong><br>
460
+ <span style="font-size: 1.5rem; color: #28a745;">{chat_count}</span>
461
+ </div>
462
+ """, unsafe_allow_html=True)
463
 
464
  st.markdown("---")
465
+
466
+ # Tech Stack
467
+ st.markdown("### πŸ› οΈ Technology Stack")
468
+ tech_stack = {
469
+ "🧠": "ChromaDB",
470
+ "⚑": "Groq LLM",
471
+ "πŸ”—": "LangChain",
472
+ "🎨": "Streamlit",
473
+ "πŸ€—": "HuggingFace"
474
+ }
475
+
476
+ for icon, tech in tech_stack.items():
477
+ st.markdown(f"{icon} **{tech}**")
478
+
479
+ st.markdown("---")
480
+ st.markdown("*Built with ❀️ for iCodeGuru community*")
481
 
482
+ # Main Content Area
483
+ # Initialize session state
484
  if "messages" not in st.session_state:
485
  st.session_state.messages = []
486
+ if "show_topics" not in st.session_state:
487
+ st.session_state.show_topics = False
488
+
489
+ # Welcome message for new users
490
+ if len(st.session_state.messages) == 0:
491
+ st.markdown("""
492
+ ### πŸ‘‹ Welcome to EduBot!
493
+
494
+ I'm your AI programming assistant, ready to help you with:
495
+ - **Programming concepts** and tutorials
496
+ - **Code examples** and best practices
497
+ - **Debugging** and troubleshooting
498
+ - **Learning resources** and recommendations
499
+
500
+ πŸš€ **Get started by asking me anything about programming!**
501
+ """)
502
+
503
+ # Sample questions
504
+ st.markdown("### πŸ’‘ Try these sample questions:")
505
+ sample_questions = [
506
+ "What is Python?",
507
+ "How to create a REST API?",
508
+ "Explain machine learning basics",
509
+ "Best practices for web development"
510
+ ]
511
+
512
+ cols = st.columns(2)
513
+ for i, question in enumerate(sample_questions):
514
+ with cols[i % 2]:
515
+ if st.button(f"❓ {question}", key=f"sample_{i}", use_container_width=True):
516
+ st.session_state.messages.append({"role": "user", "content": question})
517
+ st.rerun()
518
+
519
+ # Show topics if requested
520
+ if st.session_state.get("show_topics", False):
521
+ with st.expander("πŸ“š Available Topics", expanded=True):
522
+ st.markdown("""
523
+ Based on your knowledge base, I can help with:
524
+ - Web Development (HTML, CSS, JavaScript)
525
+ - Python Programming
526
+ - Data Science & Machine Learning
527
+ - Database Management
528
+ - Software Engineering Practices
529
+ - API Development
530
+ - And much more!
531
+
532
+ *Ask me anything specific about these topics!*
533
+ """)
534
+ if st.button("Close Topics"):
535
+ st.session_state.show_topics = False
536
+ st.rerun()
537
+
538
+ # Chat History with Enhanced Styling
539
+ if st.session_state.messages:
540
+ st.markdown("### πŸ’¬ Conversation History")
541
+
542
+ for i, message in enumerate(st.session_state.messages):
543
+ with st.chat_message(message["role"]):
544
+ # Enhanced message display
545
+ if message["role"] == "user":
546
+ st.markdown(f"**You:** {message['content']}")
547
+ else:
548
+ st.markdown(message["content"])
549
+
550
+ # Enhanced sources display
551
+ if "sources" in message and message["sources"]:
552
+ with st.expander(f"πŸ“š Sources ({len(message['sources'])} found)", expanded=False):
553
+ for j, source in enumerate(message["sources"], 1):
554
+ st.markdown(f"""
555
+ <div class="source-card">
556
+ <strong>Source {j}:</strong><br>
557
+ {source}
558
+ </div>
559
+ """, unsafe_allow_html=True)
560
+
561
+ # Enhanced User Input Area
562
+ st.markdown("---")
563
 
564
+ # Input with suggestions
565
+ col1, col2 = st.columns([4, 1])
 
 
 
 
 
 
566
 
567
+ with col1:
568
+ user_input = st.text_input(
569
+ "πŸ’¬ Ask your question:",
570
+ placeholder="e.g., How do I create a Python function?",
571
+ key="user_input"
572
+ )
573
+
574
+ with col2:
575
+ send_button = st.button("Send πŸš€", type="primary", use_container_width=True)
576
+
577
+ # Alternative chat input (modern style)
578
+ if prompt := st.chat_input("πŸ’¬ Ask anything about programming..."):
579
+ user_input = prompt
580
+ send_button = True
581
+
582
+ # Process user input
583
+ if (send_button and user_input) or prompt:
584
+ question = user_input if send_button else prompt
585
+
586
+ # Add user message
587
+ st.session_state.messages.append({"role": "user", "content": question})
588
 
589
  # Display user message
590
  with st.chat_message("user"):
591
+ st.markdown(f"**You:** {question}")
592
 
593
+ # Get and display assistant response
594
  with st.chat_message("assistant"):
595
+ with st.spinner("πŸ€” Let me think about that..."):
596
+ response = rag_system.get_answer(question)
597
+ answer = response.get("answer", "I couldn't find an answer to that question.")
598
  source_docs = response.get("source_documents", [])
599
 
600
  st.markdown(answer)
601
 
602
+ # Enhanced sources display
603
  if source_docs:
604
  sources = []
605
+ for doc in source_docs[:4]: # Show top 4 sources
606
+ source_file = doc.metadata.get('source_file', 'Unknown')
607
+ content_preview = doc.page_content[:150] + "..." if len(doc.page_content) > 150 else doc.page_content
608
+ sources.append(f"**{source_file}**\n{content_preview}")
609
 
610
  if sources:
611
+ with st.expander(f"πŸ“š Sources ({len(sources)} found)", expanded=False):
612
  for i, source in enumerate(sources, 1):
613
+ st.markdown(f"""
614
+ <div class="source-card">
615
+ <strong>πŸ“„ Source {i}:</strong><br>
616
+ {source}
617
+ </div>
618
+ """, unsafe_allow_html=True)
619
 
620
+ # Add to session state
621
  st.session_state.messages.append({
622
  "role": "assistant",
623
  "content": answer,
 
627
  st.session_state.messages.append({"role": "assistant", "content": answer})
628
  else:
629
  st.session_state.messages.append({"role": "assistant", "content": answer})
630
+
631
+ # Clear input and rerun
632
+ if send_button:
633
+ st.rerun()
634
+
635
+ # Footer
636
+ st.markdown("---")
637
+ st.markdown("""
638
+ <div style="text-align: center; color: #666; padding: 1rem;">
639
+ <p>πŸŽ“ <strong>EduBot for iCodeGuru</strong> | Empowering developers worldwide</p>
640
+ <p>Made with ❀️ using Streamlit β€’ LangChain β€’ ChromaDB β€’ Groq</p>
641
+ </div>
642
+ """, unsafe_allow_html=True)
643
 
644
  if __name__ == "__main__":
645
  main()