rag_template / ui /exploration_tab.py
Guilherme Favaron
Initial commit of local project
f5eb34f
"""
Aba de Exploração da Base de Conhecimento
Permite visualizar documentos armazenados e testar busca semântica
"""
import time
import gradio as gr
from src.database import DatabaseManager
from src.embeddings import EmbeddingManager
def create_exploration_tab(db_manager: DatabaseManager, embedding_manager: EmbeddingManager, session_id: str):
"""Cria aba de exploração da base de conhecimento"""
with gr.Tab(" Exploração da Base"):
gr.Markdown("""
## Exploração da Base de Conhecimento
Visualize documentos armazenados e teste a busca semântica:
- **Documentos**: Veja todos os chunks armazenados
- **Busca Semântica**: Teste queries e veja resultados ranqueados
- **Scores de Similaridade**: Entenda a relevância dos resultados
""")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Estatísticas do Banco")
refresh_stats_btn = gr.Button(" Atualizar Estatísticas", size="sm")
db_stats_display = gr.JSON(label="Métricas da Base de Dados")
gr.Markdown("### Busca Semântica")
search_query = gr.Textbox(
label="Query de Busca",
placeholder="Digite sua pergunta ou termo de busca...",
lines=2
)
top_k_search = gr.Slider(
minimum=1,
maximum=20,
value=5,
step=1,
label="Top K (quantidade de resultados)"
)
search_btn = gr.Button(" Buscar", variant="primary")
with gr.Column(scale=2):
gr.Markdown("### Resultados da Busca")
search_status = gr.Markdown("Aguardando query de busca...")
with gr.Accordion(" Resultados Detalhados", open=True):
search_results = gr.Dataframe(
headers=["Rank", "Score", "Título", "Conteúdo (preview)"],
label="Documentos Recuperados",
wrap=True
)
with gr.Accordion(" Análise de Scores", open=False):
scores_analysis = gr.Markdown("Sem dados")
with gr.Accordion(" Conteúdo Completo", open=False):
full_content_display = gr.Textbox(
label="Conteúdo dos Resultados",
lines=15,
max_lines=30,
interactive=False
)
with gr.Row():
gr.Markdown("### 📚 Documentos Armazenados")
with gr.Row():
docs_limit = gr.Slider(
minimum=10,
maximum=200,
value=50,
step=10,
label="Limite de documentos a exibir"
)
refresh_docs_btn = gr.Button(" Carregar Documentos")
documents_display = gr.Dataframe(
headers=["ID", "Título", "Preview", "Data"],
label="Base de Conhecimento",
wrap=True
)
# Função para atualizar estatísticas
def refresh_stats():
stats = db_manager.get_database_stats()
if not stats:
return {"erro": "Não foi possível conectar ao banco"}
return stats
# Função para busca semântica
def semantic_search(query, k):
if not query or not query.strip():
return (
" Digite uma query para buscar",
[],
"Nenhuma análise disponível",
""
)
start_time = time.time()
# Gera embedding da query
query_embedding = embedding_manager.encode_single(query, normalize=True)
# Busca no banco (apenas na sessão do usuário)
results = db_manager.search_similar(query_embedding, k=int(k), session_id=session_id)
search_time = (time.time() - start_time) * 1000
if not results:
return (
f" Nenhum resultado encontrado (tempo: {search_time:.0f}ms)",
[],
"Sem resultados para análise",
""
)
# Prepara dados para tabela
table_data = []
full_contents = []
for i, result in enumerate(results, 1):
preview = result['content'][:100] + "..." if len(result['content']) > 100 else result['content']
table_data.append([
i,
f"{result['score']:.4f}",
result['title'],
preview
])
full_contents.append(f"--- Resultado {i} (Score: {result['score']:.4f}) ---")
full_contents.append(f"Título: {result['title']}")
full_contents.append(f"Conteúdo:\n{result['content']}\n")
# Análise de scores
scores = [r['score'] for r in results]
avg_score = sum(scores) / len(scores)
max_score = max(scores)
min_score = min(scores)
analysis_md = f"""
**Análise dos Scores de Similaridade**
- **Tempo de busca**: {search_time:.0f}ms
- **Resultados encontrados**: {len(results)}
- **Score máximo**: {max_score:.4f} (melhor match)
- **Score mínimo**: {min_score:.4f} (pior match)
- **Score médio**: {avg_score:.4f}
**Interpretação**:
- Scores próximos de 1.0 = alta similaridade
- Scores próximos de 0.5 = similaridade moderada
- Scores abaixo de 0.3 = baixa similaridade
"""
status_md = f" **Busca concluída** em {search_time:.0f}ms | {len(results)} resultados"
full_text = "\n".join(full_contents)
return status_md, table_data, analysis_md, full_text
# Função para carregar documentos
def load_documents(limit):
docs = db_manager.get_all_documents(limit=int(limit), session_id=session_id)
if not docs:
return []
table_data = []
for doc in docs:
preview = doc['content'][:80] + "..." if len(doc['content']) > 80 else doc['content']
created_str = str(doc['created_at']) if doc['created_at'] else "N/A"
table_data.append([
doc['id'],
doc['title'],
preview,
created_str
])
return table_data
# Conecta eventos
refresh_stats_btn.click(
fn=refresh_stats,
outputs=[db_stats_display]
)
search_btn.click(
fn=semantic_search,
inputs=[search_query, top_k_search],
outputs=[search_status, search_results, scores_analysis, full_content_display]
)
refresh_docs_btn.click(
fn=load_documents,
inputs=[docs_limit],
outputs=[documents_display]
)
return {
"search_query": search_query,
"search_btn": search_btn
}