Spaces:
Sleeping
Sleeping
| """ | |
| Formatting tools for displaying analysis results with rich formatting. | |
| """ | |
| import os | |
| import tempfile | |
| import traceback | |
| from typing import Dict, Any, Tuple | |
| from loguru import logger | |
| from smolagents import Tool | |
| from rich.console import Console | |
| from rich.panel import Panel | |
| from rich.text import Text | |
| from rich.table import Table | |
| from rich.theme import Theme | |
| from rich.box import ROUNDED | |
| from rich.console import Group | |
| class FormatAnalysisResultsTool(Tool): | |
| """Tool for formatting analysis results""" | |
| name = "format_analysis_results" | |
| description = "Formats the analysis results for better readability" | |
| inputs = { | |
| "analysis_json": {"type": "any", "description": "JSON string or dictionary containing the analysis results"} | |
| } | |
| output_type = "string" | |
| def forward(self, analysis_json: Dict) -> str: | |
| """ | |
| Formats the analysis results for better readability. | |
| Args: | |
| analysis_json: Dictionary containing the analysis results | |
| Returns: | |
| A formatted string representation of the analysis | |
| """ | |
| analysis = analysis_json | |
| logger.debug(f"Analysis structure keys: {list(analysis.keys()) if isinstance(analysis, dict) else 'Not a dictionary'}") | |
| try: | |
| return self._format_rich(analysis) | |
| except Exception as e: | |
| error_traceback = traceback.format_exc() | |
| logger.error(f"Error in rich formatting: {str(e)}\nTraceback:\n{error_traceback}") | |
| self._log_analysis_debug_info(analysis) | |
| # Return error message instead of falling back to simple formatting | |
| return f"Error formatting analysis results: {str(e)}" | |
| def _log_analysis_debug_info(self, analysis: Dict) -> None: | |
| """Log debug information about the analysis dictionary""" | |
| if isinstance(analysis, dict): | |
| for key, value in analysis.items(): | |
| logger.debug(f"Key: {key}, Value type: {type(value)}, Value: {str(value)[:100]}{'...' if len(str(value)) > 100 else ''}") | |
| def _create_rich_console(self) -> Tuple[Console, Any]: | |
| """Create and configure a Rich console with a temporary file""" | |
| logger.debug("Starting rich formatting") | |
| temp_file = tempfile.NamedTemporaryFile(mode='w+', encoding='utf-8', delete=False) | |
| # Reduce console width for better display in Gradio UI | |
| console = Console(file=temp_file, width=70) | |
| # Create a custom theme for consistent styling | |
| custom_theme = Theme({ | |
| "heading": "bold cyan underline", | |
| "highlight": "bold yellow", | |
| "positive": "green", | |
| "negative": "red", | |
| "neutral": "magenta", | |
| "quote": "italic yellow", | |
| "metadata": "dim white", | |
| "conclusion": "bold magenta" | |
| }) | |
| # Apply the theme to our console | |
| console.theme = custom_theme | |
| return console, temp_file | |
| def _format_summary(self, console: Console, analysis: Dict) -> None: | |
| """Format and print the summary section""" | |
| summary = analysis.get("summary", "No summary available") | |
| logger.debug(f"Summary content: {summary if summary else 'Not available'}") | |
| console.print(Panel( | |
| Text(summary, justify="center"), | |
| title="[heading]Song Analysis[/]", | |
| subtitle="[metadata]Summary[/]", | |
| expand=True # Расширять панель на всю доступную ширину | |
| )) | |
| def _format_info_table(self, console: Console, analysis: Dict) -> None: | |
| """Format and print the info table with themes and mood""" | |
| info_table = Table(show_header=False, box=ROUNDED, expand=True) | |
| info_table.add_column("Key", style="bold blue") | |
| info_table.add_column("Value") | |
| # Add the mood | |
| mood = analysis.get("mood", "Not specified") | |
| logger.debug(f"Mood content: {mood if mood else 'Not specified'}") | |
| info_table.add_row("Mood", mood) | |
| # Add the themes as a comma-separated list | |
| themes = analysis.get("main_themes", []) | |
| logger.debug(f"Themes: {themes if themes else 'Not available'}") | |
| if themes: | |
| themes_text = ", ".join([f"[highlight]{theme}[/]" for theme in themes]) | |
| info_table.add_row("Main Themes", themes_text) | |
| console.print(info_table) | |
| def _format_section(self, console: Console, section: Dict) -> None: | |
| """Format and print a single section""" | |
| section_type = section.get("section_type", "Unknown") | |
| section_number = section.get("section_number", "") | |
| logger.debug(f"Processing section: {section_type} {section_number}") | |
| section_title = f"{section_type.title()} {section_number}" if section_number else section_type.title() | |
| section_analysis = section.get("analysis", "No analysis available") | |
| lines = section.get("lines", []) | |
| logger.debug(f"Section lines count: {len(lines) if lines else 0}") | |
| # Create a group with the lyrics and analysis | |
| section_content = [] | |
| if lines: | |
| # Format lyrics in a more readable way | |
| section_content.append(Text("Lyrics:", style="bold blue")) | |
| # Format each lyrics line with the quote style | |
| lyrics_lines = [] | |
| for line in lines: | |
| lyrics_lines.append(f"[quote]{line}[/]") | |
| lyrics_panel = Panel( | |
| "\n".join(lyrics_lines), | |
| border_style="blue", | |
| padding=(1, 2), | |
| expand=True # Расширять панель на всю доступную ширину | |
| ) | |
| section_content.append(lyrics_panel) | |
| section_content.append(Text("Analysis:", style="bold blue")) | |
| section_content.append(Text(section_analysis)) | |
| # Add the section panel | |
| console.print(Panel( | |
| Group(*section_content), | |
| title=f"[bold cyan]{section_title}[/]", | |
| border_style="cyan", | |
| expand=True # Расширять панель на всю доступную ширину | |
| )) | |
| def _format_sections(self, console: Console, analysis: Dict) -> None: | |
| """Format and print all sections""" | |
| sections = analysis.get("sections_analysis", []) | |
| logger.debug(f"Sections count: {len(sections) if sections else 0}") | |
| if sections: | |
| console.print("\n[heading]Section-by-Section Analysis[/]") | |
| for section in sections: | |
| self._format_section(console, section) | |
| def _format_conclusion(self, console: Console, analysis: Dict) -> None: | |
| """Format and print the conclusion""" | |
| conclusion = analysis.get("conclusion", "No conclusion available") | |
| logger.debug(f"Conclusion content: {conclusion if conclusion else 'Not available'}") | |
| console.print("\n[heading]Conclusion[/]") | |
| console.print(Panel( | |
| Text(conclusion, justify="left"), | |
| border_style="magenta", | |
| expand=True # Расширять панель на всю доступную ширину | |
| )) | |
| def _format_rich(self, analysis: Dict) -> str: | |
| """Format the analysis using rich formatting""" | |
| console, temp_file = self._create_rich_console() | |
| # Format each section | |
| self._format_summary(console, analysis) | |
| self._format_info_table(console, analysis) | |
| self._format_sections(console, analysis) | |
| self._format_conclusion(console, analysis) | |
| # Save output to file and read back as string | |
| temp_file.close() | |
| with open(temp_file.name, 'r', encoding='utf-8') as f: | |
| result = f.read() | |
| # Градио не поддерживает HTML-теги pre, поэтому просто возвращаем текст как есть | |
| # Текстовое форматирование Rich уже содержит необходимые отступы и пробелы | |
| # Clean up the temp file | |
| try: | |
| os.unlink(temp_file.name) | |
| except Exception as e: | |
| logger.warning(f"Could not delete temporary file {temp_file.name}: {str(e)}") | |
| return result | |