File size: 5,801 Bytes
148bf6b
 
 
 
 
 
 
10ab3df
148bf6b
 
 
 
 
10ab3df
 
 
 
 
 
 
 
 
 
 
148bf6b
10ab3df
 
 
 
 
148bf6b
 
10ab3df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81ef1b9
10ab3df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
125
126
127
128
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(
                "<div id='title'>"
                "<h1>🇹🇷 Türkçe Duygu Analizi</h1>"
                "<p>Model: <b>celalkartoglu/tr-sentiment-bert-win-v1</b> &nbsp;|&nbsp; Sınıflar: <b>Negative</b>, <b>Notr</b>, <b>Positive</b></p>"
                "</div>"
            )
        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 <b>Notr kuralı</b> ayarlarını kullanarak dengeleyebilirsin.")
    gr.Markdown("© 2025 • Gradio ile oluşturuldu")

demo.queue().launch()