Update app.py
Browse files
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 |
-
|
|
|
527 |
except Exception as e:
|
528 |
print(f"Error processing {filename}: {e}")
|
529 |
-
return
|
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 |
-
|
536 |
-
doc_texts[filename] = content
|
537 |
|
538 |
-
return doc_texts
|
539 |
|
540 |
-
|
|
|
|
|
541 |
|
542 |
def clean_text(text):
|
543 |
-
|
|
|
|
|
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
|
551 |
-
import
|
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 |
-
|
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 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
لطفاً
|
655 |
سوال:
|
656 |
{query}
|
657 |
-
|
658 |
-
{
|
659 |
پاسخ نهایی:
|
660 |
"""
|
661 |
-
|
662 |
SystemMessage(content="You are a helpful assistant."),
|
663 |
-
HumanMessage(content=
|
664 |
])
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
|
|
|
|
669 |
سوال:
|
670 |
{query}
|
671 |
-
آیا مدل دوم به درستی جواب داده است؟
|
672 |
-
پاسخ مدل دوم:
|
673 |
-
{rewritten_model_3}
|
674 |
-
لطفاً تایید کن که آیا این پاسخ مناسب است یا خیر.
|
675 |
"""
|
676 |
-
|
677 |
SystemMessage(content="You are a helpful assistant."),
|
678 |
-
HumanMessage(content=
|
679 |
])
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
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()
|
|