Spaces:
Sleeping
Sleeping
Guilherme Favaron
Major update: Add hybrid search, reranking, multiple LLMs, and UI improvements
1b447de
| """ | |
| Aba de Visualizações Avançadas | |
| Análise visual de embeddings e resultados | |
| """ | |
| import gradio as gr | |
| import numpy as np | |
| import plotly.graph_objects as go | |
| import plotly.express as px | |
| from sklearn.decomposition import PCA | |
| from sklearn.manifold import TSNE | |
| from typing import List, Dict, Any | |
| from src.database import DatabaseManager | |
| from src.embeddings import EmbeddingManager | |
| def create_visualizations_tab( | |
| db_manager: DatabaseManager, | |
| embedding_manager: EmbeddingManager, | |
| session_id: str | |
| ): | |
| """Cria aba de visualizações""" | |
| with gr.Tab("Visualizações"): | |
| gr.Markdown(""" | |
| ## Análise Visual de Embeddings | |
| Visualize seus documentos em 2D para entender a distribuição semântica. | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### Configuração") | |
| reduction_method = gr.Radio( | |
| choices=["PCA", "t-SNE", "UMAP"], | |
| value="PCA", | |
| label="Método de Redução de Dimensionalidade", | |
| info="PCA: rápido, linear. t-SNE: melhor clusters, mais lento" | |
| ) | |
| n_components = gr.Slider( | |
| minimum=2, | |
| maximum=3, | |
| value=2, | |
| step=1, | |
| label="Dimensões (2D ou 3D)", | |
| info="3D permite rotação interativa" | |
| ) | |
| color_by = gr.Radio( | |
| choices=["Documento", "Cluster"], | |
| value="Documento", | |
| label="Colorir Por" | |
| ) | |
| generate_btn = gr.Button( | |
| "Gerar Visualização", | |
| variant="primary", | |
| size="lg", | |
| elem_classes=["primary-button"] | |
| ) | |
| gr.Markdown(""" | |
| **Sobre os métodos:** | |
| - **PCA**: Preserva variância, rápido | |
| - **t-SNE**: Preserva vizinhanças locais | |
| - **UMAP**: Balanceado (requer instalação) | |
| """) | |
| with gr.Column(scale=2): | |
| gr.Markdown("### Plot Interativo") | |
| plot_output = gr.Plot(label="Embeddings Reduzidos") | |
| stats_output = gr.Markdown("") | |
| # Função de visualização | |
| def visualize_embeddings(method, n_dims, color_option): | |
| try: | |
| # 1. Busca documentos do banco | |
| docs = db_manager.get_all_documents(session_id) | |
| if not docs or len(docs) < 3: | |
| return None, "**Erro**: Ingira pelo menos 3 documentos para visualizar." | |
| # 2. Extrai embeddings (assumindo que estão armazenados) | |
| # Como embeddings estão no banco, vamos recalcular para demonstração | |
| texts = [doc['content'] for doc in docs] | |
| embeddings = embedding_manager.encode(texts, normalize=True) | |
| # 3. Reduz dimensionalidade | |
| if method == "PCA": | |
| reducer = PCA(n_components=int(n_dims)) | |
| reduced = reducer.fit_transform(embeddings) | |
| explained_var = reducer.explained_variance_ratio_ | |
| method_info = f"Variância explicada: {sum(explained_var):.2%}" | |
| elif method == "t-SNE": | |
| reducer = TSNE(n_components=int(n_dims), random_state=42, perplexity=min(30, len(docs)-1)) | |
| reduced = reducer.fit_transform(embeddings) | |
| method_info = f"KL divergence: {reducer.kl_divergence_:.4f}" | |
| elif method == "UMAP": | |
| try: | |
| import umap | |
| reducer = umap.UMAP(n_components=int(n_dims), random_state=42) | |
| reduced = reducer.fit_transform(embeddings) | |
| method_info = "UMAP aplicado com sucesso" | |
| except ImportError: | |
| return None, "**Erro**: UMAP não instalado. Use `pip install umap-learn`" | |
| # 4. Prepara dados para plot | |
| titles = [doc['title'] for doc in docs] | |
| previews = [doc['content'][:100] + "..." for doc in docs] | |
| # Colorir por documento ou cluster | |
| if color_option == "Documento": | |
| colors = titles | |
| else: | |
| # Clustering simples com K-means | |
| from sklearn.cluster import KMeans | |
| n_clusters = min(5, len(docs)) | |
| kmeans = KMeans(n_clusters=n_clusters, random_state=42, n_init=10) | |
| clusters = kmeans.fit_predict(embeddings) | |
| colors = [f"Cluster {c+1}" for c in clusters] | |
| # 5. Cria plot | |
| if int(n_dims) == 2: | |
| fig = px.scatter( | |
| x=reduced[:, 0], | |
| y=reduced[:, 1], | |
| color=colors, | |
| hover_name=titles, | |
| hover_data={"Preview": previews}, | |
| title=f"Visualização de Embeddings ({method})", | |
| labels={"x": "Componente 1", "y": "Componente 2"} | |
| ) | |
| fig.update_traces(marker=dict(size=12, line=dict(width=1, color='white'))) | |
| else: # 3D | |
| fig = px.scatter_3d( | |
| x=reduced[:, 0], | |
| y=reduced[:, 1], | |
| z=reduced[:, 2], | |
| color=colors, | |
| hover_name=titles, | |
| hover_data={"Preview": previews}, | |
| title=f"Visualização 3D de Embeddings ({method})", | |
| labels={"x": "Componente 1", "y": "Componente 2", "z": "Componente 3"} | |
| ) | |
| fig.update_traces(marker=dict(size=8, line=dict(width=0.5, color='white'))) | |
| fig.update_layout( | |
| template="plotly_white", | |
| hovermode='closest', | |
| height=600 | |
| ) | |
| # 6. Estatísticas | |
| stats = f""" | |
| ### Estatísticas | |
| **Documentos visualizados:** {len(docs)} | |
| **Método:** {method} | |
| - {method_info} | |
| **Dimensões:** | |
| - Original: {embeddings.shape[1]} | |
| - Reduzida: {reduced.shape[1]} | |
| **Interpretação:** | |
| - Pontos próximos = semanticamente similares | |
| - Pontos distantes = semanticamente diferentes | |
| - Clusters = grupos de documentos relacionados | |
| """ | |
| return fig, stats | |
| except Exception as e: | |
| return None, f"**Erro**: {str(e)}" | |
| # Conecta evento | |
| generate_btn.click( | |
| fn=visualize_embeddings, | |
| inputs=[reduction_method, n_components, color_by], | |
| outputs=[plot_output, stats_output] | |
| ) | |