RathodHarish commited on
Commit
d578a70
·
verified ·
1 Parent(s): ce507e4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +166 -204
app.py CHANGED
@@ -1,286 +1,248 @@
1
- import gradio as gr
 
2
  import pandas as pd
3
  from datetime import datetime
4
  import logging
5
- import plotly.express as px
6
- from sklearn.ensemble import IsolationForest # For anomaly detection
7
  from transformers import pipeline
8
- import torch # For GPU availability check
 
9
 
10
- # Configure logging for debugging
11
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
12
 
13
- # Preload Hugging Face summarization model at startup
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  logging.info("Preloading Hugging Face model...")
15
  try:
16
  device = 0 if torch.cuda.is_available() else -1
17
- summarizer = pipeline("summarization", model="sshleifer/distilbart-cnn-12-6", device=device) # Lighter model
18
  logging.info(f"Hugging Face model preloaded successfully on device: {'GPU' if device == 0 else 'CPU'}")
19
  except Exception as e:
20
  logging.error(f"Failed to preload model: {str(e)}")
21
  raise e
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  # Format summary prompt and generate report
24
- def summarize_logs(df, progress=gr.Progress()):
25
- progress(0.1, "Generating summary report...")
26
  try:
27
  total_devices = df["device_id"].nunique()
28
  most_used = df.groupby("device_id")["usage_hours"].sum().idxmax() if not df.empty else "N/A"
29
-
30
  prompt = f"Maintenance logs: {total_devices} devices. Most used: {most_used}."
31
  summary = summarizer(prompt, max_length=50, min_length=10, do_sample=False)[0]["summary_text"]
32
- logging.info("Summary generated successfully")
33
  return summary
34
  except Exception as e:
35
  logging.error(f"Summary generation failed: {str(e)}")
36
  return "Failed to generate summary."
37
 
38
- # Anomaly Detection using Isolation Forest with sampling for large datasets
39
- def detect_anomalies(df, progress=gr.Progress()):
40
- progress(0.4, "Detecting anomalies...")
41
  try:
42
  if "usage_hours" not in df.columns or "downtime" not in df.columns:
43
- logging.warning("Required columns for anomaly detection not found")
44
- return "Anomaly detection requires 'usage_hours' and 'downtime' columns."
45
-
46
  if len(df) > 5000:
47
  df = df.sample(n=5000, random_state=42)
48
  logging.info("Sampled data for anomaly detection to 5,000 rows")
49
-
50
  features = df[["usage_hours", "downtime"]].fillna(0)
51
  iso_forest = IsolationForest(contamination=0.1, random_state=42, n_jobs=-1)
52
  df["anomaly"] = iso_forest.fit_predict(features)
53
-
54
  anomalies = df[df["anomaly"] == -1][["device_id", "usage_hours", "downtime", "timestamp"]]
55
  if anomalies.empty:
56
- return "No anomalies detected."
57
-
58
- anomaly_lines = ["**Detected Anomalies:**"]
59
  for idx, row in anomalies.head(5).iterrows():
60
- anomaly_lines.append(f"- Device ID: {row['device_id']}, Usage Hours: {row['usage_hours']}, Downtime: {row['downtime']}, Timestamp: {row['timestamp']}")
61
- anomaly_list = "\n".join(anomaly_lines)
62
- logging.info("Anomalies detected successfully")
63
- return anomaly_list
 
 
 
64
  except Exception as e:
65
  logging.error(f"Anomaly detection failed: {str(e)}")
66
- return f"Anomaly detection failed: {str(e)}"
67
 
68
- # AMC Reminders based on device and AMC date
69
- def check_amc_reminders(df, current_date, progress=gr.Progress()):
70
- progress(0.6, "Checking AMC reminders...")
71
  try:
72
  if "device_id" not in df.columns or "amc_date" not in df.columns:
73
- logging.warning("Required columns for AMC reminders not found")
74
- return "AMC reminders require 'device_id' and 'amc_date' columns."
75
-
76
- df["amc_date"] = pd.to_datetime(df["amc_date"], errors='coerce')
77
  current_date = pd.to_datetime(current_date)
78
-
79
  df["days_to_amc"] = (df["amc_date"] - current_date).dt.days
80
  reminders = df[(df["days_to_amc"] >= 0) & (df["days_to_amc"] <= 30)][["device_id", "amc_date"]]
81
-
82
  if reminders.empty:
83
- return "No AMC reminders due within the next 30 days."
84
-
85
- reminder_lines = ["**Upcoming AMC Reminders:**"]
86
  for idx, row in reminders.head(5).iterrows():
87
- reminder_lines.append(f"- Device ID: {row['device_id']}, AMC Date: {row['amc_date']}")
88
- reminder_list = "\n".join(reminder_lines)
89
- logging.info("AMC reminders generated successfully")
90
- return reminder_list
 
91
  except Exception as e:
92
  logging.error(f"AMC reminder generation failed: {str(e)}")
93
- return f"AMC reminder generation failed: {str(e)}"
94
 
95
- # Dashboard Insights (AI-generated executive-level insights)
96
- def generate_dashboard_insights(df, progress=gr.Progress()):
97
- progress(0.8, "Generating dashboard insights...")
98
  try:
99
  total_devices = df["device_id"].nunique()
100
  avg_usage = df["usage_hours"].mean() if "usage_hours" in df.columns else 0
101
  prompt = f"Insights: {total_devices} devices, avg usage {avg_usage:.2f} hours."
102
  insights = summarizer(prompt, max_length=50, min_length=10, do_sample=False)[0]["summary_text"]
103
- logging.info("Dashboard insights generated successfully")
104
  return insights
105
  except Exception as e:
106
  logging.error(f"Dashboard insights generation failed: {str(e)}")
107
  return f"Dashboard insights generation failed: {str(e)}"
108
 
109
- # Create a bar chart for usage hours per device
110
- def create_usage_chart(df, progress=gr.Progress()):
111
- progress(0.9, "Creating usage chart...")
112
  try:
113
  usage_data = df.groupby("device_id")["usage_hours"].sum().reset_index()
114
  if len(usage_data) > 5:
115
  usage_data = usage_data.nlargest(5, "usage_hours")
116
  logging.info("Limited chart data to top 5 devices")
117
-
118
- custom_colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4']
119
- fig = px.bar(
120
- usage_data,
121
- x="device_id",
122
- y="usage_hours",
123
- title="Usage Hours per Device",
124
- labels={"device_id": "Device ID", "usage_hours": "Usage Hours"},
125
- color="device_id",
126
- color_discrete_sequence=custom_colors
127
- )
128
- fig.update_layout(
129
- title_font_size=16,
130
- margin=dict(l=20, r=20, t=40, b=20),
131
- plot_bgcolor="white",
132
- paper_bgcolor="white",
133
- font=dict(size=12)
134
- )
135
- return fig
136
  except Exception as e:
137
- logging.error(f"Failed to create usage chart: {str(e)}")
138
- return None
139
 
140
- # Main Gradio function
141
- async def process_logs(file_obj, row_limit=10000, progress=gr.Progress()):
 
142
  try:
143
- progress(0, "Starting file processing...")
144
- if file_obj is None:
145
- logging.warning("No file uploaded, returning empty results")
146
- return "No file uploaded.", "No data to preview.", None, "No anomalies detected.", "No AMC reminders.", "No insights generated."
147
-
148
- file_name = file_obj.name if hasattr(file_obj, 'name') else file_obj
149
- logging.info(f"Processing file: {file_name}")
150
-
151
- if not file_name.endswith(".csv"):
152
- logging.error("Unsupported file format")
153
- return "Unsupported file format. Please upload a CSV file.", None, None, None, None, None
154
-
155
- progress(0.05, "Loading CSV file...")
156
- try:
157
- usecols = ["device_id", "timestamp", "usage_hours", "downtime", "amc_date"]
158
- dtypes = {
159
- "device_id": "string",
160
- "usage_hours": "float32",
161
- "downtime": "float32",
162
- "amc_date": "string"
163
- }
164
- df = pd.read_csv(file_name, usecols=usecols, dtype=dtypes, nrows=row_limit)
165
- logging.info(f"File loaded successfully with {len(df)} rows (limited to {row_limit} rows)")
166
- except Exception as e:
167
- logging.error(f"Failed to load CSV: {str(e)}")
168
- return f"Failed to load CSV: {str(e)}", None, None, None, None, None
169
-
170
- progress(0.1, "Converting timestamps...")
171
- try:
172
- df["timestamp"] = pd.to_datetime(df["timestamp"], errors='coerce')
173
- except Exception as e:
174
- logging.error(f"Date conversion failed: {str(e)}")
175
- return f"Failed to convert timestamp to datetime: {str(e)}", None, None, None, None, None
176
-
177
  if df.empty:
178
- logging.warning("No data in the file")
179
- return "No data available in the file.", "No data to preview.", None, "No anomalies detected.", "No AMC reminders.", "No insights generated."
180
 
181
  # Step 1: Summary Report
182
- progress(0.2, "Generating summary...")
183
- summary = f"**Step 1: Summary Report** \n{summarize_logs(df, progress)}"
184
-
185
- # Step 2: Log Preview
186
- progress(0.3, "Previewing logs...")
187
- if not df.empty:
188
- preview_lines = ["**Step 2: Log Preview (First 5 Rows)**"]
189
- for idx, row in df.head().iterrows():
190
- preview_lines.append(f"**Row {idx + 1}:** Device ID: {row['device_id']}, Timestamp: {row['timestamp']}, Usage Hours: {row['usage_hours']}, Downtime: {row['downtime']}, AMC Date: {row['amc_date']}")
191
- preview = "\n".join(preview_lines)
192
- else:
193
- preview = "**Step 2: Log Preview** \nNo data available."
194
-
195
- # Step 3: Usage Chart
196
- chart = create_usage_chart(df, progress)
 
197
 
198
  # Step 4: Anomaly Detection
199
- anomalies = f"**Step 3: Anomaly Detection** \n{detect_anomalies(df, progress)}"
 
 
200
 
201
  # Step 5: AMC Reminders
202
- amc_reminders = f"**Step 4: AMC Reminders** \n{check_amc_reminders(df, datetime.now(), progress)}"
 
 
203
 
204
  # Step 6: Dashboard Insights
205
- insights = f"**Step 5: Dashboard Insights (AI)** \n{generate_dashboard_insights(df, progress)}"
206
 
207
- progress(1.0, "Processing complete!")
208
- return summary, preview, chart, anomalies, amc_reminders, insights
209
- except Exception as e:
210
- logging.error(f"Failed to process file: {str(e)}")
211
- return f"Failed to process file: {str(e)}", None, None, None, None, None
 
 
 
 
212
 
213
- # Gradio Interface with Step-by-Step Layout
214
- try:
215
- logging.info("Initializing Gradio Blocks interface...")
216
- with gr.Blocks(css="""
217
- .dashboard-container {border: 1px solid #e0e0e0; padding: 10/* Reduced padding */ 10px; border-radius: 5px; background-color: #f9f9f9;}
218
- .dashboard-title {font-size: 24px; font-weight: bold; margin-bottom: 5px; /* Reduced margin */}
219
- .dashboard-section {margin-bottom: 5px; /* Reduced margin */}
220
- .dashboard-section h3 {font-size: 18px; margin-bottom: 2px; /* Reduced margin */}
221
- .dashboard-section p {margin: 1px 0; line-height: 1.2; /* Tighter line spacing */}
222
- .dashboard-section li {margin: 1px 0; line-height: 1.2; /* Tighter spacing for list items */}
223
- .dashboard-section ul {margin: 2px 0; padding-left: 20px; /* Reduced margin/padding for lists */}
224
- """) as iface:
225
- gr.Markdown("<h1>LabOps Log Analyzer Dashboard (Hugging Face AI)</h1>")
226
- gr.Markdown("Upload a CSV file containing lab equipment logs to analyze usage.")
227
 
228
- with gr.Row():
229
- with gr.Column(scale=1):
230
- file_input = gr.File(label="Upload Logs (CSV)", file_types=[".csv"])
231
- submit_button = gr.Button("Submit", variant="primary")
232
-
233
- with gr.Column(scale=2):
234
- with gr.Group(elem_classes="dashboard-container"):
235
- gr.Markdown("<div class='dashboard-title'>Analysis Results (Step-by-Step)</div>")
236
-
237
- # Step 1: Summary Report
238
- with gr.Group(elem_classes="dashboard-section"):
239
- gr.Markdown("### Step 1: Summary Report")
240
- summary_output = gr.Markdown()
241
-
242
- # Step 2: Log Preview
243
- with gr.Group(elem_classes="dashboard-section"):
244
- gr.Markdown("### Step 2: Log Preview")
245
- preview_output = gr.Markdown()
246
-
247
- # Step 3: Usage Chart
248
- with gr.Group(elem_classes="dashboard-section"):
249
- gr.Markdown("### Step 3: Usage Chart")
250
- chart_output = gr.Plot()
251
-
252
- # Step 4: Anomaly Detection
253
- with gr.Group(elem_classes="dashboard-section"):
254
- gr.Markdown("### Step 4: Anomaly Detection")
255
- anomaly_output = gr.Markdown()
256
-
257
- # Step 5: AMC Reminders
258
- with gr.Group(elem_classes="dashboard-section"):
259
- gr.Markdown("### Step 5: AMC Reminders")
260
- amc_output = gr.Markdown()
261
-
262
- # Step 6: Dashboard Insights
263
- with gr.Group(elem_classes="dashboard-section"):
264
- gr.Markdown("### Step 6: Dashboard Insights (AI)")
265
- insights_output = gr.Markdown()
266
-
267
- submit_button.click(
268
- fn=process_logs,
269
- inputs=[file_input],
270
- outputs=[summary_output, preview_output, chart_output, anomaly_output, amc_output, insights_output]
271
- )
272
-
273
- logging.info("Gradio interface initialized successfully")
274
- except Exception as e:
275
- logging.error(f"Failed to initialize Gradio interface: {str(e)}")
276
- raise e
277
 
278
  if __name__ == "__main__":
279
- try:
280
- logging.info("Launching Gradio interface...")
281
- iface.launch(server_name="0.0.0.0", server_port=7860, debug=True, share=False)
282
- logging.info("Gradio interface launched successfully")
283
- except Exception as e:
284
- logging.error(f"Failed to launch Gradio interface: {str(e)}")
285
- print(f"Error launching app: {str(e)}")
286
- raise e
 
1
+ from flask import Flask, request, jsonify
2
+ from simple_salesforce import Salesforce
3
  import pandas as pd
4
  from datetime import datetime
5
  import logging
6
+ from sklearn.ensemble import IsolationForest
 
7
  from transformers import pipeline
8
+ import torch
9
+ import os
10
 
11
+ # Configure logging
12
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
13
 
14
+ # Initialize Flask app
15
+ app = Flask(__name__)
16
+
17
+ # Salesforce credentials (use environment variables for security)
18
+ SF_USERNAME = os.getenv('SF_USERNAME', 'your_salesforce_username')
19
+ SF_PASSWORD = os.getenv('SF_PASSWORD', 'your_salesforce_password')
20
+ SF_SECURITY_TOKEN = os.getenv('SF_SECURITY_TOKEN', 'your_security_token')
21
+ SF_INSTANCE_URL = os.getenv('SF_INSTANCE_URL', 'https://login.salesforce.com')
22
+
23
+ # Connect to Salesforce
24
+ try:
25
+ sf = Salesforce(
26
+ username=SF_USERNAME,
27
+ password=SF_PASSWORD,
28
+ security_token=SF_SECURITY_TOKEN,
29
+ instance_url=SF_INSTANCE_URL
30
+ )
31
+ logging.info("Connected to Salesforce successfully")
32
+ except Exception as e:
33
+ logging.error(f"Failed to connect to Salesforce: {str(e)}")
34
+ raise e
35
+
36
+ # Preload Hugging Face summarization model
37
  logging.info("Preloading Hugging Face model...")
38
  try:
39
  device = 0 if torch.cuda.is_available() else -1
40
+ summarizer = pipeline("summarization", model="sshleifer/distilbart-cnn-12-6", device=device)
41
  logging.info(f"Hugging Face model preloaded successfully on device: {'GPU' if device == 0 else 'CPU'}")
42
  except Exception as e:
43
  logging.error(f"Failed to preload model: {str(e)}")
44
  raise e
45
 
46
+ # Fetch SmartLog records from Salesforce
47
+ def fetch_smartlog_records(lab_site, start_date, end_date, equipment_type):
48
+ try:
49
+ query = "SELECT Device_Id__c, Log_Type__c, Status__c, Timestamp__c, Usage_Hours__c, Downtime__c, AMC_Date__c FROM SmartLog__c WHERE "
50
+ conditions = []
51
+ params = {}
52
+ if lab_site:
53
+ conditions.append("Lab_Site__c = :lab_site")
54
+ params['lab_site'] = lab_site
55
+ if start_date:
56
+ conditions.append("Timestamp__c >= :start_date")
57
+ params['start_date'] = start_date
58
+ if end_date:
59
+ conditions.append("Timestamp__c <= :end_date")
60
+ params['end_date'] = end_date
61
+ if equipment_type:
62
+ conditions.append("Log_Type__c = :equipment_type")
63
+ params['equipment_type'] = equipment_type
64
+
65
+ if not conditions:
66
+ query = query.replace(" WHERE ", "")
67
+ else:
68
+ query += " AND ".join(conditions)
69
+
70
+ # Execute SOQL query
71
+ result = sf.query_all(query, **params)
72
+ records = result['records']
73
+
74
+ # Convert records to a DataFrame
75
+ data = []
76
+ for record in records:
77
+ data.append({
78
+ 'device_id': record['Device_Id__c'],
79
+ 'log_type': record['Log_Type__c'],
80
+ 'status': record['Status__c'],
81
+ 'timestamp': record['Timestamp__c'],
82
+ 'usage_hours': record['Usage_Hours__c'],
83
+ 'downtime': record['Downtime__c'],
84
+ 'amc_date': record['AMC_Date__c']
85
+ })
86
+ df = pd.DataFrame(data)
87
+ df['timestamp'] = pd.to_datetime(df['timestamp'], errors='coerce')
88
+ df['amc_date'] = pd.to_datetime(df['amc_date'], errors='coerce')
89
+ return df
90
+ except Exception as e:
91
+ logging.error(f"Failed to fetch SmartLog records: {str(e)}")
92
+ raise e
93
+
94
  # Format summary prompt and generate report
95
+ def summarize_logs(df):
 
96
  try:
97
  total_devices = df["device_id"].nunique()
98
  most_used = df.groupby("device_id")["usage_hours"].sum().idxmax() if not df.empty else "N/A"
 
99
  prompt = f"Maintenance logs: {total_devices} devices. Most used: {most_used}."
100
  summary = summarizer(prompt, max_length=50, min_length=10, do_sample=False)[0]["summary_text"]
 
101
  return summary
102
  except Exception as e:
103
  logging.error(f"Summary generation failed: {str(e)}")
104
  return "Failed to generate summary."
105
 
106
+ # Anomaly Detection
107
+ def detect_anomalies(df):
 
108
  try:
109
  if "usage_hours" not in df.columns or "downtime" not in df.columns:
110
+ return None, "Anomaly detection requires 'usage_hours' and 'downtime' columns."
 
 
111
  if len(df) > 5000:
112
  df = df.sample(n=5000, random_state=42)
113
  logging.info("Sampled data for anomaly detection to 5,000 rows")
 
114
  features = df[["usage_hours", "downtime"]].fillna(0)
115
  iso_forest = IsolationForest(contamination=0.1, random_state=42, n_jobs=-1)
116
  df["anomaly"] = iso_forest.fit_predict(features)
 
117
  anomalies = df[df["anomaly"] == -1][["device_id", "usage_hours", "downtime", "timestamp"]]
118
  if anomalies.empty:
119
+ return None, "No anomalies detected."
120
+ anomaly_lines = []
 
121
  for idx, row in anomalies.head(5).iterrows():
122
+ anomaly_lines.append({
123
+ "device_id": row['device_id'],
124
+ "usage_hours": float(row['usage_hours']),
125
+ "downtime": float(row['downtime']),
126
+ "timestamp": row['timestamp'].isoformat()
127
+ })
128
+ return anomaly_lines, None
129
  except Exception as e:
130
  logging.error(f"Anomaly detection failed: {str(e)}")
131
+ return None, f"Anomaly detection failed: {str(e)}"
132
 
133
+ # AMC Reminders
134
+ def check_amc_reminders(df, current_date):
 
135
  try:
136
  if "device_id" not in df.columns or "amc_date" not in df.columns:
137
+ return None, "AMC reminders require 'device_id' and 'amc_date' columns."
 
 
 
138
  current_date = pd.to_datetime(current_date)
 
139
  df["days_to_amc"] = (df["amc_date"] - current_date).dt.days
140
  reminders = df[(df["days_to_amc"] >= 0) & (df["days_to_amc"] <= 30)][["device_id", "amc_date"]]
 
141
  if reminders.empty:
142
+ return None, "No AMC reminders due within the next 30 days."
143
+ reminder_lines = []
 
144
  for idx, row in reminders.head(5).iterrows():
145
+ reminder_lines.append({
146
+ "device_id": row['device_id'],
147
+ "amc_date": row['amc_date'].isoformat()
148
+ })
149
+ return reminder_lines, None
150
  except Exception as e:
151
  logging.error(f"AMC reminder generation failed: {str(e)}")
152
+ return None, f"AMC reminder generation failed: {str(e)}"
153
 
154
+ # Dashboard Insights
155
+ def generate_dashboard_insights(df):
 
156
  try:
157
  total_devices = df["device_id"].nunique()
158
  avg_usage = df["usage_hours"].mean() if "usage_hours" in df.columns else 0
159
  prompt = f"Insights: {total_devices} devices, avg usage {avg_usage:.2f} hours."
160
  insights = summarizer(prompt, max_length=50, min_length=10, do_sample=False)[0]["summary_text"]
 
161
  return insights
162
  except Exception as e:
163
  logging.error(f"Dashboard insights generation failed: {str(e)}")
164
  return f"Dashboard insights generation failed: {str(e)}"
165
 
166
+ # Create usage chart data for LaTeX table
167
+ def create_usage_chart_data(df):
 
168
  try:
169
  usage_data = df.groupby("device_id")["usage_hours"].sum().reset_index()
170
  if len(usage_data) > 5:
171
  usage_data = usage_data.nlargest(5, "usage_hours")
172
  logging.info("Limited chart data to top 5 devices")
173
+ chart_lines = []
174
+ for idx, row in usage_data.iterrows():
175
+ chart_lines.append({
176
+ "device_id": row['device_id'],
177
+ "usage_hours": float(row['usage_hours'])
178
+ })
179
+ return chart_lines
 
 
 
 
 
 
 
 
 
 
 
 
180
  except Exception as e:
181
+ logging.error(f"Failed to create usage chart data: {str(e)}")
182
+ return []
183
 
184
+ # HTTP endpoint to process logs
185
+ @app.route('/process_logs', methods=['POST'])
186
+ def process_logs():
187
  try:
188
+ data = request.get_json()
189
+ lab_site = data.get('lab_site')
190
+ start_date = data.get('start_date')
191
+ end_date = data.get('end_date')
192
+ equipment_type = data.get('equipment_type')
193
+ amc_threshold = data.get('amc_threshold', 30)
194
+
195
+ # Fetch SmartLog records from Salesforce
196
+ df = fetch_smartlog_records(lab_site, start_date, end_date, equipment_type)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  if df.empty:
198
+ return jsonify({"error": "No data available in SmartLog__c."}), 400
 
199
 
200
  # Step 1: Summary Report
201
+ summary = summarize_logs(df)
202
+
203
+ # Step 2: Log Preview (First 5 Rows)
204
+ preview_lines = []
205
+ for idx, row in df.head().iterrows():
206
+ preview_lines.append({
207
+ "row": idx + 1,
208
+ "device_id": row['device_id'],
209
+ "timestamp": row['timestamp'].isoformat() if pd.notnull(row['timestamp']) else None,
210
+ "usage_hours": float(row['usage_hours']) if pd.notnull(row['usage_hours']) else 0,
211
+ "downtime": float(row['downtime']) if pd.notnull(row['downtime']) else 0,
212
+ "amc_date": row['amc_date'].isoformat() if pd.notnull(row['amc_date']) else None
213
+ })
214
+
215
+ # Step 3: Usage Chart (Textual Data)
216
+ chart_data = create_usage_chart_data(df)
217
 
218
  # Step 4: Anomaly Detection
219
+ anomaly_lines, anomaly_error = detect_anomalies(df)
220
+ if anomaly_error:
221
+ anomaly_lines = [{"error": anomaly_error}]
222
 
223
  # Step 5: AMC Reminders
224
+ reminder_lines, reminder_error = check_amc_reminders(df, datetime.now())
225
+ if reminder_error:
226
+ reminder_lines = [{"error": reminder_error}]
227
 
228
  # Step 6: Dashboard Insights
229
+ insights = generate_dashboard_insights(df)
230
 
231
+ # Prepare the response
232
+ response = {
233
+ "summary": summary,
234
+ "log_preview": preview_lines,
235
+ "usage_chart": chart_data,
236
+ "anomalies": anomaly_lines,
237
+ "amc_reminders": reminder_lines,
238
+ "insights": insights
239
+ }
240
 
241
+ return jsonify(response), 200
 
 
 
 
 
 
 
 
 
 
 
 
 
242
 
243
+ except Exception as e:
244
+ logging.error(f"Failed to process logs: {str(e)}")
245
+ return jsonify({"error": str(e)}), 500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
 
247
  if __name__ == "__main__":
248
+ app.run(host="0.0.0.0", port=5000, debug=True)