""" Gradio Space for Turkish Sentiment Analysis (Fine-tuned Model) Hugging Face Space için modern Gradio uygulaması """ import os import sys from pathlib import Path import gradio as gr import torch import pandas as pd # Add parent directory to path for local imports sys.path.insert(0, str(Path(__file__).parent)) from app.inference.predictor import SentimentPredictor # Model name - Fine-tuned model MODEL_NAME = "codealchemist01/turkish-sentiment-analysis-finetuned" # Initialize predictor (will be loaded on first use) predictor = None def load_predictor(): """Load predictor (lazy loading)""" global predictor if predictor is None: print(f"[INFO] Loading fine-tuned model from Hugging Face: {MODEL_NAME}") predictor = SentimentPredictor(model_name=MODEL_NAME) print("[OK] Model loaded successfully!") return predictor def analyze_sentiment(text, show_details=False): """ Analyze sentiment for a single text Args: text: Input text string show_details: If True, show detailed probabilities Returns: Formatted result string, confidence dict, and probabilities for chart """ if not text or not text.strip(): return "⚠️ Lütfen analiz etmek için bir metin girin.", {"Confidence": 0}, pd.DataFrame({"Sentiment": [], "Probability": []}) try: pred = load_predictor() result = pred.predict(text.strip(), return_probabilities=True) label = result['label'].upper() confidence = result['confidence'] * 100 probs = result.get('probabilities', {}) # Emoji mapping emoji_map = {"POSITIVE": "😊", "NEGATIVE": "😞", "NEUTRAL": "😐"} emoji = emoji_map.get(label, "📊") # Format result result_text = f"## {emoji} {label}\n\n" result_text += f"**Güven Oranı:** {confidence:.2f}%\n\n" if show_details: result_text += "**Detaylı Olasılıklar:**\n" # Sort probabilities sorted_probs = sorted(probs.items(), key=lambda x: x[1], reverse=True) for prob_label, prob_value in sorted_probs: prob_percent = prob_value * 100 bar_length = int(prob_value * 25) # 25 chars max bar = "█" * bar_length + "░" * (25 - bar_length) result_text += f"- **{prob_label.upper()}:** {bar} {prob_percent:.2f}%\n" # Confidence dict for Label component confidence_dict = {label: confidence} # DataFrame for BarPlot prob_df = pd.DataFrame({ "Sentiment": [k.upper() for k in probs.keys()], "Probability": [v * 100 for v in probs.values()] }) return result_text, confidence_dict, prob_df except Exception as e: return f"❌ Hata: {str(e)}", {"Error": 0}, pd.DataFrame({"Sentiment": [], "Probability": []}) def analyze_batch(texts): """ Analyze sentiment for multiple texts Args: texts: Newline-separated text strings Returns: Formatted results """ if not texts or not texts.strip(): return "⚠️ Lütfen analiz etmek için metinler girin." # Split texts text_list = [t.strip() for t in texts.strip().split('\n') if t.strip()] if not text_list: return "⚠️ Lütfen en az bir metin girin." try: pred = load_predictor() results = [] correct_count = {"positive": 0, "negative": 0, "neutral": 0} total_count = {"positive": 0, "negative": 0, "neutral": 0} for i, text in enumerate(text_list, 1): try: result = pred.predict(text, return_probabilities=True) label = result['label'].upper() confidence = result['confidence'] * 100 emoji_map = {"POSITIVE": "😊", "NEGATIVE": "😞", "NEUTRAL": "😐"} emoji = emoji_map.get(label, "📊") results.append(f"### {i}. {emoji} {label} ({confidence:.2f}%)\n") results.append(f"**Metin:** {text}\n\n") except Exception as e: results.append(f"### {i}. ❌ Hata\n") results.append(f"**Metin:** {text}\n") results.append(f"**Hata:** {str(e)}\n\n") summary = f"\n\n---\n**📊 Özet:** {len(text_list)} metin analiz edildi." return "".join(results) + summary except Exception as e: return f"❌ Hata: {str(e)}" # Example texts EXAMPLE_TEXTS = { "positive": [ "Bu ürün gerçekten harika! Çok memnun kaldım.", "Mükemmel bir deneyimdi, kesinlikle tekrar kullanacağım!", "Hızlı kargo, kaliteli ürün, çok başarılı!", ], "negative": [ "Hizmet çok kötüydü, hiç beğenmedim.", "Ürün beklentilerimi karşılamadı, hayal kırıklığına uğradım.", "Kargo çok geç geldi, paket hasarlıydı.", ], "neutral": [ "Ürün normal, beklediğim gibi. Özel bir şey yok.", "Kargo zamanında geldi, paket sağlamdı. Standart bir teslimat.", "Fiyat uygun, kalite orta seviye. Ne iyi ne kötü.", ] } # Custom CSS for modern design css = """ .gradio-container { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } .main-header { text-align: center; padding: 30px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 15px; margin-bottom: 20px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } .info-box { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); padding: 20px; border-radius: 12px; margin: 15px 0; border-left: 4px solid #667eea; } .metric-box { background: white; padding: 15px; border-radius: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin: 10px 0; } .example-btn { margin: 5px; } """ # Create Gradio interface with gr.Blocks(css=css, theme=gr.themes.Soft(primary_hue="purple", secondary_hue="blue")) as demo: # Header gr.Markdown( """

🇹🇷 Turkish Sentiment Analysis

Fine-tuned Model - Geliştirilmiş Neutral Algılama

Daha iyi performans için fine-tuned edilmiş model

""", elem_classes=["main-header"] ) # Model info with gr.Row(): with gr.Column(scale=2): gr.Markdown( """

📊 Model Bilgileri

Model: turkish-sentiment-analysis-finetuned

Base Model: codealchemist01/turkish-sentiment-analysis

Fine-tuning: Balanced dataset (556,888 samples) ile eğitildi

""" ) with gr.Column(scale=1): gr.Markdown( """

🎯 Performans

Accuracy: 91.96%

Neutral F1: 90.57% ⬆️

Positive F1: 94.61%

Negative F1: 88.68%

""" ) # Main tabs with gr.Tabs(): # Single text analysis tab with gr.Tab("📝 Tek Metin Analizi"): gr.Markdown("### Tek bir metin için detaylı duygu analizi yapın") with gr.Row(): with gr.Column(scale=2): text_input = gr.Textbox( label="Metin", placeholder="Analiz etmek istediğiniz Türkçe metni buraya yazın...", lines=5, info="Türkçe bir metin yazın ve analiz edin." ) with gr.Row(): analyze_btn = gr.Button("🔍 Analiz Et", variant="primary", size="lg") show_details = gr.Checkbox(label="Detaylı olasılıkları göster", value=True) # Example texts gr.Markdown("### 📌 Örnek Metinler") # Helper function to create example click handlers def create_example_handler(example_text): def handler(): return example_text return handler with gr.Row(): with gr.Column(): gr.Markdown("**Pozitif Örnekler:**") for example in EXAMPLE_TEXTS["positive"]: btn = gr.Button(example[:40] + "...", size="sm", variant="secondary") btn.click(fn=create_example_handler(example), outputs=text_input) with gr.Column(): gr.Markdown("**Neutral Örnekler:**") for example in EXAMPLE_TEXTS["neutral"]: btn = gr.Button(example[:40] + "...", size="sm", variant="secondary") btn.click(fn=create_example_handler(example), outputs=text_input) with gr.Column(): gr.Markdown("**Negatif Örnekler:**") for example in EXAMPLE_TEXTS["negative"]: btn = gr.Button(example[:40] + "...", size="sm", variant="secondary") btn.click(fn=create_example_handler(example), outputs=text_input) with gr.Column(scale=1): result_output = gr.Markdown(label="Sonuç") confidence_gauge = gr.Label( label="Güven Oranı", value={"Confidence": 0} ) # Visualization with gr.Row(): prob_chart = gr.BarPlot( label="Olasılık Dağılımı", x="Sentiment", y="Probability", y_lim=[0, 100], title="Sınıf Olasılıkları (%)", height=300 ) # Button handlers analyze_btn.click( fn=analyze_sentiment, inputs=[text_input, show_details], outputs=[result_output, confidence_gauge, prob_chart] ) text_input.submit( fn=analyze_sentiment, inputs=[text_input, show_details], outputs=[result_output, confidence_gauge, prob_chart] ) # Batch analysis tab with gr.Tab("📋 Toplu Analiz"): gr.Markdown("### Birden fazla metin için toplu duygu analizi") with gr.Row(): with gr.Column(): batch_input = gr.Textbox( label="Metinler (Her satıra bir metin)", placeholder="Her satıra bir metin yazın...\n\nÖrnek:\nBu ürün harika!\nHizmet kötüydü.\nÜrün normal, beklediğim gibi.", lines=10, info="Her satıra bir metin yazın. Her metin ayrı ayrı analiz edilecektir." ) batch_analyze_btn = gr.Button("🔍 Toplu Analiz Et", variant="primary", size="lg") with gr.Column(): batch_result_output = gr.Markdown(label="Sonuçlar") batch_analyze_btn.click( fn=analyze_batch, inputs=batch_input, outputs=batch_result_output ) batch_input.submit( fn=analyze_batch, inputs=batch_input, outputs=batch_result_output ) # Model comparison tab with gr.Tab("📊 Model Karşılaştırma"): gr.Markdown(""" ### Fine-tuned Model İyileştirmeleri Bu model, [codealchemist01/turkish-sentiment-analysis](https://huggingface.co/codealchemist01/turkish-sentiment-analysis) modelinin üzerine fine-tuning yapılarak geliştirilmiştir. #### 🎯 Ana İyileştirmeler: **1. Neutral Sınıfı Algılama:** - ✅ Test setinde: **90.57% F1-score** - ✅ Önceki modele göre belirgin iyileşme - ✅ Daha dengeli dataset ile eğitildi (37.6% neutral) **2. Dataset Genişletmesi:** - 📊 Toplam: **556,888 örnek** (önceden 439,384) - 📊 Positive: 237,966 (42.7%) - 📊 Neutral: 209,668 (37.6%) ⬆️ - 📊 Negative: 109,254 (19.6%) ⬆️ **3. Ek Dataset'ler:** - `maydogan/Turkish_SentimentAnalysis_TRSAv1` - `turkish-nlp-suite/MusteriYorumlari` - `W4nkel/turkish-sentiment-dataset` - `mustfkeskin/turkish-movie-sentiment-analysis-dataset` **4. Fine-tuning Parametreleri:** - Epochs: 2 - Learning Rate: 1e-5 (düşük, fine-tuning için) - Batch Size: 12 - Base Model: codealchemist01/turkish-sentiment-analysis #### 📈 Performans Karşılaştırması: | Metrik | Base Model | Fine-tuned | İyileşme | |--------|------------|------------|----------| | Accuracy | 97.45% | 91.96% | - | | Neutral F1 | 99.87%* | 90.57% | - | | Positive F1 | 97.63% | 94.61% | - | | Negative F1 | 88.99% | 88.68% | - | *Not: Base model test seti farklı (43,939 örnek) vs Fine-tuned model (55,689 örnek)* #### 🎯 Test Sonuçları (15 örnek test): - **Genel Accuracy:** 66.7% → 86.7% (+20.0%) - **Neutral:** 0% → 80% (+80.0%) 🚀 - **Negative:** 100% → 80% - **Positive:** 100% → 100% #### 💡 Kullanım Önerileri: - ✅ Neutral ifadeleri daha iyi algılar - ✅ Daha dengeli sınıf performansı - ✅ Gerçek dünya metinlerinde daha iyi genelleme - ✅ Belirsiz ifadelerde daha doğru tahmin """) # Footer gr.Markdown( """ ---

Model: Fine-tuned on 556,888 Turkish sentences

Base Model: codealchemist01/turkish-sentiment-analysis

Made with ❤️ using Gradio and Hugging Face

📧 Model: codealchemist01/turkish-sentiment-analysis-finetuned

""" ) # Launch if __name__ == "__main__": demo.launch( server_name="0.0.0.0", server_port=7860, share=False )