M17idd commited on
Commit
4b80f55
·
1 Parent(s): b141134

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -137
app.py CHANGED
@@ -500,19 +500,20 @@ st.markdown("""
500
  }
501
  </style>
502
  """, unsafe_allow_html=True)
503
- import streamlit as st
 
 
504
  import os
505
- import docx
506
- from hazm import Normalizer, SentenceTokenizer
507
- from concurrent.futures import ThreadPoolExecutor
508
- from sklearn.feature_extraction.text import TfidfVectorizer
509
- from sklearn.cluster import KMeans
510
- from sklearn.metrics.pairwise import cosine_similarity
511
  import re
 
 
 
 
 
 
512
 
513
  folder_path = '46'
514
  normalizer = Normalizer()
515
- sentence_tokenizer = SentenceTokenizer()
516
 
517
  @st.cache_data(show_spinner="در حال پردازش اسناد... لطفاً صبور باشید.")
518
  def load_and_process_documents(path):
@@ -520,147 +521,62 @@ def load_and_process_documents(path):
520
  try:
521
  full_path = os.path.join(path, filename)
522
  doc = docx.Document(full_path)
523
- text = "\n".join([para.text for para in doc.paragraphs]) # استخراج متن
524
  normalized = normalizer.normalize(text)
525
- sentences = normalized
526
- return sentences
527
  except Exception as e:
528
  print(f"Error processing {filename}: {e}")
529
- return []
530
- with ThreadPoolExecutor() as executor:
531
- results = executor.map(process_docx, [f for f in os.listdir(path) if f.endswith(".docx")])
532
-
533
- return list(results)
534
 
535
- # بارگذاری و پردازش اسناد
536
- all_sentences = load_and_process_documents(folder_path)
537
 
538
- # # تابع خلاصه‌سازی متن با استفاده از KMeans
539
- # def summarize_text_with_kmeans(text, num_sentences=3):
540
- # sentences = sentence_tokenizer.tokenize(text) # تقسیم متن به جملات
541
- # tfidf_vectorizer = TfidfVectorizer()
542
- # tfidf_matrix = tfidf_vectorizer.fit_transform(sentences) # تبدیل جملات به ماتریس TF-IDF
543
 
544
- # # الگوریتم خوشه‌بندی KMeans
545
- # kmeans = KMeans(n_clusters=1) # یک خوشه برای استخراج خلاصه
546
- # kmeans.fit(tfidf_matrix)
547
 
548
- # # پیدا کردن جملات نزدیک به مرکز خوشه
549
- # closest_centroid = kmeans.cluster_centers_[0]
550
- # similarities = cosine_similarity(tfidf_matrix, closest_centroid.reshape(1, -1))
551
- # similar_sentences_indices = similarities.flatten().argsort()[-num_sentences:][::-1] # انتخاب jملات نزدیک
552
 
553
- # summary = [sentences[i] for i in similar_sentences_indices]
554
- # return ' '.join(summary)
555
 
 
 
556
 
557
- # # خلاصه‌سازی متن قبل از ارسال به LLM
558
- # text_to_summarize = "\n".join(all_sentences) # تمام جملات را با هم ترکیب کنید
559
- summarized_text = all_sentences
560
 
561
- # تابع تمیز کردن متن
562
- def clean_text(text):
563
- cleaned_text = re.sub(r'[^آ-ی۰-۹0-9،.؟!؛+\-* ]+', '', text)
564
- return cleaned_text
565
 
566
- # محاسبه شباهت بین جملات
567
- def compute_similarity(sentence, query, threshold):
568
- similarity = fuzz.partial_ratio(sentence, query)
569
- if similarity >= threshold:
570
- return sentence
571
- return None
572
 
573
- # پردازش پرسش
574
  if query:
575
- threshold = 75
576
- keywords = query.split() # فرض می‌کنیم که query یک رشته است و کلمات کلیدی به طور پیش‌فرض از آن استخراج می‌شود
577
-
578
-
579
- # استفاده از پردازش موازی برای افزایش سرعت fuzzy matching
580
- max_workers = os.cpu_count()
581
-
582
- # پردازش موازی با استفاده از تعداد هسته‌ها
583
- with ThreadPoolExecutor(max_workers=max_workers) as executor:
584
- futures = [executor.submit(compute_similarity, sentence, query, threshold) for sentence in all_sentences]
585
- matched_sentences = [future.result() for future in futures if future.result()]
586
-
587
- # فیلتر کردن جملات بر اساس کلمات کلیدی
588
- if matched_sentences:
589
- found_sentences = [sentence for sentence in matched_sentences if any(keyword in sentence for keyword in keywords)]
590
-
591
- if found_sentences:
592
- matched_text = "\n".join(found_sentences) # ترکیب جملات مشابه به یک رشته
593
-
594
- prompt = f"""
595
- تعدادی پاسخ برای سوال زیر تولید شده است. لطفاً ابتدا این پاسخ‌ها را بررسی کن، سپس با در نظر گرفتن محتوای سوال و لحن آن، یک پاسخ نهایی حرفه‌ای، دقیق و روان از داخل پاسخ‌ها ارائه کن که هم به سوال پاسخ دهد و هم از نظر نگارشی و ساختاری در سطح بالایی باشد. پاسخ نهایی باید حداکثر 2048 کاراکتر و حداقل 512 باشد، خلاصه و واضح نوشته شود و فقط به زبان فارسی باشد. از تکرار اضافی پرهیز کن و فقط از پاسخ‌های زیر استفاده کن. در صورت نیاز، محتوای چند پاسخ را با هم ترکیب کن.
596
- سوال:
597
- {query}
598
- پاسخ‌ها:
599
- {summarized_text}
600
- پاسخ نهایی حرفه‌ای بازنویسی‌شده:
601
- """
602
-
603
- response = llm([
604
- SystemMessage(content="You are a helpful assistant."),
605
- HumanMessage(content=prompt)
606
- ])
607
- rewritten = clean_text(response.content.strip())
608
-
609
- review_prompt = f"""
610
- لطفاً بررسی کن که آیا پاسخ زیر به سوال داده‌شده مرتبط، دقیق و معتبر است یا خیر. اگر پاسخ قابل قبول و دقیق است بنویس 'تأیید شد'. اگر متوسط است بنویس 'کمی خوب'. اگر بی‌ربط یا اشتباه است بنویس 'نیاز به اصلاح دارد'.
611
- سوال:
612
- {query}
613
- پاسخ:
614
- {rewritten}
615
- """
616
-
617
- review_response = llm([
618
- SystemMessage(content="You are a helpful assistant."),
619
- HumanMessage(content=review_prompt)
620
- ])
621
- review_result = review_response.content.strip()
622
-
623
- if "تأیید شد" in review_result:
624
- st.markdown(f'<div class="chat-message">{rewritten}</div>', unsafe_allow_html=True)
625
-
626
- elif "کمی خوب" in review_result:
627
- final_prompt = f"""
628
- لطفاً برای سوال زیر پاسخی حرفه‌ای، دقیق و روان تولید کن که مرتبط و معتبر باشد. از زبانی جز فارسی استفاده نکن. از محتوای زیر استفاده کن و یک پاسخ نهایی خوب بنویس:
629
- سوال:
630
- {query}
631
- پاسخ اولیه:
632
- {rewritten}
633
- پاسخ نهایی:
634
- """
635
- new_response = llm([
636
- SystemMessage(content="You are a helpful assistant."),
637
- HumanMessage(content=final_prompt)
638
- ])
639
- final_answer = clean_text(new_response.content.strip())
640
- st.markdown(f'<div class="chat-message">{final_answer}</div>', unsafe_allow_html=True)
641
-
642
- else:
643
- fallback_prompt = f"""
644
- لطفاً برای سوال زیر پاسخی حرفه‌ای، دقیق و روان تولید کن که مرتبط و معتبر باشد. اگر اطلاعات کافی وجود ندارد، صادقانه بگو. فقط به زبان فارسی پاسخ بده:
645
- سوال:
646
- {query}
647
- """
648
- fallback_response = llm([
649
- SystemMessage(content="You are a helpful assistant."),
650
- HumanMessage(content=fallback_prompt)
651
- ])
652
- final_fallback = clean_text(fallback_response.content.strip())
653
- st.markdown(f'<div class="chat-message">{final_fallback}</div>', unsafe_allow_html=True)
654
 
655
- else:
656
- fallback_prompt = f"""
657
- لطفاً برای سوال زیر یک متن مرتبط و معتبر تولید کن. اگر اطلاعات کافی وجود ندارد، صادقانه اعلام کن. فقط به زبان فارسی پاسخ بده:
658
- سوال:
659
- {query}
660
- """
661
- response = llm([
662
- SystemMessage(content="You are a helpful assistant."),
663
- HumanMessage(content=fallback_prompt)
664
- ])
665
- rewritten = clean_text(response.content.strip())
666
- st.markdown(f'<div class="chat-message">{rewritten}</div>', unsafe_allow_html=True)
 
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
  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
 
543
+ def clean_text(text):
544
+ return re.sub(r'[^آ-ی۰-۹0-9،.؟!؛+\-* ]+', '', text)
545
 
 
 
 
546
 
547
+ def find_closest_filename(query, filenames):
548
+ scores = [(f, fuzz.partial_ratio(query, f)) for f in filenames]
549
+ scores.sort(key=lambda x: x[1], reverse=True)
550
+ return scores[0][0] if scores else None
551
 
 
 
 
 
 
 
552
 
553
+ # فرض بر این است که متغیر query توسط کاربر مشخص شده است
554
  if query:
555
+ closest_file = find_closest_filename(query, list(doc_texts.keys()))
556
+
557
+ if closest_file:
558
+ matched_text = doc_texts[closest_file]
559
+ st.markdown(scores[0][0])
560
+ st.markdown(matched_text)
561
+ prompt = f"""
562
+ لطفاً با توجه به سؤال زیر و محتوای سند موجود، یک پاسخ نهایی حرفه‌ای، دقیق و روان تولید کن. فقط از متن سند استفاده کن. اگر اطلاعات کافی در متن وجود ندارد، صادقانه اعلام کن.
563
+ سوال:
564
+ {query}
565
+ محتوای سند:
566
+ {matched_text}
567
+ پاسخ نهایی:
568
+ """
569
+
570
+ response = llm([
571
+ SystemMessage(content="You are a helpful assistant."),
572
+ HumanMessage(content=prompt)
573
+ ])
574
+ rewritten = clean_text(response.content.strip())
575
+
576
+ st.markdown(f'<div class="chat-message">{rewritten}</div>', unsafe_allow_html=True)
577
+ think.empty()
578
+
579
+ else:
580
+ st.warning("هیچ سند مرتبطی پیدا نشد.")
581
+ think.empty()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
582