Files
timmy-config/wizards/allegro-primus/dashboard/dashboard.py
2026-03-31 20:02:01 +00:00

296 lines
8.7 KiB
Python

"""
Allegro-Primus Progress Dashboard
Main dashboard server with real-time metrics and visualization.
"""
import os
import sys
import json
import logging
from datetime import datetime, timedelta
from pathlib import Path
from typing import Dict, List, Any, Optional
from flask import Flask, render_template, jsonify, request, send_from_directory
from flask import Response
import threading
# Add parent directory to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent))
# Import API blueprint
from api import api_bp, metrics_collector, knowledge_stats, issue_tracker
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Flask app
app = Flask(__name__,
template_folder='templates',
static_folder='static')
app.register_blueprint(api_bp)
# Configuration
DASHBOARD_PORT = int(os.getenv('AP_DASHBOARD_PORT', 8080))
DASHBOARD_HOST = os.getenv('AP_DASHBOARD_HOST', '0.0.0.0')
# Paths
BASE_DIR = Path("/root/wizards/allegro-primus")
JOURNAL_DIR = BASE_DIR / ".journal"
class DashboardData:
"""Centralized dashboard data management."""
def __init__(self):
self._cache = {}
self._cache_time = None
self._cache_ttl = 30 # seconds
def get_overview(self) -> Dict[str, Any]:
"""Get dashboard overview data."""
return {
"metrics": metrics_collector.get_current_metrics(),
"performance": metrics_collector.get_performance_metrics(),
"issues": issue_tracker.get_issue_stats(),
"knowledge": knowledge_stats.get_stats(),
"model_comparison": metrics_collector.get_model_comparison(),
"timestamp": datetime.now().isoformat()
}
def get_charts_data(self) -> Dict[str, Any]:
"""Get data for charts."""
time_series = metrics_collector.get_time_series(30)
return {
"time_series": time_series,
"success_rate_trend": [
{"date": t['date'], "rate": t['success'] / (t['success'] + t['failed']) * 100
if (t['success'] + t['failed']) > 0 else 0}
for t in time_series
],
"response_time_trend": [
{"date": t['date'], "time": t['avg_response_time']}
for t in time_series
],
"task_volume": [
{"date": t['date'], "tasks": t['total_tasks']}
for t in time_series
]
}
dashboard_data = DashboardData()
# Routes
@app.route('/')
def index():
"""Main dashboard page."""
overview = dashboard_data.get_overview()
charts_data = dashboard_data.get_charts_data()
return render_template('index.html',
overview=overview,
charts_data=charts_data,
now=datetime.now())
@app.route('/metrics')
def metrics_page():
"""Detailed metrics page."""
metrics = {
"current": metrics_collector.get_current_metrics(),
"performance": metrics_collector.get_performance_metrics(),
"model_comparison": metrics_collector.get_model_comparison(),
"time_series": metrics_collector.get_time_series(30)
}
return render_template('metrics.html', metrics=metrics)
@app.route('/journal')
def journal_page():
"""Journal entries page."""
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 20, type=int)
entries = metrics_collector.journal_entries
total = len(entries)
# Sort by timestamp descending
sorted_entries = sorted(entries, key=lambda x: x.get('timestamp', ''), reverse=True)
# Paginate
start = (page - 1) * per_page
end = start + per_page
paginated_entries = sorted_entries[start:end]
total_pages = (total + per_page - 1) // per_page
return render_template('journal.html',
entries=paginated_entries,
page=page,
per_page=per_page,
total=total,
total_pages=total_pages)
@app.route('/issues')
def issues_page():
"""Issues page."""
issues = issue_tracker.get_issues()
stats = issue_tracker.get_issue_stats()
return render_template('issues.html',
issues=issues,
stats=stats)
@app.route('/knowledge')
def knowledge_page():
"""Knowledge base page."""
stats = knowledge_stats.get_stats()
return render_template('knowledge.html', stats=stats)
@app.route('/reports')
def reports_page():
"""Reports page."""
from reports import ReportGenerator
generator = ReportGenerator()
# Generate all reports
daily = generator.generate_daily_report()
weekly = generator.generate_weekly_report()
issues_report = generator.generate_issues_report()
knowledge_report = generator.generate_knowledge_report()
return render_template('reports.html',
daily=daily,
weekly=weekly,
issues=issues_report,
knowledge=knowledge_report)
@app.route('/report/<report_type>')
def view_report(report_type):
"""View specific report."""
from reports import ReportGenerator
generator = ReportGenerator()
if report_type == 'daily':
report = generator.generate_daily_report()
elif report_type == 'weekly':
report = generator.generate_weekly_report()
elif report_type == 'issues':
report = generator.generate_issues_report()
elif report_type == 'knowledge':
report = generator.generate_knowledge_report()
elif report_type == 'improvement':
report = generator.generate_self_improvement_report()
else:
return "Report not found", 404
return render_template('report.html',
report=report,
report_type=report_type)
@app.route('/export/<format>')
def export_data(format):
"""Export dashboard data."""
if format == 'json':
data = dashboard_data.get_overview()
return Response(
json.dumps(data, indent=2, default=str),
mimetype='application/json',
headers={'Content-Disposition': f'attachment; filename=ap_dashboard_{datetime.now().strftime("%Y%m%d")}.json'}
)
elif format == 'csv':
import csv
import io
output = io.StringIO()
writer = csv.writer(output)
writer.writerow(['Timestamp', 'Task', 'Result', 'Success', 'Response Time (ms)'])
for entry in metrics_collector.journal_entries:
writer.writerow([
entry.get('timestamp'),
entry.get('task'),
entry.get('result'),
entry.get('success'),
entry.get('response_time_ms')
])
return Response(
output.getvalue(),
mimetype='text/csv',
headers={'Content-Disposition': f'attachment; filename=ap_journal_{datetime.now().strftime("%Y%m%d")}.csv'}
)
return "Invalid format", 400
# Static files
@app.route('/static/<path:filename>')
def serve_static(filename):
"""Serve static files."""
return send_from_directory('static', filename)
# Error handlers
@app.errorhandler(404)
def not_found(e):
return render_template('error.html', error="Page not found"), 404
@app.errorhandler(500)
def server_error(e):
return render_template('error.html', error="Internal server error"), 500
# Context processors
@app.context_processor
def inject_globals():
"""Inject global variables into templates."""
return {
'app_name': 'Allegro-Primus Dashboard',
'app_version': '1.0.0',
'current_year': datetime.now().year
}
def run_dashboard(host: str = None, port: int = None, debug: bool = False):
"""Run the dashboard server."""
host = host or DASHBOARD_HOST
port = port or DASHBOARD_PORT
logger.info(f"Starting Allegro-Primus Dashboard on {host}:{port}")
try:
app.run(host=host, port=port, debug=debug, threaded=True)
except Exception as e:
logger.error(f"Failed to start dashboard: {e}")
raise
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description='Allegro-Primus Dashboard')
parser.add_argument('--host', default=DASHBOARD_HOST, help='Host to bind to')
parser.add_argument('--port', type=int, default=DASHBOARD_PORT, help='Port to bind to')
parser.add_argument('--debug', action='store_true', help='Enable debug mode')
args = parser.parse_args()
run_dashboard(args.host, args.port, args.debug)