leilaghomashchi commited on
Commit
6799ed0
·
verified ·
1 Parent(s): af857d7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +124 -224
app.py CHANGED
@@ -11,10 +11,10 @@ class CerebrasConfig:
11
  """تنظیمات Cerebras API برای Qwen 3-32B"""
12
  api_key: str
13
  base_url: str = "https://api.cerebras.ai/v1"
14
- model: str = "qwen-3-32b" # مدل Qwen 3-32B (سرعت 2,400 t/s)
15
- max_tokens: int = 2000
16
- temperature: float = 0.6 # توصیه شده برای Qwen (0.6)
17
- top_p: float = 0.95 # توصیه شده برای Qwen
18
 
19
  class AdvancedCerebrasAnonymizer:
20
  """سیستم پیشرفته ناشناس‌سازی متون مالی/خبری فارسی با Qwen 3-32B"""
@@ -29,8 +29,10 @@ class AdvancedCerebrasAnonymizer:
29
  self.system_prompt = self._create_advanced_system_prompt()
30
 
31
  def _create_advanced_system_prompt(self) -> str:
32
- """ایجاد دستورالعمل سیستمی فشرده برای Qwen 3-32B"""
33
- return """شما متن‌های مالی فارسی را ناشناس می‌کنید. اسامی خاص و اعداد را با شناسه جایگزین کنید.
 
 
34
 
35
  ## قوانین اندیس‌گذاری:
36
  1. **ترتیب پیوسته**: company-01, company-02, ... | person-01, person-02, ... | amount-01, amount-02, ... | percent-01, percent-02, ...
@@ -39,60 +41,35 @@ class AdvancedCerebrasAnonymizer:
39
  4. **اشاره ضمنی**: "این شرکت" اگر به company-01 اشاره دارد → company-01 (نه company-02)
40
 
41
  ## انواع موجودیت:
42
- - **company-XX**: شرکت‌ها، بانک‌ها، سازمان‌ها، گروه‌ها (⚠️ "گروه X" = company نه group)
43
- - **person-XX**: نام و نام خانوادگی اشخاص
44
- - **amount-XX**: مبالغ (تومان، ریال، همت، دلار، تن، دستگاه) - واحد را حفظ کن
45
- - **percent-XX**: درصدها و نسبت‌ها
46
-
47
- ## ⚠️ قوانین کلیدی:
48
- 1. **بازرس = شرکت است**: "بازرس قانونی" → company-XX (نه person)
49
- 2. **واحدها**: "amount-01 میلیارد تومان" ✅ | "amount-01" ❌
50
- 3. **گروه‌ها**: "گروه مالی صبا" → company-XX (نه group-XX)
51
- 4. **کلمات عمومی حفظ**: "سه شرکت"، "چند بانک"، "مراکز درمانی" → حفظ (موجودیت نیستند)
52
- 5. **دوره زمانی حفظ**: "۵ ماهه"، "۹ ماهه اول" → حفظ (نه amount)
53
- 6. **بازه = یک entity**: "یک تا 1.5 میلیون" → amount-01
54
- 7. **شماره ثبت حفظ**: "شماره 11385" → حفظ (نه amount)
55
- 8. **نهادهای عمومی حفظ**: "مرجع ثبت شرکتها"، "هیئت مجلس" → حفظ
56
-
57
- ## موارد حفظ شده:
58
- تاریخ، فصل (پاییز)، عناوین شغلی، مکان‌ها، کلمات عمومی بدون نام خاص، دوره‌های زمانی (۹ ماهه)
59
-
60
- ## مثال‌های کلیدی:
61
-
62
- **مثال 1:**
63
- ورودی: مهدی اخوان، مدیرعامل همراه اول، اعلام کرد درآمد با رشد 37 درصدی به 677 میلیارد تومان رسید. سود تلفیگی گروه همراه اول 8003 میلیارد شد.
64
- خروجی: person-01، مدیرعامل company-01، اعلام کرد درآمد با رشد percent-01 به amount-01 رسید. سود تلفیگی company-01 amount-02 شد.
65
 
66
- **مثال 2:**
67
- ورودی: فولاد مبارکه اصفهان با ملی نفت قرارداد امضا کرد. فاما سرمایه را از 8700 به 12500 میلیارد افزایش می‌دهد.
68
- خروجی: company-01 با company-02 قرارداد امضا کرد. company-01 سرمایه را از amount-01 به amount-02 افزایش می‌دهد.
 
 
 
 
69
 
70
- **مثال 3:**
71
- ورودی: مجمع پتروشیمی بوعلی سینا برگزار شد. وانیا نیک تدبیر را بازرس قانونی و تدوین و همکاران را بازرس علی‌البدل انتخاب کردند.
72
- خروجی: مجمع company-01 برگزار شد. company-02 را بازرس قانونی و company-03 را بازرس علی‌البدل انتخاب کردند.
73
 
74
- **مثال 4:**
75
- ورودی: همراه اول در ۹ ماه سال 49 هزار میلیارد درآمد کسب کرد. عملکرد ۵ ماهه رشد 37 درصدی داشت.
76
- خروجی: company-01 در ۹ ماه سال amount-01 درآمد کسب کرد. عملکرد ۵ ماهه رشد percent-01 داشت.
77
-
78
- **مثال 5:**
79
- ورودی: پالایش نفت اصفهان EPS آن به 2500 ریال می‌رسد. این شرکت یکی از بزرگ‌ترین پالایشگاه‌ها است.
80
- خروجی: company-01 EPS آن به amount-01 می‌رسد. این شرکت یکی از بزرگ‌ترین پالایشگاه‌ها است.
81
- ⚠️ "این شرکت" = company-01 (نه company-02)
82
-
83
- **مثال 6:**
84
- ورودی: سازمان تامین اجتماعی دارای سه شرکت دارویی است که از مراکز درمانی وزارت بهداشت مطالبات دارند.
85
- خروجی: company-01 دارای سه شرکت دارویی است که از مراکز درمانی company-02 مطالبات دارند.
86
-
87
- فقط متن ناشناس‌شده را برگردان، بدون توضیح."""
88
 
89
  def _make_api_request(self, text: str) -> Dict[str, Any]:
90
- """ارسال درخواست به Cerebras API با پارامترهای بهینه Qwen"""
91
  headers = {
92
  "Authorization": f"Bearer {self.config.api_key}",
93
  "Content-Type": "application/json"
94
  }
95
 
 
 
 
96
  payload = {
97
  "messages": [
98
  {
@@ -101,7 +78,7 @@ class AdvancedCerebrasAnonymizer:
101
  },
102
  {
103
  "role": "user",
104
- "content": text
105
  }
106
  ],
107
  "model": self.config.model,
@@ -115,7 +92,7 @@ class AdvancedCerebrasAnonymizer:
115
  f"{self.config.base_url}/chat/completions",
116
  headers=headers,
117
  json=payload,
118
- timeout=60 # افزایش timeout برای Qwen 32B
119
  )
120
  response.raise_for_status()
121
  return response.json()
@@ -142,12 +119,18 @@ class AdvancedCerebrasAnonymizer:
142
 
143
  content = response["choices"][0]["message"]["content"]
144
 
 
 
 
145
  # پاک کردن markdown اگر وجود دارد
146
  content = self._clean_markdown(content)
147
 
148
  # حذف خطوط اضافی و فضاهای خالی
149
  content = content.strip()
150
 
 
 
 
151
  # تحلیل نتایج
152
  analysis = self._analyze_anonymized_text(content)
153
 
@@ -167,6 +150,16 @@ class AdvancedCerebrasAnonymizer:
167
  "error": f"خطا در پردازش: {str(e)}"
168
  }
169
 
 
 
 
 
 
 
 
 
 
 
170
  def _clean_markdown(self, content: str) -> str:
171
  """پاک کردن markdown از پاسخ"""
172
  if "```" in content:
@@ -182,6 +175,19 @@ class AdvancedCerebrasAnonymizer:
182
  content = '\n'.join(clean_lines)
183
  return content
184
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  def _analyze_anonymized_text(self, text: str) -> Dict[str, Any]:
186
  """تحلیل متن ناشناس‌سازی شده"""
187
  import re
@@ -270,13 +276,14 @@ class AdvancedCerebrasAnonymizer:
270
  }
271
  }
272
 
 
 
 
273
  def create_advanced_interface():
274
  """ایجاد رابط کاربری پیشرفته"""
275
 
276
- # بررسی وجود کلید API
277
  api_key_available = bool(os.getenv("CEREBRAS_API_KEY"))
278
 
279
- # CSS سفارشی پیشرفته
280
  custom_css = """
281
  .gradio-container {
282
  font-family: 'Tahoma', 'Arial', sans-serif !important;
@@ -348,23 +355,19 @@ def create_advanced_interface():
348
 
349
  with gr.Blocks(css=custom_css, title="ناشناس‌ساز پیشرفته با Qwen 3-32B", theme=gr.themes.Soft()) as interface:
350
 
351
- # عنوان
352
  gr.Markdown("""
353
  # 🔒 سیستم پیشرفته ناشناس‌سازی متون مالی/خبری فارسی
354
- ### ⚡ قدرت‌گرفته از Cerebras AI - سریع‌ترین استنباط در جهان
355
  """)
356
 
357
- # نمایش اطلاعات مدل Qwen
358
  gr.Markdown("""
359
  <div class="qwen-box">
360
- 🚀 <strong>مدل: Alibaba Qwen 3-32B</strong><br>
361
- ⚡ سرعت: 2,400 توکن در ثانیه | 🧠 قدرت: 32 میلیارد پارامتر<br>
362
- 💰 قیمت: $0.40/M input, $0.80/M output | 📝 Context: 128K tokens<br>
363
- 🎯 مدل Reasoning هیبریدی با دقت بالا
364
  </div>
365
  """)
366
 
367
- # نمایش وضعیت API
368
  if api_key_available:
369
  gr.Markdown("""
370
  <div class="success-box">
@@ -376,7 +379,7 @@ def create_advanced_interface():
376
  gr.Markdown("""
377
  <div class="warning-box">
378
  ⚠️ <strong>کلید API تنظیم نشده</strong><br>
379
- لطفاً کلید Cerebras API خود را در زیر وارد کنید (از https://cloud.cerebras.ai دریافت کنید)
380
  </div>
381
  """)
382
  api_key_input = gr.Textbox(
@@ -396,7 +399,7 @@ def create_advanced_interface():
396
 
397
  with gr.Row():
398
  anonymize_btn = gr.Button(
399
- "🔒 ناشناس‌سازی با Qwen 3-32B",
400
  variant="primary",
401
  size="lg"
402
  )
@@ -413,23 +416,19 @@ def create_advanced_interface():
413
  elem_classes=["result-box"]
414
  )
415
 
416
- # دکمه کپی
417
  copy_btn = gr.Button(
418
  "📋 کپی متن",
419
  variant="secondary",
420
  size="sm"
421
  )
422
 
423
- # متن برای کپی
424
  copy_output = gr.Textbox(
425
- label="📋 متن برای کپی (Ctrl+A و Ctrl+C)",
426
  lines=3,
427
- max_lines=10,
428
  visible=False,
429
  interactive=True
430
  )
431
 
432
- # نمایش آمار پیشرفته
433
  with gr.Row():
434
  with gr.Column():
435
  statistics_output = gr.Markdown(label="📊 آمار کلی")
@@ -438,19 +437,17 @@ def create_advanced_interface():
438
 
439
  with gr.Row():
440
  with gr.Column():
441
- entities_output = gr.Markdown(label="🏷️ موجودیت‌های شناسایی شده")
442
  with gr.Column():
443
  detailed_analysis_output = gr.Markdown(label="🔍 تحلیل دقیق")
444
 
445
  usage_output = gr.Markdown(label="⚡ اطلاعات پردازش")
446
 
447
  def process_advanced_text(text: str, api_key_manual: str = ""):
448
- """پردازش پیشرفته متن با Qwen 3-32B"""
449
- # حل مشکل NoneType
450
  if api_key_manual is None:
451
  api_key_manual = ""
452
 
453
- # تعیین کلید API
454
  final_api_key = ""
455
  if api_key_manual and api_key_manual.strip():
456
  final_api_key = api_key_manual.strip()
@@ -458,124 +455,72 @@ def create_advanced_interface():
458
  final_api_key = os.getenv("CEREBRAS_API_KEY")
459
 
460
  if not final_api_key:
461
- return (
462
- "",
463
- "❌ کلید API وارد نشده است",
464
- "",
465
- "",
466
- "",
467
- ""
468
- )
469
 
470
  if not text or not text.strip():
471
- return (
472
- "",
473
- "❌ لطفاً متن ورودی را وارد کنید",
474
- "",
475
- "",
476
- "",
477
- ""
478
- )
479
 
480
  try:
481
  anonymizer = AdvancedCerebrasAnonymizer(api_key=final_api_key)
482
  result = anonymizer.anonymize_text(text)
483
 
484
  if not result["success"]:
485
- return (
486
- "",
487
- f"❌ خطا: {result['error']}",
488
- "",
489
- "",
490
- "",
491
- ""
492
- )
493
 
494
- # آمار کلی
495
  stats = result.get("statistics", {})
496
- stats_md = "📊 **آمار کلی:**\n\n"
497
-
498
- stats_md += f"""
499
- <div class="stats-grid">
500
- <div class="stat-card">
501
- <h3>🏢 شرکت‌ها</h3>
502
- <h2>{stats.get('company', 0)}</h2>
503
- <small>(شامل گروه‌ها)</small>
504
- </div>
505
- <div class="stat-card">
506
- <h3>👤 اشخاص</h3>
507
- <h2>{stats.get('person', 0)}</h2>
508
- </div>
509
- <div class="stat-card">
510
- <h3>💰 مبالغ</h3>
511
- <h2>{stats.get('amount', 0)}</h2>
512
- </div>
513
- <div class="stat-card">
514
- <h3>📊 درصدها</h3>
515
- <h2>{stats.get('percent', 0)}</h2>
516
- </div>
517
- <div class="stat-card">
518
- <h3>🔢 کل تغییرات</h3>
519
- <h2>{stats.get('total_replacements', 0)}</h2>
520
- </div>
521
- </div>
522
- """
523
 
524
- # کنترل کیفیت
525
  quality = result.get("quality_check", {})
526
  quality_md = "✅ **کنترل کیفیت:**\n\n"
527
 
528
  if quality.get("is_valid", False):
529
- quality_md += '<span class="quality-badge quality-pass">✅ تمام بررسی‌ها موفق</span>\n\n'
530
  else:
531
- quality_md += '<span class="quality-badge quality-fail">❌ مشکلاتی یافت شد</span>\n\n'
532
  issues = quality.get("issues", [])
533
  if issues:
534
  quality_md += "**مشکلات:**\n"
535
  for issue in issues:
536
  quality_md += f"• {issue}\n"
537
 
538
- entity_counts = quality.get("entity_counts", {})
539
- if entity_counts:
540
- quality_md += f"\n**تعداد موجودیت‌های منحصربه‌فرد:**\n"
541
- for entity_type, count in entity_counts.items():
542
- if count > 0:
543
- quality_md += f"• {entity_type}: {count}\n"
544
-
545
- # موجودیت‌های شناسایی شده
546
  entities = result.get("entities", {})
547
- entities_md = "🏷️ **موجودیت‌های شناسایی شده:**\n\n"
548
 
549
  if entities.get("companies"):
550
- entities_md += f"🏢 **شرکت‌ها (شامل گروه‌ها):** company-{', company-'.join(entities['companies'])}\n\n"
551
  if entities.get("persons"):
552
- entities_md += f"👤 **اشخاص:** person-{', person-'.join(entities['persons'])}\n\n"
553
  if entities.get("amounts"):
554
- entities_md += f"💰 **مبالغ:** amount-{', amount-'.join(entities['amounts'])}\n\n"
555
  if entities.get("percents"):
556
- entities_md += f"📊 **درصدها:** percent-{', percent-'.join(entities['percents'])}\n\n"
557
 
558
- # تحلیل دقیق
559
  detailed = result.get("detailed_analysis", {})
560
- detailed_md = "🔍 **تحلیل دقیق:**\n\n"
561
- detailed_md += f"📅 **تاریخ‌های حفظ شده:** {detailed.get('preserved_dates', 0)}\n"
562
- detailed_md += f"🕐 **ساعت‌های حفظ شده:** {detailed.get('preserved_times', 0)}\n"
563
- detailed_md += f"📈 **شاخص‌های مالی:** {detailed.get('financial_indicators', 0)}\n"
564
- detailed_md += f"📏 **واحدهای حفظ شده:** {detailed.get('units_preserved', 0)}\n"
 
565
 
566
- # اطلاعات پردازش
567
  usage = result.get("usage", {})
568
- usage_md = "⚡ **اطلاعات پردازش Cerebras (Qwen 3-32B):**\n\n"
569
- if usage:
570
- usage_md += f"🤖 **مدل:** {anonymizer.config.model}\n"
571
- usage_md += f"🌡️ **Temperature:** {anonymizer.config.temperature}\n"
572
- usage_md += f"🎲 **Top-P:** {anonymizer.config.top_p}\n"
573
- usage_md += f"📥 **Token های ورودی:** {usage.get('prompt_tokens', 'نامشخص')}\n"
574
- usage_md += f"📤 **Token های خروجی:** {usage.get('completion_tokens', 'نامشخص')}\n"
575
- usage_md += f"📊 **کل Token ها:** {usage.get('total_tokens', 'نامشخص')}\n"
576
- usage_md += f"\n⚡ **سرعت Qwen 3-32B: 2,400 tokens/second - فوق‌العاده سریع!**"
577
- else:
578
- usage_md += "✅ پردازش با موفقیت انجام شد"
579
 
580
  return (
581
  result["anonymized_text"],
@@ -587,27 +532,16 @@ def create_advanced_interface():
587
  )
588
 
589
  except Exception as e:
590
- return (
591
- "",
592
- f"❌ خطایی غیرمنتظره: {str(e)}",
593
- "",
594
- "",
595
- "",
596
- ""
597
- )
598
 
599
  def copy_text(text_to_copy):
600
- """تابع کپی متن"""
601
  if not text_to_copy or not text_to_copy.strip():
602
- return gr.Textbox(visible=False), "⚠️ متنی برای کپی وجود ندارد"
603
-
604
- return gr.Textbox(value=text_to_copy, visible=True), "✅ متن در کادر زیر آماده کپی است"
605
 
606
  def clear_all():
607
- """پاک کردن تمام فیلدها"""
608
  return "", "", "", "", "", "", "", gr.Textbox(visible=False)
609
 
610
- # اتصال رویدادها
611
  anonymize_btn.click(
612
  fn=process_advanced_text,
613
  inputs=[input_text, api_key_input],
@@ -625,69 +559,35 @@ def create_advanced_interface():
625
  outputs=[input_text, output_text, statistics_output, quality_output, entities_output, detailed_analysis_output, usage_output, copy_output]
626
  )
627
 
628
- # مثال‌های پیشرفته
629
  gr.Examples(
630
  examples=[
631
- ["مجمع عمومی عادی سالیانه شرکت پتروشیمی بوعلی سینا برگزار شد. شرکت وانیا نیک تدبیر را به‌ عنوان بازرس قانونی و حسابرس انتخاب کردند. هزینه لجستیکی بوعلی حدود 100 میلیون دلار بوده و حدود 40 درصد خوراک از طریق خط لوله و 60 درصد باقی‌مانده معادل یک تا 1.5 میلیون تن در سال تهیه می‌شود."],
632
- ["تحلیل صورت‌های مالی شرکت پالایش نفت اصفهان در سال 1403 این احتمال را مطرح می‌کند که EPS این شرکت در سال مالی 1404 به 2500 ریال برسد. این شرکت به‌عنوان یکی از بزرگ‌ترین پالایشگاه‌های کشور فعالیت می‌کند."],
633
- ["سازمان تامین اجتماعی دارای سه شرکت دارویی است که از مراکز درمانی وابسته به وزارت بهداشت مطالباتی دارند."],
634
- ["براساس آخرین گزارش سازمان تنظیم مقررات رادیویی در پاییز ۱۴۰۱ تعداد مشترکین تلفن همراه در ایران به بالای ۱۴۵ میلیون نفر رسیده که نسبت به سال گذشته حدود ۷.۲ درصد رشد داشته است."],
635
- ["شرکت فولاد مبارکه اصفهان با همکاری شرکت ملی نفت ایران، قرارداد توسعه میدان گازی مدار را امضا کرد. شرکت فاما قصد دارد سرمایه خود را از ۸،۷۰۰ میلیارد ریال به ۱۲،۵۰۰ میلیارد ریال افزایش دهد."],
636
- ["صورت‌های مالی سه خودروساز بزرگ کشور نشان می‌دهد که زیان انباشته تلفیقی خودروسازان از مرز 500 همت عبور کرده و به 620 همت رسیده است."]
637
  ],
638
  inputs=input_text,
639
- label="📚 مثال‌های پیشرفته آزمایشی"
640
  )
641
 
642
- # راهنمای کامل
643
- with gr.Accordion("📖 راهنمای کامل استفاده", open=False):
644
  gr.Markdown("""
645
- ## 🎯 ویژگی‌های سیستم با Qwen 3-32B:
646
-
647
- ### 🚀 مزایای Qwen 3-32B:
648
- - **سرعت فوق‌العاده:** 2,400 tokens/second
649
- - **دقت بالا:** 32 میلیارد پارامتر
650
- - **Context بزرگ:** 128K tokens
651
- - **مدل Reasoning:** قابلیت استدلال پیشرفته
652
- - **قیمت مناسب:** $0.40/M input, $0.80/M output
653
- - **پشتیبانی عالی از فارسی:** به عنوان یکی از مدل‌های قدرتمند چندزبانه
654
-
655
- ### ⚙️ پارامترهای بهینه شده:
656
- - **Temperature:** 0.6 (توصیه شده برای Qwen)
657
- - **Top-P:** 0.95 (برای تنوع و دقت بهتر)
658
- - **Max Tokens:** 2000
659
 
660
- ### 🏷️ انواع برچسب‌ها:
661
- - **company-XX:** شرکت‌ها، سازمان‌ها، گروه‌ها
662
- - ⚠️ "گروه همراه اول" = company-XX (نه group-XX)
663
- - ⚠️ "فاما" = "فولاد مبارکه" = company-01
664
- - **person-XX:** اشخاص حقیقی
665
- - **amount-XX:** مبالغ (با حفظ واحد)
666
- - **percent-XX:** درصدها
667
 
668
- ### موارد حفظ شده:
669
- - تاریخ‌ها، فصل‌ها، مکان‌ها
670
- - عناوین شغلی و واحدها
671
- - شاخص‌های مالی (EPS, P/E, etc.)
672
- - کلمات عمومی ("سه شرکت"، "چند بانک")
673
- - دوره‌های زمانی ("۹ ماهه"، "۵ ماهه سال")
674
-
675
- ### 💡 نکات مهم:
676
- - Qwen 3-32B دقت بالاتری نسبت به Llama 3.1-8B دارد
677
- - مدل Reasoning برای تحلیل پیچیده بهتر است
678
- - سرعت 2,400 t/s یعنی پاسخ تقریباً لحظه‌ای
679
- - برای متون طولانی‌تر (تا 128K tokens) مناسب است
680
-
681
- ### 🔧 مدل‌های جایگزین Cerebras:
682
- qwen-3-32b # فعلی ⭐ (توصیه می‌شود)
683
- qwen-3-235b-a22b-instruct-2507 # قدرتمندتر اما گران‌تر
684
- llama3.1-8b # سریع‌تر اما ضعیف‌تر
685
- llama3.3-70b # تعادل خوب
686
- """)
687
 
688
  return interface
689
 
690
- # اجرای برنامه
691
  if __name__ == "__main__":
692
  interface = create_advanced_interface()
693
  interface.launch(
 
11
  """تنظیمات Cerebras API برای Qwen 3-32B"""
12
  api_key: str
13
  base_url: str = "https://api.cerebras.ai/v1"
14
+ model: str = "qwen-3-32b"
15
+ max_tokens: int = 3000 # افزایش برای thinking tokens
16
+ temperature: float = 0.3 # کاهش برای دقت بیشتر
17
+ top_p: float = 0.9
18
 
19
  class AdvancedCerebrasAnonymizer:
20
  """سیستم پیشرفته ناشناس‌سازی متون مالی/خبری فارسی با Qwen 3-32B"""
 
29
  self.system_prompt = self._create_advanced_system_prompt()
30
 
31
  def _create_advanced_system_prompt(self) -> str:
32
+ """ایجاد دستورالعمل سیستمی بهینه شده"""
33
+ return """شما یک سیستم ناشناس‌سازی متون مالی فارسی هستید.
34
+
35
+ ⚠️ CRITICAL: در پاسخ نهایی خود، فقط و فقط متن ناشناس‌سازی شده را برگردانید، بدون هیچ توضیح، تحلیل، یا تگ اضافی.
36
 
37
  ## قوانین اندیس‌گذاری:
38
  1. **ترتیب پیوسته**: company-01, company-02, ... | person-01, person-02, ... | amount-01, amount-02, ... | percent-01, percent-02, ...
 
41
  4. **اشاره ضمنی**: "این شرکت" اگر به company-01 اشاره دارد → company-01 (نه company-02)
42
 
43
  ## انواع موجودیت:
44
+ - **company-XX**: شرکت‌ها، بانک‌ها، سازمان‌ها، گروه‌ها
45
+ - **person-XX**: نام و نام خانوادگی اشخاص
46
+ - **amount-XX**: مبالغ - واحد را حفظ کن
47
+ - **percent-XX**: درصدها
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
+ ## قوانین کلیدی:
50
+ 1. بازرس = شرکت است company-XX
51
+ 2. واحدها: "amount-01 میلیارد تومان"
52
+ 3. گروه‌ها: "گروه X" → company-XX
53
+ 4. کلمات عمومی حفظ: "سه شرکت" → حفظ
54
+ 5. دوره زمانی حفظ: "۵ ماهه" → حفظ
55
+ 6. بازه = یک entity: "یک تا 1.5 میلیون" → amount-01
56
 
57
+ ## مثال:
58
+ ورودی: ایران خودرو در اسفند 1402 حدود 23 هزار و 296 میلیارد درآمد کسب کرد که 4.58 درصد افزایش داشت.
59
+ خروجی: company-01 در اسفند 1402 حدود amount-01 درآمد کسب کرد که percent-01 افزایش داشت.
60
 
61
+ ⚠️ یادآوری: فقط متن ناشناس‌شده، بدون هیچ توضیح اضافی."""
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  def _make_api_request(self, text: str) -> Dict[str, Any]:
64
+ """ارسال درخواست به Cerebras API"""
65
  headers = {
66
  "Authorization": f"Bearer {self.config.api_key}",
67
  "Content-Type": "application/json"
68
  }
69
 
70
+ # اضافه کردن /no_think به متن برای غیرفعال کردن reasoning
71
+ user_content = f"{text}\n\n/no_think"
72
+
73
  payload = {
74
  "messages": [
75
  {
 
78
  },
79
  {
80
  "role": "user",
81
+ "content": user_content
82
  }
83
  ],
84
  "model": self.config.model,
 
92
  f"{self.config.base_url}/chat/completions",
93
  headers=headers,
94
  json=payload,
95
+ timeout=60
96
  )
97
  response.raise_for_status()
98
  return response.json()
 
119
 
120
  content = response["choices"][0]["message"]["content"]
121
 
122
+ # پاک کردن thinking tags اگر وجود دارد
123
+ content = self._remove_thinking_tags(content)
124
+
125
  # پاک کردن markdown اگر وجود دارد
126
  content = self._clean_markdown(content)
127
 
128
  # حذف خطوط اضافی و فضاهای خالی
129
  content = content.strip()
130
 
131
+ # حذف توضیحات اضافی در ابتدا یا انتها
132
+ content = self._clean_explanations(content)
133
+
134
  # تحلیل نتایج
135
  analysis = self._analyze_anonymized_text(content)
136
 
 
150
  "error": f"خطا در پردازش: {str(e)}"
151
  }
152
 
153
+ def _remove_thinking_tags(self, content: str) -> str:
154
+ """حذف تگ‌های thinking از خروجی"""
155
+ # حذف محتوای داخل <think>...</think>
156
+ content = re.sub(r'<think>.*?</think>', '', content, flags=re.DOTALL)
157
+
158
+ # حذف تگ‌های خالی
159
+ content = re.sub(r'</?think>', '', content)
160
+
161
+ return content.strip()
162
+
163
  def _clean_markdown(self, content: str) -> str:
164
  """پاک کردن markdown از پاسخ"""
165
  if "```" in content:
 
175
  content = '\n'.join(clean_lines)
176
  return content
177
 
178
+ def _clean_explanations(self, content: str) -> str:
179
+ """حذف توضیحات اضافی در ابتدا یا انتها"""
180
+ lines = content.split('\n')
181
+ clean_lines = []
182
+
183
+ for line in lines:
184
+ # حذف خطوطی که شامل توضیحات متا هستند
185
+ if any(word in line.lower() for word in ['okay', 'let me', 'here is', 'خروجی', 'نتیجه', 'پاسخ']):
186
+ continue
187
+ clean_lines.append(line)
188
+
189
+ return '\n'.join(clean_lines).strip()
190
+
191
  def _analyze_anonymized_text(self, text: str) -> Dict[str, Any]:
192
  """تحلیل متن ناشناس‌سازی شده"""
193
  import re
 
276
  }
277
  }
278
 
279
+ # باقی کد رابط کاربری همان قبل است...
280
+ # (تابع create_advanced_interface و بقیه کد تغییری ندارد)
281
+
282
  def create_advanced_interface():
283
  """ایجاد رابط کاربری پیشرفته"""
284
 
 
285
  api_key_available = bool(os.getenv("CEREBRAS_API_KEY"))
286
 
 
287
  custom_css = """
288
  .gradio-container {
289
  font-family: 'Tahoma', 'Arial', sans-serif !important;
 
355
 
356
  with gr.Blocks(css=custom_css, title="ناشناس‌ساز پیشرفته با Qwen 3-32B", theme=gr.themes.Soft()) as interface:
357
 
 
358
  gr.Markdown("""
359
  # 🔒 سیستم پیشرفته ناشناس‌سازی متون مالی/خبری فارسی
360
+ ### ⚡ قدرت‌گرفته از Cerebras AI + Alibaba Qwen 3-32B
361
  """)
362
 
 
363
  gr.Markdown("""
364
  <div class="qwen-box">
365
+ 🚀 <strong>مدل: Alibaba Qwen 3-32B (اصلاح شده)</strong><br>
366
+ ⚡ سرعت: 2,400 توکن/ثانیه | 🧠 32B پارامتر | 💰 $0.40/$0.80<br>
367
+ <strong>بهینه‌سازی شده:</strong> Thinking Mode غیرفعال برای خروجی مستقیم
 
368
  </div>
369
  """)
370
 
 
371
  if api_key_available:
372
  gr.Markdown("""
373
  <div class="success-box">
 
379
  gr.Markdown("""
380
  <div class="warning-box">
381
  ⚠️ <strong>کلید API تنظیم نشده</strong><br>
382
+ لطفاً کلید Cerebras API خود را وارد کنید
383
  </div>
384
  """)
385
  api_key_input = gr.Textbox(
 
399
 
400
  with gr.Row():
401
  anonymize_btn = gr.Button(
402
+ "🔒 ناشناس‌سازی",
403
  variant="primary",
404
  size="lg"
405
  )
 
416
  elem_classes=["result-box"]
417
  )
418
 
 
419
  copy_btn = gr.Button(
420
  "📋 کپی متن",
421
  variant="secondary",
422
  size="sm"
423
  )
424
 
 
425
  copy_output = gr.Textbox(
426
+ label="📋 متن برای کپی",
427
  lines=3,
 
428
  visible=False,
429
  interactive=True
430
  )
431
 
 
432
  with gr.Row():
433
  with gr.Column():
434
  statistics_output = gr.Markdown(label="📊 آمار کلی")
 
437
 
438
  with gr.Row():
439
  with gr.Column():
440
+ entities_output = gr.Markdown(label="🏷️ موجودیت‌ها")
441
  with gr.Column():
442
  detailed_analysis_output = gr.Markdown(label="🔍 تحلیل دقیق")
443
 
444
  usage_output = gr.Markdown(label="⚡ اطلاعات پردازش")
445
 
446
  def process_advanced_text(text: str, api_key_manual: str = ""):
447
+ """پردازش متن"""
 
448
  if api_key_manual is None:
449
  api_key_manual = ""
450
 
 
451
  final_api_key = ""
452
  if api_key_manual and api_key_manual.strip():
453
  final_api_key = api_key_manual.strip()
 
455
  final_api_key = os.getenv("CEREBRAS_API_KEY")
456
 
457
  if not final_api_key:
458
+ return ("", "❌ کلید API وارد نشده است", "", "", "", "")
 
 
 
 
 
 
 
459
 
460
  if not text or not text.strip():
461
+ return ("", "❌ لطفاً متن ورودی را وارد کنید", "", "", "", "")
 
 
 
 
 
 
 
462
 
463
  try:
464
  anonymizer = AdvancedCerebrasAnonymizer(api_key=final_api_key)
465
  result = anonymizer.anonymize_text(text)
466
 
467
  if not result["success"]:
468
+ return ("", f"❌ خطا: {result['error']}", "", "", "", "")
 
 
 
 
 
 
 
469
 
 
470
  stats = result.get("statistics", {})
471
+ stats_md = f"""📊 **آمار کلی:**
472
+
473
+ <div class="stats-grid">
474
+ <div class="stat-card"><h3>🏢 شرکت‌ها</h3><h2>{stats.get('company', 0)}</h2></div>
475
+ <div class="stat-card"><h3>👤 اشخاص</h3><h2>{stats.get('person', 0)}</h2></div>
476
+ <div class="stat-card"><h3>💰 مبالغ</h3><h2>{stats.get('amount', 0)}</h2></div>
477
+ <div class="stat-card"><h3>📊 درصدها</h3><h2>{stats.get('percent', 0)}</h2></div>
478
+ <div class="stat-card"><h3>🔢 کل</h3><h2>{stats.get('total_replacements', 0)}</h2></div>
479
+ </div>
480
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
481
 
 
482
  quality = result.get("quality_check", {})
483
  quality_md = "✅ **کنترل کیفیت:**\n\n"
484
 
485
  if quality.get("is_valid", False):
486
+ quality_md += '<span class="quality-badge quality-pass">✅ موفق</span>\n\n'
487
  else:
488
+ quality_md += '<span class="quality-badge quality-fail">❌ مشکل</span>\n\n'
489
  issues = quality.get("issues", [])
490
  if issues:
491
  quality_md += "**مشکلات:**\n"
492
  for issue in issues:
493
  quality_md += f"• {issue}\n"
494
 
 
 
 
 
 
 
 
 
495
  entities = result.get("entities", {})
496
+ entities_md = "🏷️ **موجودیت‌ها:**\n\n"
497
 
498
  if entities.get("companies"):
499
+ entities_md += f"🏢 company-{', company-'.join(entities['companies'])}\n\n"
500
  if entities.get("persons"):
501
+ entities_md += f"👤 person-{', person-'.join(entities['persons'])}\n\n"
502
  if entities.get("amounts"):
503
+ entities_md += f"💰 amount-{', amount-'.join(entities['amounts'])}\n\n"
504
  if entities.get("percents"):
505
+ entities_md += f"📊 percent-{', percent-'.join(entities['percents'])}\n\n"
506
 
 
507
  detailed = result.get("detailed_analysis", {})
508
+ detailed_md = f"""🔍 **تحلیل:**
509
+
510
+ 📅 تاریخ: {detailed.get('preserved_dates', 0)}
511
+ 📈 شاخص‌ها: {detailed.get('financial_indicators', 0)}
512
+ 📏 واحدها: {detailed.get('units_preserved', 0)}
513
+ """
514
 
 
515
  usage = result.get("usage", {})
516
+ usage_md = f"""**Qwen 3-32B:**
517
+
518
+ 🤖 مدل: {anonymizer.config.model}
519
+ 🌡️ Temperature: {anonymizer.config.temperature}
520
+ 📥 Input: {usage.get('prompt_tokens', '?')}
521
+ 📤 Output: {usage.get('completion_tokens', '?')}
522
+ 📊 Total: {usage.get('total_tokens', '?')}
523
+ """
 
 
 
524
 
525
  return (
526
  result["anonymized_text"],
 
532
  )
533
 
534
  except Exception as e:
535
+ return ("", f"❌ خطا: {str(e)}", "", "", "", "")
 
 
 
 
 
 
 
536
 
537
  def copy_text(text_to_copy):
 
538
  if not text_to_copy or not text_to_copy.strip():
539
+ return gr.Textbox(visible=False), "⚠️ متن خالی"
540
+ return gr.Textbox(value=text_to_copy, visible=True), "✅ آماده کپی"
 
541
 
542
  def clear_all():
 
543
  return "", "", "", "", "", "", "", gr.Textbox(visible=False)
544
 
 
545
  anonymize_btn.click(
546
  fn=process_advanced_text,
547
  inputs=[input_text, api_key_input],
 
559
  outputs=[input_text, output_text, statistics_output, quality_output, entities_output, detailed_analysis_output, usage_output, copy_output]
560
  )
561
 
 
562
  gr.Examples(
563
  examples=[
564
+ ["ایران خودرو در اسفندماه سال 1402 حدود 23 هزار و 296 میلیارد تومان درآمد کسب کرد که در مقایسه با بهمن 4.58 درصد افزایش داشت."],
565
+ ["مجمع پتروشیمی بوعلی سینا برگزار شد. وانیا نیک تدبیر را بازرس قانونی انتخاب کردند."],
566
+ ["شرکت فولاد مبارکه اصفهان با ملی نفت قرارداد امضا کرد. فاما سرمایه را از 8700 به 12500 میلیارد افزایش می‌دهد."]
 
 
 
567
  ],
568
  inputs=input_text,
569
+ label="📚 مثال‌ها"
570
  )
571
 
572
+ with gr.Accordion("📖 راهنما", open=False):
 
573
  gr.Markdown("""
574
+ ## 🔧 اصلاحات انجام شده:
 
 
 
 
 
 
 
 
 
 
 
 
 
575
 
576
+ ### مشکل حل شده:
577
+ - غیرفعال کردن Thinking Mode با `/no_think`
578
+ - حذف خودکار تگ‌های `<think>`
579
+ - پاک‌سازی توضیحات اضافی
580
+ - کاهش Temperature به 0.3 برای دقت بیشتر
 
 
581
 
582
+ ### 🎯 چگونه کار می‌کند:
583
+ 1. پرامپت بهینه شده برای خروجی مستقیم
584
+ 2. اضافه کردن `/no_think` به انتهای درخواست
585
+ 3. پردازش و پاک‌سازی خودکار خروجی
586
+ 4. حذف تمام توضیحات و تگ‌های اضافی
587
+ """)
 
 
 
 
 
 
 
 
 
 
 
 
 
588
 
589
  return interface
590
 
 
591
  if __name__ == "__main__":
592
  interface = create_advanced_interface()
593
  interface.launch(