RathodHarish commited on
Commit
c39136b
·
verified ·
1 Parent(s): 71b38b7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -113
app.py CHANGED
@@ -8,52 +8,20 @@ from reportlab.pdfgen import canvas
8
 
9
  REQUIRED_COLUMNS = ['DeviceID', 'Lab', 'Type', 'Timestamp', 'Status', 'UsageCount']
10
 
11
- # ----------------------------
12
- # Helper to extract file content correctly for HF Spaces and local
13
- # ----------------------------
14
- def get_file_content(file_obj):
15
- if file_obj is None:
16
- return None
17
-
18
- if hasattr(file_obj, "read"):
19
- content = file_obj.read()
20
- if isinstance(content, bytes):
21
- return content
22
- else:
23
- return content.encode('utf-8')
24
-
25
- if isinstance(file_obj, dict) and 'data' in file_obj:
26
- data = file_obj['data']
27
- if isinstance(data, str):
28
- import base64
29
- if data.startswith("data:"):
30
- data = data.split(",")[1]
31
- return base64.b64decode(data)
32
- elif isinstance(data, bytes):
33
- return data
34
- else:
35
- raise ValueError("Unexpected data format in file upload dict")
36
-
37
- if isinstance(file_obj, str):
38
- with open(file_obj, "rb") as f:
39
- return f.read()
40
-
41
- raise ValueError("Unsupported file object format")
42
-
43
  # ----------------------------
44
  # Load Logs Safely
45
  # ----------------------------
46
  def load_logs(file_obj):
47
  try:
48
  if file_obj is not None:
49
- content_bytes = get_file_content(file_obj)
50
- content_str = content_bytes.decode('utf-8')
51
- df = pd.read_csv(io.StringIO(content_str))
52
  if not all(col in df.columns for col in REQUIRED_COLUMNS):
53
  raise ValueError(f"CSV must contain columns: {', '.join(REQUIRED_COLUMNS)}")
54
  df['Timestamp'] = pd.to_datetime(df['Timestamp'], errors='coerce')
55
  df.dropna(subset=['Timestamp'], inplace=True)
56
  else:
 
57
  df = pd.DataFrame({
58
  'DeviceID': ['D001', 'D002', 'D003'],
59
  'Lab': ['Lab A', 'Lab B', 'Lab A'],
@@ -69,15 +37,14 @@ def load_logs(file_obj):
69
  raise ValueError(f"Failed to load CSV: {e}")
70
 
71
  # ----------------------------
72
- # Filter DataFrame by Lab and Type
73
  # ----------------------------
74
- def filter_df(df, selected_lab, selected_type):
75
- filtered = df.copy()
76
- if selected_lab and selected_lab != "All":
77
- filtered = filtered[filtered['Lab'] == selected_lab]
78
- if selected_type and selected_type != "All":
79
- filtered = filtered[filtered['Type'] == selected_type]
80
- return filtered
81
 
82
  # ----------------------------
83
  # Summarize Log Data
@@ -91,12 +58,12 @@ def summarize_logs(df):
91
  # ----------------------------
92
  # Generate Chart
93
  # ----------------------------
94
- def generate_chart(df, selected_lab, selected_type):
95
- filtered = filter_df(df, selected_lab, selected_type)
96
- summary = summarize_logs(filtered)
97
  if summary.empty:
98
- fig, ax = plt.subplots(figsize=(8, 4))
99
- ax.text(0.5, 0.5, 'No data for selected filters', ha='center', va='center', fontsize=14)
100
  ax.axis('off')
101
  return fig
102
  fig, ax = plt.subplots(figsize=(8, 4))
@@ -111,9 +78,9 @@ def generate_chart(df, selected_lab, selected_type):
111
  # ----------------------------
112
  # Export PDF using ReportLab
113
  # ----------------------------
114
- def export_pdf(df, selected_lab, selected_type):
115
- filtered = filter_df(df, selected_lab, selected_type)
116
- summary = summarize_logs(filtered)
117
  buffer = io.BytesIO()
118
  pdf = canvas.Canvas(buffer, pagesize=letter)
119
  width, height = letter
@@ -122,8 +89,9 @@ def export_pdf(df, selected_lab, selected_type):
122
  pdf.drawCentredString(width / 2, height - 40, "LabOps Dashboard Summary Report")
123
  pdf.setFont("Helvetica", 10)
124
  pdf.drawCentredString(width / 2, height - 60, f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
 
125
 
126
- y = height - 100
127
  pdf.setFont("Helvetica-Bold", 10)
128
  pdf.drawString(50, y, "Lab")
129
  pdf.drawString(150, y, "Device Type")
@@ -132,9 +100,9 @@ def export_pdf(df, selected_lab, selected_type):
132
  y -= 20
133
  pdf.setFont("Helvetica", 10)
134
 
135
- for (lab, dev_type), row in summary.iterrows():
136
- pdf.drawString(50, y, str(lab))
137
- pdf.drawString(150, y, str(dev_type))
138
  pdf.drawString(300, y, str(int(row.get('OK', 0))))
139
  pdf.drawString(350, y, str(int(row.get('DOWN', 0))))
140
  y -= 20
@@ -147,79 +115,61 @@ def export_pdf(df, selected_lab, selected_type):
147
  return ("LabOps_Summary.pdf", buffer.read())
148
 
149
  # ----------------------------
150
- # Update dropdown options based on uploaded file
151
  # ----------------------------
152
- def update_dropdown_options(file_obj):
153
- try:
154
- df = load_logs(file_obj)
155
- labs = sorted(df['Lab'].dropna().unique().tolist())
156
- types = sorted(df['Type'].dropna().unique().tolist())
157
- labs = ["All"] + labs
158
- types = ["All"] + types
159
- return labs, types, gr.update(visible=True)
160
- except Exception as e:
161
- return ["All"], ["All"], gr.update(visible=False)
162
 
163
- # ----------------------------
164
- # Dashboard Display with filters
165
- # ----------------------------
166
- def dashboard(file_obj, selected_lab, selected_type):
167
- try:
168
- df = load_logs(file_obj)
169
- fig = generate_chart(df, selected_lab, selected_type)
170
- return fig, gr.update(visible=False)
171
- except Exception as e:
172
- return None, gr.update(value=f"❌ Error: {e}", visible=True)
173
 
174
- # ----------------------------
175
- # PDF Generator with filters
176
- # ----------------------------
177
- def generate_pdf_button(file_obj, selected_lab, selected_type):
 
 
 
 
 
 
 
 
 
178
  try:
179
- df = load_logs(file_obj)
180
- filename, pdf_bytes = export_pdf(df, selected_lab, selected_type)
181
- return gr.File.update(value=(filename, pdf_bytes), visible=True), gr.Textbox.update(visible=False)
182
  except Exception as e:
183
- return gr.File.update(visible=False), gr.Textbox.update(value=f"❌ Error: {e}", visible=True)
184
 
185
  # ----------------------------
186
  # Gradio Interface
187
  # ----------------------------
188
  with gr.Blocks() as demo:
189
- gr.Markdown("## 🧪 LabOps Dashboard")
190
- gr.Markdown("Upload lab device logs to visualize uptime/downtime & generate PDF reports.")
191
 
192
  with gr.Row():
193
  file_input = gr.File(label="Upload Log CSV", file_types=[".csv"])
194
- lab_dropdown = gr.Dropdown(label="Select Lab", choices=["All"], value="All", interactive=True)
195
- type_dropdown = gr.Dropdown(label="Select Equipment Type", choices=["All"], value="All", interactive=True)
 
 
 
 
 
 
196
  download_button = gr.Button("Download PDF Summary")
197
  download_file = gr.File(label="Download PDF", visible=False)
198
 
199
- plot_output = gr.Plot()
200
- error_output = gr.Textbox(visible=False, label="Errors")
201
-
202
- # Update dropdowns on file upload
203
- file_input.change(
204
- fn=update_dropdown_options,
205
- inputs=file_input,
206
- outputs=[lab_dropdown, type_dropdown, error_output]
207
- )
208
-
209
- # Update plot when file or dropdowns change
210
- inputs_for_dashboard = [file_input, lab_dropdown, type_dropdown]
211
- for input_component in inputs_for_dashboard:
212
- input_component.change(
213
- fn=dashboard,
214
- inputs=inputs_for_dashboard,
215
- outputs=[plot_output, error_output]
216
- )
217
-
218
- # Generate PDF on button click
219
- download_button.click(
220
- fn=generate_pdf_button,
221
- inputs=[file_input, lab_dropdown, type_dropdown],
222
- outputs=[download_file, error_output]
223
- )
224
 
225
  demo.launch()
 
8
 
9
  REQUIRED_COLUMNS = ['DeviceID', 'Lab', 'Type', 'Timestamp', 'Status', 'UsageCount']
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  # ----------------------------
12
  # Load Logs Safely
13
  # ----------------------------
14
  def load_logs(file_obj):
15
  try:
16
  if file_obj is not None:
17
+ # file_obj is a NamedTemporaryFile, get file path to read with pandas directly
18
+ df = pd.read_csv(file_obj.name)
 
19
  if not all(col in df.columns for col in REQUIRED_COLUMNS):
20
  raise ValueError(f"CSV must contain columns: {', '.join(REQUIRED_COLUMNS)}")
21
  df['Timestamp'] = pd.to_datetime(df['Timestamp'], errors='coerce')
22
  df.dropna(subset=['Timestamp'], inplace=True)
23
  else:
24
+ # Default sample data
25
  df = pd.DataFrame({
26
  'DeviceID': ['D001', 'D002', 'D003'],
27
  'Lab': ['Lab A', 'Lab B', 'Lab A'],
 
37
  raise ValueError(f"Failed to load CSV: {e}")
38
 
39
  # ----------------------------
40
+ # Filter dataframe by Lab and Type
41
  # ----------------------------
42
+ def filter_data(df, lab, dev_type):
43
+ if lab != "All":
44
+ df = df[df['Lab'] == lab]
45
+ if dev_type != "All":
46
+ df = df[df['Type'] == dev_type]
47
+ return df
 
48
 
49
  # ----------------------------
50
  # Summarize Log Data
 
58
  # ----------------------------
59
  # Generate Chart
60
  # ----------------------------
61
+ def generate_chart(df, lab, dev_type):
62
+ filtered_df = filter_data(df, lab, dev_type)
63
+ summary = summarize_logs(filtered_df)
64
  if summary.empty:
65
+ fig, ax = plt.subplots()
66
+ ax.text(0.5, 0.5, "No data for selected filters", ha='center', va='center')
67
  ax.axis('off')
68
  return fig
69
  fig, ax = plt.subplots(figsize=(8, 4))
 
78
  # ----------------------------
79
  # Export PDF using ReportLab
80
  # ----------------------------
81
+ def export_pdf(df, lab, dev_type):
82
+ filtered_df = filter_data(df, lab, dev_type)
83
+ summary = summarize_logs(filtered_df)
84
  buffer = io.BytesIO()
85
  pdf = canvas.Canvas(buffer, pagesize=letter)
86
  width, height = letter
 
89
  pdf.drawCentredString(width / 2, height - 40, "LabOps Dashboard Summary Report")
90
  pdf.setFont("Helvetica", 10)
91
  pdf.drawCentredString(width / 2, height - 60, f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
92
+ pdf.drawCentredString(width / 2, height - 80, f"Filters - Lab: {lab}, Type: {dev_type}")
93
 
94
+ y = height - 110
95
  pdf.setFont("Helvetica-Bold", 10)
96
  pdf.drawString(50, y, "Lab")
97
  pdf.drawString(150, y, "Device Type")
 
100
  y -= 20
101
  pdf.setFont("Helvetica", 10)
102
 
103
+ for (lab_name, dev_type_name), row in summary.iterrows():
104
+ pdf.drawString(50, y, str(lab_name))
105
+ pdf.drawString(150, y, str(dev_type_name))
106
  pdf.drawString(300, y, str(int(row.get('OK', 0))))
107
  pdf.drawString(350, y, str(int(row.get('DOWN', 0))))
108
  y -= 20
 
115
  return ("LabOps_Summary.pdf", buffer.read())
116
 
117
  # ----------------------------
118
+ # UI Functions
119
  # ----------------------------
 
 
 
 
 
 
 
 
 
 
120
 
121
+ def get_unique_labs_types(df):
122
+ labs = ["All"] + sorted(df['Lab'].unique().tolist())
123
+ types = ["All"] + sorted(df['Type'].unique().tolist())
124
+ return labs, types
 
 
 
 
 
 
125
 
126
+ def on_file_load(file_obj):
127
+ df = load_logs(file_obj)
128
+ labs, types = get_unique_labs_types(df)
129
+ fig = generate_chart(df, "All", "All")
130
+ return fig, gr.Dropdown.update(choices=labs, value="All"), gr.Dropdown.update(choices=types, value="All"), ""
131
+
132
+ def on_filter_change(file_obj, lab, dev_type):
133
+ df = load_logs(file_obj)
134
+ fig = generate_chart(df, lab, dev_type)
135
+ return fig
136
+
137
+ def on_generate_pdf(file_obj, lab, dev_type):
138
+ df = load_logs(file_obj)
139
  try:
140
+ filename, pdf_bytes = export_pdf(df, lab, dev_type)
141
+ return gr.File.update(value=(filename, pdf_bytes), visible=True), ""
 
142
  except Exception as e:
143
+ return gr.File.update(visible=False), f"❌ Error generating PDF: {e}"
144
 
145
  # ----------------------------
146
  # Gradio Interface
147
  # ----------------------------
148
  with gr.Blocks() as demo:
149
+ gr.Markdown("## 🧪 LabOps Dashboard with Filters")
150
+ gr.Markdown("Upload lab device logs, filter by Lab and Equipment Type, visualize uptime/downtime & generate PDF reports.")
151
 
152
  with gr.Row():
153
  file_input = gr.File(label="Upload Log CSV", file_types=[".csv"])
154
+ with gr.Row():
155
+ lab_dropdown = gr.Dropdown(label="Select Lab", choices=["All"], value="All")
156
+ type_dropdown = gr.Dropdown(label="Select Equipment Type", choices=["All"], value="All")
157
+
158
+ plot_output = gr.Plot()
159
+ error_output = gr.Textbox(visible=False, interactive=False, label="Errors", lines=1)
160
+
161
+ with gr.Row():
162
  download_button = gr.Button("Download PDF Summary")
163
  download_file = gr.File(label="Download PDF", visible=False)
164
 
165
+ # Load file -> update dropdowns & plot
166
+ file_input.change(fn=on_file_load, inputs=file_input, outputs=[plot_output, lab_dropdown, type_dropdown, error_output])
167
+
168
+ # When filters change -> update plot only
169
+ lab_dropdown.change(fn=on_filter_change, inputs=[file_input, lab_dropdown, type_dropdown], outputs=plot_output)
170
+ type_dropdown.change(fn=on_filter_change, inputs=[file_input, lab_dropdown, type_dropdown], outputs=plot_output)
171
+
172
+ # Generate PDF button
173
+ download_button.click(fn=on_generate_pdf, inputs=[file_input, lab_dropdown, type_dropdown], outputs=[download_file, error_output])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
  demo.launch()