leilaghomashchi commited on
Commit
fc2da02
·
verified ·
1 Parent(s): 90a6f53

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +171 -140
app.py CHANGED
@@ -3,7 +3,7 @@ NER Anonymization Evaluator for Hugging Face Spaces
3
  ابزار ارزیابی استاندارد سیستم‌های ناشناس‌سازی با NER
4
 
5
  Author: Your Name
6
- Version: 1.0.0
7
  License: MIT
8
  """
9
 
@@ -14,6 +14,8 @@ from typing import Dict, List, Tuple
14
  import gradio as gr
15
  from datetime import datetime
16
  import io
 
 
17
 
18
  # ==================== Import seqeval ====================
19
  try:
@@ -286,30 +288,59 @@ class StandardNEREvaluator:
286
 
287
  try:
288
  # بارگذاری فایل
289
- df = pd.read_csv(file_path)
 
 
 
290
 
291
- # تشخیص ستون‌ها
292
  if 'Reference_text' in df.columns and 'anonymized_text' in df.columns:
293
  reference_col = 'Reference_text'
294
  predicted_col = 'anonymized_text'
 
295
  elif 'original_text' in df.columns and 'anonymized_text' in df.columns:
296
  reference_col = 'original_text'
297
  predicted_col = 'anonymized_text'
 
298
  else:
 
299
  return (
300
  False,
301
- "❌ فایل باید شامل ستون‌های 'original_text' و 'anonymized_text' باشد",
302
  pd.DataFrame()
303
  )
304
 
 
 
305
  # ارزیابی هر سطر
306
  results = []
307
  for index, row in df.iterrows():
308
- metrics = self.evaluate_single_row(
309
- str(row[reference_col]),
310
- str(row[predicted_col])
311
- )
312
- results.append(metrics)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
 
314
  # ایجاد DataFrame نتایج
315
  results_df = pd.DataFrame(results)
@@ -355,7 +386,11 @@ class StandardNEREvaluator:
355
  • کل False Negatives: {total_fn}
356
  • تعداد سطرها: {len(df)}
357
 
358
- 🔬 **مقایسه با Exact Match:**
 
 
 
 
359
  • F1 (seqeval): {avg_seqeval_f1:.4f}
360
  • F1 (Exact): {avg_exact_f1:.4f}
361
  • اختلاف: {abs(avg_seqeval_f1 - avg_exact_f1):.4f}
@@ -365,7 +400,10 @@ class StandardNEREvaluator:
365
  return True, status, results_df
366
 
367
  except Exception as e:
368
- return False, f"❌ خطا در پردازش: {str(e)}", pd.DataFrame()
 
 
 
369
 
370
  def generate_report(self, df: pd.DataFrame) -> str:
371
  """
@@ -397,11 +435,11 @@ class StandardNEREvaluator:
397
 
398
  # تفسیر نتایج
399
  if avg_seqeval_f1 >= 0.9:
400
- interpretation = "✅ عملکرد عالی - سیستم شما بسیار دقیق است"
401
  elif avg_seqeval_f1 >= 0.7:
402
  interpretation = "⚠️ عملکرد خوب - اما قابل بهبود"
403
  else:
404
- interpretation = "❌ عملکرد ضعیف - نیاز به بهبود اساسی"
405
 
406
  report = f"""
407
  ## 📊 گزارش جامع ارزیابی NER
@@ -412,6 +450,7 @@ class StandardNEREvaluator:
412
  ### 📈 آمار کلی:
413
  - **تعداد کل سطرها:** {total_rows}
414
  - **روش ارزیابی:** IOB2 Tagging (استاندارد CoNLL-2003)
 
415
 
416
  ### ✅ نتایج seqeval (استاندارد):
417
  - **میانگین Precision:** {avg_seqeval_p:.4f}
@@ -429,30 +468,38 @@ class StandardNEREvaluator:
429
  - **بدترین F1:** {df.loc[worst_idx, 'seqeval_f1']:.4f} (سطر {worst_idx + 1})
430
 
431
  ### 💡 توصیه‌ها:
432
- {"- سیستم شما عملکرد بسیار خوبی دارد" if avg_seqeval_f1 >= 0.9 else ""}
433
- {"- روی بهبود Precision تمرکز کنید" if avg_seqeval_p < avg_seqeval_r else ""}
434
- {"- روی بهبود Recall تمرکز کنید" if avg_seqeval_r < avg_seqeval_p else ""}
435
- {"- نیاز به بازنگری اساسی در مدل دارید" if avg_seqeval_f1 < 0.5 else ""}
436
  """
437
 
438
  return report
439
 
440
- def create_csv(self) -> bytes:
441
  """
442
  ایجاد فایل CSV برای دانلود
443
 
444
  Returns:
445
- محتوای CSV به صورت bytes
446
  """
447
  if self.results_df is None or self.results_df.empty:
448
  return None
449
 
450
  try:
451
- csv_buffer = io.StringIO()
452
- self.results_df.to_csv(csv_buffer, index=False, encoding='utf-8')
453
- return csv_buffer.getvalue().encode('utf-8-sig')
 
 
 
 
 
 
 
 
454
  except Exception as e:
455
- print(f"خطا در ایجاد CSV: {str(e)}")
456
  return None
457
 
458
 
@@ -494,14 +541,6 @@ def create_interface():
494
  border-radius: 5px;
495
  margin: 10px 0;
496
  }
497
- .metric-good {
498
- color: #059669;
499
- font-weight: bold;
500
- }
501
- .metric-bad {
502
- color: #dc2626;
503
- font-weight: bold;
504
- }
505
  """
506
 
507
  # ساخت Interface
@@ -515,25 +554,23 @@ def create_interface():
515
  ) as demo:
516
 
517
  # هدر
518
- with gr.Row():
519
- gr.Markdown(f"""
520
- <div class="header-box">
521
- <h1 style="margin:0; text-align:center;">🎯 ابزار ارزیابی استاندارد NER</h1>
522
- <p style="margin:5px 0 0 0; text-align:center;">
523
- Named Entity Recognition Evaluation Tool
524
- </p>
525
- </div>
526
- """)
527
 
528
  # وضعیت seqeval
529
- with gr.Row():
530
- gr.Markdown(f"""
531
- <div class="status-box rtl">
532
- <strong>وضعیت seqeval:</strong> {seqeval_emoji} {seqeval_status}
533
- <br>
534
- <small>این ابزار برای ارزیابی سیستم‌های ناشناس‌سازی متن با استفاده از الگوریتم‌های استاندارد NER طراحی شده است.</small>
535
- </div>
536
- """)
537
 
538
  # بخش اصلی
539
  with gr.Row():
@@ -542,16 +579,17 @@ def create_interface():
542
  gr.Markdown("### 📁 بارگذاری فایل", elem_classes=["rtl"])
543
 
544
  file_input = gr.File(
545
- label="فایل CSV",
546
  file_types=[".csv"],
547
  type="filepath"
548
  )
549
 
550
  gr.Markdown("""
551
  <div class="rtl" style="font-size:0.9em; color:#666;">
552
- فایل باید شامل دو ستون باشد:<br>
553
- • <code>original_text</code> یا <code>Reference_text</code><br>
554
- • <code>anonymized_text</code>
 
555
  </div>
556
  """)
557
 
@@ -561,8 +599,8 @@ def create_interface():
561
  size="lg"
562
  )
563
 
564
- download_btn = gr.DownloadButton(
565
- label="💾 دانلود نتایج CSV",
566
  visible=False,
567
  variant="secondary"
568
  )
@@ -570,7 +608,7 @@ def create_interface():
570
  # ستون راست: وضعیت
571
  with gr.Column(scale=2):
572
  status_output = gr.Markdown(
573
- "آماده دریافت فایل CSV...",
574
  elem_classes=["rtl"]
575
  )
576
 
@@ -587,96 +625,50 @@ def create_interface():
587
  wrap=True
588
  )
589
 
 
 
 
 
 
 
590
  # راهنما
591
  with gr.Accordion("📖 راهنمای استفاده", open=False):
592
  gr.Markdown("""
593
  <div class="rtl">
594
 
595
- ## 🎯 نحوه استفاده:
596
 
597
- ### 1. آماده‌سازی فایل CSV:
598
-
599
- فایل شما باید شامل دو ستون باشد:
600
 
601
  ```csv
602
- original_text,anonymized_text
603
- "شرکت فولاد مبارکه","شرکت company-01"
604
- "آقای احمد رضایی","person-02"
605
- "سود 15 درصد","سود percent-03"
606
  ```
607
 
608
- ### 2. فرمت‌های پشتیبانی شده:
609
 
610
- #### شرکت‌ها (Company):
611
- - `company-01`, `Company-01`, `COMPANY-01`
612
- - `COMPANY_001`, `COMPANY_001_REGEX`
613
 
614
- #### افراد (Person):
615
- - `person-02`, `Person-02`, `PERSON-02`
616
- - `PERSON_002`, `PERSON_002_REGEX`
617
 
618
- #### مبالغ (Amount):
619
- - `amount-03`, `AMOUNT-03`
620
- - `AMOUNT_003`, `AMOUNT_003_REGEX`
621
 
622
- #### درصدها (Percent):
623
- - `percent-04`, `PERCENT-04`
624
 
625
- #### گروه‌ها (Group):
 
 
 
626
  - `group-05`, `GROUP-05`
627
-
628
- #### سهام (Stock):
629
  - `stock-06`, `STOCK-06`
630
- - `STOCK_SYMBOL_006`
631
 
632
  ### 3. معیارهای ارزیابی:
633
 
634
- - **Precision**: از entities شناسایی شده، چند درصد درست بودند؟
635
- - **Recall**: از entities واقعی، چند درصد پیدا شدند؟
636
  - **F1-Score**: میانگین هماهنگ Precision و Recall
637
- - **Accuracy**: دقت کلی
638
-
639
- ### 4. روش‌های ارزیابی:
640
-
641
- 1. **seqeval (پیشنهادی)**: استفاده از IOB2 tagging - استاندارد CoNLL-2003
642
- 2. **Exact Match**: مقایسه مستقیم شناسه‌ها
643
-
644
- ### 5. تفسیر نتایج:
645
-
646
- - **F1 ≥ 0.9**: عملکرد عالی ✅
647
- - **F1 ≥ 0.7**: عملکرد خوب ⚠️
648
- - **F1 < 0.7**: نیاز به بهبود ❌
649
-
650
- </div>
651
- """)
652
-
653
- # مثال
654
- with gr.Accordion("💡 مثال عملی", open=False):
655
- gr.Markdown("""
656
- <div class="rtl">
657
-
658
- ## مثال:
659
-
660
- ### ورودی:
661
- ```
662
- متن مرجع: "شرکت company-01 با person-02 کار می‌کند"
663
- متن پیش‌بینی: "شرکت company-01 با person-99 کار می‌کند"
664
- ```
665
-
666
- ### تحلیل:
667
- - ✅ `company-01` درست شناسایی شد
668
- - ❌ `person-02` باید بود اما `person-99` شد
669
-
670
- ### نتایج:
671
- - **True Positive**: 1 (company-01)
672
- - **False Positive**: 1 (person-99)
673
- - **False Negative**: 1 (person-02)
674
- - **Precision**: 0.50
675
- - **Recall**: 0.50
676
- - **F1-Score**: 0.50
677
-
678
- ### تفسیر:
679
- سیستم 50% دقت دارد - نیمی از entities را درست تشخیص داده است.
680
 
681
  </div>
682
  """)
@@ -696,7 +688,7 @@ def create_interface():
696
 
697
  Made with ❤️ for Persian NLP Community
698
 
699
- <small>Version 1.0.0 • MIT License</small>
700
 
701
  </div>
702
  """)
@@ -710,52 +702,85 @@ def create_interface():
710
  "❌ لطفاً فایل CSV را بارگذاری کنید",
711
  gr.Markdown(visible=False),
712
  gr.Dataframe(visible=False),
713
- gr.DownloadButton(visible=False)
 
714
  )
715
 
716
  try:
 
 
 
 
717
  # ارزیابی
718
  success, message, df = evaluator.evaluate_dataset(file)
719
 
720
  if not success:
 
721
  return (
722
  f"❌ {message}",
723
  gr.Markdown(visible=False),
724
  gr.Dataframe(visible=False),
725
- gr.DownloadButton(visible=False)
 
726
  )
727
 
 
 
728
  # تولید گزارش
729
  summary = evaluator.generate_report(df)
730
 
731
- # ایجاد CSV
732
- csv_content = evaluator.create_csv()
733
-
734
  # نمایش نتایج
735
  return (
736
  message,
737
  gr.Markdown(value=summary, visible=True),
738
  gr.Dataframe(value=df.head(10), visible=True),
739
- gr.DownloadButton(
740
- label="💾 دانلود نتایج کامل CSV",
741
- value=csv_content,
742
- visible=True
743
- )
744
  )
745
 
746
  except Exception as e:
 
 
 
747
  return (
748
- f"❌ خطای غیرمنتظره: {str(e)}",
749
  gr.Markdown(visible=False),
750
  gr.Dataframe(visible=False),
751
- gr.DownloadButton(visible=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
752
  )
753
 
754
- # اتصال event
755
  evaluate_btn.click(
756
  fn=evaluate_file,
757
  inputs=[file_input],
758
- outputs=[status_output, summary_output, results_table, download_btn]
 
 
 
 
 
759
  )
760
 
761
  return demo
@@ -763,10 +788,16 @@ def create_interface():
763
 
764
  # ==================== Main ====================
765
  if __name__ == "__main__":
 
 
 
 
 
 
766
  # ایجاد و اجرای interface
767
  demo = create_interface()
768
  demo.launch(
769
  server_name="0.0.0.0",
770
  server_port=7860,
771
  share=False
772
- )
 
3
  ابزار ارزیابی استاندارد سیستم‌های ناشناس‌سازی با NER
4
 
5
  Author: Your Name
6
+ Version: 1.0.1
7
  License: MIT
8
  """
9
 
 
14
  import gradio as gr
15
  from datetime import datetime
16
  import io
17
+ import tempfile
18
+ import os
19
 
20
  # ==================== Import seqeval ====================
21
  try:
 
288
 
289
  try:
290
  # بارگذاری فایل
291
+ print(f"📁 در حال خواندن فایل: {file_path}")
292
+ df = pd.read_csv(file_path, encoding='utf-8-sig')
293
+ print(f"✅ فایل خوانده شد: {len(df)} سطر")
294
+ print(f"📋 ستون‌ها: {list(df.columns)}")
295
 
296
+ # تشخیص ستون‌ها با اولویت Reference_text
297
  if 'Reference_text' in df.columns and 'anonymized_text' in df.columns:
298
  reference_col = 'Reference_text'
299
  predicted_col = 'anonymized_text'
300
+ print(f"✅ حالت 3 ستونه: Reference_text (مرجع) vs anonymized_text (LLM)")
301
  elif 'original_text' in df.columns and 'anonymized_text' in df.columns:
302
  reference_col = 'original_text'
303
  predicted_col = 'anonymized_text'
304
+ print(f"⚠️ حالت 2 ستونه: original_text به عنوان مرجع")
305
  else:
306
+ available_cols = list(df.columns)
307
  return (
308
  False,
309
+ f"❌ ستون‌های مورد نیاز یافت نشد!\n\nستون‌های موجود: {available_cols}\n\nستون‌های مورد نیاز:\n• Reference_text (مرجع انسانی)\n• anonymized_text (پیش‌بینی LLM)",
310
  pd.DataFrame()
311
  )
312
 
313
+ print(f"🔍 شروع ارزیابی {len(df)} سطر...")
314
+
315
  # ارزیابی هر سطر
316
  results = []
317
  for index, row in df.iterrows():
318
+ if (index + 1) % 10 == 0:
319
+ print(f" پردازش سطر {index + 1}/{len(df)}...")
320
+
321
+ try:
322
+ metrics = self.evaluate_single_row(
323
+ str(row[reference_col]),
324
+ str(row[predicted_col])
325
+ )
326
+ results.append(metrics)
327
+ except Exception as e:
328
+ print(f"⚠️ خطا در سطر {index + 1}: {str(e)}")
329
+ # افزودن نتایج صفر برای این سطر
330
+ results.append({
331
+ 'seqeval_precision': 0.0,
332
+ 'seqeval_recall': 0.0,
333
+ 'seqeval_f1': 0.0,
334
+ 'seqeval_accuracy': 0.0,
335
+ 'exact_precision': 0.0,
336
+ 'exact_recall': 0.0,
337
+ 'exact_f1': 0.0,
338
+ 'tp_count': 0,
339
+ 'fp_count': 0,
340
+ 'fn_count': 0
341
+ })
342
+
343
+ print(f"✅ ارزیابی کامل شد!")
344
 
345
  # ایجاد DataFrame نتایج
346
  results_df = pd.DataFrame(results)
 
386
  • کل False Negatives: {total_fn}
387
  • تعداد سطرها: {len(df)}
388
 
389
+ 🔬 **مقایسه:**
390
+ • مرجع (انسانی): {reference_col}
391
+ • پیش‌بینی (LLM): {predicted_col}
392
+
393
+ 🔬 **مقایسه روش‌ها:**
394
  • F1 (seqeval): {avg_seqeval_f1:.4f}
395
  • F1 (Exact): {avg_exact_f1:.4f}
396
  • اختلاف: {abs(avg_seqeval_f1 - avg_exact_f1):.4f}
 
400
  return True, status, results_df
401
 
402
  except Exception as e:
403
+ import traceback
404
+ error_details = traceback.format_exc()
405
+ print(f"❌ خطا: {error_details}")
406
+ return False, f"❌ خطا در پردازش:\n\n{str(e)}\n\nجزئیات:\n{error_details[:500]}", pd.DataFrame()
407
 
408
  def generate_report(self, df: pd.DataFrame) -> str:
409
  """
 
435
 
436
  # تفسیر نتایج
437
  if avg_seqeval_f1 >= 0.9:
438
+ interpretation = "✅ عملکرد عالی - سیستم LLM شما بسیار دقیق است"
439
  elif avg_seqeval_f1 >= 0.7:
440
  interpretation = "⚠️ عملکرد خوب - اما قابل بهبود"
441
  else:
442
+ interpretation = "❌ عملکرد ضعیف - نیاز به بهبود اساسی در مدل LLM"
443
 
444
  report = f"""
445
  ## 📊 گزارش جامع ارزیابی NER
 
450
  ### 📈 آمار کلی:
451
  - **تعداد کل سطرها:** {total_rows}
452
  - **روش ارزیابی:** IOB2 Tagging (استاندارد CoNLL-2003)
453
+ - **مقایسه:** مرجع انسانی (Reference_text) vs پیش‌بینی LLM (anonymized_text)
454
 
455
  ### ✅ نتایج seqeval (استاندارد):
456
  - **میانگین Precision:** {avg_seqeval_p:.4f}
 
468
  - **بدترین F1:** {df.loc[worst_idx, 'seqeval_f1']:.4f} (سطر {worst_idx + 1})
469
 
470
  ### 💡 توصیه‌ها:
471
+ {"- مدل LLM شما عملکرد بسیار خوبی دارد" if avg_seqeval_f1 >= 0.9 else ""}
472
+ {"- روی بهبود Precision تمرکز کنید (کاهش False Positives)" if avg_seqeval_p < avg_seqeval_r else ""}
473
+ {"- روی بهبود Recall تمرکز کنید (کاهش False Negatives)" if avg_seqeval_r < avg_seqeval_p else ""}
474
+ {"- نیاز به بازنگری اساسی در prompt یا fine-tuning مدل LLM دارید" if avg_seqeval_f1 < 0.5 else ""}
475
  """
476
 
477
  return report
478
 
479
+ def create_downloadable_csv(self) -> str:
480
  """
481
  ایجاد فایل CSV برای دانلود
482
 
483
  Returns:
484
+ مسیر فایل موقت
485
  """
486
  if self.results_df is None or self.results_df.empty:
487
  return None
488
 
489
  try:
490
+ # ایجاد فایل موقت
491
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
492
+ temp_filename = f"evaluation_results_{timestamp}.csv"
493
+ temp_path = os.path.join(tempfile.gettempdir(), temp_filename)
494
+
495
+ # ذخیره DataFrame
496
+ self.results_df.to_csv(temp_path, index=False, encoding='utf-8-sig')
497
+
498
+ print(f"✅ فایل CSV ایجاد شد: {temp_path}")
499
+ return temp_path
500
+
501
  except Exception as e:
502
+ print(f"خطا در ایجاد CSV: {str(e)}")
503
  return None
504
 
505
 
 
541
  border-radius: 5px;
542
  margin: 10px 0;
543
  }
 
 
 
 
 
 
 
 
544
  """
545
 
546
  # ساخت Interface
 
554
  ) as demo:
555
 
556
  # هدر
557
+ gr.Markdown(f"""
558
+ <div class="header-box">
559
+ <h1 style="margin:0; text-align:center;">🎯 ابزار ارزیابی استاندارد NER</h1>
560
+ <p style="margin:5px 0 0 0; text-align:center;">
561
+ Named Entity Recognition Evaluation Tool
562
+ </p>
563
+ </div>
564
+ """)
 
565
 
566
  # وضعیت seqeval
567
+ gr.Markdown(f"""
568
+ <div class="status-box rtl">
569
+ <strong>وضعیت seqeval:</strong> {seqeval_emoji} {seqeval_status}
570
+ <br>
571
+ <small>این ابزار مرجع انسانی (Reference_text) را با خروجی LLM (anonymized_text) مقایسه می‌کند.</small>
572
+ </div>
573
+ """)
 
574
 
575
  # بخش اصلی
576
  with gr.Row():
 
579
  gr.Markdown("### 📁 بارگذاری فایل", elem_classes=["rtl"])
580
 
581
  file_input = gr.File(
582
+ label="فایل CSV (3 ستون)",
583
  file_types=[".csv"],
584
  type="filepath"
585
  )
586
 
587
  gr.Markdown("""
588
  <div class="rtl" style="font-size:0.9em; color:#666;">
589
+ فایل باید شامل سه ستون باشد:<br>
590
+ • <code>original_text</code> - متن خام<br>
591
+ • <code>Reference_text</code> - ناشناس‌سازی انسانی (مرجع)<br>
592
+ • <code>anonymized_text</code> - ناشناس‌سازی LLM (پیش‌بینی)
593
  </div>
594
  """)
595
 
 
599
  size="lg"
600
  )
601
 
602
+ download_btn = gr.Button(
603
+ "💾 دانلود نتایج CSV",
604
  visible=False,
605
  variant="secondary"
606
  )
 
608
  # ستون راست: وضعیت
609
  with gr.Column(scale=2):
610
  status_output = gr.Markdown(
611
+ "آماده دریافت فایل CSV با 3 ستون (original_text, Reference_text, anonymized_text)...",
612
  elem_classes=["rtl"]
613
  )
614
 
 
625
  wrap=True
626
  )
627
 
628
+ # فایل دانلود
629
+ download_file = gr.File(
630
+ visible=False,
631
+ label="فایل نتایج"
632
+ )
633
+
634
  # راهنما
635
  with gr.Accordion("📖 راهنمای استفاده", open=False):
636
  gr.Markdown("""
637
  <div class="rtl">
638
 
639
+ ## 🎯 ساختار فایل CSV:
640
 
641
+ فایل شما باید **3 ستون** داشته باشد:
 
 
642
 
643
  ```csv
644
+ original_text,Reference_text,anonymized_text
645
+ "شرکت فولاد با درآمد 500 میلیارد","شرکت company-01 با درآمد amount-02 میلیارد","شرکت company-01 با درآمد amount-03 میلیارد"
 
 
646
  ```
647
 
648
+ ### توضیح ستون‌ها:
649
 
650
+ 1. **original_text**: متن اصلی و خام (بدون ناشناس‌سازی)
651
+ 2. **Reference_text**: متن ناشناس‌سازی شده توسط انسان - **این مرجع (Gold Standard) است**
652
+ 3. **anonymized_text**: متن ناشناس‌سازی شده توسط مدل LLM شما - **این پیش‌بینی است**
653
 
654
+ ### نحوه ارزیابی:
 
 
655
 
656
+ ابزار **Reference_text** را به عنوان جواب صحیح در نظر می‌گیرد و **anonymized_text** را با آن مقایسه می‌کند.
 
 
657
 
658
+ ### 2. فرمت‌های پشتیبانی شده:
 
659
 
660
+ - `company-01`, `COMPANY-01`, `COMPANY_001_REGEX`
661
+ - `person-02`, `PERSON-02`, `PERSON_002_REGEX`
662
+ - `amount-03`, `AMOUNT-03`
663
+ - `percent-04`, `PERCENT-04`
664
  - `group-05`, `GROUP-05`
 
 
665
  - `stock-06`, `STOCK-06`
 
666
 
667
  ### 3. معیارهای ارزیابی:
668
 
669
+ - **Precision**: از entities که LLM شناسایی کرده، چند درصد درست بودند؟
670
+ - **Recall**: از entities مرجع، چند درصد توسط LLM پیدا شدند؟
671
  - **F1-Score**: میانگین هماهنگ Precision و Recall
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
672
 
673
  </div>
674
  """)
 
688
 
689
  Made with ❤️ for Persian NLP Community
690
 
691
+ <small>Version 1.0.1</small>
692
 
693
  </div>
694
  """)
 
702
  "❌ لطفاً فایل CSV را بارگذاری کنید",
703
  gr.Markdown(visible=False),
704
  gr.Dataframe(visible=False),
705
+ gr.Button(visible=False),
706
+ gr.File(visible=False)
707
  )
708
 
709
  try:
710
+ print(f"\n{'='*60}")
711
+ print(f"شروع ارزیابی فایل: {file}")
712
+ print(f"{'='*60}\n")
713
+
714
  # ارزیابی
715
  success, message, df = evaluator.evaluate_dataset(file)
716
 
717
  if not success:
718
+ print(f"❌ ارزیابی ناموفق: {message}")
719
  return (
720
  f"❌ {message}",
721
  gr.Markdown(visible=False),
722
  gr.Dataframe(visible=False),
723
+ gr.Button(visible=False),
724
+ gr.File(visible=False)
725
  )
726
 
727
+ print(f"✅ ارزیابی موفق!")
728
+
729
  # تولید گزارش
730
  summary = evaluator.generate_report(df)
731
 
 
 
 
732
  # نمایش نتایج
733
  return (
734
  message,
735
  gr.Markdown(value=summary, visible=True),
736
  gr.Dataframe(value=df.head(10), visible=True),
737
+ gr.Button(visible=True),
738
+ gr.File(visible=False)
 
 
 
739
  )
740
 
741
  except Exception as e:
742
+ import traceback
743
+ error_details = traceback.format_exc()
744
+ print(f"❌ خطای غیرمنتظره:\n{error_details}")
745
  return (
746
+ f"❌ خطای غیرمنتظره:\n\n{str(e)}\n\nلطفاً فایل CSV را بررسی کنید.",
747
  gr.Markdown(visible=False),
748
  gr.Dataframe(visible=False),
749
+ gr.Button(visible=False),
750
+ gr.File(visible=False)
751
+ )
752
+
753
+ def download_results():
754
+ """تابع دانلود نتایج"""
755
+ try:
756
+ csv_path = evaluator.create_downloadable_csv()
757
+
758
+ if csv_path and os.path.exists(csv_path):
759
+ return (
760
+ "✅ فایل نتایج آماده دانلود است",
761
+ gr.File(value=csv_path, visible=True)
762
+ )
763
+ else:
764
+ return (
765
+ "❌ خطا در ایجاد فایل نتایج",
766
+ gr.File(visible=False)
767
+ )
768
+ except Exception as e:
769
+ return (
770
+ f"❌ خطا: {str(e)}",
771
+ gr.File(visible=False)
772
  )
773
 
774
+ # اتصال event ها
775
  evaluate_btn.click(
776
  fn=evaluate_file,
777
  inputs=[file_input],
778
+ outputs=[status_output, summary_output, results_table, download_btn, download_file]
779
+ )
780
+
781
+ download_btn.click(
782
+ fn=download_results,
783
+ outputs=[status_output, download_file]
784
  )
785
 
786
  return demo
 
788
 
789
  # ==================== Main ====================
790
  if __name__ == "__main__":
791
+ print("="*60)
792
+ print("🎯 NER Anonymization Evaluator")
793
+ print("="*60)
794
+ print(f"seqeval available: {SEQEVAL_AVAILABLE}")
795
+ print("="*60)
796
+
797
  # ایجاد و اجرای interface
798
  demo = create_interface()
799
  demo.launch(
800
  server_name="0.0.0.0",
801
  server_port=7860,
802
  share=False
803
+ )