Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -2,8 +2,6 @@ import gradio as gr
|
|
| 2 |
import pandas as pd
|
| 3 |
from datetime import datetime, timedelta
|
| 4 |
import logging
|
| 5 |
-
import plotly.express as px
|
| 6 |
-
import plotly.graph_objects as go
|
| 7 |
from sklearn.ensemble import IsolationForest
|
| 8 |
from concurrent.futures import ThreadPoolExecutor
|
| 9 |
import os
|
|
@@ -15,18 +13,15 @@ from simple_salesforce import Salesforce
|
|
| 15 |
# Configure logging
|
| 16 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
| 17 |
|
| 18 |
-
#
|
| 19 |
try:
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
)
|
| 26 |
-
|
| 27 |
-
except Exception as e:
|
| 28 |
-
logging.error(f"Failed to connect to Salesforce: {str(e)}")
|
| 29 |
-
sf = None
|
| 30 |
|
| 31 |
# Try to import reportlab
|
| 32 |
try:
|
|
@@ -40,6 +35,19 @@ except ImportError:
|
|
| 40 |
logging.warning("reportlab module not found. PDF generation disabled.")
|
| 41 |
reportlab_available = False
|
| 42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
# Cache picklist values at startup
|
| 44 |
def get_picklist_values(field_name):
|
| 45 |
if sf is None:
|
|
@@ -254,20 +262,30 @@ def generate_dashboard_insights(df):
|
|
| 254 |
logging.error(f"Dashboard insights generation failed: {str(e)}")
|
| 255 |
return "Failed to generate insights."
|
| 256 |
|
| 257 |
-
# Placeholder chart for empty data
|
| 258 |
def create_placeholder_chart(title):
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 268 |
|
| 269 |
# Create usage chart
|
| 270 |
def create_usage_chart(df):
|
|
|
|
|
|
|
|
|
|
| 271 |
try:
|
| 272 |
if df.empty or "usage_hours" not in df.columns or "device_id" not in df.columns:
|
| 273 |
logging.warning("Insufficient data for usage chart")
|
|
@@ -290,6 +308,9 @@ def create_usage_chart(df):
|
|
| 290 |
|
| 291 |
# Create downtime chart
|
| 292 |
def create_downtime_chart(df):
|
|
|
|
|
|
|
|
|
|
| 293 |
try:
|
| 294 |
if df.empty or "downtime" not in df.columns or "device_id" not in df.columns:
|
| 295 |
logging.warning("Insufficient data for downtime chart")
|
|
@@ -312,6 +333,9 @@ def create_downtime_chart(df):
|
|
| 312 |
|
| 313 |
# Create daily log trends chart
|
| 314 |
def create_daily_log_trends_chart(df):
|
|
|
|
|
|
|
|
|
|
| 315 |
try:
|
| 316 |
if df.empty or "timestamp" not in df.columns:
|
| 317 |
logging.warning("Insufficient data for daily log trends chart")
|
|
@@ -335,6 +359,9 @@ def create_daily_log_trends_chart(df):
|
|
| 335 |
|
| 336 |
# Create weekly uptime chart
|
| 337 |
def create_weekly_uptime_chart(df):
|
|
|
|
|
|
|
|
|
|
| 338 |
try:
|
| 339 |
if df.empty or "timestamp" not in df.columns or "usage_hours" not in df.columns or "downtime" not in df.columns:
|
| 340 |
logging.warning("Insufficient data for weekly uptime chart")
|
|
@@ -364,6 +391,9 @@ def create_weekly_uptime_chart(df):
|
|
| 364 |
|
| 365 |
# Create anomaly alerts chart
|
| 366 |
def create_anomaly_alerts_chart(anomalies_df):
|
|
|
|
|
|
|
|
|
|
| 367 |
try:
|
| 368 |
if anomalies_df is None or anomalies_df.empty or "timestamp" not in anomalies_df.columns:
|
| 369 |
logging.warning("Insufficient data for anomaly alerts chart")
|
|
@@ -396,9 +426,9 @@ def generate_device_cards(df):
|
|
| 396 |
}).reset_index()
|
| 397 |
device_stats['count'] = df.groupby('device_id').size().reindex(device_stats['device_id']).values
|
| 398 |
device_stats['health'] = device_stats['status'].map({
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
}).fillna('Unknown')
|
| 403 |
cards_html = '<div style="display: flex; flex-wrap: wrap; gap: 20px;">'
|
| 404 |
for _, row in device_stats.iterrows():
|
|
@@ -421,6 +451,7 @@ def generate_device_cards(df):
|
|
| 421 |
# Generate PDF content
|
| 422 |
def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights, device_cards_html, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart):
|
| 423 |
if not reportlab_available:
|
|
|
|
| 424 |
return None
|
| 425 |
try:
|
| 426 |
pdf_path = f"status_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
|
|
@@ -479,7 +510,10 @@ def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights
|
|
| 479 |
story.append(Spacer(1, 12))
|
| 480 |
|
| 481 |
story.append(Paragraph("Charts", styles['Heading2']))
|
| 482 |
-
|
|
|
|
|
|
|
|
|
|
| 483 |
|
| 484 |
doc.build(story)
|
| 485 |
logging.info(f"PDF generated at {pdf_path}")
|
|
|
|
| 2 |
import pandas as pd
|
| 3 |
from datetime import datetime, timedelta
|
| 4 |
import logging
|
|
|
|
|
|
|
| 5 |
from sklearn.ensemble import IsolationForest
|
| 6 |
from concurrent.futures import ThreadPoolExecutor
|
| 7 |
import os
|
|
|
|
| 13 |
# Configure logging
|
| 14 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
| 15 |
|
| 16 |
+
# Try to import plotly
|
| 17 |
try:
|
| 18 |
+
import plotly.express as px
|
| 19 |
+
import plotly.graph_objects as go
|
| 20 |
+
plotly_available = True
|
| 21 |
+
logging.info("plotly module successfully imported")
|
| 22 |
+
except ImportError:
|
| 23 |
+
logging.warning("plotly module not found. Chart generation disabled.")
|
| 24 |
+
plotly_available = False
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
# Try to import reportlab
|
| 27 |
try:
|
|
|
|
| 35 |
logging.warning("reportlab module not found. PDF generation disabled.")
|
| 36 |
reportlab_available = False
|
| 37 |
|
| 38 |
+
# Salesforce configuration
|
| 39 |
+
try:
|
| 40 |
+
sf = Salesforce(
|
| 41 |
+
username='multi-devicelabopsdashboard@sathkrutha.com',
|
| 42 |
+
password='Team@1234',
|
| 43 |
+
security_token=os.getenv('SF_SECURITY_TOKEN', ''),
|
| 44 |
+
domain='login'
|
| 45 |
+
)
|
| 46 |
+
logging.info("Salesforce connection established")
|
| 47 |
+
except Exception as e:
|
| 48 |
+
logging.error(f"Failed to connect to Salesforce: {str(e)}")
|
| 49 |
+
sf = None
|
| 50 |
+
|
| 51 |
# Cache picklist values at startup
|
| 52 |
def get_picklist_values(field_name):
|
| 53 |
if sf is None:
|
|
|
|
| 262 |
logging.error(f"Dashboard insights generation failed: {str(e)}")
|
| 263 |
return "Failed to generate insights."
|
| 264 |
|
| 265 |
+
# Placeholder chart for empty data or missing plotly
|
| 266 |
def create_placeholder_chart(title):
|
| 267 |
+
if not plotly_available:
|
| 268 |
+
logging.warning(f"Cannot create chart '{title}': plotly not available")
|
| 269 |
+
return None
|
| 270 |
+
try:
|
| 271 |
+
fig = go.Figure()
|
| 272 |
+
fig.add_annotation(
|
| 273 |
+
text="No data available for this chart",
|
| 274 |
+
xref="paper", yref="paper",
|
| 275 |
+
x=0.5, y=0.5, showarrow=False,
|
| 276 |
+
font=dict(size=16)
|
| 277 |
+
)
|
| 278 |
+
fig.update_layout(title=title, margin=dict(l=20, r=20, t=40, b=20))
|
| 279 |
+
return fig
|
| 280 |
+
except Exception as e:
|
| 281 |
+
logging.error(f"Failed to create placeholder chart '{title}': {str(e)}")
|
| 282 |
+
return None
|
| 283 |
|
| 284 |
# Create usage chart
|
| 285 |
def create_usage_chart(df):
|
| 286 |
+
if not plotly_available:
|
| 287 |
+
logging.warning("Cannot create usage chart: plotly not available")
|
| 288 |
+
return None
|
| 289 |
try:
|
| 290 |
if df.empty or "usage_hours" not in df.columns or "device_id" not in df.columns:
|
| 291 |
logging.warning("Insufficient data for usage chart")
|
|
|
|
| 308 |
|
| 309 |
# Create downtime chart
|
| 310 |
def create_downtime_chart(df):
|
| 311 |
+
if not plotly_available:
|
| 312 |
+
logging.warning("Cannot create downtime chart: plotly not available")
|
| 313 |
+
return None
|
| 314 |
try:
|
| 315 |
if df.empty or "downtime" not in df.columns or "device_id" not in df.columns:
|
| 316 |
logging.warning("Insufficient data for downtime chart")
|
|
|
|
| 333 |
|
| 334 |
# Create daily log trends chart
|
| 335 |
def create_daily_log_trends_chart(df):
|
| 336 |
+
if not plotly_available:
|
| 337 |
+
logging.warning("Cannot create daily log trends chart: plotly not available")
|
| 338 |
+
return None
|
| 339 |
try:
|
| 340 |
if df.empty or "timestamp" not in df.columns:
|
| 341 |
logging.warning("Insufficient data for daily log trends chart")
|
|
|
|
| 359 |
|
| 360 |
# Create weekly uptime chart
|
| 361 |
def create_weekly_uptime_chart(df):
|
| 362 |
+
if not plotly_available:
|
| 363 |
+
logging.warning("Cannot create weekly uptime chart: plotly not available")
|
| 364 |
+
return None
|
| 365 |
try:
|
| 366 |
if df.empty or "timestamp" not in df.columns or "usage_hours" not in df.columns or "downtime" not in df.columns:
|
| 367 |
logging.warning("Insufficient data for weekly uptime chart")
|
|
|
|
| 391 |
|
| 392 |
# Create anomaly alerts chart
|
| 393 |
def create_anomaly_alerts_chart(anomalies_df):
|
| 394 |
+
if not plotly_available:
|
| 395 |
+
logging.warning("Cannot create anomaly alerts chart: plotly not available")
|
| 396 |
+
return None
|
| 397 |
try:
|
| 398 |
if anomalies_df is None or anomalies_df.empty or "timestamp" not in anomalies_df.columns:
|
| 399 |
logging.warning("Insufficient data for anomaly alerts chart")
|
|
|
|
| 426 |
}).reset_index()
|
| 427 |
device_stats['count'] = df.groupby('device_id').size().reindex(device_stats['device_id']).values
|
| 428 |
device_stats['health'] = device_stats['status'].map({
|
| 429 |
+
'Active': 'Healthy',
|
| 430 |
+
'Inactive': 'Unhealthy',
|
| 431 |
+
'Pending': 'Warning'
|
| 432 |
}).fillna('Unknown')
|
| 433 |
cards_html = '<div style="display: flex; flex-wrap: wrap; gap: 20px;">'
|
| 434 |
for _, row in device_stats.iterrows():
|
|
|
|
| 451 |
# Generate PDF content
|
| 452 |
def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights, device_cards_html, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart):
|
| 453 |
if not reportlab_available:
|
| 454 |
+
logging.warning("PDF generation disabled: reportlab not available")
|
| 455 |
return None
|
| 456 |
try:
|
| 457 |
pdf_path = f"status_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
|
|
|
|
| 510 |
story.append(Spacer(1, 12))
|
| 511 |
|
| 512 |
story.append(Paragraph("Charts", styles['Heading2']))
|
| 513 |
+
if not plotly_available:
|
| 514 |
+
story.append(safe_paragraph("Charts unavailable: plotly not installed.", styles['Normal']))
|
| 515 |
+
else:
|
| 516 |
+
story.append(safe_paragraph("[Chart placeholders - see dashboard for visuals]", styles['Normal']))
|
| 517 |
|
| 518 |
doc.build(story)
|
| 519 |
logging.info(f"PDF generated at {pdf_path}")
|