Spaces:
Running
Running
File size: 5,474 Bytes
46b2f94 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
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
@retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(6))
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)
|