muhalwan commited on
Commit
0279df1
·
1 Parent(s): cf29b06
Files changed (1) hide show
  1. app.py +137 -208
app.py CHANGED
@@ -1,5 +1,4 @@
1
  import logging
2
- import os
3
  from typing import Optional, Tuple
4
 
5
  import gradio as gr
@@ -44,7 +43,7 @@ def initialize_system():
44
  _processor.raw_data["students_yearly"]
45
  )
46
 
47
- logger.info("System initialized successfully")
48
  return True
49
  except Exception as e:
50
  logger.error(f"Failed to initialize system: {e}", exc_info=True)
@@ -75,13 +74,13 @@ def generate_predictions(
75
  try:
76
  if semester not in [1, 2]:
77
  return (
78
- "Error: Semester must be 1 (Ganjil) or 2 (Genap)",
79
  None,
80
  None,
81
  )
82
 
83
  if year < 2020 or year > 2030:
84
- return "Error: Year must be between 2020 and 2030", None, None
85
 
86
  if (
87
  _config is None
@@ -91,7 +90,7 @@ def generate_predictions(
91
  or _elective_codes is None
92
  ):
93
  return (
94
- "Error: System not initialized. Please restart the app.",
95
  None,
96
  None,
97
  )
@@ -109,11 +108,11 @@ def generate_predictions(
109
 
110
  if has_actual_data:
111
  logger.info(
112
- f"Found actual enrollment data for {year} Semester {semester} - will compare predictions vs actual"
113
  )
114
  else:
115
  logger.info(
116
- f"No actual data for {year} Semester {semester} - generating future predictions"
117
  )
118
 
119
  if _backtest_metrics is None:
@@ -182,80 +181,78 @@ def generate_predictions(
182
  total_actual = courses_with_actual["actual_enrollment"].sum()
183
  total_predicted = courses_with_actual["predicted_enrollment"].sum()
184
 
185
- summary = f"""## 📊 {year} Semester {semester_name} - Validation Against Actual Data
186
 
187
- <div style='background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; border-radius: 10px; color: white; margin-bottom: 20px;'>
188
- <h3 style='margin-top: 0; color: white;'>✅ Historical Validation</h3>
189
- <p style='margin-bottom: 5px;'><strong>Status:</strong> Comparing predictions against actual enrollment data</p>
190
- <p style='margin-bottom: 0;'><strong>Courses Validated:</strong> {len(courses_with_actual)} courses</p>
191
- </div>
192
 
193
- ### 📈 Prediction Accuracy
194
  | Metric | Value |
195
  |--------|-------|
196
- | **Prediction MAE** | {comparison_mae:.2f} students |
197
- | **Prediction RMSE** | {comparison_rmse:.2f} students |
198
- | **Overall Accuracy** | {(1 - abs(total_predicted - total_actual) / total_actual) * 100:.1f}% |
199
 
200
- ### 📊 Enrollment Summary
201
  | Category | Actual | Predicted | Difference |
202
  |----------|--------|-----------|------------|
203
- | **Total Students** | {int(total_actual)} | {int(total_predicted)} | {int(total_predicted - total_actual):+d} |
204
- | **Courses Analyzed** | {len(courses_with_actual)} | {len(courses_with_actual)} | - |
205
 
206
- ### 🎯 Model Baseline (Cross-Validation)
207
- - **Backtest MAE**: {metrics["mae"]:.2f} students
208
- - **Backtest RMSE**: {metrics["rmse"]:.2f} students
209
-
210
- ### 💡 Recommendation Summary
211
- - **Courses Recommended to Open**: {total_to_open}
212
- - **Total Quota Needed**: {total_seats} seats
213
-
214
- ---
215
- 💡 **Tip:** Scroll down to see the detailed comparison table showing prediction accuracy for each course.
 
216
  """
217
  else:
218
- summary = f"""## 📊 {year} Semester {semester_name}
219
-
220
- <div style='background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); padding: 20px; border-radius: 10px; color: white; margin-bottom: 20px;'>
221
- <h3 style='margin-top: 0; color: white;'>⚠️ Limited Validation Data</h3>
222
- <p style='margin-bottom: 0;'>Actual semester data exists, but no matching elective courses found for comparison</p>
223
- </div>
224
 
225
- ### 🎯 Model Performance (Backtest)
226
- - **MAE**: {metrics["mae"]:.2f} students
227
- - **RMSE**: {metrics["rmse"]:.2f} students
228
 
229
- ### 💡 Recommendations
230
- - **Courses to Open**: {total_to_open}
231
- | **Total Seats** | {total_seats} |
232
- | **Estimated Total Students** | {int(predictions["predicted_enrollment"].sum())} |
 
 
 
 
 
 
 
 
233
  """
234
  else:
235
- summary = f"""## 📊 {year} Semester {semester_name} - Future Prediction
236
 
237
- <div style='background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); padding: 20px; border-radius: 10px; color: white; margin-bottom: 20px;'>
238
- <h3 style='margin-top: 0; color: white;'>🔮 Forward-Looking Forecast</h3>
239
- <p style='margin-bottom: 5px;'><strong>Status:</strong> No actual enrollment data available</p>
240
- <p style='margin-bottom: 0;'><strong>Type:</strong> Predictive forecast based on historical trends</p>
241
- </div>
242
 
243
- ### 🎯 Model Performance (Historical Backtest)
244
  | Metric | Value |
245
  |--------|-------|
246
- | **MAE** | {metrics["mae"]:.2f} students |
247
- | **RMSE** | {metrics["rmse"]:.2f} students |
248
 
249
- ### 📋 Forecast Summary
250
  | Category | Value |
251
  |----------|-------|
252
- | **Courses to Open** | {total_to_open} |
253
- | **Total Seats** | {total_seats} |
254
- | **Estimated Total Students** | {int(predictions["predicted_enrollment"].sum())} |
255
  """
256
 
257
  # Prepare all predictions display
258
- # All predictions
259
  all_predictions_display = predictions[
260
  [
261
  "kode_mk",
@@ -281,9 +278,9 @@ def generate_predictions(
281
  ].round(1)
282
  all_predictions_display["Quota"] = all_predictions_display["Quota"].astype(int)
283
 
284
- # Add status emoji
285
  all_predictions_display["Status"] = all_predictions_display["Status"].map(
286
- {"BUKA": "OPEN", "TUTUP": "CLOSE"}
287
  )
288
 
289
  all_predictions_display = all_predictions_display.sort_values(
@@ -369,22 +366,22 @@ def generate_predictions(
369
  )
370
 
371
  logger.info(
372
- f"Comparison table created with {len(comparison_display)} courses"
373
  )
374
  else:
375
  logger.warning(
376
- "⚠️ Actual data exists but no matching courses found for comparison"
377
  )
378
  logger.warning(f"Predicted courses: {predictions['kode_mk'].tolist()}")
379
  logger.warning(f"Actual courses: {actual_data['kode_mk'].tolist()}")
380
 
381
  logger.info(
382
- f"Predictions generated successfully (comparison_display: {comparison_display is not None})"
383
  )
384
  return summary, all_predictions_display, comparison_display
385
 
386
  except Exception as e:
387
- error_msg = f"Error generating predictions: {str(e)}"
388
  logger.error(error_msg, exc_info=True)
389
  return error_msg, None, None
390
 
@@ -395,37 +392,42 @@ def get_data_info() -> str:
395
 
396
  try:
397
  if _processor is None or _config is None:
398
- return "System not initialized"
399
 
400
  courses = _processor.raw_data.get("courses")
401
  students = _processor.raw_data.get("students_yearly")
402
 
403
  if courses is None or students is None:
404
- return "Data not loaded"
405
 
406
  # Get elective courses
407
  elective_courses = courses[courses["kategori_mk"] == "P"]
408
 
409
  info = f"""
410
- ## 📁 Dataset Information
411
 
412
  ### Course Catalog
413
- - **Total Courses**: {len(courses)}
414
- - **Elective Courses**: {len(elective_courses)}
415
- - **Mandatory Courses**: {len(courses) - len(elective_courses)}
 
 
416
 
417
  ### Student Population
418
- - **Years Available**: {students["thn"].min()} - {students["thn"].max()}
419
- - **Total Records**: {len(students)}
 
 
420
 
421
  ### Data Source
422
- - File: `{_config.data.FILE_PATH}`
423
- - Last Updated: October 8, 2025
 
424
  """
425
  return info
426
 
427
  except Exception as e:
428
- return f"Error getting data info: {str(e)}"
429
 
430
 
431
  # Initialize system at startup
@@ -437,121 +439,63 @@ if not init_success:
437
 
438
  # Create Gradio Interface
439
  with gr.Blocks(title="SKS Enrollment Predictor") as demo:
440
- # Show disclaimer banner if using demo data
441
- if os.getenv("DEMO_MODE", "false").lower() == "true":
442
- gr.Markdown(
443
- """
444
- <div style='padding: 15px; background-color: #fff3cd; border-left: 5px solid #ffc107; margin-bottom: 20px;'>
445
- <h3 style='margin-top: 0; color: #856404;'>⚠️ Demo Version - Anonymized Data</h3>
446
- <p style='margin-bottom: 0; color: #856404;'>
447
- This demonstration uses <strong>anonymized enrollment data</strong> to protect student privacy.
448
- All predictions and functionality are identical to the production version.
449
- </p>
450
- <details style='margin-top: 10px;'>
451
- <summary style='cursor: pointer; color: #856404;'><strong>Changes made for demo:</strong></summary>
452
- <ul style='color: #856404;'>
453
- <li>Student IDs replaced with anonymous codes (STU000001, STU000002, ...)</li>
454
- <li>Population counts have ±3% random noise added</li>
455
- <li>Course information and enrollment patterns fully preserved</li>
456
- </ul>
457
- </details>
458
- </div>
459
- """,
460
- sanitize_html=False,
461
- )
462
-
463
- # Header
464
- gr.Markdown(
465
- """
466
- # 🎓 SKS Course Enrollment Prediction System
467
- ### Intelligent forecasting for elective course planning
468
- """
469
- )
470
-
471
- with gr.Tabs():
472
- with gr.Tab("📊 Predictions", id="predictions"):
473
- with gr.Row():
474
- with gr.Column(scale=1, min_width=300):
475
- gr.Markdown("### 🎯 Select Target Semester")
476
-
477
- year_input = gr.Number(
478
- label="Year",
479
- value=2025,
480
- precision=0,
481
- minimum=2020,
482
- maximum=2030,
483
- )
484
-
485
- semester_input = gr.Radio(
486
- choices=[1, 2],
487
- label="Semester",
488
- value=2,
489
- info="1 = Ganjil (Odd) | 2 = Genap (Even)",
490
- )
491
-
492
- predict_btn = gr.Button(
493
- "🚀 Generate Predictions",
494
- variant="primary",
495
- size="lg",
496
- scale=1,
497
- )
498
-
499
- gr.Markdown(
500
- """
501
- ---
502
- **💡 Tips:**
503
- - Historical semesters show validation results
504
- - Future semesters show forecasts
505
- - Use filters in tables to find specific courses
506
- """
507
- )
508
-
509
- with gr.Column(scale=2):
510
- summary_output = gr.Markdown(
511
- value="""
512
- <div style='text-align: center; padding: 40px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 10px; color: white;'>
513
- <h2 style='color: white; margin-top: 0;'>👈 Select Parameters</h2>
514
- <p style='margin-bottom: 0;'>Choose a year and semester, then click "Generate Predictions"</p>
515
- </div>
516
- """
517
- )
518
 
519
- gr.Markdown("---")
 
 
 
 
520
 
521
- with gr.Row():
522
- with gr.Column():
523
- gr.Markdown("### 📋 All Course Predictions")
524
- gr.Markdown(
525
- "*Complete list of all elective courses with recommendations*"
526
- )
527
- all_predictions_output = gr.Dataframe(
528
- label="Predictions",
529
- wrap=True,
530
- interactive=False,
531
- )
532
 
533
- gr.Markdown("---")
 
 
 
534
 
535
- with gr.Accordion(
536
- "📈 Prediction vs Actual Comparison", open=False
537
- ) as comparison_accordion:
538
- comparison_info = gr.Markdown(
539
- value="*This section will show validation data when actual enrollment is available*",
540
- )
541
- comparison_output = gr.Dataframe(
542
- label="Detailed Comparison",
543
- wrap=True,
544
- interactive=False,
545
- )
546
-
547
- with gr.Tab("ℹ️ Data Info", id="info"):
548
- gr.Markdown("### 📁 Dataset Information")
549
 
550
- data_info_btn = gr.Button("🔄 Refresh Data Info", variant="secondary")
551
- data_info_output = gr.Markdown()
 
 
 
 
 
552
 
553
- data_info_btn.click(fn=get_data_info, inputs=[], outputs=data_info_output)
554
- demo.load(fn=get_data_info, inputs=[], outputs=data_info_output)
 
 
 
 
 
 
 
 
555
 
556
  def update_ui_with_predictions(year, semester):
557
  """Wrapper to handle UI updates based on whether comparison data exists."""
@@ -566,9 +510,9 @@ with gr.Blocks(title="SKS Enrollment Predictor") as demo:
566
  return (
567
  summary,
568
  all_predictions,
569
- gr.update(open=True), # Open accordion
570
  gr.update(
571
- value=f"**✅ Validated against {len(comparison)} courses with actual enrollment data**\n\nThe table below shows prediction accuracy for each course:",
572
  ),
573
  gr.update(value=comparison),
574
  )
@@ -577,9 +521,9 @@ with gr.Blocks(title="SKS Enrollment Predictor") as demo:
577
  return (
578
  summary,
579
  all_predictions,
580
- gr.update(open=False), # Keep accordion closed
581
  gr.update(
582
- value="*No actual enrollment data available for this semester (future prediction)*",
583
  ),
584
  gr.update(value=None),
585
  )
@@ -596,27 +540,12 @@ with gr.Blocks(title="SKS Enrollment Predictor") as demo:
596
  ],
597
  )
598
 
599
- # Footer
600
- gr.Markdown("---")
601
- if os.getenv("DEMO_MODE", "false").lower() == "true":
602
- gr.Markdown(
603
- """
604
- <div style='text-align: center; padding: 20px; background: #f8f9fa; border-radius: 10px;'>
605
- <p style='margin: 0; color: #666;'>📊 <strong>Demo Version</strong> with Anonymized Data | For Educational Purposes</p>
606
- </div>
607
- """,
608
- sanitize_html=False,
609
- )
610
- else:
611
- gr.Markdown(
612
- """
613
- <div style='text-align: center; padding: 20px; background: #f8f9fa; border-radius: 10px;'>
614
- <p style='margin: 0; color: #666;'>🔒 <strong>Private & Confidential</strong> | For Authorized Use Only</p>
615
- </div>
616
- """,
617
- sanitize_html=False,
618
- )
619
 
620
  # Launch the app
621
  if __name__ == "__main__":
622
- demo.launch(server_name="0.0.0.0", server_port=7860, share=False, show_error=True)
 
 
 
 
 
 
1
  import logging
 
2
  from typing import Optional, Tuple
3
 
4
  import gradio as gr
 
43
  _processor.raw_data["students_yearly"]
44
  )
45
 
46
+ logger.info("System initialized successfully")
47
  return True
48
  except Exception as e:
49
  logger.error(f"Failed to initialize system: {e}", exc_info=True)
 
74
  try:
75
  if semester not in [1, 2]:
76
  return (
77
+ "Error: Semester must be 1 (Ganjil) or 2 (Genap)",
78
  None,
79
  None,
80
  )
81
 
82
  if year < 2020 or year > 2030:
83
+ return "Error: Year must be between 2020 and 2030", None, None
84
 
85
  if (
86
  _config is None
 
90
  or _elective_codes is None
91
  ):
92
  return (
93
+ "Error: System not initialized. Please restart the app.",
94
  None,
95
  None,
96
  )
 
108
 
109
  if has_actual_data:
110
  logger.info(
111
+ f"Found actual enrollment data for {year} Semester {semester} - will compare predictions vs actual"
112
  )
113
  else:
114
  logger.info(
115
+ f"No actual data for {year} Semester {semester} - generating future predictions"
116
  )
117
 
118
  if _backtest_metrics is None:
 
181
  total_actual = courses_with_actual["actual_enrollment"].sum()
182
  total_predicted = courses_with_actual["predicted_enrollment"].sum()
183
 
184
+ summary = f"""## {year} Semester {semester_name} - Validation Against Actual Data
185
 
186
+ ### Historical Validation
187
+ - **Status:** Comparing predictions against actual enrollment data
188
+ - **Courses Validated:** {len(courses_with_actual)} courses
 
 
189
 
190
+ ### Prediction Accuracy
191
  | Metric | Value |
192
  |--------|-------|
193
+ | Prediction MAE | {comparison_mae:.2f} students |
194
+ | Prediction RMSE | {comparison_rmse:.2f} students |
195
+ | Overall Accuracy | {(1 - abs(total_predicted - total_actual) / total_actual) * 100:.1f}% |
196
 
197
+ ### Enrollment Summary
198
  | Category | Actual | Predicted | Difference |
199
  |----------|--------|-----------|------------|
200
+ | Total Students | {int(total_actual)} | {int(total_predicted)} | {int(total_predicted - total_actual):+d} |
201
+ | Courses Analyzed | {len(courses_with_actual)} | {len(courses_with_actual)} | - |
202
 
203
+ ### Model Baseline (Cross-Validation)
204
+ | Metric | Value |
205
+ |--------|-------|
206
+ | Backtest MAE | {metrics["mae"]:.2f} students |
207
+ | Backtest RMSE | {metrics["rmse"]:.2f} students |
208
+
209
+ ### Recommendation Summary
210
+ | Item | Value |
211
+ |------|-------|
212
+ | Courses Recommended to Open | {total_to_open} |
213
+ | Total Quota Needed | {total_seats} seats |
214
  """
215
  else:
216
+ summary = f"""## {year} Semester {semester_name}
 
 
 
 
 
217
 
218
+ ### Limited Validation Data
219
+ Actual semester data exists, but no matching elective courses found for comparison.
 
220
 
221
+ ### Model Performance (Backtest)
222
+ | Metric | Value |
223
+ |--------|-------|
224
+ | MAE | {metrics["mae"]:.2f} students |
225
+ | RMSE | {metrics["rmse"]:.2f} students |
226
+
227
+ ### Recommendations
228
+ | Item | Value |
229
+ |------|-------|
230
+ | Courses to Open | {total_to_open} |
231
+ | Total Seats | {total_seats} |
232
+ | Estimated Total Students | {int(predictions["predicted_enrollment"].sum())} |
233
  """
234
  else:
235
+ summary = f"""## {year} Semester {semester_name} - Future Prediction
236
 
237
+ ### Forward-Looking Forecast
238
+ - **Status:** No actual enrollment data available
239
+ - **Type:** Predictive forecast based on historical trends
 
 
240
 
241
+ ### Model Performance (Historical Backtest)
242
  | Metric | Value |
243
  |--------|-------|
244
+ | MAE | {metrics["mae"]:.2f} students |
245
+ | RMSE | {metrics["rmse"]:.2f} students |
246
 
247
+ ### Forecast Summary
248
  | Category | Value |
249
  |----------|-------|
250
+ | Courses to Open | {total_to_open} |
251
+ | Total Seats | {total_seats} |
252
+ | Estimated Total Students | {int(predictions["predicted_enrollment"].sum())} |
253
  """
254
 
255
  # Prepare all predictions display
 
256
  all_predictions_display = predictions[
257
  [
258
  "kode_mk",
 
278
  ].round(1)
279
  all_predictions_display["Quota"] = all_predictions_display["Quota"].astype(int)
280
 
281
+ # Map status to plain text
282
  all_predictions_display["Status"] = all_predictions_display["Status"].map(
283
+ {"BUKA": "OPEN", "TUTUP": "CLOSE"}
284
  )
285
 
286
  all_predictions_display = all_predictions_display.sort_values(
 
366
  )
367
 
368
  logger.info(
369
+ f"Comparison table created with {len(comparison_display)} courses"
370
  )
371
  else:
372
  logger.warning(
373
+ "Actual data exists but no matching courses found for comparison"
374
  )
375
  logger.warning(f"Predicted courses: {predictions['kode_mk'].tolist()}")
376
  logger.warning(f"Actual courses: {actual_data['kode_mk'].tolist()}")
377
 
378
  logger.info(
379
+ f"Predictions generated successfully (comparison_display: {comparison_display is not None})"
380
  )
381
  return summary, all_predictions_display, comparison_display
382
 
383
  except Exception as e:
384
+ error_msg = f"Error generating predictions: {str(e)}"
385
  logger.error(error_msg, exc_info=True)
386
  return error_msg, None, None
387
 
 
392
 
393
  try:
394
  if _processor is None or _config is None:
395
+ return "System not initialized"
396
 
397
  courses = _processor.raw_data.get("courses")
398
  students = _processor.raw_data.get("students_yearly")
399
 
400
  if courses is None or students is None:
401
+ return "Data not loaded"
402
 
403
  # Get elective courses
404
  elective_courses = courses[courses["kategori_mk"] == "P"]
405
 
406
  info = f"""
407
+ ## Dataset Information
408
 
409
  ### Course Catalog
410
+ | Item | Value |
411
+ |------|-------|
412
+ | Total Courses | {len(courses)} |
413
+ | Elective Courses | {len(elective_courses)} |
414
+ | Mandatory Courses | {len(courses) - len(elective_courses)} |
415
 
416
  ### Student Population
417
+ | Item | Value |
418
+ |------|-------|
419
+ | Years Available | {students["thn"].min()} - {students["thn"].max()} |
420
+ | Total Records | {len(students)} |
421
 
422
  ### Data Source
423
+ | Item | Value |
424
+ |------|-------|
425
+ | File | {_config.data.FILE_PATH} |
426
  """
427
  return info
428
 
429
  except Exception as e:
430
+ return f"Error getting data info: {str(e)}"
431
 
432
 
433
  # Initialize system at startup
 
439
 
440
  # Create Gradio Interface
441
  with gr.Blocks(title="SKS Enrollment Predictor") as demo:
442
+ # Clean header
443
+ gr.Markdown("# Course Enrollment Predictor")
444
+
445
+ with gr.Row(equal_height=True):
446
+ # Left panel - Controls
447
+ with gr.Column(scale=1, min_width=280):
448
+ gr.Markdown("#### Target Semester")
449
+
450
+ year_input = gr.Number(
451
+ label="Year",
452
+ value=2025,
453
+ precision=0,
454
+ minimum=2020,
455
+ maximum=2030,
456
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
457
 
458
+ semester_input = gr.Radio(
459
+ choices=[("Ganjil (Odd)", 1), ("Genap (Even)", 2)],
460
+ label="Semester",
461
+ value=2,
462
+ )
463
 
464
+ predict_btn = gr.Button(
465
+ "Generate Predictions",
466
+ variant="primary",
467
+ size="lg",
468
+ )
 
 
 
 
 
 
469
 
470
+ # Data info section
471
+ with gr.Accordion("Dataset Info", open=False):
472
+ data_info_output = gr.Markdown()
473
+ demo.load(fn=get_data_info, inputs=[], outputs=data_info_output)
474
 
475
+ # Right panel - Results
476
+ with gr.Column(scale=3):
477
+ summary_output = gr.Markdown(
478
+ value="Select year and semester, then click Generate Predictions"
479
+ )
 
 
 
 
 
 
 
 
 
480
 
481
+ # Predictions table
482
+ gr.Markdown("#### Predictions")
483
+ all_predictions_output = gr.Dataframe(
484
+ label="",
485
+ wrap=True,
486
+ interactive=False,
487
+ )
488
 
489
+ # Comparison section
490
+ with gr.Accordion("Validation Results", open=False) as comparison_accordion:
491
+ comparison_info = gr.Markdown(
492
+ value="Validation data appears when actual enrollment is available",
493
+ )
494
+ comparison_output = gr.Dataframe(
495
+ label="",
496
+ wrap=True,
497
+ interactive=False,
498
+ )
499
 
500
  def update_ui_with_predictions(year, semester):
501
  """Wrapper to handle UI updates based on whether comparison data exists."""
 
510
  return (
511
  summary,
512
  all_predictions,
513
+ gr.update(open=True),
514
  gr.update(
515
+ value=f"Validated against {len(comparison)} courses",
516
  ),
517
  gr.update(value=comparison),
518
  )
 
521
  return (
522
  summary,
523
  all_predictions,
524
+ gr.update(open=False),
525
  gr.update(
526
+ value="No validation data available for future predictions",
527
  ),
528
  gr.update(value=None),
529
  )
 
540
  ],
541
  )
542
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
543
 
544
  # Launch the app
545
  if __name__ == "__main__":
546
+ demo.launch(
547
+ server_name="0.0.0.0",
548
+ server_port=7860,
549
+ share=False,
550
+ show_error=True,
551
+ )