RathodHarish commited on
Commit
d2edd75
·
verified ·
1 Parent(s): cd2b774

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +122 -397
app.py CHANGED
@@ -1,413 +1,138 @@
1
- import gradio as gr
 
2
  import pandas as pd
3
- import matplotlib.pyplot as plt
4
- import numpy as np
5
- import io
6
  from datetime import datetime, timedelta
7
- import sys
8
- import traceback
9
 
10
- # Try to import fpdf2, but allow the app to run without it
11
- try:
12
- from fpdf2 import FPDF
13
- FPDF_AVAILABLE = True
14
- print("FPDF2 successfully loaded.") # Debug log to confirm fpdf2 installation
15
- except ImportError:
16
- FPDF_AVAILABLE = False
17
- FPDF = None
18
- print("FPDF2 not installed. PDF download feature will be disabled.")
19
 
20
- # Check library versions for debugging
21
- debug_msg = "Library Versions:\n"
22
- try:
23
- debug_msg += f"Python: {sys.version}\n"
24
- debug_msg += f"Gradio: {gr.__version__}\n"
25
- debug_msg += f"Pandas: {pd.__version__}\n"
26
- debug_msg += f"Matplotlib: {matplotlib.__version__}\n"
27
- debug_msg += f"NumPy: {np.__version__}\n"
28
- if FPDF_AVAILABLE:
29
- debug_msg += f"FPDF2: {FPDF.__version__}\n"
30
- else:
31
- debug_msg += "FPDF2: Not installed (PDF download feature disabled)\n"
32
- except Exception as e:
33
- debug_msg += f"Error checking library versions: {str(e)}\n"
34
 
35
- # Global DataFrame to store the CSV data
36
- df = pd.DataFrame()
37
-
38
- def upload_csv(file):
39
- global df
40
- debug_msg_local = debug_msg + "\nStarting CSV upload process...\n"
41
  try:
42
- if file is None:
43
- debug_msg_local += "No file uploaded. Please upload a CSV file.\n"
44
- print(debug_msg_local) # Log to console for debugging
45
- return ["All"], ["All"], ["All"], debug_msg_local, "All", "All", "All", None, None, None, None
46
-
47
- # Read the CSV file with encoding handling
48
- debug_msg_local += "Reading CSV file...\n"
49
- try:
50
- df = pd.read_csv(file, encoding='utf-8')
51
- except UnicodeDecodeError:
52
- debug_msg_local += "Error: CSV file encoding is not UTF-8. Trying latin1 encoding...\n"
53
- df = pd.read_csv(file, encoding='latin1')
54
- except Exception as e:
55
- debug_msg_local += f"Error reading CSV file: {str(e)}\n{traceback.format_exc()}\n"
56
- print(debug_msg_local)
57
- return ["All"], ["All"], ["All"], debug_msg_local, "All", "All", "All", None, None, None, None
58
-
59
- if df.empty:
60
- debug_msg_local += "The uploaded CSV file is empty.\n"
61
- print(debug_msg_local)
62
- return ["All"], ["All"], ["All"], debug_msg_local, "All", "All", "All", None, None, None, None
63
-
64
- # Debug: Show the CSV column names (limit verbosity)
65
- debug_msg_local += f"CSV Columns: {', '.join(df.columns)}\n"
66
-
67
- # Define required columns
68
- required_columns = {'DeviceID', 'Lab', 'Type', 'Timestamp', 'Status', 'UsageCount'}
69
- if not required_columns.issubset(df.columns):
70
- missing_cols = required_columns - set(df.columns)
71
- debug_msg_local += f"Error: CSV is missing required columns: {', '.join(missing_cols)}\n"
72
- print(debug_msg_local)
73
- return ["All"], ["All"], ["All"], debug_msg_local, "All", "All", "All", None, None, None, None
74
-
75
- # Debug: Check data types and sample values (limit to 5 rows)
76
- debug_msg_local += f"Data Types:\n{df.dtypes.to_string()}\n"
77
- debug_msg_local += f"Sample Values (first 5 rows):\n{df.head(5).to_string()}\n"
78
-
79
- # Check for empty or all-NaN columns
80
- if df['Lab'].dropna().empty:
81
- debug_msg_local += "Error: Lab column is empty or contains only NaN values.\n"
82
- if df['Type'].dropna().empty:
83
- debug_msg_local += "Error: Type column is empty or contains only NaN values.\n"
84
- if df['Lab'].dropna().empty or df['Type'].dropna().empty:
85
- print(debug_msg_local)
86
- return ["All"], ["All"], ["All"], debug_msg_local, "All", "All", "All", None, None, None, None
87
-
88
- # Convert Timestamp to datetime with a specific format and fallback
89
- debug_msg_local += "Converting Timestamp column...\n"
90
- try:
91
- # Try parsing with a common format first
92
- df['Timestamp'] = pd.to_datetime(df['Timestamp'], format='%Y-%m-%d %H:%M:%S', errors='coerce')
93
- # If parsing fails for some rows, try without a specific format
94
- if df['Timestamp'].isna().any():
95
- debug_msg_local += "Some timestamps failed to parse with format '%Y-%m-%d %H:%M:%S'. Falling back to generic parsing...\n"
96
- df['Timestamp'] = pd.to_datetime(df['Timestamp'], errors='coerce')
97
- timestamps_invalid = df['Timestamp'].isna().all()
98
- if timestamps_invalid:
99
- debug_msg_local += "Warning: All Timestamp values are invalid or unparseable. Date range filtering will be disabled.\n"
100
- except Exception as e:
101
- debug_msg_local += f"Error parsing Timestamp column: {str(e)}\n{traceback.format_exc()}\n"
102
- print(debug_msg_local)
103
- return ["All"], ["All"], ["All"], debug_msg_local, "All", "All", "All", None, None, None, None
104
-
105
- # Extract unique values for dropdowns
106
- debug_msg_local += "Extracting unique values for dropdowns...\n"
107
- labs = ['All'] + sorted([str(lab) for lab in df['Lab'].dropna().unique()])
108
- types = ['All'] + sorted([str(v) for v in df['Type'].dropna().unique()])
109
- debug_msg_local += f"Lab options: {', '.join(labs)}\nType options: {', '.join(types)}\n"
110
-
111
- # Extract date range for filter
112
- if timestamps_invalid:
113
- date_ranges = ['All']
114
- debug_msg_local += "Date range dropdown disabled due to invalid timestamps.\n"
115
- else:
116
- min_date = df['Timestamp'].min()
117
- max_date = df['Timestamp'].max()
118
- if pd.isna(min_date) or pd.isna(max_date):
119
- date_ranges = ['All']
120
- debug_msg_local += "Warning: Could not determine date range due to invalid timestamps.\n"
121
- else:
122
- min_date_str = min_date.strftime('%Y-%m-%d')
123
- max_date_str = max_date.strftime('%Y-%m-%d')
124
- date_ranges = ['All', f"{min_date_str} to {max_date_str}"]
125
- debug_msg_local += f"Date Range: {min_date_str} to {max_date_str}\n"
126
-
127
- # Automatically trigger filter_and_visualize after upload with default filters
128
- debug_msg_local += "Triggering initial visualization with default filters...\n"
129
- try:
130
- device_cards, plot_daily, plot_uptime, anomaly_text, filter_msg = filter_and_visualize("All", "All", "All")
131
- debug_msg_local += f"Initial Filter Result: {filter_msg}\n"
132
- except Exception as e:
133
- debug_msg_local += f"Initial Filter Error: {str(e)}\n{traceback.format_exc()}\n"
134
- device_cards, plot_daily, plot_uptime, anomaly_text = None, None, None, None
135
-
136
- # Truncate debug message to prevent Gradio rendering issues
137
- debug_msg_local = debug_msg_local[:5000] # Limit to 5000 characters
138
- print(debug_msg_local)
139
- return labs, types, date_ranges, debug_msg_local, "All", "All", "All", device_cards, plot_daily, plot_uptime, anomaly_text
140
- except Exception as e:
141
- debug_msg_local += f"Failed to process CSV: {str(e)}\n{traceback.format_exc()}\n"
142
- debug_msg_local = debug_msg_local[:5000] # Limit to 5000 characters
143
- print(debug_msg_local)
144
- return ["All"], ["All"], ["All"], debug_msg_local, "All", "All", "All", None, None, None, None
145
 
146
- def filter_and_visualize(selected_lab, selected_type, selected_date_range):
147
- global df
148
- error_msg = "Starting filter and visualize process...\n"
149
- try:
150
- if df.empty:
151
- error_msg += "No data available.\n"
152
- print(error_msg)
153
- return None, None, None, None, error_msg
154
-
155
- # Debug: Log the filter parameters
156
- error_msg += f"Applying filters: Lab={selected_lab}, Type={selected_type}, Date Range={selected_date_range}\n"
157
-
158
- # Filter the DataFrame
159
- filtered_df = df.copy()
160
- error_msg += f"Initial DataFrame: {len(filtered_df)} rows\n"
161
-
162
- if selected_lab != "All":
163
- filtered_df = filtered_df[filtered_df["Lab"] == selected_lab]
164
- error_msg += f"After Lab filter ({selected_lab}): {len(filtered_df)} rows\n"
165
- if selected_type != "All":
166
- filtered_df = filtered_df[filtered_df["Type"] == selected_type]
167
- error_msg += f"After Type filter ({selected_type}): {len(filtered_df)} rows\n"
168
- if selected_date_range != "All" and selected_date_range != "No data available." and not df['Timestamp'].isna().all():
169
- try:
170
- start_date, end_date = selected_date_range.split(" to ")
171
- start_date = pd.to_datetime(start_date)
172
- end_date = pd.to_datetime(end_date) + timedelta(days=1) # Include end date
173
- filtered_df = filtered_df[(filtered_df["Timestamp"] >= start_date) & (filtered_df["Timestamp"] < end_date)]
174
- error_msg += f"After Date Range filter ({start_date} to {end_date}): {len(filtered_df)} rows\n"
175
- except Exception as e:
176
- error_msg += f"Error parsing date range: {str(e)}\n{traceback.format_exc()}\n"
177
-
178
- if filtered_df.empty:
179
- error_msg += "No data matches the selected filters.\n"
180
- print(error_msg)
181
- return None, None, None, None, error_msg
182
-
183
- # Debug: Log the filtered DataFrame (limit verbosity)
184
- error_msg += f"Filtered DataFrame (first 5 rows):\n{filtered_df.head(5).to_string()}\n"
185
-
186
- # Device Cards (as a table)
187
- device_cards = filtered_df[['DeviceID', 'Lab', 'Type', 'UsageCount', 'Timestamp']].sort_values(by='Timestamp', ascending=False)
188
-
189
- # Daily Log Trends (Line Chart)
190
- try:
191
- if df['Timestamp'].isna().all():
192
- error_msg += "Warning: All timestamps are invalid. Skipping Daily Log Trends.\n"
193
- plt.figure(figsize=(8, 4))
194
- plt.title("Daily Log Trends - No Data (Invalid Timestamps)")
195
- plt.xlabel("Date")
196
- plt.ylabel("Number of Logs")
197
- plot_daily = io.BytesIO()
198
- plt.savefig(plot_daily, format="png", bbox_inches="tight")
199
- plt.close()
200
- plot_daily.seek(0)
201
- else:
202
- daily_logs = filtered_df.groupby(filtered_df['Timestamp'].dt.date).size()
203
- if daily_logs.empty:
204
- error_msg += "Warning: No data for Daily Log Trends.\n"
205
- plt.figure(figsize=(8, 4))
206
- plt.title("Daily Log Trends - No Data")
207
- plt.xlabel("Date")
208
- plt.ylabel("Number of Logs")
209
- plot_daily = io.BytesIO()
210
- plt.savefig(plot_daily, format="png", bbox_inches="tight")
211
- plt.close()
212
- plot_daily.seek(0)
213
- else:
214
- plt.figure(figsize=(8, 4))
215
- daily_logs.plot(kind='line', marker='o', color='blue')
216
- plt.title("Daily Log Trends")
217
- plt.xlabel("Date")
218
- plt.ylabel("Number of Logs")
219
- plt.xticks(rotation=45)
220
- plot_daily = io.BytesIO()
221
- plt.savefig(plot_daily, format="png", bbox RACinches="tight")
222
- plt.close()
223
- plot_daily.seek(0)
224
- except Exception as e:
225
- error_msg += f"Error generating Daily Log Trends: {str(e)}\n{traceback.format_exc()}\n"
226
- plt.figure(figsize=(8, 4))
227
- plt.title("Daily Log Trends - Error")
228
- plt.xlabel("Date")
229
- plt.ylabel("Number of Logs")
230
- plot_daily = io.BytesIO()
231
- plt.savefig(plot_daily, format="png", bbox_inches="tight")
232
- plt.close()
233
- plot_daily.seek(0)
234
-
235
- # Weekly Uptime % (Bar Chart)
236
- try:
237
- if df['Timestamp'].isna().all():
238
- error_msg += "Warning: All timestamps are invalid. Skipping Weekly Uptime.\n"
239
- plt.figure(figsize=(8, 4))
240
- plt.title("Weekly Uptime % - No Data (Invalid Timestamps)")
241
- plt.xlabel("Date")
242
- plt.ylabel("Uptime %")
243
- plot_uptime = io.BytesIO()
244
- plt.savefig(plot_uptime, format="png", bbox_inches="tight")
245
- plt.close()
246
- plot_uptime.seek(0)
247
- else:
248
- end_date = filtered_df['Timestamp'].max()
249
- start_date = end_date - timedelta(days=7)
250
- weekly_df = filtered_df[(filtered_df['Timestamp'] >= start_date) & (filtered_df['Timestamp'] <= end_date)]
251
- if weekly_df.empty:
252
- error_msg += "Warning: No data for Weekly Uptime % (date range too narrow).\n"
253
- plt.figure(figsize=(8, 4))
254
- plt.title("Weekly Uptime % - No Data")
255
- plt.xlabel("Date")
256
- plt.ylabel("Uptime %")
257
- plot_uptime = io.BytesIO()
258
- plt.savefig(plot_uptime, format="png", bbox_inches="tight")
259
- plt.close()
260
- plot_uptime.seek(0)
261
- else:
262
- uptime = weekly_df.groupby(weekly_df['Timestamp'].dt.date)['Status'].apply(lambda x: (x == 'Up').mean() * 100)
263
- plt.figure(figsize=(8, 4))
264
- uptime.plot(kind='bar', color='green')
265
- plt.title("Weekly Uptime %")
266
- plt.xlabel("Date")
267
- plt.ylabel("Uptime %")
268
- plt.xticks(rotation=45)
269
- plot_uptime = io.BytesIO()
270
- plt.savefig(plot_uptime, format="png", bbox_inches="tight")
271
- plt.close()
272
- plot_uptime.seek(0)
273
- except Exception as e:
274
- error_msg += f"Error generating Weekly Uptime %: {str(e)}\n{traceback.format_exc()}\n"
275
- plt.figure(figsize=(8, 4))
276
- plt.title("Weekly Uptime % - Error")
277
- plt.xlabel("Date")
278
- plt.ylabel("Uptime %")
279
- plot_uptime = io.BytesIO()
280
- plt.savefig(plot_uptime, format="png", bbox_inches="tight")
281
- plt.close()
282
- plot_uptime.seek(0)
283
-
284
- # Anomaly Alerts (Text)
285
- try:
286
- anomalies = filtered_df[(filtered_df['UsageCount'] > 80) | (filtered_df['Status'] == 'Down')]
287
- if anomalies.empty:
288
- anomaly_text = "No anomalies detected."
289
- else:
290
- anomaly_text = "Anomalies Detected:\n" + anomalies[['DeviceID', 'Lab', 'Type', 'Status', 'UsageCount']].to_string(index=False)
291
- except Exception as e:
292
- error_msg += f"Error generating Anomaly Alerts: {str(e)}\n{traceback.format_exc()}\n"
293
- anomaly_text = "Error generating anomaly alerts."
294
-
295
- error_msg = error_msg[:5000] # Limit to 5000 characters
296
- print(error_msg)
297
- return device_cards, plot_daily, plot_uptime, anomaly_text, f"{error_msg}Filters applied successfully."
298
- except Exception as e:
299
- error_msg += f"Unexpected error in filter_and_visualize: {str(e)}\n{traceback.format_exc()}\n"
300
- plt.figure(figsize=(8, 4))
301
- plt.title("Daily Log Trends - Error")
302
- plt.xlabel("Date")
303
- plt.ylabel("Number of Logs")
304
- plot_daily = io.BytesIO()
305
- plt.savefig(plot_daily, format="png", bbox_inches="tight")
306
- plt.close()
307
- plot_daily.seek(0)
308
-
309
- plt.figure(figsize=(8, 4))
310
- plt.title("Weekly Uptime % - Error")
311
- plt.xlabel("Date")
312
- plt.ylabel("Uptime %")
313
- plot_uptime = io.BytesIO()
314
- plt.savefig(plot_uptime, format="png", bbox_inches="tight")
315
- plt.close()
316
- plot_uptime.seek(0)
317
-
318
- error_msg = error_msg[:5000] # Limit to 5000 characters
319
- print(error_msg)
320
- return None, plot_daily, plot_uptime, "Error generating anomaly alerts.", error_msg
321
 
322
- def download_pdf(selected_lab, selected_type, selected_date_range):
323
- global df
 
324
  try:
325
- if not FPDF_AVAILABLE:
326
- print("PDF download feature disabled: fpdf2 module not installed.")
327
- return None
328
-
329
- if df.empty:
330
- return None
331
-
332
- filtered_df = df.copy()
333
- if selected_lab != "All":
334
- filtered_df = filtered_df[filtered_df["Lab"] == selected_lab]
335
- if selected_type != "All":
336
- filtered_df = filtered_df[filtered_df["Type"] == selected_type]
337
- if selected_date_range != "All" and selected_date_range != "No data available." and not df['Timestamp'].isna().all():
338
- start_date, end_date = selected_date_range.split(" to ")
339
- start_date = pd.to_datetime(start_date)
340
- end_date = pd.to_datetime(end_date) + timedelta(days=1)
341
- filtered_df = filtered_df[(filtered_df["Timestamp"] >= start_date) & (filtered_df["Timestamp"] < end_date)]
342
-
343
- if filtered_df.empty:
344
- return None
345
-
346
- pdf = FPDF()
347
- pdf.add_page()
348
- pdf.set_font("Arial", size=12)
349
- pdf.cell(200, 10, txt="LabOps Dashboard Report", ln=True, align='C')
350
- pdf.ln(10)
351
-
352
- for index, row in filtered_df.iterrows():
353
- line = f"{row['Timestamp']} | {row['DeviceID']} | {row['Lab']} | {row['Type']} | {row['Status']} | {row['UsageCount']}"
354
- pdf.multi_cell(0, 10, txt=line)
355
-
356
- output = io.BytesIO()
357
- pdf.output(output)
358
- output.seek(0)
359
- return output
360
- except Exception as e:
361
- print(f"Error in download_pdf: {str(e)}\n{traceback.format_exc()}")
362
- return None
363
 
364
- # Build the Gradio interface
365
- try:
366
- with gr.Blocks() as demo:
367
- gr.Markdown("🧪 **Multi-Device LabOps Dashboard**\nMonitor smart lab devices, visualize logs, and generate PDF reports.")
368
 
369
- with gr.Row():
370
- csv_input = gr.File(label="Upload Device Logs CSV", file_types=[".csv"])
371
-
372
- with gr.Row():
373
- lab_dropdown = gr.Dropdown(label="Filter by Lab", choices=["All"], value="All")
374
- type_dropdown = gr.Dropdown(label="Filter by Equipment Type", choices=["All"], value="All")
375
- date_dropdown = gr.Dropdown(label="Filter by Date Range", choices=["All"], value="All")
 
376
 
377
- with gr.Row():
378
- submit_btn = gr.Button("Submit Filters")
 
 
 
 
 
 
 
 
379
 
380
- with gr.Row():
381
- device_cards = gr.DataFrame(label="Device Cards (Usage, Last Log)")
382
- plot_daily = gr.Image(label="Daily Log Trends")
383
- plot_uptime = gr.Image(label="Weekly Uptime %")
384
 
385
- anomaly_output = gr.Textbox(label="Anomaly Alerts")
386
-
387
- with gr.Row():
388
- download_btn = gr.Button("Download PDF Report", visible=True) # Always visible since fpdf2 should be installed
389
-
390
- error_box = gr.Textbox(label="Status/Error Message", visible=True, interactive=False)
391
 
392
- # Connect the components
393
- csv_input.change(
394
- fn=upload_csv,
395
- inputs=csv_input,
396
- outputs=[lab_dropdown, type_dropdown, date_dropdown, error_box, lab_dropdown, type_dropdown, date_dropdown, device_cards, plot_daily, plot_uptime, anomaly_output]
397
- )
398
-
399
- submit_btn.click(
400
- fn=filter_and_visualize,
401
- inputs=[lab_dropdown, type_dropdown, date_dropdown],
402
- outputs=[device_cards, plot_daily, plot_uptime, anomaly_output, error_box]
403
- )
404
-
405
- download_btn.click(
406
- fn=download_pdf,
407
- inputs=[lab_dropdown, type_dropdown, date_dropdown],
408
- outputs=gr.File(label="Download PDF")
409
- )
 
410
 
411
- demo.launch()
412
- except Exception as e:
413
- print(f"Error launching Gradio interface: {str(e)}\n{traceback.format_exc()}")
 
1
+ from flask import Flask, request, jsonify
2
+ from transformers import pipeline
3
  import pandas as pd
 
 
 
4
  from datetime import datetime, timedelta
5
+ import json
 
6
 
7
+ app = Flask(__name__)
 
 
 
 
 
 
 
 
8
 
9
+ # Initialize Hugging Face summarization pipeline
10
+ summarizer = pipeline("text2text-generation", model="t5-small")
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ # Helper function to calculate days until AMC expiry
13
+ def days_until_expiry(expiry_date_str):
 
 
 
 
14
  try:
15
+ expiry_date = datetime.strptime(expiry_date_str, "%Y-%m-%d")
16
+ current_date = datetime.now()
17
+ return (expiry_date - current_date).days
18
+ except ValueError:
19
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
+ # Helper function to detect anomalies (rule-based)
22
+ def detect_anomalies(logs):
23
+ anomalies = []
24
+ for log in logs:
25
+ # Rule 1: Flag ERROR status as high severity
26
+ if log["status"] == "ERROR":
27
+ anomalies.append({
28
+ "device_id": log["device_id"],
29
+ "issue": "ERROR status detected",
30
+ "detected_on": log["timestamp"],
31
+ "severity": "high"
32
+ })
33
+ # Rule 2: Flag usage spikes (>7 hours as example threshold)
34
+ if log["usage_hours"] > 7:
35
+ anomalies.append({
36
+ "device_id": log["device_id"],
37
+ "issue": "Usage spike",
38
+ "detected_on": log["timestamp"],
39
+ "severity": "high"
40
+ })
41
+ # Rule 3: Flag downtime (usage_hours = 0 with DOWN status)
42
+ if log["status"] == "DOWN" and log["usage_hours"] == 0:
43
+ anomalies.append({
44
+ "device_id": log["device_id"],
45
+ "issue": "Unplanned downtime",
46
+ "detected_on": log["timestamp"],
47
+ "severity": "medium"
48
+ })
49
+ return anomalies
50
+
51
+ # Helper function to generate AMC reminders
52
+ def generate_amc_reminders(logs):
53
+ reminders = []
54
+ for log in logs:
55
+ days_left = days_until_expiry(log["amc_expiry"])
56
+ if days_left is not None and 0 < days_left <= 30:
57
+ reminders.append({
58
+ "device_id": log["device_id"],
59
+ "amc_expiry": log["amc_expiry"],
60
+ "days_remaining": days_left,
61
+ "alert": f"AMC expires in {days_left} days"
62
+ })
63
+ return reminders
64
+
65
+ # Helper function to summarize logs
66
+ def summarize_logs(logs, prompt):
67
+ # Convert logs to text for summarization
68
+ log_text = "\n".join([f"Device {log['device_id']} ({log['log_type']}): Status {log['status']}, Usage {log['usage_hours']} hours, Timestamp {log['timestamp']}, AMC Expiry {log['amc_expiry']}" for log in logs])
69
+ input_text = f"{prompt}\n\nLogs:\n{log_text}"
70
+
71
+ # Use Hugging Face summarizer
72
+ summary = summarizer(input_text, max_length=150, min_length=50, do_sample=False)[0]["generated_text"]
73
+ return summary
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
+ # API endpoint to process logs
76
+ @app.route("/process-logs", methods=["POST"])
77
+ def process_logs():
78
  try:
79
+ data = request.get_json()
80
+ logs = data.get("logs", [])
81
+ prompt = data.get("prompt", "Summarize downtime and usage patterns for SmartLab-1 from May 1 to May 14")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
+ if not logs:
84
+ return jsonify({"error": "No logs provided"}), 400
 
 
85
 
86
+ # Convert logs to DataFrame for analysis
87
+ df = pd.DataFrame(logs)
88
+
89
+ # Calculate summary metrics
90
+ total_devices = len(df["device_id"].unique())
91
+ avg_uptime = len(df[df["status"] == "OK"]) / len(df) * 100 if len(df) > 0 else 0
92
+ downtime_events = len(df[df["status"] == "DOWN"])
93
+ most_used_device = df.groupby("device_id")["usage_hours"].sum().idxmax() if not df.empty else "N/A"
94
 
95
+ # Generate outputs
96
+ summary = {
97
+ "total_devices": total_devices,
98
+ "avg_uptime": f"{avg_uptime:.1f}%",
99
+ "downtime_events": downtime_events,
100
+ "most_used_device": most_used_device
101
+ }
102
+ anomalies = detect_anomalies(logs)
103
+ amc_reminders = generate_amc_reminders(logs)
104
+ text_summary = summarize_logs(logs, prompt)
105
 
106
+ # Generate maintenance report
107
+ report = f"""
108
+ SmartLab-1 Maintenance Report (May 1–14, 2025)
109
+ Generated on: {datetime.now().strftime('%Y-%m-%d')}
110
 
111
+ 1. Summary
112
+ Total Devices: {total_devices}
113
+ Average Uptime: {avg_uptime:.1f}%
114
+ Downtime Events: {downtime_events}
115
+ Most Used Device: {most_used_device}
 
116
 
117
+ 2. Anomalies Detected
118
+ {chr(10).join([f"- {a['device_id']}: {a['issue']} on {a['detected_on']} ({a['severity']} severity)" for a in anomalies]) or "No anomalies detected"}
119
+
120
+ 3. AMC Alerts
121
+ {chr(10).join([f"- {r['device_id']}: AMC expires on {r['amc_expiry']} ({r['days_remaining']} days remaining)" for r in amc_reminders]) or "No AMC expirations within 30 days"}
122
+
123
+ 4. AI-Generated Summary
124
+ {text_summary}
125
+ """
126
+
127
+ return jsonify({
128
+ "summary": summary,
129
+ "anomalies": anomalies,
130
+ "amc_reminders": amc_reminders,
131
+ "maintenance_report": report
132
+ })
133
+
134
+ except Exception as e:
135
+ return jsonify({"error": str(e)}), 500
136
 
137
+ if __name__ == "__main__":
138
+ app.run(debug=True, host="0.0.0.0", port=5000)