sofzcc commited on
Commit
5de21d9
Β·
verified Β·
1 Parent(s): 636ac20

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +51 -67
app.py CHANGED
@@ -388,93 +388,77 @@ class RAGIndex:
388
  return answer
389
 
390
  def answer(self, question: str) -> str:
391
- """Answer a question using RAG - simplified extractive approach."""
392
  if not self.initialized:
393
  return "❌ Assistant not properly initialized. Please check the logs."
394
-
395
  if not question or not question.strip():
396
  return "Please ask a question."
397
-
398
  if self.index is None or not self.chunks:
399
  return (
400
  f"πŸ“š Knowledge base is empty.\n\n"
401
  f"Please add documents to: `{KB_DIR}`\n"
402
  f"Supported formats: .txt, .md, .pdf, .docx"
403
  )
404
-
405
- # Retrieve relevant contexts
406
  contexts = self.retrieve(question, top_k=3)
407
-
408
  if not contexts:
409
  return (
410
  f"{NO_ANSWER_MSG}\n\n"
411
  f"πŸ’‘ Try rephrasing your question or check if relevant documents exist in the knowledge base."
412
  )
413
-
414
  used_sources = set()
415
- best_context = None
416
- best_score = 0
417
-
418
- # Find the best matching context
419
  for ctx, source, score in contexts:
420
  used_sources.add(source)
421
- if score > best_score:
422
- best_score = score
423
- best_context = ctx
424
-
425
- if not best_context:
426
- return f"{NO_ANSWER_MSG}"
427
-
428
- # AGGRESSIVE cleaning of the context
429
- def deep_clean(text):
430
- """Remove ALL markdown, bullets, numbers, emojis, and formatting."""
431
- # Remove emojis and special characters
432
- text = re.sub(r'[πŸ“˜πŸ“„πŸŸ’πŸŸ‘πŸŸ βœ“βœ—βŒβš οΈπŸ’‘πŸ“š]', '', text)
433
- # Remove markdown headers (# ## ###)
434
- text = re.sub(r'^#{1,6}\s+', '', text, flags=re.MULTILINE)
435
- # Remove numbered lists (1. 2. 3.)
436
- text = re.sub(r'^\s*\d+\.\s+', '', text, flags=re.MULTILINE)
437
- # Remove bullet points (- * β€’)
438
- text = re.sub(r'^\s*[-*β€’]\s+', '', text, flags=re.MULTILINE)
439
- # Remove bold/italic (**text** *text*)
440
- text = re.sub(r'\*\*([^*]+)\*\*', r'\1', text)
441
- text = re.sub(r'\*([^*]+)\*', r'\1', text)
442
- # Remove extra colons from labels
443
- text = re.sub(r':\s*$', '', text, flags=re.MULTILINE)
444
- # Clean multiple spaces
445
- text = re.sub(r'\s+', ' ', text)
446
- # Remove "Good:" "Bad:" type prefixes
447
- text = re.sub(r'^(Good|Bad|Example|Note):\s*', '', text, flags=re.MULTILINE)
448
- return text.strip()
449
-
450
- cleaned = deep_clean(best_context)
451
-
452
- # Extract just the most relevant sentences (3-4 sentences max)
453
- sentences = [s.strip() + '.' for s in cleaned.split('.') if len(s.strip()) > 20]
454
- answer_text = ' '.join(sentences[:4]) # First 4 good sentences
455
-
456
- # If we got good text, try to generate a natural answer
457
- if len(answer_text) > 50:
458
- # Simple prompt for FLAN-T5
459
- prompt = f"Question: {question}\n\nInformation: {answer_text[:800]}\n\nWrite a clear answer in 2-3 sentences:"
460
-
461
- try:
462
- generated = self._generate_from_context(prompt, max_new_tokens=150)
463
- generated = generated.strip()
464
-
465
- # Only use generated answer if it looks good
466
- if (len(generated) > 30 and
467
- not generated.startswith(("Do NOT", "You are", "##", "**")) and
468
- generated.count(':') < 3):
469
- answer_text = generated
470
- # Otherwise, keep the cleaned extractive answer
471
-
472
- except Exception as e:
473
- print(f"Generation error (using extractive fallback): {e}")
474
- # Keep the cleaned extractive answer
475
-
476
  sources_str = ", ".join(sorted(used_sources)) if used_sources else "N/A"
477
-
478
  return (
479
  f"**Answer:** {answer_text}\n\n"
480
  f"**Sources:** {sources_str}"
 
388
  return answer
389
 
390
  def answer(self, question: str) -> str:
391
+ """Answer a question using RAG with a generative seq2seq model (Flan-T5, BART, etc.)."""
392
  if not self.initialized:
393
  return "❌ Assistant not properly initialized. Please check the logs."
394
+
395
  if not question or not question.strip():
396
  return "Please ask a question."
397
+
398
  if self.index is None or not self.chunks:
399
  return (
400
  f"πŸ“š Knowledge base is empty.\n\n"
401
  f"Please add documents to: `{KB_DIR}`\n"
402
  f"Supported formats: .txt, .md, .pdf, .docx"
403
  )
404
+
405
+ # 1) Retrieve relevant contexts
406
  contexts = self.retrieve(question, top_k=3)
407
+
408
  if not contexts:
409
  return (
410
  f"{NO_ANSWER_MSG}\n\n"
411
  f"πŸ’‘ Try rephrasing your question or check if relevant documents exist in the knowledge base."
412
  )
413
+
414
  used_sources = set()
415
+ context_texts = []
416
+
 
 
417
  for ctx, source, score in contexts:
418
  used_sources.add(source)
419
+ cleaned_ctx = clean_context_text(ctx)
420
+ if cleaned_ctx:
421
+ context_texts.append(cleaned_ctx)
422
+
423
+ if not context_texts:
424
+ return (
425
+ f"{NO_ANSWER_MSG}\n\n"
426
+ f"πŸ’‘ Try adding more detailed documents to the knowledge base."
427
+ )
428
+
429
+ # 2) Combine contexts into a single evidence block
430
+ combined_context = "\n\n".join(context_texts)
431
+
432
+ # Keep context at a reasonable size for the model
433
+ max_context_chars = 3000
434
+ if len(combined_context) > max_context_chars:
435
+ combined_context = combined_context[:max_context_chars]
436
+
437
+ # 3) Build a prompt that works for both BART (summarization-style)
438
+ # and instruction-tuned models like Flan-T5.
439
+ prompt = (
440
+ "You are an assistant that answers questions about a knowledge base.\n"
441
+ "Using only the information in the passages below, answer the question in 2–4 sentences.\n"
442
+ "Explain in clear, natural language. Do NOT copy section numbers, markdown headings, or bullet symbols.\n\n"
443
+ f"Passages:\n{combined_context}\n\n"
444
+ f"Question: {question}\n\n"
445
+ "Answer:"
446
+ )
447
+
448
+ try:
449
+ answer_text = self._generate_from_context(prompt, max_new_tokens=180).strip()
450
+ except Exception as e:
451
+ print(f"Generation error: {e}")
452
+ return (
453
+ "There was an error while generating the answer. "
454
+ "Please try again with a shorter question or different wording."
455
+ )
456
+
457
+ if not answer_text:
458
+ answer_text = NO_ANSWER_MSG
459
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
460
  sources_str = ", ".join(sorted(used_sources)) if used_sources else "N/A"
461
+
462
  return (
463
  f"**Answer:** {answer_text}\n\n"
464
  f"**Sources:** {sources_str}"