Spaces:
Sleeping
Sleeping
import json | |
import numpy as np | |
import gradio as gr | |
import logging | |
from openai import OpenAI | |
from tenacity import retry, wait_random_exponential, stop_after_attempt | |
import os | |
# Recupero della chiave API dalla variabile d'ambiente "api" | |
api_key = os.environ.get("api") | |
if not api_key: | |
raise ValueError("La variabile d'ambiente 'api' non è stata impostata. Verifica la configurazione dei secrets.") | |
client = OpenAI(api_key=api_key) | |
# Configurazione del logging per errori | |
logging.basicConfig(filename="error.log", level=logging.ERROR, | |
format='%(asctime)s - %(levelname)s - %(message)s') | |
# Funzione per ottenere l'embedding da OpenAI con la nuova sintassi | |
def get_embedding(text, model="text-embedding-3-small"): | |
if not isinstance(text, str) or not text.strip(): | |
raise ValueError("Il testo di input deve essere una stringa non vuota.") | |
text = text.replace("\n", " ") | |
response = client.embeddings.create(input=[text], model=model) | |
return response.data[0].embedding | |
# Funzione per calcolare la similarità coseno | |
def cosine_similarity(vec_a, vec_b): | |
dot_product = np.dot(vec_a, vec_b) | |
norm_a = np.linalg.norm(vec_a) | |
norm_b = np.linalg.norm(vec_b) | |
if norm_a == 0 or norm_b == 0: | |
return 0.0 | |
return dot_product / (norm_a * norm_b) | |
# Funzione per caricare gli embeddings dal file JSON | |
def load_embeddings(file_path): | |
try: | |
with open(file_path, 'r', encoding='utf-8') as file: | |
data = json.load(file) | |
return data | |
except UnicodeDecodeError as e: | |
logging.error(f"Errore di codifica nel caricamento del file JSON: {e}") | |
return f"Errore: {e}" | |
except json.JSONDecodeError as e: | |
logging.error(f"Errore di parsing JSON: {e}") | |
return f"Errore: {e}" | |
except Exception as e: | |
logging.error(f"Errore generico nel caricamento del file JSON: {e}") | |
return f"Errore: {e}" | |
# Funzione per trovare gli articoli simili a partire da una frase chiave | |
def find_similar_articles_from_query(query, embeddings_data): | |
try: | |
query_embedding = get_embedding(query) | |
except Exception as e: | |
error_message = f"Errore nel calcolo dell'embedding per la query: {e}" | |
logging.error(error_message) | |
return None, None, error_message | |
similarities = [] | |
# Calcola la similarità tra l'embedding della query e ciascun articolo | |
for article in embeddings_data: | |
try: | |
similarity = cosine_similarity(query_embedding, article['embedding']) | |
except Exception as e: | |
logging.error(f"Errore nel calcolo della similarità per l'articolo {article.get('titolo_articolo', 'Sconosciuto')}: {e}") | |
similarity = 0.0 | |
# Costruzione del link per il download del PDF | |
pdf_url = f"https://storiadellarterivista.it/data/pdf/{article['testo_pdf']}" | |
pdf_link = f'<a href="{pdf_url}" download>{article["testo_pdf"]}</a>' | |
similarities.append({ | |
"titolo_articolo": article['titolo_articolo'], | |
"similarity": similarity, | |
"pdf_link": pdf_link | |
}) | |
# Ordina gli articoli in ordine decrescente per similarità | |
similarities_sorted = sorted(similarities, key=lambda x: x['similarity'], reverse=True) | |
top_5 = similarities_sorted[:5] | |
# Ordina in ordine crescente per ottenere i 5 articoli con minore similarità | |
bottom_5 = sorted(similarities, key=lambda x: x['similarity'])[:5] | |
return top_5, bottom_5, None | |
# Funzione per generare una tabella HTML a partire da una lista di articoli | |
def generate_html_table(articles, title): | |
html = f"<h3>{title}</h3>" | |
html += '<table border="1" style="border-collapse: collapse; width:100%;">' | |
html += "<tr><th>Titolo Articolo</th><th>Similarità</th><th>PDF</th></tr>" | |
for art in articles: | |
html += f"<tr><td>{art['titolo_articolo']}</td><td>{art['similarity']:.3f}</td><td>{art['pdf_link']}</td></tr>" | |
html += "</table>" | |
return html | |
# Funzione principale chiamata dall'interfaccia GRADIO | |
def search_articles(query): | |
top_5, bottom_5, error = find_similar_articles_from_query(query, embeddings_data) | |
if error: | |
return error, error | |
top_table = generate_html_table(top_5, "Top 5 Articoli più simili") | |
bottom_table = generate_html_table(bottom_5, "Bottom 5 Articoli meno simili") | |
return top_table, bottom_table | |
# Caricamento degli embeddings dal file JSON | |
file_path = 'embedded_articles.json' # Percorso del file JSON contenente gli embeddings | |
embeddings_data = load_embeddings(file_path) | |
# Controllo di eventuali errori nel caricamento degli embeddings | |
if isinstance(embeddings_data, str): | |
logging.error(embeddings_data) | |
print(embeddings_data) | |
else: | |
iface = gr.Interface( | |
fn=search_articles, | |
inputs=gr.Textbox(label="Inserisci una frase chiave", placeholder="Scrivi qui la tua frase di ricerca..."), | |
outputs=[gr.HTML(label="Articoli più simili"), gr.HTML(label="Articoli meno simili")], | |
title="Ricerca Articoli Simili da Frase Chiave", | |
description=("Inserisci una frase chiave per trovare gli articoli semanticamente simili. " | |
"Vengono mostrati i 5 articoli con maggiore similarità e i 5 con minore similarità, " | |
"con il coefficiente di similarità e un link per il download del PDF.") | |
) | |
iface.launch(share=True) | |