waleedmohd commited on
Commit
217eb0a
·
verified ·
1 Parent(s): c045b61

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -923
app.py DELETED
@@ -1,923 +0,0 @@
1
- import gradio as gr
2
- import re
3
- 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
- # Import customer service enhancements
16
- try:
17
- from customer_service_enhancements import (
18
- ENHANCED_CUSTOMER_SERVICE_PHRASES_AR,
19
- ENHANCED_CUSTOMER_SERVICE_PHRASES_EN,
20
- BANKING_FAQS_AR,
21
- BANKING_FAQS_EN,
22
- BANKING_GLOSSARY_AR,
23
- BANKING_GLOSSARY_EN,
24
- get_enhanced_response,
25
- handle_banking_faq,
26
- offer_satisfaction_survey,
27
- get_banking_term_definition
28
- )
29
- CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE = True
30
- except ImportError:
31
- CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE = False
32
- # Fallback customer service phrases
33
- ENHANCED_CUSTOMER_SERVICE_PHRASES_AR = {
34
- "greeting": [
35
- "مرحبًا بك في بنك أم درمان الوطني! كيف يمكنني مساعدتك اليوم؟",
36
- "أهلاً بك في خدمة العملاء الافتراضية لبنك أم درمان الوطني. كيف يمكنني خدمتك؟"
37
- ],
38
- "thanks": [
39
- "شكرًا لتواصلك مع بنك أم درمان الوطني!",
40
- "نشكرك على ثقتك في خدماتنا المصرفية."
41
- ],
42
- "follow_up": [
43
- "هل هناك خدمة مصرفية أخرى يمكنني مساعدتك بها اليوم؟",
44
- "هل لديك أي استفسارات أخرى حول منتجاتنا أو خدماتنا المصرفية؟"
45
- ]
46
- }
47
- ENHANCED_CUSTOMER_SERVICE_PHRASES_EN = {
48
- "greeting": [
49
- "Welcome to Omdurman National Bank! How may I assist you today?",
50
- "Hello and welcome to ONB virtual customer service. How can I help you?"
51
- ],
52
- "thanks": [
53
- "Thank you for contacting Omdurman National Bank!",
54
- "We appreciate your trust in our banking services."
55
- ],
56
- "follow_up": [
57
- "Is there any other banking service I can assist you with today?",
58
- "Do you have any other questions about our products or banking services?"
59
- ]
60
- }
61
-
62
- # Omdurman National Bank-specific guidelines in Arabic
63
- ONB_GUIDELINES_AR = {
64
- "balance": "يمكنك التحقق من رصيدك عبر الإنترنت أو عبر تطبيق الهاتف الخاص ببنك أم درمان الوطني. <a href='#' onclick='window.open(\"https://onb.sd/balance\", \"_blank\")'>افحص رصيدك الآن</a>",
65
- "lost_card": "في حالة فقدان البطاقة، اتصل بالرقم <a href='tel:249123456789'>249-123-456-789</a> فورًا أو <a href='#' onclick='window.open(\"https://onb.sd/block-card\", \"_blank\")'>أوقف البطاقة عبر الإنترنت</a>.",
66
- "loan": "شروط القرض تشمل الحد الأدنى للدخل (5000 جنيه سوداني) وتاريخ ائتماني جيد. <a href='#' onclick='window.open(\"https://onb.sd/loans\", \"_blank\")'>تقدم بطلب قرض الآن</a>",
67
- "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>.",
68
- "new_account": "لفتح حساب جديد، قم بزيارة أقرب فرع مع جواز سفرك أو هويتك الوطنية. <a href='#' onclick='window.open(\"https://onb.sd/new-account\", \"_blank\")'>احجز موعدًا الآن</a>",
69
- "interest_rates": "أسعار الفائدة على الودائع تتراوح بين 5% إلى 10% سنويًا. <a href='#' onclick='window.open(\"https://onb.sd/rates\", \"_blank\")'>اطلع على جميع الأسعار</a>",
70
- "branches": "فروعنا موجودة في أم درمان، الخرطوم، وبورتسودان. <a href='#' onclick='window.open(\"https://onb.sd/branches\", \"_blank\")'>اعثر على أقرب فرع</a>",
71
- "working_hours": "ساعات العمل من 8 صباحًا إلى 3 مساءً من الأحد إلى الخميس. <a href='#' onclick='window.open(\"https://onb.sd/hours\", \"_blank\")'>تحقق من ساعات العمل الخاصة</a>",
72
- "contact": "الاتصال بنا على الرقم <a href='tel:249123456789'>249-123-456-789</a> أو عبر البريد الإلكتروني <a href='mailto:[email protected]'>[email protected]</a>. <a href='#' onclick='window.open(\"https://onb.sd/contact\", \"_blank\")'>نموذج الاتصال</a>"
73
- }
74
-
75
- # Omdurman National Bank-specific guidelines in English
76
- ONB_GUIDELINES_EN = {
77
- "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>",
78
- "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>.",
79
- "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>",
80
- "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>.",
81
- "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>",
82
- "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>",
83
- "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>",
84
- "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>",
85
- "contact": "Contact us at <a href='tel:249123456789'>249-123-456-789</a> or via email at <a href='mailto:[email protected]'>[email protected]</a>. <a href='#' onclick='window.open(\"https://onb.sd/contact\", \"_blank\")'>Contact form</a>"
86
- }
87
-
88
- # Quick action buttons in Arabic
89
- QUICK_ACTIONS_AR = [
90
- {"text": "تحقق من الرصيد", "intent": "balance"},
91
- {"text": "الإبلاغ عن بطاقة مفقودة", "intent": "lost_card"},
92
- {"text": "معلومات القرض", "intent": "loan"},
93
- {"text": "تحويل الأموال", "intent": "transfer"},
94
- {"text": "فتح حساب جديد", "intent": "new_account"},
95
- {"text": "أسعار الفائدة", "intent": "interest_rates"},
96
- {"text": "مواقع الفروع", "intent": "branches"},
97
- {"text": "ساعات العمل", "intent": "working_hours"},
98
- {"text": "اتصل بنا", "intent": "contact"}
99
- ]
100
-
101
- # Quick action buttons in English
102
- QUICK_ACTIONS_EN = [
103
- {"text": "Check Balance", "intent": "balance"},
104
- {"text": "Report Lost Card", "intent": "lost_card"},
105
- {"text": "Loan Information", "intent": "loan"},
106
- {"text": "Transfer Funds", "intent": "transfer"},
107
- {"text": "Open New Account", "intent": "new_account"},
108
- {"text": "Interest Rates", "intent": "interest_rates"},
109
- {"text": "Branch Locations", "intent": "branches"},
110
- {"text": "Working Hours", "intent": "working_hours"},
111
- {"text": "Contact Us", "intent": "contact"}
112
- ]
113
-
114
- # Menu options in both languages
115
- MENU_AR = """
116
- قائمة الخدمات المصرفية:
117
- 1. رصيد - استعلام عن رصيد حسابك
118
- 2. بطاقة - الإبلاغ عن بطاقة مفقودة
119
- 3. قرض - معلومات عن القروض
120
- 4. تحويل - تحويل الأموال
121
- 5. حساب - فتح حساب جديد
122
- 6. فائدة - أسعار الفائدة
123
- 7. فرع - مواقع الفروع
124
- 8. ساعات - ساعات العمل
125
- 9. اتصال - معلومات الاتصال
126
- """
127
-
128
- MENU_EN = """
129
- Banking Services Menu:
130
- 1. balance - Check your account balance
131
- 2. card - Report a lost card
132
- 3. loan - Information about loans
133
- 4. transfer - Transfer funds
134
- 5. account - Open a new account
135
- 6. interest - Interest rates
136
- 7. branch - Branch locations
137
- 8. hours - Working hours
138
- 9. contact - Contact information
139
- """
140
-
141
- # Map intents to keywords (enhanced)
142
- INTENT_KEYWORDS = {
143
- "balance": ["balance", "check balance", "account balance", "how much", "رصيد", "حساب", "كم المبلغ", "1"],
144
- "lost_card": ["lost", "card", "stolen", "missing", "فقدت", "بطاقة", "مسروقة", "ضائعة", "2"],
145
- "loan": ["loan", "borrow", "borrowing", "credit", "قرض", "استدانة", "إئتمان", "3"],
146
- "transfer": ["transfer", "send money", "payment", "تحويل", "ارسال", "دفع", "4"],
147
- "new_account": ["account", "open", "create", "new", "حساب", "فتح", "جديد", "إنشاء", "5"],
148
- "interest_rates": ["interest", "rate", "rates", "return", "فائدة", "نسبة", "عائد", "6"],
149
- "branches": ["branch", "location", "where", "office", "فرع", "موقع", "أين", "مكتب", "7"],
150
- "working_hours": ["hours", "time", "open", "close", "ساعات", "وقت", "مفتوح", "مغلق", "8"],
151
- "contact": ["contact", "phone", "email", "call", "اتصال", "هاتف", "بريد", "اتصل", "9"]
152
- }
153
-
154
- # Function to get a random phrase from the customer service phrases
155
- def get_random_phrase(category, language):
156
- import random
157
- if language == "ar":
158
- return random.choice(ENHANCED_CUSTOMER_SERVICE_PHRASES_AR[category])
159
- else:
160
- return random.choice(ENHANCED_CUSTOMER_SERVICE_PHRASES_EN[category])
161
-
162
- def classify_intent(message: str):
163
- # Check for menu request
164
- menu_keywords = ["menu", "options", "help", "قائمة", "خيارات", "مساعدة"]
165
- message_lower = message.lower()
166
-
167
- for keyword in menu_keywords:
168
- if keyword in message_lower:
169
- return "menu"
170
-
171
- # Use keyword matching for intent classification
172
- for intent_key, keywords in INTENT_KEYWORDS.items():
173
- for keyword in keywords:
174
- if keyword.lower() in message_lower:
175
- return intent_key
176
-
177
- return "unknown"
178
-
179
- # Function to log customer interactions
180
- def log_interaction(user_message, bot_response, intent, language):
181
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
182
- log_entry = {
183
- "timestamp": timestamp,
184
- "user_message": user_message,
185
- "bot_response": bot_response,
186
- "intent": intent,
187
- "language": language
188
- }
189
-
190
- try:
191
- with open("interaction_logs.jsonl", "a") as f:
192
- f.write(json.dumps(log_entry) + "\n")
193
- except Exception as e:
194
- print(f"Error logging interaction: {e}")
195
-
196
- def respond(message: str):
197
- if not message.strip():
198
- return {
199
- "ar": "الرجاء كتابة سؤالك.",
200
- "en": "Please type your question."
201
- }
202
-
203
- # Detect language using simple function
204
- language = simple_detect_language(message)
205
-
206
- # Classify the user's intent using keyword matching
207
- intent = classify_intent(message)
208
-
209
- # Prepare responses in both languages
210
- responses = {
211
- "ar": "",
212
- "en": ""
213
- }
214
-
215
- # Special handling for menu request
216
- if intent == "menu":
217
- responses["ar"] = MENU_AR
218
- responses["en"] = MENU_EN
219
- log_interaction(message, responses[language], "menu", language)
220
- return responses
221
-
222
- # Check if it's a banking FAQ
223
- if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
224
- faq_answer = handle_banking_faq(message, language)
225
- if faq_answer:
226
- # Add a greeting phrase at the beginning
227
- greeting_ar = get_random_phrase("greeting", "ar")
228
- greeting_en = get_random_phrase("greeting", "en")
229
-
230
- # Add a follow-up phrase at the end
231
- follow_up_ar = get_random_phrase("follow_up", "ar")
232
- follow_up_en = get_random_phrase("follow_up", "en")
233
-
234
- # Combine all parts
235
- responses["ar"] = f"{greeting_ar}<br><br>{faq_answer}<br><br>{follow_up_ar}"
236
- responses["en"] = f"{greeting_en}<br><br>{faq_answer}<br><br>{follow_up_en}"
237
-
238
- log_interaction(message, responses[language], "faq", language)
239
- return responses
240
-
241
- # Check if it's a banking term definition request
242
- if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
243
- term_definition = get_banking_term_definition(message, language)
244
- if term_definition:
245
- # Add a greeting phrase at the beginning
246
- greeting_ar = get_random_phrase("greeting", "ar")
247
- greeting_en = get_random_phrase("greeting", "en")
248
-
249
- # Add a follow-up phrase at the end
250
- follow_up_ar = get_random_phrase("follow_up", "ar")
251
- follow_up_en = get_random_phrase("follow_up", "en")
252
-
253
- # Combine all parts
254
- responses["ar"] = f"{greeting_ar}<br><br>{term_definition}<br><br>{follow_up_ar}"
255
- responses["en"] = f"{greeting_en}<br><br>{term_definition}<br><br>{follow_up_en}"
256
-
257
- log_interaction(message, responses[language], "term", language)
258
- return responses
259
-
260
- # If intent is recognized, return the corresponding response
261
- if intent != "unknown":
262
- if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
263
- # Use enhanced response if available
264
- responses["ar"] = get_enhanced_response(intent, "ar")
265
- responses["en"] = get_enhanced_response(intent, "en")
266
- else:
267
- # Add a greeting phrase at the beginning
268
- greeting_ar = get_random_phrase("greeting", "ar")
269
- greeting_en = get_random_phrase("greeting", "en")
270
-
271
- # Add the main response
272
- main_response_ar = ONB_GUIDELINES_AR.get(intent, "عذرًا، لم يتم التعرف على الخيار المحدد.")
273
- main_response_en = ONB_GUIDELINES_EN.get(intent, "Sorry, the selected option was not recognized.")
274
-
275
- # Add a follow-up phrase at the end
276
- follow_up_ar = get_random_phrase("follow_up", "ar")
277
- follow_up_en = get_random_phrase("follow_up", "en")
278
-
279
- # Combine all parts
280
- responses["ar"] = f"{greeting_ar}<br><br>{main_response_ar}<br><br>{follow_up_ar}"
281
- responses["en"] = f"{greeting_en}<br><br>{main_response_en}<br><br>{follow_up_en}"
282
- else:
283
- # Default response if no intent is matched - show menu
284
- responses["ar"] = "عذرًا، لم أفهم سؤالك. إليك قائمة بالخدمات المتاحة:" + MENU_AR
285
- responses["en"] = "Sorry, I didn't understand your question. Here's a menu of available services:" + MENU_EN
286
-
287
- # Log the interaction
288
- log_interaction(message, responses[language], intent, language)
289
-
290
- return responses
291
-
292
- # Custom CSS for better UI
293
- custom_css = """
294
- .gradio-container {
295
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
296
- }
297
-
298
- .chat-message {
299
- padding: 1rem;
300
- border-radius: 10px;
301
- margin-bottom: 1rem;
302
- max-width: 80%;
303
- }
304
-
305
- .user-message {
306
- background-color: #e6f7ff;
307
- margin-left: auto;
308
- text-align: right;
309
- }
310
-
311
- .bot-message {
312
- background-color: #f0f0f0;
313
- margin-right: auto;
314
- text-align: left;
315
- }
316
-
317
- .bot-message-ar {
318
- background-color: #f0f0f0;
319
- margin-left: auto;
320
- text-align: right;
321
- }
322
-
323
- .header-section {
324
- background-color: #1a5276;
325
- color: white;
326
- padding: 1rem;
327
- border-radius: 10px;
328
- margin-bottom: 1rem;
329
- text-align: center;
330
- }
331
-
332
- .footer-section {
333
- font-size: 0.8rem;
334
- text-align: center;
335
- margin-top: 2rem;
336
- color: #666;
337
- }
338
-
339
- .lang-selector {
340
- text-align: right;
341
- margin-bottom: 1rem;
342
- }
343
-
344
- .menu-button {
345
- margin-top: 0.5rem;
346
- }
347
-
348
- .quick-actions {
349
- display: flex;
350
- flex-wrap: wrap;
351
- gap: 0.5rem;
352
- margin: 1rem 0;
353
- }
354
-
355
- .quick-action-button {
356
- background-color: #1a5276;
357
- color: white;
358
- border: none;
359
- border-radius: 20px;
360
- padding: 0.5rem 1rem;
361
- cursor: pointer;
362
- font-size: 0.9rem;
363
- transition: background-color 0.3s;
364
- }
365
-
366
- .quick-action-button:hover {
367
- background-color: #2980b9;
368
- }
369
-
370
- .chat-container {
371
- border: 1px solid #ddd;
372
- border-radius: 10px;
373
- padding: 1rem;
374
- background-color: #f9f9f9;
375
- }
376
-
377
- .typing-indicator {
378
- display: inline-block;
379
- width: 50px;
380
- text-align: left;
381
- }
382
-
383
- .typing-indicator span {
384
- display: inline-block;
385
- width: 8px;
386
- height: 8px;
387
- background-color: #1a5276;
388
- border-radius: 50%;
389
- margin-right: 5px;
390
- animation: typing 1s infinite;
391
- }
392
-
393
- .typing-indicator span:nth-child(2) {
394
- animation-delay: 0.2s;
395
- }
396
-
397
- .typing-indicator span:nth-child(3) {
398
- animation-delay: 0.4s;
399
- }
400
-
401
- @keyframes typing {
402
- 0%, 100% {
403
- transform: translateY(0);
404
- }
405
- 50% {
406
- transform: translateY(-5px);
407
- }
408
- }
409
-
410
- .live-agent-button {
411
- background-color: #27ae60;
412
- color: white;
413
- border: none;
414
- border-radius: 5px;
415
- padding: 0.5rem 1rem;
416
- cursor: pointer;
417
- font-size: 0.9rem;
418
- margin-top: 1rem;
419
- transition: background-color 0.3s;
420
- }
421
-
422
- .live-agent-button:hover {
423
- background-color: #2ecc71;
424
- }
425
-
426
- /* Add custom styling for links */
427
- a {
428
- color: #2980b9;
429
- text-decoration: none;
430
- font-weight: bold;
431
- }
432
-
433
- a:hover {
434
- text-decoration: underline;
435
- }
436
-
437
- /* Add styling for action buttons */
438
- .action-button {
439
- display: inline-block;
440
- background-color: #3498db;
441
- color: white;
442
- padding: 0.5rem 1rem;
443
- border-radius: 5px;
444
- margin: 0.5rem 0;
445
- text-decoration: none;
446
- }
447
-
448
- .action-button:hover {
449
- background-color: #2980b9;
450
- text-decoration: none;
451
- }
452
-
453
- /* Styling for satisfaction survey */
454
- .satisfaction-survey {
455
- background-color: #f8f9fa;
456
- border: 1px solid #ddd;
457
- border-radius: 10px;
458
- padding: 1rem;
459
- margin-top: 1rem;
460
- }
461
-
462
- .survey-question {
463
- margin-bottom: 1rem;
464
- }
465
-
466
- .rating-options {
467
- display: flex;
468
- justify-content: space-between;
469
- margin-bottom: 0.5rem;
470
- }
471
-
472
- .survey-submit {
473
- background-color: #1a5276;
474
- color: white;
475
- border: none;
476
- border-radius: 5px;
477
- padding: 0.5rem 1rem;
478
- cursor: pointer;
479
- font-size: 0.9rem;
480
- margin-top: 1rem;
481
- }
482
-
483
- .survey-submit:hover {
484
- background-color: #2980b9;
485
- }
486
- """
487
-
488
- # Custom JavaScript for enhanced functionality
489
- custom_js = """
490
- function simulateTyping(message, elementId, delay = 30) {
491
- const element = document.getElementById(elementId);
492
- if (!element) return;
493
-
494
- element.innerHTML = "";
495
- let i = 0;
496
-
497
- function type() {
498
- if (i < message.length) {
499
- element.innerHTML += message.charAt(i);
500
- i++;
501
- setTimeout(type, delay);
502
- }
503
- }
504
-
505
- type();
506
- }
507
-
508
- // Function to show typing indicator
509
- function showTypingIndicator() {
510
- const chatbox = document.getElementById('chatbox');
511
- if (!chatbox) return;
512
-
513
- const typingIndicator = document.createElement('div');
514
- typingIndicator.className = 'typing-indicator';
515
- typingIndicator.id = 'typing-indicator';
516
- typingIndicator.innerHTML = '<span></span><span></span><span></span>';
517
-
518
- chatbox.appendChild(typingIndicator);
519
- chatbox.scrollTop = chatbox.scrollHeight;
520
- }
521
-
522
- // Function to hide typing indicator
523
- function hideTypingIndicator() {
524
- const typingIndicator = document.getElementById('typing-indicator');
525
- if (typingIndicator) {
526
- typingIndicator.remove();
527
- }
528
- }
529
-
530
- // Function to connect with a live agent
531
- function connectLiveAgent() {
532
- alert('Connecting to a live customer service agent. Please wait a moment...');
533
- // In a real implementation, this would initiate a connection to a live agent system
534
- }
535
-
536
- // Function to show satisfaction survey
537
- function showSatisfactionSurvey(surveyHtml) {
538
- const chatbox = document.getElementById('chatbox');
539
- if (!chatbox) return;
540
-
541
- const surveyDiv = document.createElement('div');
542
- surveyDiv.innerHTML = surveyHtml;
543
-
544
- chatbox.appendChild(surveyDiv);
545
- chatbox.scrollTop = chatbox.scrollHeight;
546
- }
547
-
548
- // Function to submit survey
549
- function submitSurvey() {
550
- const form = document.getElementById('satisfaction-form');
551
- if (!form) return;
552
-
553
- // In a real implementation, this would send the survey data to a server
554
- alert('Thank you for your feedback!');
555
- form.style.display = 'none';
556
- }
557
- """
558
-
559
- # Chat interface with enhanced UI
560
- with gr.Blocks(css=custom_css, js=custom_js) as demo:
561
- # Store conversation history
562
- state = gr.State(value=[])
563
- # Store selected language
564
- selected_lang = gr.State(value="ar")
565
- # Store user name for personalization
566
- user_name = gr.State(value=None)
567
-
568
- with gr.Row(elem_classes="header-section"):
569
- with gr.Column():
570
- gr.Markdown("# Omdurman National Bank | بنك أم درمان الوطني")
571
- gr.Markdown("### Virtual Banking Assistant | المساعد المصرفي الافتراضي")
572
-
573
- with gr.Row():
574
- with gr.Column(elem_classes="lang-selector"):
575
- language_btn = gr.Radio(
576
- ["العربية", "English"],
577
- value="العربية",
578
- label="Language | اللغة"
579
- )
580
-
581
- with gr.Row(elem_classes="chat-container"):
582
- chat_box = gr.HTML(elem_id="chatbox", value="<div style='height: 400px; overflow-y: auto;'></div>")
583
-
584
- # Quick action buttons (will be populated based on language)
585
- with gr.Row(elem_classes="quick-actions", visible=True) as quick_actions_container:
586
- quick_action_buttons = []
587
- for i in range(9): # Create 9 buttons (one for each intent)
588
- button = gr.Button("", visible=False, elem_classes="quick-action-button")
589
- quick_action_buttons.append(button)
590
-
591
- with gr.Row():
592
- with gr.Column(scale=8):
593
- text_input = gr.Textbox(
594
- placeholder="Type your question here | اكتب سؤالك هنا",
595
- label="",
596
- elem_id="chat-input"
597
- )
598
- with gr.Column(scale=1):
599
- submit_btn = gr.Button("Send | إرسال", variant="primary")
600
-
601
- with gr.Row():
602
- with gr.Column(scale=1):
603
- menu_btn = gr.Button("Show Menu | إظهار القائمة", elem_classes="menu-button")
604
- with gr.Column(scale=1):
605
- live_agent_btn = gr.Button("Connect to Live Agent | الاتصال بوكيل حي", elem_classes="live-agent-button")
606
- with gr.Column(scale=1):
607
- survey_btn = gr.Button("Feedback | تقييم الخدمة", elem_classes="menu-button")
608
-
609
- with gr.Row(elem_classes="footer-section"):
610
- gr.Markdown("© 2025 Omdurman National Bank. All Rights Reserved. | جميع الحقوق محفوظة لبنك أم درمان الوطني ٢٠٢٥ ©")
611
-
612
- # Update language state and quick action buttons when language is changed
613
- def update_language_and_buttons(lang):
614
- language_code = "ar" if lang == "العربية" else "en"
615
-
616
- # Get the appropriate quick actions based on language
617
- quick_actions = QUICK_ACTIONS_AR if language_code == "ar" else QUICK_ACTIONS_EN
618
-
619
- # Update button visibility and text
620
- button_updates = []
621
- for i, button in enumerate(quick_action_buttons):
622
- if i < len(quick_actions):
623
- button_updates.append(gr.Button.update(visible=True, value=quick_actions[i]["text"]))
624
- else:
625
- button_updates.append(gr.Button.update(visible=False))
626
-
627
- return [language_code] + button_updates
628
-
629
- # Connect language button to update function
630
- outputs = [selected_lang] + quick_action_buttons
631
- language_btn.change(
632
- fn=update_language_and_buttons,
633
- inputs=language_btn,
634
- outputs=outputs
635
- )
636
-
637
- # Function to add message to chat
638
- def add_message_to_chat(message, is_user, lang):
639
- # Create a JavaScript function to add the message to the chat
640
- alignment = "right" if (is_user or (not is_user and lang == "ar")) else "left"
641
- background = "#e6f7ff" if is_user else "#f0f0f0"
642
-
643
- js_code = f"""
644
- (function() {{
645
- const chatbox = document.getElementById('chatbox').querySelector('div');
646
- const messageDiv = document.createElement('div');
647
- messageDiv.style.padding = '1rem';
648
- messageDiv.style.borderRadius = '10px';
649
- messageDiv.style.marginBottom = '1rem';
650
- messageDiv.style.maxWidth = '80%';
651
- messageDiv.style.backgroundColor = '{background}';
652
- messageDiv.style.marginLeft = '{alignment === "right" ? "auto" : "0"}';
653
- messageDiv.style.marginRight = '{alignment === "left" ? "auto" : "0"}';
654
- messageDiv.style.textAlign = '{alignment}';
655
- messageDiv.innerHTML = `{message}`;
656
- chatbox.appendChild(messageDiv);
657
- chatbox.scrollTop = chatbox.scrollHeight;
658
- }})();
659
- """
660
-
661
- return js_code
662
-
663
- # Handle message submission with typing effect
664
- def on_submit(message, chat_history, lang, name):
665
- if not message.strip():
666
- return "", chat_history, "", name
667
-
668
- # Check if this is a name introduction
669
- name_patterns = [
670
- r"my name is (\w+)",
671
- r"i am (\w+)",
672
- r"i'm (\w+)",
673
- r"اسمي (\w+)",
674
- r"أنا (\w+)"
675
- ]
676
-
677
- for pattern in name_patterns:
678
- match = re.search(pattern, message.lower())
679
- if match:
680
- name = match.group(1)
681
- break
682
-
683
- # Add user message to chat
684
- user_js = add_message_to_chat(message, True, lang)
685
-
686
- # Show typing indicator
687
- typing_js = "showTypingIndicator();"
688
-
689
- # Get response
690
- responses = respond(message)
691
-
692
- # Select response based on language
693
- response = responses[lang]
694
-
695
- # Personalize response if name is available
696
- if name and CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
697
- if lang == "ar":
698
- response = response.replace("مرحبًا", f"مرحبًا {name}")
699
- else:
700
- response = response.replace("Welcome", f"Welcome {name}")
701
- response = response.replace("Hello", f"Hello {name}")
702
-
703
- # Hide typing indicator and add bot response
704
- bot_js = f"""
705
- setTimeout(function() {{
706
- hideTypingIndicator();
707
- {add_message_to_chat(response, False, lang)}
708
- }}, 1000);
709
- """
710
-
711
- # Combine all JavaScript
712
- combined_js = user_js + typing_js + bot_js
713
-
714
- return "", chat_history, combined_js, name
715
-
716
- # Handle menu button click
717
- def show_menu(chat_history, lang):
718
- menu_responses = {
719
- "ar": MENU_AR,
720
- "en": MENU_EN
721
- }
722
-
723
- # Get menu text
724
- menu_text = menu_responses[lang]
725
-
726
- # Add system message showing the menu
727
- js_code = add_message_to_chat(menu_text.replace("\n", "<br>"), False, lang)
728
-
729
- return chat_history, js_code
730
-
731
- # Handle quick action button clicks
732
- def handle_quick_action(button_index, chat_history, lang, name):
733
- # Get the appropriate quick actions based on language
734
- quick_actions = QUICK_ACTIONS_AR if lang == "ar" else QUICK_ACTIONS_EN
735
-
736
- if button_index < len(quick_actions):
737
- # Get the intent for this button
738
- intent = quick_actions[button_index]["intent"]
739
-
740
- # Get the response for this intent
741
- if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
742
- # Use enhanced response if available
743
- response_ar = get_enhanced_response(intent, "ar", name)
744
- response_en = get_enhanced_response(intent, "en", name)
745
- else:
746
- # Add a greeting phrase at the beginning
747
- greeting_ar = get_random_phrase("greeting", "ar")
748
- greeting_en = get_random_phrase("greeting", "en")
749
-
750
- # Add the main response
751
- main_response_ar = ONB_GUIDELINES_AR.get(intent, "")
752
- main_response_en = ONB_GUIDELINES_EN.get(intent, "")
753
-
754
- # Add a follow-up phrase at the end
755
- follow_up_ar = get_random_phrase("follow_up", "ar")
756
- follow_up_en = get_random_phrase("follow_up", "en")
757
-
758
- # Combine all parts
759
- response_ar = f"{greeting_ar}<br><br>{main_response_ar}<br><br>{follow_up_ar}"
760
- response_en = f"{greeting_en}<br><br>{main_response_en}<br><br>{follow_up_en}"
761
-
762
- responses = {
763
- "ar": response_ar,
764
- "en": response_en
765
- }
766
-
767
- # Select response based on language
768
- response = responses[lang]
769
-
770
- # Personalize response if name is available
771
- if name:
772
- if lang == "ar":
773
- response = response.replace("مرحبًا", f"مرحبًا {name}")
774
- else:
775
- response = response.replace("Welcome", f"Welcome {name}")
776
- response = response.replace("Hello", f"Hello {name}")
777
-
778
- # Add button text as user message
779
- button_text = quick_actions[button_index]["text"]
780
- user_js = add_message_to_chat(button_text, True, lang)
781
-
782
- # Show typing indicator
783
- typing_js = "showTypingIndicator();"
784
-
785
- # Hide typing indicator and add bot response
786
- bot_js = f"""
787
- setTimeout(function() {{
788
- hideTypingIndicator();
789
- {add_message_to_chat(response, False, lang)}
790
- }}, 1000);
791
- """
792
-
793
- # Combine all JavaScript
794
- combined_js = user_js + typing_js + bot_js
795
-
796
- # Log the interaction
797
- log_interaction(button_text, response, intent, lang)
798
-
799
- return chat_history, combined_js
800
-
801
- return chat_history, ""
802
-
803
- # Handle live agent button click
804
- def connect_to_live_agent():
805
- return "connectLiveAgent();"
806
-
807
- # Handle satisfaction survey button click
808
- def show_satisfaction_survey(lang):
809
- if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
810
- survey_html = offer_satisfaction_survey(lang)
811
- return f"showSatisfactionSurvey(`{survey_html}`);"
812
- else:
813
- # Simple survey HTML if enhancements not available
814
- title = "استطلاع رضا العملاء" if lang == "ar" else "Customer Satisfaction Survey"
815
- intro = "نقدر ملاحظاتك!" if lang == "ar" else "We value your feedback!"
816
- submit = "إرسال" if lang == "ar" else "Submit"
817
-
818
- survey_html = f"""
819
- <div class="satisfaction-survey" dir="{('rtl' if lang == 'ar' else 'ltr')}">
820
- <h3>{title}</h3>
821
- <p>{intro}</p>
822
- <button onclick="submitSurvey()" class="survey-submit">{submit}</button>
823
- </div>
824
- """
825
-
826
- return f"showSatisfactionSurvey(`{survey_html}`);"
827
-
828
- # Link inputs and button to response function
829
- submit_btn.click(
830
- fn=on_submit,
831
- inputs=[text_input, state, selected_lang, user_name],
832
- outputs=[text_input, state, chat_box, user_name]
833
- )
834
-
835
- # Link menu button to show menu function
836
- menu_btn.click(
837
- fn=show_menu,
838
- inputs=[state, selected_lang],
839
- outputs=[state, chat_box]
840
- )
841
-
842
- # Link live agent button to connect function
843
- live_agent_btn.click(
844
- fn=connect_to_live_agent,
845
- inputs=[],
846
- outputs=[chat_box]
847
- )
848
-
849
- # Link survey button to show survey function
850
- survey_btn.click(
851
- fn=show_satisfaction_survey,
852
- inputs=[selected_lang],
853
- outputs=[chat_box]
854
- )
855
-
856
- # Link quick action buttons to handler function
857
- for i, button in enumerate(quick_action_buttons):
858
- button.click(
859
- fn=lambda idx=i, s=state, l=selected_lang, n=user_name: handle_quick_action(idx, s, l, n),
860
- inputs=[state, selected_lang, user_name],
861
- outputs=[state, chat_box]
862
- )
863
-
864
- # Also trigger on Enter key
865
- text_input.submit(
866
- fn=on_submit,
867
- inputs=[text_input, state, selected_lang, user_name],
868
- outputs=[text_input, state, chat_box, user_name]
869
- )
870
-
871
- # Initialize the chat with a welcome message
872
- def init_chat(lang):
873
- # Get welcome message based on language
874
- welcome_ar = """
875
- <div style='text-align: center; margin-bottom: 20px;'>
876
- <img src='https://via.placeholder.com/150?text=ONB+Logo' alt='ONB Logo' style='max-width: 150px;'>
877
- <h3>مرحبًا بك في المساعد المصرفي الافتراضي لبنك أم درمان الوطني!</h3>
878
- <p>يمكنك طرح أي سؤال حول خدماتنا المصرفية أو استخدام أزرار الإجراءات السريعة أدناه.</p>
879
- </div>
880
- """
881
-
882
- welcome_en = """
883
- <div style='text-align: center; margin-bottom: 20px;'>
884
- <img src='https://via.placeholder.com/150?text=ONB+Logo' alt='ONB Logo' style='max-width: 150px;'>
885
- <h3>Welcome to Omdurman National Bank Virtual Banking Assistant!</h3>
886
- <p>You can ask any question about our banking services or use the quick action buttons below.</p>
887
- </div>
888
- """
889
-
890
- welcome_message = welcome_ar if lang == "ar" else welcome_en
891
-
892
- # Add welcome message to chat
893
- js_code = f"""
894
- (function() {{
895
- const chatbox = document.getElementById('chatbox').querySelector('div');
896
- chatbox.innerHTML = `{welcome_message}`;
897
- }})();
898
- """
899
-
900
- # Update quick action buttons
901
- quick_actions = QUICK_ACTIONS_AR if lang == "ar" else QUICK_ACTIONS_EN
902
- button_updates = []
903
- for i, button in enumerate(quick_action_buttons):
904
- if i < len(quick_actions):
905
- button_updates.append(gr.Button.update(visible=True, value=quick_actions[i]["text"]))
906
- else:
907
- button_updates.append(gr.Button.update(visible=False))
908
-
909
- return [js_code] + button_updates
910
-
911
- # Initialize the chat when the app starts
912
- demo.load(
913
- fn=lambda: init_chat("ar"),
914
- inputs=[],
915
- outputs=[chat_box] + quick_action_buttons
916
- )
917
-
918
- if __name__ == "__main__":
919
- demo.launch(
920
- server_name="0.0.0.0",
921
- server_port=7860,
922
- share=True # Enable public link
923
- )