waleedmohd commited on
Commit
7d0b36f
·
verified ·
1 Parent(s): 091771a

Upload 7 files

Browse files
INSTALLATION.md ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Installation Instructions for Omdurman National Bank Chatbot
2
+
3
+ This document provides instructions for installing and running the improved Omdurman National Bank chatbot.
4
+
5
+ ## Prerequisites
6
+
7
+ - Python 3.6 or higher
8
+ - pip (Python package installer)
9
+
10
+ ## Installation Steps
11
+
12
+ 1. Create a virtual environment (recommended):
13
+ ```bash
14
+ python3 -m venv venv
15
+ source venv/bin/activate # On Windows: venv\Scripts\activate
16
+ ```
17
+
18
+ 2. Install Gradio with minimal dependencies:
19
+ ```bash
20
+ pip install gradio --no-deps
21
+ ```
22
+
23
+ 3. Install required dependencies:
24
+ ```bash
25
+ pip install gradio-client
26
+ ```
27
+
28
+ 4. For full functionality (if disk space allows):
29
+ ```bash
30
+ pip install numpy pandas
31
+ ```
32
+
33
+ ## Running the Chatbot
34
+
35
+ ### Basic Version
36
+ To run the basic version of the chatbot:
37
+
38
+ ```bash
39
+ python3 final_chatbot.py
40
+ ```
41
+
42
+ This will start the chatbot with core functionality. The chatbot will automatically detect if the customer service enhancements module is available and adapt accordingly.
43
+
44
+ ### Testing Locally
45
+
46
+ Once the chatbot is running, you can access it at:
47
+ - http://localhost:7860
48
+
49
+ The chatbot will also generate a public link that you can use to access it from any device.
50
+
51
+ ## Troubleshooting
52
+
53
+ ### Disk Space Issues
54
+
55
+ If you encounter disk space issues during installation, you can try:
56
+
57
+ 1. Using the `--no-deps` flag with pip to avoid installing unnecessary dependencies:
58
+ ```bash
59
+ pip install gradio --no-deps
60
+ ```
61
+
62
+ 2. Installing only the essential dependencies:
63
+ ```bash
64
+ pip install gradio-client
65
+ ```
66
+
67
+ 3. Using a smaller version of the chatbot by removing the customer service enhancements:
68
+ ```bash
69
+ # Run without importing customer_service_enhancements.py
70
+ ```
71
+
72
+ ### Missing Modules
73
+
74
+ If you encounter "ModuleNotFoundError" messages:
75
+
76
+ 1. Install the specific missing module:
77
+ ```bash
78
+ pip install [module_name]
79
+ ```
80
+
81
+ 2. If the error is related to gradio-client:
82
+ ```bash
83
+ pip install gradio-client
84
+ ```
85
+
86
+ ## File Structure
87
+
88
+ - `final_chatbot.py`: The main chatbot implementation with all features
89
+ - `customer_service_enhancements.py`: Additional customer service features (optional)
90
+ - `original_chatbot.py`: The original chatbot implementation for reference
91
+ - `README.md`: Overview of the chatbot features and implementation
92
+ - `INSTALLATION.md`: This installation guide
93
+
94
+ ## Contact
95
+
96
+ For any issues or questions, please contact the Omdurman National Bank IT support team.
README.md CHANGED
@@ -1,14 +1,61 @@
1
- ---
2
- title: Arabic Sentiment Demo
3
- emoji: 💬
4
- colorFrom: yellow
5
- colorTo: purple
6
- sdk: gradio
7
- sdk_version: 5.0.1
8
- app_file: app.py
9
- pinned: false
10
- license: apache-2.0
11
- short_description: Chatbot customer
12
- ---
13
-
14
- An example chatbot using [Gradio](https://gradio.app), [`huggingface_hub`](https://huggingface.co/docs/huggingface_hub/v0.22.2/en/index), and the [Hugging Face Inference API](https://huggingface.co/docs/api-inference/index).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Omdurman National Bank Chatbot
2
+
3
+ This is an improved chatbot for Omdurman National Bank with user-friendly features and external action capabilities.
4
+
5
+ ## Features
6
+
7
+ ### User-Friendly Enhancements
8
+ - Bilingual support (Arabic and English)
9
+ - Quick action buttons for common banking tasks
10
+ - Typing indicators for a more natural conversation experience
11
+ - Enhanced UI with better styling and layout
12
+ - Welcome message with bank logo
13
+
14
+ ### External Actions
15
+ - Clickable links for online banking actions
16
+ - Phone number links for direct calling
17
+ - Email links for customer support
18
+ - Branch location finder
19
+ - Live agent connection option
20
+
21
+ ### Customer Service Expertise
22
+ - Natural language responses with greeting and follow-up phrases
23
+ - Personalized customer service tone
24
+ - Interaction logging for quality improvement
25
+ - Menu of available services
26
+
27
+ ## Implementation Details
28
+
29
+ The chatbot has been implemented with disk space constraints in mind:
30
+ - Replaced the heavy transformers-based language detection with a lightweight regex-based approach
31
+ - Used HTML/CSS/JavaScript for enhanced UI features instead of additional dependencies
32
+ - Implemented all functionality within a single file for easy deployment
33
+
34
+ ## How to Run
35
+
36
+ ```bash
37
+ cd /home/ubuntu/banking_chatbot
38
+ python3 improved_chatbot.py
39
+ ```
40
+
41
+ The chatbot will be available at http://localhost:7860 and will also generate a public link for external access.
42
+
43
+ ## Comparison with Original Version
44
+
45
+ The improved version offers several advantages over the original:
46
+ 1. More user-friendly interface with quick action buttons
47
+ 2. External action links for banking services
48
+ 3. More natural, human-like responses
49
+ 4. Typing indicators for a more engaging experience
50
+ 5. Live agent connection option
51
+ 6. Interaction logging for service improvement
52
+ 7. Reduced dependencies for better performance
53
+
54
+ ## Customization
55
+
56
+ You can customize the chatbot by modifying:
57
+ - `ONB_GUIDELINES_AR` and `ONB_GUIDELINES_EN` for response content
58
+ - `QUICK_ACTIONS_AR` and `QUICK_ACTIONS_EN` for quick action buttons
59
+ - `CUSTOMER_SERVICE_PHRASES_AR` and `CUSTOMER_SERVICE_PHRASES_EN` for tone and style
60
+ - `custom_css` for visual styling
61
+ - `custom_js` for interactive behavior
customer_service_enhancements.py ADDED
@@ -0,0 +1,349 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Customer Service Expertise Enhancements for Omdurman National Bank Chatbot
3
+
4
+ This module contains additional customer service expertise elements that can be
5
+ integrated into the main chatbot implementation to provide a more personalized
6
+ and professional banking experience.
7
+ """
8
+
9
+ # Enhanced customer service phrases with more banking-specific language
10
+ ENHANCED_CUSTOMER_SERVICE_PHRASES_AR = {
11
+ "greeting": [
12
+ "مرحبًا بك في بنك أم درمان الوطني! كيف يمكنني مساعدتك اليوم؟",
13
+ "أهلاً بك في خدمة العملاء الافتراضية لبنك أم درمان الوطني. كيف يمكنني خدمتك؟",
14
+ "مرحبًا! أنا مساعدك المصرفي الشخصي من بنك أم درمان الوطني. كيف يمكنني مساعدتك؟",
15
+ "شكرًا لاختيارك بنك أم درمان الوطني. كيف يمكنني تلبية احتياجاتك المصرفية اليوم؟"
16
+ ],
17
+ "thanks": [
18
+ "شكرًا لتواصلك مع بنك أم درمان الوطني!",
19
+ "نشكرك على ثقتك في خدماتنا المصرفية.",
20
+ "سعداء بخدمتك دائمًا في بنك أم درمان الوطني!",
21
+ "نقدر اختيارك لبنك أم درمان الوطني لتلبية احتياجاتك المالية."
22
+ ],
23
+ "follow_up": [
24
+ "هل هناك خدمة مصرفية أخرى يمكنني مساعدتك بها اليوم؟",
25
+ "هل لديك أي استفسارات أخرى حول منتجاتنا أو خدماتنا المصرفية؟",
26
+ "هل تحتاج إلى مساعدة في أي معاملات مصرفية أخرى؟",
27
+ "هل يمكنني مساعدتك في أي شيء آخر لتحسين تجربتك المصرفية معنا؟"
28
+ ],
29
+ "apology": [
30
+ "أعتذر عن أي إزعاج قد سببناه لك.",
31
+ "نأسف على هذه التجربة، ونحن ملتزمون بتحسين خدماتنا.",
32
+ "أعتذر عن عدم تلبية توقعاتك. دعنا نعمل معًا لإيجاد حل.",
33
+ "نعتذر عن هذا الخطأ ونقدر صبرك."
34
+ ],
35
+ "reassurance": [
36
+ "يمكنك الاطمئنان بأن أموالك في أيدٍ أمينة مع بنك أم درمان الوطني.",
37
+ "أمن معلوماتك المالية هو أولويتنا القصوى.",
38
+ "نحن نلتزم بتقديم أفضل الحلول المالية لعملائنا الكرام.",
39
+ "ثقتك مهمة لنا، ونحن نعمل جاهدين للحفاظ عليها."
40
+ ]
41
+ }
42
+
43
+ ENHANCED_CUSTOMER_SERVICE_PHRASES_EN = {
44
+ "greeting": [
45
+ "Welcome to Omdurman National Bank! How may I assist you today?",
46
+ "Hello and welcome to ONB virtual customer service. How can I help you?",
47
+ "Greetings! I'm your personal banking assistant from Omdurman National Bank. How can I assist you?",
48
+ "Thank you for choosing Omdurman National Bank. How may I address your banking needs today?"
49
+ ],
50
+ "thanks": [
51
+ "Thank you for contacting Omdurman National Bank!",
52
+ "We appreciate your trust in our banking services.",
53
+ "Always a pleasure serving you at Omdurman National Bank!",
54
+ "We value your choice of Omdurman National Bank for your financial needs."
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
+ "Do you need assistance with any other banking transactions?",
60
+ "Can I help you with anything else to enhance your banking experience with us?"
61
+ ],
62
+ "apology": [
63
+ "I apologize for any inconvenience this may have caused you.",
64
+ "We're sorry about this experience, and we're committed to improving our services.",
65
+ "I apologize that we didn't meet your expectations. Let's work together to find a solution.",
66
+ "We apologize for this error and appreciate your patience."
67
+ ],
68
+ "reassurance": [
69
+ "You can rest assured that your money is in safe hands with Omdurman National Bank.",
70
+ "The security of your financial information is our top priority.",
71
+ "We are committed to providing the best financial solutions for our valued customers.",
72
+ "Your trust is important to us, and we work hard to maintain it."
73
+ ]
74
+ }
75
+
76
+ # Banking-specific FAQs
77
+ BANKING_FAQS_AR = [
78
+ {
79
+ "question": "ما هي متطلبات فتح حساب توفير؟",
80
+ "answer": "لفتح حساب توفير، تحتاج إلى هوية وطنية سارية المفعول أو جواز سفر، وإثبات عنوان (مثل فاتورة مرافق)، والحد الأدنى للإيداع هو 1000 جنيه سوداني."
81
+ },
82
+ {
83
+ "question": "كيف يمكنني تغيير رقم هاتفي المسجل لدى البنك؟",
84
+ "answer": "لتغيير رقم هاتفك المسجل، يرجى زيارة أقرب فرع مع إثبات هويتك، أو يمكنك تقديم طلب عبر الخدمات المصرفية عبر الإنترنت في قسم 'تحديث المعلومات الشخصية'."
85
+ },
86
+ {
87
+ "question": "ما هي رسوم التحويلات الدولية؟",
88
+ "answer": "تبدأ رسوم التحويلات الدولية من 25 جنيه سوداني وتختلف حسب البلد المستلم ومبلغ التحويل. للحصول على تفاصيل محددة، يرجى الاطلاع على جدول الرسوم على موقعنا الإلكتروني."
89
+ },
90
+ {
91
+ "question": "هل يمكنني الحصول على قرض إذا كنت متقاعدًا؟",
92
+ "answer": "نعم، يمكن للمتقاعدين التقدم بطلب للحصول على قروض خاصة مع شروط ميسرة. يجب أن يكون عمرك أقل من 70 عامًا وأن تتلقى معاشك التقاعدي من خلال حساب في بنكنا."
93
+ },
94
+ {
95
+ "question": "كم من الوقت يستغرق إصدار بطاقة ائتمان جديدة؟",
96
+ "answer": "عادة ما يستغرق إصدار بطاقة ائتمان جديدة من 7 إلى 10 أيام عمل من تاريخ الموافقة على الطلب. يمكنك متابعة حالة طلبك من خلال الخدمات المصرفية عبر الإنترنت."
97
+ }
98
+ ]
99
+
100
+ BANKING_FAQS_EN = [
101
+ {
102
+ "question": "What are the requirements for opening a savings account?",
103
+ "answer": "To open a savings account, you need a valid national ID or passport, proof of address (such as a utility bill), and the minimum deposit is 1000 SDG."
104
+ },
105
+ {
106
+ "question": "How can I change my registered phone number with the bank?",
107
+ "answer": "To change your registered phone number, please visit your nearest branch with your ID proof, or you can submit a request through online banking in the 'Update Personal Information' section."
108
+ },
109
+ {
110
+ "question": "What are the fees for international transfers?",
111
+ "answer": "International transfer fees start from 25 SDG and vary depending on the receiving country and transfer amount. For specific details, please check the fee schedule on our website."
112
+ },
113
+ {
114
+ "question": "Can I get a loan if I am retired?",
115
+ "answer": "Yes, retirees can apply for special loans with favorable terms. You must be under 70 years of age and receive your pension through an account with our bank."
116
+ },
117
+ {
118
+ "question": "How long does it take to issue a new credit card?",
119
+ "answer": "Issuing a new credit card typically takes 7-10 business days from the date of application approval. You can track your application status through online banking."
120
+ }
121
+ ]
122
+
123
+ # Customer satisfaction survey
124
+ SATISFACTION_SURVEY_AR = {
125
+ "title": "استطلاع رضا العملاء",
126
+ "intro": "نقدر ملاحظاتك! يرجى تقييم تجربتك مع مساعدنا المصرفي الافتراضي.",
127
+ "questions": [
128
+ "كيف تقيم سهولة استخدام المساعد المصرفي الافتراضي؟",
129
+ "هل كانت المعلومات المقدمة مفيدة ودقيقة؟",
130
+ "هل تمت معالجة استفسارك بشكل فعال؟",
131
+ "ما مدى احتمالية استخدامك للمساعد المصرفي الافتراضي مرة أخرى؟",
132
+ "هل لديك أي اقتراحات لتحسين خدمتنا؟"
133
+ ],
134
+ "ratings": ["ممتاز", "جيد جدًا", "جيد", "مقبول", "ضعيف"],
135
+ "submit": "إرسال التقييم",
136
+ "thanks": "شكرًا على ملاحظاتك القيمة!"
137
+ }
138
+
139
+ SATISFACTION_SURVEY_EN = {
140
+ "title": "Customer Satisfaction Survey",
141
+ "intro": "We value your feedback! Please rate your experience with our virtual banking assistant.",
142
+ "questions": [
143
+ "How would you rate the ease of use of the virtual banking assistant?",
144
+ "Was the information provided helpful and accurate?",
145
+ "Was your inquiry handled effectively?",
146
+ "How likely are you to use the virtual banking assistant again?",
147
+ "Do you have any suggestions for improving our service?"
148
+ ],
149
+ "ratings": ["Excellent", "Very Good", "Good", "Fair", "Poor"],
150
+ "submit": "Submit Rating",
151
+ "thanks": "Thank you for your valuable feedback!"
152
+ }
153
+
154
+ # Banking terminology glossary
155
+ BANKING_GLOSSARY_AR = {
156
+ "حساب جاري": "حساب مصرفي يسمح بالسحب والإيداع المتكرر، عادة بدون فائدة.",
157
+ "حساب توفير": "حساب مصرفي يدفع فائدة على الأموال المودعة ويشجع على الادخار.",
158
+ "بطاقة الخصم": "بطاقة تسمح بالدفع الإلكتروني مباشرة من الحساب الجاري.",
159
+ "بطاقة ائتمان": "بطاقة تسمح بالاقتراض ضمن حد ائتماني محدد مسبقًا.",
160
+ "معدل الفائدة": "النسبة المئوية للمبلغ الأصلي الذي يدفعه المقترض كرسوم للمقرض.",
161
+ "الرصيد المتاح": "المبلغ المتاح للسحب من الحساب.",
162
+ "كشف الحساب": "سجل للمعاملات المالية خلال فترة زمنية محددة.",
163
+ "الحوالة المصرفية": "تحويل الأموال إلكترونيًا من حساب إلى آخر.",
164
+ "الرهن العقاري": "قرض لشراء عقار، حيث يكون العقار نفسه ضمانًا للقرض.",
165
+ "الوديعة لأجل": "إيداع مالي في البنك لفترة زمنية محددة بسعر فائدة ثابت."
166
+ }
167
+
168
+ BANKING_GLOSSARY_EN = {
169
+ "Current Account": "A bank account that allows frequent withdrawals and deposits, usually without interest.",
170
+ "Savings Account": "A bank account that pays interest on deposits and encourages saving.",
171
+ "Debit Card": "A card that allows electronic payment directly from a current account.",
172
+ "Credit Card": "A card that allows borrowing within a pre-approved credit limit.",
173
+ "Interest Rate": "The percentage of the principal amount that a borrower pays as a fee to the lender.",
174
+ "Available Balance": "The amount available for withdrawal from an account.",
175
+ "Bank Statement": "A record of financial transactions over a specified period.",
176
+ "Wire Transfer": "Electronic transfer of funds from one account to another.",
177
+ "Mortgage": "A loan to purchase real estate, where the property itself serves as collateral.",
178
+ "Fixed Deposit": "A financial deposit in a bank for a specified time period at a fixed interest rate."
179
+ }
180
+
181
+ # Function to get enhanced customer service response
182
+ def get_enhanced_response(intent, language, user_name=None):
183
+ """
184
+ Generate an enhanced customer service response based on intent and language.
185
+
186
+ Args:
187
+ intent (str): The identified user intent
188
+ language (str): The language code ('ar' or 'en')
189
+ user_name (str, optional): The user's name for personalization
190
+
191
+ Returns:
192
+ str: An enhanced response with appropriate customer service elements
193
+ """
194
+ import random
195
+
196
+ # Select the appropriate phrases based on language
197
+ phrases = ENHANCED_CUSTOMER_SERVICE_PHRASES_AR if language == "ar" else ENHANCED_CUSTOMER_SERVICE_PHRASES_EN
198
+
199
+ # Get the base response content
200
+ if language == "ar":
201
+ base_content = ONB_GUIDELINES_AR.get(intent, "")
202
+ else:
203
+ base_content = ONB_GUIDELINES_EN.get(intent, "")
204
+
205
+ # Add personalization if user name is provided
206
+ greeting = random.choice(phrases["greeting"])
207
+ if user_name:
208
+ if language == "ar":
209
+ greeting = greeting.replace("مرحبًا", f"مرحبًا {user_name}")
210
+ else:
211
+ greeting = greeting.replace("Welcome", f"Welcome {user_name}")
212
+
213
+ # Add reassurance for financial security related intents
214
+ reassurance = ""
215
+ if intent in ["balance", "transfer", "loan", "new_account"]:
216
+ reassurance = f"<br><br>{random.choice(phrases['reassurance'])}"
217
+
218
+ # Add follow-up
219
+ follow_up = random.choice(phrases["follow_up"])
220
+
221
+ # Combine all elements
222
+ enhanced_response = f"{greeting}<br><br>{base_content}{reassurance}<br><br>{follow_up}"
223
+
224
+ return enhanced_response
225
+
226
+ # Function to handle common banking FAQs
227
+ def handle_banking_faq(question, language):
228
+ """
229
+ Check if the user's question matches any common banking FAQs and return the answer.
230
+
231
+ Args:
232
+ question (str): The user's question
233
+ language (str): The language code ('ar' or 'en')
234
+
235
+ Returns:
236
+ str or None: The FAQ answer if found, None otherwise
237
+ """
238
+ # Select the appropriate FAQs based on language
239
+ faqs = BANKING_FAQS_AR if language == "ar" else BANKING_FAQS_EN
240
+
241
+ # Convert question to lowercase for case-insensitive matching
242
+ question_lower = question.lower()
243
+
244
+ # Check each FAQ for a match
245
+ for faq in faqs:
246
+ faq_question_lower = faq["question"].lower()
247
+
248
+ # Check if the user's question contains the FAQ question keywords
249
+ keywords = faq_question_lower.split()
250
+ match_count = sum(1 for keyword in keywords if keyword in question_lower)
251
+
252
+ # If more than 50% of keywords match, consider it a match
253
+ if match_count >= len(keywords) * 0.5:
254
+ return faq["answer"]
255
+
256
+ return None
257
+
258
+ # Function to offer satisfaction survey
259
+ def offer_satisfaction_survey(language):
260
+ """
261
+ Generate HTML for a customer satisfaction survey.
262
+
263
+ Args:
264
+ language (str): The language code ('ar' or 'en')
265
+
266
+ Returns:
267
+ str: HTML for the satisfaction survey
268
+ """
269
+ # Select the appropriate survey based on language
270
+ survey = SATISFACTION_SURVEY_AR if language == "ar" else SATISFACTION_SURVEY_EN
271
+
272
+ # Generate HTML for the survey
273
+ html = f"""
274
+ <div class="satisfaction-survey" dir="{('rtl' if language == 'ar' else 'ltr')}">
275
+ <h3>{survey['title']}</h3>
276
+ <p>{survey['intro']}</p>
277
+ <form id="satisfaction-form">
278
+ """
279
+
280
+ # Add questions
281
+ for i, question in enumerate(survey['questions']):
282
+ html += f"""
283
+ <div class="survey-question">
284
+ <p>{question}</p>
285
+ <div class="rating-options">
286
+ """
287
+
288
+ # Add rating options
289
+ for rating in survey['ratings']:
290
+ html += f"""
291
+ <label>
292
+ <input type="radio" name="q{i+1}" value="{rating}">
293
+ {rating}
294
+ </label>
295
+ """
296
+
297
+ html += """
298
+ </div>
299
+ </div>
300
+ """
301
+
302
+ # Add text area for suggestions
303
+ html += f"""
304
+ <div class="survey-question">
305
+ <p>{survey['questions'][-1]}</p>
306
+ <textarea name="suggestions" rows="3" cols="40"></textarea>
307
+ </div>
308
+ """
309
+
310
+ # Add submit button
311
+ html += f"""
312
+ <button type="button" onclick="submitSurvey()" class="survey-submit">{survey['submit']}</button>
313
+ </form>
314
+ </div>
315
+
316
+ <script>
317
+ function submitSurvey() {{
318
+ alert('{survey['thanks']}');
319
+ document.getElementById('satisfaction-form').style.display = 'none';
320
+ }}
321
+ </script>
322
+ """
323
+
324
+ return html
325
+
326
+ # Function to provide banking term definition
327
+ def get_banking_term_definition(term, language):
328
+ """
329
+ Get the definition of a banking term from the glossary.
330
+
331
+ Args:
332
+ term (str): The banking term to look up
333
+ language (str): The language code ('ar' or 'en')
334
+
335
+ Returns:
336
+ str or None: The definition if found, None otherwise
337
+ """
338
+ # Select the appropriate glossary based on language
339
+ glossary = BANKING_GLOSSARY_AR if language == "ar" else BANKING_GLOSSARY_EN
340
+
341
+ # Convert term to lowercase for case-insensitive matching
342
+ term_lower = term.lower()
343
+
344
+ # Check each term in the glossary
345
+ for glossary_term, definition in glossary.items():
346
+ if glossary_term.lower() in term_lower or term_lower in glossary_term.lower():
347
+ return definition
348
+
349
+ return None
final_chatbot.py ADDED
@@ -0,0 +1,923 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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("/home/ubuntu/banking_chatbot/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
+ )
improved_chatbot.py ADDED
@@ -0,0 +1,460 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ # Omdurman National Bank-specific guidelines in Arabic
16
+ ONB_GUIDELINES_AR = {
17
+ "balance": "يمكنك التحقق من رصيدك عبر الإنترنت أو عبر تطبيق الهاتف الخاص ببنك أم درمان الوطني. <a href='#' onclick='window.open(\"https://onb.sd/balance\", \"_blank\")'>افحص رصيدك الآن</a>",
18
+ "lost_card": "في حالة فقدان البطاقة، اتصل بالرقم <a href='tel:249123456789'>249-123-456-789</a> فورًا أو <a href='#' onclick='window.open(\"https://onb.sd/block-card\", \"_blank\")'>أوقف البطاقة عبر الإنترنت</a>.",
19
+ "loan": "شروط القرض تشمل الحد الأدنى للدخل (5000 جنيه سوداني) وتاريخ ائتماني جيد. <a href='#' onclick='window.open(\"https://onb.sd/loans\", \"_blank\")'>تقدم بطلب قرض الآن</a>",
20
+ "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>.",
21
+ "new_account": "لفتح حساب جديد، قم بزيارة أقرب فرع مع جواز سفرك أو هويتك الوطنية. <a href='#' onclick='window.open(\"https://onb.sd/new-account\", \"_blank\")'>احجز موعدًا الآن</a>",
22
+ "interest_rates": "أسعار الفائدة على الودائع تتراوح بين 5% إلى 10% سنويًا. <a href='#' onclick='window.open(\"https://onb.sd/rates\", \"_blank\")'>اطلع على جميع الأسعار</a>",
23
+ "branches": "فروعنا موجودة في أم درمان، الخرطوم، وبورتسودان. <a href='#' onclick='window.open(\"https://onb.sd/branches\", \"_blank\")'>اعثر على أقرب فرع</a>",
24
+ "working_hours": "ساعات العمل من 8 صباحًا إلى 3 مساءً من الأحد إلى الخميس. <a href='#' onclick='window.open(\"https://onb.sd/hours\", \"_blank\")'>تحقق من ساعات العمل الخاصة</a>",
25
+ "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>"
26
+ }
27
+
28
+ # Omdurman National Bank-specific guidelines in English
29
+ ONB_GUIDELINES_EN = {
30
+ "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>",
31
+ "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>.",
32
+ "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>",
33
+ "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>.",
34
+ "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>",
35
+ "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>",
36
+ "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>",
37
+ "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>",
38
+ "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>"
39
+ }
40
+
41
+ # Quick action buttons in Arabic
42
+ QUICK_ACTIONS_AR = [
43
+ {"text": "تحقق من الرصيد", "intent": "balance"},
44
+ {"text": "الإبلاغ عن بطاقة مفقودة", "intent": "lost_card"},
45
+ {"text": "معلومات القرض", "intent": "loan"},
46
+ {"text": "تحويل الأموال", "intent": "transfer"},
47
+ {"text": "فتح حساب جديد", "intent": "new_account"},
48
+ {"text": "أسعار الفائدة", "intent": "interest_rates"},
49
+ {"text": "مواقع الفروع", "intent": "branches"},
50
+ {"text": "ساعات العمل", "intent": "working_hours"},
51
+ {"text": "اتصل بنا", "intent": "contact"}
52
+ ]
53
+
54
+ # Quick action buttons in English
55
+ QUICK_ACTIONS_EN = [
56
+ {"text": "Check Balance", "intent": "balance"},
57
+ {"text": "Report Lost Card", "intent": "lost_card"},
58
+ {"text": "Loan Information", "intent": "loan"},
59
+ {"text": "Transfer Funds", "intent": "transfer"},
60
+ {"text": "Open New Account", "intent": "new_account"},
61
+ {"text": "Interest Rates", "intent": "interest_rates"},
62
+ {"text": "Branch Locations", "intent": "branches"},
63
+ {"text": "Working Hours", "intent": "working_hours"},
64
+ {"text": "Contact Us", "intent": "contact"}
65
+ ]
66
+
67
+ # Menu options in both languages
68
+ MENU_AR = """
69
+ قائمة الخدمات المصرفية:
70
+ 1. رصيد - استعلام عن رصيد حسابك
71
+ 2. بطاقة - الإبلاغ عن بطاقة مفقودة
72
+ 3. قرض - معلومات عن القروض
73
+ 4. تحويل - تحويل الأموال
74
+ 5. حساب - فتح حساب جديد
75
+ 6. فائدة - أسعار الفائدة
76
+ 7. فرع - مواقع الفروع
77
+ 8. ساعات - ساعات العمل
78
+ 9. اتصال - معلومات الاتصال
79
+ """
80
+
81
+ MENU_EN = """
82
+ Banking Services Menu:
83
+ 1. balance - Check your account balance
84
+ 2. card - Report a lost card
85
+ 3. loan - Information about loans
86
+ 4. transfer - Transfer funds
87
+ 5. account - Open a new account
88
+ 6. interest - Interest rates
89
+ 7. branch - Branch locations
90
+ 8. hours - Working hours
91
+ 9. contact - Contact information
92
+ """
93
+
94
+ # Map intents to keywords (enhanced)
95
+ INTENT_KEYWORDS = {
96
+ "balance": ["balance", "check balance", "account balance", "how much", "رصيد", "حساب", "كم المبلغ", "1"],
97
+ "lost_card": ["lost", "card", "stolen", "missing", "فقدت", "بطاقة", "مسروقة", "ضائعة", "2"],
98
+ "loan": ["loan", "borrow", "borrowing", "credit", "قرض", "استدانة", "إئتمان", "3"],
99
+ "transfer": ["transfer", "send money", "payment", "تحويل", "ارسال", "دفع", "4"],
100
+ "new_account": ["account", "open", "create", "new", "حساب", "فتح", "جديد", "إنشاء", "5"],
101
+ "interest_rates": ["interest", "rate", "rates", "return", "فائدة", "نسبة", "عائد", "6"],
102
+ "branches": ["branch", "location", "where", "office", "فرع", "موقع", "أين", "مكتب", "7"],
103
+ "working_hours": ["hours", "time", "open", "close", "ساعات", "وقت", "مفتوح", "مغلق", "8"],
104
+ "contact": ["contact", "phone", "email", "call", "اتصال", "هاتف", "بريد", "اتصل", "9"]
105
+ }
106
+
107
+ # Customer service phrases for more human-like responses
108
+ CUSTOMER_SERVICE_PHRASES_AR = {
109
+ "greeting": [
110
+ "مرحبًا! كيف يمكنني مساعدتك اليوم؟",
111
+ "أهلاً بك في بنك أم درمان الوطني! كيف يمكنني خدمتك؟",
112
+ "مرحبًا بك! أنا هنا للمساعدة في أي استفسارات مصرفية."
113
+ ],
114
+ "thanks": [
115
+ "شكرًا لتواصلك معنا!",
116
+ "نشكرك على استخدام خدماتنا المصرفية.",
117
+ "سعداء بخدمتك دائمًا!"
118
+ ],
119
+ "follow_up": [
120
+ "هل هناك شيء آخر يمكنني مساعدتك به؟",
121
+ "هل لديك أي أسئلة أخرى؟",
122
+ "هل تحتاج إلى مساعدة في أمر آخر؟"
123
+ ]
124
+ }
125
+
126
+ CUSTOMER_SERVICE_PHRASES_EN = {
127
+ "greeting": [
128
+ "Hello! How can I assist you today?",
129
+ "Welcome to Omdurman National Bank! How may I help you?",
130
+ "Hi there! I'm here to help with any banking inquiries."
131
+ ],
132
+ "thanks": [
133
+ "Thank you for contacting us!",
134
+ "We appreciate you using our banking services.",
135
+ "Always happy to serve you!"
136
+ ],
137
+ "follow_up": [
138
+ "Is there anything else I can help you with?",
139
+ "Do you have any other questions?",
140
+ "Do you need assistance with anything else?"
141
+ ]
142
+ }
143
+
144
+ # Function to get a random phrase from the customer service phrases
145
+ def get_random_phrase(category, language):
146
+ import random
147
+ if language == "ar":
148
+ return random.choice(CUSTOMER_SERVICE_PHRASES_AR[category])
149
+ else:
150
+ return random.choice(CUSTOMER_SERVICE_PHRASES_EN[category])
151
+
152
+ def classify_intent(message: str):
153
+ # Check for menu request
154
+ menu_keywords = ["menu", "options", "help", "قائمة", "خيارات", "مساعدة"]
155
+ message_lower = message.lower()
156
+
157
+ for keyword in menu_keywords:
158
+ if keyword in message_lower:
159
+ return "menu"
160
+
161
+ # Use keyword matching for intent classification
162
+ for intent_key, keywords in INTENT_KEYWORDS.items():
163
+ for keyword in keywords:
164
+ if keyword.lower() in message_lower:
165
+ return intent_key
166
+
167
+ return "unknown"
168
+
169
+ # Function to log customer interactions
170
+ def log_interaction(user_message, bot_response, intent, language):
171
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
172
+ log_entry = {
173
+ "timestamp": timestamp,
174
+ "user_message": user_message,
175
+ "bot_response": bot_response,
176
+ "intent": intent,
177
+ "language": language
178
+ }
179
+
180
+ try:
181
+ with open("/home/ubuntu/banking_chatbot/interaction_logs.jsonl", "a") as f:
182
+ f.write(json.dumps(log_entry) + "\n")
183
+ except Exception as e:
184
+ print(f"Error logging interaction: {e}")
185
+
186
+ def respond(message: str):
187
+ if not message.strip():
188
+ return {
189
+ "ar": "الرجاء كتابة سؤالك.",
190
+ "en": "Please type your question."
191
+ }
192
+
193
+ # Detect language using simple function
194
+ language = simple_detect_language(message)
195
+
196
+ # Classify the user's intent using keyword matching
197
+ intent = classify_intent(message)
198
+
199
+ # Prepare responses in both languages
200
+ responses = {
201
+ "ar": "",
202
+ "en": ""
203
+ }
204
+
205
+ # Special handling for menu request
206
+ if intent == "menu":
207
+ responses["ar"] = MENU_AR
208
+ responses["en"] = MENU_EN
209
+ log_interaction(message, responses[language], "menu", language)
210
+ return responses
211
+
212
+ # If intent is recognized, return the corresponding response
213
+ if intent != "unknown":
214
+ # Add a greeting phrase at the beginning
215
+ greeting_ar = get_random_phrase("greeting", "ar")
216
+ greeting_en = get_random_phrase("greeting", "en")
217
+
218
+ # Add the main response
219
+ main_response_ar = ONB_GUIDELINES_AR.get(intent, "عذرًا، لم يتم التعرف على الخيار المحدد.")
220
+ main_response_en = ONB_GUIDELINES_EN.get(intent, "Sorry, the selected option was not recognized.")
221
+
222
+ # Add a follow-up phrase at the end
223
+ follow_up_ar = get_random_phrase("follow_up", "ar")
224
+ follow_up_en = get_random_phrase("follow_up", "en")
225
+
226
+ # Combine all parts
227
+ responses["ar"] = f"{greeting_ar}<br><br>{main_response_ar}<br><br>{follow_up_ar}"
228
+ responses["en"] = f"{greeting_en}<br><br>{main_response_en}<br><br>{follow_up_en}"
229
+ else:
230
+ # Default response if no intent is matched - show menu
231
+ responses["ar"] = "عذرًا، لم أفهم سؤالك. إليك قائمة بالخدمات المتاحة:" + MENU_AR
232
+ responses["en"] = "Sorry, I didn't understand your question. Here's a menu of available services:" + MENU_EN
233
+
234
+ # Log the interaction
235
+ log_interaction(message, responses[language], intent, language)
236
+
237
+ return responses
238
+
239
+ # Custom CSS for better UI
240
+ custom_css = """
241
+ .gradio-container {
242
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
243
+ }
244
+
245
+ .chat-message {
246
+ padding: 1rem;
247
+ border-radius: 10px;
248
+ margin-bottom: 1rem;
249
+ max-width: 80%;
250
+ }
251
+
252
+ .user-message {
253
+ background-color: #e6f7ff;
254
+ margin-left: auto;
255
+ text-align: right;
256
+ }
257
+
258
+ .bot-message {
259
+ background-color: #f0f0f0;
260
+ margin-right: auto;
261
+ text-align: left;
262
+ }
263
+
264
+ .bot-message-ar {
265
+ background-color: #f0f0f0;
266
+ margin-left: auto;
267
+ text-align: right;
268
+ }
269
+
270
+ .header-section {
271
+ background-color: #1a5276;
272
+ color: white;
273
+ padding: 1rem;
274
+ border-radius: 10px;
275
+ margin-bottom: 1rem;
276
+ text-align: center;
277
+ }
278
+
279
+ .footer-section {
280
+ font-size: 0.8rem;
281
+ text-align: center;
282
+ margin-top: 2rem;
283
+ color: #666;
284
+ }
285
+
286
+ .lang-selector {
287
+ text-align: right;
288
+ margin-bottom: 1rem;
289
+ }
290
+
291
+ .menu-button {
292
+ margin-top: 0.5rem;
293
+ }
294
+
295
+ .quick-actions {
296
+ display: flex;
297
+ flex-wrap: wrap;
298
+ gap: 0.5rem;
299
+ margin: 1rem 0;
300
+ }
301
+
302
+ .quick-action-button {
303
+ background-color: #1a5276;
304
+ color: white;
305
+ border: none;
306
+ border-radius: 20px;
307
+ padding: 0.5rem 1rem;
308
+ cursor: pointer;
309
+ font-size: 0.9rem;
310
+ transition: background-color 0.3s;
311
+ }
312
+
313
+ .quick-action-button:hover {
314
+ background-color: #2980b9;
315
+ }
316
+
317
+ .chat-container {
318
+ border: 1px solid #ddd;
319
+ border-radius: 10px;
320
+ padding: 1rem;
321
+ background-color: #f9f9f9;
322
+ }
323
+
324
+ .typing-indicator {
325
+ display: inline-block;
326
+ width: 50px;
327
+ text-align: left;
328
+ }
329
+
330
+ .typing-indicator span {
331
+ display: inline-block;
332
+ width: 8px;
333
+ height: 8px;
334
+ background-color: #1a5276;
335
+ border-radius: 50%;
336
+ margin-right: 5px;
337
+ animation: typing 1s infinite;
338
+ }
339
+
340
+ .typing-indicator span:nth-child(2) {
341
+ animation-delay: 0.2s;
342
+ }
343
+
344
+ .typing-indicator span:nth-child(3) {
345
+ animation-delay: 0.4s;
346
+ }
347
+
348
+ @keyframes typing {
349
+ 0%, 100% {
350
+ transform: translateY(0);
351
+ }
352
+ 50% {
353
+ transform: translateY(-5px);
354
+ }
355
+ }
356
+
357
+ .live-agent-button {
358
+ background-color: #27ae60;
359
+ color: white;
360
+ border: none;
361
+ border-radius: 5px;
362
+ padding: 0.5rem 1rem;
363
+ cursor: pointer;
364
+ font-size: 0.9rem;
365
+ margin-top: 1rem;
366
+ transition: background-color 0.3s;
367
+ }
368
+
369
+ .live-agent-button:hover {
370
+ background-color: #2ecc71;
371
+ }
372
+
373
+ /* Add custom styling for links */
374
+ a {
375
+ color: #2980b9;
376
+ text-decoration: none;
377
+ font-weight: bold;
378
+ }
379
+
380
+ a:hover {
381
+ text-decoration: underline;
382
+ }
383
+
384
+ /* Add styling for action buttons */
385
+ .action-button {
386
+ display: inline-block;
387
+ background-color: #3498db;
388
+ color: white;
389
+ padding: 0.5rem 1rem;
390
+ border-radius: 5px;
391
+ margin: 0.5rem 0;
392
+ text-decoration: none;
393
+ }
394
+
395
+ .action-button:hover {
396
+ background-color: #2980b9;
397
+ text-decoration: none;
398
+ }
399
+ """
400
+
401
+ # Custom JavaScript for enhanced functionality
402
+ custom_js = """
403
+ function simulateTyping(message, elementId, delay = 30) {
404
+ const element = document.getElementById(elementId);
405
+ if (!element) return;
406
+
407
+ element.innerHTML = "";
408
+ let i = 0;
409
+
410
+ function type() {
411
+ if (i < message.length) {
412
+ element.innerHTML += message.charAt(i);
413
+ i++;
414
+ setTimeout(type, delay);
415
+ }
416
+ }
417
+
418
+ type();
419
+ }
420
+
421
+ // Function to show typing indicator
422
+ function showTypingIndicator() {
423
+ const chatbox = document.getElementById('chatbox');
424
+ if (!chatbox) return;
425
+
426
+ const typingIndicator = document.createElement('div');
427
+ typingIndicator.className = 'typing-indicator';
428
+ typingIndicator.id = 'typing-indicator';
429
+ typingIndicator.innerHTML = '<span></span><span></span><span></span>';
430
+
431
+ chatbox.appendChild(typingIndicator);
432
+ chatbox.scrollTop = chatbox.scrollHeight;
433
+ }
434
+
435
+ // Function to hide typing indicator
436
+ function hideTypingIndicator() {
437
+ const typingIndicator = document.getElementById('typing-indicator');
438
+ if (typingIndicator) {
439
+ typingIndicator.remove();
440
+ }
441
+ }
442
+
443
+ // Function to connect with a live agent
444
+ function connectLiveAgent() {
445
+ alert('Connecting to a live customer service agent. Please wait a moment...');
446
+ // In a real implementation, this would initiate a connection to a live agent system
447
+ }
448
+ """
449
+
450
+ # Chat interface with enhanced UI
451
+ with gr.Blocks(css=custom_css, js=custom_js) as demo:
452
+ # Store conversation history
453
+ state = gr.State(value=[])
454
+ # Store selected language
455
+ selected_lang = gr.State(value="ar")
456
+
457
+ with gr.Row(elem_classes="header-section"):
458
+ with gr.Column():
459
+ gr.Markdown("# Omdurman National Bank | بنك أم درمان الوطني")
460
+ gr.Markdown("### Virtual Banking Assistant | المساعد المصرفي ا<response clipped><NOTE>To save on context only part of this file has been shown to you. You should retry this tool after you have searched inside the file with `grep -n` in order to find the line numbers of what you are looking for.</NOTE>
original_chatbot.py ADDED
@@ -0,0 +1,305 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import re
3
+
4
+ # Load language detection model only (smaller model)
5
+ from transformers import pipeline
6
+ language_detector = pipeline("text-classification", model="papluca/xlm-roberta-base-language-detection")
7
+
8
+ # Omdurman National Bank-specific guidelines in Arabic
9
+ ONB_GUIDELINES_AR = {
10
+ "balance": "يمكنك التحقق من رصيدك عبر الإنترنت أو عبر تطبيق الهاتف الخاص ببنك الوطني.",
11
+ "lost_card": "في حالة فقدان البطاقة، اتصل بالرقم 249-123-456-789 فورًا.",
12
+ "loan": "شروط القرض تشمل الحد الأدنى للدخل (5000 جنيه سوداني) وتاريخ ائتماني جيد.",
13
+ "transfer": "لتحويل الأموال، استخدم تطبيق الهاتف أو الخدمة المصرفية عبر الإنترنت.",
14
+ "new_account": "لفتح حساب جديد، قم بزيارة أقرب فرع مع جواز سفرك أو هويتك الوطنية.",
15
+ "interest_rates": "أسعار الفائدة على الودائع تتراوح بين 5% إلى 10% سنويًا.",
16
+ "branches": "فروعنا موجودة في أم درمان، الخرطوم، وبورتسودان. زيارة موقعنا للتفاصيل.",
17
+ "working_hours": "ساعات العمل من 8 صباحًا إلى 3 مساءً من الأحد إلى الخميس.",
18
+ "contact": "الاتصال بنا على الرقم 249-123-456-789 أو عبر البريد الإلكتروني [email protected]."
19
+ }
20
+
21
+ # Omdurman National Bank-specific guidelines in English
22
+ ONB_GUIDELINES_EN = {
23
+ "balance": "You can check your balance online or via the ONB mobile app.",
24
+ "lost_card": "In case of a lost card, call 249-123-456-789 immediately.",
25
+ "loan": "Loan requirements include minimum income (5000 SDG) and good credit history.",
26
+ "transfer": "To transfer funds, use the mobile app or online banking service.",
27
+ "new_account": "To open a new account, visit your nearest branch with your passport or national ID.",
28
+ "interest_rates": "Interest rates on deposits range from 5% to 10% annually.",
29
+ "branches": "Our branches are located in Omdurman, Khartoum, and Port Sudan. Visit our website for details.",
30
+ "working_hours": "Working hours are from 8 AM to 3 PM, Sunday to Thursday.",
31
+ "contact": "Contact us at 249-123-456-789 or via email at [email protected]."
32
+ }
33
+
34
+ # Menu options in both languages
35
+ MENU_AR = """
36
+ قائمة الخدمات المصرفية:
37
+ 1. رصيد - استعلام عن رصيد حسابك
38
+ 2. بطاقة - الإبلاغ عن بطاقة مفقودة
39
+ 3. قرض - معلومات عن القروض
40
+ 4. تحويل - تحويل الأموال
41
+ 5. حساب - فتح حساب جديد
42
+ 6. فائدة - أسعار الفائدة
43
+ 7. فرع - مواقع الفروع
44
+ 8. ساعات - ساعات العمل
45
+ 9. اتصال - معلومات الاتصال
46
+ """
47
+
48
+ MENU_EN = """
49
+ Banking Services Menu:
50
+ 1. balance - Check your account balance
51
+ 2. card - Report a lost card
52
+ 3. loan - Information about loans
53
+ 4. transfer - Transfer funds
54
+ 5. account - Open a new account
55
+ 6. interest - Interest rates
56
+ 7. branch - Branch locations
57
+ 8. hours - Working hours
58
+ 9. contact - Contact information
59
+ """
60
+
61
+ # Map intents to keywords (enhanced)
62
+ INTENT_KEYWORDS = {
63
+ "balance": ["balance", "check balance", "account balance", "how much", "رصيد", "حساب", "كم المبلغ", "1"],
64
+ "lost_card": ["lost", "card", "stolen", "missing", "فقدت", "بطاقة", "مسروقة", "ضائعة", "2"],
65
+ "loan": ["loan", "borrow", "borrowing", "credit", "قرض", "استدانة", "إئتمان", "3"],
66
+ "transfer": ["transfer", "send money", "payment", "تحويل", "ارسال", "دفع", "4"],
67
+ "new_account": ["account", "open", "create", "new", "حساب", "فتح", "جديد", "إنشاء", "5"],
68
+ "interest_rates": ["interest", "rate", "rates", "return", "فائدة", "نسبة", "عائد", "6"],
69
+ "branches": ["branch", "location", "where", "office", "فرع", "موقع", "أين", "مكتب", "7"],
70
+ "working_hours": ["hours", "time", "open", "close", "ساعات", "وقت", "مفتوح", "مغلق", "8"],
71
+ "contact": ["contact", "phone", "email", "call", "اتصال", "هاتف", "بريد", "اتصل", "9"]
72
+ }
73
+
74
+ def detect_language(text):
75
+ # Use Hugging Face language detection model
76
+ result = language_detector(text)
77
+ language = result[0]['label']
78
+ return language
79
+
80
+ def classify_intent(message: str):
81
+ # Check for menu request
82
+ menu_keywords = ["menu", "options", "help", "قائمة", "خيارات", "مساعدة"]
83
+ message_lower = message.lower()
84
+
85
+ for keyword in menu_keywords:
86
+ if keyword in message_lower:
87
+ return "menu"
88
+
89
+ # Use keyword matching for intent classification
90
+ for intent_key, keywords in INTENT_KEYWORDS.items():
91
+ for keyword in keywords:
92
+ if keyword.lower() in message_lower:
93
+ return intent_key
94
+
95
+ return "unknown"
96
+
97
+ def respond(message: str):
98
+ if not message.strip():
99
+ return {
100
+ "ar": "الرجاء كتابة سؤالك.",
101
+ "en": "Please type your question."
102
+ }
103
+
104
+ # Detect language
105
+ language = detect_language(message)
106
+
107
+ # If the language is neither Arabic nor English, default to English
108
+ if language != "ar" and language != "en":
109
+ language = "en"
110
+
111
+ # Classify the user's intent using keyword matching
112
+ intent = classify_intent(message)
113
+
114
+ # Prepare responses in both languages
115
+ responses = {
116
+ "ar": "",
117
+ "en": ""
118
+ }
119
+
120
+ # Special handling for menu request
121
+ if intent == "menu":
122
+ responses["ar"] = MENU_AR
123
+ responses["en"] = MENU_EN
124
+ return responses
125
+
126
+ # If intent is recognized, return the corresponding response
127
+ if intent != "unknown":
128
+ responses["ar"] = ONB_GUIDELINES_AR.get(intent, "عذرًا، لم يتم التعرف على الخيار المحدد.")
129
+ responses["en"] = ONB_GUIDELINES_EN.get(intent, "Sorry, the selected option was not recognized.")
130
+ else:
131
+ # Default response if no intent is matched - show menu
132
+ responses["ar"] = "عذرًا، لم أفهم سؤالك. إليك قائمة بالخدمات المتاحة:" + MENU_AR
133
+ responses["en"] = "Sorry, I didn't understand your question. Here's a menu of available services:" + MENU_EN
134
+
135
+ return responses
136
+
137
+ # Custom CSS for better UI
138
+ custom_css = """
139
+ .gradio-container {
140
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
141
+ }
142
+
143
+ .chat-message {
144
+ padding: 1rem;
145
+ border-radius: 10px;
146
+ margin-bottom: 1rem;
147
+ max-width: 80%;
148
+ }
149
+
150
+ .user-message {
151
+ background-color: #e6f7ff;
152
+ margin-left: auto;
153
+ text-align: right;
154
+ }
155
+
156
+ .bot-message {
157
+ background-color: #f0f0f0;
158
+ margin-right: auto;
159
+ text-align: left;
160
+ }
161
+
162
+ .bot-message-ar {
163
+ background-color: #f0f0f0;
164
+ margin-left: auto;
165
+ text-align: right;
166
+ }
167
+
168
+ .header-section {
169
+ background-color: #1a5276;
170
+ color: white;
171
+ padding: 1rem;
172
+ border-radius: 10px;
173
+ margin-bottom: 1rem;
174
+ text-align: center;
175
+ }
176
+
177
+ .footer-section {
178
+ font-size: 0.8rem;
179
+ text-align: center;
180
+ margin-top: 2rem;
181
+ color: #666;
182
+ }
183
+
184
+ .lang-selector {
185
+ text-align: right;
186
+ margin-bottom: 1rem;
187
+ }
188
+
189
+ .menu-button {
190
+ margin-top: 0.5rem;
191
+ }
192
+ """
193
+
194
+ # Chat interface with enhanced UI
195
+ with gr.Blocks(css=custom_css) as demo:
196
+ # Store conversation history
197
+ state = gr.State(value=[])
198
+ # Store selected language
199
+ selected_lang = gr.State(value="ar")
200
+
201
+ with gr.Row(elem_classes="header-section"):
202
+ with gr.Column():
203
+ gr.Markdown("# Omdurman National Bank | بنك أم درمان الوطني")
204
+ gr.Markdown("### Virtual Banking Assistant | المساعد المصرفي الافتراضي")
205
+
206
+ with gr.Row():
207
+ with gr.Column(elem_classes="lang-selector"):
208
+ language_btn = gr.Radio(
209
+ ["العربية", "English"],
210
+ value="العربية",
211
+ label="Language | اللغة"
212
+ )
213
+
214
+ with gr.Row():
215
+ chat_box = gr.Chatbot(elem_id="chatbox", height=400)
216
+
217
+ with gr.Row():
218
+ with gr.Column(scale=8):
219
+ text_input = gr.Textbox(
220
+ placeholder="Type your question here | اكتب سؤالك هنا",
221
+ label="",
222
+ elem_id="chat-input"
223
+ )
224
+ with gr.Column(scale=1):
225
+ submit_btn = gr.Button("Send | إرسال", variant="primary")
226
+
227
+ with gr.Row():
228
+ with gr.Column(elem_classes="menu-button"):
229
+ menu_btn = gr.Button("Show Menu | إظهار القائمة")
230
+
231
+ with gr.Row(elem_classes="footer-section"):
232
+ gr.Markdown("© 2025 Omdurman National Bank. All Rights Reserved. | جميع الحقوق محفوظة لبنك أم درمان الوطني ٢٠٢٥ ©")
233
+
234
+ # Update language state when language is changed
235
+ def update_language(lang):
236
+ if lang == "العربية":
237
+ return "ar"
238
+ else:
239
+ return "en"
240
+
241
+ language_btn.change(
242
+ fn=update_language,
243
+ inputs=language_btn,
244
+ outputs=selected_lang
245
+ )
246
+
247
+ # Handle message submission
248
+ def on_submit(message, chat_history, lang):
249
+ if not message.strip():
250
+ return "", chat_history
251
+
252
+ # Add user message to chat history
253
+ chat_history.append([message, None])
254
+
255
+ # Get response
256
+ responses = respond(message)
257
+
258
+ # Select response based on language
259
+ response = responses[lang]
260
+
261
+ # Update bot response in chat history
262
+ chat_history[-1][1] = response
263
+
264
+ return "", chat_history
265
+
266
+ # Handle menu button click
267
+ def show_menu(chat_history, lang):
268
+ menu_responses = {
269
+ "ar": MENU_AR,
270
+ "en": MENU_EN
271
+ }
272
+
273
+ # Add system message showing the menu
274
+ menu_text = menu_responses[lang]
275
+ chat_history.append([None, menu_text])
276
+
277
+ return chat_history
278
+
279
+ # Link inputs and button to response function
280
+ submit_btn.click(
281
+ fn=on_submit,
282
+ inputs=[text_input, chat_box, selected_lang],
283
+ outputs=[text_input, chat_box]
284
+ )
285
+
286
+ # Link menu button to show menu function
287
+ menu_btn.click(
288
+ fn=show_menu,
289
+ inputs=[chat_box, selected_lang],
290
+ outputs=[chat_box]
291
+ )
292
+
293
+ # Also trigger on Enter key
294
+ text_input.submit(
295
+ fn=on_submit,
296
+ inputs=[text_input, chat_box, selected_lang],
297
+ outputs=[text_input, chat_box]
298
+ )
299
+
300
+ if __name__ == "__main__":
301
+ demo.launch(
302
+ server_name="0.0.0.0",
303
+ server_port=7860,
304
+ share=True # Enable public link
305
+ )
requirements.txt CHANGED
@@ -1,8 +1 @@
1
- huggingface_hub==0.25.2
2
- gradio>=4.0
3
- transformers
4
- torch
5
- sentencepiece
6
- protobuf
7
- accelerate
8
- optimum
 
1
+ gradio>=3.50.2