Download src/ui.py from voidful/RefCheck: direct link, hf CLI and curl.
- Browser
- Download file 7.65 kB
-
https://huggingface.co/spaces/voidful/RefCheck/resolve/main/src/ui.py
- Command line
-
hf download hf://spaces/voidful/RefCheck/src/ui.py
-
curl -L -o ui.py https://huggingface.co/spaces/voidful/RefCheck/resolve/main/src/ui.py
7.65 kB
| from rich.console import Console | |
| from rich.table import Table | |
| from rich.panel import Panel | |
| from rich.tree import Tree | |
| import copy | |
| class BibUI: | |
| """Handles all terminal UI interactions for BibGuard.""" | |
| def __init__(self): | |
| self.console = Console() | |
| def show_analysis_report(self, ok_entries, to_fix, to_review, to_remove): | |
| """Display the initial analysis summary table.""" | |
| table = Table(title="π Analysis Report", show_header=True, header_style="bold magenta") | |
| table.add_column("Category", style="cyan") | |
| table.add_column("Count", justify="right") | |
| table.add_column("Description") | |
| table.add_row("β Correct", str(len(ok_entries)), "Entries match valid metadata") | |
| table.add_row("π οΈ To Fix", str(len(to_fix)), "[green]High confidence auto-fixes[/green]") | |
| table.add_row("π Review", str(len(to_review)), "[yellow]Ambiguous or low confidence[/yellow]") | |
| table.add_row("ποΈ Remove", str(len(to_remove)), "[red]No metadata found (Hallucinations)[/red]") | |
| self.console.print(table) | |
| if not (to_fix or to_review or to_remove): | |
| self.console.print(Panel("[green]β No issues found. All entries are valid.[/green]", title="Status")) | |
| def show_manual_review(self, entry, best_res, candidates, apply_fix_func): | |
| """Display manual review table for a single entry.""" | |
| self.console.print(f"\n[bold]Entry: {entry.key}[/bold]") | |
| self.console.print(f"Title: {entry.title}") | |
| self.console.print(f"Year: {entry.year}") | |
| self.console.print(f"Auth: {entry.author}") | |
| cand_table = Table(show_header=True, header_style="bold blue") | |
| cand_table.add_column("#", style="dim", width=4) | |
| cand_table.add_column("Source", style="cyan", width=12) | |
| cand_table.add_column("Conf", justify="right") | |
| cand_table.add_column("Candidate Metadata (Fetched)", style="white") | |
| cand_table.add_column("Proposed Changes", style="green") | |
| for i, cand in enumerate(candidates, 1): | |
| # We need to simulate the fix to show changes | |
| # We pass the apply_fix function to avoid circular dependency or logic duplication | |
| temp_entry = copy.deepcopy(entry) | |
| changes = apply_fix_func(temp_entry, cand.fetched_data) | |
| change_desc = "\n".join(changes) if changes else "[dim]No changes[/dim]" | |
| conf_style = "green" if cand.confidence > 0.7 else "yellow" if cand.confidence > 0.4 else "red" | |
| # Format the candidate's actual metadata | |
| fd = cand.fetched_data | |
| meta_lines = [] | |
| if getattr(fd, 'title', None): | |
| meta_lines.append(f"[bold]Title:[/bold] {fd.title[:60] + '...' if len(fd.title) > 60 else fd.title}") | |
| if getattr(fd, 'authors', None): | |
| a_str = " and ".join(fd.authors) | |
| meta_lines.append(f"[bold]Authors:[/bold] {a_str[:60] + '...' if len(a_str) > 60 else a_str}") | |
| if getattr(fd, 'year', None): | |
| meta_lines.append(f"[bold]Year:[/bold] {fd.year}") | |
| if getattr(fd, 'doi', None): | |
| meta_lines.append(f"[bold]DOI:[/bold] {fd.doi}") | |
| meta_desc = "\n".join(meta_lines) if meta_lines else "[dim]No metadata details[/dim]" | |
| cand_table.add_row( | |
| str(i), | |
| cand.source, | |
| f"[{conf_style}]{cand.confidence:.2f}[/{conf_style}]", | |
| meta_desc, | |
| change_desc | |
| ) | |
| self.console.print(cand_table) | |
| def show_final_report(self, total, verified, issues, not_found, reports, fixed_count, fixed_details, removed_details): | |
| """Display the verification status and modification tree.""" | |
| # Visual Final Status | |
| status_table = Table(box=None, padding=(0, 2)) | |
| status_table.add_column("Metric", style="bold") | |
| status_table.add_column("Value", justify="right") | |
| status_table.add_row("Total Entries", str(total)) | |
| status_table.add_row("Verified", f"[green]{verified}[/green]") | |
| status_table.add_row("Issues", f"[red]{issues}[/red]" if issues > 0 else "0") | |
| status_table.add_row("Not Found", f"[yellow]{not_found}[/yellow]" if not_found > 0 else "0") | |
| self.console.print(Panel(status_table, title="π Final Status", expand=False)) | |
| if issues > 0: | |
| self.console.print("\n[bold red]β Remaining Issues (Not Auto-Fixed):[/bold red]") | |
| for r in reports: | |
| if r.comparison and r.comparison.has_issues: | |
| self.console.print(f" - [bold]{r.entry.key}[/bold] (Conf: {r.comparison.confidence:.2f}): {', '.join(r.comparison.issues)}") | |
| # Report fixes and removals | |
| if fixed_count > 0 or removed_details: | |
| tree = Tree("βοΈ Modifications Report") | |
| if removed_details: | |
| rem_node = tree.add(f"[red]Removed {len(removed_details)} entries[/red]") | |
| for entry, reason in removed_details: | |
| rem_node.add(f"[bold]{entry.key}[/bold]: \"{entry.title}\" ([italic]{reason}[/italic])") | |
| if fixed_count > 0: | |
| fix_node = tree.add(f"[green]Fixed {fixed_count} entries[/green]") | |
| for key, changes in fixed_details.items(): | |
| entry_node = fix_node.add(f"[bold]{key}[/bold]") | |
| for change in changes: | |
| entry_node.add(change) | |
| self.console.print(tree) | |
| self.console.print("\n[green]β Changes applied and saved to file.[/green]") | |
| else: | |
| self.console.print("\n[green]β No changes were needed.[/green]") | |
| def show_sanitize_report(self, sanitize_fixes: dict): | |
| """Display sanitization results as a rich tree.""" | |
| if not sanitize_fixes: | |
| self.console.print("[green]β No formatting issues found.[/green]\n") | |
| return | |
| # Category display info | |
| category_info = { | |
| "dblp_id": ("π’", "DBLP Disambiguation ID Cleanup", "red"), | |
| "corporate_author": ("π’", "Corporate Author Protection", "yellow"), | |
| "entry_type": ("π", "Entry Type Correction", "cyan"), | |
| "title_case": ("π€", "Title Capitalization Protection", "blue"), | |
| "doi_mismatch": ("π", "DOI Mismatch", "red"), | |
| "future_year": ("π ", "Future Year Detection", "magenta"), | |
| "field_cleanup": ("π§Ή", "Junk Field Removal", "dim"), | |
| } | |
| total_fixes = sum(len(fixes) for fixes in sanitize_fixes.values()) | |
| tree = Tree(f"π§Ή Sanitization Report ({total_fixes} fixes in {len(sanitize_fixes)} entries)") | |
| # Group fixes by category across all entries | |
| by_category = {} | |
| for entry_key, fixes in sanitize_fixes.items(): | |
| for fix in fixes: | |
| if fix.category not in by_category: | |
| by_category[fix.category] = [] | |
| by_category[fix.category].append(fix) | |
| for cat, fixes in by_category.items(): | |
| icon, label, color = category_info.get(cat, ("β", cat, "white")) | |
| cat_node = tree.add(f"{icon} [{color}]{label} ({len(fixes)})[/{color}]") | |
| for fix in fixes: | |
| cat_node.add(f"[bold]{fix.entry_key}[/bold]: {fix.description}") | |
| self.console.print(tree) | |
| self.console.print("") | |