Spaces:
Sleeping
Sleeping
Creazione function e database_hundling
Browse files- app.py +28 -17
- app/document_handling.py +22 -69
- app/{app.py → functions/__init__.py} +0 -0
- app/functions/database_handling.py +59 -0
- app/llm_handling_2.py +0 -34
- app/llm_handling_3.py +0 -76
- app/logging_config.py +48 -9
- logging_config.py +0 -40
- ui/chatbot_tab.py +1 -1
- ui/db_management_tab.py +22 -18
- ui/document_management_tab.py +44 -31
- ui/document_view_tab.py +2 -2
- ui/new_features_tab.py +2 -1
app.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1 |
-
#
|
2 |
|
3 |
import gradio as gr
|
|
|
4 |
from app.logging_config import configure_logging
|
5 |
-
from app.
|
6 |
from ui.chatbot_tab import create_chatbot_tab
|
7 |
from ui.db_management_tab import create_db_management_tab
|
8 |
from ui.document_management_tab import create_document_management_tab
|
@@ -14,27 +15,37 @@ configure_logging()
|
|
14 |
|
15 |
def update_all_dropdowns():
|
16 |
"""
|
17 |
-
Aggiorna tutti i dropdown
|
18 |
-
|
|
|
|
|
19 |
"""
|
20 |
databases = list_databases()
|
21 |
-
|
22 |
-
|
|
|
23 |
|
24 |
def main():
|
25 |
"""Funzione principale che crea e lancia l'app Gradio."""
|
26 |
-
|
27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
-
#
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
create_new_features_tab()
|
35 |
-
|
36 |
-
# Avvia l'app
|
37 |
-
rag_chatbot.launch()
|
38 |
|
39 |
if __name__ == "__main__":
|
40 |
main()
|
|
|
1 |
+
# app.py
|
2 |
|
3 |
import gradio as gr
|
4 |
+
import logging
|
5 |
from app.logging_config import configure_logging
|
6 |
+
from app.functions.database_handling import list_databases
|
7 |
from ui.chatbot_tab import create_chatbot_tab
|
8 |
from ui.db_management_tab import create_db_management_tab
|
9 |
from ui.document_management_tab import create_document_management_tab
|
|
|
15 |
|
16 |
def update_all_dropdowns():
|
17 |
"""
|
18 |
+
Aggiorna tutti i dropdown in tutte le tab.
|
19 |
+
Nel tuo scenario, hai 6 dropdown totali (2 nella tab DB, 2 nella tab Documenti,
|
20 |
+
eventualmente 1 nella tab Chatbot, 1 in altre tab, ecc.).
|
21 |
+
Se ne hai di più o di meno, modifica il numero nel range.
|
22 |
"""
|
23 |
databases = list_databases()
|
24 |
+
# Imposta la prima voce selezionata (value) solo se la lista non è vuota
|
25 |
+
# e aggiorna le "choices" di tutti i dropdown.
|
26 |
+
return [gr.update(choices=databases, value=databases[0] if databases else None) for _ in range(6)]
|
27 |
|
28 |
def main():
|
29 |
"""Funzione principale che crea e lancia l'app Gradio."""
|
30 |
+
logging.info("Avvio applicazione")
|
31 |
+
try:
|
32 |
+
with gr.Blocks() as rag_chatbot:
|
33 |
+
gr.Markdown("# Chatbot basato su RAG")
|
34 |
+
logging.info("Interfaccia Gradio inizializzata")
|
35 |
+
|
36 |
+
# Crea i vari tab dell'interfaccia
|
37 |
+
create_chatbot_tab()
|
38 |
+
create_db_management_tab(update_all_dropdowns) # Passiamo la callback
|
39 |
+
create_document_management_tab(update_all_dropdowns) # Passiamo la callback
|
40 |
+
create_document_view_tab()
|
41 |
+
create_new_features_tab()
|
42 |
+
logging.info("Tab dell'interfaccia creati con successo")
|
43 |
|
44 |
+
# Avvia l'app
|
45 |
+
logging.info("Avvio server Gradio")
|
46 |
+
rag_chatbot.launch()
|
47 |
+
except Exception as e:
|
48 |
+
logging.error(f"Errore durante l'avvio: {str(e)}", exc_info=True)
|
|
|
|
|
|
|
|
|
49 |
|
50 |
if __name__ == "__main__":
|
51 |
main()
|
app/document_handling.py
CHANGED
@@ -81,63 +81,6 @@ def answer_question(question, db_name="default_db"):
|
|
81 |
results = [doc.page_content for doc in docs]
|
82 |
return "\n\n".join(results)
|
83 |
|
84 |
-
# -------------- DATABASE MANAGEMENT TAB FUNCTIONS --------------
|
85 |
-
def create_database(db_name):
|
86 |
-
logging.info(f"Creating database: {db_name}")
|
87 |
-
db_path = f"faiss_index_{db_name}"
|
88 |
-
|
89 |
-
if os.path.exists(db_path):
|
90 |
-
return f"Il database {db_name} esiste già."
|
91 |
-
|
92 |
-
try:
|
93 |
-
os.makedirs(db_path)
|
94 |
-
logging.info(f"Database {db_name} created successfully.")
|
95 |
-
databases = list_databases()
|
96 |
-
return (f"Database {db_name} creato con successo.", databases)
|
97 |
-
except Exception as e:
|
98 |
-
logging.error(f"Errore nella creazione del database: {e}")
|
99 |
-
return (f"Errore nella creazione del database: {e}", [])
|
100 |
-
|
101 |
-
def delete_database(db_name):
|
102 |
-
db_path = f"faiss_index_{db_name}"
|
103 |
-
if not os.path.exists(db_path):
|
104 |
-
return f"Il database {db_name} non esiste."
|
105 |
-
try:
|
106 |
-
shutil.rmtree(db_path)
|
107 |
-
logging.info(f"Database {db_name} eliminato con successo.")
|
108 |
-
return f"Database {db_name} eliminato con successo."
|
109 |
-
except OSError as e:
|
110 |
-
logging.error(f"Impossibile eliminare il database {db_name}: {e}")
|
111 |
-
return f"Impossibile eliminare il database {db_name}: {e}"
|
112 |
-
|
113 |
-
def modify_database(old_db_name, new_db_name):
|
114 |
-
old_db_path = f"faiss_index_{old_db_name}"
|
115 |
-
new_db_path = f"faiss_index_{new_db_name}"
|
116 |
-
if not os.path.exists(old_db_path):
|
117 |
-
return f"Il database {old_db_name} non esiste."
|
118 |
-
if os.path.exists(new_db_path):
|
119 |
-
return f"Il database {new_db_name} esiste già."
|
120 |
-
try:
|
121 |
-
os.rename(old_db_path, new_db_path)
|
122 |
-
return f"Database {old_db_name} rinominato in {new_db_name} con successo."
|
123 |
-
except Exception as e:
|
124 |
-
return f"Errore durante la modifica del database: {e}"
|
125 |
-
|
126 |
-
def list_databases():
|
127 |
-
try:
|
128 |
-
databases = []
|
129 |
-
for item in os.listdir():
|
130 |
-
if os.path.isdir(item) and item.startswith("faiss_index_"):
|
131 |
-
db_name = item.replace("faiss_index_", "")
|
132 |
-
databases.append(db_name)
|
133 |
-
# Ensure "default_db" is in the list
|
134 |
-
if "default_db" not in databases:
|
135 |
-
databases.append("default_db")
|
136 |
-
return databases
|
137 |
-
except Exception as e:
|
138 |
-
logging.error(f"Error listing databases: {e}")
|
139 |
-
return []
|
140 |
-
|
141 |
# -------------- DOCUMENT MANAGEMENT TAB FUNCTIONS --------------
|
142 |
def upload_and_index(files, title, author, db_name="default_db"):
|
143 |
if not files:
|
@@ -153,6 +96,7 @@ def upload_and_index(files, title, author, db_name="default_db"):
|
|
153 |
elif file.name.endswith('.docx'):
|
154 |
text = extract_text_from_docx(file.name)
|
155 |
else:
|
|
|
156 |
with open(file.name, 'r', encoding='utf-8') as f:
|
157 |
text = f.read()
|
158 |
|
@@ -195,13 +139,14 @@ def upload_and_index(files, title, author, db_name="default_db"):
|
|
195 |
texts = [doc["content"] for doc in documents]
|
196 |
metadatas = [{k: v for k, v in doc.items() if k != "content"} for doc in documents]
|
197 |
|
|
|
198 |
vectorstore = FAISS.from_texts(texts, embeddings, metadatas=metadatas)
|
199 |
vectorstore.save_local(db_path)
|
200 |
|
201 |
-
# Salva i metadati del documento
|
202 |
save_metadata(doc_metadata, db_name)
|
203 |
|
204 |
-
return f"Documenti indicizzati con successo nel database {db_name}!"
|
205 |
except Exception as e:
|
206 |
logging.error(f"Errore durante l'indicizzazione: {e}")
|
207 |
return f"Errore durante l'indicizzazione: {e}"
|
@@ -219,6 +164,9 @@ def list_indexed_files(db_name="default_db"):
|
|
219 |
with open(metadata_file, 'r') as f:
|
220 |
metadata = json.load(f)
|
221 |
|
|
|
|
|
|
|
222 |
output = []
|
223 |
for doc in metadata:
|
224 |
output.append(
|
@@ -235,11 +183,16 @@ def list_indexed_files(db_name="default_db"):
|
|
235 |
return f"Errore nella lettura dei metadati: {e}"
|
236 |
|
237 |
def delete_file_from_database(file_name, db_name="default_db"):
|
|
|
|
|
|
|
|
|
|
|
238 |
db_path = f"faiss_index_{db_name}"
|
239 |
file_list_path = os.path.join(db_path, "file_list.txt")
|
240 |
|
241 |
if not os.path.exists(file_list_path):
|
242 |
-
return "Database non trovato."
|
243 |
|
244 |
try:
|
245 |
# Leggi la lista dei file
|
@@ -247,14 +200,14 @@ def delete_file_from_database(file_name, db_name="default_db"):
|
|
247 |
files = f.readlines()
|
248 |
|
249 |
# Rimuovi il file dalla lista
|
250 |
-
files = [
|
251 |
|
252 |
# Riscrivi la lista aggiornata
|
253 |
with open(file_list_path, "w") as f:
|
254 |
-
for
|
255 |
-
f.write(f"{
|
256 |
|
257 |
-
return f"File {file_name} rimosso dal database {db_name}."
|
258 |
except Exception as e:
|
259 |
return f"Errore durante la rimozione del file: {e}"
|
260 |
|
@@ -264,10 +217,10 @@ def list_indexed_documents(db_name="default_db"):
|
|
264 |
metadata_file = os.path.join(db_path, "metadata.json")
|
265 |
|
266 |
if not os.path.exists(db_path):
|
267 |
-
return f"Il database {db_name} non esiste."
|
268 |
|
269 |
if not os.path.exists(metadata_file):
|
270 |
-
return f"Nessun documento nel database {db_name}."
|
271 |
|
272 |
try:
|
273 |
with open(metadata_file, 'r') as f:
|
@@ -299,7 +252,7 @@ def list_indexed_documents(db_name="default_db"):
|
|
299 |
def search_documents(query, db_name="default_db"):
|
300 |
db_path = f"faiss_index_{db_name}"
|
301 |
if not os.path.exists(db_path):
|
302 |
-
logging.warning(f"L'indice FAISS per il database {db_name} non esiste.")
|
303 |
return "Database non trovato."
|
304 |
|
305 |
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
|
@@ -316,5 +269,5 @@ def search_documents(query, db_name="default_db"):
|
|
316 |
return "\n\n".join(results)
|
317 |
|
318 |
def generate_summary(db_name="default_db"):
|
319 |
-
# Placeholder
|
320 |
-
return "This is a summary of the documents in the database."
|
|
|
81 |
results = [doc.page_content for doc in docs]
|
82 |
return "\n\n".join(results)
|
83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
# -------------- DOCUMENT MANAGEMENT TAB FUNCTIONS --------------
|
85 |
def upload_and_index(files, title, author, db_name="default_db"):
|
86 |
if not files:
|
|
|
96 |
elif file.name.endswith('.docx'):
|
97 |
text = extract_text_from_docx(file.name)
|
98 |
else:
|
99 |
+
# File .txt o altro testo semplice
|
100 |
with open(file.name, 'r', encoding='utf-8') as f:
|
101 |
text = f.read()
|
102 |
|
|
|
139 |
texts = [doc["content"] for doc in documents]
|
140 |
metadatas = [{k: v for k, v in doc.items() if k != "content"} for doc in documents]
|
141 |
|
142 |
+
# Crea o sovrascrivi l'indice FAISS con questi documenti
|
143 |
vectorstore = FAISS.from_texts(texts, embeddings, metadatas=metadatas)
|
144 |
vectorstore.save_local(db_path)
|
145 |
|
146 |
+
# Salva i metadati del documento su file
|
147 |
save_metadata(doc_metadata, db_name)
|
148 |
|
149 |
+
return f"Documenti indicizzati con successo nel database '{db_name}'!"
|
150 |
except Exception as e:
|
151 |
logging.error(f"Errore durante l'indicizzazione: {e}")
|
152 |
return f"Errore durante l'indicizzazione: {e}"
|
|
|
164 |
with open(metadata_file, 'r') as f:
|
165 |
metadata = json.load(f)
|
166 |
|
167 |
+
if not metadata:
|
168 |
+
return "Nessun documento nel database."
|
169 |
+
|
170 |
output = []
|
171 |
for doc in metadata:
|
172 |
output.append(
|
|
|
183 |
return f"Errore nella lettura dei metadati: {e}"
|
184 |
|
185 |
def delete_file_from_database(file_name, db_name="default_db"):
|
186 |
+
"""
|
187 |
+
Esempio semplificato: potresti voler rimuovere i chunk
|
188 |
+
da FAISS. Attualmente, la funzione gestisce un 'file_list.txt',
|
189 |
+
ma devi adattarla alle tue esigenze di rimozione dei chunk.
|
190 |
+
"""
|
191 |
db_path = f"faiss_index_{db_name}"
|
192 |
file_list_path = os.path.join(db_path, "file_list.txt")
|
193 |
|
194 |
if not os.path.exists(file_list_path):
|
195 |
+
return "Database non trovato (file_list.txt mancante)."
|
196 |
|
197 |
try:
|
198 |
# Leggi la lista dei file
|
|
|
200 |
files = f.readlines()
|
201 |
|
202 |
# Rimuovi il file dalla lista
|
203 |
+
files = [line.strip() for line in files if line.strip() != file_name]
|
204 |
|
205 |
# Riscrivi la lista aggiornata
|
206 |
with open(file_list_path, "w") as f:
|
207 |
+
for fl in files:
|
208 |
+
f.write(f"{fl}\n")
|
209 |
|
210 |
+
return f"File '{file_name}' rimosso dal database '{db_name}'."
|
211 |
except Exception as e:
|
212 |
return f"Errore durante la rimozione del file: {e}"
|
213 |
|
|
|
217 |
metadata_file = os.path.join(db_path, "metadata.json")
|
218 |
|
219 |
if not os.path.exists(db_path):
|
220 |
+
return f"Il database '{db_name}' non esiste."
|
221 |
|
222 |
if not os.path.exists(metadata_file):
|
223 |
+
return f"Nessun documento nel database '{db_name}'."
|
224 |
|
225 |
try:
|
226 |
with open(metadata_file, 'r') as f:
|
|
|
252 |
def search_documents(query, db_name="default_db"):
|
253 |
db_path = f"faiss_index_{db_name}"
|
254 |
if not os.path.exists(db_path):
|
255 |
+
logging.warning(f"L'indice FAISS per il database '{db_name}' non esiste.")
|
256 |
return "Database non trovato."
|
257 |
|
258 |
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
|
|
|
269 |
return "\n\n".join(results)
|
270 |
|
271 |
def generate_summary(db_name="default_db"):
|
272 |
+
# Placeholder per la logica di summarization
|
273 |
+
return "This is a summary of the documents in the database."
|
app/{app.py → functions/__init__.py}
RENAMED
File without changes
|
app/functions/database_handling.py
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import logging
|
2 |
+
import os
|
3 |
+
import shutil
|
4 |
+
|
5 |
+
# -------------- DATABASE MANAGEMENT TAB FUNCTIONS --------------
|
6 |
+
def create_database(db_name):
|
7 |
+
logging.info(f"Creating database: {db_name}")
|
8 |
+
db_path = f"faiss_index_{db_name}"
|
9 |
+
|
10 |
+
if os.path.exists(db_path):
|
11 |
+
return f"Il database '{db_name}' esiste già."
|
12 |
+
|
13 |
+
try:
|
14 |
+
os.makedirs(db_path)
|
15 |
+
logging.info(f"Database {db_name} created successfully.")
|
16 |
+
return f"Database '{db_name}' creato con successo."
|
17 |
+
except Exception as e:
|
18 |
+
logging.error(f"Errore nella creazione del database: {e}")
|
19 |
+
return f"Errore nella creazione del database: {e}"
|
20 |
+
|
21 |
+
def delete_database(db_name):
|
22 |
+
db_path = f"faiss_index_{db_name}"
|
23 |
+
if not os.path.exists(db_path):
|
24 |
+
return f"Il database '{db_name}' non esiste."
|
25 |
+
try:
|
26 |
+
shutil.rmtree(db_path)
|
27 |
+
logging.info(f"Database {db_name} eliminato con successo.")
|
28 |
+
return f"Database '{db_name}' eliminato con successo."
|
29 |
+
except OSError as e:
|
30 |
+
logging.error(f"Impossibile eliminare il database {db_name}: {e}")
|
31 |
+
return f"Impossibile eliminare il database '{db_name}': {e}"
|
32 |
+
|
33 |
+
def modify_database(old_db_name, new_db_name):
|
34 |
+
old_db_path = f"faiss_index_{old_db_name}"
|
35 |
+
new_db_path = f"faiss_index_{new_db_name}"
|
36 |
+
if not os.path.exists(old_db_path):
|
37 |
+
return f"Il database '{old_db_name}' non esiste."
|
38 |
+
if os.path.exists(new_db_path):
|
39 |
+
return f"Il database '{new_db_name}' esiste già."
|
40 |
+
try:
|
41 |
+
os.rename(old_db_path, new_db_path)
|
42 |
+
return f"Database '{old_db_name}' rinominato in '{new_db_name}' con successo."
|
43 |
+
except Exception as e:
|
44 |
+
return f"Errore durante la modifica del database: {e}"
|
45 |
+
|
46 |
+
def list_databases():
|
47 |
+
try:
|
48 |
+
databases = []
|
49 |
+
for item in os.listdir():
|
50 |
+
if os.path.isdir(item) and item.startswith("faiss_index_"):
|
51 |
+
db_name = item.replace("faiss_index_", "")
|
52 |
+
databases.append(db_name)
|
53 |
+
# Ensure "default_db" is in the list
|
54 |
+
if "default_db" not in databases:
|
55 |
+
databases.append("default_db")
|
56 |
+
return databases
|
57 |
+
except Exception as e:
|
58 |
+
logging.error(f"Error listing databases: {e}")
|
59 |
+
return []
|
app/llm_handling_2.py
DELETED
@@ -1,34 +0,0 @@
|
|
1 |
-
import logging
|
2 |
-
from langchain_openai import ChatOpenAI
|
3 |
-
from app.config import OPENAI_API_KEY
|
4 |
-
|
5 |
-
def answer_question(question):
|
6 |
-
logging.info(f"Chiamata all'LLM con domanda: {question}")
|
7 |
-
sys = (
|
8 |
-
"Sei un assistente AI per la lingua Italiana di nome Counselorbot. "
|
9 |
-
"Rispondi nella lingua usata per la domanda in modo chiaro, semplice ed esaustivo."
|
10 |
-
)
|
11 |
-
|
12 |
-
messages = [
|
13 |
-
{"role": "system", "content": sys},
|
14 |
-
{"role": "user", "content": question}
|
15 |
-
]
|
16 |
-
logging.info(f"Messages sent to LLM: {messages}")
|
17 |
-
|
18 |
-
try:
|
19 |
-
llm = ChatOpenAI(
|
20 |
-
model="gpt-4o-mini",
|
21 |
-
openai_api_key=OPENAI_API_KEY,
|
22 |
-
temperature=0.6,
|
23 |
-
max_tokens=512,
|
24 |
-
top_p=0.9
|
25 |
-
)
|
26 |
-
response = llm.invoke(input=messages)
|
27 |
-
logging.info(f"Contesto RAG inviato all'LLM: {messages}")
|
28 |
-
logging.info(f"Risposta ricevuta dall'LLM: {response}")
|
29 |
-
answer = response.content.strip()
|
30 |
-
logging.info(f"Domanda: {question} | Risposta: {answer}")
|
31 |
-
return answer
|
32 |
-
except Exception as e:
|
33 |
-
logging.error(f"Errore durante la generazione della risposta: {e}")
|
34 |
-
return f"Errore durante la generazione della risposta: {e}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/llm_handling_3.py
DELETED
@@ -1,76 +0,0 @@
|
|
1 |
-
import logging
|
2 |
-
from openai import OpenAI
|
3 |
-
from langchain_community.vectorstores import FAISS
|
4 |
-
from langchain_community.embeddings import HuggingFaceEmbeddings
|
5 |
-
from app.config import OPENAI_API_KEY
|
6 |
-
import gradio as gr
|
7 |
-
import os
|
8 |
-
import shutil
|
9 |
-
|
10 |
-
logging.basicConfig(level=logging.INFO)
|
11 |
-
|
12 |
-
def answer_question(question, db_name, chat_history=None):
|
13 |
-
if chat_history is None:
|
14 |
-
chat_history = []
|
15 |
-
|
16 |
-
logging.info(f"Inizio elaborazione domanda: {question} per database: {db_name}")
|
17 |
-
|
18 |
-
try:
|
19 |
-
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
|
20 |
-
db_path = f"faiss_index_{db_name}"
|
21 |
-
|
22 |
-
if not os.path.exists(db_path):
|
23 |
-
return [{"role": "user", "content": question},
|
24 |
-
{"role": "assistant", "content": "Database non trovato"}]
|
25 |
-
|
26 |
-
vectorstore = FAISS.load_local(db_path, embeddings, allow_dangerous_deserialization=True)
|
27 |
-
relevant_docs = vectorstore.similarity_search(question, k=3)
|
28 |
-
|
29 |
-
# Prepara il contesto dai documenti
|
30 |
-
context = "\n".join([doc.page_content for doc in relevant_docs])
|
31 |
-
|
32 |
-
client = OpenAI(api_key=OPENAI_API_KEY)
|
33 |
-
|
34 |
-
messages = [
|
35 |
-
{"role": "system", "content": f"Usa questo contesto per rispondere: {context}"},
|
36 |
-
{"role": "user", "content": question}
|
37 |
-
]
|
38 |
-
|
39 |
-
response = client.chat.completions.create(
|
40 |
-
model="gpt-3.5-turbo", # Cambiato da gpt-4o-mini a un modello supportato
|
41 |
-
messages=messages,
|
42 |
-
temperature=0,
|
43 |
-
max_tokens=2048
|
44 |
-
)
|
45 |
-
|
46 |
-
answer = response.choices[0].message.content
|
47 |
-
|
48 |
-
return [
|
49 |
-
{"role": "user", "content": question},
|
50 |
-
{"role": "assistant", "content": answer}
|
51 |
-
]
|
52 |
-
|
53 |
-
except Exception as e:
|
54 |
-
logging.error(f"Errore durante la generazione della risposta: {e}")
|
55 |
-
return [
|
56 |
-
{"role": "user", "content": question},
|
57 |
-
{"role": "assistant", "content": f"Si è verificato un errore: {str(e)}"}
|
58 |
-
]
|
59 |
-
|
60 |
-
# Nel document_handling.py, aggiornare delete_database per restituire anche l'aggiornamento del dropdown
|
61 |
-
def delete_database(db_name):
|
62 |
-
db_path = f"faiss_index_{db_name}"
|
63 |
-
if not os.path.exists(db_path):
|
64 |
-
return f"Il database {db_name} non esiste.", gr.Dropdown.update(choices=list_databases())
|
65 |
-
try:
|
66 |
-
shutil.rmtree(db_path)
|
67 |
-
logging.info(f"Database {db_name} eliminato con successo.")
|
68 |
-
return f"Database {db_name} eliminato con successo.", gr.Dropdown.update(choices=list_databases())
|
69 |
-
except OSError as e:
|
70 |
-
logging.error(f"Impossibile eliminare il database {db_name}: {e}")
|
71 |
-
return f"Impossibile eliminare il database {db_name}: {e}", gr.Dropdown.update(choices=list_databases())
|
72 |
-
|
73 |
-
# Manca la chiamata a ensure_default_db()
|
74 |
-
if __name__ == "__main__":
|
75 |
-
ensure_default_db() # Aggiungere questa chiamata
|
76 |
-
rag_chatbot.launch(share=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/logging_config.py
CHANGED
@@ -1,12 +1,51 @@
|
|
1 |
import logging
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
load_dotenv()
|
6 |
|
7 |
def configure_logging():
|
8 |
-
logging.
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import logging
|
2 |
+
import os
|
3 |
+
from datetime import datetime
|
4 |
+
from logging.handlers import RotatingFileHandler
|
|
|
5 |
|
6 |
def configure_logging():
|
7 |
+
"""Configura le impostazioni di logging dell'applicazione."""
|
8 |
+
# Percorso assoluto per la directory logs
|
9 |
+
base_dir = os.path.dirname(os.path.abspath(__file__))
|
10 |
+
log_directory = os.path.join(base_dir, "logs")
|
11 |
+
|
12 |
+
# Crea la directory dei log se non esiste
|
13 |
+
if not os.path.exists(log_directory):
|
14 |
+
os.makedirs(log_directory)
|
15 |
+
|
16 |
+
# Nome file log con timestamp
|
17 |
+
timestamp = datetime.now().strftime("%Y%m%d")
|
18 |
+
log_file = os.path.join(log_directory, f"app_{timestamp}.log")
|
19 |
+
|
20 |
+
# Configura il logger root
|
21 |
+
logger = logging.getLogger()
|
22 |
+
logger.setLevel(logging.INFO)
|
23 |
+
|
24 |
+
# Formattazione del log dettagliata
|
25 |
+
formatter = logging.Formatter(
|
26 |
+
'%(asctime)s - %(name)s - [%(levelname)s] - %(message)s - (%(filename)s:%(lineno)d)'
|
27 |
+
)
|
28 |
+
|
29 |
+
# Handler per il file con rotazione (10MB per file)
|
30 |
+
file_handler = RotatingFileHandler(
|
31 |
+
log_file,
|
32 |
+
maxBytes=10*1024*1024, # 10MB
|
33 |
+
backupCount=10,
|
34 |
+
encoding='utf-8'
|
35 |
+
)
|
36 |
+
file_handler.setFormatter(formatter)
|
37 |
+
file_handler.setLevel(logging.INFO)
|
38 |
+
|
39 |
+
# Handler per la console
|
40 |
+
console_handler = logging.StreamHandler()
|
41 |
+
console_handler.setFormatter(formatter)
|
42 |
+
console_handler.setLevel(logging.INFO)
|
43 |
+
|
44 |
+
# Rimuovi handler esistenti e aggiungi i nuovi
|
45 |
+
logger.handlers.clear()
|
46 |
+
logger.addHandler(file_handler)
|
47 |
+
logger.addHandler(console_handler)
|
48 |
+
|
49 |
+
# Test di scrittura
|
50 |
+
logging.info(f"Logging inizializzato - File: {log_file}")
|
51 |
+
logging.info("Test scrittura log")
|
logging_config.py
DELETED
@@ -1,40 +0,0 @@
|
|
1 |
-
import logging
|
2 |
-
import os
|
3 |
-
from logging.handlers import RotatingFileHandler
|
4 |
-
|
5 |
-
def configure_logging():
|
6 |
-
"""Configura le impostazioni di logging dell'applicazione."""
|
7 |
-
# Crea la directory dei log se non esiste
|
8 |
-
log_directory = "logs"
|
9 |
-
if not os.path.exists(log_directory):
|
10 |
-
os.makedirs(log_directory)
|
11 |
-
|
12 |
-
# Percorso completo del file di log
|
13 |
-
log_file = os.path.join(log_directory, "app.log")
|
14 |
-
|
15 |
-
# Configura il logger root
|
16 |
-
logger = logging.getLogger()
|
17 |
-
logger.setLevel(logging.INFO)
|
18 |
-
|
19 |
-
# Formattazione del log
|
20 |
-
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
21 |
-
|
22 |
-
# Handler per il file con rotazione
|
23 |
-
file_handler = RotatingFileHandler(log_file, maxBytes=1024*1024, backupCount=5)
|
24 |
-
file_handler.setFormatter(formatter)
|
25 |
-
file_handler.setLevel(logging.INFO)
|
26 |
-
|
27 |
-
# Handler per la console
|
28 |
-
console_handler = logging.StreamHandler()
|
29 |
-
console_handler.setFormatter(formatter)
|
30 |
-
console_handler.setLevel(logging.INFO)
|
31 |
-
|
32 |
-
# Rimuovi eventuali handler esistenti
|
33 |
-
logger.handlers.clear()
|
34 |
-
|
35 |
-
# Aggiungi i nuovi handler
|
36 |
-
logger.addHandler(file_handler)
|
37 |
-
logger.addHandler(console_handler)
|
38 |
-
|
39 |
-
# Log di test per verifica
|
40 |
-
logging.info("Logging configurato con successo")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ui/chatbot_tab.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
# ui/chatbot_tab.py
|
2 |
|
3 |
import gradio as gr
|
4 |
-
from app.
|
5 |
from utils.helpers import extract_text_from_files
|
6 |
from app.llm_handling import answer_question
|
7 |
|
|
|
1 |
# ui/chatbot_tab.py
|
2 |
|
3 |
import gradio as gr
|
4 |
+
from app.functions.database_handling import list_databases
|
5 |
from utils.helpers import extract_text_from_files
|
6 |
from app.llm_handling import answer_question
|
7 |
|
ui/db_management_tab.py
CHANGED
@@ -1,16 +1,10 @@
|
|
1 |
-
# ui/db_management_tab.py
|
2 |
-
|
3 |
import gradio as gr
|
4 |
-
from app.document_handling import create_database, modify_database, delete_database, list_databases
|
|
|
5 |
|
6 |
-
def create_db_management_tab(
|
7 |
"""Crea il tab 'Gestione Database' dell'interfaccia Gradio."""
|
8 |
|
9 |
-
def update_dropdowns_callback():
|
10 |
-
"""Aggiorna tutti i dropdown con la lista aggiornata dei database."""
|
11 |
-
databases = list_databases()
|
12 |
-
return [gr.update(choices=databases) for _ in range(6)]
|
13 |
-
|
14 |
# Ottieni la lista iniziale dei database
|
15 |
databases = list_databases()
|
16 |
|
@@ -26,43 +20,53 @@ def create_db_management_tab(update_dropdowns):
|
|
26 |
|
27 |
with gr.Column():
|
28 |
gr.Markdown("### Rinomina Database")
|
29 |
-
modify_db_old_name = gr.Dropdown(
|
|
|
|
|
|
|
30 |
modify_db_new_name = gr.Textbox(label="Nuovo Nome")
|
31 |
modify_db_button = gr.Button("Rinomina Database")
|
32 |
modify_output = gr.Textbox(label="Stato Modifica")
|
33 |
|
34 |
with gr.Column():
|
35 |
gr.Markdown("### Elimina Database")
|
36 |
-
delete_db_dropdown = gr.Dropdown(
|
|
|
|
|
|
|
37 |
delete_db_button = gr.Button("Elimina Database")
|
38 |
delete_output = gr.Textbox(label="Stato Eliminazione")
|
39 |
|
40 |
# Eventi per i bottoni di gestione DB
|
41 |
create_db_button.click(
|
42 |
-
create_database,
|
43 |
inputs=db_name_input,
|
44 |
outputs=create_output
|
45 |
).then(
|
46 |
-
|
|
|
47 |
outputs=[modify_db_old_name, delete_db_dropdown]
|
48 |
)
|
49 |
|
50 |
modify_db_button.click(
|
51 |
-
modify_database,
|
52 |
inputs=[modify_db_old_name, modify_db_new_name],
|
53 |
outputs=modify_output
|
54 |
).then(
|
55 |
-
|
|
|
56 |
outputs=[modify_db_old_name, delete_db_dropdown]
|
57 |
)
|
58 |
|
59 |
delete_db_button.click(
|
60 |
-
delete_database,
|
61 |
inputs=delete_db_dropdown,
|
62 |
outputs=delete_output
|
63 |
).then(
|
64 |
-
|
|
|
65 |
outputs=[modify_db_old_name, delete_db_dropdown]
|
66 |
)
|
67 |
|
68 |
-
|
|
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
+
#from app.document_handling import create_database, modify_database, delete_database, list_databases
|
3 |
+
from app.functions.database_handling import create_database, modify_database, delete_database, list_databases
|
4 |
|
5 |
+
def create_db_management_tab(update_all_dropdowns=None):
|
6 |
"""Crea il tab 'Gestione Database' dell'interfaccia Gradio."""
|
7 |
|
|
|
|
|
|
|
|
|
|
|
8 |
# Ottieni la lista iniziale dei database
|
9 |
databases = list_databases()
|
10 |
|
|
|
20 |
|
21 |
with gr.Column():
|
22 |
gr.Markdown("### Rinomina Database")
|
23 |
+
modify_db_old_name = gr.Dropdown(
|
24 |
+
choices=databases,
|
25 |
+
label="Database da Rinominare"
|
26 |
+
)
|
27 |
modify_db_new_name = gr.Textbox(label="Nuovo Nome")
|
28 |
modify_db_button = gr.Button("Rinomina Database")
|
29 |
modify_output = gr.Textbox(label="Stato Modifica")
|
30 |
|
31 |
with gr.Column():
|
32 |
gr.Markdown("### Elimina Database")
|
33 |
+
delete_db_dropdown = gr.Dropdown(
|
34 |
+
choices=databases,
|
35 |
+
label="Database da Eliminare"
|
36 |
+
)
|
37 |
delete_db_button = gr.Button("Elimina Database")
|
38 |
delete_output = gr.Textbox(label="Stato Eliminazione")
|
39 |
|
40 |
# Eventi per i bottoni di gestione DB
|
41 |
create_db_button.click(
|
42 |
+
fn=create_database,
|
43 |
inputs=db_name_input,
|
44 |
outputs=create_output
|
45 |
).then(
|
46 |
+
fn=update_all_dropdowns, # <--- callback globale
|
47 |
+
inputs=[],
|
48 |
outputs=[modify_db_old_name, delete_db_dropdown]
|
49 |
)
|
50 |
|
51 |
modify_db_button.click(
|
52 |
+
fn=modify_database,
|
53 |
inputs=[modify_db_old_name, modify_db_new_name],
|
54 |
outputs=modify_output
|
55 |
).then(
|
56 |
+
fn=update_all_dropdowns, # <--- callback globale
|
57 |
+
inputs=[],
|
58 |
outputs=[modify_db_old_name, delete_db_dropdown]
|
59 |
)
|
60 |
|
61 |
delete_db_button.click(
|
62 |
+
fn=delete_database,
|
63 |
inputs=delete_db_dropdown,
|
64 |
outputs=delete_output
|
65 |
).then(
|
66 |
+
fn=update_all_dropdowns, # <--- callback globale
|
67 |
+
inputs=[],
|
68 |
outputs=[modify_db_old_name, delete_db_dropdown]
|
69 |
)
|
70 |
|
71 |
+
# Ritorna i componenti che vogliamo poter aggiornare/agganciare
|
72 |
+
return [modify_db_old_name, delete_db_dropdown, create_db_button, modify_db_button, delete_db_button]
|
ui/document_management_tab.py
CHANGED
@@ -1,27 +1,32 @@
|
|
1 |
-
# ui/document_management_tab.py
|
2 |
-
|
3 |
import gradio as gr
|
4 |
-
|
|
|
|
|
5 |
|
6 |
-
def create_document_management_tab(
|
7 |
"""Crea il tab 'Gestione Documenti' dell'interfaccia Gradio."""
|
8 |
|
9 |
def upload_and_index_callback(files, title, author, db_name):
|
10 |
"""Carica e indicizza i documenti, quindi aggiorna la lista dei file."""
|
11 |
-
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
def list_files_callback(db_name):
|
15 |
"""Elenca i file indicizzati nel database specificato."""
|
16 |
files = list_indexed_files(db_name)
|
17 |
-
return
|
18 |
|
19 |
def delete_file_callback(file_name, db_name):
|
20 |
"""Elimina un file dal database e aggiorna la lista."""
|
21 |
status = delete_file_from_database(file_name, db_name)
|
22 |
return status
|
23 |
|
24 |
-
# Ottieni la lista
|
25 |
databases = list_databases()
|
26 |
|
27 |
with gr.Tab("Gestione Documenti"):
|
@@ -45,48 +50,56 @@ def create_document_management_tab(update_dropdowns):
|
|
45 |
|
46 |
upload_button = gr.Button("Indicizza Documenti")
|
47 |
upload_output = gr.Textbox(label="Stato Upload")
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
db_name_list = gr.Dropdown(
|
52 |
-
choices=databases,
|
53 |
-
label="
|
54 |
value="default_db"
|
55 |
)
|
56 |
-
list_button = gr.Button("
|
57 |
-
|
58 |
-
|
|
|
|
|
59 |
delete_file_button = gr.Button("Elimina File")
|
60 |
-
|
61 |
-
|
62 |
-
# Eventi
|
63 |
upload_button.click(
|
64 |
-
upload_and_index_callback,
|
65 |
inputs=[file_input, title_input, author_input, db_name_upload],
|
66 |
outputs=upload_output
|
67 |
).then(
|
68 |
-
|
69 |
-
inputs=
|
|
|
|
|
|
|
|
|
70 |
outputs=list_output
|
71 |
)
|
72 |
|
73 |
list_button.click(
|
74 |
-
|
75 |
-
inputs=db_name_list,
|
76 |
outputs=list_output
|
77 |
)
|
78 |
|
79 |
delete_file_button.click(
|
80 |
-
delete_file_callback,
|
81 |
inputs=[delete_file_input, db_name_list],
|
82 |
outputs=delete_file_output
|
83 |
).then(
|
84 |
-
|
85 |
-
inputs=
|
86 |
-
outputs=list_output
|
87 |
-
).then(
|
88 |
-
update_dropdowns,
|
89 |
outputs=[db_name_upload, db_name_list]
|
|
|
|
|
|
|
|
|
90 |
)
|
91 |
|
92 |
-
|
|
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
+
import logging
|
3 |
+
from app.document_handling import upload_and_index, list_indexed_files, delete_file_from_database
|
4 |
+
from app.functions.database_handling import list_databases
|
5 |
|
6 |
+
def create_document_management_tab(update_all_dropdowns=None):
|
7 |
"""Crea il tab 'Gestione Documenti' dell'interfaccia Gradio."""
|
8 |
|
9 |
def upload_and_index_callback(files, title, author, db_name):
|
10 |
"""Carica e indicizza i documenti, quindi aggiorna la lista dei file."""
|
11 |
+
try:
|
12 |
+
status = upload_and_index(files, title, author, db_name)
|
13 |
+
logging.info(f"Upload completato: {status}")
|
14 |
+
return status
|
15 |
+
except Exception as e:
|
16 |
+
logging.error(f"Errore durante l'upload: {str(e)}")
|
17 |
+
return f"Errore: {str(e)}"
|
18 |
|
19 |
def list_files_callback(db_name):
|
20 |
"""Elenca i file indicizzati nel database specificato."""
|
21 |
files = list_indexed_files(db_name)
|
22 |
+
return files
|
23 |
|
24 |
def delete_file_callback(file_name, db_name):
|
25 |
"""Elimina un file dal database e aggiorna la lista."""
|
26 |
status = delete_file_from_database(file_name, db_name)
|
27 |
return status
|
28 |
|
29 |
+
# Ottieni la lista dei database
|
30 |
databases = list_databases()
|
31 |
|
32 |
with gr.Tab("Gestione Documenti"):
|
|
|
50 |
|
51 |
upload_button = gr.Button("Indicizza Documenti")
|
52 |
upload_output = gr.Textbox(label="Stato Upload")
|
53 |
+
|
54 |
+
gr.Markdown("### Gestione File")
|
55 |
+
with gr.Row():
|
56 |
db_name_list = gr.Dropdown(
|
57 |
+
choices=databases,
|
58 |
+
label="Database",
|
59 |
value="default_db"
|
60 |
)
|
61 |
+
list_button = gr.Button("Lista File")
|
62 |
+
list_output = gr.Textbox(label="File nel Database")
|
63 |
+
|
64 |
+
with gr.Row():
|
65 |
+
delete_file_input = gr.Textbox(label="Nome File da Eliminare")
|
66 |
delete_file_button = gr.Button("Elimina File")
|
67 |
+
delete_file_output = gr.Textbox(label="Stato Eliminazione")
|
68 |
+
|
69 |
+
# Eventi
|
70 |
upload_button.click(
|
71 |
+
fn=upload_and_index_callback,
|
72 |
inputs=[file_input, title_input, author_input, db_name_upload],
|
73 |
outputs=upload_output
|
74 |
).then(
|
75 |
+
fn=update_all_dropdowns, # <--- callback globale
|
76 |
+
inputs=[],
|
77 |
+
outputs=[db_name_upload, db_name_list]
|
78 |
+
).then(
|
79 |
+
fn=list_files_callback,
|
80 |
+
inputs=[db_name_list],
|
81 |
outputs=list_output
|
82 |
)
|
83 |
|
84 |
list_button.click(
|
85 |
+
fn=list_files_callback,
|
86 |
+
inputs=[db_name_list],
|
87 |
outputs=list_output
|
88 |
)
|
89 |
|
90 |
delete_file_button.click(
|
91 |
+
fn=delete_file_callback,
|
92 |
inputs=[delete_file_input, db_name_list],
|
93 |
outputs=delete_file_output
|
94 |
).then(
|
95 |
+
fn=update_all_dropdowns, # <--- callback globale
|
96 |
+
inputs=[],
|
|
|
|
|
|
|
97 |
outputs=[db_name_upload, db_name_list]
|
98 |
+
).then(
|
99 |
+
fn=list_files_callback,
|
100 |
+
inputs=[db_name_list],
|
101 |
+
outputs=list_output
|
102 |
)
|
103 |
|
104 |
+
# Ritorna i dropdown (e altri componenti, se servono) per poterli aggiornare
|
105 |
+
return [db_name_upload, db_name_list, upload_button, list_button, delete_file_button]
|
ui/document_view_tab.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
# ui/document_view_tab.py
|
2 |
|
3 |
import gradio as gr
|
4 |
-
from app.document_handling import list_indexed_documents
|
5 |
-
|
6 |
def create_document_view_tab():
|
7 |
"""Crea il tab 'Visualizza Documenti Indicizzati' dell'interfaccia Gradio."""
|
8 |
|
|
|
1 |
# ui/document_view_tab.py
|
2 |
|
3 |
import gradio as gr
|
4 |
+
from app.document_handling import list_indexed_documents
|
5 |
+
from app.functions.database_handling import list_databases
|
6 |
def create_document_view_tab():
|
7 |
"""Crea il tab 'Visualizza Documenti Indicizzati' dell'interfaccia Gradio."""
|
8 |
|
ui/new_features_tab.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1 |
# ui/new_features_tab.py
|
2 |
|
3 |
import gradio as gr
|
4 |
-
from app.document_handling import search_documents
|
|
|
5 |
|
6 |
def create_new_features_tab():
|
7 |
"""Crea il tab 'Nuove Funzionalità' dell'interfaccia Gradio."""
|
|
|
1 |
# ui/new_features_tab.py
|
2 |
|
3 |
import gradio as gr
|
4 |
+
from app.document_handling import search_documents
|
5 |
+
from app.functions.database_handling import list_databases
|
6 |
|
7 |
def create_new_features_tab():
|
8 |
"""Crea il tab 'Nuove Funzionalità' dell'interfaccia Gradio."""
|