hm_ai_qc_report_tool/app.py
nickviljoen e910e00edf Add Usage Dashboard with token tracking, cost estimates, and filters
- New UsageLog model tracking every LLM API call (provider, model,
  tokens, estimated cost, user, module, check name)
- Instrument LLMConfig.call_vision_api() to auto-log each call
- New /usage tab in nav bar with dashboard showing:
  - Summary cards (total calls, tokens, estimated cost)
  - Breakdowns by provider, model, tool, and user
  - Recent API calls table
  - Time filters (All Time, 30 Days, 7 Days, Today)
- Cost estimates based on per-model token pricing
- Pass logged-in user through executor context for tracking

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 18:17:21 +02:00

163 lines
4.8 KiB
Python

"""
Flask Application Factory for Unified HM QC Platform.
This application merges multiple QC tools into a single platform with:
- HM QC (PDF/image quality control)
- Video QC (video quality control)
- Video Master Adot Detection (video matching)
- Reporting (consolidated reports from Box.com and QC modules)
"""
import logging
import os
from flask import Flask, render_template, session, request, redirect, url_for
# Import configuration
import config as app_config
# Import core modules
from core.auth.middleware import AuthMiddleware
from core.models.database import init_db, db
from core.services.box_client import BoxReportClient
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
def create_app(config_class=app_config.Config):
"""
Application factory function.
Args:
config_class: Configuration class to use
Returns:
Configured Flask application instance
"""
# Initialize Flask app
app = Flask(__name__)
app.config.from_object(config_class)
# Create necessary directories
os.makedirs('database', exist_ok=True)
os.makedirs('uploads/hm_qc', exist_ok=True)
os.makedirs('uploads/video_qc', exist_ok=True)
os.makedirs('uploads/video_master', exist_ok=True)
os.makedirs('storage/reports/hm_qc', exist_ok=True)
os.makedirs('storage/reports/consolidated', exist_ok=True)
# Initialize database
init_db(app)
logger.info("Database initialized")
# Initialize authentication middleware (simple session-based auth)
auth = AuthMiddleware(app)
logger.info("Authentication initialized")
app.auth = auth
# Initialize Box client (lazy loading)
app._box_client = None
def get_box_client():
"""Get or initialize Box client."""
if app._box_client is None:
try:
app._box_client = BoxReportClient(
config_path=app.config['BOX_CONFIG_PATH'],
report_folder_id=app.config['BOX_REPORT_FOLDER_ID']
)
logger.info("Box client initialized successfully")
except Exception as e:
logger.error(f"Failed to initialize Box client: {e}")
raise
return app._box_client
# Store box client getter in app context
app.get_box_client = get_box_client
# Register blueprints
# Auth blueprint (for login/logout endpoints)
from core.auth.routes import auth_bp
app.register_blueprint(auth_bp)
logger.info("Auth blueprint registered at /auth")
# Require login for all routes except auth endpoints and static files
@app.before_request
def require_login():
allowed_prefixes = ('/auth/', '/static/')
if any(request.path.startswith(p) for p in allowed_prefixes):
return None
if not session.get('authenticated'):
return redirect(url_for('auth.login_page'))
# Task #3: Reporting blueprint (COMPLETED)
from modules.reporting import reporting_bp
app.register_blueprint(reporting_bp)
logger.info("Reporting blueprint registered at /reporting")
# Task #4: HM QC blueprint (COMPLETED)
from modules.hm_qc import hm_qc_bp
app.register_blueprint(hm_qc_bp)
logger.info("HM QC blueprint registered at /hm-qc")
# Task #5: Video QC blueprint (BETA)
from modules.video_qc import video_qc_bp
app.register_blueprint(video_qc_bp)
logger.info("Video QC blueprint (BETA) registered at /video-qc")
# Task #6: Video Master blueprint (BETA)
from modules.video_master import video_master_bp
app.register_blueprint(video_master_bp)
logger.info("Video Master blueprint (BETA) registered at /video-master")
# Usage Dashboard
from modules.usage import usage_bp
app.register_blueprint(usage_bp)
logger.info("Usage dashboard registered at /usage")
@app.route('/')
def root():
"""Render reporting index at root."""
return render_template('reporting/index.html', active_tab='reporting')
# Register error handlers
register_error_handlers(app)
logger.info("Application initialized successfully")
return app
def register_error_handlers(app):
"""
Register error handlers.
Args:
app: Flask application
"""
@app.errorhandler(404)
def not_found(error):
"""Handle 404 errors."""
return render_template('404.html'), 404
@app.errorhandler(500)
def internal_error(error):
"""Handle 500 errors."""
logger.error(f"Internal server error: {error}")
return render_template('500.html'), 500
# Create application instance
app = create_app()
if __name__ == '__main__':
# Run app
app.run(
host=app.config['HOST'],
port=app.config['PORT'],
debug=True
)