| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- """
- Terminal User Interface (TUI) for progress display.
- """
- import shutil
- from typing import Optional
- class ProgressDisplay:
- """Beautiful, terminal-aware progress display."""
- def __init__(self):
- """Initialize progress display."""
- self.terminal_width = shutil.get_terminal_size((80, 20)).columns
- self.current_step = ""
- self.current_substep = ""
- def clear_line(self) -> None:
- """Clear the current line."""
- print('\r' + ' ' * self.terminal_width + '\r', end='', flush=True)
- def update_width(self) -> None:
- """Update terminal width (call if terminal is resized)."""
- self.terminal_width = shutil.get_terminal_size((80, 20)).columns
- def print_header(self, text: str) -> None:
- """Print a formatted header."""
- self.update_width()
- print()
- print("=" * self.terminal_width)
- centered = self._center_text(text)
- print(centered)
- print("=" * self.terminal_width)
- print()
- def print_section(self, text: str) -> None:
- """Print a formatted section."""
- self.update_width()
- print()
- print(f"▶ {text}")
- print()
- def print_info(self, text: str, indent: int = 0) -> None:
- """Print an info line."""
- prefix = " " * indent
- print(f"{prefix}ℹ {text}")
- def print_success(self, text: str, indent: int = 0) -> None:
- """Print a success message."""
- prefix = " " * indent
- print(f"{prefix}✓ {text}")
- def print_warning(self, text: str, indent: int = 0) -> None:
- """Print a warning message."""
- prefix = " " * indent
- print(f"{prefix}⚠ {text}")
- def print_error(self, text: str, indent: int = 0) -> None:
- """Print an error message."""
- prefix = " " * indent
- print(f"{prefix}✗ {text}")
- def print_progress_bar(self, current: int, total: int, label: str = "",
- bar_width: Optional[int] = None) -> None:
- """
- Print a progress bar that adapts to terminal width.
- Args:
- current: Current progress value
- total: Total value
- label: Optional label for the progress
- bar_width: Optional custom bar width (defaults to terminal width - 30)
- """
- self.update_width()
- if bar_width is None:
- bar_width = max(10, self.terminal_width - 40)
- if total == 0:
- percentage = 0
- filled = 0
- else:
- percentage = (current / total) * 100
- filled = int((current / total) * bar_width)
- bar = "█" * filled + "░" * (bar_width - filled)
- status = f"{current:>{len(str(total))}}/{total}"
- if label:
- output = f" {label:<20} │{bar}│ {status} ({percentage:5.1f}%)"
- else:
- output = f" │{bar}│ {status} ({percentage:5.1f}%)"
- # Truncate if too long
- if len(output) > self.terminal_width - 2:
- output = output[:self.terminal_width - 5] + "..."
- print(output)
- def print_stats(self, stats: dict) -> None:
- """
- Print formatted statistics.
- Args:
- stats: Dictionary of stat_name -> stat_value
- """
- self.update_width()
- print()
- for key, value in stats.items():
- # Format the key-value pair
- line = f" {key}: {value}"
- print(line)
- print()
- def _center_text(self, text: str) -> str:
- """Center text within terminal width."""
- available_width = self.terminal_width - 2 # Account for padding
- if len(text) >= available_width:
- return text[:available_width]
- left_pad = (available_width - len(text)) // 2
- right_pad = available_width - len(text) - left_pad
- return " " * left_pad + text + " " * right_pad
- def print_banner(self, text: str) -> None:
- """Print a decorative banner."""
- self.update_width()
- print()
- print("╔" + "═" * (self.terminal_width - 2) + "╗")
- print("║" + self._center_text(text) + "║")
- print("╚" + "═" * (self.terminal_width - 2) + "╝")
- print()
- def print_step(self, step_number: int, total_steps: int, description: str) -> None:
- """
- Print a numbered step.
- Args:
- step_number: Current step number
- total_steps: Total number of steps
- description: Description of the step
- """
- print(f"\n[{step_number}/{total_steps}] {description}")
- def print_file_info(self, filename: str, total_minutes: int, total_hours: float,
- chunk_count: int) -> None:
- """Print file information."""
- self.update_width()
- print()
- print(f" 📄 File: {filename}")
- print(f" ⏱ Duration: {total_minutes} minutes ({total_hours:.2f} hours)")
- print(f" 📦 Chunks: {chunk_count} (estimated based on 32k token limit)")
- print()
- def print_chunk_status(self, chunk_id: int, total_chunks: int,
- status: str, details: str = "") -> None:
- """
- Print status of a single chunk.
- Args:
- chunk_id: Chunk identifier (1-indexed)
- total_chunks: Total number of chunks
- status: Status emoji/icon
- details: Additional details
- """
- detail_str = f" - {details}" if details else ""
- print(f" Chunk {chunk_id:>3}/{total_chunks}: {status}{detail_str}")
|