|
|
"""
|
|
|
Componenti UI riutilizzabili per Streamlit.
|
|
|
"""
|
|
|
|
|
|
import streamlit as st
|
|
|
import pandas as pd
|
|
|
from typing import Dict
|
|
|
from config import Config
|
|
|
|
|
|
def setup_page_config():
|
|
|
"""Configura la pagina Streamlit"""
|
|
|
st.set_page_config(
|
|
|
page_title="Anonimizzatore Documenti",
|
|
|
page_icon="🔒",
|
|
|
layout="wide"
|
|
|
)
|
|
|
|
|
|
def display_sidebar():
|
|
|
"""Mostra sidebar con configurazioni"""
|
|
|
with st.sidebar:
|
|
|
st.header("⚙️ Configurazione")
|
|
|
|
|
|
|
|
|
if Config.AZURE_API_KEY and Config.AZURE_ENDPOINT:
|
|
|
st.success("✅ Azure OpenAI configurato")
|
|
|
st.info(f"Chat Model: {Config.DEPLOYMENT_NAME}")
|
|
|
st.info(f"Embedding Model: {Config.AZURE_EMBEDDING_DEPLOYMENT_NAME}")
|
|
|
else:
|
|
|
st.error("❌ Azure OpenAI non configurato")
|
|
|
st.write("Configura le variabili d'ambiente:")
|
|
|
st.code("""
|
|
|
AZURE_ENDPOINT=your_endpoint
|
|
|
AZURE_API_KEY=your_api_key
|
|
|
AZURE_ENDPOINT_EMB=your_embedding_endpoint
|
|
|
AZURE_API_KEY_EMB=your_embedding_api_key
|
|
|
""")
|
|
|
|
|
|
st.markdown("---")
|
|
|
|
|
|
|
|
|
if 'uploaded_files' in st.session_state and st.session_state.uploaded_files:
|
|
|
st.subheader("📊 Statistiche")
|
|
|
uploaded_count = len(st.session_state.uploaded_files)
|
|
|
anonymized_count = len(st.session_state.get('anonymized_docs', {}))
|
|
|
confirmed_count = sum(1 for doc in st.session_state.get('anonymized_docs', {}).values()
|
|
|
if doc.get('confirmed', False))
|
|
|
|
|
|
st.metric("File caricati", uploaded_count)
|
|
|
st.metric("Anonimizzati", anonymized_count)
|
|
|
st.metric("Confermati", confirmed_count)
|
|
|
|
|
|
if confirmed_count > 0:
|
|
|
if st.session_state.get('vector_store_built', False):
|
|
|
st.success("✅ Knowledge Base pronto")
|
|
|
else:
|
|
|
st.info("🔄 Knowledge Base da costruire")
|
|
|
|
|
|
st.markdown("---")
|
|
|
|
|
|
|
|
|
if st.button("🔄 Reset sessione"):
|
|
|
for key in list(st.session_state.keys()):
|
|
|
del st.session_state[key]
|
|
|
st.rerun()
|
|
|
|
|
|
def display_entity_editor(entities: Dict, doc_key: str):
|
|
|
"""Editor per entità rilevate"""
|
|
|
if not entities:
|
|
|
st.info("Nessuna entità sensibile rilevata.")
|
|
|
return entities
|
|
|
|
|
|
st.subheader("🔍 Entità rilevate")
|
|
|
st.write("Verifica e modifica le entità sensibili:")
|
|
|
|
|
|
current_entities_list = list(entities.items())
|
|
|
updated_entities_dict = {}
|
|
|
deleted_placeholders = set()
|
|
|
|
|
|
for i, (placeholder, original_value) in enumerate(current_entities_list):
|
|
|
col1, col2, col3 = st.columns([2, 3, 1])
|
|
|
|
|
|
with col1:
|
|
|
st.write(f"**{placeholder}**")
|
|
|
|
|
|
with col2:
|
|
|
new_value = st.text_input(
|
|
|
"Valore originale",
|
|
|
value=original_value,
|
|
|
key=f"{doc_key}_{placeholder}_value_{i}"
|
|
|
)
|
|
|
updated_entities_dict[placeholder] = new_value
|
|
|
|
|
|
with col3:
|
|
|
if st.button("🗑️", key=f"{doc_key}_{placeholder}_delete_{i}", help="Rimuovi"):
|
|
|
deleted_placeholders.add(placeholder)
|
|
|
|
|
|
|
|
|
if deleted_placeholders:
|
|
|
final_entities = {k: v for k, v in updated_entities_dict.items()
|
|
|
if k not in deleted_placeholders}
|
|
|
st.session_state.anonymized_docs[doc_key]['entities'] = final_entities
|
|
|
|
|
|
|
|
|
from anonymizer import NERAnonimizer
|
|
|
anonymizer = NERAnonimizer()
|
|
|
st.session_state.anonymized_docs[doc_key]['anonymized'], _ = anonymizer.anonymize(
|
|
|
st.session_state.anonymized_docs[doc_key]['original']
|
|
|
)
|
|
|
st.session_state.vector_store_built = False
|
|
|
st.rerun()
|
|
|
|
|
|
return updated_entities_dict
|
|
|
|
|
|
def display_file_preview(filename: str, content: str, max_chars: int = 500):
|
|
|
"""Mostra anteprima file"""
|
|
|
with st.expander(f"📄 {filename} ({len(content)} caratteri)"):
|
|
|
preview_text = content[:max_chars]
|
|
|
if len(content) > max_chars:
|
|
|
preview_text += "..."
|
|
|
|
|
|
st.text_area(
|
|
|
"Contenuto",
|
|
|
value=preview_text,
|
|
|
height=150,
|
|
|
disabled=True,
|
|
|
key=f"preview_{filename}",
|
|
|
label_visibility="collapsed"
|
|
|
)
|
|
|
|
|
|
def display_analysis_results(filename: str, result: Dict):
|
|
|
"""Mostra risultati analisi"""
|
|
|
with st.expander(f"📊 Analisi: {filename}"):
|
|
|
|
|
|
col1, col2, col3 = st.columns(3)
|
|
|
col1.metric("Caratteri testo", len(result['anonymized_text']))
|
|
|
col2.metric("Entità trovate", result['entities_count'])
|
|
|
col3.metric("Stato", "✅ Completato")
|
|
|
|
|
|
|
|
|
st.subheader("📄 Testo Anonimizzato")
|
|
|
st.text_area(
|
|
|
"Testo processato",
|
|
|
value=result['anonymized_text'],
|
|
|
height=150,
|
|
|
disabled=True,
|
|
|
key=f"analysis_text_{filename}"
|
|
|
)
|
|
|
|
|
|
|
|
|
st.subheader("🤖 Analisi AI")
|
|
|
st.markdown(result['analysis'])
|
|
|
|
|
|
|
|
|
if result['entities']:
|
|
|
st.subheader("🔍 Entità Anonimizzate")
|
|
|
entities_df = pd.DataFrame([
|
|
|
{
|
|
|
'Placeholder': k,
|
|
|
'Valore Originale': v,
|
|
|
'Tipo': k.split('_')[0].replace('[', '')
|
|
|
}
|
|
|
for k, v in result['entities'].items()
|
|
|
])
|
|
|
st.dataframe(entities_df, use_container_width=True)
|
|
|
|
|
|
def display_crewai_result(analysis: Dict, index: int):
|
|
|
"""Mostra risultato analisi CrewAI"""
|
|
|
with st.expander(
|
|
|
f"🤖 Analisi {index}: {analysis['analysis_type'].upper()} - {analysis['timestamp']}"
|
|
|
):
|
|
|
|
|
|
col1, col2, col3 = st.columns(3)
|
|
|
|
|
|
with col1:
|
|
|
st.metric("Tipo Analisi", analysis['analysis_type'].capitalize())
|
|
|
|
|
|
with col2:
|
|
|
st.metric("Timestamp", analysis['timestamp'])
|
|
|
|
|
|
with col3:
|
|
|
agents_used = analysis.get('agents_used', 'auto')
|
|
|
if agents_used == 'auto':
|
|
|
agent_count = "Automatico"
|
|
|
elif isinstance(agents_used, list):
|
|
|
agent_count = f"{len(agents_used)} agenti"
|
|
|
else:
|
|
|
agent_count = str(agents_used)
|
|
|
st.metric("Agenti", agent_count)
|
|
|
|
|
|
|
|
|
st.subheader("❓ Query Originale")
|
|
|
st.info(analysis['query'])
|
|
|
|
|
|
st.subheader("🎯 Risultato Analisi")
|
|
|
st.markdown(analysis['result'])
|
|
|
|
|
|
def display_progress_metrics():
|
|
|
"""Mostra metriche di progresso"""
|
|
|
if 'anonymized_docs' in st.session_state:
|
|
|
confirmed_count = sum(1 for doc in st.session_state.anonymized_docs.values()
|
|
|
if doc.get('confirmed', False))
|
|
|
total_count = len(st.session_state.anonymized_docs)
|
|
|
|
|
|
if total_count > 0:
|
|
|
st.metric(
|
|
|
"Progresso Conferme",
|
|
|
f"{confirmed_count}/{total_count}",
|
|
|
delta=f"{(confirmed_count/total_count)*100:.1f}%"
|
|
|
)
|
|
|
|
|
|
def display_examples_section():
|
|
|
"""Mostra esempi di query CrewAI"""
|
|
|
with st.expander("💡 Esempi di Query per CrewAI"):
|
|
|
st.markdown("""
|
|
|
**Analisi Comprensiva:**
|
|
|
- "Fornisci un'analisi completa dei documenti identificando rischi, opportunità e raccomandazioni strategiche"
|
|
|
- "Analizza la comunicazione aziendale e suggerisci miglioramenti nella gestione clienti"
|
|
|
|
|
|
**Analisi Documentale:**
|
|
|
- "Classifica i documenti per tipologia e identifica pattern ricorrenti"
|
|
|
- "Analizza la struttura e organizzazione delle informazioni nei documenti"
|
|
|
|
|
|
**Sentiment Analysis:**
|
|
|
- "Valuta il sentiment generale nelle comunicazioni e identifica aree di miglioramento"
|
|
|
- "Analizza le emozioni e i trend nei feedback dei clienti"
|
|
|
|
|
|
**Query RAG Avanzata:**
|
|
|
- "Trova tutte le menzioni di problemi operativi e le relative soluzioni proposte"
|
|
|
- "Estrai informazioni su scadenze, deadline e milestone importanti"
|
|
|
|
|
|
**Personalizzata:**
|
|
|
- Combina agenti specifici per analisi mirate alle tue esigenze
|
|
|
""")
|
|
|
|
|
|
def create_download_button(data: str, filename: str, label: str, key: str):
|
|
|
"""Crea bottone download con dati"""
|
|
|
st.download_button(
|
|
|
label=label,
|
|
|
data=data,
|
|
|
file_name=filename,
|
|
|
mime="application/json",
|
|
|
key=key
|
|
|
) |