Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -9,6 +9,10 @@ import io
|
|
| 9 |
import time
|
| 10 |
import asyncio
|
| 11 |
from simple_salesforce import Salesforce
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
# Configure logging
|
| 14 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
@@ -41,10 +45,6 @@ except ImportError:
|
|
| 41 |
|
| 42 |
# Try to import reportlab
|
| 43 |
try:
|
| 44 |
-
from reportlab.lib.pagesizes import letter
|
| 45 |
-
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
|
| 46 |
-
from reportlab.lib.styles import getSampleStyleSheet
|
| 47 |
-
from reportlab.lib import colors
|
| 48 |
reportlab_available = True
|
| 49 |
logging.info("reportlab module successfully imported")
|
| 50 |
except ImportError:
|
|
@@ -465,7 +465,7 @@ def generate_device_cards(df):
|
|
| 465 |
return f'<p>Error generating device cards: {str(e)}</p>'
|
| 466 |
|
| 467 |
# Generate PDF content
|
| 468 |
-
def generate_pdf_content(summary,
|
| 469 |
if not reportlab_available:
|
| 470 |
logging.warning("PDF generation disabled: reportlab not available")
|
| 471 |
return None
|
|
@@ -475,8 +475,10 @@ def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights
|
|
| 475 |
styles = getSampleStyleSheet()
|
| 476 |
story = []
|
| 477 |
|
|
|
|
| 478 |
def safe_paragraph(text, style):
|
| 479 |
-
|
|
|
|
| 480 |
|
| 481 |
story.append(Paragraph("LabOps Status Report", styles['Title']))
|
| 482 |
story.append(Paragraph(f"Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", styles['Normal']))
|
|
@@ -487,6 +489,8 @@ def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights
|
|
| 487 |
story.append(Spacer(1, 12))
|
| 488 |
|
| 489 |
story.append(Paragraph("Log Preview", styles['Heading2']))
|
|
|
|
|
|
|
| 490 |
if not preview_df.empty:
|
| 491 |
data = [preview_df.columns.tolist()] + preview_df.head(5).values.tolist()
|
| 492 |
table = Table(data)
|
|
@@ -509,7 +513,7 @@ def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights
|
|
| 509 |
story.append(Spacer(1, 12))
|
| 510 |
|
| 511 |
story.append(Paragraph("Device Cards", styles['Heading2']))
|
| 512 |
-
device_cards_text = device_cards_html.replace('<div>', '').replace('</div>', '\n').replace('<h4>', '').replace('</h4>', '\n').replace('<p>', '').replace('</p>', '\n').replace('<b>', '').replace('</b>', '').replace('<span style="color: green">', '').replace('<span style="color: red">', '').replace('<span style="color: orange">', '').replace('<span style="color: gray">', '').replace('</span>', '')
|
| 513 |
story.append(safe_paragraph(device_cards_text, styles['Normal']))
|
| 514 |
story.append(Spacer(1, 12))
|
| 515 |
|
|
@@ -529,13 +533,14 @@ def generate_pdf_content(summary, preview_df, anomalies, amc_reminders, insights
|
|
| 529 |
if not plotly_available:
|
| 530 |
story.append(safe_paragraph("Charts unavailable: plotly not installed.", styles['Normal']))
|
| 531 |
else:
|
| 532 |
-
|
|
|
|
| 533 |
|
| 534 |
doc.build(story)
|
| 535 |
-
logging.info(f"PDF generated at {pdf_path}")
|
| 536 |
return pdf_path
|
| 537 |
except Exception as e:
|
| 538 |
-
logging.error(f"Failed to generate PDF: {str(e)}. Check input data or reportlab configuration.")
|
| 539 |
return None
|
| 540 |
|
| 541 |
# Main processing function
|
|
@@ -585,7 +590,6 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
|
|
| 585 |
filtered_df = filtered_df[filtered_df['equipment_type'] == equipment_type_filter]
|
| 586 |
if date_range is not None:
|
| 587 |
if isinstance(date_range, (int, float)):
|
| 588 |
-
# Convert single value to a range for a single day
|
| 589 |
days = int(date_range)
|
| 590 |
date_range = [days, days]
|
| 591 |
logging.info(f"Converted single value {days} to range {date_range}")
|
|
@@ -649,14 +653,17 @@ async def process_logs(file_obj, lab_site_filter, equipment_type_filter, date_ra
|
|
| 649 |
# Generate PDF separately
|
| 650 |
async def generate_pdf(summary, preview_html, usage_chart, device_cards, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart, anomalies, amc_reminders, insights):
|
| 651 |
try:
|
| 652 |
-
|
| 653 |
-
|
|
|
|
|
|
|
| 654 |
if pdf_file is None:
|
| 655 |
logging.warning("PDF generation failed or disabled.")
|
| 656 |
return "PDF generation failed. Check logs for details."
|
|
|
|
| 657 |
return pdf_file
|
| 658 |
except Exception as e:
|
| 659 |
-
logging.error(f"Failed to generate PDF: {str(e)}")
|
| 660 |
return f"Error generating PDF: {str(e)}"
|
| 661 |
|
| 662 |
# Update filters
|
|
|
|
| 9 |
import time
|
| 10 |
import asyncio
|
| 11 |
from simple_salesforce import Salesforce
|
| 12 |
+
from reportlab.lib.pagesizes import letter
|
| 13 |
+
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
|
| 14 |
+
from reportlab.lib.styles import getSampleStyleSheet
|
| 15 |
+
from reportlab.lib import colors
|
| 16 |
|
| 17 |
# Configure logging
|
| 18 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
|
|
| 45 |
|
| 46 |
# Try to import reportlab
|
| 47 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
reportlab_available = True
|
| 49 |
logging.info("reportlab module successfully imported")
|
| 50 |
except ImportError:
|
|
|
|
| 465 |
return f'<p>Error generating device cards: {str(e)}</p>'
|
| 466 |
|
| 467 |
# Generate PDF content
|
| 468 |
+
def generate_pdf_content(summary, preview_html, anomalies, amc_reminders, insights, device_cards_html, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart):
|
| 469 |
if not reportlab_available:
|
| 470 |
logging.warning("PDF generation disabled: reportlab not available")
|
| 471 |
return None
|
|
|
|
| 475 |
styles = getSampleStyleSheet()
|
| 476 |
story = []
|
| 477 |
|
| 478 |
+
logging.info("Starting PDF generation with summary: %s", summary)
|
| 479 |
def safe_paragraph(text, style):
|
| 480 |
+
cleaned_text = str(text).replace('\n', '<br/>') if text else "No data available"
|
| 481 |
+
return Paragraph(cleaned_text, style)
|
| 482 |
|
| 483 |
story.append(Paragraph("LabOps Status Report", styles['Title']))
|
| 484 |
story.append(Paragraph(f"Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", styles['Normal']))
|
|
|
|
| 489 |
story.append(Spacer(1, 12))
|
| 490 |
|
| 491 |
story.append(Paragraph("Log Preview", styles['Heading2']))
|
| 492 |
+
preview_df = pd.DataFrame() if not preview_html else pd.read_html(preview_html)[0] if pd.read_html(preview_html, flavor='bs4') else pd.DataFrame()
|
| 493 |
+
logging.info("Preview DF shape: %s", preview_df.shape if not preview_df.empty else "Empty")
|
| 494 |
if not preview_df.empty:
|
| 495 |
data = [preview_df.columns.tolist()] + preview_df.head(5).values.tolist()
|
| 496 |
table = Table(data)
|
|
|
|
| 513 |
story.append(Spacer(1, 12))
|
| 514 |
|
| 515 |
story.append(Paragraph("Device Cards", styles['Heading2']))
|
| 516 |
+
device_cards_text = device_cards_html.replace('<div>', '').replace('</div>', '\n').replace('<h4>', '').replace('</h4>', '\n').replace('<p>', '').replace('</p>', '\n').replace('<b>', '').replace('</b>', '').replace('<span style="color: green">', '').replace('<span style="color: red">', '').replace('<span style="color: orange">', '').replace('<span style="color: gray">', '').replace('</span>', '') if device_cards_html else "No device cards available"
|
| 517 |
story.append(safe_paragraph(device_cards_text, styles['Normal']))
|
| 518 |
story.append(Spacer(1, 12))
|
| 519 |
|
|
|
|
| 533 |
if not plotly_available:
|
| 534 |
story.append(safe_paragraph("Charts unavailable: plotly not installed.", styles['Normal']))
|
| 535 |
else:
|
| 536 |
+
chart_count = sum(1 for chart in [daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart] if chart is not None)
|
| 537 |
+
story.append(safe_paragraph(f"[Chart placeholders - {chart_count} charts included, see dashboard for visuals]", styles['Normal']))
|
| 538 |
|
| 539 |
doc.build(story)
|
| 540 |
+
logging.info(f"PDF generated successfully at {pdf_path}")
|
| 541 |
return pdf_path
|
| 542 |
except Exception as e:
|
| 543 |
+
logging.error(f"Failed to generate PDF: {str(e)}. Check input data or reportlab configuration. Input summary: {summary[:100]}...")
|
| 544 |
return None
|
| 545 |
|
| 546 |
# Main processing function
|
|
|
|
| 590 |
filtered_df = filtered_df[filtered_df['equipment_type'] == equipment_type_filter]
|
| 591 |
if date_range is not None:
|
| 592 |
if isinstance(date_range, (int, float)):
|
|
|
|
| 593 |
days = int(date_range)
|
| 594 |
date_range = [days, days]
|
| 595 |
logging.info(f"Converted single value {days} to range {date_range}")
|
|
|
|
| 653 |
# Generate PDF separately
|
| 654 |
async def generate_pdf(summary, preview_html, usage_chart, device_cards, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart, anomalies, amc_reminders, insights):
|
| 655 |
try:
|
| 656 |
+
logging.info("Starting PDF generation process")
|
| 657 |
+
preview_df = pd.DataFrame() if not preview_html else pd.read_html(preview_html, flavor='bs4')[0] if pd.read_html(preview_html, flavor='bs4') else pd.DataFrame()
|
| 658 |
+
logging.info("Preview DF created with shape: %s", preview_df.shape if not preview_df.empty else "Empty")
|
| 659 |
+
pdf_file = generate_pdf_content(summary, preview_html, anomalies, amc_reminders, insights, device_cards, daily_log_chart, weekly_uptime_chart, anomaly_alerts_chart, downtime_chart)
|
| 660 |
if pdf_file is None:
|
| 661 |
logging.warning("PDF generation failed or disabled.")
|
| 662 |
return "PDF generation failed. Check logs for details."
|
| 663 |
+
logging.info("PDF generated successfully at: %s", pdf_file)
|
| 664 |
return pdf_file
|
| 665 |
except Exception as e:
|
| 666 |
+
logging.error(f"Failed to generate PDF: {str(e)}. Input summary: {summary[:100]}...")
|
| 667 |
return f"Error generating PDF: {str(e)}"
|
| 668 |
|
| 669 |
# Update filters
|