waleedmohd commited on
Commit
da5d4ac
·
verified ·
1 Parent(s): d1731fe

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +321 -210
app.py CHANGED
@@ -1,227 +1,338 @@
1
  import gradio as gr
2
- import torch
3
- import faiss
4
- import numpy as np
5
- from sentence_transformers import SentenceTransformer
6
- from langdetect import detect
7
- from typing import List, Dict, Tuple, Any
8
- from datetime import datetime
9
-
10
- class MultilingualVectorChatbot:
11
- def __init__(self,
12
- embedding_model_name: str = 'paraphrase-multilingual-MiniLM-L12-v2',
13
- similarity_threshold: float = 0.7):
14
- """
15
- Initialize the multilingual chatbot with enhanced features
16
-
17
- :param embedding_model_name: Multilingual sentence embedding model
18
- :param similarity_threshold: Minimum similarity score for valid responses
19
- """
20
- # Initialize models and databases
21
- self.embedding_model = SentenceTransformer(embedding_model_name)
22
- self.embedding_dimension = self.embedding_model.get_sentence_embedding_dimension()
23
- self.index = faiss.IndexFlatL2(self.embedding_dimension)
24
- self.knowledge_base = []
25
- self.similarity_threshold = similarity_threshold
26
-
27
- # Language-specific configurations
28
- self.FALLBACK_RESPONSES = {
29
- 'ar': "عذرًا، لا أملك إجابة محددة لهذا السؤال. هل يمكنك إعادة الصياغة؟",
30
- 'en': "I'm sorry, I don't have a specific answer. Could you rephrase?",
31
- 'fr': "Désolé, je n'ai pas de réponse spécifique. Pouvez-vous reformuler?",
32
- 'es': "Lo siento, no tengo una respuesta específica. ¿Podrías reformular?"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  }
34
-
35
- # Conversation history
36
- self.conversation_history = []
37
-
38
- # Preload knowledge
39
- self._preload_knowledge()
40
-
41
- def _preload_knowledge(self):
42
- """Preload initial multilingual knowledge base"""
43
- knowledge_pairs = [
44
- # Arabic Knowledge
45
- {
46
- 'questions': [
47
- "ما هي عاصمة مصر؟",
48
- "أين تقع القاهرة؟",
49
- "ما أهمية القاهرة؟"
50
- ],
51
- 'answer': "القاهرة هي عاصمة جمهورية مصر العربية، وتقع على ضفاف نهر النيل. وهي أكبر مدن مصر وأهم مركز سياسي وثقافي واقتصادي في البلاد.",
52
- 'language': 'ar'
53
- },
54
- {
55
- 'questions': [
56
- "كيف يمكنني تعلم البرمجة؟",
57
- "ما هي أفضل طرق تعلم البرمجة؟"
58
- ],
59
- 'answer': "يمكنك تعلم البرمجة من خلال عدة طرق: دورات مجانية عبر الإنترنت مثل Coursera وfreeCodeCamp، منصات التعلم التفاعلية مثل Codecademy، ومشاريع عملية على GitHub. ابدأ بتعلم لغة برمجة أساسية مثل Python، وركز على الممارسة العملية.",
60
- 'language': 'ar'
61
- },
62
- # English Knowledge
63
- {
64
- 'questions': [
65
- "What is the capital of France?",
66
- "Where is Paris located?",
67
- "Tell me about Paris"
68
- ],
69
- 'answer': "Paris is the capital of France, located in the north-central part of the country on the Seine River. It's known for its art, fashion, gastronomy and culture, and is home to landmarks like the Eiffel Tower and Louvre Museum.",
70
- 'language': 'en'
71
  },
72
- {
73
- 'questions': [
74
- "How can I learn programming?",
75
- "What are the best ways to learn coding?"
76
- ],
77
- 'answer': "You can learn programming through various methods: free online courses like Coursera and freeCodeCamp, interactive learning platforms like Codecademy, and practical projects on GitHub. Start by learning a foundational programming language like Python, and focus on hands-on practice.",
78
- 'language': 'en'
79
- }
80
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
- # Batch add knowledge for better performance
83
- all_questions = []
84
- all_answers = []
85
- all_languages = []
86
 
87
- for knowledge in knowledge_pairs:
88
- all_questions.extend(knowledge['questions'])
89
- all_answers.extend([knowledge['answer']] * len(knowledge['questions']))
90
- all_languages.extend([knowledge['language']] * len(knowledge['questions']))
91
 
92
- self.add_knowledge_batch(all_questions, all_answers, all_languages)
93
-
94
- def add_knowledge_batch(self, questions: List[str], answers: List[str], languages: List[str] = None):
95
- """
96
- Add knowledge in batch for better performance
97
 
98
- :param questions: List of questions
99
- :param answers: List of corresponding answers
100
- :param languages: List of language codes
101
- """
102
- if len(questions) != len(answers):
103
- raise ValueError("Questions and answers must have the same length")
104
-
105
- if languages and len(questions) != len(languages):
106
- raise ValueError("Languages list must match questions length")
107
 
108
- # Detect languages if not provided
109
- if not languages:
110
- languages = []
111
- for q in questions:
112
- try:
113
- languages.append(detect(q))
114
- except:
115
- languages.append('en') # default to English
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
- # Batch embed questions
118
- question_embeddings = self.embedding_model.encode(questions)
 
 
 
 
119
 
120
- # Add to FAISS index
121
- if len(questions) > 0:
122
- self.index.add(np.array(question_embeddings))
123
-
124
- # Store in knowledge base
125
- for q, a, lang in zip(questions, answers, languages):
126
- self.knowledge_base.append({
127
- 'question': q,
128
- 'answer': a,
129
- 'language': lang
130
- })
131
-
132
- def find_similar_question(self, query: str, top_k: int = 3) -> List[Dict]:
133
- """
134
- Enhanced similarity search with confidence scores
135
 
136
- :param query: Input query
137
- :param top_k: Number of results to return
138
- :return: List of results with similarity scores
139
- """
140
- query_embedding = self.embedding_model.encode(query)
141
- distances, indices = self.index.search(np.array([query_embedding]), top_k)
142
 
143
- results = []
144
- for dist, idx in zip(distances[0], indices[0]):
145
- if idx < len(self.knowledge_base):
146
- similarity = 1 / (1 + dist) # Convert distance to similarity
147
- result = self.knowledge_base[idx].copy()
148
- result.update({
149
- 'similarity_score': similarity,
150
- 'distance': dist
151
- })
152
- results.append(result)
153
 
154
- return sorted(results, key=lambda x: x['similarity_score'], reverse=True)
155
-
156
- def generate_response(self, query: str, include_confidence: bool = False) -> str:
157
- """
158
- Generate response with confidence scoring and language detection
159
 
160
- :param query: User query
161
- :param include_confidence: Whether to include confidence score
162
- :return: Generated response
163
- """
164
- try:
165
- # Detect language
166
- lang = detect(query)
167
-
168
- # Find similar questions
169
- similar_results = self.find_similar_question(query, top_k=1)
170
-
171
- # Prepare response
172
- if similar_results and similar_results[0]['similarity_score'] >= self.similarity_threshold:
173
- response = similar_results[0]['answer']
174
- if include_confidence:
175
- confidence = similar_results[0]['similarity_score']
176
- if lang == 'ar':
177
- response += f"\n(ثقة الإجابة: {confidence:.2f})"
178
- else:
179
- response += f"\n(Answer confidence: {confidence:.2f})"
180
- else:
181
- response = self.FALLBACK_RESPONSES.get(lang, self.FALLBACK_RESPONSES['en'])
182
-
183
- # Update conversation history
184
- self.conversation_history.append({
185
- 'query': query,
186
- 'response': response,
187
- 'language': lang,
188
- 'timestamp': str(datetime.now())
189
- })
190
-
191
- return response
192
 
193
- except Exception as e:
194
- print(f"Error generating response: {str(e)}")
195
- return self.FALLBACK_RESPONSES['en']
196
-
197
- # Initialize the chatbot
198
- chatbot = MultilingualVectorChatbot()
199
-
200
- def chat_interface(message: str, history: List[List[str]]) -> Tuple[str, Any]:
201
- """
202
- Gradio chat interface that properly handles state
203
- """
204
- try:
205
- response = chatbot.generate_response(message, include_confidence=True)
206
- return response
207
- except Exception as e:
208
- print(f"Interface error: {e}")
209
- return "An error occurred. Please try again."
210
-
211
- # Create and launch the interface
212
- iface = gr.ChatInterface(
213
- fn=chat_interface,
214
- title="🌍 Multilingual Vector Chatbot",
215
- description="Ask me questions in Arabic, English, French, or Spanish about various topics!",
216
- theme="soft",
217
- examples=[
218
- ["What is the capital of France?"],
219
- ["كيف أتعلم البرمجة؟"],
220
- ["Comment ça va?"],
221
- ["¿Dónde está el baño?"]
222
- ],
223
- cache_examples=True
224
- )
225
 
 
226
  if __name__ == "__main__":
227
- iface.launch()
 
 
 
 
 
 
1
  import gradio as gr
2
+ import re
3
+ from transformers import pipeline
4
+ import json
5
+
6
+ # Load language detection model
7
+ language_detector = pipeline("text-classification", model="papluca/xlm-roberta-base-language-detection")
8
+
9
+ # Enhanced Omdurman National Bank guidelines with more detailed information
10
+ ONB_GUIDELINES = {
11
+ "ar": {
12
+ "balance": {
13
+ "response": "يمكنك التحقق من رصيدك عبر الإنترنت أو عبر تطبيق الهاتف الخاص ببنك الوطني.",
14
+ "actions": [
15
+ {"label": "تطبيق الهاتف", "url": "https://onb.sd/mobile-app"},
16
+ {"label": "الخدمات المصرفية عبر الإنترنت", "url": "https://onb.sd/online-banking"}
17
+ ]
18
+ },
19
+ "lost_card": {
20
+ "response": "في حالة فقدان البطاقة، اتصل بالرقم 249-123-456-789 فورًا. سنقوم بإيقاف البطاقة وإصدار بطاقة جديدة.",
21
+ "actions": [
22
+ {"label": "إيقاف البطاقة فورًا", "url": "tel:249-123-456-789"},
23
+ {"label": "طلب بطاقة جديدة", "url": "https://onb.sd/replace-card"}
24
+ ]
25
+ },
26
+ "loan": {
27
+ "response": "شروط القرض تشمل الحد الأدنى للدخل (5000 جنيه سوداني) وتاريخ ائتماني جيد. نقدم أنواع مختلفة من القروض لتناسب احتياجاتك.",
28
+ "actions": [
29
+ {"label": "حاسبة القروض", "url": "https://onb.sd/loan-calculator"},
30
+ {"label": "تقديم طلب قرض", "url": "https://onb.sd/loan-application"}
31
+ ]
32
+ },
33
+ # ... other guideline entries similarly expanded
34
+ },
35
+ "en": {
36
+ "balance": {
37
+ "response": "You can check your balance online or via the ONB mobile app. We offer multiple convenient ways to monitor your account.",
38
+ "actions": [
39
+ {"label": "Mobile App", "url": "https://onb.sd/mobile-app"},
40
+ {"label": "Online Banking", "url": "https://onb.sd/online-banking"}
41
+ ]
42
+ },
43
+ "lost_card": {
44
+ "response": "In case of a lost card, call 249-123-456-789 immediately. We'll block the card and issue a new one to protect your funds.",
45
+ "actions": [
46
+ {"label": "Block Card Immediately", "url": "tel:249-123-456-789"},
47
+ {"label": "Request New Card", "url": "https://onb.sd/replace-card"}
48
+ ]
49
+ },
50
+ "loan": {
51
+ "response": "Loan requirements include minimum income (5000 SDG) and good credit history. We offer various loan types to suit your needs.",
52
+ "actions": [
53
+ {"label": "Loan Calculator", "url": "https://onb.sd/loan-calculator"},
54
+ {"label": "Apply for Loan", "url": "https://onb.sd/loan-application"}
55
+ ]
56
+ },
57
+ # ... other guideline entries similarly expanded
58
+ }
59
+ }
60
+
61
+ # Expanded menu with more descriptive options
62
+ MENU = {
63
+ "ar": """
64
+ 📱 قائمة الخدمات المصرفية المتقدمة:
65
+ 1️⃣ رصيد - تتبع حسابك بسهولة 💰
66
+ 2️⃣ بطاقة - الإبلاغ عن بطاقة مفقودة أو إيقافها 💳
67
+ 3️⃣ قرض - استكشف خيارات التمويل 💸
68
+ 4️⃣ تحويل - حوالات محلية ودولية 🌐
69
+ 5️⃣ حساب - فتح حساب جديد بخطوات مبسطة 📋
70
+ 6️⃣ فائدة - معرفة أحدث أسعار الفائدة 📈
71
+ 7️⃣ فرع - مواقع وعناوين الفروع 🏦
72
+ 8️⃣ ساعات - مواعيد العمل 🕒
73
+ 9️⃣ اتصال - قنوات التواصل المتاحة 📞
74
+ """,
75
+ "en": """
76
+ 📱 Advanced Banking Services Menu:
77
+ 1️⃣ Balance - Easily track your account 💰
78
+ 2️⃣ Card - Report or block lost card 💳
79
+ 3️⃣ Loan - Explore financing options 💸
80
+ 4️⃣ Transfer - Local and international transfers 🌐
81
+ 5️⃣ Account - Open a new account in simple steps 📋
82
+ 6️⃣ Interest - Latest interest rates 📈
83
+ 7️⃣ Branch - Locations and addresses 🏦
84
+ 8️⃣ Hours - Working hours 🕒
85
+ 9️⃣ Contact - Available communication channels 📞
86
+ """
87
+ }
88
+
89
+ # Enhanced intent keywords with more variations
90
+ INTENT_KEYWORDS = {
91
+ "balance": [
92
+ "balance", "check balance", "account balance", "how much",
93
+ "رصيد", "حساب", "كم المبلغ", "1", "مبلغ"
94
+ ],
95
+ "lost_card": [
96
+ "lost", "card", "stolen", "missing", "block",
97
+ "فقدت", "بطاقة", "مسروقة", "ضائعة", "إيقاف", "2"
98
+ ],
99
+ # ... other intents similarly expanded
100
+ }
101
+
102
+ def detect_language(text):
103
+ """Detect the language of the input text."""
104
+ try:
105
+ result = language_detector(text)
106
+ language = result[0]['label']
107
+ return language if language in ['ar', 'en'] else 'en'
108
+ except Exception:
109
+ return 'en'
110
+
111
+ def classify_intent(message: str):
112
+ """Classify user intent based on keywords."""
113
+ message_lower = message.lower()
114
+
115
+ # Check for menu request
116
+ menu_keywords = ["menu", "options", "help", "قائمة", "خيارات", "مساعدة"]
117
+ if any(keyword in message_lower for keyword in menu_keywords):
118
+ return "menu"
119
+
120
+ # Use keyword matching for intent classification
121
+ for intent_key, keywords in INTENT_KEYWORDS.items():
122
+ if any(keyword.lower() in message_lower for keyword in keywords):
123
+ return intent_key
124
+
125
+ return "unknown"
126
+
127
+ def generate_response(intent: str, language: str):
128
+ """Generate a comprehensive response with actions."""
129
+ if intent == "menu":
130
+ return {
131
+ "response": MENU[language],
132
+ "actions": []
133
  }
134
+
135
+ # Get the guideline for the specific intent and language
136
+ guideline = ONB_GUIDELINES.get(language, {}).get(intent, {
137
+ "response": "I'm sorry, I couldn't find specific information about this topic.",
138
+ "actions": []
139
+ })
140
+
141
+ return guideline
142
+
143
+ def generate_chat_response(message: str):
144
+ """Generate a comprehensive chat response."""
145
+ if not message.strip():
146
+ return {
147
+ "response": {
148
+ "ar": "الرجاء كتابة سؤالك.",
149
+ "en": "Please type your question."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  },
151
+ "actions": []
152
+ }
153
+
154
+ # Detect language
155
+ language = detect_language(message)
156
+
157
+ # Classify intent
158
+ intent = classify_intent(message)
159
+
160
+ # Generate response
161
+ response_data = generate_response(intent, language)
162
+
163
+ return {
164
+ "response": response_data['response'],
165
+ "actions": response_data.get('actions', []),
166
+ "language": language
167
+ }
168
+
169
+ # Custom CSS for enhanced UI
170
+ custom_css = """
171
+ .gradio-container {
172
+ font-family: 'Cairo', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
173
+ direction: rtl;
174
+ }
175
+
176
+ .chat-message {
177
+ padding: 1rem;
178
+ border-radius: 10px;
179
+ margin-bottom: 1rem;
180
+ max-width: 80%;
181
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
182
+ }
183
+
184
+ .user-message {
185
+ background-color: #e6f7ff;
186
+ margin-left: auto;
187
+ text-align: right;
188
+ direction: rtl;
189
+ }
190
+
191
+ .bot-message {
192
+ background-color: #f0f0f0;
193
+ margin-right: auto;
194
+ text-align: right;
195
+ direction: rtl;
196
+ }
197
+
198
+ .action-buttons {
199
+ display: flex;
200
+ flex-wrap: wrap;
201
+ gap: 0.5rem;
202
+ margin-top: 0.5rem;
203
+ }
204
+
205
+ .action-button {
206
+ background-color: #1a5276;
207
+ color: white;
208
+ border: none;
209
+ padding: 0.5rem 1rem;
210
+ border-radius: 5px;
211
+ text-decoration: none;
212
+ display: inline-block;
213
+ transition: background-color 0.3s ease;
214
+ }
215
+
216
+ .action-button:hover {
217
+ background-color: #2980b9;
218
+ }
219
+
220
+ .header-section {
221
+ background-color: #1a5276;
222
+ color: white;
223
+ padding: 1rem;
224
+ border-radius: 10px;
225
+ margin-bottom: 1rem;
226
+ text-align: center;
227
+ }
228
+
229
+ .footer-section {
230
+ font-size: 0.8rem;
231
+ text-align: center;
232
+ margin-top: 2rem;
233
+ color: #666;
234
+ }
235
+ """
236
+
237
+ # Enhanced Gradio Interface
238
+ def create_gradio_interface():
239
+ with gr.Blocks(css=custom_css, direction="rtl") as demo:
240
+ # Language selection
241
+ language_state = gr.State(value="ar")
242
+ language_btn = gr.Radio(
243
+ ["العربية", "English"],
244
+ value="العربية",
245
+ label="Language | اللغة"
246
+ )
247
 
248
+ # Chat interface
249
+ chatbot = gr.Chatbot(height=500)
250
+ msg = gr.Textbox(label="", placeholder="اكتب سؤالك هنا | Type your question here")
251
+ submit_btn = gr.Button("إرسال | Send")
252
 
253
+ # Action buttons container
254
+ action_container = gr.HTML()
 
 
255
 
256
+ # Update language state
257
+ def update_language(lang):
258
+ return "ar" if lang == "العربية" else "en"
 
 
259
 
260
+ language_btn.change(
261
+ fn=update_language,
262
+ inputs=language_btn,
263
+ outputs=language_state
264
+ )
 
 
 
 
265
 
266
+ # Chat submission handler
267
+ def submit_message(message, chat_history, language):
268
+ # Generate response
269
+ response_data = generate_chat_response(message)
270
+
271
+ # Ensure we're using the correct language
272
+ if response_data['language'] != language:
273
+ language = response_data['language']
274
+
275
+ # Update chat history
276
+ chat_history.append((message, response_data['response']))
277
+
278
+ # Prepare action buttons HTML
279
+ action_html = ""
280
+ if response_data.get('actions'):
281
+ action_html = "<div class='action-buttons'>"
282
+ for action in response_data['actions']:
283
+ action_html += f"""
284
+ <a href="{action['url']}"
285
+ class="action-button"
286
+ target="_blank">
287
+ {action['label']}
288
+ </a>
289
+ """
290
+ action_html += "</div>"
291
+
292
+ return "", chat_history, action_html
293
 
294
+ # Wire up the interface
295
+ submit_btn.click(
296
+ fn=submit_message,
297
+ inputs=[msg, chatbot, language_state],
298
+ outputs=[msg, chatbot, action_container]
299
+ )
300
 
301
+ msg.submit(
302
+ fn=submit_message,
303
+ inputs=[msg, chatbot, language_state],
304
+ outputs=[msg, chatbot, action_container]
305
+ )
 
 
 
 
 
 
 
 
 
 
306
 
307
+ # Add menu button
308
+ menu_btn = gr.Button("إظهار القائمة | Show Menu")
 
 
 
 
309
 
310
+ def show_menu(chat_history, language):
311
+ menu_text = MENU[language]
312
+ chat_history.append((None, menu_text))
313
+ return chat_history
 
 
 
 
 
 
314
 
315
+ menu_btn.click(
316
+ fn=show_menu,
317
+ inputs=[chatbot, language_state],
318
+ outputs=[chatbot]
319
+ )
320
 
321
+ # Header and footer
322
+ with gr.Row(elem_classes="header-section"):
323
+ gr.Markdown("# Omdurman National Bank | بنك أم درمان الوطني")
324
+ gr.Markdown("### Virtual Banking Assistant | المساعد المصرفي الافتراضي")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
 
326
+ with gr.Row(elem_classes="footer-section"):
327
+ gr.Markdown("© 2025 Omdurman National Bank. All Rights Reserved. | جميع الحقوق محفوظة لبنك أم درمان الوطني ٢٠٢٥ ©")
328
+
329
+ return demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
 
331
+ # Launch the application
332
  if __name__ == "__main__":
333
+ demo = create_gradio_interface()
334
+ demo.launch(
335
+ server_name="0.0.0.0",
336
+ server_port=7860,
337
+ share=True
338
+ )