classquota / app.py
muhalwan's picture
Revised version
6a0a429
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,
)