|
import gradio as gr |
|
from transformers import pipeline |
|
import re |
|
|
|
|
|
intent_classifier_ar = pipeline("text-classification", model="aubmindlab/bert-base-arabertv02") |
|
|
|
|
|
intent_classifier_en = pipeline("text-classification", model="facebook/bart-large-mnli") |
|
|
|
|
|
language_detector = pipeline("text-classification", model="papluca/xlm-roberta-base-language-detection") |
|
|
|
|
|
ONB_GUIDELINES_AR = { |
|
"balance": "يمكنك التحقق من رصيدك عبر الإنترنت أو عبر تطبيق الهاتف الخاص ببنك الوطني.", |
|
"lost_card": "في حالة فقدان البطاقة، اتصل بالرقم 249-123-456-789 فورًا.", |
|
"loan": "شروط القرض تشمل الحد الأدنى للدخل (5000 جنيه سوداني) وتاريخ ائتماني جيد.", |
|
"transfer": "لتحويل الأموال، استخدم تطبيق الهاتف أو الخدمة المصرفية عبر الإنترنت.", |
|
"new_account": "لفتح حساب جديد، قم بزيارة أقرب فرع مع جواز سفرك أو هويتك الوطنية.", |
|
"interest_rates": "أسعار الفائدة على الودائع تتراوح بين 5% إلى 10% سنويًا.", |
|
"branches": "فروعنا موجودة في أم درمان، الخرطوم، وبورتسودان. زيارة موقعنا للتفاصيل.", |
|
"working_hours": "ساعات العمل من 8 صباحًا إلى 3 مساءً من الأحد إلى الخميس.", |
|
"contact": "الاتصال بنا على الرقم 249-123-456-789 أو عبر البريد الإلكتروني [email protected]." |
|
} |
|
|
|
|
|
ONB_GUIDELINES_EN = { |
|
"balance": "You can check your balance online or via the ONB mobile app.", |
|
"lost_card": "In case of a lost card, call 249-123-456-789 immediately.", |
|
"loan": "Loan requirements include minimum income (5000 SDG) and good credit history.", |
|
"transfer": "To transfer funds, use the mobile app or online banking service.", |
|
"new_account": "To open a new account, visit your nearest branch with your passport or national ID.", |
|
"interest_rates": "Interest rates on deposits range from 5% to 10% annually.", |
|
"branches": "Our branches are located in Omdurman, Khartoum, and Port Sudan. Visit our website for details.", |
|
"working_hours": "Working hours are from 8 AM to 3 PM, Sunday to Thursday.", |
|
"contact": "Contact us at 249-123-456-789 or via email at [email protected]." |
|
} |
|
|
|
|
|
INTENT_KEYWORDS = { |
|
"balance": ["balance", "رصيد", "حساب"], |
|
"lost_card": ["lost", "card", "stolen", "فقدت", "بطاقة", "مسروقة"], |
|
"loan": ["loan", "borrow", "قرض", "استدانة"], |
|
"transfer": ["transfer", "send money", "تحويل", "ارسال"], |
|
"new_account": ["account", "open", "حساب", "فتح"], |
|
"interest_rates": ["interest", "rate", "فائدة", "نسبة"], |
|
"branches": ["branch", "location", "فرع", "موقع"], |
|
"working_hours": ["hours", "time", "ساعات", "وقت"], |
|
"contact": ["contact", "phone", "email", "اتصال", "هاتف", "بريد"] |
|
} |
|
|
|
def detect_language(text): |
|
|
|
result = language_detector(text) |
|
language = result[0]['label'] |
|
return language |
|
|
|
def classify_intent(message: str, language: str): |
|
|
|
if language == "ar": |
|
|
|
result = intent_classifier_ar(message) |
|
intent = result[0]['label'] |
|
else: |
|
|
|
result = intent_classifier_en(message, candidate_labels=list(INTENT_KEYWORDS.keys())) |
|
intent = result["labels"][0] |
|
|
|
|
|
if intent not in INTENT_KEYWORDS: |
|
for intent_key, keywords in INTENT_KEYWORDS.items(): |
|
for keyword in keywords: |
|
if re.search(r'\b' + re.escape(keyword.lower()) + r'\b', message.lower()): |
|
return intent_key |
|
return "unknown" |
|
|
|
return intent |
|
|
|
def respond(message: str): |
|
if not message.strip(): |
|
return { |
|
"ar": "الرجاء كتابة سؤالك.", |
|
"en": "Please type your question." |
|
} |
|
|
|
|
|
language = detect_language(message) |
|
|
|
|
|
if language != "ar" and language != "en": |
|
language = "en" |
|
|
|
|
|
intent = classify_intent(message, language) |
|
|
|
|
|
responses = { |
|
"ar": "", |
|
"en": "" |
|
} |
|
|
|
|
|
if intent != "unknown": |
|
responses["ar"] = ONB_GUIDELINES_AR.get(intent, "عذرًا، لم يتم التعرف على الخيار المحدد.") |
|
responses["en"] = ONB_GUIDELINES_EN.get(intent, "Sorry, the selected option was not recognized.") |
|
else: |
|
|
|
ar_options = ", ".join(list(ONB_GUIDELINES_AR.keys())) |
|
en_options = ", ".join(list(ONB_GUIDELINES_EN.keys())) |
|
|
|
responses["ar"] = f"عذرًا، لم أفهم سؤالك. الرجاء إعادة الصياغة أو اختيار أحد الخيارات التالية: {ar_options}" |
|
responses["en"] = f"Sorry, I didn't understand your question. Please rephrase or choose one of the following options: {en_options}" |
|
|
|
return responses |
|
|
|
|
|
custom_css = """ |
|
.gradio-container { |
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
|
} |
|
|
|
.chat-message { |
|
padding: 1rem; |
|
border-radius: 10px; |
|
margin-bottom: 1rem; |
|
max-width: 80%; |
|
} |
|
|
|
.user-message { |
|
background-color: #e6f7ff; |
|
margin-left: auto; |
|
text-align: right; |
|
} |
|
|
|
.bot-message { |
|
background-color: #f0f0f0; |
|
margin-right: auto; |
|
text-align: left; |
|
} |
|
|
|
.bot-message-ar { |
|
background-color: #f0f0f0; |
|
margin-left: auto; |
|
text-align: right; |
|
} |
|
|
|
.header-section { |
|
background-color: #1a5276; |
|
color: white; |
|
padding: 1rem; |
|
border-radius: 10px; |
|
margin-bottom: 1rem; |
|
text-align: center; |
|
} |
|
|
|
.footer-section { |
|
font-size: 0.8rem; |
|
text-align: center; |
|
margin-top: 2rem; |
|
color: #666; |
|
} |
|
|
|
.lang-selector { |
|
text-align: right; |
|
margin-bottom: 1rem; |
|
} |
|
""" |
|
|
|
|
|
with gr.Blocks(css=custom_css) as demo: |
|
|
|
state = gr.State(value=[]) |
|
|
|
selected_lang = gr.State(value="ar") |
|
|
|
with gr.Row(elem_classes="header-section"): |
|
with gr.Column(): |
|
gr.Markdown("# Omdurman National Bank | بنك أم درمان الوطني") |
|
gr.Markdown("### Virtual Banking Assistant | المساعد المصرفي الافتراضي") |
|
|
|
with gr.Row(): |
|
with gr.Column(elem_classes="lang-selector"): |
|
language_btn = gr.Radio( |
|
["العربية", "English"], |
|
value="العربية", |
|
label="Language | اللغة" |
|
) |
|
|
|
with gr.Row(): |
|
chat_box = gr.Chatbot(elem_id="chatbox", height=400) |
|
|
|
with gr.Row(): |
|
with gr.Column(scale=8): |
|
text_input = gr.Textbox( |
|
placeholder="Type your question here | اكتب سؤالك هنا", |
|
label="", |
|
elem_id="chat-input" |
|
) |
|
with gr.Column(scale=1): |
|
submit_btn = gr.Button("Send | إرسال", variant="primary") |
|
|
|
with gr.Row(elem_classes="footer-section"): |
|
gr.Markdown("© 2025 Omdurman National Bank. All Rights Reserved. | جميع الحقوق محفوظة لبنك أم درمان الوطني ٢٠٢٥ ©") |
|
|
|
|
|
def update_language(lang): |
|
if lang == "العربية": |
|
return "ar" |
|
else: |
|
return "en" |
|
|
|
language_btn.change( |
|
fn=update_language, |
|
inputs=language_btn, |
|
outputs=selected_lang |
|
) |
|
|
|
|
|
def on_submit(message, chat_history, lang): |
|
if not message.strip(): |
|
return "", chat_history |
|
|
|
|
|
chat_history.append([message, None]) |
|
|
|
|
|
responses = respond(message) |
|
|
|
|
|
response = responses[lang] |
|
|
|
|
|
chat_history[-1][1] = response |
|
|
|
return "", chat_history |
|
|
|
|
|
submit_btn.click( |
|
fn=on_submit, |
|
inputs=[text_input, chat_box, selected_lang], |
|
outputs=[text_input, chat_box] |
|
) |
|
|
|
|
|
text_input.submit( |
|
fn=on_submit, |
|
inputs=[text_input, chat_box, selected_lang], |
|
outputs=[text_input, chat_box] |
|
) |
|
|
|
if __name__ == "__main__": |
|
demo.launch( |
|
server_name="0.0.0.0", |
|
server_port=7860, |
|
share=True |
|
) |