import logging import gradio as gr from backend import get_backend from ui_components import ( build_data_info, build_multi_year_summary, build_prediction_summary, get_forecast_placeholder, get_prediction_placeholder, ) from utils import setup_logging setup_logging("INFO") logger = logging.getLogger("GradioApp") # Backend Interface def get_data_info() -> str: backend = get_backend() data = backend.get_data_info() return build_data_info(data) def generate_predictions(year: int, semester: int): backend = get_backend() result = backend.generate_predictions(year, semester) if result.error: return f"Error: {result.error}", None, None summary_html = build_prediction_summary(result.summary_data) return summary_html, result.predictions_df, result.comparison_df def generate_multi_year_forecast(year: int, semester: int, years_ahead: int = 3): backend = get_backend() result = backend.generate_multi_year_forecast(year, semester, years_ahead) if result.error: return f"Error: {result.error}", None summary_html = build_multi_year_summary(result.summary_data) return summary_html, result.forecast_df def update_ui_with_predictions(year: int, semester: int): summary, all_predictions, comparison = generate_predictions(year, semester) logger.info( f"UI Update: comparison is None: {comparison is None}, " f"empty: {comparison.empty if comparison is not None else 'N/A'}" ) if comparison is not None and not comparison.empty: logger.info(f"Showing comparison table with {len(comparison)} rows") return ( summary, all_predictions, gr.update(open=True), gr.update( value=f"Validasi terhadap {len(comparison)} mata kuliah - " "termasuk perbandingan jumlah kelas aktual vs prediksi" ), gr.update(value=comparison), ) else: logger.info("Hiding comparison table - no data available") return ( summary, all_predictions, gr.update(open=False), gr.update(value="Tidak ada data validasi untuk prediksi masa depan"), gr.update(value=None), ) # Gradio UI def create_gradio_app() -> gr.Blocks: """Create and configure the Gradio application.""" with gr.Blocks(title="SKS Enrollment Predictor") as demo: # Header gr.Markdown("# Course Enrollment & Class Capacity Predictor") gr.Markdown( "Sistem prediksi **jumlah kelas yang perlu dibuka** berdasarkan " "forecasting enrollment dengan mempertimbangkan kapasitas maksimum per kelas." ) with gr.Tabs(): # Single Year with gr.TabItem("Prediksi Semester"): with gr.Row(): with gr.Column(scale=1, min_width=300): year_input = gr.Number( label="Tahun", value=2025, precision=0, minimum=2020, maximum=2030, ) semester_input = gr.Radio( choices=[("1 (Ganjil)", 1), ("2 (Genap)", 2)], label="Semester", value=2, ) predict_btn = gr.Button( "Generate Predictions", variant="primary", size="lg", ) gr.Markdown("---") with gr.Accordion("Dataset Info", open=False): data_info_output = gr.HTML() demo.load( fn=get_data_info, inputs=[], outputs=data_info_output ) with gr.Column(scale=3): summary_output = gr.HTML(value=get_prediction_placeholder()) gr.Markdown("---") gr.Markdown("### Rekomendasi Jumlah Kelas per Mata Kuliah") gr.Markdown( "*Jumlah kelas dihitung berdasarkan prediksi enrollment รท " "kapasitas per kelas*" ) all_predictions_output = gr.Dataframe( label="", wrap=True, interactive=False, ) with gr.Accordion( "Detail Validasi", open=False ) as comparison_accordion: comparison_info = gr.Markdown( value="Data validasi muncul ketika data aktual tersedia" ) comparison_output = gr.Dataframe( label="", wrap=True, interactive=False, ) # Multi-Year Forecast with gr.TabItem("Proyeksi Multi-Tahun"): gr.Markdown("### Forecasting Kebutuhan Kelas Beberapa Tahun ke Depan") gr.Markdown( "Memprediksi tren jumlah mahasiswa dan kebutuhan kelas " "untuk perencanaan jangka panjang." ) with gr.Row(): with gr.Column(scale=1): forecast_year = gr.Number( label="Tahun Mulai", value=2025, precision=0, minimum=2020, maximum=2030, ) forecast_semester = gr.Radio( choices=[("1 (Ganjil)", 1), ("2 (Genap)", 2)], label="Semester", value=2, ) forecast_years = gr.Slider( label="Tahun ke Depan", minimum=1, maximum=5, value=3, step=1, ) forecast_btn = gr.Button( "Generate Forecast", variant="primary", size="lg", ) with gr.Column(scale=3): forecast_summary = gr.HTML(value=get_forecast_placeholder()) gr.Markdown("---") gr.Markdown("### Detail Proyeksi per Mata Kuliah per Tahun") forecast_table = gr.Dataframe( label="", wrap=True, interactive=False, ) predict_btn.click( fn=update_ui_with_predictions, inputs=[year_input, semester_input], outputs=[ summary_output, all_predictions_output, comparison_accordion, comparison_info, comparison_output, ], ) forecast_btn.click( fn=generate_multi_year_forecast, inputs=[forecast_year, forecast_semester, forecast_years], outputs=[forecast_summary, forecast_table], ) return demo logger.info("Starting Gradio app...") backend = get_backend() init_success = backend.initialize() if not init_success: logger.error("Failed to initialize system. App may not work correctly.") demo = create_gradio_app() # Launch the app if __name__ == "__main__": demo.launch( server_name="0.0.0.0", server_port=7860, share=False, show_error=True, )