Spaces:
Sleeping
Sleeping
| import os | |
| import torch | |
| import pandas as pd | |
| import gradio as gr | |
| from collections import defaultdict | |
| from transformers import AutoTokenizer, AutoModelForTokenClassification | |
| # ========================================================================= | |
| # 1. Sabitler ve Model Yükleme | |
| # ========================================================================= | |
| # Hugging Face Hub'daki modelinizin ID'si | |
| HF_MODEL_ID = "LiProject/Bert-Turkish-POS-Trained-V2" | |
| # GPU/CPU kontrolü | |
| DEVICE = "cuda" if torch.cuda.is_available() else "cpu" | |
| try: | |
| # Model ve Tokenizer'ı HF Hub'dan yükle | |
| tok = AutoTokenizer.from_pretrained(HF_MODEL_ID, use_fast=True) | |
| mdl = AutoModelForTokenClassification.from_pretrained(HF_MODEL_ID).to(DEVICE).eval() | |
| print(f"Model yükleme başarılı: {HF_MODEL_ID} ({DEVICE} üzerinde)") | |
| except Exception as e: | |
| print(f"Model veya Tokenizer yüklenirken kritik hata oluştu: {e}") | |
| exit(1) | |
| # ========================================================================= | |
| # 2. Etiket Okuma Fonksiyonları | |
| # ========================================================================= | |
| def build_id2label_from_config(cfg): | |
| # Modelin config dosyasından id2label'ı güvenilir bir şekilde okur | |
| n = getattr(cfg, "num_labels", None) | |
| if n is None: | |
| if isinstance(getattr(cfg, "id2label", None), dict): n = len(cfg.id2label) | |
| elif isinstance(getattr(cfg, "label2id", None), dict): n = len(cfg.label2id) | |
| else: raise ValueError("num_labels/id2label/label2id yok.") | |
| labels = [f"LABEL_{i}" for i in range(n)] | |
| id2label = getattr(cfg, "id2label", None) | |
| if id2label: | |
| if isinstance(id2label, dict): | |
| for k,v in id2label.items(): | |
| try: i = int(k) | |
| except: | |
| try: i = int(float(k)) | |
| except: continue | |
| if 0 <= i < n: labels[i] = str(v) | |
| elif isinstance(id2label, (list,tuple)) and len(id2label)==n: | |
| labels = [str(x) for x in id2label] | |
| l2i = getattr(cfg, "label2id", None) | |
| if isinstance(l2i, dict): | |
| for lbl, idx_ in l2i.items(): | |
| try: i = int(idx_) | |
| except: | |
| try: i = int(float(idx_)) | |
| except: continue | |
| if 0 <= i < n and labels[i].startswith("LABEL_"): | |
| labels[i] = str(lbl) | |
| for i,v in enumerate(labels): | |
| if v.startswith("LABEL_"): labels[i] = str(i) | |
| return labels | |
| ID2LABEL = build_id2label_from_config(mdl.config) | |
| # ========================================================================= | |
| # 3. Inference ve Çıktı Formatı | |
| # ========================================================================= | |
| def tag_rows(multiline_text: str): | |
| """Metni işler ve kelime bazlı etiketlenmiş DataFrame döndürür.""" | |
| rows = [] | |
| sentences = [s.strip() for s in multiline_text.splitlines() if s.strip()] | |
| if not sentences: | |
| return pd.DataFrame(rows) | |
| for sent in sentences: | |
| enc = tok(sent, return_tensors="pt", truncation=True, add_special_tokens=True).to(DEVICE) | |
| logits = mdl(**enc).logits[0] | |
| fast = tok(sent, return_offsets_mapping=True, add_special_tokens=True) | |
| word_ids = fast.word_ids() | |
| offsets = fast["offset_mapping"] | |
| idxs_by_word = defaultdict(list) | |
| for i, wid in enumerate(word_ids): | |
| if wid is not None: | |
| idxs_by_word[wid].append(i) | |
| for wid in sorted(idxs_by_word.keys()): | |
| sub_idxs = idxs_by_word[wid] | |
| start = offsets[sub_idxs[0]][0] | |
| end = offsets[sub_idxs[-1]][1] | |
| surface = sent[start:end] if (start is not None and end is not None) else "" | |
| mean_logits = logits[sub_idxs].mean(dim=0) | |
| pid = int(mean_logits.argmax().item()) | |
| # Modelin doğrudan tahmin ettiği orijinal etiketi al | |
| tag = ID2LABEL[pid] if pid < len(ID2LABEL) else str(pid) | |
| rows.append({"Full_Sentence": sent, "Word": surface, "Tag": tag}) | |
| return pd.DataFrame(rows) | |
| def add_sentence_separators(df: pd.DataFrame, char: str = "-", repeat: int = 10) -> pd.DataFrame: | |
| """Görünürlük için cümleler arasına ayraç satırları ekler.""" | |
| rows, prev = [], None | |
| for _, r in df.iterrows(): | |
| if prev is not None and r["Full_Sentence"] != prev: | |
| sep = char * repeat | |
| rows.append({"Full_Sentence": sep, "Word": sep, "Tag": sep}) | |
| rows.append(r.to_dict()) | |
| prev = r["Full_Sentence"] | |
| return pd.DataFrame(rows) | |
| def run_and_save(text): | |
| """Ana çalıştırma fonksiyonu, tabloyu ve indirilebilir CSV'yi hazırlar.""" | |
| df = tag_rows(text) | |
| df_view = add_sentence_separators(df, char="-", repeat=10) | |
| out_path = "pos_output.csv" | |
| df.to_csv(out_path, index=False) | |
| return df_view, out_path | |
| examples = [ | |
| "hızlıca koştu", | |
| "O her zaman güler.", | |
| "At hızlıca koştu." | |
| ] | |
| # ========================================================================= | |
| # 4. Gradio Arayüzü | |
| # ========================================================================= | |
| # Tema ve CSS (Sizin orijinal stiliniz korundu) | |
| theme = gr.themes.Soft(primary_hue="slate", neutral_hue="slate") | |
| custom_css = """ | |
| /* Sayfa ve temel renkler */ | |
| .gradio-container { background: #000000 !important; color: #FFE8DB !important; font-family: Inter, ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, "Helvetica Neue", Arial, sans-serif; } | |
| .prose h1, .prose h2, .prose h3, .prose p, label { color: #FFE8DB !important; } | |
| .gr-box, .gr-panel, .border, .container { background: #0b0b0b !important; border: 1.5px solid #739EC9 !important; border-radius: 14px !important; } | |
| textarea, input, .gr-textbox, .gr-file, .gr-form input, .gr-form textarea { background: #0f1a26 !important; color: #FFE8DB !important; border: 2px solid #5682B1 !important; border-radius: 12px !important; } | |
| button { transition: background 0.15s ease, filter 0.15s ease, box-shadow 0.15s ease; } | |
| button.primary, .btn-primary { background: #FFE8DB !important; color: #000000 !important; } | |
| button.primary:hover, .btn-primary:hover { filter: brightness(0.92); } | |
| button.secondary, .btn-secondary { background: rgba(86,130,177,0.15) !important; color: #FFE8DB !important; } | |
| button.secondary:hover, .btn-secondary:hover { background: rgba(86,130,177,0.38) !important; border-color: #5682B1 !important; } | |
| table { border-collapse: separate !important; border-spacing: 0 !important; } | |
| th { background: #5682B1 !important; color: #FFE8DB !important; } | |
| td { background: #0f1a26 !important; color: #FFE8DB !important; } | |
| tbody tr:nth-child(2n) td { background: #122434 !important; } | |
| #results_table { max-height: 360px !important; overflow: auto !important; } | |
| #results_table table { table-layout: fixed !important; width: 100% !important; } | |
| #results_table th, #results_table td { white-space: normal !important; word-break: break-word !important; } | |
| #input_text textarea { min-height: 150px !important; } | |
| """ | |
| with gr.Blocks(title="TR POS Tagger", theme=theme, css=custom_css, fill_height=True) as demo: | |
| gr.Markdown("# 🇹🇷 Türkçe POS Tagger") | |
| gr.Markdown(f"Model: `{HF_MODEL_ID.split('/')[-1]}`. Metni satır satır gir (her satır = 1 cümle). Çıktı: **Full_Sentence, Word, Tag**.") | |
| with gr.Row(): | |
| with gr.Column(scale=3): | |
| inp = gr.Textbox( | |
| lines=6, | |
| placeholder="Örn:\nAt hızlıca koştu.\nO her zaman güler.", | |
| show_label=False, | |
| elem_id="input_text" | |
| ) | |
| with gr.Column(scale=1): | |
| btn = gr.Button("Etiketle ve CSV indir", variant="primary", elem_id="run_btn") | |
| clr = gr.Button("Temizle", variant="secondary", elem_id="clear_btn") | |
| out_tbl = gr.Dataframe( | |
| headers=["Full_Sentence","Word","Tag"], | |
| label="Önizleme", | |
| interactive=False, | |
| elem_id="results_table" | |
| ) | |
| out_file = gr.File(label="Çıktı CSV") | |
| gr.Examples(examples=[[e] for e in examples], inputs=inp) | |
| btn.click(run_and_save, inputs=inp, outputs=[out_tbl, out_file]) | |
| inp.submit(run_and_save, inputs=inp, outputs=[out_tbl, out_file]) | |
| clr.click(lambda: ("", None, None), outputs=[inp, out_tbl, out_file]) | |
| if __name__ == "__main__": | |
| demo.launch(debug=True) |