AURA-chatbot / app.py
Flavio Casadei Della Chiesa
aggiunto gpot
f6254de
import streamlit as st
from ragpipeline import (RAGPipeline,Retriever,OllamaChatbot)
import tempfile
import pandas as pd
from textutils import ParagraphDocumentProcessor, SmallFragmentDocumentProcessor,WholeTextDocumentProcessor
from HFChatbot import HFBot
import os
def main():
if "faiss_builder" not in st.session_state:
ragpipeline = RAGPipeline(numero_frammenti=10)
st.session_state["faiss_builder"] = ragpipeline
else:
ragpipeline = st.session_state["faiss_builder"]
if "storico_domande" not in st.session_state:
st.session_state["storico_domande"] = []
if "indice_creato" not in st.session_state:
st.session_state["indice_creato"] = False
modelliVelvet = [
'Almawave/Velvet-2B',
'Almawave/Velvet-14B',
]
modelliLLM = [
'Almawave/Velvet-2B',
'Almawave/Velvet-14B',
'mistralai/Mistral-7B-Instruct-v0.1',
'Qwen/Qwen2.5-1.5B',
]
modelliOllama = [
'Almawave/Velvet:2B',
'Almawave/Velvet:14b',
'llama3.1:8b-instruct-q4_K_M',
'qwen3:14b',
'qwen3:30b-a3b',
'gpt-oss:20b'
]
## indica se sono sullo spaces di HF (deve essere inserita uan variabile I_AM_ON_HF)
sono_su_hf =os.environ.get('I_AM_ON_HF', False)
## se sono su Hugginh Face non uso ollama
if not sono_su_hf:
modelliLLM.append("----- USARE SOLO CON OLLAMA -----")
for mollama in modelliOllama:
modelliLLM.append(mollama)
UPLOAD_DIR="/tmp/"
if "indice_creato" not in st.session_state:
st.session_state["indice_creato"] = False
if "faiss_builder" not in st.session_state:
ragpipeline = RAGPipeline( )
codice_tabella = f"<table><tr><td>💡AURA:</td><td> AI-Utilizzata per la Regolarità Amministrativa</td></tr></table>"
st.markdown(codice_tabella, unsafe_allow_html=True)
st.title("Cosa è AURA?")
st.write("""
Questo strumento, attualmente in fase sperimentale, è stato sviluppato per eseguire controlli di
regolarità amministrativa ai sensi dell’art. 147-bis del D.Lgs. 267/2000,
con riferimento agli atti relativi al PNRR.
È in continua evoluzione. Per testarne il funzionamento, è sufficiente caricare un file PDF contenente
una determinazione dirigenziale.
<p>
AURA è un sistema RAG <em>Retrieval Augmented Generation</em> che dato un atto amministrativo ed eventuali allegati
ed una o più domande ricerca nei documenti
i frammenti rilevanti per la domanda; questi assieme ad alcune istruzioni (<em>In-context learning</em>)
vengono inviati ad un LLM <em>Large Language Model</em>
al fine di generare una risposta corretta e coerente con i frammenti rilevanti.
</p>
<p>
Questa versione di AURA utilizza Velvet di Almawave, rilasciato sotto
<a href="https://www.apache.org/licenses/LICENSE-2.0">Licenza Apache 2.0</a> come LLM.
</p>
""" , unsafe_allow_html=True)
st.warning("Attenzione questo tool è sperimentale. AURA può sbagliare")
if not sono_su_hf:
modello_scelto = st.selectbox("Seleziona un modello:", modelliLLM, index=0)
else:
modello_scelto = st.selectbox("Seleziona un modello:", modelliVelvet, index=0)
st.write(f"Hai selezionato: {modello_scelto}")
if not sono_su_hf:
st.title("Generazione testo")
generatoriLLM = {
'Hugging Face Transformers': "HF",
'Ollama in locale' :"OLLAMA"
}
selected_generator= st.selectbox("Scegli lo strumento per interagire con LLM", generatoriLLM.keys())
chiave_LLM=generatoriLLM[selected_generator]
st.write(f"Hai selezionato {selected_generator}")
else:
chiave_LLM="HF"
st.title("Suddivisione in paragrafi")
docprocessor_options = {
"Small Fragments (più veloce ma poco preciso)": SmallFragmentDocumentProcessor(),
"ParagraphDocumentProcessor (più lento e leggermente più preciso)": ParagraphDocumentProcessor(),
"WholeText (viene generato un solo grande frammento, può confondere gli LLM)": WholeTextDocumentProcessor(),
}
selected_docprocessor = st.selectbox("Divisione in paragrafi", docprocessor_options.keys())
ragpipeline.docprocessor = docprocessor_options[selected_docprocessor]
st.write(f"Hai selezionato: **{selected_docprocessor}**")
if not st.session_state["indice_creato"]:
st.subheader("Carica eventuali Allegati PDF multipli")
other_pdfs = st.file_uploader("Carica allegati (puoi caricare più PDF)",
type=["pdf"],
accept_multiple_files=True,
key="allegati_pdf")
if st.button("Crea indice FAISS"):
if other_pdfs:
nfile=1
for uploaded_file in other_pdfs:
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf", dir=UPLOAD_DIR) as tmp_file:
tmp_file.write(uploaded_file.read())
tmp_path = tmp_file.name
ragpipeline.aggiungi_file_pdf(tmp_path)
st.write(f"Caricato file N {nfile}")
nfile = nfile+1
st.success("Allegati caricati con successo!")
else:
st.error("Nessun allegato caricato.")
ragpipeline.crea_indice()
st.success("Indice FAISS generato e caricato.")
st.session_state["indice_creato"] = True
frammenti_recuperati =ragpipeline.attributi_frammenti
for frammento_recuperato in frammenti_recuperati:
RAGPipeline.dump_excel(dizionario=frammento_recuperato, filename="frammentiChatbot.xlsx")
if st.session_state["indice_creato"]:
with st.form(key="domanda_form"):
domanda = st.text_area("Inserisci la domanda", key="domanda_input")
istruzione = st.text_area("Inserisci le istruzioni", key="istruzione_input")
submit_button = st.form_submit_button("Analizza atto")
if submit_button:
if domanda.strip().upper() == "FINE":
st.stop()
if chiave_LLM == "HF":
LLM=HFBot(model_name=modello_scelto)
elif chiave_LLM == "OLLAMA":
LLM=OllamaChatbot(model_name="flaollama",model_orig=modello_scelto)
else:
LLM=HFBot(model_name=modello_scelto)
ret = Retriever(
indice=ragpipeline.indice,
sentence_transformer_model=ragpipeline.sentence_transformer_model,
query=domanda + istruzione,
documenti=ragpipeline.documenti,
frammenti_indicizzati=ragpipeline.frammenti_indicizzati,
attributi_frammenti=ragpipeline.attributi_frammenti
)
ret.esegui_query(top_k=3)
risposta = LLM.generate(
query=domanda,
relevant_docs=ret.passaggi_rilevanti,
attributi_frammenti_rilevanti=ret.attributi_rilevanti,
istruzioni=istruzione
)
st.session_state.storico_domande.append((modello_scelto, domanda, istruzione, risposta))
st.markdown(
f"<p><strong>Domanda:</strong> {domanda} <br/>"
f"<strong>Istruzioni:</strong> <em>{istruzione}</em><br/><br/>"
f"<strong>Risposta:</strong><em> {risposta}</em></p>",
unsafe_allow_html=True
)
id_frammenti_recuperati = ":".join(sorted(set(elemento['id'] for elemento in ret.attributi_rilevanti)))
dump = {
'timestamp': ragpipeline.timestamp,
"modello": modello_scelto,
"documenti": st.session_state.get("main_pdf_nome", "non disponibile"),
"file_recuperati": "",
"file_gold": "",
"frammenti_recuperati":id_frammenti_recuperati,
"frammenti_gold": "",
"domanda":domanda,
"istruzioni":istruzione,
"risposta_gold": " ",
"risposta":LLM.pulisci_risposta(risposta)}
RAGPipeline.dump_excel(dizionario=dump,filename="dumpChatbot.xlsx")
if st.session_state.storico_domande:
st.markdown("---")
st.subheader("Storico delle domande analizzate")
for idx, (mymod, q, inst, resp) in enumerate(st.session_state.storico_domande, 1):
st.markdown(
f"""
**{idx}. Domanda:** {q}<br/>
<em>Modello: </em>{mymod}<br/>
<em>Istruzioni:</em> {inst}<br/><br/>
<strong>Risposta:</strong> {resp}<br/>
""",
unsafe_allow_html=True
)
if __name__ == "__main__":
main()