From 6739059038595aebaa99e0f9587ef80d18dfbf63 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Sat, 20 Sep 2025 20:42:07 -0400 Subject: [PATCH] Implement Phase 1: Core milestone system architecture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add complete MilestoneSystem class with 5 epic milestones - Integrate milestone detection into module completion workflow - Implement milestone CLI commands (status, timeline, test, demo) - Add milestone progress tracking and storage (.tito/milestones.json) - Create epic celebration system for milestone unlocks - Register milestone commands in main CLI Features: - 5 milestones: Basic Inference โ†’ Computer Vision โ†’ Full Training โ†’ Advanced Vision โ†’ Language Generation - Visual progress tracking with Rich library - Module completion triggers milestone evaluation - Epic ASCII art celebrations for achievements - Timeline views (tree and horizontal progress bar) - Milestone testing and validation The milestone system transforms module completion into meaningful capability achievements that prepare students for ML engineering careers. --- tito/commands/milestone.py | 734 +++++++++++++++++++++++++++++++++++++ tito/commands/module.py | 185 +++++++++- tito/main.py | 7 +- 3 files changed, 906 insertions(+), 20 deletions(-) create mode 100644 tito/commands/milestone.py diff --git a/tito/commands/milestone.py b/tito/commands/milestone.py new file mode 100644 index 00000000..eec41a60 --- /dev/null +++ b/tito/commands/milestone.py @@ -0,0 +1,734 @@ +""" +Milestone command group for TinyTorch CLI: capability-based learning progression. + +The milestone system transforms module completion into meaningful capability achievements. +Instead of just finishing modules, students unlock epic milestones that represent +real-world ML engineering skills. +""" + +from argparse import ArgumentParser, Namespace +from rich.panel import Panel +from rich import box +from rich.progress import Progress, BarColumn, TextColumn, SpinnerColumn, TimeElapsedColumn +from rich.console import Console +from rich.align import Align +from rich.text import Text +from rich.layout import Layout +from rich.tree import Tree +from rich.columns import Columns +import sys +import json +import time +import subprocess +from datetime import datetime +from pathlib import Path + +from .base import BaseCommand +from .checkpoint import CheckpointSystem +from ..core.console import print_ascii_logo +from ..core.console import get_console + + +class MilestoneSystem: + """Core milestone tracking and management system.""" + + def __init__(self, config): + self.config = config + self.console = get_console() + + # Define the 5 Epic Milestones + self.MILESTONES = { + "1": { + "id": "1", + "name": "Basic Inference", + "title": "Neural Networks Work!", + "trigger_module": "05_dense", + "required_checkpoints": ["00", "01", "02", "03", "04"], + "victory_condition": "Build multi-layer networks that solve XOR problem", + "capability": "I can create working neural networks!", + "real_world_impact": "Foundation of any AI system", + "emoji": "๐Ÿฅ‰", + "celebration_level": "milestone", + "demo_file": "01_basic_inference_demo.py" + }, + "2": { + "id": "2", + "name": "Computer Vision", + "title": "Machines Can See!", + "trigger_module": "06_spatial", + "required_checkpoints": ["05"], + "victory_condition": "Achieve 95%+ accuracy on MNIST with CNN", + "capability": "I can teach machines to see!", + "real_world_impact": "Image recognition like autonomous vehicles", + "emoji": "๐Ÿฅˆ", + "celebration_level": "major", + "demo_file": "02_computer_vision_demo.py" + }, + "3": { + "id": "3", + "name": "Full Training", + "title": "Production Training!", + "trigger_module": "11_training", + "required_checkpoints": ["06", "07", "08", "09", "10"], + "victory_condition": "Train CNN from scratch to convergence on CIFAR-10", + "capability": "I can train production ML models!", + "real_world_impact": "Train models like those used in industry", + "emoji": "๐Ÿ†", + "celebration_level": "major", + "demo_file": "03_full_training_demo.py" + }, + "4": { + "id": "4", + "name": "Advanced Vision", + "title": "Production Vision!", + "trigger_module": "13_kernels", + "required_checkpoints": ["11", "12"], + "victory_condition": "Achieve 75%+ accuracy on CIFAR-10 with optimized kernels", + "capability": "I build production-ready vision systems!", + "real_world_impact": "Computer vision systems used in tech companies", + "emoji": "๐Ÿ’Ž", + "celebration_level": "epic", + "demo_file": "04_advanced_vision_demo.py" + }, + "5": { + "id": "5", + "name": "Language Generation", + "title": "Build the Future!", + "trigger_module": "16_tinygpt", + "required_checkpoints": ["13", "14", "15"], + "victory_condition": "Generate coherent text and Python code with TinyGPT", + "capability": "I can build the future of AI!", + "real_world_impact": "Build systems like ChatGPT and GitHub Copilot", + "emoji": "๐Ÿ‘‘", + "celebration_level": "north_star", + "demo_file": "05_language_generation_demo.py" + } + } + + def get_milestone_status(self) -> dict: + """Get current milestone progress status.""" + checkpoint_system = CheckpointSystem(self.config) + milestone_data = self._get_milestone_progress_data() + + status = { + "milestones": {}, + "overall_progress": 0, + "total_unlocked": 0, + "next_milestone": None + } + + total_milestones = len(self.MILESTONES) + unlocked_count = 0 + + for milestone_id, milestone in self.MILESTONES.items(): + # Check if all required checkpoints are complete + required_complete = all( + checkpoint_system.get_checkpoint_status(cp_id).get("is_complete", False) + for cp_id in milestone["required_checkpoints"] + ) + + # Check if milestone is unlocked + is_unlocked = milestone_id in milestone_data.get("unlocked_milestones", []) + + # Check if trigger module is completed + trigger_complete = self._is_module_completed(milestone["trigger_module"]) + + milestone_status = { + "id": milestone_id, + "name": milestone["name"], + "title": milestone["title"], + "emoji": milestone["emoji"], + "trigger_module": milestone["trigger_module"], + "required_checkpoints": milestone["required_checkpoints"], + "victory_condition": milestone["victory_condition"], + "capability": milestone["capability"], + "real_world_impact": milestone["real_world_impact"], + "required_complete": required_complete, + "trigger_complete": trigger_complete, + "is_unlocked": is_unlocked, + "can_unlock": required_complete and trigger_complete and not is_unlocked, + "unlock_date": milestone_data.get("unlock_dates", {}).get(milestone_id) + } + + status["milestones"][milestone_id] = milestone_status + + if is_unlocked: + unlocked_count += 1 + elif milestone_status["can_unlock"] and not status["next_milestone"]: + status["next_milestone"] = milestone_id + + status["total_unlocked"] = unlocked_count + status["overall_progress"] = (unlocked_count / total_milestones) * 100 + + return status + + def check_milestone_unlock(self, completed_module: str) -> dict: + """Check if completing a module unlocks a milestone.""" + result = { + "milestone_unlocked": False, + "milestone_id": None, + "milestone_data": None, + "celebration_needed": False + } + + # Find milestone triggered by this module + for milestone_id, milestone in self.MILESTONES.items(): + if milestone["trigger_module"] == completed_module: + status = self.get_milestone_status() + milestone_status = status["milestones"][milestone_id] + + if milestone_status["can_unlock"]: + # Unlock the milestone! + self._unlock_milestone(milestone_id) + result.update({ + "milestone_unlocked": True, + "milestone_id": milestone_id, + "milestone_data": milestone, + "celebration_needed": True + }) + break + + return result + + def run_milestone_test(self, milestone_id: str) -> dict: + """Run tests to validate milestone achievement.""" + if milestone_id not in self.MILESTONES: + return {"success": False, "error": f"Milestone {milestone_id} not found"} + + milestone = self.MILESTONES[milestone_id] + + # Check all required checkpoints + checkpoint_system = CheckpointSystem(self.config) + failed_checkpoints = [] + + for cp_id in milestone["required_checkpoints"]: + if not checkpoint_system.get_checkpoint_status(cp_id).get("is_complete", False): + failed_checkpoints.append(cp_id) + + if failed_checkpoints: + return { + "success": False, + "error": f"Required checkpoints not completed: {', '.join(failed_checkpoints)}", + "milestone_name": milestone["name"] + } + + # Check trigger module completion + if not self._is_module_completed(milestone["trigger_module"]): + return { + "success": False, + "error": f"Trigger module {milestone['trigger_module']} not completed", + "milestone_name": milestone["name"] + } + + # All tests passed + return { + "success": True, + "milestone_id": milestone_id, + "milestone_name": milestone["name"], + "title": milestone["title"], + "capability": milestone["capability"], + "victory_condition": milestone["victory_condition"] + } + + def _unlock_milestone(self, milestone_id: str) -> None: + """Record milestone unlock in progress tracking.""" + milestone_data = self._get_milestone_progress_data() + + if milestone_id not in milestone_data["unlocked_milestones"]: + milestone_data["unlocked_milestones"].append(milestone_id) + milestone_data["unlock_dates"][milestone_id] = datetime.now().isoformat() + milestone_data["total_unlocked"] = len(milestone_data["unlocked_milestones"]) + + self._save_milestone_progress_data(milestone_data) + + def _is_module_completed(self, module_name: str) -> bool: + """Check if a module has been completed.""" + # Check module progress file + progress_file = Path(".tito") / "progress.json" + if progress_file.exists(): + try: + with open(progress_file, 'r') as f: + progress_data = json.load(f) + return module_name in progress_data.get("completed_modules", []) + except (json.JSONDecodeError, IOError): + pass + return False + + def _get_milestone_progress_data(self) -> dict: + """Get or create milestone progress data.""" + progress_dir = Path(".tito") + progress_file = progress_dir / "milestones.json" + + progress_dir.mkdir(exist_ok=True) + + if progress_file.exists(): + try: + with open(progress_file, 'r') as f: + return json.load(f) + except (json.JSONDecodeError, IOError): + pass + + return { + "unlocked_milestones": [], + "unlock_dates": {}, + "total_unlocked": 0, + "achievements": [] + } + + def _save_milestone_progress_data(self, milestone_data: dict) -> None: + """Save milestone progress data.""" + progress_dir = Path(".tito") + progress_file = progress_dir / "milestones.json" + + progress_dir.mkdir(exist_ok=True) + + try: + with open(progress_file, 'w') as f: + json.dump(milestone_data, f, indent=2) + except IOError: + pass + + +class MilestoneCommand(BaseCommand): + @property + def name(self) -> str: + return "milestone" + + @property + def description(self) -> str: + return "Milestone achievement and capability unlock commands" + + def add_arguments(self, parser: ArgumentParser) -> None: + subparsers = parser.add_subparsers( + dest='milestone_command', + help='Milestone subcommands', + metavar='SUBCOMMAND' + ) + + # Status subcommand + status_parser = subparsers.add_parser( + 'status', + help='View milestone progress and achievements' + ) + status_parser.add_argument( + '--detailed', + action='store_true', + help='Show detailed milestone information' + ) + + # Timeline subcommand + timeline_parser = subparsers.add_parser( + 'timeline', + help='View milestone timeline and progression' + ) + timeline_parser.add_argument( + '--horizontal', + action='store_true', + help='Show horizontal progress bar instead of tree' + ) + + # Test subcommand + test_parser = subparsers.add_parser( + 'test', + help='Test milestone achievement requirements' + ) + test_parser.add_argument( + 'milestone_id', + nargs='?', + help='Milestone ID to test (1-5), or test next available' + ) + + # Demo subcommand + demo_parser = subparsers.add_parser( + 'demo', + help='Run milestone capability demonstration' + ) + demo_parser.add_argument( + 'milestone_id', + help='Milestone ID to demonstrate (1-5)' + ) + + def run(self, args: Namespace) -> int: + console = self.console + + if not hasattr(args, 'milestone_command') or not args.milestone_command: + console.print(Panel( + "[bold cyan]Milestone Commands[/bold cyan]\n\n" + "Transform module completion into epic capability achievements!\n\n" + "Available subcommands:\n" + " โ€ข [bold]status[/bold] - View milestone progress and achievements\n" + " โ€ข [bold]timeline[/bold] - View milestone timeline and progression\n" + " โ€ข [bold]test[/bold] - Test milestone achievement requirements\n" + " โ€ข [bold]demo[/bold] - Run milestone capability demonstration\n\n" + "[dim]Examples:[/dim]\n" + "[dim] tito milestone status --detailed[/dim]\n" + "[dim] tito milestone timeline --horizontal[/dim]\n" + "[dim] tito milestone test 2[/dim]\n" + "[dim] tito milestone demo 1[/dim]", + title="๐ŸŽฎ Milestone System", + border_style="bright_cyan" + )) + return 0 + + # Execute the appropriate subcommand + if args.milestone_command == 'status': + return self._handle_status_command(args) + elif args.milestone_command == 'timeline': + return self._handle_timeline_command(args) + elif args.milestone_command == 'test': + return self._handle_test_command(args) + elif args.milestone_command == 'demo': + return self._handle_demo_command(args) + else: + console.print(Panel( + f"[red]Unknown milestone subcommand: {args.milestone_command}[/red]", + title="Error", + border_style="red" + )) + return 1 + + def _handle_status_command(self, args: Namespace) -> int: + """Handle milestone status command.""" + console = self.console + milestone_system = MilestoneSystem(self.config) + status = milestone_system.get_milestone_status() + + # Show header with overall progress + console.print(Panel( + f"[bold cyan]๐ŸŽฎ TinyTorch Milestone Progress[/bold cyan]\n\n" + f"[bold]Capabilities Unlocked:[/bold] {status['total_unlocked']}/5 milestones\n" + f"[bold]Overall Progress:[/bold] {status['overall_progress']:.0f}%\n\n" + f"[dim]Transform from student to ML Systems Engineer![/dim]", + title="๐Ÿš€ Your Epic Journey", + border_style="bright_blue" + )) + + # Show milestone status + for milestone_id in ["1", "2", "3", "4", "5"]: + milestone = status["milestones"][milestone_id] + self._show_milestone_status(milestone, args.detailed) + + # Show next steps + if status["next_milestone"]: + next_milestone = status["milestones"][status["next_milestone"]] + console.print(Panel( + f"[bold cyan]๐ŸŽฏ Next Achievement[/bold cyan]\n\n" + f"[bold yellow]{next_milestone['emoji']} {next_milestone['title']}[/bold yellow]\n" + f"[dim]{next_milestone['victory_condition']}[/dim]\n\n" + f"[green]Ready to unlock![/green] Complete: {next_milestone['trigger_module']}\n" + f"[dim]tito module complete {next_milestone['trigger_module']}[/dim]", + title="Next Milestone", + border_style="bright_green" + )) + elif status["total_unlocked"] == 5: + console.print(Panel( + f"[bold green]๐Ÿ† QUEST COMPLETE! ๐Ÿ†[/bold green]\n\n" + f"[green]You've unlocked all 5 epic milestones![/green]\n" + f"[bold white]You are now an ML Systems Engineer![/bold white]\n\n" + f"[cyan]Share your achievement and inspire others![/cyan]", + title="๐ŸŒŸ FULL MASTERY ACHIEVED", + border_style="bright_green" + )) + + return 0 + + def _show_milestone_status(self, milestone: dict, detailed: bool = False) -> None: + """Show status for a single milestone.""" + console = self.console + + # Status indicator + if milestone["is_unlocked"]: + status_icon = "๐Ÿ”“" + status_color = "green" + status_text = "UNLOCKED" + elif milestone["can_unlock"]: + status_icon = "โšก" + status_color = "yellow" + status_text = "READY TO UNLOCK" + elif milestone["required_complete"] and not milestone["trigger_complete"]: + status_icon = "๐Ÿ”’" + status_color = "cyan" + status_text = f"COMPLETE: {milestone['trigger_module']}" + else: + status_icon = "๐Ÿ”’" + status_color = "dim" + status_text = "LOCKED" + + # Basic display + milestone_content = ( + f"[{status_color}]{status_icon} {milestone['emoji']} {milestone['title']}[/{status_color}]\n" + f"[dim]{milestone['victory_condition']}[/dim]" + ) + + # Add detailed information if requested + if detailed: + req_status = "โœ…" if milestone["required_complete"] else "โŒ" + trigger_status = "โœ…" if milestone["trigger_complete"] else "โŒ" + + milestone_content += ( + f"\n\n[bold]Requirements:[/bold]\n" + f" {req_status} Checkpoints: {', '.join(milestone['required_checkpoints'])}\n" + f" {trigger_status} Module: {milestone['trigger_module']}\n" + f"[bold]Capability:[/bold] {milestone['capability']}\n" + f"[bold]Impact:[/bold] {milestone['real_world_impact']}" + ) + + if milestone["is_unlocked"] and milestone.get("unlock_date"): + unlock_date = datetime.fromisoformat(milestone["unlock_date"]).strftime("%Y-%m-%d") + milestone_content += f"\n[dim]Unlocked: {unlock_date}[/dim]" + + console.print(Panel( + milestone_content, + title=f"Milestone {milestone['id']}", + border_style=status_color + )) + + def _handle_timeline_command(self, args: Namespace) -> int: + """Handle milestone timeline command.""" + console = self.console + milestone_system = MilestoneSystem(self.config) + status = milestone_system.get_milestone_status() + + if args.horizontal: + self._show_horizontal_timeline(status) + else: + self._show_tree_timeline(status) + + return 0 + + def _show_horizontal_timeline(self, status: dict) -> None: + """Show horizontal progress bar timeline.""" + console = self.console + + console.print(Panel( + f"[bold cyan]๐ŸŽฎ Milestone Timeline[/bold cyan]\n\n" + f"[bold]Progress:[/bold] {status['total_unlocked']}/5 milestones unlocked", + title="Your Epic Journey", + border_style="bright_blue" + )) + + # Create progress bar + progress_width = 50 + unlocked_width = int((status["total_unlocked"] / 5) * progress_width) + + # Create milestone markers + timeline = [] + for i in range(5): + milestone_id = str(i + 1) + milestone = status["milestones"][milestone_id] + + if milestone["is_unlocked"]: + marker = f"[green]{milestone['emoji']}[/green]" + elif milestone["can_unlock"]: + marker = f"[yellow blink]{milestone['emoji']}[/yellow blink]" + else: + marker = f"[dim]{milestone['emoji']}[/dim]" + + timeline.append(marker) + + # Show timeline + console.print(f"\n{' '.join(timeline)}") + + # Progress bar + filled = "โ–ˆ" * unlocked_width + empty = "โ–‘" * (progress_width - unlocked_width) + console.print(f"\n[green]{filled}[/green][dim]{empty}[/dim]") + console.print(f"[dim]{status['overall_progress']:.0f}% complete[/dim]\n") + + def _show_tree_timeline(self, status: dict) -> None: + """Show tree-style milestone timeline.""" + console = self.console + + console.print(Panel( + f"[bold cyan]๐ŸŽฎ Milestone Progression Tree[/bold cyan]\n\n" + f"[bold]Your journey from student to ML Systems Engineer[/bold]", + title="Epic Timeline", + border_style="bright_blue" + )) + + # Create tree structure + tree = Tree("๐Ÿš€ [bold]TinyTorch Mastery Journey[/bold]") + + for milestone_id in ["1", "2", "3", "4", "5"]: + milestone = status["milestones"][milestone_id] + + if milestone["is_unlocked"]: + node_style = "green" + icon = "โœ…" + elif milestone["can_unlock"]: + node_style = "yellow" + icon = "โšก" + else: + node_style = "dim" + icon = "๐Ÿ”’" + + branch = tree.add( + f"[{node_style}]{icon} {milestone['emoji']} {milestone['title']}[/{node_style}]" + ) + + # Add capability description + branch.add(f"[dim]{milestone['capability']}[/dim]") + + # Add trigger module info + if milestone["trigger_complete"]: + branch.add(f"[green]โœ… {milestone['trigger_module']} completed[/green]") + else: + branch.add(f"[dim]๐ŸŽฏ Complete: {milestone['trigger_module']}[/dim]") + + console.print(tree) + console.print() + + def _handle_test_command(self, args: Namespace) -> int: + """Handle milestone test command.""" + console = self.console + milestone_system = MilestoneSystem(self.config) + + # Determine which milestone to test + if args.milestone_id: + milestone_id = args.milestone_id + else: + # Test next available milestone + status = milestone_system.get_milestone_status() + if status["next_milestone"]: + milestone_id = status["next_milestone"] + else: + console.print(Panel( + "[yellow]No milestone available to test.[/yellow]\n\n" + "Either all milestones are unlocked or none are ready.\n" + "Use [dim]tito milestone status[/dim] to see your progress.", + title="No Test Available", + border_style="yellow" + )) + return 0 + + # Validate milestone ID + if milestone_id not in milestone_system.MILESTONES: + console.print(Panel( + f"[red]Invalid milestone ID: {milestone_id}[/red]\n\n" + f"Valid milestone IDs: 1, 2, 3, 4, 5", + title="Invalid Milestone", + border_style="red" + )) + return 1 + + milestone = milestone_system.MILESTONES[milestone_id] + + console.print(Panel( + f"[bold cyan]๐Ÿงช Testing Milestone {milestone_id}[/bold cyan]\n\n" + f"[bold]{milestone['emoji']} {milestone['title']}[/bold]\n" + f"[dim]{milestone['victory_condition']}[/dim]", + title="Milestone Test", + border_style="bright_cyan" + )) + + # Run the test with progress animation + with console.status(f"[bold green]Testing milestone requirements...", spinner="dots"): + result = milestone_system.run_milestone_test(milestone_id) + + # Show results + if result["success"]: + console.print(Panel( + f"[bold green]โœ… Milestone Test Passed![/bold green]\n\n" + f"[green]All requirements met for {result['milestone_name']}[/green]\n" + f"[cyan]Capability: {result['capability']}[/cyan]\n\n" + f"[bold yellow]Complete the trigger module to unlock:[/bold yellow]\n" + f"[dim]tito module complete {milestone['trigger_module']}[/dim]", + title="๐ŸŽ‰ Ready to Unlock!", + border_style="green" + )) + else: + console.print(Panel( + f"[bold yellow]โš ๏ธ Milestone Requirements Not Met[/bold yellow]\n\n" + f"[yellow]Milestone: {result.get('milestone_name', 'Unknown')}[/yellow]\n" + f"[red]Issue: {result.get('error', 'Unknown error')}[/red]\n\n" + f"[cyan]Complete the required modules and try again.[/cyan]", + title="Requirements Missing", + border_style="yellow" + )) + + return 0 + + def _handle_demo_command(self, args: Namespace) -> int: + """Handle milestone demo command.""" + console = self.console + milestone_system = MilestoneSystem(self.config) + milestone_id = args.milestone_id + + # Validate milestone ID + if milestone_id not in milestone_system.MILESTONES: + console.print(Panel( + f"[red]Invalid milestone ID: {milestone_id}[/red]\n\n" + f"Valid milestone IDs: 1, 2, 3, 4, 5", + title="Invalid Milestone", + border_style="red" + )) + return 1 + + milestone = milestone_system.MILESTONES[milestone_id] + status = milestone_system.get_milestone_status() + milestone_status = status["milestones"][milestone_id] + + # Check if milestone is unlocked + if not milestone_status["is_unlocked"]: + console.print(Panel( + f"[yellow]Milestone {milestone_id} not yet unlocked.[/yellow]\n\n" + f"[bold]{milestone['emoji']} {milestone['title']}[/bold]\n" + f"[dim]{milestone['victory_condition']}[/dim]\n\n" + f"[cyan]Complete the requirements first:[/cyan]\n" + f"[dim]tito milestone test {milestone_id}[/dim]", + title="Milestone Locked", + border_style="yellow" + )) + return 0 + + # Check if demo file exists + demo_path = Path("capabilities") / milestone["demo_file"] + if not demo_path.exists(): + console.print(Panel( + f"[yellow]Demo not available for Milestone {milestone_id}[/yellow]\n\n" + f"Demo file not found: {milestone['demo_file']}\n" + f"[dim]This demo may be coming in a future update.[/dim]", + title="Demo Unavailable", + border_style="yellow" + )) + return 0 + + # Run the demo + console.print(Panel( + f"[bold cyan]๐ŸŽฌ Launching Milestone {milestone_id} Demo[/bold cyan]\n\n" + f"[bold]{milestone['emoji']} {milestone['title']}[/bold]\n" + f"[yellow]Watch your capability in action![/yellow]\n\n" + f"[cyan]Demonstrating: {milestone['capability']}[/cyan]\n" + f"[dim]Running: {milestone['demo_file']}[/dim]", + title="Capability Demo", + border_style="bright_cyan" + )) + + try: + result = subprocess.run( + [sys.executable, str(demo_path)], + capture_output=False, + text=True + ) + + if result.returncode == 0: + console.print(Panel( + f"[bold green]โœ… Demo completed successfully![/bold green]\n\n" + f"[yellow]You've seen your {milestone['title']} capability in action![/yellow]\n" + f"[cyan]Real-world impact: {milestone['real_world_impact']}[/cyan]", + title="๐ŸŽ‰ Demo Complete", + border_style="green" + )) + else: + console.print(f"[yellow]โš ๏ธ Demo completed with status: {result.returncode}[/yellow]") + + except Exception as e: + console.print(Panel( + f"[red]โŒ Error running demo: {e}[/red]\n\n" + f"[dim]You can manually run: python capabilities/{milestone['demo_file']}[/dim]", + title="Demo Error", + border_style="red" + )) + return 1 + + return 0 \ No newline at end of file diff --git a/tito/commands/module.py b/tito/commands/module.py index b82842f3..227112ff 100644 --- a/tito/commands/module.py +++ b/tito/commands/module.py @@ -27,6 +27,7 @@ from .clean import CleanCommand from .export import ExportCommand from .view import ViewCommand from .checkpoint import CheckpointSystem +from .milestone import MilestoneSystem from ..core.console import print_ascii_logo from pathlib import Path @@ -250,7 +251,12 @@ class ModuleCommand(BaseCommand): if not args.skip_test: console.print(f"\n[bold]Step 3: Testing capabilities...[/bold]") checkpoint_result = self._run_checkpoint_for_module(normalized_name) - self._show_completion_results(checkpoint_result, normalized_name, integration_result) + + # Step 4: Check for milestone unlock (NEW!) + console.print(f"\n[bold]Step 4: Checking for milestone unlocks...[/bold]") + milestone_result = self._check_milestone_unlock(normalized_name) + + self._show_completion_results(checkpoint_result, normalized_name, integration_result, milestone_result) else: console.print(f"\n[bold yellow]Step 3: Checkpoint test skipped[/bold yellow]") console.print(f"[dim]Module integrated successfully. Run checkpoint test manually if needed.[/dim]") @@ -374,7 +380,12 @@ class ModuleCommand(BaseCommand): "module_name": module_name } - def _show_completion_results(self, result: dict, module_name: str, integration_result: dict = None) -> None: + def _check_milestone_unlock(self, module_name: str) -> dict: + """Check if completing this module unlocks a milestone.""" + milestone_system = MilestoneSystem(self.config) + return milestone_system.check_milestone_unlock(module_name) + + def _show_completion_results(self, result: dict, module_name: str, integration_result: dict = None, milestone_result: dict = None) -> None: """Show results of module completion workflow.""" console = self.console @@ -389,8 +400,12 @@ class ModuleCommand(BaseCommand): # Record successful completion first self._record_module_completion(module_name) - # Show celebration first - self._show_capability_unlock_celebration(module_name, result) + # Check for EPIC MILESTONE UNLOCK first! + if milestone_result and milestone_result.get("milestone_unlocked"): + self._show_epic_milestone_celebration(milestone_result) + else: + # Show regular capability celebration + self._show_capability_unlock_celebration(module_name, result) # Check for capability showcase self._check_and_run_capability_showcase(module_name) @@ -399,21 +414,36 @@ class ModuleCommand(BaseCommand): checkpoint_name = result.get("checkpoint_name", "Unknown") capability = result.get("capability", "") - # Show both integration and capability success - console.print(Panel( - f"[bold green]๐ŸŽ‰ Module Complete![/bold green]\n\n" - f"[green]โœ… Package Integration: Module exported and integrated[/green]\n" - f"[green]โœ… Capability Test: {checkpoint_name} checkpoint achieved![/green]\n" - f"[green]๐Ÿš€ Capability unlocked: {capability}[/green]\n\n" - f"[bold cyan]๐Ÿ”„ Two-Tier Validation Success[/bold cyan]\n" - f"Module {module_name} passed both integration and capability tests!\n" - f"Your module is fully functional in the TinyTorch ecosystem.", - title=f"๐Ÿ† {module_name} Achievement", - border_style="green" - )) + # Show completion status (enhanced for milestones) + if milestone_result and milestone_result.get("milestone_unlocked"): + milestone_data = milestone_result["milestone_data"] + console.print(Panel( + f"[bold green]๐ŸŽ‰ EPIC MILESTONE UNLOCKED![/bold green]\n\n" + f"[green]โœ… Package Integration: Module exported and integrated[/green]\n" + f"[green]โœ… Capability Test: {checkpoint_name} checkpoint achieved![/green]\n" + f"[yellow]๐ŸŽฏ MILESTONE {milestone_result['milestone_id']}: {milestone_data['title']}![/yellow]\n\n" + f"[bold magenta]๐Ÿš€ New Capability: {milestone_data['capability']}[/bold magenta]\n" + f"[cyan]Real-world impact: {milestone_data['real_world_impact']}[/cyan]\n\n" + f"[bold cyan]๐Ÿ”“ You've unlocked a major ML engineering capability![/bold cyan]", + title=f"๐ŸŒŸ MILESTONE {milestone_result['milestone_id']} ACHIEVED", + border_style="bright_magenta" + )) + else: + # Standard completion message + console.print(Panel( + f"[bold green]๐ŸŽ‰ Module Complete![/bold green]\n\n" + f"[green]โœ… Package Integration: Module exported and integrated[/green]\n" + f"[green]โœ… Capability Test: {checkpoint_name} checkpoint achieved![/green]\n" + f"[green]๐Ÿš€ Capability unlocked: {capability}[/green]\n\n" + f"[bold cyan]๐Ÿ”„ Two-Tier Validation Success[/bold cyan]\n" + f"Module {module_name} passed both integration and capability tests!\n" + f"Your module is fully functional in the TinyTorch ecosystem.", + title=f"๐Ÿ† {module_name} Achievement", + border_style="green" + )) - # Show progress and next steps - self._enhanced_show_progress_and_next_steps(module_name) + # Show progress and next steps (enhanced for milestones) + self._enhanced_show_progress_and_next_steps(module_name, milestone_result) else: console.print(Panel( f"[bold yellow]โš ๏ธ Integration Complete, Capability Test Failed[/bold yellow]\n\n" @@ -684,6 +714,123 @@ class ModuleCommand(BaseCommand): # Brief pause for celebration time.sleep(1.5) + def _show_epic_milestone_celebration(self, milestone_result: dict) -> None: + """Show epic celebration for milestone unlock achievement.""" + console = self.console + milestone_data = milestone_result["milestone_data"] + milestone_id = milestone_result["milestone_id"] + + # Clear screen effect + console.print("\n" * 2) + + # Epic milestone unlock sequence + console.print(Align.center(Text("โšก EPIC MILESTONE UNLOCKED! โšก", style="bold blink bright_magenta"))) + console.print("\n") + + # Show the TinyTorch logo for special milestones + if milestone_id in ["3", "5"]: # Training and Language Generation + print_ascii_logo() + + # Create milestone-specific celebration art + celebration_art = self._get_milestone_celebration_art(milestone_id) + + # Epic celebration panel + console.print(Panel( + f"{celebration_art}\n\n" + f"[bold bright_yellow]๐ŸŽ‰ MILESTONE {milestone_id} ACHIEVED! ๐ŸŽ‰[/bold bright_yellow]\n\n" + f"[bold white]{milestone_data['emoji']} {milestone_data['title']} {milestone_data['emoji']}[/bold white]\n\n" + f"[bold cyan]โœจ NEW CAPABILITY UNLOCKED: โœจ[/bold cyan]\n" + f"[bold magenta]{milestone_data['capability']}[/bold magenta]\n\n" + f"[green]๐ŸŒŸ Real-World Impact:[/green]\n" + f"[yellow]{milestone_data['real_world_impact']}[/yellow]\n\n" + f"[bold cyan]๐Ÿš€ You're becoming an ML Systems Engineer! ๐Ÿš€[/bold cyan]", + title=f"๐Ÿ† MILESTONE {milestone_id}: {milestone_data['name'].upper()}", + border_style="bright_magenta", + box=box.ROUNDED + )) + + # Extended celebration pause + time.sleep(3) + + # Milestone-specific encouragement + encouragement = self._get_milestone_encouragement(milestone_id) + console.print(Panel( + encouragement, + title="๐ŸŒŸ Your Journey Continues", + border_style="bright_cyan" + )) + + time.sleep(2) + + def _get_milestone_celebration_art(self, milestone_id: str) -> str: + """Get ASCII art for milestone celebrations.""" + if milestone_id == "1": + return """ + ๐Ÿง  NEURAL NETWORKS UNLOCKED! ๐Ÿง  + โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— + โ•‘ โšก BASIC INFERENCE โšก โ•‘ + โ•‘ Your first AI breakthrough โ•‘ + โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + """ + elif milestone_id == "2": + return """ + ๐Ÿ‘๏ธ COMPUTER VISION UNLOCKED! ๐Ÿ‘๏ธ + โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— + โ•‘ ๐Ÿ–ผ๏ธ MACHINES CAN SEE ๐Ÿ–ผ๏ธ โ•‘ + โ•‘ Image recognition mastery โ•‘ + โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + """ + elif milestone_id == "3": + return """ + ๐ŸŽ“ FULL TRAINING PIPELINE UNLOCKED! ๐ŸŽ“ + โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— + โ•‘ ๐Ÿญ PRODUCTION TRAINING ๐Ÿญ โ•‘ + โ•‘ End-to-end ML system mastery โ•‘ + โ•‘ ๐Ÿš€ Industry-ready skills โ•‘ + โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + """ + elif milestone_id == "4": + return """ + โšก ADVANCED VISION SYSTEMS UNLOCKED! โšก + โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— + โ•‘ ๐Ÿ’Ž PRODUCTION VISION ๐Ÿ’Ž โ•‘ + โ•‘ High-performance optimization โ•‘ + โ•‘ ๐Ÿข Tech company level โ•‘ + โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + """ + elif milestone_id == "5": + return """ + ๐Ÿค– LANGUAGE GENERATION UNLOCKED! ๐Ÿค– + โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— + โ•‘ ๐Ÿ‘‘ BUILD THE FUTURE ๐Ÿ‘‘ โ•‘ + โ•‘ Transformer architecture mastery โ•‘ + โ•‘ ๐ŸŒŸ ChatGPT-level systems โ•‘ + โ•‘ ๐Ÿš€ AI PIONEER STATUS ๐Ÿš€ โ•‘ + โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + """ + else: + return """ + โœจ MILESTONE ACHIEVED โœจ + ๐Ÿ† CAPABILITY ๐Ÿ† + ๐ŸŒŸ UNLOCKED ๐ŸŒŸ + """ + + def _get_milestone_encouragement(self, milestone_id: str) -> str: + """Get milestone-specific encouragement message.""" + encouragements = { + "1": "[bold green]Amazing start![/bold green] You've built your first working neural networks.\n[cyan]You can now solve classification problems and understand gradient flow.\n[yellow]Next up: Teaching machines to see with computer vision![/yellow]", + + "2": "[bold green]Incredible breakthrough![/bold green] Machines can now see through your code.\n[cyan]You've mastered convolutional networks and image processing.\n[yellow]Next up: Building complete training pipelines![/yellow]", + + "3": "[bold green]Outstanding achievement![/bold green] You can now train production ML models.\n[cyan]You've built end-to-end systems that rivals industry standards.\n[yellow]Next up: Optimizing for real-world performance![/yellow]", + + "4": "[bold green]Exceptional mastery![/bold green] You build production-ready vision systems.\n[cyan]Your skills now match those of tech company engineers.\n[yellow]Next up: The ultimate challenge - language generation![/yellow]", + + "5": "[bold green]๐ŸŽ‰ LEGENDARY STATUS ACHIEVED! ๐ŸŽ‰[/bold green]\n[cyan]You can build the future of AI - transformer language models!\n[magenta]You are now a true ML Systems Engineer![/magenta]\n[yellow]Share your achievement and inspire others![/yellow]" + } + + return encouragements.get(milestone_id, "[green]Great job on achieving this milestone![/green]") + def _check_and_run_capability_showcase(self, module_name: str) -> None: """Check if showcase exists and prompt user to run it.""" showcase_file = CAPABILITY_SHOWCASES.get(module_name) @@ -1017,7 +1164,7 @@ class ModuleCommand(BaseCommand): except IOError: pass # Fail silently if we can't save - def _enhanced_show_progress_and_next_steps(self, completed_module: str) -> None: + def _enhanced_show_progress_and_next_steps(self, completed_module: str, milestone_result: dict = None) -> None: """Show enhanced progress visualization and suggest next steps.""" console = self.console diff --git a/tito/main.py b/tito/main.py index 1094a7f4..b429335e 100644 --- a/tito/main.py +++ b/tito/main.py @@ -39,6 +39,7 @@ from .commands.checkpoint import CheckpointCommand from .commands.grade import GradeCommand from .commands.demo import DemoCommand from .commands.logo import LogoCommand +from .commands.milestone import MilestoneCommand # Configure logging logging.basicConfig( @@ -66,6 +67,7 @@ class TinyTorchCLI: 'package': PackageCommand, 'nbgrader': NBGraderCommand, 'checkpoint': CheckpointCommand, + 'milestone': MilestoneCommand, # Convenience commands 'export': ExportCommand, 'test': TestCommand, @@ -88,6 +90,7 @@ Command Groups: package Package management and nbdev integration commands nbgrader Assignment management and auto-grading commands checkpoint Track ML systems engineering progress through checkpoints + milestone Epic capability achievements and ML systems mastery Convenience Commands: export Export modules to package (quick shortcut) @@ -199,7 +202,8 @@ Examples: " [bold green]module[/bold green] - Module development and management\n" " [bold green]package[/bold green] - Package management and nbdev integration\n" " [bold green]nbgrader[/bold green] - Assignment management and auto-grading\n" - " [bold green]checkpoint[/bold green] - Track ML systems engineering progress\n\n" + " [bold green]checkpoint[/bold green] - Track ML systems engineering progress\n" + " [bold magenta]milestone[/bold magenta] - Epic capability achievements and ML mastery\n\n" "[bold]Convenience Commands:[/bold]\n" " [bold green]export[/bold green] - Export modules to package\n" " [bold green]test[/bold green] - Run tests\n" @@ -210,6 +214,7 @@ Examples: " [dim]tito module status --metadata[/dim] - Module status with metadata\n" " [dim]tito module view 01_setup[/dim] - Start coding in Jupyter Lab\n" " [dim]tito checkpoint timeline[/dim] - Visual progress timeline\n" + " [dim]tito milestone status[/dim] - See your epic achievement progress\n" "[bold]Get Help:[/bold]\n" " [dim]tito system[/dim] - Show system subcommands\n" " [dim]tito module[/dim] - Show module subcommands\n"