import gradio as gr import torch from torch.nn.functional import softmax from transformers import AutoTokenizer, AutoModelForSequenceClassification MODEL_ID = "celalkartoglu/tr-sentiment-bert-win-v1" LABELS = ["Negative","Notr","Positive"] MAX_LEN_DEFAULT = 256 tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) model = AutoModelForSequenceClassification.from_pretrained(MODEL_ID) model.eval() def postprocess_label(probs, min_conf=0.55, close_gap=0.10): neg, notr, pos = probs top = probs.argmax() # düşük güven: Notr if probs[top] < min_conf: return "Notr" # Neg ve Pos birbirine çok yakınsa: Notr if abs(neg - pos) < close_gap and (notr >= 0.30 or probs[top] < 0.60): return "Notr" return LABELS[int(top)] @torch.inference_mode() def infer_one(text, max_len=MAX_LEN_DEFAULT, use_rule=False, min_conf=0.55, close_gap=0.10): text = (text or "").strip() if not text: return "", {"Negative": 0.0, "Notr": 0.0, "Positive": 0.0} inputs = tokenizer(text, return_tensors="pt", truncation=True, max_length=int(max_len)) logits = model(**inputs).logits probs = softmax(logits, dim=-1).squeeze().tolist() scores = {LABELS[i]: float(probs[i]) for i in range(3)} label = postprocess_label(torch.tensor(probs), min_conf, close_gap) if use_rule else LABELS[int(torch.tensor(probs).argmax())] return label, scores def infer_batch(texts, max_len=MAX_LEN_DEFAULT, use_rule=False, min_conf=0.55, close_gap=0.10): if isinstance(texts, str): rows = [t.strip() for t in texts.split("\n") if t.strip()] else: rows = texts or [] results = [] for t in rows: lbl, scores = infer_one(t, max_len, use_rule, min_conf, close_gap) results.append([t, lbl, scores["Negative"], scores["Notr"], scores["Positive"]]) return results def export_csv(table): import pandas as pd df = pd.DataFrame(table, columns=["text","label","Negative","Notr","Positive"]) return gr.File.update(value=df.to_csv(index=False).encode("utf-8"), visible=True) theme = gr.themes.Soft(primary_hue="blue", neutral_hue="slate") CUSTOM_CSS = """ #title h1 { font-weight: 800; letter-spacing: -0.02em; } footer {opacity:.7} """ with gr.Blocks(theme=theme, css=CUSTOM_CSS, title="Türkçe Duygu Analizi | BERT") as demo: with gr.Row(): with gr.Column(scale=7): gr.Markdown( "
" "

🇹🇷 Türkçe Duygu Analizi

" "

Model: celalkartoglu/tr-sentiment-bert-win-v1  |  Sınıflar: Negative, Notr, Positive

" "
" ) with gr.Column(scale=5, min_width=280): with gr.Group(): use_rule = gr.Checkbox(value=False, label="Notr kuralını uygula (düşük güven & Neg-Pos yakınlığı)") min_conf = gr.Slider(0.30, 0.85, value=0.55, step=0.01, label="Min güven (Notr eşiği)") close_gap = gr.Slider(0.00, 0.50, value=0.10, step=0.01, label="Neg-Pos yakınlık eşiği") max_len = gr.Slider(64, 384, value=MAX_LEN_DEFAULT, step=8, label="Maks. token uzunluğu") with gr.Tabs(): with gr.Tab("Tek Cümle"): with gr.Row(): with gr.Column(scale=7): txt = gr.Textbox(label="Cümle gir", placeholder="Örn: Film gerçekten çok kötüydü.", lines=3) with gr.Row(): btn = gr.Button("Tahmin Et", variant="primary") clr = gr.Button("Temizle") with gr.Column(scale=5): out_label = gr.Label(label="Tahmin") out_scores = gr.Label(label="Olasılıklar (P)") gr.Markdown("Örnekler") gr.Examples( examples=[ ["Bu yemek harikaydı, ellerinize sağlık."], ["Ne çok iyi ne de çok kötüydü."], ["Film gerçekten çok kötüydü."], ["Ürün zamanında teslim edildi, paketleme normaldi."], ["Beklediğim gibi değildi ama kötü de sayılmaz."] ], inputs=txt ) btn.click( fn=infer_one, inputs=[txt, max_len, use_rule, min_conf, close_gap], outputs=[out_label, out_scores] ) clr.click(lambda: ("", {"Negative":0.0,"Notr":0.0,"Positive":0.0}), outputs=[out_label, out_scores]) with gr.Tab("Çoklu Cümle (satır satır)"): with gr.Row(): with gr.Column(scale=7): multi = gr.Textbox(lines=10, label="Her satıra bir cümle yaz") btn2 = gr.Button("Toplu Tahmin", variant="primary") with gr.Column(scale=5): table = gr.Dataframe(headers=["text","label","Negative","Notr","Positive"], wrap=True, interactive=False, label="Sonuçlar") with gr.Row(): to_csv = gr.Button("CSV Olarak İndir") csv_file = gr.File(label="İndirilebilir CSV", visible=False) btn2.click( fn=infer_batch, inputs=[multi, max_len, use_rule, min_conf, close_gap], outputs=table ) to_csv.click(export_csv, inputs=table, outputs=csv_file) gr.Markdown("---") gr.Markdown("💡 İpucu: Nötr cümleler negatif/pozitife kayıyorsa, sağdaki Notr kuralı ayarlarını kullanarak dengeleyebilirsin.") gr.Markdown("© 2025 • Gradio ile oluşturuldu") demo.queue().launch()