File size: 35,418 Bytes
7d0b36f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
import gradio as gr
import re
import json
import time
from datetime import datetime

# Simple language detection function instead of using transformers
def simple_detect_language(text):
    # Check for Arabic characters
    arabic_pattern = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF]+')
    if arabic_pattern.search(text):
        return "ar"
    return "en"

# Import customer service enhancements
try:
    from customer_service_enhancements import (
        ENHANCED_CUSTOMER_SERVICE_PHRASES_AR,
        ENHANCED_CUSTOMER_SERVICE_PHRASES_EN,
        BANKING_FAQS_AR,
        BANKING_FAQS_EN,
        BANKING_GLOSSARY_AR,
        BANKING_GLOSSARY_EN,
        get_enhanced_response,
        handle_banking_faq,
        offer_satisfaction_survey,
        get_banking_term_definition
    )
    CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE = True
except ImportError:
    CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE = False
    # Fallback customer service phrases
    ENHANCED_CUSTOMER_SERVICE_PHRASES_AR = {
        "greeting": [
            "مرحبًا بك في بنك أم درمان الوطني! كيف يمكنني مساعدتك اليوم؟",
            "أهلاً بك في خدمة العملاء الافتراضية لبنك أم درمان الوطني. كيف يمكنني خدمتك؟"
        ],
        "thanks": [
            "شكرًا لتواصلك مع بنك أم درمان الوطني!",
            "نشكرك على ثقتك في خدماتنا المصرفية."
        ],
        "follow_up": [
            "هل هناك خدمة مصرفية أخرى يمكنني مساعدتك بها اليوم؟",
            "هل لديك أي استفسارات أخرى حول منتجاتنا أو خدماتنا المصرفية؟"
        ]
    }
    ENHANCED_CUSTOMER_SERVICE_PHRASES_EN = {
        "greeting": [
            "Welcome to Omdurman National Bank! How may I assist you today?",
            "Hello and welcome to ONB virtual customer service. How can I help you?"
        ],
        "thanks": [
            "Thank you for contacting Omdurman National Bank!",
            "We appreciate your trust in our banking services."
        ],
        "follow_up": [
            "Is there any other banking service I can assist you with today?",
            "Do you have any other questions about our products or banking services?"
        ]
    }

# Omdurman National Bank-specific guidelines in Arabic
ONB_GUIDELINES_AR = {
    "balance": "يمكنك التحقق من رصيدك عبر الإنترنت أو عبر تطبيق الهاتف الخاص ببنك أم درمان الوطني. <a href='#' onclick='window.open(\"https://onb.sd/balance\", \"_blank\")'>افحص رصيدك الآن</a>",
    "lost_card": "في حالة فقدان البطاقة، اتصل بالرقم <a href='tel:249123456789'>249-123-456-789</a> فورًا أو <a href='#' onclick='window.open(\"https://onb.sd/block-card\", \"_blank\")'>أوقف البطاقة عبر الإنترنت</a>.",
    "loan": "شروط القرض تشمل الحد الأدنى للدخل (5000 جنيه سوداني) وتاريخ ائتماني جيد. <a href='#' onclick='window.open(\"https://onb.sd/loans\", \"_blank\")'>تقدم بطلب قرض الآن</a>",
    "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>.",
    "new_account": "لفتح حساب جديد، قم بزيارة أقرب فرع مع جواز سفرك أو هويتك الوطنية. <a href='#' onclick='window.open(\"https://onb.sd/new-account\", \"_blank\")'>احجز موعدًا الآن</a>",
    "interest_rates": "أسعار الفائدة على الودائع تتراوح بين 5% إلى 10% سنويًا. <a href='#' onclick='window.open(\"https://onb.sd/rates\", \"_blank\")'>اطلع على جميع الأسعار</a>",
    "branches": "فروعنا موجودة في أم درمان، الخرطوم، وبورتسودان. <a href='#' onclick='window.open(\"https://onb.sd/branches\", \"_blank\")'>اعثر على أقرب فرع</a>",
    "working_hours": "ساعات العمل من 8 صباحًا إلى 3 مساءً من الأحد إلى الخميس. <a href='#' onclick='window.open(\"https://onb.sd/hours\", \"_blank\")'>تحقق من ساعات العمل الخاصة</a>",
    "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>"
}

# Omdurman National Bank-specific guidelines in English
ONB_GUIDELINES_EN = {
    "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>",
    "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>.",
    "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>",
    "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>.",
    "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>",
    "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>",
    "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>",
    "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>",
    "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>"
}

# Quick action buttons in Arabic
QUICK_ACTIONS_AR = [
    {"text": "تحقق من الرصيد", "intent": "balance"},
    {"text": "الإبلاغ عن بطاقة مفقودة", "intent": "lost_card"},
    {"text": "معلومات القرض", "intent": "loan"},
    {"text": "تحويل الأموال", "intent": "transfer"},
    {"text": "فتح حساب جديد", "intent": "new_account"},
    {"text": "أسعار الفائدة", "intent": "interest_rates"},
    {"text": "مواقع الفروع", "intent": "branches"},
    {"text": "ساعات العمل", "intent": "working_hours"},
    {"text": "اتصل بنا", "intent": "contact"}
]

# Quick action buttons in English
QUICK_ACTIONS_EN = [
    {"text": "Check Balance", "intent": "balance"},
    {"text": "Report Lost Card", "intent": "lost_card"},
    {"text": "Loan Information", "intent": "loan"},
    {"text": "Transfer Funds", "intent": "transfer"},
    {"text": "Open New Account", "intent": "new_account"},
    {"text": "Interest Rates", "intent": "interest_rates"},
    {"text": "Branch Locations", "intent": "branches"},
    {"text": "Working Hours", "intent": "working_hours"},
    {"text": "Contact Us", "intent": "contact"}
]

# Menu options in both languages
MENU_AR = """
قائمة الخدمات المصرفية:
1. رصيد - استعلام عن رصيد حسابك
2. بطاقة - الإبلاغ عن بطاقة مفقودة
3. قرض - معلومات عن القروض
4. تحويل - تحويل الأموال
5. حساب - فتح حساب جديد
6. فائدة - أسعار الفائدة
7. فرع - مواقع الفروع
8. ساعات - ساعات العمل
9. اتصال - معلومات الاتصال
"""

MENU_EN = """
Banking Services Menu:
1. balance - Check your account balance
2. card - Report a lost card
3. loan - Information about loans
4. transfer - Transfer funds
5. account - Open a new account
6. interest - Interest rates
7. branch - Branch locations
8. hours - Working hours
9. contact - Contact information
"""

# Map intents to keywords (enhanced)
INTENT_KEYWORDS = {
    "balance": ["balance", "check balance", "account balance", "how much", "رصيد", "حساب", "كم المبلغ", "1"],
    "lost_card": ["lost", "card", "stolen", "missing", "فقدت", "بطاقة", "مسروقة", "ضائعة", "2"],
    "loan": ["loan", "borrow", "borrowing", "credit", "قرض", "استدانة", "إئتمان", "3"],
    "transfer": ["transfer", "send money", "payment", "تحويل", "ارسال", "دفع", "4"],
    "new_account": ["account", "open", "create", "new", "حساب", "فتح", "جديد", "إنشاء", "5"],
    "interest_rates": ["interest", "rate", "rates", "return", "فائدة", "نسبة", "عائد", "6"],
    "branches": ["branch", "location", "where", "office", "فرع", "موقع", "أين", "مكتب", "7"],
    "working_hours": ["hours", "time", "open", "close", "ساعات", "وقت", "مفتوح", "مغلق", "8"],
    "contact": ["contact", "phone", "email", "call", "اتصال", "هاتف", "بريد", "اتصل", "9"]
}

# Function to get a random phrase from the customer service phrases
def get_random_phrase(category, language):
    import random
    if language == "ar":
        return random.choice(ENHANCED_CUSTOMER_SERVICE_PHRASES_AR[category])
    else:
        return random.choice(ENHANCED_CUSTOMER_SERVICE_PHRASES_EN[category])

def classify_intent(message: str):
    # Check for menu request
    menu_keywords = ["menu", "options", "help", "قائمة", "خيارات", "مساعدة"]
    message_lower = message.lower()
    
    for keyword in menu_keywords:
        if keyword in message_lower:
            return "menu"
    
    # Use keyword matching for intent classification
    for intent_key, keywords in INTENT_KEYWORDS.items():
        for keyword in keywords:
            if keyword.lower() in message_lower:
                return intent_key
                
    return "unknown"

# Function to log customer interactions
def log_interaction(user_message, bot_response, intent, language):
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    log_entry = {
        "timestamp": timestamp,
        "user_message": user_message,
        "bot_response": bot_response,
        "intent": intent,
        "language": language
    }
    
    try:
        with open("/home/ubuntu/banking_chatbot/interaction_logs.jsonl", "a") as f:
            f.write(json.dumps(log_entry) + "\n")
    except Exception as e:
        print(f"Error logging interaction: {e}")

def respond(message: str):
    if not message.strip():
        return {
            "ar": "الرجاء كتابة سؤالك.",
            "en": "Please type your question."
        }
    
    # Detect language using simple function
    language = simple_detect_language(message)
    
    # Classify the user's intent using keyword matching
    intent = classify_intent(message)
    
    # Prepare responses in both languages
    responses = {
        "ar": "",
        "en": ""
    }
    
    # Special handling for menu request
    if intent == "menu":
        responses["ar"] = MENU_AR
        responses["en"] = MENU_EN
        log_interaction(message, responses[language], "menu", language)
        return responses
    
    # Check if it's a banking FAQ
    if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
        faq_answer = handle_banking_faq(message, language)
        if faq_answer:
            # Add a greeting phrase at the beginning
            greeting_ar = get_random_phrase("greeting", "ar")
            greeting_en = get_random_phrase("greeting", "en")
            
            # Add a follow-up phrase at the end
            follow_up_ar = get_random_phrase("follow_up", "ar")
            follow_up_en = get_random_phrase("follow_up", "en")
            
            # Combine all parts
            responses["ar"] = f"{greeting_ar}<br><br>{faq_answer}<br><br>{follow_up_ar}"
            responses["en"] = f"{greeting_en}<br><br>{faq_answer}<br><br>{follow_up_en}"
            
            log_interaction(message, responses[language], "faq", language)
            return responses
    
    # Check if it's a banking term definition request
    if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
        term_definition = get_banking_term_definition(message, language)
        if term_definition:
            # Add a greeting phrase at the beginning
            greeting_ar = get_random_phrase("greeting", "ar")
            greeting_en = get_random_phrase("greeting", "en")
            
            # Add a follow-up phrase at the end
            follow_up_ar = get_random_phrase("follow_up", "ar")
            follow_up_en = get_random_phrase("follow_up", "en")
            
            # Combine all parts
            responses["ar"] = f"{greeting_ar}<br><br>{term_definition}<br><br>{follow_up_ar}"
            responses["en"] = f"{greeting_en}<br><br>{term_definition}<br><br>{follow_up_en}"
            
            log_interaction(message, responses[language], "term", language)
            return responses
    
    # If intent is recognized, return the corresponding response
    if intent != "unknown":
        if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
            # Use enhanced response if available
            responses["ar"] = get_enhanced_response(intent, "ar")
            responses["en"] = get_enhanced_response(intent, "en")
        else:
            # Add a greeting phrase at the beginning
            greeting_ar = get_random_phrase("greeting", "ar")
            greeting_en = get_random_phrase("greeting", "en")
            
            # Add the main response
            main_response_ar = ONB_GUIDELINES_AR.get(intent, "عذرًا، لم يتم التعرف على الخيار المحدد.")
            main_response_en = ONB_GUIDELINES_EN.get(intent, "Sorry, the selected option was not recognized.")
            
            # Add a follow-up phrase at the end
            follow_up_ar = get_random_phrase("follow_up", "ar")
            follow_up_en = get_random_phrase("follow_up", "en")
            
            # Combine all parts
            responses["ar"] = f"{greeting_ar}<br><br>{main_response_ar}<br><br>{follow_up_ar}"
            responses["en"] = f"{greeting_en}<br><br>{main_response_en}<br><br>{follow_up_en}"
    else:
        # Default response if no intent is matched - show menu
        responses["ar"] = "عذرًا، لم أفهم سؤالك. إليك قائمة بالخدمات المتاحة:" + MENU_AR
        responses["en"] = "Sorry, I didn't understand your question. Here's a menu of available services:" + MENU_EN
    
    # Log the interaction
    log_interaction(message, responses[language], intent, language)
    
    return responses

# Custom CSS for better UI
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;
}

.menu-button {
    margin-top: 0.5rem;
}

.quick-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 1rem 0;
}

.quick-action-button {
    background-color: #1a5276;
    color: white;
    border: none;
    border-radius: 20px;
    padding: 0.5rem 1rem;
    cursor: pointer;
    font-size: 0.9rem;
    transition: background-color 0.3s;
}

.quick-action-button:hover {
    background-color: #2980b9;
}

.chat-container {
    border: 1px solid #ddd;
    border-radius: 10px;
    padding: 1rem;
    background-color: #f9f9f9;
}

.typing-indicator {
    display: inline-block;
    width: 50px;
    text-align: left;
}

.typing-indicator span {
    display: inline-block;
    width: 8px;
    height: 8px;
    background-color: #1a5276;
    border-radius: 50%;
    margin-right: 5px;
    animation: typing 1s infinite;
}

.typing-indicator span:nth-child(2) {
    animation-delay: 0.2s;
}

.typing-indicator span:nth-child(3) {
    animation-delay: 0.4s;
}

@keyframes typing {
    0%, 100% {
        transform: translateY(0);
    }
    50% {
        transform: translateY(-5px);
    }
}

.live-agent-button {
    background-color: #27ae60;
    color: white;
    border: none;
    border-radius: 5px;
    padding: 0.5rem 1rem;
    cursor: pointer;
    font-size: 0.9rem;
    margin-top: 1rem;
    transition: background-color 0.3s;
}

.live-agent-button:hover {
    background-color: #2ecc71;
}

/* Add custom styling for links */
a {
    color: #2980b9;
    text-decoration: none;
    font-weight: bold;
}

a:hover {
    text-decoration: underline;
}

/* Add styling for action buttons */
.action-button {
    display: inline-block;
    background-color: #3498db;
    color: white;
    padding: 0.5rem 1rem;
    border-radius: 5px;
    margin: 0.5rem 0;
    text-decoration: none;
}

.action-button:hover {
    background-color: #2980b9;
    text-decoration: none;
}

/* Styling for satisfaction survey */
.satisfaction-survey {
    background-color: #f8f9fa;
    border: 1px solid #ddd;
    border-radius: 10px;
    padding: 1rem;
    margin-top: 1rem;
}

.survey-question {
    margin-bottom: 1rem;
}

.rating-options {
    display: flex;
    justify-content: space-between;
    margin-bottom: 0.5rem;
}

.survey-submit {
    background-color: #1a5276;
    color: white;
    border: none;
    border-radius: 5px;
    padding: 0.5rem 1rem;
    cursor: pointer;
    font-size: 0.9rem;
    margin-top: 1rem;
}

.survey-submit:hover {
    background-color: #2980b9;
}
"""

# Custom JavaScript for enhanced functionality
custom_js = """
function simulateTyping(message, elementId, delay = 30) {
    const element = document.getElementById(elementId);
    if (!element) return;
    
    element.innerHTML = "";
    let i = 0;
    
    function type() {
        if (i < message.length) {
            element.innerHTML += message.charAt(i);
            i++;
            setTimeout(type, delay);
        }
    }
    
    type();
}

// Function to show typing indicator
function showTypingIndicator() {
    const chatbox = document.getElementById('chatbox');
    if (!chatbox) return;
    
    const typingIndicator = document.createElement('div');
    typingIndicator.className = 'typing-indicator';
    typingIndicator.id = 'typing-indicator';
    typingIndicator.innerHTML = '<span></span><span></span><span></span>';
    
    chatbox.appendChild(typingIndicator);
    chatbox.scrollTop = chatbox.scrollHeight;
}

// Function to hide typing indicator
function hideTypingIndicator() {
    const typingIndicator = document.getElementById('typing-indicator');
    if (typingIndicator) {
        typingIndicator.remove();
    }
}

// Function to connect with a live agent
function connectLiveAgent() {
    alert('Connecting to a live customer service agent. Please wait a moment...');
    // In a real implementation, this would initiate a connection to a live agent system
}

// Function to show satisfaction survey
function showSatisfactionSurvey(surveyHtml) {
    const chatbox = document.getElementById('chatbox');
    if (!chatbox) return;
    
    const surveyDiv = document.createElement('div');
    surveyDiv.innerHTML = surveyHtml;
    
    chatbox.appendChild(surveyDiv);
    chatbox.scrollTop = chatbox.scrollHeight;
}

// Function to submit survey
function submitSurvey() {
    const form = document.getElementById('satisfaction-form');
    if (!form) return;
    
    // In a real implementation, this would send the survey data to a server
    alert('Thank you for your feedback!');
    form.style.display = 'none';
}
"""

# Chat interface with enhanced UI
with gr.Blocks(css=custom_css, js=custom_js) as demo:
    # Store conversation history
    state = gr.State(value=[])
    # Store selected language
    selected_lang = gr.State(value="ar")
    # Store user name for personalization
    user_name = gr.State(value=None)
    
    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(elem_classes="chat-container"):
        chat_box = gr.HTML(elem_id="chatbox", value="<div style='height: 400px; overflow-y: auto;'></div>")
    
    # Quick action buttons (will be populated based on language)
    with gr.Row(elem_classes="quick-actions", visible=True) as quick_actions_container:
        quick_action_buttons = []
        for i in range(9):  # Create 9 buttons (one for each intent)
            button = gr.Button("", visible=False, elem_classes="quick-action-button")
            quick_action_buttons.append(button)
    
    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():
        with gr.Column(scale=1):
            menu_btn = gr.Button("Show Menu | إظهار القائمة", elem_classes="menu-button")
        with gr.Column(scale=1):
            live_agent_btn = gr.Button("Connect to Live Agent | الاتصال بوكيل حي", elem_classes="live-agent-button")
        with gr.Column(scale=1):
            survey_btn = gr.Button("Feedback | تقييم الخدمة", elem_classes="menu-button")
    
    with gr.Row(elem_classes="footer-section"):
        gr.Markdown("© 2025 Omdurman National Bank. All Rights Reserved. | جميع الحقوق محفوظة لبنك أم درمان الوطني ٢٠٢٥ ©")
    
    # Update language state and quick action buttons when language is changed
    def update_language_and_buttons(lang):
        language_code = "ar" if lang == "العربية" else "en"
        
        # Get the appropriate quick actions based on language
        quick_actions = QUICK_ACTIONS_AR if language_code == "ar" else QUICK_ACTIONS_EN
        
        # Update button visibility and text
        button_updates = []
        for i, button in enumerate(quick_action_buttons):
            if i < len(quick_actions):
                button_updates.append(gr.Button.update(visible=True, value=quick_actions[i]["text"]))
            else:
                button_updates.append(gr.Button.update(visible=False))
        
        return [language_code] + button_updates
    
    # Connect language button to update function
    outputs = [selected_lang] + quick_action_buttons
    language_btn.change(
        fn=update_language_and_buttons,
        inputs=language_btn,
        outputs=outputs
    )
    
    # Function to add message to chat
    def add_message_to_chat(message, is_user, lang):
        # Create a JavaScript function to add the message to the chat
        alignment = "right" if (is_user or (not is_user and lang == "ar")) else "left"
        background = "#e6f7ff" if is_user else "#f0f0f0"
        
        js_code = f"""
        (function() {{
            const chatbox = document.getElementById('chatbox').querySelector('div');
            const messageDiv = document.createElement('div');
            messageDiv.style.padding = '1rem';
            messageDiv.style.borderRadius = '10px';
            messageDiv.style.marginBottom = '1rem';
            messageDiv.style.maxWidth = '80%';
            messageDiv.style.backgroundColor = '{background}';
            messageDiv.style.marginLeft = '{alignment === "right" ? "auto" : "0"}';
            messageDiv.style.marginRight = '{alignment === "left" ? "auto" : "0"}';
            messageDiv.style.textAlign = '{alignment}';
            messageDiv.innerHTML = `{message}`;
            chatbox.appendChild(messageDiv);
            chatbox.scrollTop = chatbox.scrollHeight;
        }})();
        """
        
        return js_code
    
    # Handle message submission with typing effect
    def on_submit(message, chat_history, lang, name):
        if not message.strip():
            return "", chat_history, "", name
        
        # Check if this is a name introduction
        name_patterns = [
            r"my name is (\w+)",
            r"i am (\w+)",
            r"i'm (\w+)",
            r"اسمي (\w+)",
            r"أنا (\w+)"
        ]
        
        for pattern in name_patterns:
            match = re.search(pattern, message.lower())
            if match:
                name = match.group(1)
                break
        
        # Add user message to chat
        user_js = add_message_to_chat(message, True, lang)
        
        # Show typing indicator
        typing_js = "showTypingIndicator();"
        
        # Get response
        responses = respond(message)
        
        # Select response based on language
        response = responses[lang]
        
        # Personalize response if name is available
        if name and CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
            if lang == "ar":
                response = response.replace("مرحبًا", f"مرحبًا {name}")
            else:
                response = response.replace("Welcome", f"Welcome {name}")
                response = response.replace("Hello", f"Hello {name}")
        
        # Hide typing indicator and add bot response
        bot_js = f"""
        setTimeout(function() {{
            hideTypingIndicator();
            {add_message_to_chat(response, False, lang)}
        }}, 1000);
        """
        
        # Combine all JavaScript
        combined_js = user_js + typing_js + bot_js
        
        return "", chat_history, combined_js, name
    
    # Handle menu button click
    def show_menu(chat_history, lang):
        menu_responses = {
            "ar": MENU_AR,
            "en": MENU_EN
        }
        
        # Get menu text
        menu_text = menu_responses[lang]
        
        # Add system message showing the menu
        js_code = add_message_to_chat(menu_text.replace("\n", "<br>"), False, lang)
        
        return chat_history, js_code
    
    # Handle quick action button clicks
    def handle_quick_action(button_index, chat_history, lang, name):
        # Get the appropriate quick actions based on language
        quick_actions = QUICK_ACTIONS_AR if lang == "ar" else QUICK_ACTIONS_EN
        
        if button_index < len(quick_actions):
            # Get the intent for this button
            intent = quick_actions[button_index]["intent"]
            
            # Get the response for this intent
            if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
                # Use enhanced response if available
                response_ar = get_enhanced_response(intent, "ar", name)
                response_en = get_enhanced_response(intent, "en", name)
            else:
                # Add a greeting phrase at the beginning
                greeting_ar = get_random_phrase("greeting", "ar")
                greeting_en = get_random_phrase("greeting", "en")
                
                # Add the main response
                main_response_ar = ONB_GUIDELINES_AR.get(intent, "")
                main_response_en = ONB_GUIDELINES_EN.get(intent, "")
                
                # Add a follow-up phrase at the end
                follow_up_ar = get_random_phrase("follow_up", "ar")
                follow_up_en = get_random_phrase("follow_up", "en")
                
                # Combine all parts
                response_ar = f"{greeting_ar}<br><br>{main_response_ar}<br><br>{follow_up_ar}"
                response_en = f"{greeting_en}<br><br>{main_response_en}<br><br>{follow_up_en}"
            
            responses = {
                "ar": response_ar,
                "en": response_en
            }
            
            # Select response based on language
            response = responses[lang]
            
            # Personalize response if name is available
            if name:
                if lang == "ar":
                    response = response.replace("مرحبًا", f"مرحبًا {name}")
                else:
                    response = response.replace("Welcome", f"Welcome {name}")
                    response = response.replace("Hello", f"Hello {name}")
            
            # Add button text as user message
            button_text = quick_actions[button_index]["text"]
            user_js = add_message_to_chat(button_text, True, lang)
            
            # Show typing indicator
            typing_js = "showTypingIndicator();"
            
            # Hide typing indicator and add bot response
            bot_js = f"""
            setTimeout(function() {{
                hideTypingIndicator();
                {add_message_to_chat(response, False, lang)}
            }}, 1000);
            """
            
            # Combine all JavaScript
            combined_js = user_js + typing_js + bot_js
            
            # Log the interaction
            log_interaction(button_text, response, intent, lang)
            
            return chat_history, combined_js
        
        return chat_history, ""
    
    # Handle live agent button click
    def connect_to_live_agent():
        return "connectLiveAgent();"
    
    # Handle satisfaction survey button click
    def show_satisfaction_survey(lang):
        if CUSTOMER_SERVICE_ENHANCEMENTS_AVAILABLE:
            survey_html = offer_satisfaction_survey(lang)
            return f"showSatisfactionSurvey(`{survey_html}`);"
        else:
            # Simple survey HTML if enhancements not available
            title = "استطلاع رضا العملاء" if lang == "ar" else "Customer Satisfaction Survey"
            intro = "نقدر ملاحظاتك!" if lang == "ar" else "We value your feedback!"
            submit = "إرسال" if lang == "ar" else "Submit"
            
            survey_html = f"""
            <div class="satisfaction-survey" dir="{('rtl' if lang == 'ar' else 'ltr')}">
                <h3>{title}</h3>
                <p>{intro}</p>
                <button onclick="submitSurvey()" class="survey-submit">{submit}</button>
            </div>
            """
            
            return f"showSatisfactionSurvey(`{survey_html}`);"
    
    # Link inputs and button to response function
    submit_btn.click(
        fn=on_submit,
        inputs=[text_input, state, selected_lang, user_name],
        outputs=[text_input, state, chat_box, user_name]
    )
    
    # Link menu button to show menu function
    menu_btn.click(
        fn=show_menu,
        inputs=[state, selected_lang],
        outputs=[state, chat_box]
    )
    
    # Link live agent button to connect function
    live_agent_btn.click(
        fn=connect_to_live_agent,
        inputs=[],
        outputs=[chat_box]
    )
    
    # Link survey button to show survey function
    survey_btn.click(
        fn=show_satisfaction_survey,
        inputs=[selected_lang],
        outputs=[chat_box]
    )
    
    # Link quick action buttons to handler function
    for i, button in enumerate(quick_action_buttons):
        button.click(
            fn=lambda idx=i, s=state, l=selected_lang, n=user_name: handle_quick_action(idx, s, l, n),
            inputs=[state, selected_lang, user_name],
            outputs=[state, chat_box]
        )
    
    # Also trigger on Enter key
    text_input.submit(
        fn=on_submit,
        inputs=[text_input, state, selected_lang, user_name],
        outputs=[text_input, state, chat_box, user_name]
    )
    
    # Initialize the chat with a welcome message
    def init_chat(lang):
        # Get welcome message based on language
        welcome_ar = """
        <div style='text-align: center; margin-bottom: 20px;'>
            <img src='https://via.placeholder.com/150?text=ONB+Logo' alt='ONB Logo' style='max-width: 150px;'>
            <h3>مرحبًا بك في المساعد المصرفي الافتراضي لبنك أم درمان الوطني!</h3>
            <p>يمكنك طرح أي سؤال حول خدماتنا المصرفية أو استخدام أزرار الإجراءات السريعة أدناه.</p>
        </div>
        """
        
        welcome_en = """
        <div style='text-align: center; margin-bottom: 20px;'>
            <img src='https://via.placeholder.com/150?text=ONB+Logo' alt='ONB Logo' style='max-width: 150px;'>
            <h3>Welcome to Omdurman National Bank Virtual Banking Assistant!</h3>
            <p>You can ask any question about our banking services or use the quick action buttons below.</p>
        </div>
        """
        
        welcome_message = welcome_ar if lang == "ar" else welcome_en
        
        # Add welcome message to chat
        js_code = f"""
        (function() {{
            const chatbox = document.getElementById('chatbox').querySelector('div');
            chatbox.innerHTML = `{welcome_message}`;
        }})();
        """
        
        # Update quick action buttons
        quick_actions = QUICK_ACTIONS_AR if lang == "ar" else QUICK_ACTIONS_EN
        button_updates = []
        for i, button in enumerate(quick_action_buttons):
            if i < len(quick_actions):
                button_updates.append(gr.Button.update(visible=True, value=quick_actions[i]["text"]))
            else:
                button_updates.append(gr.Button.update(visible=False))
        
        return [js_code] + button_updates
    
    # Initialize the chat when the app starts
    demo.load(
        fn=lambda: init_chat("ar"),
        inputs=[],
        outputs=[chat_box] + quick_action_buttons
    )

if __name__ == "__main__":
    demo.launch(
        server_name="0.0.0.0",
        server_port=7860,
        share=True  # Enable public link
    )