petter2025 commited on
Commit
cc15516
·
verified ·
1 Parent(s): 8f174fa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +237 -62
app.py CHANGED
@@ -1041,7 +1041,7 @@ class AuditTrailManager:
1041
 
1042
  def get_execution_dataframe(self) -> pd.DataFrame:
1043
  """
1044
- FIXED: Returns pandas DataFrame for Gradio DataFrame component
1045
  """
1046
  try:
1047
  if not self.executions:
@@ -1051,50 +1051,136 @@ class AuditTrailManager:
1051
  "Start Time", "End Time", "Duration", "Boundary"
1052
  ])
1053
 
1054
- # Build DataFrame from executions
1055
  data = []
1056
  for i, execution in enumerate(self.executions):
1057
- # Extract execution ID from result or generate one
1058
- exec_id = execution.get("result", {}).get("execution_id", f"exec_{i}")
1059
- status = "Success" if "success" in str(execution.get("result", {})).lower() else "Failed"
1060
- mode = execution.get("mode", "unknown")
1061
- scenario = execution.get("scenario", "Unknown")
1062
- timestamp = execution.get("timestamp", "")
1063
- boundary = execution.get("boundary_context", "Unknown")
1064
-
1065
- # Extract end time from telemetry if available
1066
- end_time = execution.get("result", {}).get("telemetry", {}).get("end_time", "")
1067
- duration = "12m" # Mock duration
1068
-
1069
- data.append({
1070
- "Execution ID": exec_id,
1071
- "Scenario": scenario,
1072
- "Status": status,
1073
- "Mode": mode,
1074
- "Start Time": timestamp[:19] if timestamp else "", # Format: YYYY-MM-DD HH:MM:SS
1075
- "End Time": end_time[:19] if end_time else "",
1076
- "Duration": duration,
1077
- "Boundary": boundary
1078
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1079
 
 
1080
  df = pd.DataFrame(data)
1081
 
1082
- # Sort by time (newest first)
1083
  if not df.empty and "Start Time" in df.columns:
1084
- df = df.sort_values("Start Time", ascending=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
1085
 
 
1086
  return df
1087
 
1088
  except Exception as e:
1089
- logger.error(f"Error creating execution DataFrame: {e}")
1090
- # Return empty DataFrame as fallback
1091
- return pd.DataFrame(columns=[
1092
- "Error", "Message"
1093
- ]).from_records([{"Error": "DataFrame Error", "Message": str(e)}])
 
 
 
 
 
1094
 
1095
  def get_incident_dataframe(self) -> pd.DataFrame:
1096
  """
1097
- FIXED: Returns pandas DataFrame for Gradio DataFrame component
1098
  """
1099
  try:
1100
  if not self.incidents:
@@ -1104,46 +1190,135 @@ class AuditTrailManager:
1104
  "Confidence", "Action", "Target"
1105
  ])
1106
 
1107
- # Build DataFrame from incidents
1108
  data = []
1109
  for i, incident in enumerate(self.incidents):
1110
- scenario = incident.get("scenario", "Unknown")
1111
- analysis = incident.get("analysis", {})
1112
- status = analysis.get("status", "analyzed").capitalize()
1113
- boundary = incident.get("boundary_context", "OSS analysis")
1114
- timestamp = incident.get("timestamp", "")
1115
- time_display = timestamp[11:19] if len(timestamp) > 11 else ""
1116
-
1117
- # Extract analysis details
1118
- healing_intent = analysis.get("oss_analysis", {}).get("analysis", {}).get("decision", {})
1119
- confidence = healing_intent.get("confidence", 0.85)
1120
- action = healing_intent.get("action", "Analysis")
1121
- target = healing_intent.get("target", "system")
1122
-
1123
- data.append({
1124
- "Scenario": scenario,
1125
- "Status": status,
1126
- "Boundary": boundary,
1127
- "Time": time_display,
1128
- "Confidence": f"{confidence * 100:.1f}%",
1129
- "Action": action,
1130
- "Target": target
1131
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1132
 
 
1133
  df = pd.DataFrame(data)
1134
 
1135
- # Sort by time (newest first)
1136
  if not df.empty and "Time" in df.columns:
1137
- df = df.sort_values("Time", ascending=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
1138
 
 
1139
  return df
1140
 
1141
  except Exception as e:
1142
- logger.error(f"Error creating incident DataFrame: {e}")
1143
- # Return empty DataFrame as fallback
1144
- return pd.DataFrame(columns=[
1145
- "Error", "Message"
1146
- ]).from_records([{"Error": "DataFrame Error", "Message": str(e)}])
 
 
 
 
 
1147
 
1148
  def get_execution_table_html(self):
1149
  """Legacy HTML method for backward compatibility"""
 
1041
 
1042
  def get_execution_dataframe(self) -> pd.DataFrame:
1043
  """
1044
+ FIXED: Robust pandas DataFrame creation for Gradio DataFrame component
1045
  """
1046
  try:
1047
  if not self.executions:
 
1051
  "Start Time", "End Time", "Duration", "Boundary"
1052
  ])
1053
 
1054
+ # Build DataFrame from executions with safe access
1055
  data = []
1056
  for i, execution in enumerate(self.executions):
1057
+ try:
1058
+ # Safe access to nested dictionaries
1059
+ result = execution.get("result", {})
1060
+
1061
+ # Execution ID - safe extraction with fallback
1062
+ exec_id = result.get("execution_id", f"exec_{i:03d}")
1063
+
1064
+ # Status determination with multiple fallbacks
1065
+ status_text = "Unknown"
1066
+ if isinstance(result, dict):
1067
+ status_lower = str(result.get("status", "")).lower()
1068
+ if "success" in status_lower:
1069
+ status_text = "Success"
1070
+ elif "failed" in status_lower or "error" in status_lower:
1071
+ status_text = "Failed"
1072
+ else:
1073
+ # Check if there's an error key
1074
+ if result.get("error"):
1075
+ status_text = "Failed"
1076
+ else:
1077
+ status_text = "Success"
1078
+
1079
+ # Mode extraction
1080
+ mode = execution.get("mode", "unknown")
1081
+
1082
+ # Scenario extraction
1083
+ scenario = execution.get("scenario", "Unknown")
1084
+
1085
+ # Timestamp formatting with validation
1086
+ timestamp = execution.get("timestamp", "")
1087
+ start_time = ""
1088
+ if timestamp and len(timestamp) > 10:
1089
+ try:
1090
+ # Format: YYYY-MM-DD HH:MM:SS
1091
+ start_time = timestamp[:19]
1092
+ except Exception:
1093
+ start_time = timestamp # Fallback to raw string
1094
+
1095
+ # End time extraction from telemetry
1096
+ end_time = ""
1097
+ telemetry = result.get("telemetry", {})
1098
+ if telemetry:
1099
+ end_timestamp = telemetry.get("end_time", "")
1100
+ if end_timestamp and len(end_timestamp) > 10:
1101
+ try:
1102
+ end_time = end_timestamp[:19]
1103
+ except Exception:
1104
+ end_time = end_timestamp # Fallback
1105
+
1106
+ # Duration - mock or extract from execution
1107
+ duration = "12m" # Default mock duration
1108
+ if telemetry and "estimated_duration" in telemetry:
1109
+ duration = telemetry.get("estimated_duration", "12m")
1110
+
1111
+ # Boundary context
1112
+ boundary = execution.get("boundary_context", "Unknown")
1113
+
1114
+ data.append({
1115
+ "Execution ID": exec_id,
1116
+ "Scenario": scenario,
1117
+ "Status": status_text,
1118
+ "Mode": mode,
1119
+ "Start Time": start_time,
1120
+ "End Time": end_time,
1121
+ "Duration": duration,
1122
+ "Boundary": boundary
1123
+ })
1124
+
1125
+ except Exception as row_error:
1126
+ logger.warning(f"Error processing execution row {i}: {row_error}")
1127
+ # Add error row for debugging
1128
+ data.append({
1129
+ "Execution ID": f"error_{i}",
1130
+ "Scenario": "Error",
1131
+ "Status": "Failed",
1132
+ "Mode": "error",
1133
+ "Start Time": datetime.datetime.now().isoformat()[:19],
1134
+ "End Time": "",
1135
+ "Duration": "0m",
1136
+ "Boundary": "Error processing"
1137
+ })
1138
+
1139
+ if not data:
1140
+ logger.warning("No valid execution data found, returning empty DataFrame")
1141
+ return pd.DataFrame(columns=[
1142
+ "Execution ID", "Scenario", "Status", "Mode",
1143
+ "Start Time", "End Time", "Duration", "Boundary"
1144
+ ])
1145
 
1146
+ # Create DataFrame
1147
  df = pd.DataFrame(data)
1148
 
1149
+ # Safe sorting - only if we have valid Start Time data
1150
  if not df.empty and "Start Time" in df.columns:
1151
+ # Check if Start Time column has valid data
1152
+ valid_times = df["Start Time"].apply(
1153
+ lambda x: isinstance(x, str) and len(x) > 0 and x != "None"
1154
+ )
1155
+
1156
+ if valid_times.any():
1157
+ try:
1158
+ # Sort by time (newest first)
1159
+ df = df.sort_values("Start Time", ascending=False)
1160
+ except Exception as sort_error:
1161
+ logger.warning(f"Could not sort DataFrame: {sort_error}")
1162
+ # Keep unsorted if sorting fails
1163
+ else:
1164
+ logger.debug("No valid timestamps for sorting")
1165
 
1166
+ logger.info(f"✅ Created execution DataFrame with {len(df)} rows")
1167
  return df
1168
 
1169
  except Exception as e:
1170
+ logger.error(f"Error creating execution DataFrame: {e}")
1171
+ # Return informative error DataFrame
1172
+ error_df = pd.DataFrame(columns=[
1173
+ "Error", "Message", "Timestamp"
1174
+ ]).from_records([{
1175
+ "Error": "DataFrame Creation Failed",
1176
+ "Message": str(e),
1177
+ "Timestamp": datetime.datetime.now().isoformat()[:19]
1178
+ }])
1179
+ return error_df
1180
 
1181
  def get_incident_dataframe(self) -> pd.DataFrame:
1182
  """
1183
+ FIXED: Robust pandas DataFrame creation for Gradio DataFrame component
1184
  """
1185
  try:
1186
  if not self.incidents:
 
1190
  "Confidence", "Action", "Target"
1191
  ])
1192
 
1193
+ # Build DataFrame from incidents with safe access
1194
  data = []
1195
  for i, incident in enumerate(self.incidents):
1196
+ try:
1197
+ # Safe extraction of basic fields
1198
+ scenario = incident.get("scenario", "Unknown")
1199
+ boundary = incident.get("boundary_context", "OSS analysis")
1200
+
1201
+ # Analysis data extraction
1202
+ analysis = incident.get("analysis", {})
1203
+
1204
+ # Status determination
1205
+ status = "Analyzed"
1206
+ if isinstance(analysis, dict):
1207
+ analysis_status = analysis.get("status", "").lower()
1208
+ if analysis_status:
1209
+ status = analysis_status.capitalize()
1210
+ else:
1211
+ # Fallback status determination
1212
+ if analysis.get("error"):
1213
+ status = "Error"
1214
+ elif analysis.get("analysis") or analysis.get("oss_analysis"):
1215
+ status = "Success"
1216
+
1217
+ # Timestamp formatting
1218
+ timestamp = incident.get("timestamp", "")
1219
+ time_display = ""
1220
+ if timestamp and len(timestamp) > 10:
1221
+ try:
1222
+ # Extract HH:MM:SS
1223
+ time_display = timestamp[11:19]
1224
+ except Exception:
1225
+ time_display = timestamp[:8] if len(timestamp) >= 8 else timestamp
1226
+
1227
+ # Extract healing intent details with multiple fallback paths
1228
+ confidence = 0.85 # Default confidence
1229
+ action = "Analysis"
1230
+ target = "system"
1231
+
1232
+ # Try multiple paths to find healing intent
1233
+ healing_intent = None
1234
+
1235
+ # Path 1: oss_analysis -> analysis -> decision
1236
+ oss_analysis = analysis.get("oss_analysis", {})
1237
+ if isinstance(oss_analysis, dict):
1238
+ oss_analysis_inner = oss_analysis.get("analysis", {})
1239
+ if isinstance(oss_analysis_inner, dict):
1240
+ healing_intent = oss_analysis_inner.get("decision", {})
1241
+
1242
+ # Path 2: direct analysis -> decision
1243
+ if not healing_intent and isinstance(analysis.get("analysis", {}), dict):
1244
+ healing_intent = analysis["analysis"].get("decision", {})
1245
+
1246
+ # Path 3: direct healing_intent
1247
+ if not healing_intent:
1248
+ healing_intent = analysis.get("healing_intent", {})
1249
+
1250
+ if healing_intent and isinstance(healing_intent, dict):
1251
+ confidence = healing_intent.get("confidence", 0.85)
1252
+ action = healing_intent.get("action", "Analysis")
1253
+ target = healing_intent.get("target", "system")
1254
+
1255
+ # Format confidence as percentage
1256
+ confidence_display = f"{confidence * 100:.1f}%"
1257
+
1258
+ data.append({
1259
+ "Scenario": scenario,
1260
+ "Status": status,
1261
+ "Boundary": boundary,
1262
+ "Time": time_display,
1263
+ "Confidence": confidence_display,
1264
+ "Action": action[:50], # Limit action length
1265
+ "Target": target[:30] # Limit target length
1266
+ })
1267
+
1268
+ except Exception as row_error:
1269
+ logger.warning(f"Error processing incident row {i}: {row_error}")
1270
+ # Add error row for debugging
1271
+ data.append({
1272
+ "Scenario": "Error",
1273
+ "Status": "Failed",
1274
+ "Boundary": "Error processing",
1275
+ "Time": datetime.datetime.now().isoformat()[11:19],
1276
+ "Confidence": "0.0%",
1277
+ "Action": "Error",
1278
+ "Target": "system"
1279
+ })
1280
+
1281
+ if not data:
1282
+ logger.warning("No valid incident data found, returning empty DataFrame")
1283
+ return pd.DataFrame(columns=[
1284
+ "Scenario", "Status", "Boundary", "Time",
1285
+ "Confidence", "Action", "Target"
1286
+ ])
1287
 
1288
+ # Create DataFrame
1289
  df = pd.DataFrame(data)
1290
 
1291
+ # Safe sorting - only if we have valid Time data
1292
  if not df.empty and "Time" in df.columns:
1293
+ # Check if Time column has valid data
1294
+ valid_times = df["Time"].apply(
1295
+ lambda x: isinstance(x, str) and len(x) > 0 and x != "None"
1296
+ )
1297
+
1298
+ if valid_times.any():
1299
+ try:
1300
+ # Sort by time (newest first)
1301
+ df = df.sort_values("Time", ascending=False)
1302
+ except Exception as sort_error:
1303
+ logger.warning(f"Could not sort incident DataFrame: {sort_error}")
1304
+ # Keep unsorted if sorting fails
1305
+ else:
1306
+ logger.debug("No valid timestamps for sorting in incident DataFrame")
1307
 
1308
+ logger.info(f"✅ Created incident DataFrame with {len(df)} rows")
1309
  return df
1310
 
1311
  except Exception as e:
1312
+ logger.error(f"Error creating incident DataFrame: {e}")
1313
+ # Return informative error DataFrame
1314
+ error_df = pd.DataFrame(columns=[
1315
+ "Error", "Message", "Timestamp"
1316
+ ]).from_records([{
1317
+ "Error": "DataFrame Creation Failed",
1318
+ "Message": str(e),
1319
+ "Timestamp": datetime.datetime.now().isoformat()[:19]
1320
+ }])
1321
+ return error_df
1322
 
1323
  def get_execution_table_html(self):
1324
  """Legacy HTML method for backward compatibility"""