parsBert / app.py
Younes13's picture
Update app.py
4b84e82 verified
import torch
from transformers import AutoTokenizer, AutoModel, AutoModelForCausalLM
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
import gradio as gr
import re
# 📌 مدل‌های مختلف
# مدل BERT برای semantic search
bert_model_name = "HooshvareLab/bert-fa-base-uncased"
bert_tokenizer = AutoTokenizer.from_pretrained(bert_model_name)
bert_model = AutoModel.from_pretrained(bert_model_name)
# مدل generative برای تولید پاسخ (می‌توانید از مدل‌های دیگر استفاده کنید)
# اگر مدل generative فارسی در دسترس نداشته باشید، از همین BERT استفاده می‌کنیم
try:
# مثال: استفاده از مدل generative فارسی
gen_model_name = "HooshvareLab/bert-fa-base-uncased" # جایگزین کنید
gen_tokenizer = AutoTokenizer.from_pretrained(gen_model_name)
gen_model = AutoModel.from_pretrained(gen_model_name)
has_generative = False # فعلاً False چون BERT generative نیست
except:
has_generative = False
# 📄 دیتاست گسترده‌تر
faq_data = {
"پایتخت ایران کجاست؟": "تهران پایتخت ایران است.",
"زبان رسمی ایران چیست؟": "فارسی زبان رسمی ایران است.",
"واحد پول ایران چیست؟": "ریال واحد پول ایران است.",
"چه زمانی انتخاب واحد شروع می‌شود؟": "معمولاً انتخاب واحد در پایان شهریور یا بهمن ماه شروع می‌شود.",
"چه معدلی برای گرفتن 24 واحد لازم است؟": "برای گرفتن 24 واحد حداقل معدل 17 لازم است.",
"ساعت کاری ادارات چیست؟": "ساعت کاری ادارات معمولاً از 8 صبح تا 4 عصر است.",
"چگونه می‌توانم درخواست پاسپورت بدهم؟": "برای درخواست پاسپورت باید به اداره گذرنامه مراجعه کنید.",
"فصل‌های سال در ایران چیست؟": "فصل‌های سال شامل بهار، تابستان، پاییز و زمستان است.",
}
# اضافه کردن دانش عمومی
general_knowledge = {
"چگونه": "این سوال درباره نحوه انجام کاری است. برای پاسخ دقیق‌تر، لطفاً سوال خود را کامل‌تر بپرسید.",
"چرا": "این سوال درباره دلیل چیزی است. برای پاسخ بهتر، موضوع مشخصی را بیان کنید.",
"چیست": "این سوال تعریف چیزی را می‌خواهد. لطفاً موضوع مورد نظر را دقیق‌تر بیان کنید.",
"کجا": "این سوال درباره مکان است. برای پاسخ دقیق‌تر، موضوع خاصی را مشخص کنید.",
"کی": "این سوال درباره زمان است. لطفاً موضوع مورد نظر را دقیق‌تر بیان کنید.",
}
# ترکیب دیتاست‌ها
all_data = {**faq_data, **general_knowledge}
questions = list(all_data.keys())
answers = list(all_data.values())
# 📄 تولید embedding
def get_embedding(text):
inputs = bert_tokenizer(text, return_tensors="pt", truncation=True, padding=True, max_length=128)
with torch.no_grad():
outputs = bert_model(**inputs)
emb = outputs.last_hidden_state.mean(dim=1).squeeze().cpu().numpy()
return emb
# محاسبه embedding برای همه سوالات
faq_embeddings = [get_embedding(q) for q in questions]
# 📄 تشخیص نوع سوال
def detect_question_type(question):
question_lower = question.lower()
# الگوهای سوال
patterns = {
'definition': ['چیست', 'چی هست', 'تعریف', 'معنی'],
'how': ['چگونه', 'چطور', 'چه طور'],
'why': ['چرا', 'به چه دلیل'],
'when': ['چه زمانی', 'کی', 'چه وقت'],
'where': ['کجا', 'در کجا', 'کدام مکان'],
'who': ['کی', 'چه کسی', 'کدام فرد'],
'greeting': ['سلام', 'درود', 'صبح بخیر', 'ظهر بخیر', 'عصر بخیر', 'شب بخیر'],
'thanks': ['ممنون', 'متشکرم', 'سپاس', 'تشکر'],
'yes_no': ['آیا', 'مگر', 'آیا که']
}
for q_type, words in patterns.items():
for word in words:
if word in question_lower:
return q_type
return 'general'
# 📄 تولید پاسخ برای سوالات عمومی
def generate_general_answer(question, question_type):
if question_type == 'greeting':
return "سلام! چطور می‌تونم کمکتون کنم؟"
elif question_type == 'thanks':
return "خواهش می‌کنم! اگر سوال دیگری دارید، بپرسید."
elif question_type == 'definition':
return "برای تعریف دقیق‌تر این موضوع، لطفاً سوال خود را کامل‌تر بپرسید تا بتوانم پاسخ مناسبی ارائه دهم."
elif question_type == 'how':
return "برای راهنمایی دقیق‌تر درباره نحوه انجام این کار، لطفاً جزئیات بیشتری از سوال خود ارائه دهید."
elif question_type == 'why':
return "برای توضیح دلایل، لطفاً موضوع مورد نظر را دقیق‌تر مشخص کنید تا بتوانم پاسخ مناسبی ارائه دهم."
elif question_type == 'when':
return "برای اطلاع از زمان دقیق، لطفاً موضوع خاصی را مشخص کنید تا بتوانم راهنمایی کنم."
elif question_type == 'where':
return "برای اطلاع از مکان، لطفاً موضوع مورد نظر را دقیق‌تر بیان کنید."
elif question_type == 'yes_no':
return "برای پاسخ به این سوال، لطفاً موضوع را کامل‌تر مطرح کنید."
else:
# پاسخ عمومی هوشمند
return "سوال جالبی پرسیده‌اید. متأسفانه در حال حاضر اطلاعات کاملی در این زمینه ندارم، اما اگر سوال خود را دقیق‌تر مطرح کنید، شاید بتوانم کمک بیشتری کنم."
# 📄 تابع اصلی پاسخ
def answer_question(user_question):
# حذف فاصله‌های اضافی
user_question = user_question.strip()
if not user_question:
return "لطفاً سوال خود را بنویسید."
# تشخیص نوع سوال
question_type = detect_question_type(user_question)
# جستجوی semantic در دیتاست
user_emb = get_embedding(user_question)
sims = [cosine_similarity([user_emb], [emb])[0][0] for emb in faq_embeddings]
best_idx = int(np.argmax(sims))
best_score = sims[best_idx]
# تنظیم threshold بر اساس نوع سوال
if question_type in ['greeting', 'thanks']:
threshold = 0.3
else:
threshold = 0.65
if best_score > threshold:
return answers[best_idx]
else:
# تولید پاسخ برای سوالات خارج از دیتاست
return generate_general_answer(user_question, question_type)
# 📄 تابع اضافه کردن دانش جدید
def add_knowledge(question, answer):
if question and answer:
global questions, answers, faq_embeddings, all_data
# اضافه کردن به دیتاست
all_data[question] = answer
questions.append(question)
answers.append(answer)
# محاسبه embedding جدید
new_emb = get_embedding(question)
faq_embeddings.append(new_emb)
return f"دانش جدید اضافه شد: {question} -> {answer}"
else:
return "لطفاً هم سوال و هم پاسخ را وارد کنید."
# 📄 رابط Gradio
with gr.Blocks(title="🤖 دستیار فارسی هوشمند") as demo:
gr.Markdown("## 🤖 دستیار فارسی هوشمند (پاسخ به سوالات داخل و خارج دیتاست)")
with gr.Tab("💬 پرسش و پاسخ"):
inp = gr.Textbox(label="سؤال خود را بنویسید", placeholder="مثال: سلام، پایتخت ایران کجاست؟")
out = gr.Textbox(label="پاسخ", lines=3)
btn = gr.Button("پاسخ بده", variant="primary")
btn.click(fn=answer_question, inputs=inp, outputs=out)
with gr.Tab("📚 افزودن دانش"):
gr.Markdown("### افزودن سوال و پاسخ جدید به دیتاست")
new_q = gr.Textbox(label="سوال جدید")
new_a = gr.Textbox(label="پاسخ جدید", lines=2)
add_btn = gr.Button("اضافه کن", variant="secondary")
add_result = gr.Textbox(label="نتیجه")
add_btn.click(fn=add_knowledge, inputs=[new_q, new_a], outputs=add_result)
with gr.Tab("ℹ️ راهنما"):
gr.Markdown("""
### نحوه استفاده:
1. **سوالات معمولی**: مثل "پایتخت ایران کجاست؟"
2. **احوال‌پرسی**: مثل "سلام" یا "صبح بخیر"
3. **تشکر**: مثل "ممنون" یا "متشکرم"
4. **سوالات عمومی**: حتی اگر در دیتاست نباشد، پاسخ مناسب می‌دهد
### ویژگی‌ها:
- پاسخ به سوالات داخل دیتاست با دقت بالا
- پاسخ هوشمند به سوالات خارج دیتاست
- تشخیص نوع سوال (تعریف، چگونه، چرا، کجا، کی)
- قابلیت افزودن دانش جدید
""")
demo.launch()