File size: 9,374 Bytes
ec11884
0c8a0f0
9367294
0bb3508
 
9367294
 
 
 
edd8287
e83c95e
 
 
9367294
 
38447bb
cd2bc8b
 
 
 
 
 
 
 
 
 
9367294
 
 
 
 
 
 
 
 
 
 
 
 
0bb3508
9367294
 
 
 
 
 
 
 
 
 
d4efbd1
9906480
0c8a0f0
e83c95e
 
 
 
0c8a0f0
9367294
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0bb3508
9906480
9367294
 
 
 
 
 
0c8a0f0
 
 
9367294
 
 
 
 
 
0c8a0f0
9367294
 
 
 
 
0bb3508
 
 
9367294
 
 
 
 
 
 
 
 
b9f9e30
9367294
4600387
9367294
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
967751a
9367294
 
 
 
 
 
 
 
 
 
cd2bc8b
9367294
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9906480
9367294
 
e1f9a88
9367294
 
9906480
9367294
 
9906480
9367294
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ec11884
 
549f4f9
cd2bc8b
 
 
b9f9e30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
import gradio as gr
from transformers import pipeline
import re

# Load Arabic NLP model for intent classification
intent_classifier_ar = pipeline("text-classification", model="aubmindlab/bert-base-arabertv02")

# Load English NLP model for intent classification
intent_classifier_en = pipeline("text-classification", model="facebook/bart-large-mnli")

# Load language detection model
language_detector = pipeline("text-classification", model="papluca/xlm-roberta-base-language-detection")

# Omdurman National Bank-specific guidelines in Arabic
ONB_GUIDELINES_AR = {
    "balance": "يمكنك التحقق من رصيدك عبر الإنترنت أو عبر تطبيق الهاتف الخاص ببنك الوطني.",
    "lost_card": "في حالة فقدان البطاقة، اتصل بالرقم 249-123-456-789 فورًا.",
    "loan": "شروط القرض تشمل الحد الأدنى للدخل (5000 جنيه سوداني) وتاريخ ائتماني جيد.",
    "transfer": "لتحويل الأموال، استخدم تطبيق الهاتف أو الخدمة المصرفية عبر الإنترنت.",
    "new_account": "لفتح حساب جديد، قم بزيارة أقرب فرع مع جواز سفرك أو هويتك الوطنية.",
    "interest_rates": "أسعار الفائدة على الودائع تتراوح بين 5% إلى 10% سنويًا.",
    "branches": "فروعنا موجودة في أم درمان، الخرطوم، وبورتسودان. زيارة موقعنا للتفاصيل.",
    "working_hours": "ساعات العمل من 8 صباحًا إلى 3 مساءً من الأحد إلى الخميس.",
    "contact": "الاتصال بنا على الرقم 249-123-456-789 أو عبر البريد الإلكتروني [email protected]."
}

# Omdurman National Bank-specific guidelines in English
ONB_GUIDELINES_EN = {
    "balance": "You can check your balance online or via the ONB mobile app.",
    "lost_card": "In case of a lost card, call 249-123-456-789 immediately.",
    "loan": "Loan requirements include minimum income (5000 SDG) and good credit history.",
    "transfer": "To transfer funds, use the mobile app or online banking service.",
    "new_account": "To open a new account, visit your nearest branch with your passport or national ID.",
    "interest_rates": "Interest rates on deposits range from 5% to 10% annually.",
    "branches": "Our branches are located in Omdurman, Khartoum, and Port Sudan. Visit our website for details.",
    "working_hours": "Working hours are from 8 AM to 3 PM, Sunday to Thursday.",
    "contact": "Contact us at 249-123-456-789 or via email at [email protected]."
}

# Map intents to responses
INTENT_KEYWORDS = {
    "balance": ["balance", "رصيد", "حساب"],
    "lost_card": ["lost", "card", "stolen", "فقدت", "بطاقة", "مسروقة"],
    "loan": ["loan", "borrow", "قرض", "استدانة"],
    "transfer": ["transfer", "send money", "تحويل", "ارسال"],
    "new_account": ["account", "open", "حساب", "فتح"],
    "interest_rates": ["interest", "rate", "فائدة", "نسبة"],
    "branches": ["branch", "location", "فرع", "موقع"],
    "working_hours": ["hours", "time", "ساعات", "وقت"],
    "contact": ["contact", "phone", "email", "اتصال", "هاتف", "بريد"]
}

def detect_language(text):
    # Use Hugging Face language detection model
    result = language_detector(text)
    language = result[0]['label']
    return language

def classify_intent(message: str, language: str):
    # Use appropriate classifier based on language
    if language == "ar":
        # For Arabic
        result = intent_classifier_ar(message)
        intent = result[0]['label']
    else:
        # For English
        result = intent_classifier_en(message, candidate_labels=list(INTENT_KEYWORDS.keys()))
        intent = result["labels"][0]
    
    # Fallback to keyword matching
    if intent not in INTENT_KEYWORDS:
        for intent_key, keywords in INTENT_KEYWORDS.items():
            for keyword in keywords:
                if re.search(r'\b' + re.escape(keyword.lower()) + r'\b', message.lower()):
                    return intent_key
        return "unknown"
    
    return intent

def respond(message: str):
    if not message.strip():
        return {
            "ar": "الرجاء كتابة سؤالك.",
            "en": "Please type your question."
        }
    
    # Detect language
    language = detect_language(message)
    
    # If the language is neither Arabic nor English, default to English
    if language != "ar" and language != "en":
        language = "en"
    
    # Classify the user's intent
    intent = classify_intent(message, language)
    
    # Prepare responses in both languages
    responses = {
        "ar": "",
        "en": ""
    }
    
    # If intent is recognized, return the corresponding response
    if intent != "unknown":
        responses["ar"] = ONB_GUIDELINES_AR.get(intent, "عذرًا، لم يتم التعرف على الخيار المحدد.")
        responses["en"] = ONB_GUIDELINES_EN.get(intent, "Sorry, the selected option was not recognized.")
    else:
        # Default response if no intent is matched
        ar_options = ", ".join(list(ONB_GUIDELINES_AR.keys()))
        en_options = ", ".join(list(ONB_GUIDELINES_EN.keys()))
        
        responses["ar"] = f"عذرًا، لم أفهم سؤالك. الرجاء إعادة الصياغة أو اختيار أحد الخيارات التالية: {ar_options}"
        responses["en"] = f"Sorry, I didn't understand your question. Please rephrase or choose one of the following options: {en_options}"
    
    return responses

# Custom CSS for better UI
custom_css = """
.gradio-container {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

.chat-message {
    padding: 1rem;
    border-radius: 10px;
    margin-bottom: 1rem;
    max-width: 80%;
}

.user-message {
    background-color: #e6f7ff;
    margin-left: auto;
    text-align: right;
}

.bot-message {
    background-color: #f0f0f0;
    margin-right: auto;
    text-align: left;
}

.bot-message-ar {
    background-color: #f0f0f0;
    margin-left: auto;
    text-align: right;
}

.header-section {
    background-color: #1a5276;
    color: white;
    padding: 1rem;
    border-radius: 10px;
    margin-bottom: 1rem;
    text-align: center;
}

.footer-section {
    font-size: 0.8rem;
    text-align: center;
    margin-top: 2rem;
    color: #666;
}

.lang-selector {
    text-align: right;
    margin-bottom: 1rem;
}
"""

# Chat interface with enhanced UI
with gr.Blocks(css=custom_css) as demo:
    # Store conversation history
    state = gr.State(value=[])
    # Store selected language
    selected_lang = gr.State(value="ar")
    
    with gr.Row(elem_classes="header-section"):
        with gr.Column():
            gr.Markdown("# Omdurman National Bank | بنك أم درمان الوطني")
            gr.Markdown("### Virtual Banking Assistant | المساعد المصرفي الافتراضي")
    
    with gr.Row():
        with gr.Column(elem_classes="lang-selector"):
            language_btn = gr.Radio(
                ["العربية", "English"], 
                value="العربية", 
                label="Language | اللغة"
            )
    
    with gr.Row():
        chat_box = gr.Chatbot(elem_id="chatbox", height=400)
    
    with gr.Row():
        with gr.Column(scale=8):
            text_input = gr.Textbox(
                placeholder="Type your question here | اكتب سؤالك هنا", 
                label="", 
                elem_id="chat-input"
            )
        with gr.Column(scale=1):
            submit_btn = gr.Button("Send | إرسال", variant="primary")
    
    with gr.Row(elem_classes="footer-section"):
        gr.Markdown("© 2025 Omdurman National Bank. All Rights Reserved. | جميع الحقوق محفوظة لبنك أم درمان الوطني ٢٠٢٥ ©")
    
    # Update language state when language is changed
    def update_language(lang):
        if lang == "العربية":
            return "ar"
        else:
            return "en"
    
    language_btn.change(
        fn=update_language,
        inputs=language_btn,
        outputs=selected_lang
    )
    
    # Handle message submission
    def on_submit(message, chat_history, lang):
        if not message.strip():
            return "", chat_history
        
        # Add user message to chat history
        chat_history.append([message, None])
        
        # Get response
        responses = respond(message)
        
        # Select response based on language
        response = responses[lang]
        
        # Update bot response in chat history
        chat_history[-1][1] = response
        
        return "", chat_history
    
    # Link inputs and button to response function
    submit_btn.click(
        fn=on_submit,
        inputs=[text_input, chat_box, selected_lang],
        outputs=[text_input, chat_box]
    )
    
    # Also trigger on Enter key
    text_input.submit(
        fn=on_submit,
        inputs=[text_input, chat_box, selected_lang],
        outputs=[text_input, chat_box]
    )

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