MaheshP98 commited on
Commit
231d664
·
verified ·
1 Parent(s): de27e81

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +68 -18
app.py CHANGED
@@ -12,6 +12,23 @@ import tempfile
12
  # Configure logging to match the log format
13
  logging.basicConfig(level=logging.INFO, format='%(asctime)s,%(msecs)03d - %(levelname)s - %(message)s')
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  def process_files(uploaded_files):
16
  """
17
  Process uploaded CSV files, generate usage plots, detect anomalies, and process AMC expiries.
@@ -39,6 +56,11 @@ def process_files(uploaded_files):
39
  try:
40
  df = pd.read_csv(file.name)
41
  logging.info(f"Loaded {len(df)} records from {file.name}")
 
 
 
 
 
42
  all_data.append(df)
43
  except Exception as e:
44
  logging.error(f"Failed to load {file.name}: {str(e)}")
@@ -79,7 +101,7 @@ def process_files(uploaded_files):
79
  # Prepare output dataframe (combine original data with anomalies)
80
  output_df = combined_df.copy()
81
  if anomaly_df is not None:
82
- output_df['anomaly'] = anomaly_df['anomaly']
83
 
84
  return output_df, plot_path, pdf_path, amc_message
85
 
@@ -89,20 +111,27 @@ def generate_usage_plot(df):
89
  Returns the path to the saved plot.
90
  """
91
  try:
92
- plt.figure(figsize=(10, 6))
 
 
93
  for status in df['status'].unique():
94
  subset = df[df['status'] == status]
95
- plt.bar(subset['equipment'] + f" ({status})", subset['usage_count'], label=status)
96
- plt.xlabel("Equipment (Status)")
97
- plt.ylabel("Usage Count")
98
- plt.title("Usage Count by Equipment and Status")
99
- plt.legend()
100
- plt.xticks(rotation=45)
 
 
 
 
 
101
  plt.tight_layout()
102
 
103
  # Save plot to temporary file
104
  with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as tmp:
105
- plt.savefig(tmp.name, format='png')
106
  plot_path = tmp.name
107
  plt.close()
108
  return plot_path
@@ -136,8 +165,8 @@ def process_amc_expiries(df):
136
  df['amc_expiry'] = pd.to_datetime(df['amc_expiry'])
137
  upcoming_expiries = df[df['amc_expiry'] <= threshold]
138
  unique_devices = upcoming_expiries['equipment'].unique()
139
- message = f"Found {len(unique_devices)} devices with upcoming AMC expiries."
140
- logging.info(message)
141
  return message, upcoming_expiries
142
  except Exception as e:
143
  logging.error(f"Failed to process AMC expiries: {str(e)}")
@@ -149,38 +178,59 @@ def generate_pdf_report(original_df, anomaly_df, amc_df):
149
  Returns the path to the saved PDF.
150
  """
151
  try:
152
- if original_df is None:
153
  logging.warning("No data available for PDF generation.")
154
  return None
155
 
156
  with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp:
157
  c = canvas.Canvas(tmp.name, pagesize=letter)
 
158
  c.drawString(100, 750, "Equipment Log Analysis Report")
159
- y = 700
 
160
 
161
  # Summary
 
 
162
  c.drawString(100, y, f"Total Records: {len(original_df)}")
163
- c.drawString(100, y-20, f"Devices: {', '.join(original_df['equipment'].unique())}")
 
164
  y -= 40
165
 
166
  # Anomalies
 
 
167
  if anomaly_df is not None:
168
  num_anomalies = sum(anomaly_df['anomaly'] == -1)
169
  c.drawString(100, y, f"Anomalies Detected: {num_anomalies}")
 
170
  if num_anomalies > 0:
171
- anomaly_equipment = anomaly_df[anomaly_df['anomaly'] == -1]['equipment'].unique()
172
- c.drawString(100, y-20, f"Anomalous Devices: {', '.join(anomaly_equipment)}")
173
- y -= 40
 
 
 
 
 
 
174
  else:
175
  c.drawString(100, y, "Anomaly detection failed.")
176
  y -= 20
 
177
 
178
  # AMC Expiries
 
 
179
  if amc_df is not None and not amc_df.empty:
180
  c.drawString(100, y, f"Devices with Upcoming AMC Expiries: {len(amc_df['equipment'].unique())}")
 
181
  for _, row in amc_df.iterrows():
182
- c.drawString(100, y-20, f"{row['equipment']}: {row['amc_expiry'].strftime('%Y-%m-%d')}")
183
  y -= 20
 
 
 
184
  else:
185
  c.drawString(100, y, "No AMC expiry data available.")
186
  y -= 20
 
12
  # Configure logging to match the log format
13
  logging.basicConfig(level=logging.INFO, format='%(asctime)s,%(msecs)03d - %(levelname)s - %(message)s')
14
 
15
+ def validate_csv(df):
16
+ """
17
+ Validate that the CSV has the required columns.
18
+ Returns True if valid, False otherwise with an error message.
19
+ """
20
+ required_columns = ['equipment', 'usage_count', 'status', 'amc_expiry']
21
+ missing_columns = [col for col in required_columns if col not in df.columns]
22
+ if missing_columns:
23
+ return False, f"Missing required columns: {', '.join(missing_columns)}"
24
+ # Validate data types
25
+ try:
26
+ df['usage_count'] = pd.to_numeric(df['usage_count'], errors='raise')
27
+ df['amc_expiry'] = pd.to_datetime(df['amc_expiry'], errors='raise')
28
+ except Exception as e:
29
+ return False, f"Invalid data types: {str(e)}"
30
+ return True, ""
31
+
32
  def process_files(uploaded_files):
33
  """
34
  Process uploaded CSV files, generate usage plots, detect anomalies, and process AMC expiries.
 
56
  try:
57
  df = pd.read_csv(file.name)
58
  logging.info(f"Loaded {len(df)} records from {file.name}")
59
+ # Validate CSV structure
60
+ is_valid, error_msg = validate_csv(df)
61
+ if not is_valid:
62
+ logging.error(f"Failed to load {file.name}: {error_msg}")
63
+ return None, None, None, f"Error loading {file.name}: {error_msg}"
64
  all_data.append(df)
65
  except Exception as e:
66
  logging.error(f"Failed to load {file.name}: {str(e)}")
 
101
  # Prepare output dataframe (combine original data with anomalies)
102
  output_df = combined_df.copy()
103
  if anomaly_df is not None:
104
+ output_df['anomaly'] = anomaly_df['anomaly'].map({1: "Normal", -1: "Anomaly"})
105
 
106
  return output_df, plot_path, pdf_path, amc_message
107
 
 
111
  Returns the path to the saved plot.
112
  """
113
  try:
114
+ plt.figure(figsize=(12, 6))
115
+ # Define colors for statuses
116
+ status_colors = {'Active': '#36A2EB', 'Inactive': '#FF6384', 'Down': '#FFCE56', 'Online': '#4BC0C0'}
117
  for status in df['status'].unique():
118
  subset = df[df['status'] == status]
119
+ plt.bar(
120
+ subset['equipment'] + f" ({status})",
121
+ subset['usage_count'],
122
+ label=status,
123
+ color=status_colors.get(status, '#999999')
124
+ )
125
+ plt.xlabel("Equipment (Status)", fontsize=12)
126
+ plt.ylabel("Usage Count", fontsize=12)
127
+ plt.title("Usage Count by Equipment and Status", fontsize=14)
128
+ plt.legend(title="Status")
129
+ plt.xticks(rotation=45, ha='right')
130
  plt.tight_layout()
131
 
132
  # Save plot to temporary file
133
  with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as tmp:
134
+ plt.savefig(tmp.name, format='png', dpi=100)
135
  plot_path = tmp.name
136
  plt.close()
137
  return plot_path
 
165
  df['amc_expiry'] = pd.to_datetime(df['amc_expiry'])
166
  upcoming_expiries = df[df['amc_expiry'] <= threshold]
167
  unique_devices = upcoming_expiries['equipment'].unique()
168
+ message = f"Found {len(unique_devices)} devices with upcoming AMC expiries: {', '.join(unique_devices)}."
169
+ logging.info(f"Found {len(unique_devices)} devices with upcoming AMC expiries.")
170
  return message, upcoming_expiries
171
  except Exception as e:
172
  logging.error(f"Failed to process AMC expiries: {str(e)}")
 
178
  Returns the path to the saved PDF.
179
  """
180
  try:
181
+ if original_df is None or original_df.empty:
182
  logging.warning("No data available for PDF generation.")
183
  return None
184
 
185
  with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp:
186
  c = canvas.Canvas(tmp.name, pagesize=letter)
187
+ c.setFont("Helvetica-Bold", 16)
188
  c.drawString(100, 750, "Equipment Log Analysis Report")
189
+ c.setFont("Helvetica", 12)
190
+ y = 720
191
 
192
  # Summary
193
+ c.drawString(100, y, "Summary")
194
+ y -= 20
195
  c.drawString(100, y, f"Total Records: {len(original_df)}")
196
+ y -= 20
197
+ c.drawString(100, y, f"Devices: {', '.join(original_df['equipment'].unique())}")
198
  y -= 40
199
 
200
  # Anomalies
201
+ c.drawString(100, y, "Anomaly Detection Results")
202
+ y -= 20
203
  if anomaly_df is not None:
204
  num_anomalies = sum(anomaly_df['anomaly'] == -1)
205
  c.drawString(100, y, f"Anomalies Detected: {num_anomalies}")
206
+ y -= 20
207
  if num_anomalies > 0:
208
+ anomaly_records = anomaly_df[anomaly_df['anomaly'] == -1][['equipment', 'usage_count']]
209
+ c.drawString(100, y, "Anomalous Records:")
210
+ y -= 20
211
+ for _, row in anomaly_records.iterrows():
212
+ c.drawString(100, y, f"{row['equipment']}: Usage Count = {row['usage_count']}")
213
+ y -= 20
214
+ if y < 50:
215
+ c.showPage()
216
+ y = 750
217
  else:
218
  c.drawString(100, y, "Anomaly detection failed.")
219
  y -= 20
220
+ y -= 20
221
 
222
  # AMC Expiries
223
+ c.drawString(100, y, "AMC Expiries Within 7 Days")
224
+ y -= 20
225
  if amc_df is not None and not amc_df.empty:
226
  c.drawString(100, y, f"Devices with Upcoming AMC Expiries: {len(amc_df['equipment'].unique())}")
227
+ y -= 20
228
  for _, row in amc_df.iterrows():
229
+ c.drawString(100, y, f"{row['equipment']}: {row['amc_expiry'].strftime('%Y-%m-%d')}")
230
  y -= 20
231
+ if y < 50:
232
+ c.showPage()
233
+ y = 750
234
  else:
235
  c.drawString(100, y, "No AMC expiry data available.")
236
  y -= 20