import json import os import gradio as gr import numpy from transformers import pipeline, AutoTokenizer, AutoModelForSequenceClassification # ============================== # MODELLO ITALIAN SENTIMENT # ============================== print("๐Ÿ”„ Caricamento modello...") tokenizer = AutoTokenizer.from_pretrained( "MilaNLProc/feel-it-italian-sentiment", use_fast=False ) model = AutoModelForSequenceClassification.from_pretrained( "MilaNLProc/feel-it-italian-sentiment" ) sentiment_pipeline = pipeline( "text-classification", model=model, tokenizer=tokenizer, truncation=True, max_length=512 ) print("โœ… Modello caricato!") # ============================== # CHUNKING # ============================== def chunk_text(text, max_chars=400): if not text or not text.strip(): return [] sentences = text.replace("\n", " ").split(". ") chunks, current = [], "" for s in sentences: if len(current) + len(s) <= max_chars: current += s + ". " else: chunks.append(current.strip()) current = s + ". " if current.strip(): chunks.append(current.strip()) return chunks # ============================== # ANALISI SENTIMENT PER ARTICOLO # ============================== def analyze_article_sentiment(article): text = article.get("content", "") if not text.strip(): article["sentimentAnalysis"] = "UNKNOWN" article["sentimentScore"] = None article["chunksAnalyzed"] = 0 return article chunks = chunk_text(text) if not chunks: article["sentimentAnalysis"] = "UNKNOWN" article["sentimentScore"] = None article["chunksAnalyzed"] = 0 return article results = sentiment_pipeline(chunks) scores = [] for r in results: label = r["label"].lower() if label == "negative": scores.append(0.0) elif label == "neutral": scores.append(0.5) elif label == "positive": scores.append(1.0) if not scores: article["sentimentAnalysis"] = "UNKNOWN" article["sentimentScore"] = None article["chunksAnalyzed"] = len(chunks) return article avg_score = sum(scores) / len(scores) if avg_score <= 0.4: sentiment = "NEGATIVE" elif avg_score < 0.66: sentiment = "NEUTRAL" else: sentiment = "POSITIVE" article["sentimentAnalysis"] = sentiment article["sentimentScore"] = round(avg_score, 3) article["chunksAnalyzed"] = len(chunks) return article # ============================== # FUNZIONE PER GRADIO # ============================== def process_input_json(): """ Legge input.json dal repository, processa gli articoli e restituisce output.json """ input_file = "input.json" output_file = "/tmp/output.json" # Verifica esistenza file if not os.path.exists(input_file): available_files = os.listdir() error_msg = f"โŒ File {input_file} non trovato!\n\n๐Ÿ“‚ File disponibili nella directory:\n" error_msg += "\n".join(f" - {f}" for f in available_files) return None, error_msg try: # Leggi input with open(input_file, 'r', encoding='utf-8') as f: articles = json.load(f) if not isinstance(articles, list): return None, "โŒ Errore: il file JSON deve contenere un array di articoli" log = f"๐Ÿ“Š Trovati {len(articles)} articoli da analizzare\n\n" processed_articles = [] for i, article in enumerate(articles, 1): title = article.get('title', 'N/A')[:60] log += f"โณ [{i}/{len(articles)}] {title}...\n" processed_article = analyze_article_sentiment(article) processed_articles.append(processed_article) log += f" โœ… {processed_article['sentimentAnalysis']} " log += f"(score: {processed_article['sentimentScore']}, " log += f"chunks: {processed_article['chunksAnalyzed']})\n\n" # Scrivi output with open(output_file, 'w', encoding='utf-8') as f: json.dump(processed_articles, f, ensure_ascii=False, indent=2) log += f"\nโœ… COMPLETATO! {len(processed_articles)} articoli processati.\n" log += f"๐Ÿ’พ Output salvato e pronto per il download" return output_file, log except Exception as e: import traceback error_msg = f"โŒ Errore durante l'elaborazione:\n{str(e)}\n\n" error_msg += f"Traceback:\n{traceback.format_exc()}" return None, error_msg def clear_outputs(): """ Pulisce l'output file e il log """ return None, "๐Ÿงน Interfaccia pulita! Puoi modificare input.json e riprocessare." # ============================== # INTERFACCIA GRADIO # ============================== with gr.Blocks(title="Italian Sentiment Analyzer", theme=gr.themes.Soft()) as demo: gr.Markdown("# ๐Ÿง  Italian Sentiment Analyzer") gr.Markdown("Analizza il sentiment di articoli italiani usando il modello Feel-IT") gr.Markdown("### ๐Ÿ“‹ Istruzioni:") gr.Markdown("1. Assicurati che `input.json` sia presente nel repository") gr.Markdown("2. Clicca il pulsante per avviare l'analisi") gr.Markdown("3. Scarica `output.json` con i risultati") with gr.Row(): process_btn = gr.Button("๐Ÿš€ Processa input.json", variant="primary", size="lg", scale=2) clear_btn = gr.Button("๐Ÿงน Clear", variant="secondary", size="lg", scale=1) with gr.Row(): with gr.Column(scale=1): output_file = gr.File(label="๐Ÿ’พ Scarica output.json") with gr.Column(scale=2): log_box = gr.Textbox( label="๐Ÿ“‹ Log elaborazione", lines=20, max_lines=30 ) process_btn.click( fn=process_input_json, inputs=None, outputs=[output_file, log_box] ) clear_btn.click( fn=clear_outputs, inputs=None, outputs=[output_file, log_box] ) gr.Markdown("---") gr.Markdown("### ๐Ÿ“Š Logica di classificazione:") gr.Markdown("- **NEGATIVE** ๐Ÿ”ด: score โ‰ค 0.4") gr.Markdown("- **NEUTRAL** ๐ŸŸก: 0.4 < score < 0.66") gr.Markdown("- **POSITIVE** ๐ŸŸข: score โ‰ฅ 0.66") gr.Markdown("### ๐ŸŽฏ Campi aggiunti nell'output:") gr.Markdown("- **sentimentAnalysis**: POSITIVE / NEUTRAL / NEGATIVE / UNKNOWN") gr.Markdown("- **sentimentScore**: valore numerico da 0.0 (negativo) a 1.0 (positivo)") gr.Markdown("- **chunksAnalyzed**: numero di chunks in cui รจ stato suddiviso il testo") # ============================== # LAUNCH # ============================== if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860)