M17idd commited on
Commit
c673adf
·
1 Parent(s): 39f1557

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +97 -142
app.py CHANGED
@@ -500,20 +500,9 @@ st.markdown("""
500
  }
501
  </style>
502
  """, unsafe_allow_html=True)
503
-
504
-
505
-
506
- import os
507
- import re
508
- import docx
509
- import streamlit as st
510
- import concurrent.futures
511
- from hazm import Normalizer
512
- from rapidfuzz import fuzz
513
- from langchain.schema import SystemMessage, HumanMessage
514
-
515
  folder_path = '46'
516
  normalizer = Normalizer()
 
517
 
518
  @st.cache_data(show_spinner="در حال پردازش اسناد... لطفاً صبور باشید.")
519
  def load_and_process_documents(path):
@@ -521,43 +510,34 @@ def load_and_process_documents(path):
521
  try:
522
  full_path = os.path.join(path, filename)
523
  doc = docx.Document(full_path)
524
- text = "\n".join([para.text for para in doc.paragraphs])
525
  normalized = normalizer.normalize(text)
526
- return filename, normalized
 
527
  except Exception as e:
528
  print(f"Error processing {filename}: {e}")
529
- return filename, ""
530
-
531
- filenames = [f for f in os.listdir(path) if f.endswith(".docx")]
532
- doc_texts = {}
533
-
534
  with concurrent.futures.ThreadPoolExecutor() as executor:
535
- for filename, content in executor.map(process_docx, filenames):
536
- doc_texts[filename] = content
537
 
538
- return doc_texts
539
 
540
- doc_texts = load_and_process_documents(folder_path)
 
 
541
 
542
  def clean_text(text):
543
- return re.sub(r'[^آ-ی۰-۹0-9،.؟!؛+\-* ]+', '', text)
 
 
544
 
545
- def find_closest_filenames(query, filenames, top_n=3):
546
- scores = [(f, fuzz.partial_ratio(query, f)) for f in filenames]
547
- scores.sort(key=lambda x: x[1], reverse=True)
548
- return [score[0] for score in scores[:top_n]]
549
 
550
- import re
551
- import numpy as np
552
  from sklearn.feature_extraction.text import TfidfVectorizer
553
  from sklearn.cluster import KMeans
554
- from nltk.tokenize import sent_tokenize
555
  from sklearn.metrics.pairwise import cosine_similarity
556
 
557
- # توابع کمکی
558
- def clean_text(text):
559
- return re.sub(r'[^آ-ی۰-۹0-9،.؟!؛+\-* ]+', '', text)
560
-
561
  def summarize_text_with_kmeans(text, num_sentences=3):
562
  sentences = sent_tokenize(text) # تقسیم متن به جملات
563
  tfidf_vectorizer = TfidfVectorizer()
@@ -575,122 +555,97 @@ def summarize_text_with_kmeans(text, num_sentences=3):
575
  summary = [sentences[i] for i in similar_sentences_indices]
576
  return ' '.join(summary)
577
 
578
- def find_best_answer(query, top_files, doc_texts):
579
- best_match = None
580
- best_score = 0
581
- best_text = ""
582
-
583
- for filename in top_files:
584
- text = doc_texts[filename]
585
- similarity = fuzz.partial_ratio(query, text)
586
- if similarity > best_score:
587
- best_score = similarity
588
- best_match = filename
589
- best_text = text
590
-
591
- # خلاصه کردن متن با استفاده از KMeans
592
- if best_text:
593
- summary = summarize_text_with_kmeans(best_text)
594
- else:
595
- summary = "متنی برای خلاصه‌سازی پیدا نشد."
596
-
597
- return best_match, summary
598
-
599
-
600
- # حالا این رو در کد اصلی استفاده می‌کنیم:
601
  if query:
602
- # مرحله 1: درخواست از مدل برای بررسی وجود پاسخ در نام فایل‌ها
603
- top_files = find_closest_filenames(query, list(doc_texts.keys()), top_n=3)
604
- best_file, matched_text = find_best_answer(query, top_files, doc_texts)
605
-
606
- if best_file: # اگر پاسخ از اسم فایل‌ها پیدا شد
607
- prompt_for_model_1 = f"""
608
- لطفاً با توجه به سوال زیر و محتوای سند موجود، یک پاسخ نهایی حرفه‌ای، دقیق و روان تولید کن. فقط از متن سند استفاده کن. اگر اطلاعات کافی در متن وجود ندارد، صادقانه اعلام کن.
609
- سوال:
610
- {query}
611
- محتوای سند:
612
- {matched_text}
613
- پاسخ نهایی:
614
- """
615
- response_model_1 = llm([
616
- SystemMessage(content="You are a helpful assistant."),
617
- HumanMessage(content=prompt_for_model_1)
618
- ])
619
- rewritten = clean_text(response_model_1.content.strip())
620
-
621
- # مرحله 2: بررسی پاسخ مدل اول
622
- prompt_for_model_2 = f"""
623
- سوال:
624
- {query}
625
- آیا مدل اول به درستی جواب داده است؟
626
- پاسخ مدل اول:
627
- {rewritten}
628
- لطفاً تایید کن که آیا این پاسخ مناسب است یا خیر. اگر مناسب نیست، لطفاً اطلاعات بیشتری از متن موجود در سند بده.
629
- """
630
- response_model_2 = llm([
631
- SystemMessage(content="You are a helpful assistant."),
632
- HumanMessage(content=prompt_for_model_2)
633
- ])
634
- answer_model_2 = clean_text(response_model_2.content.strip())
635
-
636
- if "تایید" in answer_model_2: # اگر تایید شد که پاسخ درست است
637
- st.markdown(f'<div class="chat-message">{rewritten}</div>', unsafe_allow_html=True)
638
- else:
639
- # مرحله 3: جستجو در متن کل سندها
640
- best_file_from_text = None
641
- best_answer_from_text = ""
642
- top_files_for_text = find_closest_filenames(query, list(doc_texts.keys()), top_n=3)
643
-
644
- for filename in top_files_for_text:
645
- text = doc_texts[filename]
646
- similarity = fuzz.partial_ratio(query, text)
647
- if similarity > 50: # حداقل شباهت برای انتخاب پاسخ
648
- best_file_from_text = filename
649
- best_answer_from_text = text
650
- break # اگر جواب خوبی پیدا شد، جستجو را متوقف می‌کنیم
651
-
652
- if best_file_from_text: # اگر جوابی از متن پیدا شد
653
- prompt_for_model_3 = f"""
654
- لطفاً با توجه به سوال زیر و محتوای سند موجود، یک پاسخ نهایی حرفه‌ای، دقیق و روان تولید کن. فقط از متن سند استفاده کن. اگر اطلاعات کافی در متن وجود ندارد، صادقانه اعلام کن.
655
  سوال:
656
  {query}
657
- محتوای سند:
658
- {best_answer_from_text}
659
  پاسخ نهایی:
660
  """
661
- response_model_3 = llm([
662
  SystemMessage(content="You are a helpful assistant."),
663
- HumanMessage(content=prompt_for_model_3)
664
  ])
665
- rewritten_model_3 = clean_text(response_model_3.content.strip())
666
-
667
- # بررسی تایید مدل 2
668
- prompt_for_model_4 = f"""
 
 
669
  سوال:
670
  {query}
671
- آیا مدل دوم به درستی جواب داده است؟
672
- پاسخ مدل دوم:
673
- {rewritten_model_3}
674
- لطفاً تایید کن که آیا این پاسخ مناسب است یا خیر.
675
  """
676
- response_model_4 = llm([
677
  SystemMessage(content="You are a helpful assistant."),
678
- HumanMessage(content=prompt_for_model_4)
679
  ])
680
- answer_model_4 = clean_text(response_model_4.content.strip())
681
-
682
- if "تایید" in answer_model_4: # اگر تایید شد که پاسخ درست است
683
- st.markdown(f'<div class="chat-message">{rewritten_model_3}</div>', unsafe_allow_html=True)
684
- else:
685
- # مرحله آخر: اگر تایید نشده بود، از دانش خود مدل استفاده کن
686
- prompt_for_model_5 = f"""
687
- سوال:
688
- {query}
689
- لطفاً جواب دقیقی از دانش خودت بده.
690
- """
691
- response_model_5 = llm([
692
- SystemMessage(content="You are a knowledgeable assistant."),
693
- HumanMessage(content=prompt_for_model_5)
694
- ])
695
- rewritten_model_5 = clean_text(response_model_5.content.strip())
696
- st.markdown(f'<div class="chat-message">{rewritten_model_5}</div>', unsafe_allow_html=True)
 
500
  }
501
  </style>
502
  """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
503
  folder_path = '46'
504
  normalizer = Normalizer()
505
+ sentence_tokenizer = SentenceTokenizer()
506
 
507
  @st.cache_data(show_spinner="در حال پردازش اسناد... لطفاً صبور باشید.")
508
  def load_and_process_documents(path):
 
510
  try:
511
  full_path = os.path.join(path, filename)
512
  doc = docx.Document(full_path)
513
+ text = "\n".join([para.text for para in doc.paragraphs]) # استخراج متن
514
  normalized = normalizer.normalize(text)
515
+ sentences = normalized
516
+ return sentences
517
  except Exception as e:
518
  print(f"Error processing {filename}: {e}")
519
+ return []
 
 
 
 
520
  with concurrent.futures.ThreadPoolExecutor() as executor:
521
+ results = executor.map(process_docx, [f for f in os.listdir(path) if f.endswith(".docx")])
 
522
 
 
523
 
524
+
525
+ return list(results)
526
+ all_sentences = load_and_process_documents(folder_path)
527
 
528
  def clean_text(text):
529
+ cleaned_text = re.sub(r'[^آ-ی۰-۹0-9،.؟!؛+\-* ]+', '', text)
530
+
531
+ return cleaned_text
532
 
 
 
 
 
533
 
534
+ import string
535
+ from hazm import word_tokenize, sent_tokenize
536
  from sklearn.feature_extraction.text import TfidfVectorizer
537
  from sklearn.cluster import KMeans
 
538
  from sklearn.metrics.pairwise import cosine_similarity
539
 
540
+ # تابع خلاصه‌سازی متن با استفاده از KMeans
 
 
 
541
  def summarize_text_with_kmeans(text, num_sentences=3):
542
  sentences = sent_tokenize(text) # تقسیم متن به جملات
543
  tfidf_vectorizer = TfidfVectorizer()
 
555
  summary = [sentences[i] for i in similar_sentences_indices]
556
  return ' '.join(summary)
557
 
558
+ # فرض بر این است که query و all_sentences قبلاً تعریف شده‌اند
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
559
  if query:
560
+ threshold = 75
561
+ keywords = extract_keywords(query)
562
+
563
+ # خلاصه‌سازی متن قبل از ارسال به LLM
564
+ text_to_summarize = "\n".join(all_sentences) # تمام جملات را با هم ترکیب کنید
565
+ summarized_text = summarize_text_with_kmeans(text_to_summarize)
566
+
567
+ # استفاده از پردازش موازی برای افزایش سرعت fuzzy matching
568
+ with ThreadPoolExecutor(max_workers=8) as executor:
569
+ futures = [executor.submit(compute_similarity, sentence, query, threshold) for sentence in all_sentences]
570
+ matched_sentences = [future.result() for future in futures if future.result()]
571
+
572
+ if matched_sentences:
573
+ found_sentences = [sentence for sentence in matched_sentences if any(keyword in sentence for keyword in keywords)]
574
+
575
+ if found_sentences:
576
+ matched_text = "\n".join(found_sentences)
577
+
578
+ prompt = f"""
579
+ تعدادی پاسخ برای سوال زیر تولید شده است. لطفاً ابتدا این پاسخ‌ها را بررسی کن، سپس با در نظر گرفتن محتوای سوال و لحن آن، یک پاسخ نهایی حرفه‌ای، دقیق و روان از داخل پاسخ‌ها ارائه کن که هم به سوال پاسخ دهد و هم از نظر نگارشی و ساختاری در سطح بالایی باشد. پاسخ نهایی باید حداکثر 2048 کاراکتر و حداقل 512 باشد، خلاصه و واضح نوشته شود و فقط به زبان فارسی باشد. از تکرار اضافی پرهیز کن و فقط از پاسخ‌های زیر استفاده کن. در صورت نیاز، محتوای چند پاسخ را با هم ترکیب کن.
580
+ سوال:
581
+ {query}
582
+ پاسخ‌ها:
583
+ {summarized_text}
584
+ پاسخ نهایی حرفه‌ای بازنویسی‌شده:
585
+ """
586
+
587
+ response = llm([
588
+ SystemMessage(content="You are a helpful assistant."),
589
+ HumanMessage(content=prompt)
590
+ ])
591
+ rewritten = clean_text(response.content.strip())
592
+
593
+ review_prompt = f"""
594
+ لطفاً بررسی کن که آیا پاسخ زیر به سوال داده‌شده مرتبط، دقیق و معتبر است یا خیر. اگر پاسخ قابل قبول و دقیق است بنویس 'تأیید شد'. اگر متوسط است بنویس 'کمی خوب'. اگر بی‌ربط یا اشتباه است بنویس 'نیاز به اصلاح دارد'.
595
+ سوال:
596
+ {query}
597
+ پاسخ:
598
+ {rewritten}
599
+ """
600
+
601
+ review_response = llm([
602
+ SystemMessage(content="You are a helpful assistant."),
603
+ HumanMessage(content=review_prompt)
604
+ ])
605
+ review_result = review_response.content.strip()
606
+
607
+ if "تأیید شد" in review_result:
608
+ st.markdown(f'<div class="chat-message">{rewritten}</div>', unsafe_allow_html=True)
609
+
610
+ elif "کمی خوب" in review_result:
611
+ final_prompt = f"""
612
+ لطفاً برای سوال زیر پاسخی حرفه‌ای، دقیق و روان تولید کن که مرتبط و معتبر باشد. از زبانی جز فارسی استفاده نکن. از محتوای زیر استفاده کن و یک پاسخ نهایی خوب بنویس:
613
  سوال:
614
  {query}
615
+ پاسخ اولیه:
616
+ {rewritten}
617
  پاسخ نهایی:
618
  """
619
+ new_response = llm([
620
  SystemMessage(content="You are a helpful assistant."),
621
+ HumanMessage(content=final_prompt)
622
  ])
623
+ final_answer = clean_text(new_response.content.strip())
624
+ st.markdown(f'<div class="chat-message">{final_answer}</div>', unsafe_allow_html=True)
625
+
626
+ else:
627
+ fallback_prompt = f"""
628
+ لطفاً برای سوال زیر پاسخی حرفه‌ای، دقیق و روان تولید کن که مرتبط و معتبر باشد. اگر اطلاعات کافی وجود ندارد، صادقانه بگو. فقط به زبان فارسی پاسخ بده:
629
  سوال:
630
  {query}
 
 
 
 
631
  """
632
+ fallback_response = llm([
633
  SystemMessage(content="You are a helpful assistant."),
634
+ HumanMessage(content=fallback_prompt)
635
  ])
636
+ final_fallback = clean_text(fallback_response.content.strip())
637
+ st.markdown(f'<div class="chat-message">{final_fallback}</div>', unsafe_allow_html=True)
638
+
639
+ else:
640
+ fallback_prompt = f"""
641
+ لطفاً برای سوال زیر یک متن مرتبط و معتبر تولید کن. اگر اطلاعات کافی وجود ندارد، صادقانه اعلام کن. فقط به زبان فارسی پاسخ بده:
642
+ سوال:
643
+ {query}
644
+ """
645
+ response = llm([
646
+ SystemMessage(content="You are a helpful assistant."),
647
+ HumanMessage(content=fallback_prompt)
648
+ ])
649
+ rewritten = clean_text(response.content.strip())
650
+ st.markdown(f'<div class="chat-message">{rewritten}</div>', unsafe_allow_html=True)
651
+ think.empty()