"""Asset: Create interactive HTML viewer for frame-by-frame ball tracking""" from pathlib import Path from typing import Dict, List from dagster import asset, AssetExecutionContext @asset( io_manager_key="json_io_manager", compute_kind="html", description="Create interactive HTML viewer with frame + 3D court visualization" ) def create_interactive_viewer( context: AssetExecutionContext, extract_video_frames: Dict, compute_ball_3d_coordinates: List[Dict] ) -> Dict: """ Create interactive HTML viewer showing: - Left: Original video frame - Right: Interactive 3D court (Three.js - rotatable with mouse) - Controls: Prev/Next buttons + slider Outputs: - data/{run_id}/viewer/index.html Returns: Dict with viewer_path """ run_id = context.run_id frames_dir = Path(extract_video_frames['frames_dir']) # Create viewer directory viewer_dir = Path(f"data/{run_id}/viewer") viewer_dir.mkdir(parents=True, exist_ok=True) # Copy frames to viewer directory import shutil viewer_frames_dir = viewer_dir / "frames" viewer_frames_dir.mkdir(exist_ok=True) # Filter frames with detections frames_with_ball = [f for f in compute_ball_3d_coordinates if f['x_m'] is not None] context.log.info(f"Creating viewer for {len(frames_with_ball)} frames with ball detections") # Copy only frames with detections for frame_data in frames_with_ball: frame_num = frame_data['frame'] src = frames_dir / f"frame_{frame_num:04d}.jpg" dst = viewer_frames_dir / f"frame_{frame_num:04d}.jpg" if src.exists(): shutil.copy2(src, dst) context.log.info(f"Copied {len(frames_with_ball)} frames to viewer directory") # Generate HTML html_content = _generate_html(frames_with_ball, run_id) # Save HTML html_path = viewer_dir / "index.html" with open(html_path, 'w') as f: f.write(html_content) context.log.info(f"β Interactive viewer created: {html_path}") context.log.info(f" Open in browser: file://{html_path.absolute()}") return { "viewer_path": str(html_path), "num_frames": len(frames_with_ball) } def _generate_html(frames_data: List[Dict], run_id: str) -> str: """Generate HTML with Three.js for real 3D visualization""" # Convert frames data to JSON import json frames_json = json.dumps(frames_data, indent=2) html = f"""