import gradio as gr import re from transformers import pipeline import json # Load language detection model language_detector = pipeline("text-classification", model="papluca/xlm-roberta-base-language-detection") # Enhanced Omdurman National Bank guidelines with more detailed information ONB_GUIDELINES = { "ar": { "balance": { "response": "يمكنك التحقق من رصيدك عبر الإنترنت أو عبر تطبيق الهاتف الخاص ببنك الوطني.", "actions": [ {"label": "تطبيق الهاتف", "url": "https://onb.sd/mobile-app"}, {"label": "الخدمات المصرفية عبر الإنترنت", "url": "https://onb.sd/online-banking"} ] }, "lost_card": { "response": "في حالة فقدان البطاقة، اتصل بالرقم 249-123-456-789 فورًا. سنقوم بإيقاف البطاقة وإصدار بطاقة جديدة.", "actions": [ {"label": "إيقاف البطاقة فورًا", "url": "tel:249-123-456-789"}, {"label": "طلب بطاقة جديدة", "url": "https://onb.sd/replace-card"} ] }, "loan": { "response": "شروط القرض تشمل الحد الأدنى للدخل (5000 جنيه سوداني) وتاريخ ائتماني جيد. نقدم أنواع مختلفة من القروض لتناسب احتياجاتك.", "actions": [ {"label": "حاسبة القروض", "url": "https://onb.sd/loan-calculator"}, {"label": "تقديم طلب قرض", "url": "https://onb.sd/loan-application"} ] }, # ... other guideline entries similarly expanded }, "en": { "balance": { "response": "You can check your balance online or via the ONB mobile app. We offer multiple convenient ways to monitor your account.", "actions": [ {"label": "Mobile App", "url": "https://onb.sd/mobile-app"}, {"label": "Online Banking", "url": "https://onb.sd/online-banking"} ] }, "lost_card": { "response": "In case of a lost card, call 249-123-456-789 immediately. We'll block the card and issue a new one to protect your funds.", "actions": [ {"label": "Block Card Immediately", "url": "tel:249-123-456-789"}, {"label": "Request New Card", "url": "https://onb.sd/replace-card"} ] }, "loan": { "response": "Loan requirements include minimum income (5000 SDG) and good credit history. We offer various loan types to suit your needs.", "actions": [ {"label": "Loan Calculator", "url": "https://onb.sd/loan-calculator"}, {"label": "Apply for Loan", "url": "https://onb.sd/loan-application"} ] }, # ... other guideline entries similarly expanded } } # Expanded menu with more descriptive options MENU = { "ar": """ 📱 قائمة الخدمات المصرفية المتقدمة: 1️⃣ رصيد - تتبع حسابك بسهولة 💰 2️⃣ بطاقة - الإبلاغ عن بطاقة مفقودة أو إيقافها 💳 3️⃣ قرض - استكشف خيارات التمويل 💸 4️⃣ تحويل - حوالات محلية ودولية 🌐 5️⃣ حساب - فتح حساب جديد بخطوات مبسطة 📋 6️⃣ فائدة - معرفة أحدث أسعار الفائدة 📈 7️⃣ فرع - مواقع وعناوين الفروع 🏦 8️⃣ ساعات - مواعيد العمل 🕒 9️⃣ اتصال - قنوات التواصل المتاحة 📞 """, "en": """ 📱 Advanced Banking Services Menu: 1️⃣ Balance - Easily track your account 💰 2️⃣ Card - Report or block lost card 💳 3️⃣ Loan - Explore financing options 💸 4️⃣ Transfer - Local and international transfers 🌐 5️⃣ Account - Open a new account in simple steps 📋 6️⃣ Interest - Latest interest rates 📈 7️⃣ Branch - Locations and addresses 🏦 8️⃣ Hours - Working hours 🕒 9️⃣ Contact - Available communication channels 📞 """ } # Enhanced intent keywords with more variations INTENT_KEYWORDS = { "balance": [ "balance", "check balance", "account balance", "how much", "رصيد", "حساب", "كم المبلغ", "1", "مبلغ" ], "lost_card": [ "lost", "card", "stolen", "missing", "block", "فقدت", "بطاقة", "مسروقة", "ضائعة", "إيقاف", "2" ], # ... other intents similarly expanded } def detect_language(text): """Detect the language of the input text.""" try: result = language_detector(text) language = result[0]['label'] return language if language in ['ar', 'en'] else 'en' except Exception: return 'en' def classify_intent(message: str): """Classify user intent based on keywords.""" message_lower = message.lower() # Check for menu request menu_keywords = ["menu", "options", "help", "قائمة", "خيارات", "مساعدة"] if any(keyword in message_lower for keyword in menu_keywords): return "menu" # Use keyword matching for intent classification for intent_key, keywords in INTENT_KEYWORDS.items(): if any(keyword.lower() in message_lower for keyword in keywords): return intent_key return "unknown" def generate_response(intent: str, language: str): """Generate a comprehensive response with actions.""" if intent == "menu": return { "response": MENU[language], "actions": [] } # Get the guideline for the specific intent and language guideline = ONB_GUIDELINES.get(language, {}).get(intent, { "response": "I'm sorry, I couldn't find specific information about this topic.", "actions": [] }) return guideline def generate_chat_response(message: str): """Generate a comprehensive chat response.""" if not message.strip(): return { "response": { "ar": "الرجاء كتابة سؤالك.", "en": "Please type your question." }, "actions": [] } # Detect language language = detect_language(message) # Classify intent intent = classify_intent(message) # Generate response response_data = generate_response(intent, language) return { "response": response_data['response'], "actions": response_data.get('actions', []), "language": language } # Custom CSS for enhanced UI custom_css = """ .gradio-container { font-family: 'Cairo', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; direction: rtl; } .chat-message { padding: 1rem; border-radius: 10px; margin-bottom: 1rem; max-width: 80%; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .user-message { background-color: #e6f7ff; margin-left: auto; text-align: right; direction: rtl; } .bot-message { background-color: #f0f0f0; margin-right: auto; text-align: right; direction: rtl; } .action-buttons { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.5rem; } .action-button { background-color: #1a5276; color: white; border: none; padding: 0.5rem 1rem; border-radius: 5px; text-decoration: none; display: inline-block; transition: background-color 0.3s ease; } .action-button:hover { background-color: #2980b9; } .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; } """ # Enhanced Gradio Interface def create_gradio_interface(): with gr.Blocks(css=custom_css) as demo: # Language selection language_state = gr.State(value="ar") language_btn = gr.Radio( ["العربية", "English"], value="العربية", label="Language | اللغة" ).container=False) # Chat interface chatbot = gr.Chatbot(height=500) msg = gr.Textbox(label="", placeholder="اكتب سؤالك هنا | Type your question here") submit_btn = gr.Button("إرسال | Send") # Action buttons container action_container = gr.HTML() # Update language state def update_language(lang): return "ar" if lang == "العربية" else "en" language_btn.change( fn=update_language, inputs=language_btn, outputs=language_state ) # Chat submission handler def submit_message(message, chat_history, language): # Generate response response_data = generate_chat_response(message) # Ensure we're using the correct language if response_data['language'] != language: language = response_data['language'] # Update chat history chat_history.append((message, response_data['response'])) # Prepare action buttons HTML action_html = "" if response_data.get('actions'): action_html = "
" return "", chat_history, action_html # Wire up the interface submit_btn.click( fn=submit_message, inputs=[msg, chatbot, language_state], outputs=[msg, chatbot, action_container] ) msg.submit( fn=submit_message, inputs=[msg, chatbot, language_state], outputs=[msg, chatbot, action_container] ) # Add menu button menu_btn = gr.Button("إظهار القائمة | Show Menu") def show_menu(chat_history, language): menu_text = MENU[language] chat_history.append((None, menu_text)) return chat_history menu_btn.click( fn=show_menu, inputs=[chatbot, language_state], outputs=[chatbot] ) # Header and footer with gr.Row(elem_classes="header-section"): gr.Markdown("# Omdurman National Bank | بنك أم درمان الوطني") gr.Markdown("### Virtual Banking Assistant | المساعد المصرفي الافتراضي") with gr.Row(elem_classes="footer-section"): gr.Markdown("© 2025 Omdurman National Bank. All Rights Reserved. | جميع الحقوق محفوظة لبنك أم درمان الوطني ٢٠٢٥ ©") return demo # Launch the application if __name__ == "__main__": demo = create_gradio_interface() demo.launch( server_name="0.0.0.0", server_port=7860, share=True )