|
|
""" |
|
|
Module: agents.visualization_agent |
|
|
Codinome: Niemeyer - Visualização Gráfica |
|
|
Description: Agent specialized in creating interactive visualizations and graphical reports |
|
|
Author: Anderson H. Silva |
|
|
Date: 2025-07-23 |
|
|
License: Proprietary - All rights reserved |
|
|
""" |
|
|
|
|
|
import asyncio |
|
|
from src.core import json_utils |
|
|
from datetime import datetime, timedelta |
|
|
from typing import Any, Dict, List, Optional, Tuple, Union |
|
|
from dataclasses import dataclass |
|
|
from enum import Enum |
|
|
|
|
|
import numpy as np |
|
|
import pandas as pd |
|
|
from pydantic import BaseModel, Field as PydanticField |
|
|
|
|
|
from src.agents.deodoro import BaseAgent, AgentContext, AgentMessage, AgentResponse |
|
|
from src.core import get_logger |
|
|
from src.core.exceptions import AgentExecutionError, DataAnalysisError |
|
|
|
|
|
|
|
|
class VisualizationType(Enum): |
|
|
"""Types of visualizations available.""" |
|
|
BAR_CHART = "bar_chart" |
|
|
LINE_CHART = "line_chart" |
|
|
PIE_CHART = "pie_chart" |
|
|
SCATTER_PLOT = "scatter_plot" |
|
|
HEATMAP = "heatmap" |
|
|
NETWORK_GRAPH = "network_graph" |
|
|
GEOGRAPHIC_MAP = "geographic_map" |
|
|
TREEMAP = "treemap" |
|
|
SANKEY_DIAGRAM = "sankey_diagram" |
|
|
DASHBOARD = "dashboard" |
|
|
|
|
|
|
|
|
@dataclass |
|
|
class VisualizationSpec: |
|
|
"""Specification for visualization creation.""" |
|
|
|
|
|
viz_type: VisualizationType |
|
|
title: str |
|
|
data_source: str |
|
|
dimensions: List[str] |
|
|
metrics: List[str] |
|
|
filters: Dict[str, Any] |
|
|
styling: Dict[str, Any] |
|
|
interactivity: List[str] |
|
|
export_formats: List[str] |
|
|
|
|
|
|
|
|
@dataclass |
|
|
class VisualizationResult: |
|
|
"""Result of visualization generation.""" |
|
|
|
|
|
viz_id: str |
|
|
viz_type: VisualizationType |
|
|
title: str |
|
|
html_content: str |
|
|
json_config: Dict[str, Any] |
|
|
static_image_path: Optional[str] |
|
|
interactive_url: Optional[str] |
|
|
metadata: Dict[str, Any] |
|
|
timestamp: datetime |
|
|
|
|
|
|
|
|
class VisualizationAgent(BaseAgent): |
|
|
""" |
|
|
Niemeyer - Visualização Gráfica |
|
|
|
|
|
MISSÃO: |
|
|
Cria visualizações interativas e relatórios gráficos para análise de dados |
|
|
governamentais, transformando informações complexas em insights visuais. |
|
|
|
|
|
ALGORITMOS E TÉCNICAS IMPLEMENTADAS: |
|
|
|
|
|
1. ALGORITMOS DE LAYOUT DE GRAFOS: |
|
|
- Force-Directed Graph Layout (Algoritmo de Fruchterman-Reingold) |
|
|
- Hierarchical Layout (Algoritmo de Sugiyama) |
|
|
- Circular Layout para redes sociais |
|
|
- Algoritmo de Spring-Embedder para posicionamento de nós |
|
|
|
|
|
2. VISUALIZAÇÃO DE SÉRIES TEMPORAIS: |
|
|
- Smoothing Algorithms (Moving Average, LOWESS) |
|
|
- Trend Detection usando Regressão Linear |
|
|
- Seasonal Decomposition (STL - Seasonal-Trend decomposition) |
|
|
- Algoritmo de detecção de Change Points |
|
|
|
|
|
3. MAPAS DE CALOR E GEOGRÁFICOS: |
|
|
- Algoritmo de Interpolação Espacial (Kriging, IDW) |
|
|
- Clustering Geográfico (DBSCAN espacial) |
|
|
- Algoritmo de Colorização baseado em densidade |
|
|
- Projeções cartográficas (Mercator, Albers) |
|
|
|
|
|
4. DASHBOARDS INTERATIVOS: |
|
|
- Algoritmo de Layout Responsivo |
|
|
- Cross-filtering entre visualizações |
|
|
- Lazy Loading para grandes datasets |
|
|
- Algoritmo de Aggregation Dinâmica |
|
|
|
|
|
5. PROCESSAMENTO DE DADOS VISUAIS: |
|
|
- Algoritmo de Binning Adaptativo |
|
|
- Data Sampling para performance (Reservoir Sampling) |
|
|
- Algoritmo de Detecção de Outliers Visuais |
|
|
- Feature Scaling para comparabilidade visual |
|
|
|
|
|
BIBLIOTECAS E FRAMEWORKS: |
|
|
|
|
|
- D3.js: Visualizações customizadas e interativas |
|
|
- Plotly: Gráficos científicos e dashboards |
|
|
- Leaflet: Mapas interativos geográficos |
|
|
- Chart.js: Gráficos responsivos leves |
|
|
- Bokeh: Visualizações Python para web |
|
|
- Deck.gl: Visualizações 3D de grande escala |
|
|
|
|
|
TÉCNICAS MATEMÁTICAS: |
|
|
|
|
|
- Algoritmo de Força de Repulsão: F = k²/d² (para layouts de grafo) |
|
|
- Interpolação Bilinear para mapas de calor |
|
|
- Transformação de coordenadas geográficas |
|
|
- Algoritmos de clustering para agrupamento visual |
|
|
- PCA para redução dimensional em scatter plots |
|
|
|
|
|
TIPOS DE VISUALIZAÇÃO SUPORTADOS: |
|
|
|
|
|
1. Gráficos Básicos: Barras, linhas, pizza, dispersão |
|
|
2. Gráficos Avançados: Heatmaps, treemaps, sankey |
|
|
3. Visualizações de Rede: Grafos, diagramas de relacionamento |
|
|
4. Mapas: Coropléticos, pontos, densidade |
|
|
5. Dashboards: Multi-panel, filtros cruzados |
|
|
|
|
|
PERFORMANCE E OTIMIZAÇÃO: |
|
|
|
|
|
- Renderização: <2s para datasets até 10K pontos |
|
|
- Interatividade: <100ms resposta para filtros |
|
|
- Memory Usage: <512MB para visualizações complexas |
|
|
- Suporte: Datasets até 1M de registros (com sampling) |
|
|
|
|
|
INTEGRAÇÃO E EXPORT: |
|
|
|
|
|
- Formatos: SVG, PNG, PDF, HTML, JSON |
|
|
- Embed: iFrame, widget, component |
|
|
- API: REST endpoints para visualizações |
|
|
- Cache: Redis para visualizações computadas |
|
|
""" |
|
|
|
|
|
def __init__(self, config: Optional[Dict[str, Any]] = None): |
|
|
super().__init__( |
|
|
name="VisualizationAgent", |
|
|
description="Niemeyer - Criador de visualizações interativas", |
|
|
config=config or {} |
|
|
) |
|
|
self.logger = get_logger(__name__) |
|
|
|
|
|
|
|
|
self.viz_config = { |
|
|
"max_data_points": 100000, |
|
|
"default_width": 800, |
|
|
"default_height": 600, |
|
|
"color_palette": ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd"], |
|
|
"font_family": "Inter, Arial, sans-serif", |
|
|
"animation_duration": 750 |
|
|
} |
|
|
|
|
|
|
|
|
self.viz_cache = {} |
|
|
|
|
|
|
|
|
self.viz_templates = {} |
|
|
|
|
|
async def initialize(self) -> None: |
|
|
"""Inicializa templates e configurações de visualização.""" |
|
|
self.logger.info("Initializing Niemeyer visualization engine...") |
|
|
|
|
|
|
|
|
await self._load_visualization_templates() |
|
|
|
|
|
|
|
|
await self._setup_rendering_engines() |
|
|
|
|
|
self.logger.info("Niemeyer ready for visualization creation") |
|
|
|
|
|
async def create_visualization( |
|
|
self, |
|
|
spec: VisualizationSpec, |
|
|
data: List[Dict[str, Any]], |
|
|
context: AgentContext |
|
|
) -> VisualizationResult: |
|
|
""" |
|
|
Cria uma visualização baseada na especificação fornecida. |
|
|
|
|
|
PIPELINE DE CRIAÇÃO: |
|
|
1. Validação da especificação e dados |
|
|
2. Pré-processamento e transformação dos dados |
|
|
3. Seleção do algoritmo de layout apropriado |
|
|
4. Geração da visualização usando bibliotecas especializadas |
|
|
5. Aplicação de styling e interatividade |
|
|
6. Otimização para performance |
|
|
7. Export nos formatos solicitados |
|
|
""" |
|
|
self.logger.info(f"Creating {spec.viz_type.value} visualization: {spec.title}") |
|
|
|
|
|
|
|
|
processed_data = await self._preprocess_data(data, spec) |
|
|
|
|
|
|
|
|
layout_config = await self._calculate_layout(processed_data, spec) |
|
|
|
|
|
|
|
|
viz_result = await self._render_visualization(processed_data, spec, layout_config) |
|
|
|
|
|
return viz_result |
|
|
|
|
|
async def create_dashboard( |
|
|
self, |
|
|
components: List[VisualizationSpec], |
|
|
layout_config: Dict[str, Any], |
|
|
context: AgentContext |
|
|
) -> VisualizationResult: |
|
|
"""Cria dashboard com múltiplas visualizações.""" |
|
|
self.logger.info(f"Creating dashboard with {len(components)} components") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return VisualizationResult( |
|
|
viz_id=f"dashboard_{datetime.utcnow().timestamp()}", |
|
|
viz_type=VisualizationType.DASHBOARD, |
|
|
title="Government Data Dashboard", |
|
|
html_content="<div>Dashboard placeholder</div>", |
|
|
json_config={}, |
|
|
static_image_path=None, |
|
|
interactive_url=None, |
|
|
metadata={"components": len(components)}, |
|
|
timestamp=datetime.utcnow() |
|
|
) |
|
|
|
|
|
async def create_geographic_map( |
|
|
self, |
|
|
geo_data: List[Dict[str, Any]], |
|
|
map_config: Dict[str, Any], |
|
|
context: AgentContext |
|
|
) -> VisualizationResult: |
|
|
"""Cria mapas geográficos interativos.""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pass |
|
|
|
|
|
async def create_network_graph( |
|
|
self, |
|
|
nodes: List[Dict], |
|
|
edges: List[Dict], |
|
|
layout_algorithm: str = "force_directed", |
|
|
context: AgentContext |
|
|
) -> VisualizationResult: |
|
|
"""Cria grafos de redes sociais e relacionamentos.""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pass |
|
|
|
|
|
async def generate_report_visualizations( |
|
|
self, |
|
|
report_data: Dict[str, Any], |
|
|
context: AgentContext |
|
|
) -> List[VisualizationResult]: |
|
|
"""Gera conjunto de visualizações para relatório.""" |
|
|
visualizations = [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return visualizations |
|
|
|
|
|
async def process_message(self, message: AgentMessage, context: AgentContext) -> AgentResponse: |
|
|
"""Processa mensagens e coordena criação de visualizações.""" |
|
|
try: |
|
|
action = message.content.get("action") |
|
|
|
|
|
if action == "create_visualization": |
|
|
spec_data = message.content.get("specification") |
|
|
data = message.content.get("data", []) |
|
|
|
|
|
|
|
|
spec = VisualizationSpec( |
|
|
viz_type=VisualizationType(spec_data.get("viz_type")), |
|
|
title=spec_data.get("title", "Visualization"), |
|
|
data_source=spec_data.get("data_source", "unknown"), |
|
|
dimensions=spec_data.get("dimensions", []), |
|
|
metrics=spec_data.get("metrics", []), |
|
|
filters=spec_data.get("filters", {}), |
|
|
styling=spec_data.get("styling", {}), |
|
|
interactivity=spec_data.get("interactivity", []), |
|
|
export_formats=spec_data.get("export_formats", ["html"]) |
|
|
) |
|
|
|
|
|
result = await self.create_visualization(spec, data, context) |
|
|
|
|
|
return AgentResponse( |
|
|
agent_name=self.name, |
|
|
content={ |
|
|
"visualization": { |
|
|
"id": result.viz_id, |
|
|
"type": result.viz_type.value, |
|
|
"title": result.title, |
|
|
"html_content": result.html_content, |
|
|
"interactive_url": result.interactive_url |
|
|
}, |
|
|
"status": "visualization_created" |
|
|
}, |
|
|
confidence=0.95, |
|
|
metadata=result.metadata |
|
|
) |
|
|
|
|
|
elif action == "create_dashboard": |
|
|
components = message.content.get("components", []) |
|
|
layout = message.content.get("layout", {}) |
|
|
|
|
|
result = await self.create_dashboard(components, layout, context) |
|
|
|
|
|
return AgentResponse( |
|
|
agent_name=self.name, |
|
|
content={"dashboard": result, "status": "dashboard_created"}, |
|
|
confidence=0.90 |
|
|
) |
|
|
|
|
|
return AgentResponse( |
|
|
agent_name=self.name, |
|
|
content={"error": "Unknown visualization action"}, |
|
|
confidence=0.0 |
|
|
) |
|
|
|
|
|
except Exception as e: |
|
|
self.logger.error(f"Error in visualization creation: {str(e)}") |
|
|
raise AgentExecutionError(f"Visualization creation failed: {str(e)}") |
|
|
|
|
|
async def _preprocess_data(self, data: List[Dict], spec: VisualizationSpec) -> pd.DataFrame: |
|
|
"""Pré-processa dados para visualização.""" |
|
|
df = pd.DataFrame(data) |
|
|
|
|
|
|
|
|
for column, filter_value in spec.filters.items(): |
|
|
if column in df.columns: |
|
|
df = df[df[column].isin(filter_value) if isinstance(filter_value, list) else df[column] == filter_value] |
|
|
|
|
|
|
|
|
if len(df) > self.viz_config["max_data_points"]: |
|
|
df = df.sample(n=self.viz_config["max_data_points"]) |
|
|
|
|
|
return df |
|
|
|
|
|
async def _calculate_layout(self, data: pd.DataFrame, spec: VisualizationSpec) -> Dict[str, Any]: |
|
|
"""Calcula layout específico para o tipo de visualização.""" |
|
|
layout_config = { |
|
|
"width": self.viz_config["default_width"], |
|
|
"height": self.viz_config["default_height"], |
|
|
"margins": {"top": 50, "right": 50, "bottom": 50, "left": 50} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return layout_config |
|
|
|
|
|
async def _render_visualization( |
|
|
self, |
|
|
data: pd.DataFrame, |
|
|
spec: VisualizationSpec, |
|
|
layout: Dict[str, Any] |
|
|
) -> VisualizationResult: |
|
|
"""Renderiza a visualização final.""" |
|
|
|
|
|
|
|
|
viz_id = f"{spec.viz_type.value}_{datetime.utcnow().timestamp()}" |
|
|
|
|
|
|
|
|
html_content = f""" |
|
|
<div id="{viz_id}" class="cidadao-visualization"> |
|
|
<h3>{spec.title}</h3> |
|
|
<p>Visualization of type: {spec.viz_type.value}</p> |
|
|
<p>Data points: {len(data)}</p> |
|
|
</div> |
|
|
""" |
|
|
|
|
|
return VisualizationResult( |
|
|
viz_id=viz_id, |
|
|
viz_type=spec.viz_type, |
|
|
title=spec.title, |
|
|
html_content=html_content, |
|
|
json_config={"spec": spec.__dict__, "layout": layout}, |
|
|
static_image_path=None, |
|
|
interactive_url=None, |
|
|
metadata={"data_points": len(data), "created_at": datetime.utcnow().isoformat()}, |
|
|
timestamp=datetime.utcnow() |
|
|
) |
|
|
|
|
|
async def _load_visualization_templates(self) -> None: |
|
|
"""Carrega templates de visualização pré-definidos.""" |
|
|
|
|
|
pass |
|
|
|
|
|
async def _setup_rendering_engines(self) -> None: |
|
|
"""Configura engines de renderização.""" |
|
|
|
|
|
pass |