AudioForge / scripts /generate_launch_report.py
OnyxlMunkey's picture
c618549
#!/usr/bin/env python3
"""
Generate comprehensive launch readiness report
Combines all verification checks into a single PDF/HTML report
"""
import asyncio
import json
import subprocess
import sys
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Any
try:
from jinja2 import Template
import markdown
except ImportError:
print("Installing required packages...")
subprocess.run([sys.executable, "-m", "pip", "install", "jinja2", "markdown"], check=True)
from jinja2 import Template
import markdown
HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AudioForge Launch Report - {{ timestamp }}</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
line-height: 1.6;
color: #333;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 12px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 40px;
text-align: center;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
font-weight: 700;
}
.header .subtitle {
font-size: 1.2em;
opacity: 0.9;
}
.header .timestamp {
margin-top: 20px;
font-size: 0.9em;
opacity: 0.8;
}
.summary {
padding: 40px;
background: #f8f9fa;
border-bottom: 2px solid #e9ecef;
}
.summary-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-top: 20px;
}
.summary-card {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
text-align: center;
transition: transform 0.2s;
}
.summary-card:hover {
transform: translateY(-5px);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.summary-card .value {
font-size: 2.5em;
font-weight: 700;
margin: 10px 0;
}
.summary-card .label {
color: #666;
font-size: 0.9em;
text-transform: uppercase;
letter-spacing: 1px;
}
.summary-card.success .value { color: #28a745; }
.summary-card.warning .value { color: #ffc107; }
.summary-card.danger .value { color: #dc3545; }
.summary-card.info .value { color: #17a2b8; }
.content {
padding: 40px;
}
.section {
margin-bottom: 40px;
}
.section-header {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 2px solid #e9ecef;
}
.section-header h2 {
font-size: 1.8em;
color: #667eea;
}
.section-badge {
padding: 5px 15px;
border-radius: 20px;
font-size: 0.8em;
font-weight: 600;
}
.section-badge.pass {
background: #d4edda;
color: #155724;
}
.section-badge.fail {
background: #f8d7da;
color: #721c24;
}
.section-badge.warn {
background: #fff3cd;
color: #856404;
}
.checks-table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
.checks-table th {
background: #f8f9fa;
padding: 12px;
text-align: left;
font-weight: 600;
border-bottom: 2px solid #dee2e6;
}
.checks-table td {
padding: 12px;
border-bottom: 1px solid #e9ecef;
}
.checks-table tr:hover {
background: #f8f9fa;
}
.status-icon {
font-size: 1.5em;
display: inline-block;
width: 30px;
text-align: center;
}
.check-details {
font-size: 0.9em;
color: #666;
margin-top: 5px;
}
.fix-command {
background: #f8f9fa;
padding: 8px 12px;
border-radius: 4px;
font-family: 'Courier New', monospace;
font-size: 0.85em;
margin-top: 5px;
border-left: 3px solid #ffc107;
}
.footer {
background: #f8f9fa;
padding: 30px;
text-align: center;
color: #666;
border-top: 2px solid #e9ecef;
}
.footer .logo {
font-size: 2em;
margin-bottom: 10px;
}
.progress-bar {
width: 100%;
height: 30px;
background: #e9ecef;
border-radius: 15px;
overflow: hidden;
margin: 20px 0;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #28a745 0%, #20c997 100%);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: 600;
transition: width 0.3s ease;
}
.action-items {
background: #fff3cd;
border-left: 4px solid #ffc107;
padding: 20px;
margin: 20px 0;
border-radius: 4px;
}
.action-items h3 {
color: #856404;
margin-bottom: 15px;
}
.action-items ul {
list-style: none;
padding-left: 0;
}
.action-items li {
padding: 8px 0;
border-bottom: 1px solid #ffeaa7;
}
.action-items li:last-child {
border-bottom: none;
}
@media print {
body {
background: white;
padding: 0;
}
.container {
box-shadow: none;
}
.summary-card:hover {
transform: none;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🎵 AudioForge Launch Report</h1>
<div class="subtitle">Production Readiness Verification</div>
<div class="timestamp">Generated: {{ timestamp }}</div>
</div>
<div class="summary">
<h2>Executive Summary</h2>
<div class="progress-bar">
<div class="progress-fill" style="width: {{ overall_success_rate }}%;">
{{ overall_success_rate }}% Ready
</div>
</div>
<div class="summary-grid">
<div class="summary-card success">
<div class="label">Passed</div>
<div class="value">{{ total_passed }}</div>
</div>
<div class="summary-card danger">
<div class="label">Failed</div>
<div class="value">{{ total_failed }}</div>
</div>
<div class="summary-card warning">
<div class="label">Warnings</div>
<div class="value">{{ total_warned }}</div>
</div>
<div class="summary-card info">
<div class="label">Total Checks</div>
<div class="value">{{ total_checks }}</div>
</div>
</div>
{% if overall_success_rate == 100 %}
<div style="margin-top: 30px; padding: 20px; background: #d4edda; border-radius: 8px; text-align: center;">
<h3 style="color: #155724; font-size: 1.5em;">🎉 READY TO LAUNCH!</h3>
<p style="color: #155724; margin-top: 10px;">All systems are go. You're cleared for production deployment.</p>
</div>
{% elif overall_success_rate >= 90 %}
<div style="margin-top: 30px; padding: 20px; background: #fff3cd; border-radius: 8px; text-align: center;">
<h3 style="color: #856404; font-size: 1.5em;">⚠️ ALMOST READY</h3>
<p style="color: #856404; margin-top: 10px;">Minor issues to address before launch.</p>
</div>
{% else %}
<div style="margin-top: 30px; padding: 20px; background: #f8d7da; border-radius: 8px; text-align: center;">
<h3 style="color: #721c24; font-size: 1.5em;">❌ NOT READY</h3>
<p style="color: #721c24; margin-top: 10px;">Critical issues must be resolved before launch.</p>
</div>
{% endif %}
</div>
<div class="content">
{% for section_name, section_data in sections.items() %}
<div class="section">
<div class="section-header">
<h2>{{ section_name }}</h2>
{% if section_data.success_rate == 100 %}
<span class="section-badge pass">✅ {{ section_data.passed }}/{{ section_data.total }}</span>
{% elif section_data.failed > 0 %}
<span class="section-badge fail">❌ {{ section_data.failed }} Failed</span>
{% else %}
<span class="section-badge warn">⚠️ {{ section_data.warned }} Warnings</span>
{% endif %}
</div>
<table class="checks-table">
<thead>
<tr>
<th style="width: 50px;">Status</th>
<th>Check</th>
<th>Message</th>
</tr>
</thead>
<tbody>
{% for check in section_data.checks %}
<tr>
<td><span class="status-icon">{{ check.status_icon }}</span></td>
<td><strong>{{ check.name }}</strong></td>
<td>
{{ check.message }}
{% if check.details %}
<div class="check-details">{{ check.details }}</div>
{% endif %}
{% if check.fix_command %}
<div class="fix-command">Fix: {{ check.fix_command }}</div>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endfor %}
{% if action_items %}
<div class="action-items">
<h3>⚡ Action Items</h3>
<ul>
{% for item in action_items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
<div class="footer">
<div class="logo">🐼⚡</div>
<p>AudioForge Launch Verification System</p>
<p style="margin-top: 10px; font-size: 0.9em;">
Forged by FusionPanda | {{ timestamp }}
</p>
</div>
</div>
</body>
</html>
"""
async def generate_report():
"""Generate comprehensive launch report."""
print("🎵 Generating AudioForge Launch Report...")
print("=" * 60)
# Run verification script
print("\n📊 Running verification checks...")
result = subprocess.run(
[sys.executable, "scripts/launch_verification.py", "--json", "launch-results.json"],
capture_output=True,
text=True
)
# Load results
results_file = Path("launch-results.json")
if not results_file.exists():
print("❌ Verification results not found!")
sys.exit(1)
with open(results_file) as f:
data = json.load(f)
# Calculate totals
total_passed = sum(section["passed"] for section in data.values())
total_failed = sum(section["failed"] for section in data.values())
total_warned = sum(section["warned"] for section in data.values())
total_checks = sum(section["total"] for section in data.values())
overall_success_rate = round((total_passed / total_checks * 100) if total_checks > 0 else 0, 1)
# Collect action items
action_items = []
for section_name, section_data in data.items():
for check in section_data["checks"]:
if check.get("details") and ("fix" in check["details"].lower() or "missing" in check["details"].lower()):
action_items.append(f"{section_name}: {check['name']} - {check['message']}")
# Prepare template data
template_data = {
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"total_passed": total_passed,
"total_failed": total_failed,
"total_warned": total_warned,
"total_checks": total_checks,
"overall_success_rate": overall_success_rate,
"sections": data,
"action_items": action_items[:10], # Top 10 action items
}
# Add status icons
status_icons = {
"PASS": "✅",
"FAIL": "❌",
"WARN": "⚠️",
"SKIP": "⏭️",
"INFO": "ℹ️",
}
for section_data in template_data["sections"].values():
for check in section_data["checks"]:
check["status_icon"] = status_icons.get(check["status"], "❓")
# Generate HTML report
template = Template(HTML_TEMPLATE)
html_content = template.render(**template_data)
# Save report
report_path = Path("LAUNCH_REPORT.html")
report_path.write_text(html_content, encoding="utf-8")
print(f"\n✅ Report generated: {report_path.absolute()}")
print(f"📊 Overall Success Rate: {overall_success_rate}%")
print(f"✅ Passed: {total_passed}")
print(f"❌ Failed: {total_failed}")
print(f"⚠️ Warnings: {total_warned}")
# Print status
if overall_success_rate == 100:
print("\n🎉 READY TO LAUNCH!")
elif overall_success_rate >= 90:
print("\n⚠️ ALMOST READY - Minor issues to fix")
else:
print("\n❌ NOT READY - Critical issues found")
# Open report in browser (optional)
try:
import webbrowser
webbrowser.open(f"file://{report_path.absolute()}")
print(f"\n🌐 Opening report in browser...")
except Exception:
pass
return overall_success_rate >= 90
if __name__ == "__main__":
success = asyncio.run(generate_report())
sys.exit(0 if success else 1)