Abs6187 commited on
Commit
4fcf028
ยท
verified ยท
1 Parent(s): c5a7400

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +246 -280
app.py CHANGED
@@ -1,280 +1,246 @@
1
- import gradio as gr
2
- import joblib
3
- import pandas as pd
4
- import numpy as np
5
- import os
6
- from PIL import Image
7
-
8
- # Load models and encoders
9
- def load_models():
10
- try:
11
- model = joblib.load('models/churn_model.pkl')
12
- encoders = joblib.load('models/label_encoders.pkl')
13
- try:
14
- scaler = joblib.load('models/scaler.pkl')
15
- except:
16
- scaler = None
17
- return model, encoders, scaler
18
- except Exception as e:
19
- print(f"Error loading models: {e}")
20
- return None, None, None
21
-
22
- model, encoders, scaler = load_models()
23
-
24
- # Define feature options based on the training data
25
- REGIONS = ['North', 'South', 'East', 'West', 'Central']
26
- PLAN_TYPES = ['Prepaid', 'Postpaid']
27
- CONTRACT_TYPES = ['Month-to-month', 'One year', 'Two year']
28
- COMPLAINT_STATUS = ['Open', 'Closed', 'Not Applicable']
29
-
30
- def predict_churn(customer_id, region, plan_type, monthly_charges, total_charges,
31
- tenure_months, contract_type, paperless_billing, payment_method,
32
- data_usage_gb, call_minutes, sms_count, complaint_status, complaint_count):
33
-
34
- if model is None:
35
- return "Model not loaded properly", 0.0
36
-
37
- try:
38
- # Create input dataframe
39
- input_data = pd.DataFrame({
40
- 'customer_id': [customer_id],
41
- 'region': [region],
42
- 'plan_type': [plan_type],
43
- 'monthly_charges': [monthly_charges],
44
- 'total_charges': [total_charges],
45
- 'tenure_months': [tenure_months],
46
- 'contract_type': [contract_type],
47
- 'paperless_billing': [1 if paperless_billing else 0],
48
- 'payment_method': [payment_method],
49
- 'data_usage_gb': [data_usage_gb],
50
- 'call_minutes': [call_minutes],
51
- 'sms_count': [sms_count],
52
- 'complaint_status': [complaint_status],
53
- 'complaint_count': [complaint_count]
54
- })
55
-
56
- # Encode categorical variables
57
- categorical_columns = ['region', 'plan_type', 'contract_type', 'payment_method', 'complaint_status']
58
-
59
- for col in categorical_columns:
60
- if col in encoders:
61
- try:
62
- input_data[col] = encoders[col].transform(input_data[col])
63
- except ValueError:
64
- # Handle unseen labels by using the most frequent class
65
- input_data[col] = 0
66
-
67
- # Drop customer_id for prediction
68
- prediction_data = input_data.drop(['customer_id'], axis=1)
69
-
70
- # Scale features if scaler exists
71
- if scaler is not None:
72
- prediction_data = scaler.transform(prediction_data)
73
-
74
- # Make prediction
75
- churn_probability = model.predict_proba(prediction_data)[0][1]
76
- churn_prediction = "HIGH RISK" if churn_probability > 0.5 else "LOW RISK"
77
-
78
- # Create detailed result
79
- risk_level = "๐Ÿ”ด HIGH RISK" if churn_probability > 0.7 else "๐ŸŸก MEDIUM RISK" if churn_probability > 0.4 else "๐ŸŸข LOW RISK"
80
-
81
- result = f"""
82
- **Prediction Result for Customer {customer_id}**
83
-
84
- **Churn Risk:** {risk_level}
85
- **Churn Probability:** {churn_probability:.1%}
86
- **Recommendation:** {'Immediate retention action required' if churn_probability > 0.7 else 'Monitor and engage' if churn_probability > 0.4 else 'Standard service maintenance'}
87
- """
88
-
89
- return result, churn_probability
90
-
91
- except Exception as e:
92
- return f"Error in prediction: {str(e)}", 0.0
93
-
94
- def load_image(image_name):
95
- """Load and return image from the images folder"""
96
- try:
97
- img_path = f"images/{image_name}"
98
- if os.path.exists(img_path):
99
- return Image.open(img_path)
100
- else:
101
- return None
102
- except Exception as e:
103
- print(f"Error loading image {image_name}: {e}")
104
- return None
105
-
106
- # Create Gradio interface
107
- with gr.Blocks(title="Telecom Churn Prediction - BRBRAITT Group 5", theme=gr.themes.Soft()) as app:
108
-
109
- # Header
110
- gr.Markdown("""
111
- # ๐Ÿ”ฎ Telecom Churn Prediction System
112
-
113
- **TIRTC Course: Advance AI/ML Training - Telecom Data Analytics (Nokia)**
114
- **Institution:** BRBRAITT, Jabalpur
115
-
116
- **Group 5 Members:**
117
- - Abhay Gupta
118
- - Jay Kumar
119
- - Kripanshu Gupta
120
- - Ruhy Namdeo
121
-
122
- ---
123
-
124
- This AI-powered system predicts customer churn with **90% accuracy** using Random Forest ML model.
125
- """)
126
-
127
- with gr.Tabs():
128
-
129
- # Tab 1: Prediction Interface
130
- with gr.TabItem("๐ŸŽฏ Churn Prediction"):
131
- gr.Markdown("### Enter Customer Details for Churn Prediction")
132
-
133
- with gr.Row():
134
- with gr.Column():
135
- customer_id = gr.Textbox(label="Customer ID", placeholder="e.g., CUST001", value="CUST001")
136
- region = gr.Dropdown(choices=REGIONS, label="Region", value="North")
137
- plan_type = gr.Dropdown(choices=PLAN_TYPES, label="Plan Type", value="Postpaid")
138
- contract_type = gr.Dropdown(choices=CONTRACT_TYPES, label="Contract Type", value="Month-to-month")
139
-
140
- with gr.Column():
141
- monthly_charges = gr.Number(label="Monthly Charges (โ‚น)", value=1000, minimum=0)
142
- total_charges = gr.Number(label="Total Charges (โ‚น)", value=12000, minimum=0)
143
- tenure_months = gr.Number(label="Tenure (Months)", value=12, minimum=0, maximum=120)
144
- paperless_billing = gr.Checkbox(label="Paperless Billing", value=True)
145
-
146
- with gr.Column():
147
- payment_method = gr.Dropdown(choices=['Electronic check', 'Mailed check', 'Bank transfer', 'Credit card'],
148
- label="Payment Method", value="Electronic check")
149
- data_usage_gb = gr.Number(label="Data Usage (GB)", value=15, minimum=0)
150
- call_minutes = gr.Number(label="Call Minutes", value=500, minimum=0)
151
- sms_count = gr.Number(label="SMS Count", value=100, minimum=0)
152
-
153
- with gr.Row():
154
- complaint_status = gr.Dropdown(choices=COMPLAINT_STATUS, label="Complaint Status", value="Not Applicable")
155
- complaint_count = gr.Number(label="Complaint Count", value=0, minimum=0)
156
-
157
- predict_btn = gr.Button("๐Ÿ”ฎ Predict Churn Risk", variant="primary", size="lg")
158
-
159
- with gr.Row():
160
- prediction_output = gr.Markdown()
161
- probability_gauge = gr.Number(label="Churn Probability", interactive=False)
162
-
163
- predict_btn.click(
164
- fn=predict_churn,
165
- inputs=[customer_id, region, plan_type, monthly_charges, total_charges,
166
- tenure_months, contract_type, paperless_billing, payment_method,
167
- data_usage_gb, call_minutes, sms_count, complaint_status, complaint_count],
168
- outputs=[prediction_output, probability_gauge]
169
- )
170
-
171
- # Tab 2: Business Insights
172
- with gr.TabItem("๐Ÿ“Š Business Insights"):
173
- gr.Markdown("### Key Findings from Analysis")
174
-
175
- insights = gr.Markdown("""
176
- ## ๐ŸŽฏ Model Performance
177
- - **Accuracy:** 90%
178
- - **AUC Score:** 0.95
179
- - **Best Algorithm:** Random Forest Classifier
180
-
181
- ## ๐Ÿ’ผ Business Impact
182
- - **Current Churn Rate:** 50%
183
- - **Revenue at Risk:** โ‚น12,250+ monthly
184
- - **Annual Loss:** โ‚น147,000+ potential
185
- - **Savings Opportunity:** โ‚น36,750+ with 25% churn reduction
186
-
187
- ## ๐Ÿ”ด Top Risk Factors
188
- 1. **Contract Type:** Month-to-month customers (100% churn rate)
189
- 2. **Tenure:** New customers (0-12 months) at highest risk
190
- 3. **Complaints:** Open complaints double churn likelihood
191
- 4. **Plan Type:** Significant differences between Prepaid/Postpaid
192
-
193
- ## ๐Ÿ“ˆ Recommendations
194
- ### Immediate Actions
195
- - Target month-to-month customers for contract upgrades
196
- - Implement 90-day new customer check-in program
197
- - Prioritize complaint resolution within 48 hours
198
-
199
- ### Long-term Strategy
200
- - Deploy real-time churn scoring system
201
- - Implement tiered retention programs
202
- - A/B test retention campaigns
203
- """)
204
-
205
- # Tab 3: Visualizations
206
- with gr.TabItem("๐Ÿ“ˆ Data Visualizations"):
207
- gr.Markdown("### Comprehensive Analysis Dashboard")
208
-
209
- # Load and display images
210
- image_files = [
211
- ("churn_distribution.png", "Overall Churn Distribution"),
212
- ("churn_by_contract.png", "Churn by Contract Type"),
213
- ("churn_by_plan.png", "Churn by Plan Type"),
214
- ("churn_by_region.png", "Regional Churn Analysis"),
215
- ("tenure_vs_churn.png", "Tenure vs Churn Pattern"),
216
- ("revenue_vs_churn.png", "Revenue Impact Analysis"),
217
- ("complaints_analysis.png", "Complaints Impact on Churn"),
218
- ("correlation_matrix.png", "Feature Correlation Matrix"),
219
- ("feature_coefficients.png", "Model Feature Importance")
220
- ]
221
-
222
- for img_file, title in image_files:
223
- img = load_image(img_file)
224
- if img is not None:
225
- with gr.Row():
226
- gr.Markdown(f"#### {title}")
227
- with gr.Row():
228
- gr.Image(img, label=title, show_label=False)
229
- else:
230
- gr.Markdown(f"*{title} - Image not available*")
231
-
232
- # Tab 4: About Project
233
- with gr.TabItem("โ„น๏ธ About Project"):
234
- gr.Markdown("""
235
- ## ๐ŸŽ“ Academic Project Details
236
-
237
- **Course:** TIRTC - Advance AI/ML Training - Telecom Data Analytics (Nokia)
238
- **Institution:** BRBRAITT (Bharat Ratna Bhimrao Ambedkar Institute of Technology and Training), Jabalpur
239
- **Project Type:** Capstone Project 1
240
-
241
- ### ๐Ÿ‘ฅ Team Members (Group 5)
242
- - **Abhay Gupta**
243
- - **Jay Kumar**
244
- - **Kripanshu Gupta**
245
- - **Ruhy Namdeo**
246
-
247
- ### ๐Ÿ› ๏ธ Technical Stack
248
- - **Machine Learning:** scikit-learn, Random Forest Classifier
249
- - **Data Processing:** pandas, numpy
250
- - **Visualization:** matplotlib, seaborn
251
- - **Interface:** Gradio
252
- - **Deployment:** Hugging Face Spaces
253
-
254
- ### ๐Ÿ“ˆ Project Scope
255
- This end-to-end machine learning project demonstrates:
256
- - Data engineering and ETL pipeline
257
- - Advanced ML model development
258
- - Business intelligence and insights generation
259
- - Production deployment capabilities
260
-
261
- ### ๐ŸŽฏ Learning Outcomes
262
- - Real-world problem solving in telecom domain
263
- - Complete ML pipeline implementation
264
- - Business value creation through AI/ML
265
- - Model deployment and productionization
266
-
267
- ---
268
-
269
- **๐Ÿ† Project Status:** Complete | **๐Ÿ“… Last Updated:** October 2024 | **๐Ÿ”ข Version:** 1.0.0
270
- """)
271
-
272
- # Footer
273
- gr.Markdown("""
274
- ---
275
- **ยฉ 2024 BRBRAITT Group 5 | TIRTC Advance AI/ML Training | Telecom Data Analytics**
276
- """)
277
-
278
- # Launch the app
279
- if __name__ == "__main__":
280
- app.launch(share=True, server_name="0.0.0.0", server_port=7860)
 
1
+ import gradio as gr
2
+ import joblib
3
+ import pandas as pd
4
+ import numpy as np
5
+ import os
6
+ from PIL import Image
7
+ import google.generativeai as genai
8
+
9
+ # --- Gemini API Configuration ---
10
+ # IMPORTANT: Set your GOOGLE_API_KEY as an environment variable
11
+ # For local testing, you can uncomment the line below and paste your key
12
+ # os.environ['GOOGLE_API_KEY'] = "YOUR_GOOGLE_API_KEY"
13
+
14
+ try:
15
+ GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')
16
+ if GOOGLE_API_KEY:
17
+ genai.configure(api_key=GOOGLE_API_KEY)
18
+ else:
19
+ print("Warning: GOOGLE_API_KEY not found. Gemini error handling will be disabled.")
20
+ except Exception as e:
21
+ print(f"Error configuring Gemini: {e}")
22
+
23
+ # --- Model and Asset Loading ---
24
+
25
+ def load_models():
26
+ """Loads the ML model, encoders, and scaler from disk."""
27
+ try:
28
+ model = joblib.load('models/churn_model.pkl')
29
+ encoders = joblib.load('models/label_encoders.pkl')
30
+ scaler = joblib.load('models/scaler.pkl')
31
+ return model, encoders, scaler
32
+ except FileNotFoundError:
33
+ print("Error: Model files not found. Please ensure 'churn_model.pkl', 'label_encoders.pkl', and 'scaler.pkl' are in the 'models/' directory.")
34
+ return None, None, None
35
+ except Exception as e:
36
+ print(f"An unexpected error occurred while loading models: {e}")
37
+ return None, None, None
38
+
39
+ model, encoders, scaler = load_models()
40
+
41
+ def load_image(image_name):
42
+ """Loads an image from the 'images' folder."""
43
+ try:
44
+ img_path = os.path.join("images", image_name)
45
+ return Image.open(img_path) if os.path.exists(img_path) else None
46
+ except Exception as e:
47
+ print(f"Error loading image {image_name}: {e}")
48
+ return None
49
+
50
+ # --- Feature Constants ---
51
+ REGIONS = ['North', 'South', 'East', 'West', 'Central']
52
+ PLAN_TYPES = ['Prepaid', 'Postpaid']
53
+ CONTRACT_TYPES = ['Month-to-month', 'One year', 'Two year']
54
+ COMPLAINT_STATUS = ['Open', 'Closed', 'Not Applicable']
55
+ PAYMENT_METHODS = ['Electronic check', 'Mailed check', 'Bank transfer', 'Credit card']
56
+
57
+ # --- Prediction Logic ---
58
+
59
+ def predict_churn(customer_id, region, plan_type, monthly_charges, total_charges,
60
+ tenure_months, contract_type, paperless_billing, payment_method,
61
+ data_usage_gb, call_minutes, sms_count, complaint_status, complaint_count):
62
+ """Predicts customer churn and generates a detailed result."""
63
+ if model is None or encoders is None or scaler is None:
64
+ return "๐Ÿ”ด **Error:** Model components are not loaded. Please check the server logs.", 0.0
65
+
66
+ try:
67
+ # 1. Create Input DataFrame
68
+ input_data = pd.DataFrame({
69
+ 'region': [region],
70
+ 'plan_type': [plan_type],
71
+ 'monthly_charges': [float(monthly_charges)],
72
+ 'total_charges': [float(total_charges)],
73
+ 'tenure_months': [int(tenure_months)],
74
+ 'contract_type': [contract_type],
75
+ 'paperless_billing': [1 if paperless_billing else 0],
76
+ 'payment_method': [payment_method],
77
+ 'data_usage_gb': [float(data_usage_gb)],
78
+ 'call_minutes': [int(call_minutes)],
79
+ 'sms_count': [int(sms_count)],
80
+ 'complaint_status': [complaint_status],
81
+ 'complaint_count': [int(complaint_count)]
82
+ })
83
+
84
+ # 2. Encode Categorical Features
85
+ for col, encoder in encoders.items():
86
+ if col in input_data.columns:
87
+ input_data[col] = input_data[col].apply(lambda x: encoder.transform([x])[0] if x in encoder.classes_ else -1)
88
+
89
+ # 3. Scale Numerical Features
90
+ scaled_data = scaler.transform(input_data)
91
+
92
+ # 4. Make Prediction
93
+ churn_probability = model.predict_proba(scaled_data)[0][1]
94
+
95
+ # 5. Format Output
96
+ if churn_probability > 0.7:
97
+ risk_level = "๐Ÿ”ด HIGH RISK"
98
+ recommendation = "Immediate retention action is strongly recommended."
99
+ elif churn_probability > 0.4:
100
+ risk_level = "๐ŸŸก MEDIUM RISK"
101
+ recommendation = "Proactively monitor and engage with personalized offers."
102
+ else:
103
+ risk_level = "๐ŸŸข LOW RISK"
104
+ recommendation = "Standard service and relationship maintenance."
105
+
106
+ result = f"""
107
+ ### Prediction for Customer `{customer_id}`
108
+ - **Churn Risk Level:** **{risk_level}**
109
+ - **Probability of Churn:** **{churn_probability:.1%}**
110
+ - **Recommendation:** {recommendation}
111
+ """
112
+ return result, churn_probability
113
+
114
+ except Exception as e:
115
+ # --- Gemini Error Handling ---
116
+ print(f"Prediction error: {e}") # Log the real error for debugging
117
+ if GOOGLE_API_KEY:
118
+ try:
119
+ # UPDATED to use the faster Flash model
120
+ gemini_model = genai.GenerativeModel('gemini-2.5-flash')
121
+ prompt = f"""
122
+ An error occurred in a telecom churn prediction app. The technical error was: '{str(e)}'.
123
+ Generate a concise, friendly, non-technical message for the user.
124
+ The message should suggest they double-check their inputs (like ensuring Total Charges are not less than Monthly Charges) and try again.
125
+ Do not mention the technical error details. Start with 'Oops! Something went wrong.'
126
+ """
127
+ response = gemini_model.generate_content(prompt)
128
+ return response.text, 0.0
129
+ except Exception as gemini_e:
130
+ print(f"Gemini API error: {gemini_e}") # Log Gemini error
131
+ return "An unexpected error occurred. Please verify your inputs and try again.", 0.0
132
+ else:
133
+ return "An unexpected error occurred. Please check your inputs are valid and try again.", 0.0
134
+
135
+
136
+ # --- Gradio UI ---
137
+
138
+ with gr.Blocks(title="Telecom Churn Prediction - BRBRAITT Group 5", theme=gr.themes.Soft()) as app:
139
+ # Header
140
+ gr.Markdown("""
141
+ # ๐Ÿ”ฎ Telecom Churn Prediction System
142
+ **TIRTC Course: Advance AI/ML Training (Nokia) | Institution: BRBRAITT, Jabalpur | Group 5**
143
+ ---
144
+ This AI-powered system predicts customer churn with over **90% accuracy** using a Random Forest model.
145
+ """)
146
+
147
+ with gr.Tabs():
148
+ # Tab 1: Prediction Interface
149
+ with gr.TabItem("๐ŸŽฏ Churn Prediction"):
150
+ with gr.Row():
151
+ with gr.Column(scale=2):
152
+ gr.Markdown("### Enter Customer Details")
153
+ with gr.Row():
154
+ customer_id = gr.Textbox(label="Customer ID", value="CUST-001")
155
+ region = gr.Dropdown(choices=REGIONS, label="Region", value="North")
156
+ plan_type = gr.Dropdown(choices=PLAN_TYPES, label="Plan Type", value="Postpaid")
157
+ with gr.Row():
158
+ contract_type = gr.Dropdown(choices=CONTRACT_TYPES, label="Contract Type", value="Month-to-month")
159
+ payment_method = gr.Dropdown(choices=PAYMENT_METHODS, label="Payment Method", value="Electronic check")
160
+ paperless_billing = gr.Checkbox(label="Paperless Billing", value=True)
161
+ gr.Markdown("#### Service Usage & Charges")
162
+ with gr.Row():
163
+ monthly_charges = gr.Number(label="Monthly Charges (โ‚น)", value=1000)
164
+ total_charges = gr.Number(label="Total Charges (โ‚น)", value=12000)
165
+ tenure_months = gr.Number(label="Tenure (Months)", value=12)
166
+ with gr.Row():
167
+ data_usage_gb = gr.Number(label="Data Usage (GB)", value=15)
168
+ call_minutes = gr.Number(label="Call Minutes", value=500)
169
+ sms_count = gr.Number(label="SMS Count", value=100)
170
+ gr.Markdown("#### Customer Complaints")
171
+ with gr.Row():
172
+ complaint_status = gr.Dropdown(choices=COMPLAINT_STATUS, label="Last Complaint Status", value="Not Applicable")
173
+ complaint_count = gr.Number(label="Total Complaint Count", value=0)
174
+
175
+ predict_btn = gr.Button("๐Ÿ”ฎ Predict Churn Risk", variant="primary", size="lg")
176
+
177
+ with gr.Column(scale=1):
178
+ gr.Markdown("### ๐Ÿ“Š Prediction Result")
179
+ prediction_output = gr.Markdown(value="*Results will be displayed here...*")
180
+ probability_gauge = gr.Gauge(label="Churn Probability", value=0.0, show_label=True)
181
+
182
+ predict_btn.click(
183
+ fn=predict_churn,
184
+ inputs=[customer_id, region, plan_type, monthly_charges, total_charges,
185
+ tenure_months, contract_type, paperless_billing, payment_method,
186
+ data_usage_gb, call_minutes, sms_count, complaint_status, complaint_count],
187
+ outputs=[prediction_output, probability_gauge]
188
+ )
189
+
190
+ # Tab 2: Business Insights
191
+ with gr.TabItem("๐Ÿ’ก Business Insights"):
192
+ gr.Markdown("### Key Findings & Recommendations")
193
+ gr.Markdown("""
194
+ #### ๐ŸŽฏ Model Performance
195
+ - **Accuracy:** 90%
196
+ - **AUC Score:** 0.95
197
+ - **Best Algorithm:** Random Forest Classifier
198
+
199
+ #### ๐Ÿ’ผ Business Impact
200
+ - **Current Churn Rate:** 50% in the sample dataset.
201
+ - **Monthly Revenue at Risk:** Over โ‚น12,250.
202
+ - **Potential Annual Loss:** Over โ‚น147,000.
203
+ - **Savings Opportunity:** A 25% reduction in churn could save over โ‚น36,750 annually.
204
+
205
+ #### ๐Ÿ”ด Top Churn Drivers
206
+ 1. **Contract Type:** `Month-to-month` customers have a near 100% churn rate in high-risk groups.
207
+ 2. **Tenure:** New customers (0-12 months) are most likely to churn.
208
+ 3. **Complaints:** A single open complaint doubles the likelihood of churn.
209
+ """)
210
+
211
+ # Tab 3: Visualizations
212
+ with gr.TabItem("๐Ÿ“ˆ Visualizations"):
213
+ gr.Markdown("### Data Analysis Dashboard")
214
+ image_files = [
215
+ ("churn_distribution.png", "Overall Churn Distribution"),
216
+ ("churn_by_contract.png", "Churn by Contract Type"),
217
+ ("revenue_vs_churn.png", "Revenue Impact Analysis"),
218
+ ("complaints_analysis.png", "Complaints Impact on Churn"),
219
+ ("correlation_matrix.png", "Feature Correlation Matrix"),
220
+ ]
221
+ for img_file, title in image_files:
222
+ img = load_image(img_file)
223
+ if img:
224
+ gr.Image(img, label=title, show_label=True)
225
+ else:
226
+ gr.Markdown(f"*{title} - Image not available*")
227
+
228
+ # Tab 4: About Project (UPDATED YEAR)
229
+ with gr.TabItem("โ„น๏ธ About"):
230
+ gr.Markdown("""
231
+ ### ๐ŸŽ“ Academic Project Details
232
+ - **Course:** TIRTC - Advance AI/ML Training (Nokia)
233
+ - **Institution:** BRBRAITT, Jabalpur
234
+ - **Project:** Capstone Project 1
235
+ - **Team (Group 5):** Abhay Gupta, Jay Kumar, Kripanshu Gupta, Ruhy Namdeo
236
+ - **Tech Stack:** Scikit-learn, Pandas, Gradio, Gemini, Hugging Face
237
+ ---
238
+ **๐Ÿ† Project Status:** Complete | **๐Ÿ“… Last Updated:** October 2025 | **๐Ÿ”ข Version:** 1.1.0
239
+ """)
240
+
241
+ # Footer (UPDATED YEAR)
242
+ gr.Markdown("--- \n ยฉ 2025 BRBRAITT Group 5 | TIRTC Advance AI/ML Training")
243
+
244
+ # Launch the app
245
+ if __name__ == "__main__":
246
+ app.launch(share=True)