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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +215 -293
app.py CHANGED
@@ -1,305 +1,227 @@
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
- )
 
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()