Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -15,21 +15,34 @@ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
| 15 |
|
| 16 |
# --- 1. MODELLERİN HAZIRLANMASI ---
|
| 17 |
ner_pipe = pipeline("ner", model="xlm-roberta-large-finetuned-conll03-english", aggregation_strategy="simple", device=-1)
|
|
|
|
|
|
|
| 18 |
model_id = "Qwen/Qwen2.5-7B-Instruct"
|
| 19 |
-
tokenizer = AutoTokenizer.from_pretrained(model_id)
|
| 20 |
|
| 21 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
llm_model = None
|
| 23 |
IS_LLM_ENABLED = False
|
| 24 |
|
| 25 |
try:
|
| 26 |
-
print("📦 LLM modeli yükleniyor...")
|
|
|
|
| 27 |
|
| 28 |
-
#
|
| 29 |
llm_model = AutoModelForCausalLM.from_pretrained(
|
| 30 |
-
model_id,
|
| 31 |
-
torch_dtype=torch.
|
| 32 |
-
device_map="cpu", #
|
| 33 |
trust_remote_code=True,
|
| 34 |
low_cpu_mem_usage=True
|
| 35 |
)
|
|
@@ -37,19 +50,19 @@ try:
|
|
| 37 |
# Modeli evaluation moduna al
|
| 38 |
llm_model.eval()
|
| 39 |
|
| 40 |
-
# Device
|
| 41 |
device = next(llm_model.parameters()).device
|
| 42 |
-
print(f"✅
|
| 43 |
print(f" Model dtype: {next(llm_model.parameters()).dtype}")
|
| 44 |
|
| 45 |
IS_LLM_ENABLED = True
|
| 46 |
|
| 47 |
except Exception as e:
|
| 48 |
IS_LLM_ENABLED = False
|
| 49 |
-
print(f"⚠️
|
| 50 |
print(traceback.format_exc())
|
| 51 |
|
| 52 |
-
# --- 2. WIKIPEDIA API
|
| 53 |
|
| 54 |
def get_wiki_summary(term):
|
| 55 |
"""Türkçe Wikipedia'dan doğrudan API ile özet getirir"""
|
|
@@ -69,6 +82,10 @@ def get_wiki_summary(term):
|
|
| 69 |
"Nobel": "Nobel Ödülü",
|
| 70 |
"Amerika": "Amerika",
|
| 71 |
"1984": "1984 (roman)",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
}
|
| 73 |
|
| 74 |
# Arama terimlerini hazırla
|
|
@@ -78,7 +95,6 @@ def get_wiki_summary(term):
|
|
| 78 |
search_terms = [value, term]
|
| 79 |
break
|
| 80 |
|
| 81 |
-
# Eğer özel durum yoksa, çoğul ve tekil dene
|
| 82 |
if len(search_terms) == 1:
|
| 83 |
if term.endswith("lar") or term.endswith("ler"):
|
| 84 |
search_terms.append(term[:-3])
|
|
@@ -88,7 +104,6 @@ def get_wiki_summary(term):
|
|
| 88 |
|
| 89 |
print(f"📝 Aranacak terimler: {search_terms}")
|
| 90 |
|
| 91 |
-
# Headers
|
| 92 |
headers = {
|
| 93 |
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
| 94 |
'Accept': 'application/json',
|
|
@@ -99,8 +114,9 @@ def get_wiki_summary(term):
|
|
| 99 |
print(f"🔎 '{search_term}' aranıyor...")
|
| 100 |
|
| 101 |
try:
|
| 102 |
-
# 1. Önce sayfayı doğrudan kontrol et
|
| 103 |
url = "https://tr.wikipedia.org/w/api.php"
|
|
|
|
|
|
|
| 104 |
params = {
|
| 105 |
"action": "query",
|
| 106 |
"format": "json",
|
|
@@ -124,12 +140,11 @@ def get_wiki_summary(term):
|
|
| 124 |
extract = page_info.get('extract', '')
|
| 125 |
if extract and len(extract) > 20:
|
| 126 |
print(f"✅ Doğrudan sayfa bulundu: '{search_term}'")
|
| 127 |
-
print(f" {extract[:100]}...")
|
| 128 |
return extract
|
| 129 |
-
except
|
| 130 |
-
|
| 131 |
|
| 132 |
-
#
|
| 133 |
search_params = {
|
| 134 |
"action": "query",
|
| 135 |
"format": "json",
|
|
@@ -147,49 +162,38 @@ def get_wiki_summary(term):
|
|
| 147 |
search_data = search_response.json()
|
| 148 |
search_results = search_data.get('query', {}).get('search', [])
|
| 149 |
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
print(f"✅ '{search_term}' -> '{title}' bulundu")
|
| 182 |
-
print(f" {extract[:100]}...")
|
| 183 |
-
return extract
|
| 184 |
-
except json.JSONDecodeError:
|
| 185 |
-
print(f"⚠️ JSON hatası")
|
| 186 |
-
|
| 187 |
-
except json.JSONDecodeError:
|
| 188 |
-
print(f"⚠️ Arama JSON hatası")
|
| 189 |
|
| 190 |
-
except requests.exceptions.RequestException as e:
|
| 191 |
-
print(f"⚠️ Request hatası: {str(e)[:50]}")
|
| 192 |
-
continue
|
| 193 |
except Exception as e:
|
| 194 |
print(f"⚠️ Hata: {str(e)[:50]}")
|
| 195 |
continue
|
|
@@ -233,7 +237,7 @@ def test_wikipedia_connection():
|
|
| 233 |
break
|
| 234 |
else:
|
| 235 |
logs.append(f"⚠️ Sayfa bulunamadı")
|
| 236 |
-
except
|
| 237 |
logs.append(f"❌ JSON parse hatası")
|
| 238 |
else:
|
| 239 |
logs.append(f"❌ API hatası: {response.status_code}")
|
|
@@ -243,26 +247,24 @@ def test_wikipedia_connection():
|
|
| 243 |
|
| 244 |
return "\n".join(logs)
|
| 245 |
|
| 246 |
-
# --- 3. LLM ANALİZ FONKSİYONU (
|
| 247 |
|
| 248 |
@spaces.GPU
|
| 249 |
def refine_label_with_llm(entity_text, full_sentence, wiki_context, custom_label_definitions):
|
| 250 |
-
"""
|
| 251 |
-
global llm_model, IS_LLM_ENABLED
|
| 252 |
|
| 253 |
if not IS_LLM_ENABLED or llm_model is None:
|
| 254 |
return "MISC", "LLM Aktif Değil"
|
| 255 |
|
| 256 |
try:
|
| 257 |
-
print(f"\n🧠 LLM analizi: '{entity_text}'")
|
| 258 |
|
| 259 |
-
#
|
| 260 |
-
|
| 261 |
-
# Modeli CPU'ya taşı (güvenlik için)
|
| 262 |
llm_model.to("cpu")
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
pass
|
| 266 |
|
| 267 |
# Etiket Tanımları
|
| 268 |
label_rules = ""
|
|
@@ -270,101 +272,90 @@ def refine_label_with_llm(entity_text, full_sentence, wiki_context, custom_label
|
|
| 270 |
anahtar_kelimeler = ', '.join(v['anahtar_kelimeler'])
|
| 271 |
label_rules += f"### {k}\n- TANIM: {v['tanim']}\n- ANAHTARLAR: {anahtar_kelimeler}\n\n"
|
| 272 |
|
| 273 |
-
#
|
| 274 |
-
prompt = f"""
|
| 275 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 276 |
|
| 277 |
-
|
| 278 |
{label_rules}
|
| 279 |
|
| 280 |
-
|
| 281 |
-
1.
|
| 282 |
-
2.
|
| 283 |
-
3.
|
| 284 |
-
4.
|
| 285 |
-
|
| 286 |
-
REFERANS ANALİZLER (FEW-SHOT):
|
| 287 |
-
Örnek 1 (Tam Uyum):
|
| 288 |
-
VARLIK: 'Inception'
|
| 289 |
-
CÜMLE: "Dün gece Inception filmini tekrar izledim."
|
| 290 |
-
WIKI: "Inception, Christopher Nolan tarafından yönetilen 2010 yapımı bilimkurgu filmidir."
|
| 291 |
-
ANALİZ:
|
| 292 |
-
- Adım 1: Cümlede 'film' ve 'izlemek' kelimeleri görsel esere işaret ediyor.
|
| 293 |
-
- Adım 2: Wiki verisi varlığın bir film olduğunu doğruluyor.
|
| 294 |
-
- Adım 3: Kaynaklar arasında çelişki yok.
|
| 295 |
-
- Adım 4: MOVIE etiketi uygundur.
|
| 296 |
-
CEVAP: MOVIE
|
| 297 |
-
|
| 298 |
-
Örnek 2 (Kritik Çelişki):
|
| 299 |
-
VARLIK: 'Gizli Bahçe'
|
| 300 |
-
CÜMLE: "Yazar son romanı 'Gizli Bahçe' ile ödül aldı."
|
| 301 |
-
WIKI: "Gizli Bahçe: 1993 yapımı bir dram filmidir."
|
| 302 |
-
ANALİZ:
|
| 303 |
-
- Adım 1: Cümlede 'roman' ve 'yazar' kelimeleri varlığı doğrudan kitap olarak niteliyor.
|
| 304 |
-
- Adım 2: Wiki verisi bu ismi bir film (movie) olarak gösteriyor.
|
| 305 |
-
- Adım 3: ÇELİŞKİ TESPİT EDİLDİ. Kaynak hiyerarşisi gereği cümledeki 'roman' ifadesi Wikipedia'dan daha önceliklidir.
|
| 306 |
-
- Adım 4: BOOK etiketi uygundur.
|
| 307 |
-
CEVAP: BOOK
|
| 308 |
-
|
| 309 |
-
GÜNCEL GÖREV:
|
| 310 |
-
- HEDEF VARLIK: {entity_text}
|
| 311 |
-
- ORİJİNAL CÜMLE: "{full_sentence}"
|
| 312 |
-
- HARİCİ BİLGİ (Wikipedia): "{wiki_context}"
|
| 313 |
-
|
| 314 |
-
ÇIKTI KURALLARI:
|
| 315 |
-
- Cevabında asla yıldız (*) veya markdown kullanma.
|
| 316 |
-
- Analiz adımlarını yukarıdaki 4 adımlı protokole göre yaz.
|
| 317 |
-
|
| 318 |
-
ÇIKTI FORMATI:
|
| 319 |
-
Analiz: [4 Adımlı CoT Analizi]
|
| 320 |
-
Cevap: [SADECE_ETIKET_ADI]"""
|
| 321 |
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
model_inputs = {k: v.to("cpu") for k, v in model_inputs.items()}
|
| 329 |
|
| 330 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
|
| 332 |
-
# Generate
|
| 333 |
with torch.no_grad():
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
max_new_tokens=
|
| 337 |
do_sample=False,
|
| 338 |
temperature=0.1,
|
|
|
|
| 339 |
pad_token_id=tokenizer.eos_token_id,
|
| 340 |
eos_token_id=tokenizer.eos_token_id,
|
| 341 |
repetition_penalty=1.1
|
| 342 |
)
|
| 343 |
|
| 344 |
# Çıktıyı decode et
|
| 345 |
-
|
| 346 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 347 |
|
| 348 |
-
print(f"
|
| 349 |
-
print(f"📝 Çıktı: {full_output[:100]}...")
|
| 350 |
|
| 351 |
# Etiket Ayıklama
|
| 352 |
-
clean_output = full_output.replace("*", "")
|
| 353 |
final_label = "MISC"
|
| 354 |
valid_keys = list(custom_label_definitions.keys())
|
| 355 |
-
match = re.search(r"Cevap:\s*([A-Z_]+)", clean_output, re.IGNORECASE)
|
| 356 |
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
if
|
| 360 |
-
final_label =
|
| 361 |
-
print(f"🏷️ Etiket: {final_label}")
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 368 |
|
| 369 |
except RuntimeError as e:
|
| 370 |
print(f"❌ RuntimeError: {str(e)}")
|
|
@@ -448,13 +439,13 @@ def process_ner(text):
|
|
| 448 |
|
| 449 |
if wiki_text and IS_LLM_ENABLED:
|
| 450 |
try:
|
| 451 |
-
current_logs.append(f"🧠 <b>LLM analizi başlatılıyor:</b> '{word}'")
|
| 452 |
yield "<br>".join(current_logs), [[r["Varlık"], r["İlk Etiket"], r["Nihai Etiket"], r["Kaynak"]] for r in final_results]
|
| 453 |
|
| 454 |
new_label, cot_text = refine_label_with_llm(word, text, wiki_text, custom_labels)
|
| 455 |
|
| 456 |
cot_preview = cot_text[:300] + "..." if len(cot_text) > 300 else cot_text
|
| 457 |
-
current_logs.append(f"🧠 <b>
|
| 458 |
|
| 459 |
res = {"Varlık": word, "İlk Etiket": label, "Nihai Etiket": new_label, "Kaynak": "RAG+LLM"}
|
| 460 |
current_logs.append(f"🏷️ <b>Nihai Etiket:</b> {new_label}")
|
|
@@ -503,9 +494,9 @@ def test_single_term(term):
|
|
| 503 |
return "\n".join(logs)
|
| 504 |
|
| 505 |
def check_llm_status():
|
| 506 |
-
global IS_LLM_ENABLED, llm_model
|
| 507 |
|
| 508 |
-
logs = ["=== LLM DURUM KONTROLÜ ==="]
|
| 509 |
logs.append(f"LLM Aktif: {IS_LLM_ENABLED}")
|
| 510 |
logs.append(f"Model: {model_id}")
|
| 511 |
|
|
@@ -516,17 +507,19 @@ def check_llm_status():
|
|
| 516 |
logs.append(f"Device: {device}")
|
| 517 |
logs.append(f"Dtype: {dtype}")
|
| 518 |
logs.append(f"CUDA Kullanılabilir: {torch.cuda.is_available()}")
|
|
|
|
| 519 |
except Exception as e:
|
| 520 |
logs.append(f"Device kontrol hatası: {str(e)}")
|
| 521 |
else:
|
| 522 |
-
logs.append("Model yüklenmemiş!")
|
| 523 |
|
| 524 |
return "\n".join(logs)
|
| 525 |
|
| 526 |
# --- 6. GRADIO ARAYÜZÜ ---
|
| 527 |
|
| 528 |
with gr.Blocks(title="RAG-NER Uzman Karar Destek Sistemi") as demo:
|
| 529 |
-
gr.Markdown("# 🚀 RAG-NER Uzman Karar Destek Sistemi (Türkçe Wikipedia)")
|
|
|
|
| 530 |
|
| 531 |
with gr.Tab("Metin Analizi"):
|
| 532 |
input_text = gr.Textbox(
|
|
@@ -587,11 +580,11 @@ with gr.Blocks(title="RAG-NER Uzman Karar Destek Sistemi") as demo:
|
|
| 587 |
)
|
| 588 |
single_term_btn.click(test_single_term, inputs=single_term_input, outputs=single_term_output)
|
| 589 |
|
| 590 |
-
gr.Markdown("### 🧠 LLM Durum Kontrolü")
|
| 591 |
with gr.Row():
|
| 592 |
-
llm_status_btn = gr.Button("
|
| 593 |
llm_status_output = gr.Textbox(
|
| 594 |
-
label="
|
| 595 |
lines=8,
|
| 596 |
interactive=False
|
| 597 |
)
|
|
@@ -608,7 +601,7 @@ if __name__ == "__main__":
|
|
| 608 |
test_result = test_wikipedia_connection()
|
| 609 |
print(test_result)
|
| 610 |
|
| 611 |
-
print("\n🧠 LLM durumu kontrol ediliyor...")
|
| 612 |
print(check_llm_status())
|
| 613 |
|
| 614 |
print("\n" + "="*50)
|
|
|
|
| 15 |
|
| 16 |
# --- 1. MODELLERİN HAZIRLANMASI ---
|
| 17 |
ner_pipe = pipeline("ner", model="xlm-roberta-large-finetuned-conll03-english", aggregation_strategy="simple", device=-1)
|
| 18 |
+
|
| 19 |
+
# Qwen modeli
|
| 20 |
model_id = "Qwen/Qwen2.5-7B-Instruct"
|
|
|
|
| 21 |
|
| 22 |
+
# Tokenizer'ı yükle
|
| 23 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 24 |
+
model_id,
|
| 25 |
+
trust_remote_code=True,
|
| 26 |
+
padding_side="left"
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
# Eğer tokenizer'da pad_token yoksa eos_token'u kullan
|
| 30 |
+
if tokenizer.pad_token is None:
|
| 31 |
+
tokenizer.pad_token = tokenizer.eos_token
|
| 32 |
+
|
| 33 |
+
# LLM modelini yükle
|
| 34 |
llm_model = None
|
| 35 |
IS_LLM_ENABLED = False
|
| 36 |
|
| 37 |
try:
|
| 38 |
+
print("📦 Qwen LLM modeli yükleniyor...")
|
| 39 |
+
print("⚠️ Bu işlem 7B model olduğu için biraz zaman alabilir...")
|
| 40 |
|
| 41 |
+
# Qwen için özel yükleme
|
| 42 |
llm_model = AutoModelForCausalLM.from_pretrained(
|
| 43 |
+
model_id,
|
| 44 |
+
torch_dtype=torch.float16, # float16 daha hızlı
|
| 45 |
+
device_map="cpu", # CPU'da çalıştır
|
| 46 |
trust_remote_code=True,
|
| 47 |
low_cpu_mem_usage=True
|
| 48 |
)
|
|
|
|
| 50 |
# Modeli evaluation moduna al
|
| 51 |
llm_model.eval()
|
| 52 |
|
| 53 |
+
# Device kontrolü
|
| 54 |
device = next(llm_model.parameters()).device
|
| 55 |
+
print(f"✅ Qwen modeli yüklendi! Device: {device}")
|
| 56 |
print(f" Model dtype: {next(llm_model.parameters()).dtype}")
|
| 57 |
|
| 58 |
IS_LLM_ENABLED = True
|
| 59 |
|
| 60 |
except Exception as e:
|
| 61 |
IS_LLM_ENABLED = False
|
| 62 |
+
print(f"⚠️ Qwen yüklenemedi: {e}")
|
| 63 |
print(traceback.format_exc())
|
| 64 |
|
| 65 |
+
# --- 2. WIKIPEDIA API ---
|
| 66 |
|
| 67 |
def get_wiki_summary(term):
|
| 68 |
"""Türkçe Wikipedia'dan doğrudan API ile özet getirir"""
|
|
|
|
| 82 |
"Nobel": "Nobel Ödülü",
|
| 83 |
"Amerika": "Amerika",
|
| 84 |
"1984": "1984 (roman)",
|
| 85 |
+
"Apple": "Apple (şirket)",
|
| 86 |
+
"Windows": "Microsoft Windows",
|
| 87 |
+
"Linux": "Linux",
|
| 88 |
+
"Python": "Python (programlama dili)",
|
| 89 |
}
|
| 90 |
|
| 91 |
# Arama terimlerini hazırla
|
|
|
|
| 95 |
search_terms = [value, term]
|
| 96 |
break
|
| 97 |
|
|
|
|
| 98 |
if len(search_terms) == 1:
|
| 99 |
if term.endswith("lar") or term.endswith("ler"):
|
| 100 |
search_terms.append(term[:-3])
|
|
|
|
| 104 |
|
| 105 |
print(f"📝 Aranacak terimler: {search_terms}")
|
| 106 |
|
|
|
|
| 107 |
headers = {
|
| 108 |
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
| 109 |
'Accept': 'application/json',
|
|
|
|
| 114 |
print(f"🔎 '{search_term}' aranıyor...")
|
| 115 |
|
| 116 |
try:
|
|
|
|
| 117 |
url = "https://tr.wikipedia.org/w/api.php"
|
| 118 |
+
|
| 119 |
+
# Doğrudan sayfa kontrolü
|
| 120 |
params = {
|
| 121 |
"action": "query",
|
| 122 |
"format": "json",
|
|
|
|
| 140 |
extract = page_info.get('extract', '')
|
| 141 |
if extract and len(extract) > 20:
|
| 142 |
print(f"✅ Doğrudan sayfa bulundu: '{search_term}'")
|
|
|
|
| 143 |
return extract
|
| 144 |
+
except:
|
| 145 |
+
pass
|
| 146 |
|
| 147 |
+
# Arama yap
|
| 148 |
search_params = {
|
| 149 |
"action": "query",
|
| 150 |
"format": "json",
|
|
|
|
| 162 |
search_data = search_response.json()
|
| 163 |
search_results = search_data.get('query', {}).get('search', [])
|
| 164 |
|
| 165 |
+
for result in search_results:
|
| 166 |
+
title = result.get('title', '')
|
| 167 |
+
if title:
|
| 168 |
+
summary_params = {
|
| 169 |
+
"action": "query",
|
| 170 |
+
"format": "json",
|
| 171 |
+
"titles": title,
|
| 172 |
+
"prop": "extracts",
|
| 173 |
+
"exintro": True,
|
| 174 |
+
"explaintext": True,
|
| 175 |
+
"exsentences": 3,
|
| 176 |
+
"origin": "*"
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
summary_response = requests.get(url, params=summary_params, headers=headers, timeout=10, verify=False)
|
| 180 |
+
|
| 181 |
+
if summary_response.status_code == 200:
|
| 182 |
+
try:
|
| 183 |
+
summary_data = summary_response.json()
|
| 184 |
+
pages = summary_data.get('query', {}).get('pages', {})
|
| 185 |
+
|
| 186 |
+
for page_id, page_info in pages.items():
|
| 187 |
+
if page_id != "-1":
|
| 188 |
+
extract = page_info.get('extract', '')
|
| 189 |
+
if extract and len(extract) > 20:
|
| 190 |
+
print(f"✅ '{search_term}' -> '{title}' bulundu")
|
| 191 |
+
return extract
|
| 192 |
+
except:
|
| 193 |
+
pass
|
| 194 |
+
except:
|
| 195 |
+
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
|
|
|
|
|
|
|
|
|
|
| 197 |
except Exception as e:
|
| 198 |
print(f"⚠️ Hata: {str(e)[:50]}")
|
| 199 |
continue
|
|
|
|
| 237 |
break
|
| 238 |
else:
|
| 239 |
logs.append(f"⚠️ Sayfa bulunamadı")
|
| 240 |
+
except:
|
| 241 |
logs.append(f"❌ JSON parse hatası")
|
| 242 |
else:
|
| 243 |
logs.append(f"❌ API hatası: {response.status_code}")
|
|
|
|
| 247 |
|
| 248 |
return "\n".join(logs)
|
| 249 |
|
| 250 |
+
# --- 3. LLM ANALİZ FONKSİYONU (QWEN İÇİN OPTİMİZE) ---
|
| 251 |
|
| 252 |
@spaces.GPU
|
| 253 |
def refine_label_with_llm(entity_text, full_sentence, wiki_context, custom_label_definitions):
|
| 254 |
+
"""Qwen ile etiket analizi yapar - RuntimeError çözümlü"""
|
| 255 |
+
global llm_model, IS_LLM_ENABLED, tokenizer
|
| 256 |
|
| 257 |
if not IS_LLM_ENABLED or llm_model is None:
|
| 258 |
return "MISC", "LLM Aktif Değil"
|
| 259 |
|
| 260 |
try:
|
| 261 |
+
print(f"\n🧠 Qwen LLM analizi: '{entity_text}'")
|
| 262 |
|
| 263 |
+
# Modeli CPU'da tut
|
| 264 |
+
if next(llm_model.parameters()).device.type != "cpu":
|
|
|
|
| 265 |
llm_model.to("cpu")
|
| 266 |
+
if torch.cuda.is_available():
|
| 267 |
+
torch.cuda.empty_cache()
|
|
|
|
| 268 |
|
| 269 |
# Etiket Tanımları
|
| 270 |
label_rules = ""
|
|
|
|
| 272 |
anahtar_kelimeler = ', '.join(v['anahtar_kelimeler'])
|
| 273 |
label_rules += f"### {k}\n- TANIM: {v['tanim']}\n- ANAHTARLAR: {anahtar_kelimeler}\n\n"
|
| 274 |
|
| 275 |
+
# Qwen için özel prompt formatı
|
| 276 |
+
prompt = f"""<|im_start|>system
|
| 277 |
+
Sen bir NER (Named Entity Recognition) uzmanısın. Verilen varlığı analiz et ve doğru kategoriyi belirle.
|
| 278 |
+
<|im_end|>
|
| 279 |
+
<|im_start|>user
|
| 280 |
+
Aşağıdaki varlığı analiz et ve hangi kategoriye ait olduğunu söyle.
|
| 281 |
+
|
| 282 |
+
VARLIK: {entity_text}
|
| 283 |
+
CÜMLE: {full_sentence}
|
| 284 |
+
WIKIPEDIA BİLGİSİ: {wiki_context}
|
| 285 |
|
| 286 |
+
KATEGORİLER VE TANIMLARI:
|
| 287 |
{label_rules}
|
| 288 |
|
| 289 |
+
Kurallar:
|
| 290 |
+
1. Cümledeki bağlama göre karar ver
|
| 291 |
+
2. Wikipedia bilgisiyle karşılaştır
|
| 292 |
+
3. Çelişki varsa cümledeki kullanıma öncelik ver
|
| 293 |
+
4. Sadece kategori adını yaz (MOVIE, BOOK, SOFTWARE, AWARD, PRODUCT, NORP, GPE)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 294 |
|
| 295 |
+
CEVAP:
|
| 296 |
+
<|im_end|>
|
| 297 |
+
<|im_start|>assistant
|
| 298 |
+
"""
|
| 299 |
+
|
| 300 |
+
print(f"🔄 Qwen generate başlatılıyor...")
|
|
|
|
| 301 |
|
| 302 |
+
# Tokenize et
|
| 303 |
+
inputs = tokenizer(
|
| 304 |
+
prompt,
|
| 305 |
+
return_tensors="pt",
|
| 306 |
+
truncation=True,
|
| 307 |
+
max_length=2048,
|
| 308 |
+
padding=True
|
| 309 |
+
)
|
| 310 |
+
inputs = {k: v.to("cpu") for k, v in inputs.items()}
|
| 311 |
|
| 312 |
+
# Generate - CPU'da
|
| 313 |
with torch.no_grad():
|
| 314 |
+
outputs = llm_model.generate(
|
| 315 |
+
inputs.input_ids,
|
| 316 |
+
max_new_tokens=200,
|
| 317 |
do_sample=False,
|
| 318 |
temperature=0.1,
|
| 319 |
+
top_p=0.9,
|
| 320 |
pad_token_id=tokenizer.eos_token_id,
|
| 321 |
eos_token_id=tokenizer.eos_token_id,
|
| 322 |
repetition_penalty=1.1
|
| 323 |
)
|
| 324 |
|
| 325 |
# Çıktıyı decode et
|
| 326 |
+
full_output = tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 327 |
+
|
| 328 |
+
print(f"✅ Qwen çıktısı alındı")
|
| 329 |
+
|
| 330 |
+
# Assistant kısmını bul
|
| 331 |
+
if "<|im_start|>assistant" in full_output:
|
| 332 |
+
response = full_output.split("<|im_start|>assistant")[-1].strip()
|
| 333 |
+
else:
|
| 334 |
+
response = full_output[len(prompt):].strip()
|
| 335 |
|
| 336 |
+
print(f"📝 Çıktı: {response[:200]}...")
|
|
|
|
| 337 |
|
| 338 |
# Etiket Ayıklama
|
|
|
|
| 339 |
final_label = "MISC"
|
| 340 |
valid_keys = list(custom_label_definitions.keys())
|
|
|
|
| 341 |
|
| 342 |
+
# Regex ile etiket bul
|
| 343 |
+
for label in valid_keys:
|
| 344 |
+
if re.search(rf'\b{label}\b', response, re.IGNORECASE):
|
| 345 |
+
final_label = label
|
| 346 |
+
print(f"🏷️ Etiket bulundu: {final_label}")
|
| 347 |
+
break
|
| 348 |
+
|
| 349 |
+
# Eğer bulunamadıysa, tüm kelimeleri kontrol et
|
| 350 |
+
if final_label == "MISC":
|
| 351 |
+
words = re.findall(r'[A-Z_]+', response.upper())
|
| 352 |
+
for word in words:
|
| 353 |
+
if word in valid_keys:
|
| 354 |
+
final_label = word
|
| 355 |
+
print(f"🏷️ Kelime eşleşmesi: {final_label}")
|
| 356 |
+
break
|
| 357 |
+
|
| 358 |
+
return final_label, response
|
| 359 |
|
| 360 |
except RuntimeError as e:
|
| 361 |
print(f"❌ RuntimeError: {str(e)}")
|
|
|
|
| 439 |
|
| 440 |
if wiki_text and IS_LLM_ENABLED:
|
| 441 |
try:
|
| 442 |
+
current_logs.append(f"🧠 <b>Qwen LLM analizi başlatılıyor:</b> '{word}' (Bu işlem biraz zaman alabilir...)")
|
| 443 |
yield "<br>".join(current_logs), [[r["Varlık"], r["İlk Etiket"], r["Nihai Etiket"], r["Kaynak"]] for r in final_results]
|
| 444 |
|
| 445 |
new_label, cot_text = refine_label_with_llm(word, text, wiki_text, custom_labels)
|
| 446 |
|
| 447 |
cot_preview = cot_text[:300] + "..." if len(cot_text) > 300 else cot_text
|
| 448 |
+
current_logs.append(f"🧠 <b>LLM Çıktısı:</b> {cot_preview}")
|
| 449 |
|
| 450 |
res = {"Varlık": word, "İlk Etiket": label, "Nihai Etiket": new_label, "Kaynak": "RAG+LLM"}
|
| 451 |
current_logs.append(f"🏷️ <b>Nihai Etiket:</b> {new_label}")
|
|
|
|
| 494 |
return "\n".join(logs)
|
| 495 |
|
| 496 |
def check_llm_status():
|
| 497 |
+
global IS_LLM_ENABLED, llm_model, model_id
|
| 498 |
|
| 499 |
+
logs = ["=== Qwen LLM DURUM KONTROLÜ ==="]
|
| 500 |
logs.append(f"LLM Aktif: {IS_LLM_ENABLED}")
|
| 501 |
logs.append(f"Model: {model_id}")
|
| 502 |
|
|
|
|
| 507 |
logs.append(f"Device: {device}")
|
| 508 |
logs.append(f"Dtype: {dtype}")
|
| 509 |
logs.append(f"CUDA Kullanılabilir: {torch.cuda.is_available()}")
|
| 510 |
+
logs.append(f"Model Boyutu: {sum(p.numel() for p in llm_model.parameters()):,} parametre")
|
| 511 |
except Exception as e:
|
| 512 |
logs.append(f"Device kontrol hatası: {str(e)}")
|
| 513 |
else:
|
| 514 |
+
logs.append("❌ Model yüklenmemiş!")
|
| 515 |
|
| 516 |
return "\n".join(logs)
|
| 517 |
|
| 518 |
# --- 6. GRADIO ARAYÜZÜ ---
|
| 519 |
|
| 520 |
with gr.Blocks(title="RAG-NER Uzman Karar Destek Sistemi") as demo:
|
| 521 |
+
gr.Markdown("# 🚀 RAG-NER Uzman Karar Destek Sistemi (Türkçe Wikipedia + Qwen)")
|
| 522 |
+
gr.Markdown(f"**LLM Modeli:** {model_id}")
|
| 523 |
|
| 524 |
with gr.Tab("Metin Analizi"):
|
| 525 |
input_text = gr.Textbox(
|
|
|
|
| 580 |
)
|
| 581 |
single_term_btn.click(test_single_term, inputs=single_term_input, outputs=single_term_output)
|
| 582 |
|
| 583 |
+
gr.Markdown("### 🧠 Qwen LLM Durum Kontrolü")
|
| 584 |
with gr.Row():
|
| 585 |
+
llm_status_btn = gr.Button("Qwen Durumunu Kontrol Et", variant="secondary")
|
| 586 |
llm_status_output = gr.Textbox(
|
| 587 |
+
label="Qwen Durumu",
|
| 588 |
lines=8,
|
| 589 |
interactive=False
|
| 590 |
)
|
|
|
|
| 601 |
test_result = test_wikipedia_connection()
|
| 602 |
print(test_result)
|
| 603 |
|
| 604 |
+
print("\n🧠 Qwen LLM durumu kontrol ediliyor...")
|
| 605 |
print(check_llm_status())
|
| 606 |
|
| 607 |
print("\n" + "="*50)
|