waleedmohd commited on
Commit
d1f8c20
·
verified ·
1 Parent(s): 5509ced

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -617
app.py CHANGED
@@ -4,15 +4,14 @@ import json
4
  import time
5
  from datetime import datetime
6
 
7
- # Simple language detection function instead of using transformers
8
  def simple_detect_language(text):
9
- # Check for Arabic characters
10
  arabic_pattern = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF]+')
11
  if arabic_pattern.search(text):
12
  return "ar"
13
  return "en"
14
 
15
- # Try to import transformers for Arabic NLP if available
16
  try:
17
  from transformers import pipeline
18
  arabic_nlp = pipeline("text-classification", model="papluca/xlm-roberta-base-language-detection")
@@ -41,63 +40,43 @@ try:
41
  CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE = True
42
  except ImportError:
43
  CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE = False
44
- # Fallback customer service phrases
45
  ENHANCED_CUSTOMER_SERVICE_PHRASES_AR = {
46
- "greeting": [
47
- "مرحبًا بك في بنك أم درمان الوطني! كيف يمكنني مساعدتك اليوم؟",
48
- "أهلاً بك في خدمة العملاء الافتراضية لبنك أم درمان الوطني. كيف يمكنني خدمتك؟"
49
- ],
50
- "thanks": [
51
- "شكرًا لتواصلك مع بنك أم درمان الوطني!",
52
- "نشكرك على ثقتك في خدماتنا المصرفية."
53
- ],
54
- "follow_up": [
55
- "هل هناك خدمة مصرفية أخرى يمكنني مساعدتك بها اليوم؟",
56
- "هل لديك أي استفسارات أخرى حول منتجاتنا أو خدماتنا المصرفية؟"
57
- ]
58
  }
59
  ENHANCED_CUSTOMER_SERVICE_PHRASES_EN = {
60
- "greeting": [
61
- "Welcome to Omdurman National Bank! How may I assist you today?",
62
- "Hello and welcome to ONB virtual customer service. How can I help you?"
63
- ],
64
- "thanks": [
65
- "Thank you for contacting Omdurman National Bank!",
66
- "We appreciate your trust in our banking services."
67
- ],
68
- "follow_up": [
69
- "Is there any other banking service I can assist you with today?",
70
- "Do you have any other questions about our products or banking services?"
71
- ]
72
  }
73
 
74
- # Omdurman National Bank-specific guidelines in Arabic
75
  ONB_GUIDELINES_AR = {
76
- "balance": "يمكنك التحقق من رصيدك عبر الإنترنت أو عبر تطبيق الهاتف الخاص ببنك أم درمان الوطني. <a href='#' onclick='window.open(\"https://onb.sd/balance\", \"_blank\")'>افحص رصيدك الآن</a>",
77
- "lost_card": "في حالة فقدان البطاقة، اتصل بالرقم <a href='tel:249123456789'>249-123-456-789</a> فورًا أو <a href='#' onclick='window.open(\"https://onb.sd/block-card\", \"_blank\")'>أوقف البطاقة عبر الإنترنت</a>.",
78
- "loan": "شروط القرض تشمل الحد الأدنى للدخل (5000 جنيه سوداني) وتاريخ ائتماني جيد. <a href='#' onclick='window.open(\"https://onb.sd/loans\", \"_blank\")'>تقدم بطلب قرض الآن</a>",
79
- "transfer": "لتحويل الأموال، استخدم <a href='#' onclick='window.open(\"https://onb.sd/mobile-app\", \"_blank\")'>تطبيق الهاتف</a> أو <a href='#' onclick='window.open(\"https://onb.sd/online-banking\", \"_blank\")'>الخدمة المصرفية عبر الإنترنت</a>.",
80
- "new_account": "لفتح حساب جديد، قم بزيارة أقرب فرع مع جواز سفرك أو هويتك الوطنية. <a href='#' onclick='window.open(\"https://onb.sd/new-account\", \"_blank\")'>احجز موعدًا الآن</a>",
81
- "interest_rates": "أسعار الفائدة على الودائع تتراوح بين 5% إلى 10% سنويًا. <a href='#' onclick='window.open(\"https://onb.sd/rates\", \"_blank\")'>اطلع على جميع الأسعار</a>",
82
- "branches": "فروعنا موجودة في أم درمان، الخرطوم، وبورتسودان. <a href='#' onclick='window.open(\"https://onb.sd/branches\", \"_blank\")'>اعثر على أقرب فرع</a>",
83
- "working_hours": "ساعات العمل من 8 صباحًا إلى 3 مساءً من الأحد إلى الخميس. <a href='#' onclick='window.open(\"https://onb.sd/hours\", \"_blank\")'>تحقق من ساعات العمل الخاصة</a>",
84
- "contact": "الاتصال بنا على الرقم <a href='tel:249123456789'>249-123-456-789</a> أو عبر البريد الإلكتروني <a href='mailto:[email protected]'>info@onb.sd</a>. <a href='#' onclick='window.open(\"https://onb.sd/contact\", \"_blank\")'>نموذج الاتصال</a>"
85
  }
86
 
87
- # Omdurman National Bank-specific guidelines in English
88
  ONB_GUIDELINES_EN = {
89
- "balance": "You can check your balance online or via the ONB mobile app. <a href='#' onclick='window.open(\"https://onb.sd/balance\", \"_blank\")'>Check your balance now</a>",
90
- "lost_card": "In case of a lost card, call <a href='tel:249123456789'>249-123-456-789</a> immediately or <a href='#' onclick='window.open(\"https://onb.sd/block-card\", \"_blank\")'>block your card online</a>.",
91
- "loan": "Loan requirements include minimum income (5000 SDG) and good credit history. <a href='#' onclick='window.open(\"https://onb.sd/loans\", \"_blank\")'>Apply for a loan now</a>",
92
- "transfer": "To transfer funds, use the <a href='#' onclick='window.open(\"https://onb.sd/mobile-app\", \"_blank\")'>mobile app</a> or <a href='#' onclick='window.open(\"https://onb.sd/online-banking\", \"_blank\")'>online banking service</a>.",
93
- "new_account": "To open a new account, visit your nearest branch with your passport or national ID. <a href='#' onclick='window.open(\"https://onb.sd/new-account\", \"_blank\")'>Book an appointment now</a>",
94
- "interest_rates": "Interest rates on deposits range from 5% to 10% annually. <a href='#' onclick='window.open(\"https://onb.sd/rates\", \"_blank\")'>View all rates</a>",
95
- "branches": "Our branches are located in Omdurman, Khartoum, and Port Sudan. <a href='#' onclick='window.open(\"https://onb.sd/branches\", \"_blank\")'>Find your nearest branch</a>",
96
- "working_hours": "Working hours are from 8 AM to 3 PM, Sunday to Thursday. <a href='#' onclick='window.open(\"https://onb.sd/hours\", \"_blank\")'>Check special hours</a>",
97
- "contact": "Contact us at <a href='tel:249123456789'>249-123-456-789</a> or via email at <a href='mailto:[email protected]'>info@onb.sd</a>. <a href='#' onclick='window.open(\"https://onb.sd/contact\", \"_blank\")'>Contact form</a>"
98
  }
99
 
100
- # Quick action buttons in Arabic
101
  QUICK_ACTIONS_AR = [
102
  {"text": "تحقق من الرصيد", "intent": "balance"},
103
  {"text": "الإبلاغ عن بطاقة مفقودة", "intent": "lost_card"},
@@ -110,7 +89,6 @@ QUICK_ACTIONS_AR = [
110
  {"text": "اتصل بنا", "intent": "contact"}
111
  ]
112
 
113
- # Quick action buttons in English
114
  QUICK_ACTIONS_EN = [
115
  {"text": "Check Balance", "intent": "balance"},
116
  {"text": "Report Lost Card", "intent": "lost_card"},
@@ -123,47 +101,7 @@ QUICK_ACTIONS_EN = [
123
  {"text": "Contact Us", "intent": "contact"}
124
  ]
125
 
126
- # Menu options in both languages
127
- MENU_AR = """
128
- قائمة الخدمات المصرفية:
129
- 1. رصيد - استعلام عن رصيد حسابك
130
- 2. بطاقة - الإبلاغ عن بطاقة مفقودة
131
- 3. قرض - معلومات عن القروض
132
- 4. تحويل - تحويل الأموال
133
- 5. حساب - فتح حساب جديد
134
- 6. فائدة - أسعار الفائدة
135
- 7. فرع - م��اقع الفروع
136
- 8. ساعات - ساعات العمل
137
- 9. اتصال - معلومات الاتصال
138
- """
139
-
140
- MENU_EN = """
141
- Banking Services Menu:
142
- 1. balance - Check your account balance
143
- 2. card - Report a lost card
144
- 3. loan - Information about loans
145
- 4. transfer - Transfer funds
146
- 5. account - Open a new account
147
- 6. interest - Interest rates
148
- 7. branch - Branch locations
149
- 8. hours - Working hours
150
- 9. contact - Contact information
151
- """
152
-
153
- # Map intents to keywords (enhanced)
154
- INTENT_KEYWORDS = {
155
- "balance": ["balance", "check balance", "account balance", "how much", "رصيد", "حساب", "كم المبلغ", "1"],
156
- "lost_card": ["lost", "card", "stolen", "missing", "فقدت", "بطاقة", "مسروقة", "ضائعة", "2"],
157
- "loan": ["loan", "borrow", "borrowing", "credit", "قرض", "استدانة", "إئتمان", "3"],
158
- "transfer": ["transfer", "send money", "payment", "تحويل", "ارسال", "دفع", "4"],
159
- "new_account": ["account", "open", "create", "new", "حساب", "فتح", "جديد", "إنشاء", "5"],
160
- "interest_rates": ["interest", "rate", "rates", "return", "فائدة", "نسبة", "عائد", "6"],
161
- "branches": ["branch", "location", "where", "office", "فرع", "موقع", "أين", "مكتب", "7"],
162
- "working_hours": ["hours", "time", "open", "close", "ساعات", "وقت", "مفتوح", "مغلق", "8"],
163
- "contact": ["contact", "phone", "email", "call", "اتصال", "هاتف", "بريد", "اتصل", "9"]
164
- }
165
-
166
- # Function to get a random phrase from the customer service phrases
167
  def get_random_phrase(category, language):
168
  import random
169
  if language == "ar":
@@ -172,7 +110,6 @@ def get_random_phrase(category, language):
172
  return random.choice(ENHANCED_CUSTOMER_SERVICE_PHRASES_EN[category])
173
 
174
  def classify_intent(message: str):
175
- # Check for menu request
176
  menu_keywords = ["menu", "options", "help", "قائمة", "خيارات", "مساعدة"]
177
  message_lower = message.lower()
178
 
@@ -180,7 +117,6 @@ def classify_intent(message: str):
180
  if keyword in message_lower:
181
  return "menu"
182
 
183
- # Use keyword matching for intent classification
184
  for intent_key, keywords in INTENT_KEYWORDS.items():
185
  for keyword in keywords:
186
  if keyword.lower() in message_lower:
@@ -205,6 +141,7 @@ def log_interaction(user_message, bot_response, intent, language):
205
  except Exception as e:
206
  print(f"Error logging interaction: {e}")
207
 
 
208
  def respond(message: str):
209
  if not message.strip():
210
  return {
@@ -212,604 +149,111 @@ def respond(message: str):
212
  "en": "Please type your question."
213
  }
214
 
215
- # Detect language using NLP if available, otherwise use simple detection
216
  if ARABIC_NLP_AVAILABLE:
217
  language = detect_language_with_nlp(message)
218
- # If the language is neither Arabic nor English, default to English
219
  if language != "ar" and language != "en":
220
  language = "en"
221
  else:
222
  language = simple_detect_language(message)
223
 
224
- # Classify the user's intent using keyword matching
225
  intent = classify_intent(message)
226
 
227
- # Prepare responses in both languages
228
  responses = {
229
  "ar": "",
230
  "en": ""
231
  }
232
 
233
- # Special handling for menu request
234
  if intent == "menu":
235
  responses["ar"] = MENU_AR
236
  responses["en"] = MENU_EN
237
  log_interaction(message, responses[language], "menu", language)
238
  return responses
239
 
240
- # Check if it's a banking FAQ
241
  if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
242
  faq_answer = handle_banking_faq(message, language)
243
  if faq_answer:
244
- # Add a greeting phrase at the beginning
245
- greeting_ar = get_random_phrase("greeting", "ar")
246
- greeting_en = get_random_phrase("greeting", "en")
247
-
248
- # Add a follow-up phrase at the end
249
- follow_up_ar = get_random_phrase("follow_up", "ar")
250
- follow_up_en = get_random_phrase("follow_up", "en")
251
-
252
- # Combine all parts
253
- responses["ar"] = f"{greeting_ar}<br><br>{faq_answer}<br><br>{follow_up_ar}"
254
- responses["en"] = f"{greeting_en}<br><br>{faq_answer}<br><br>{follow_up_en}"
255
-
256
  log_interaction(message, responses[language], "faq", language)
257
  return responses
258
 
259
- # Check if it's a banking term definition request
260
  if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
261
  term_definition = get_banking_term_definition(message, language)
262
  if term_definition:
263
- # Add a greeting phrase at the beginning
264
- greeting_ar = get_random_phrase("greeting", "ar")
265
- greeting_en = get_random_phrase("greeting", "en")
266
-
267
- # Add a follow-up phrase at the end
268
- follow_up_ar = get_random_phrase("follow_up", "ar")
269
- follow_up_en = get_random_phrase("follow_up", "en")
270
-
271
- # Combine all parts
272
- responses["ar"] = f"{greeting_ar}<br><br>{term_definition}<br><br>{follow_up_ar}"
273
- responses["en"] = f"{greeting_en}<br><br>{term_definition}<br><br>{follow_up_en}"
274
-
275
  log_interaction(message, responses[language], "term", language)
276
  return responses
277
 
278
- # If intent is recognized, return the corresponding response
279
  if intent != "unknown":
280
  if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
281
- # Use enhanced response if available
282
  responses["ar"] = get_enhanced_response(intent, "ar")
283
  responses["en"] = get_enhanced_response(intent, "en")
284
  else:
285
- # Add a greeting phrase at the beginning
286
- greeting_ar = get_random_phrase("greeting", "ar")
287
- greeting_en = get_random_phrase("greeting", "en")
288
-
289
- # Add the main response
290
- main_response_ar = ONB_GUIDELINES_AR.get(intent, "عذرًا، لم يتم التعرف على الخيار المحدد.")
291
- main_response_en = ONB_GUIDELINES_EN.get(intent, "Sorry, the selected option was not recognized.")
292
-
293
- # Add a follow-up phrase at the end
294
- follow_up_ar = get_random_phrase("follow_up", "ar")
295
- follow_up_en = get_random_phrase("follow_up", "en")
296
-
297
- # Combine all parts
298
- responses["ar"] = f"{greeting_ar}<br><br>{main_response_ar}<br><br>{follow_up_ar}"
299
- responses["en"] = f"{greeting_en}<br><br>{main_response_en}<br><br>{follow_up_en}"
300
  else:
301
- # Default response if no intent is matched - show menu
302
  responses["ar"] = "عذرًا، لم أفهم سؤالك. إليك قائمة بالخدمات المتاحة:" + MENU_AR
303
  responses["en"] = "Sorry, I didn't understand your question. Here's a menu of available services:" + MENU_EN
304
 
305
- # Log the interaction
306
  log_interaction(message, responses[language], intent, language)
307
-
308
  return responses
309
 
310
- # Custom CSS for better UI
311
- custom_css = """
312
- .gradio-container {
313
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
314
- }
315
-
316
- .chat-message {
317
- padding: 1rem;
318
- border-radius: 10px;
319
- margin-bottom: 1rem;
320
- max-width: 80%;
321
- }
322
-
323
- .user-message {
324
- background-color: #e6f7ff;
325
- margin-left: auto;
326
- text-align: right;
327
- }
328
-
329
- .bot-message {
330
- background-color: #f0f0f0;
331
- margin-right: auto;
332
- text-align: left;
333
- }
334
-
335
- .bot-message-ar {
336
- background-color: #f0f0f0;
337
- margin-left: auto;
338
- text-align: right;
339
- }
340
-
341
- .header-section {
342
- background-color: #1a5276;
343
- color: white;
344
- padding: 1rem;
345
- border-radius: 10px;
346
- margin-bottom: 1rem;
347
- text-align: center;
348
- }
349
-
350
- .footer-section {
351
- font-size: 0.8rem;
352
- text-align: center;
353
- margin-top: 2rem;
354
- color: #666;
355
- }
356
-
357
- .lang-selector {
358
- text-align: right;
359
- margin-bottom: 1rem;
360
- }
361
-
362
- .menu-button {
363
- margin-top: 0.5rem;
364
- }
365
-
366
- .quick-actions {
367
- display: flex;
368
- flex-wrap: wrap;
369
- gap: 0.5rem;
370
- margin: 1rem 0;
371
- }
372
-
373
- .quick-action-button {
374
- background-color: #1a5276;
375
- color: white;
376
- border: none;
377
- border-radius: 20px;
378
- padding: 0.5rem 1rem;
379
- cursor: pointer;
380
- font-size: 0.9rem;
381
- transition: background-color 0.3s;
382
- }
383
-
384
- .quick-action-button:hover {
385
- background-color: #2980b9;
386
- }
387
-
388
- .chat-container {
389
- border: 1px solid #ddd;
390
- border-radius: 10px;
391
- padding: 1rem;
392
- background-color: #f9f9f9;
393
- }
394
-
395
- .live-agent-button {
396
- background-color: #27ae60;
397
- color: white;
398
- border: none;
399
- border-radius: 5px;
400
- padding: 0.5rem 1rem;
401
- cursor: pointer;
402
- font-size: 0.9rem;
403
- margin-top: 1rem;
404
- transition: background-color 0.3s;
405
- }
406
-
407
- .live-agent-button:hover {
408
- background-color: #2ecc71;
409
- }
410
-
411
- /* Add custom styling for links */
412
- a {
413
- color: #2980b9;
414
- text-decoration: none;
415
- font-weight: bold;
416
- }
417
-
418
- a:hover {
419
- text-decoration: underline;
420
- }
421
-
422
- /* Add styling for action buttons */
423
- .action-button {
424
- display: inline-block;
425
- background-color: #3498db;
426
- color: white;
427
- padding: 0.5rem 1rem;
428
- border-radius: 5px;
429
- margin: 0.5rem 0;
430
- text-decoration: none;
431
- }
432
-
433
- .action-button:hover {
434
- background-color: #2980b9;
435
- text-decoration: none;
436
- }
437
-
438
- /* Styling for satisfaction survey */
439
- .satisfaction-survey {
440
- background-color: #f8f9fa;
441
- border: 1px solid #ddd;
442
- border-radius: 10px;
443
- padding: 1rem;
444
- margin-top: 1rem;
445
- }
446
-
447
- .survey-question {
448
- margin-bottom: 1rem;
449
- }
450
-
451
- .rating-options {
452
- display: flex;
453
- justify-content: space-between;
454
- margin-bottom: 0.5rem;
455
- }
456
-
457
- .survey-submit {
458
- background-color: #1a5276;
459
- color: white;
460
- border: none;
461
- border-radius: 5px;
462
- padding: 0.5rem 1rem;
463
- cursor: pointer;
464
- font-size: 0.9rem;
465
- margin-top: 1rem;
466
- }
467
-
468
- .survey-submit:hover {
469
- background-color: #2980b9;
470
- }
471
- """
472
-
473
- # Chat interface with simplified UI for Hugging Face
474
- with gr.Blocks(css=custom_css) as demo:
475
- # Store selected language
476
  selected_lang = gr.State(value="ar")
477
- # Store user name for personalization
478
  user_name = gr.State(value=None)
479
 
480
- with gr.Row(elem_classes="header-section"):
481
- with gr.Column():
482
- gr.Markdown("# Omdurman National Bank | بنك أم درمان الوطني")
483
- gr.Markdown("### Virtual Banking Assistant | المساعد المصرفي الافتراضي")
484
-
485
  with gr.Row():
486
- with gr.Column(elem_classes="lang-selector"):
487
- language_btn = gr.Radio(
488
- ["العربية", "English"],
489
- value="العربية",
490
- label="Language | اللغة"
491
- )
492
-
493
- with gr.Row(elem_classes="chat-container"):
494
- chatbot = gr.Chatbot(height=400)
495
 
496
- # Quick action buttons container
497
- with gr.Row(elem_classes="quick-actions", visible=True) as quick_actions_container:
498
- balance_btn = gr.Button("تحقق من الرصيد", elem_classes="quick-action-button")
499
- lost_card_btn = gr.Button("الإبلاغ عن بطاقة مفقودة", elem_classes="quick-action-button")
500
- loan_btn = gr.Button("معلومات القرض", elem_classes="quick-action-button")
501
-
502
- with gr.Row(elem_classes="quick-actions", visible=True):
503
- transfer_btn = gr.Button("تحويل الأموال", elem_classes="quick-action-button")
504
- new_account_btn = gr.Button("فتح حساب جديد", elem_classes="quick-action-button")
505
- interest_btn = gr.Button("أسعار الفائدة", elem_classes="quick-action-button")
506
 
507
- with gr.Row(elem_classes="quick-actions", visible=True):
508
- branches_btn = gr.Button("مواقع الفروع", elem_classes="quick-action-button")
509
- hours_btn = gr.Button("ساعات العمل", elem_classes="quick-action-button")
510
- contact_btn = gr.Button("اتصل بنا", elem_classes="quick-action-button")
511
 
512
  with gr.Row():
513
- with gr.Column(scale=8):
514
- text_input = gr.Textbox(
515
- placeholder="Type your question here | اكتب سؤالك هنا",
516
- label="",
517
- elem_id="chat-input"
518
- )
519
- with gr.Column(scale=1):
520
- submit_btn = gr.Button("Send | إرسال", variant="primary")
521
 
522
  with gr.Row():
523
- with gr.Column(scale=1):
524
- menu_btn = gr.Button("Show Menu | إظهار القائمة", elem_classes="menu-button")
525
- with gr.Column(scale=1):
526
- live_agent_btn = gr.Button("Connect to Live Agent | الاتصال بوكيل حي", elem_classes="live-agent-button")
527
- with gr.Column(scale=1):
528
- survey_btn = gr.Button("Feedback | تقييم الخدمة", elem_classes="menu-button")
529
-
530
- with gr.Row(elem_classes="footer-section"):
531
- gr.Markdown("© 2025 Omdurman National Bank. All Rights Reserved. | جميع الحقوق محفوظة لبنك أم درمان الوطني ٢٠٢٥ ©")
532
-
533
- # Update language state and quick action buttons when language is changed
534
- def update_language(lang):
535
- language_code = "ar" if lang == "العربية" else "en"
536
-
537
- # Get the appropriate quick actions based on language
538
- quick_actions = QUICK_ACTIONS_AR if language_code == "ar" else QUICK_ACTIONS_EN
539
-
540
- # Update button text based on language
541
- return [
542
- language_code,
543
- quick_actions[0]["text"], # balance
544
- quick_actions[1]["text"], # lost_card
545
- quick_actions[2]["text"], # loan
546
- quick_actions[3]["text"], # transfer
547
- quick_actions[4]["text"], # new_account
548
- quick_actions[5]["text"], # interest
549
- quick_actions[6]["text"], # branches
550
- quick_actions[7]["text"], # working_hours
551
- quick_actions[8]["text"] # contact
552
- ]
553
-
554
- # Connect language button to update function
555
- language_btn.change(
556
- fn=update_language,
557
- inputs=language_btn,
558
- outputs=[
559
- selected_lang,
560
- balance_btn,
561
- lost_card_btn,
562
- loan_btn,
563
- transfer_btn,
564
- new_account_btn,
565
- interest_btn,
566
- branches_btn,
567
- hours_btn,
568
- contact_btn
569
- ]
570
- )
571
-
572
- # Handle message submission
573
- def on_submit(message, chat_history, lang, name):
574
- if not message.strip():
575
- return "", chat_history, name
576
-
577
- # Check if this is a name introduction
578
- name_patterns = [
579
- r"my name is (\w+)",
580
- r"i am (\w+)",
581
- r"i'm (\w+)",
582
- r"اسمي (\w+)",
583
- r"أنا (\w+)"
584
- ]
585
-
586
- for pattern in name_patterns:
587
- match = re.search(pattern, message.lower())
588
- if match:
589
- name = match.group(1)
590
- break
591
-
592
- # Add user message to chat history
593
- chat_history = chat_history + [[message, None]]
594
-
595
- # Get response
596
- responses = respond(message)
597
-
598
- # Select response based on language
599
- response = responses[lang]
600
-
601
- # Personalize response if name is available
602
- if name and CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
603
- if lang == "ar":
604
- response = response.replace("مرحبًا", f"مرحبًا {name}")
605
- else:
606
- response = response.replace("Welcome", f"Welcome {name}")
607
- response = response.replace("Hello", f"Hello {name}")
608
-
609
- # Update bot response in chat history
610
- chat_history[-1][1] = response
611
-
612
- return "", chat_history, name
613
-
614
- # Handle menu button click
615
- def show_menu(chat_history, lang):
616
- menu_responses = {
617
- "ar": MENU_AR,
618
- "en": MENU_EN
619
- }
620
-
621
- # Get menu text
622
- menu_text = menu_responses[lang]
623
-
624
- # Add system message showing the menu
625
- chat_history = chat_history + [[None, menu_text.replace("\n", "<br>")]]
626
-
627
- return chat_history
628
 
629
- # Handle quick action button clicks
630
- def handle_quick_action(intent, chat_history, lang, name):
631
- # Get the appropriate quick actions based on language
632
- quick_actions = QUICK_ACTIONS_AR if lang == "ar" else QUICK_ACTIONS_EN
633
-
634
- # Find the button text for this intent
635
- button_text = ""
636
- for action in quick_actions:
637
- if action["intent"] == intent:
638
- button_text = action["text"]
639
- break
640
-
641
- # Add button text as user message
642
- chat_history = chat_history + [[button_text, None]]
643
-
644
- # Get the response for this intent
645
- if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
646
- # Use enhanced response if available
647
- response_ar = get_enhanced_response(intent, "ar", name)
648
- response_en = get_enhanced_response(intent, "en", name)
649
- else:
650
- # Add a greeting phrase at the beginning
651
- greeting_ar = get_random_phrase("greeting", "ar")
652
- greeting_en = get_random_phrase("greeting", "en")
653
-
654
- # Add the main response
655
- main_response_ar = ONB_GUIDELINES_AR.get(intent, "")
656
- main_response_en = ONB_GUIDELINES_EN.get(intent, "")
657
-
658
- # Add a follow-up phrase at the end
659
- follow_up_ar = get_random_phrase("follow_up", "ar")
660
- follow_up_en = get_random_phrase("follow_up", "en")
661
-
662
- # Combine all parts
663
- response_ar = f"{greeting_ar}<br><br>{main_response_ar}<br><br>{follow_up_ar}"
664
- response_en = f"{greeting_en}<br><br>{main_response_en}<br><br>{follow_up_en}"
665
-
666
- responses = {
667
- "ar": response_ar,
668
- "en": response_en
669
- }
670
-
671
- # Select response based on language
672
- response = responses[lang]
673
-
674
- # Personalize response if name is available
675
- if name:
676
- if lang == "ar":
677
- response = response.replace("مرحبًا", f"مرحبًا {name}")
678
- else:
679
- response = response.replace("Welcome", f"Welcome {name}")
680
- response = response.replace("Hello", f"Hello {name}")
681
-
682
- # Update bot response in chat history
683
- chat_history[-1][1] = response
684
-
685
- # Log the interaction
686
- log_interaction(button_text, response, intent, lang)
687
-
688
- return chat_history
689
-
690
- # Handle live agent button click
691
- def connect_to_live_agent(chat_history, lang):
692
- message = "Connecting to a live customer service agent. Please wait a moment..." if lang == "en" else "جاري الاتصال بوكيل خدمة العملاء. يرجى الانتظار لحظة..."
693
- chat_history = chat_history + [[None, message]]
694
- return chat_history
695
-
696
- # Handle satisfaction survey button click
697
- def show_satisfaction_survey(chat_history, lang):
698
- if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
699
- survey_html = offer_satisfaction_survey(lang)
700
- chat_history = chat_history + [[None, survey_html]]
701
- else:
702
- # Simple survey message if enhancements not available
703
- title = "استطلاع رضا العملاء" if lang == "ar" else "Customer Satisfaction Survey"
704
- message = f"<div class='satisfaction-survey'><h3>{title}</h3><p>{'نشكرك على استخدام المساعد المصرفي الافتراضي!' if lang == 'ar' else 'Thank you for using our virtual banking assistant!'}</p></div>"
705
- chat_history = chat_history + [[None, message]]
706
-
707
- return chat_history
708
-
709
- # Link inputs and button to response function
710
  submit_btn.click(
711
  fn=on_submit,
712
  inputs=[text_input, chatbot, selected_lang, user_name],
713
  outputs=[text_input, chatbot, user_name]
714
  )
715
 
716
- # Link menu button to show menu function
717
  menu_btn.click(
718
  fn=show_menu,
719
  inputs=[chatbot, selected_lang],
720
  outputs=[chatbot]
721
  )
722
 
723
- # Link live agent button to connect function
724
  live_agent_btn.click(
725
  fn=connect_to_live_agent,
726
  inputs=[chatbot, selected_lang],
727
  outputs=[chatbot]
728
  )
729
 
730
- # Link survey button to show survey function
731
  survey_btn.click(
732
  fn=show_satisfaction_survey,
733
  inputs=[chatbot, selected_lang],
734
  outputs=[chatbot]
735
  )
736
 
737
- # Link quick action buttons to handler function
738
- balance_btn.click(
739
- fn=lambda chat=chatbot, lang=selected_lang, name=user_name: handle_quick_action("balance", chat, lang, name),
740
- inputs=[chatbot, selected_lang, user_name],
741
- outputs=[chatbot]
742
- )
743
-
744
- lost_card_btn.click(
745
- fn=lambda chat=chatbot, lang=selected_lang, name=user_name: handle_quick_action("lost_card", chat, lang, name),
746
- inputs=[chatbot, selected_lang, user_name],
747
- outputs=[chatbot]
748
- )
749
-
750
- loan_btn.click(
751
- fn=lambda chat=chatbot, lang=selected_lang, name=user_name: handle_quick_action("loan", chat, lang, name),
752
- inputs=[chatbot, selected_lang, user_name],
753
- outputs=[chatbot]
754
- )
755
-
756
- transfer_btn.click(
757
- fn=lambda chat=chatbot, lang=selected_lang, name=user_name: handle_quick_action("transfer", chat, lang, name),
758
- inputs=[chatbot, selected_lang, user_name],
759
- outputs=[chatbot]
760
- )
761
-
762
- new_account_btn.click(
763
- fn=lambda chat=chatbot, lang=selected_lang, name=user_name: handle_quick_action("new_account", chat, lang, name),
764
- inputs=[chatbot, selected_lang, user_name],
765
- outputs=[chatbot]
766
- )
767
-
768
- interest_btn.click(
769
- fn=lambda chat=chatbot, lang=selected_lang, name=user_name: handle_quick_action("interest_rates", chat, lang, name),
770
- inputs=[chatbot, selected_lang, user_name],
771
- outputs=[chatbot]
772
- )
773
-
774
- branches_btn.click(
775
- fn=lambda chat=chatbot, lang=selected_lang, name=user_name: handle_quick_action("branches", chat, lang, name),
776
- inputs=[chatbot, selected_lang, user_name],
777
- outputs=[chatbot]
778
- )
779
-
780
- hours_btn.click(
781
- fn=lambda chat=chatbot, lang=selected_lang, name=user_name: handle_quick_action("working_hours", chat, lang, name),
782
- inputs=[chatbot, selected_lang, user_name],
783
- outputs=[chatbot]
784
- )
785
-
786
- contact_btn.click(
787
- fn=lambda chat=chatbot, lang=selected_lang, name=user_name: handle_quick_action("contact", chat, lang, name),
788
- inputs=[chatbot, selected_lang, user_name],
789
- outputs=[chatbot]
790
- )
791
-
792
- # Also trigger on Enter key
793
- text_input.submit(
794
- fn=on_submit,
795
- inputs=[text_input, chatbot, selected_lang, user_name],
796
- outputs=[text_input, chatbot, user_name]
797
- )
798
-
799
- # Initialize the chat with a welcome message
800
- def init_chat():
801
- # Welcome message in both languages
802
- welcome_ar = "مرحبًا بك في المساعد المصرفي الافتراضي لبنك أم درمان الوطني! يمكنك طرح أي سؤال حول خدماتنا المصرفية أو استخدام أزرار الإجراءات السريعة أدناه."
803
- welcome_en = "Welcome to Omdurman National Bank Virtual Banking Assistant! You can ask any question about our banking services or use the quick action buttons below."
804
-
805
- # Initialize chat with welcome messages
806
- chat_history = []
807
- chat_history.append([None, welcome_ar])
808
- chat_history.append([None, welcome_en])
809
-
810
- return chat_history
811
-
812
- # Initialize the chat when the app starts
813
  demo.load(
814
  fn=init_chat,
815
  inputs=[],
@@ -817,8 +261,4 @@ with gr.Blocks(css=custom_css) as demo:
817
  )
818
 
819
  if __name__ == "__main__":
820
- demo.launch(
821
- server_name="0.0.0.0",
822
- server_port=7860,
823
- share=True # Enable public link
824
- )
 
4
  import time
5
  from datetime import datetime
6
 
7
+ # Simple language detection function
8
  def simple_detect_language(text):
 
9
  arabic_pattern = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF]+')
10
  if arabic_pattern.search(text):
11
  return "ar"
12
  return "en"
13
 
14
+ # Try to import transformers for Arabic NLP
15
  try:
16
  from transformers import pipeline
17
  arabic_nlp = pipeline("text-classification", model="papluca/xlm-roberta-base-language-detection")
 
40
  CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE = True
41
  except ImportError:
42
  CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE = False
 
43
  ENHANCED_CUSTOMER_SERVICE_PHRASES_AR = {
44
+ "greeting": ["مرحبًا بك في بنك أم درمان الوطني! كيف يمكنني مساعدتك اليوم؟"],
45
+ "thanks": ["شكرًا لتواصلك مع بنك أم درمان الوطني!"],
46
+ "follow_up": ["هل هناك خدمة أخرى يمكنني مساعدتك بها؟"]
 
 
 
 
 
 
 
 
 
47
  }
48
  ENHANCED_CUSTOMER_SERVICE_PHRASES_EN = {
49
+ "greeting": ["Welcome to Omdurman National Bank! How may I assist you today?"],
50
+ "thanks": ["Thank you for contacting Omdurman National Bank!"],
51
+ "follow_up": ["Is there anything else I can help you with?"]
 
 
 
 
 
 
 
 
 
52
  }
53
 
54
+ # Omdurman National Bank-specific guidelines
55
  ONB_GUIDELINES_AR = {
56
+ "balance": "يمكنك التحقق من رصيدك عبر الإنترنت أو عبر تطبيق الهاتف الخاص ببنك أم درمان الوطني.",
57
+ "lost_card": "في حالة فقدان البطاقة، اتصل بالرقم 249-123-456-789 فورًا.",
58
+ "loan": "شروط القرض تشمل الحد الأدنى للدخل (5000 جنيه سوداني) وتاريخ ائتماني جيد.",
59
+ "transfer": "لتحويل الأموال، استخدم تطبيق الهاتف أو الخدمة المصرفية عبر الإنترنت.",
60
+ "new_account": "لفتح حساب جديد، قم بزيارة أقرب فرع مع جواز سفرك أو هويتك الوطنية.",
61
+ "interest_rates": "أسعار الفائدة على الودائع تتراوح بين 5% إلى 10% سنويًا.",
62
+ "branches": "فروعنا موجودة في أم درمان، الخرطوم، وبورتسودان.",
63
+ "working_hours": "ساعات العمل من 8 صباحًا إلى 3 مساءً من الأحد إلى الخميس.",
64
+ "contact": "الاتصال بنا على الرقم 249-123-456-789 أو عبر البريد الإلكتروني [email protected]."
65
  }
66
 
 
67
  ONB_GUIDELINES_EN = {
68
+ "balance": "You can check your balance online or via the ONB mobile app.",
69
+ "lost_card": "In case of a lost card, call 249-123-456-789 immediately.",
70
+ "loan": "Loan requirements include minimum income (5000 SDG) and good credit history.",
71
+ "transfer": "To transfer funds, use the mobile app or online banking service.",
72
+ "new_account": "To open a new account, visit your nearest branch with your passport or national ID.",
73
+ "interest_rates": "Interest rates on deposits range from 5% to 10% annually.",
74
+ "branches": "Our branches are located in Omdurman, Khartoum, and Port Sudan.",
75
+ "working_hours": "Working hours are from 8 AM to 3 PM, Sunday to Thursday.",
76
+ "contact": "Contact us at 249-123-456-789 or via email at [email protected]."
77
  }
78
 
79
+ # Quick action buttons
80
  QUICK_ACTIONS_AR = [
81
  {"text": "تحقق من الرصيد", "intent": "balance"},
82
  {"text": "الإبلاغ عن بطاقة مفقودة", "intent": "lost_card"},
 
89
  {"text": "اتصل بنا", "intent": "contact"}
90
  ]
91
 
 
92
  QUICK_ACTIONS_EN = [
93
  {"text": "Check Balance", "intent": "balance"},
94
  {"text": "Report Lost Card", "intent": "lost_card"},
 
101
  {"text": "Contact Us", "intent": "contact"}
102
  ]
103
 
104
+ # Function to get a random phrase
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  def get_random_phrase(category, language):
106
  import random
107
  if language == "ar":
 
110
  return random.choice(ENHANCED_CUSTOMER_SERVICE_PHRASES_EN[category])
111
 
112
  def classify_intent(message: str):
 
113
  menu_keywords = ["menu", "options", "help", "قائمة", "خيارات", "مساعدة"]
114
  message_lower = message.lower()
115
 
 
117
  if keyword in message_lower:
118
  return "menu"
119
 
 
120
  for intent_key, keywords in INTENT_KEYWORDS.items():
121
  for keyword in keywords:
122
  if keyword.lower() in message_lower:
 
141
  except Exception as e:
142
  print(f"Error logging interaction: {e}")
143
 
144
+ # Function to generate responses
145
  def respond(message: str):
146
  if not message.strip():
147
  return {
 
149
  "en": "Please type your question."
150
  }
151
 
152
+ # Detect language
153
  if ARABIC_NLP_AVAILABLE:
154
  language = detect_language_with_nlp(message)
 
155
  if language != "ar" and language != "en":
156
  language = "en"
157
  else:
158
  language = simple_detect_language(message)
159
 
160
+ # Classify intent
161
  intent = classify_intent(message)
162
 
163
+ # Prepare responses
164
  responses = {
165
  "ar": "",
166
  "en": ""
167
  }
168
 
169
+ # Handle menu request
170
  if intent == "menu":
171
  responses["ar"] = MENU_AR
172
  responses["en"] = MENU_EN
173
  log_interaction(message, responses[language], "menu", language)
174
  return responses
175
 
176
+ # Handle banking FAQ
177
  if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
178
  faq_answer = handle_banking_faq(message, language)
179
  if faq_answer:
180
+ responses["ar"] = f"{get_random_phrase('greeting', 'ar')}<br><br>{faq_answer}<br><br>{get_random_phrase('follow_up', 'ar')}"
181
+ responses["en"] = f"{get_random_phrase('greeting', 'en')}<br><br>{faq_answer}<br><br>{get_random_phrase('follow_up', 'en')}"
 
 
 
 
 
 
 
 
 
 
182
  log_interaction(message, responses[language], "faq", language)
183
  return responses
184
 
185
+ # Handle banking term definition
186
  if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
187
  term_definition = get_banking_term_definition(message, language)
188
  if term_definition:
189
+ responses["ar"] = f"{get_random_phrase('greeting', 'ar')}<br><br>{term_definition}<br><br>{get_random_phrase('follow_up', 'ar')}"
190
+ responses["en"] = f"{get_random_phrase('greeting', 'en')}<br><br>{term_definition}<br><br>{get_random_phrase('follow_up', 'en')}"
 
 
 
 
 
 
 
 
 
 
191
  log_interaction(message, responses[language], "term", language)
192
  return responses
193
 
194
+ # Handle recognized intents
195
  if intent != "unknown":
196
  if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
 
197
  responses["ar"] = get_enhanced_response(intent, "ar")
198
  responses["en"] = get_enhanced_response(intent, "en")
199
  else:
200
+ responses["ar"] = f"{get_random_phrase('greeting', 'ar')}<br><br>{ONB_GUIDELINES_AR.get(intent, 'عذرًا، لم يتم التعرف على الخيار المحدد.')}<br><br>{get_random_phrase('follow_up', 'ar')}"
201
+ responses["en"] = f"{get_random_phrase('greeting', 'en')}<br><br>{ONB_GUIDELINES_EN.get(intent, 'Sorry, the selected option was not recognized.')}<br><br>{get_random_phrase('follow_up', 'en')}"
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  else:
 
203
  responses["ar"] = "عذرًا، لم أفهم سؤالك. إليك قائمة بالخدمات المتاحة:" + MENU_AR
204
  responses["en"] = "Sorry, I didn't understand your question. Here's a menu of available services:" + MENU_EN
205
 
 
206
  log_interaction(message, responses[language], intent, language)
 
207
  return responses
208
 
209
+ # Gradio Interface
210
+ with gr.Blocks() as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  selected_lang = gr.State(value="ar")
 
212
  user_name = gr.State(value=None)
213
 
 
 
 
 
 
214
  with gr.Row():
215
+ gr.Markdown("# Omdurman National Bank Virtual Assistant")
 
 
 
 
 
 
 
 
216
 
217
+ with gr.Row():
218
+ language_btn = gr.Radio(["العربية", "English"], value="العربية", label="Language")
 
 
 
 
 
 
 
 
219
 
220
+ chatbot = gr.Chatbot(height=400)
 
 
 
221
 
222
  with gr.Row():
223
+ text_input = gr.Textbox(placeholder="Type your question here", label="")
224
+ submit_btn = gr.Button("Send", variant="primary")
 
 
 
 
 
 
225
 
226
  with gr.Row():
227
+ menu_btn = gr.Button("Show Menu")
228
+ live_agent_btn = gr.Button("Connect to Live Agent")
229
+ survey_btn = gr.Button("Feedback")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
 
231
+ # Link inputs and buttons to response functions
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  submit_btn.click(
233
  fn=on_submit,
234
  inputs=[text_input, chatbot, selected_lang, user_name],
235
  outputs=[text_input, chatbot, user_name]
236
  )
237
 
 
238
  menu_btn.click(
239
  fn=show_menu,
240
  inputs=[chatbot, selected_lang],
241
  outputs=[chatbot]
242
  )
243
 
 
244
  live_agent_btn.click(
245
  fn=connect_to_live_agent,
246
  inputs=[chatbot, selected_lang],
247
  outputs=[chatbot]
248
  )
249
 
 
250
  survey_btn.click(
251
  fn=show_satisfaction_survey,
252
  inputs=[chatbot, selected_lang],
253
  outputs=[chatbot]
254
  )
255
 
256
+ # Initialize chat
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  demo.load(
258
  fn=init_chat,
259
  inputs=[],
 
261
  )
262
 
263
  if __name__ == "__main__":
264
+ demo.launch(server_name="0.0.0.0", server_port=7860, share=True)