|
import gradio as gr |
|
import pandas as pd |
|
from utils.load_data import load_logs |
|
from utils.visualize import plot_usage |
|
from utils.report import generate_pdf |
|
from models.anomaly import detect_anomalies |
|
from utils.amc import upcoming_amc_devices |
|
import logging |
|
import os |
|
|
|
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") |
|
logger = logging.getLogger(__name__) |
|
|
|
def process_files(uploaded_files): |
|
"""Process uploaded CSV files and generate dashboard outputs.""" |
|
logger.info(f"Received uploaded files: {uploaded_files}") |
|
|
|
if not uploaded_files: |
|
logger.warning("No files uploaded.") |
|
return "Please upload at least one valid CSV file.", None, None, None, None |
|
|
|
|
|
if isinstance(uploaded_files, (tuple, list)) and len(uploaded_files) > 0: |
|
if isinstance(uploaded_files[0], list): |
|
valid_files = uploaded_files[0] |
|
else: |
|
valid_files = uploaded_files |
|
else: |
|
valid_files = [] |
|
|
|
|
|
valid_files = [f for f in valid_files if f is not None] |
|
if not valid_files: |
|
logger.warning("No valid files after filtering.") |
|
return "Please upload at least one valid CSV file.", None, None, None, None |
|
|
|
logger.info(f"Processing {len(valid_files)} valid files: {valid_files}") |
|
try: |
|
|
|
df = load_logs(valid_files) |
|
logger.info(f"Loaded {len(df)} log records from uploaded files.") |
|
|
|
|
|
log_table = df.head().to_dict(orient="records") |
|
|
|
|
|
logger.info("Generating usage plot...") |
|
fig = plot_usage(df) |
|
logger.info("Usage plot generated successfully.") |
|
|
|
|
|
anomaly_table = "Anomaly detection failed." |
|
try: |
|
anomalies = detect_anomalies(df) |
|
anomaly_table = anomalies.to_dict(orient="records") if not anomalies.empty else "No anomalies detected." |
|
except Exception as e: |
|
logger.error(f"Anomaly detection failed: {e}") |
|
|
|
|
|
amc_table = None |
|
try: |
|
if "amc_expiry" in df.columns: |
|
logger.info("Processing AMC expiries...") |
|
amc_df = upcoming_amc_devices(df) |
|
amc_table = amc_df.to_dict(orient="records") if not amc_df.empty else "No upcoming AMC expiries." |
|
else: |
|
amc_table = "Column `amc_expiry` not found in uploaded data." |
|
logger.warning("Missing `amc_expiry` column in data.") |
|
except Exception as e: |
|
logger.error(f"AMC processing failed: {e}") |
|
amc_table = f"Error processing AMC expiries: {e}" |
|
|
|
return log_table, fig, anomaly_table, amc_table, df |
|
except Exception as e: |
|
logger.error(f"Error processing files: {e}") |
|
return f"Error: {e}", None, None, None, None |
|
|
|
def generate_pdf_report(df): |
|
"""Generate and return path to PDF report, with error message if applicable.""" |
|
if df is None: |
|
logger.warning("No data available for PDF generation.") |
|
return None, "Please upload CSV files first." |
|
logger.info("Generating PDF report...") |
|
try: |
|
pdf_path = generate_pdf(df) |
|
return pdf_path, "PDF generated successfully." |
|
except Exception as e: |
|
logger.error(f"Failed to generate PDF: {e}") |
|
return None, f"Error generating PDF: {e}" |
|
|
|
with gr.Blocks(title="Multi-Device LabOps Dashboard") as demo: |
|
gr.Markdown("# π Multi-Device LabOps Dashboard") |
|
|
|
with gr.Row(): |
|
file_input = gr.File(file_count="multiple", file_types=[".csv"], label="Upload Device Logs (CSV)") |
|
|
|
with gr.Row(): |
|
submit_btn = gr.Button("Process Files") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
gr.Markdown("## π Uploaded Logs") |
|
log_output = gr.Dataframe() |
|
with gr.Column(): |
|
gr.Markdown("## π Daily Usage Chart") |
|
chart_output = gr.Plot() |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
gr.Markdown("## π¨ Detected Anomalies") |
|
anomaly_output = gr.Dataframe() |
|
with gr.Column(): |
|
gr.Markdown("## π Upcoming AMC Devices") |
|
amc_output = gr.Dataframe() |
|
|
|
with gr.Row(): |
|
pdf_btn = gr.Button("π Generate PDF Report") |
|
pdf_output = gr.File(label="Download PDF Report") |
|
pdf_message = gr.Textbox(label="PDF Generation Status") |
|
|
|
|
|
df_state = gr.State() |
|
|
|
|
|
submit_btn.click( |
|
fn=process_files, |
|
inputs=[file_input], |
|
outputs=[log_output, chart_output, anomaly_output, amc_output, df_state] |
|
) |
|
|
|
pdf_btn.click( |
|
fn=generate_pdf_report, |
|
inputs=[df_state], |
|
outputs=[pdf_output, pdf_message] |
|
) |
|
|
|
if __name__ == "__main__": |
|
try: |
|
logger.info("Application starting...") |
|
demo.launch(server_name="0.0.0.0", server_port=7860) |
|
except Exception as e: |
|
logger.error(f"Application failed to start: {e}") |
|
raise |