leilaghomashchi commited on
Commit
bff49f6
·
verified ·
1 Parent(s): 964df6b

Upload enhanced_anonymization_app (9).py

Browse files
Files changed (1) hide show
  1. enhanced_anonymization_app (9).py +1724 -0
enhanced_anonymization_app (9).py ADDED
@@ -0,0 +1,1724 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import re
3
+ import os
4
+ import requests
5
+ import time
6
+ import logging
7
+ from packaging import version
8
+
9
+ # تنظیم logging
10
+ logging.basicConfig(level=logging.INFO)
11
+ logger = logging.getLogger(__name__)
12
+
13
+ def auto_setup_models():
14
+ """راه‌اندازی خودکار مدل‌ها در صورت عدم وجود"""
15
+ models_dir = "./models"
16
+ required_models = {
17
+ 'bert-fa-ner': 'HooshvareLab/bert-fa-zwnj-base-ner',
18
+ 'bert-base-NER': 'dslim/bert-base-NER',
19
+ }
20
+
21
+ missing_models = []
22
+ for model_name in required_models.keys():
23
+ model_path = os.path.join(models_dir, model_name)
24
+ if not os.path.exists(model_path) or not os.listdir(model_path):
25
+ missing_models.append(model_name)
26
+
27
+ if not missing_models:
28
+ logger.info("✅ All models are already available")
29
+ return True
30
+
31
+ logger.info(f"📥 Auto-downloading missing models: {missing_models}")
32
+
33
+ try:
34
+ from transformers import AutoTokenizer, AutoModelForTokenClassification
35
+ os.makedirs(models_dir, exist_ok=True)
36
+
37
+ for model_name in missing_models:
38
+ hf_repo = required_models[model_name]
39
+ model_path = os.path.join(models_dir, model_name)
40
+ logger.info(f"📥 Downloading {model_name} from {hf_repo}...")
41
+ try:
42
+ tokenizer = AutoTokenizer.from_pretrained(hf_repo)
43
+ model = AutoModelForTokenClassification.from_pretrained(hf_repo)
44
+ tokenizer.save_pretrained(model_path)
45
+ model.save_pretrained(model_path)
46
+ logger.info(f"✅ {model_name} downloaded successfully")
47
+ del tokenizer, model
48
+ except Exception as e:
49
+ logger.error(f"❌ Failed to download {model_name}: {e}")
50
+ if os.path.exists(model_path):
51
+ import shutil
52
+ shutil.rmtree(model_path)
53
+
54
+ logger.info("🎉 Auto-setup completed!")
55
+ return True
56
+
57
+ except ImportError:
58
+ logger.error("❌ transformers library not available for auto-download")
59
+ return False
60
+ except Exception as e:
61
+ logger.error(f"❌ Auto-setup failed: {e}")
62
+ return False
63
+
64
+ # اجرای auto-setup در startup
65
+ try:
66
+ auto_setup_models()
67
+ except Exception as e:
68
+ logger.warning(f"⚠️ Auto-setup encountered an issue: {e}")
69
+ logger.info("ℹ️ Continuing with manual setup...")
70
+
71
+ class ComprehensiveBilingualDataAnonymizer:
72
+ def __init__(self):
73
+ self.mapping_table = {}
74
+ # counters به‌روزرسانی شده با تمام دسته‌های جامع (27 دسته)
75
+ self.counters = {
76
+ # اطلاعات شخصی و هویتی
77
+ 'PERSON': 0, 'MIXED_NAMES': 0, 'ID_NUMBER': 0, 'ENGLISH_TITLES': 0,
78
+
79
+ # اطلاعات مالی
80
+ 'AMOUNT': 0, 'INTERNATIONAL_CURRENCIES': 0, 'ACCOUNT': 0,
81
+ 'FINANCIAL_TERMS': 0, 'STOCK_SYMBOL': 0,
82
+
83
+ # اطلاعات زمانی
84
+ 'DATE': 0, 'ADVANCED_DATE_FORMATS': 0, 'TIME_RANGES': 0,
85
+
86
+ # اطلاعات مکانی
87
+ 'LOCATION': 0, 'COMPLEX_ADDRESSES': 0,
88
+
89
+ # اطلاعات فنی و تکنولوژیکی
90
+ 'TECHNICAL_CODES': 0, 'NETWORK_ADDRESSES': 0, 'TECHNICAL_UNITS': 0,
91
+ 'ACRONYMS_ABBREVIATIONS': 0,
92
+
93
+ # اطلاعات کسب‌وکار
94
+ 'COMPANY': 0, 'BUSINESS_TERMS': 0, 'PRODUCT': 0, 'PETROCHEMICAL': 0,
95
+
96
+ # اطلاعات کمیت و واحد
97
+ 'PERCENTAGE': 0, 'VOLUME': 0, 'RATIOS': 0,
98
+
99
+ # اطلاعات ارتباطی
100
+ 'PHONE': 0, 'EMAIL': 0
101
+ }
102
+
103
+ self.api_key = os.getenv("OPENAI_API_KEY", "")
104
+ self.models_base_path = "./models"
105
+ self.models_loaded = False
106
+ self.model_status = {}
107
+ self.load_local_ner_models()
108
+
109
+ def ensure_models_directory(self):
110
+ if not os.path.exists(self.models_base_path):
111
+ try:
112
+ os.makedirs(self.models_base_path, exist_ok=True)
113
+ logger.info(f"📁 Created models directory: {self.models_base_path}")
114
+ except Exception as e:
115
+ logger.error(f"❌ Failed to create models directory: {e}")
116
+ return False
117
+ return True
118
+
119
+ def download_model_if_missing(self, local_name, hf_repo):
120
+ model_path = os.path.join(self.models_base_path, local_name)
121
+ if os.path.exists(model_path) and os.listdir(model_path):
122
+ return True, f"Model {local_name} already exists"
123
+ try:
124
+ logger.info(f"📥 Auto-downloading {local_name} from {hf_repo}...")
125
+ from transformers import AutoTokenizer, AutoModelForTokenClassification
126
+ tokenizer = AutoTokenizer.from_pretrained(hf_repo)
127
+ model = AutoModelForTokenClassification.from_pretrained(hf_repo)
128
+ tokenizer.save_pretrained(model_path)
129
+ model.save_pretrained(model_path)
130
+ logger.info(f"✅ {local_name} auto-downloaded successfully")
131
+ return True, f"Downloaded {local_name}"
132
+ except Exception as e:
133
+ logger.error(f"❌ Auto-download failed for {local_name}: {e}")
134
+ return False, str(e)
135
+
136
+ def _load_pipeline(self, task, model_path, tokenizer_path=None):
137
+ """لود مدل با مدیریت صحیح پارامترهای ورژن مختلف transformers"""
138
+ try:
139
+ from transformers import pipeline, AutoTokenizer, AutoModelForTokenClassification, __version__ as tr_version
140
+
141
+ # بررسی پشتیبانی از aggregation_strategy
142
+ supports_agg = version.parse(tr_version) >= version.parse("4.11.0")
143
+
144
+ # لود توکنایزر و مدل به صورت جداگانه
145
+ if tokenizer_path:
146
+ tokenizer = AutoTokenizer.from_pretrained(tokenizer_path, local_files_only=True)
147
+ else:
148
+ tokenizer = AutoTokenizer.from_pretrained(model_path, local_files_only=True)
149
+
150
+ model = AutoModelForTokenClassification.from_pretrained(model_path, local_files_only=True)
151
+
152
+ # ایجاد pipeline با پارامترهای مناسب
153
+ pipeline_kwargs = {
154
+ "model": model,
155
+ "tokenizer": tokenizer,
156
+ "device": -1 # استفاده از CPU
157
+ }
158
+
159
+ # اضافه کردن aggregation_strategy اگر پشتیبانی می‌شود
160
+ if supports_agg:
161
+ pipeline_kwargs["aggregation_strategy"] = "simple"
162
+
163
+ return pipeline(task, **pipeline_kwargs)
164
+
165
+ except Exception as e:
166
+ logger.error(f"❌ Failed to load pipeline for {model_path}: {e}")
167
+ return None
168
+
169
+ def load_local_ner_models(self):
170
+ logger.info("📄 Loading local NER models with auto-download...")
171
+ if not self.ensure_models_directory():
172
+ self.models_loaded = False
173
+ self.model_status['directory'] = "❌ Cannot create models directory"
174
+ return
175
+
176
+ try:
177
+ try:
178
+ import torch
179
+ from transformers import AutoTokenizer, AutoModelForTokenClassification
180
+ transformers_available = True
181
+ logger.info("✅ Transformers library available")
182
+ except ImportError as e:
183
+ transformers_available = False
184
+ self.model_status['transformers'] = f"❌ Transformers library not installed: {str(e)}"
185
+ self.models_loaded = False
186
+ return
187
+
188
+ # Persian model
189
+ persian_model_path = os.path.join(self.models_base_path, "bert-fa-ner")
190
+ self.download_model_if_missing("bert-fa-ner", "HooshvareLab/bert-fa-zwnj-base-ner")
191
+ if os.path.exists(persian_model_path) and os.listdir(persian_model_path):
192
+ try:
193
+ self.persian_ner = self._load_pipeline("ner", persian_model_path)
194
+ if self.persian_ner:
195
+ self.model_status['persian'] = f"✅ Local Persian NER: {persian_model_path}"
196
+ else:
197
+ self.model_status['persian'] = f"❌ Failed to load Persian model: {persian_model_path}"
198
+ except Exception as e:
199
+ self.persian_ner = None
200
+ self.model_status['persian'] = f"❌ Persian model loading error: {str(e)[:100]}"
201
+ else:
202
+ self.persian_ner = None
203
+ self.model_status['persian'] = f"❌ Persian model not found: {persian_model_path}"
204
+
205
+ # English model
206
+ english_model_path = os.path.join(self.models_base_path, "bert-base-NER")
207
+ self.download_model_if_missing("bert-base-NER", "dslim/bert-base-NER")
208
+ if os.path.exists(english_model_path) and os.listdir(english_model_path):
209
+ try:
210
+ self.english_ner = self._load_pipeline("ner", english_model_path)
211
+ if self.english_ner:
212
+ self.model_status['english'] = f"✅ Local English NER: {english_model_path}"
213
+ else:
214
+ self.model_status['english'] = f"❌ Failed to load English model: {english_model_path}"
215
+ except Exception as e:
216
+ self.english_ner = None
217
+ self.model_status['english'] = f"❌ English model loading error: {str(e)[:100]}"
218
+ else:
219
+ self.english_ner = None
220
+ self.model_status['english'] = f"❌ English model not found: {english_model_path}"
221
+
222
+ loaded_models = sum(1 for status in self.model_status.values() if status.startswith("✅"))
223
+ self.models_loaded = loaded_models > 0
224
+ if loaded_models == 0:
225
+ self.model_status['fallback'] = "⚠️ Using regex-only mode (no local models found)"
226
+
227
+ except Exception as e:
228
+ self.models_loaded = False
229
+ self.model_status['critical'] = f"❌ Critical error: {str(e)[:100]}..."
230
+
231
+ def detect_language(self, text):
232
+ """تشخیص زبان متن"""
233
+ if not text:
234
+ return 'fa'
235
+
236
+ persian_chars = len(re.findall(r'[\u0600-\u06FF]', text))
237
+ english_chars = len(re.findall(r'[a-zA-Z]', text))
238
+ total = persian_chars + english_chars
239
+
240
+ if total == 0:
241
+ return 'fa'
242
+
243
+ if persian_chars / total > 0.6:
244
+ return 'fa'
245
+ elif english_chars / total > 0.6:
246
+ return 'en'
247
+ else:
248
+ return 'mixed'
249
+
250
+ def extract_entities_with_ner(self, text, lang='fa'):
251
+ """استخراج entities با مدل‌های NER محلی"""
252
+ entities = []
253
+
254
+ if not self.models_loaded:
255
+ logger.info("ℹ️ Local NER models not available - using regex only")
256
+ return entities
257
+
258
+ try:
259
+ # مدل فارسی محلی
260
+ if lang in ['fa', 'mixed'] and hasattr(self, 'persian_ner') and self.persian_ner:
261
+ try:
262
+ persian_results = self.persian_ner(text)
263
+ for entity in persian_results:
264
+ # بررسی فرمت خروجی بر اساس ورژن transformers
265
+ if isinstance(entity, dict):
266
+ if 'entity_group' in entity:
267
+ # ورژن جدید با aggregation_strategy
268
+ entities.append({
269
+ 'text': entity['word'].strip(),
270
+ 'label': entity['entity_group'],
271
+ 'start': entity['start'],
272
+ 'end': entity['end'],
273
+ 'confidence': entity['score'],
274
+ 'source': 'local_persian_ner'
275
+ })
276
+ else:
277
+ # ورژن قدیمی
278
+ entities.append({
279
+ 'text': entity['word'].strip(),
280
+ 'label': entity['entity'],
281
+ 'start': entity['start'],
282
+ 'end': entity['end'],
283
+ 'confidence': entity['score'],
284
+ 'source': 'local_persian_ner'
285
+ })
286
+ logger.info(f"Local Persian NER found {len(persian_results)} entities")
287
+ except Exception as e:
288
+ logger.error(f"Local Persian NER extraction error: {e}")
289
+
290
+ # مدل انگلیسی محلی
291
+ if lang in ['en', 'mixed'] and hasattr(self, 'english_ner') and self.english_ner:
292
+ try:
293
+ english_results = self.english_ner(text)
294
+ for entity in english_results:
295
+ # بررسی فرمت خروجی بر اساس ورژن transformers
296
+ if isinstance(entity, dict):
297
+ if 'entity_group' in entity:
298
+ # ورژن جدید با aggregation_strategy
299
+ entities.append({
300
+ 'text': entity['word'].strip(),
301
+ 'label': entity['entity_group'],
302
+ 'start': entity['start'],
303
+ 'end': entity['end'],
304
+ 'confidence': entity['score'],
305
+ 'source': 'local_english_ner'
306
+ })
307
+ else:
308
+ # ورژن قدیمی
309
+ entities.append({
310
+ 'text': entity['word'].strip(),
311
+ 'label': entity['entity'],
312
+ 'start': entity['start'],
313
+ 'end': entity['end'],
314
+ 'confidence': entity['score'],
315
+ 'source': 'local_english_ner'
316
+ })
317
+ logger.info(f"Local English NER found {len(english_results)} entities")
318
+ except Exception as e:
319
+ logger.error(f"Local English NER extraction error: {e}")
320
+
321
+ except Exception as e:
322
+ logger.error(f"Local NER extraction general error: {e}")
323
+
324
+ # حذف تکراری‌ها
325
+ unique_entities = []
326
+ seen = set()
327
+ for entity in entities:
328
+ key = (entity['text'].lower(), entity['start'], entity['end'])
329
+ if key not in seen:
330
+ seen.add(key)
331
+ unique_entities.append(entity)
332
+
333
+ logger.info(f"Total unique entities found by local models: {len(unique_entities)}")
334
+ return unique_entities
335
+
336
+ def map_ner_to_categories(self, ner_label, source=''):
337
+ """نگاشت برچسب‌های NER به دسته‌های سیستم"""
338
+ mapping = {
339
+ 'PER': 'PERSON', 'PERSON': 'PERSON',
340
+ 'ORG': 'COMPANY', 'ORGANIZATION': 'COMPANY',
341
+ 'LOC': 'LOCATION', 'LOCATION': 'LOCATION',
342
+ 'MISC': 'BUSINESS_TERMS', 'MISCELLANEOUS': 'BUSINESS_TERMS',
343
+ 'B-PER': 'PERSON', 'I-PER': 'PERSON',
344
+ 'B-ORG': 'COMPANY', 'I-ORG': 'COMPANY',
345
+ 'B-LOC': 'LOCATION', 'I-LOC': 'LOCATION',
346
+ 'B-MISC': 'BUSINESS_TERMS', 'I-MISC': 'BUSINESS_TERMS',
347
+ 'MONEY': 'AMOUNT', 'PERCENT': 'PERCENTAGE',
348
+ 'DATE': 'DATE', 'TIME': 'DATE'
349
+ }
350
+ return mapping.get(ner_label.upper(), 'BUSINESS_TERMS')
351
+
352
+ def get_comprehensive_patterns(self):
353
+ """الگوهای جامع ناشناس‌سازی بر اساس 221 الگوی دسته‌بندی شده"""
354
+ return {
355
+ # =============================================================================
356
+ # 1. اطلاعات شخصی و هویتی (PERSONAL & IDENTITY INFORMATION) - 30 الگو
357
+ # =============================================================================
358
+
359
+ 'PERSON': [
360
+ # نام‌ها با عناوین فارسی
361
+ r'آقای\s+([آ-یa-zA-Z]+(?:\s+[آ-یa-zA-Z]+)*)',
362
+ r'خانم\s+([آ-یa-zA-Z]+(?:\s+[آ-یa-zA-Z]+)*)',
363
+ r'مهندس\s+([آ-یa-zA-Z]+(?:\s+[آ-یa-zA-Z]+)*)',
364
+ r'دکتر\s+([آ-یa-zA-Z]+(?:\s+[آ-یa-zA-Z]+)*)',
365
+ r'استاد\s+([آ-یa-zA-Z]+(?:\s+[آ-یa-zA-Z]+)*)',
366
+ # نام‌ها با سمت
367
+ r'([آ-یa-zA-Z]+\s+[آ-یa-zA-Z]+)(?:،\s+مدیرعامل|\s+مدیرعامل|\s+رئیس)',
368
+ r'مدیرعامل(?=\s|$|،|\.)',
369
+ r'سرپرست(?=\s+و|\s|$|،|\.)',
370
+ r'رئیس\s+هیأت‌مدیره',
371
+ # ضمایر اشاره‌ای
372
+ r'وی(?=\s+ادامه|\s+اظهار|\s+گفت|\s+اعلام|\s+همچنین)',
373
+ # عناوین انگلیسی
374
+ r'Mr\.\s+([a-zA-Z]+(?:\s+[a-zA-Z]+)*)',
375
+ r'Ms\.\s+([a-zA-Z]+(?:\s+[a-zA-Z]+)*)',
376
+ r'Dr\.\s+([a-zA-Z]+(?:\s+[a-zA-Z]+)*)',
377
+ # نام‌های کامل
378
+ r'([آ-یa-zA-Z]{3,}\s+[آ-یa-zA-Z]{3,})(?=\s+گفت|\s+اظهار|\s+اعلام)'
379
+ ],
380
+
381
+ 'MIXED_NAMES': [
382
+ # نام‌های فارسی-انگلیسی
383
+ r'([آ-ی]+[a-zA-Z\s]+[آ-ی]+)',
384
+ r'Dr\.\s+([آ-یa-zA-Z\s‌]+)',
385
+ # نام‌های کامل بدون عنوان
386
+ r'([آ-یa-zA-Z]{2,}\s+[آ-یa-zA-Z]{2,})',
387
+ # نام‌های انگلیسی با خط تیره
388
+ r'([A-Z][a-z]+-[A-Z][a-z]+)',
389
+ r"([A-Z]'[A-Z][a-z]+)",
390
+ # نام‌های رومن
391
+ r'([A-Z][a-z]+\s+[A-Z][a-z]+\s+[IVX]+)',
392
+ # نام‌های ترکیبی با سمت
393
+ r'([a-z\s]+)\s+([آ-ی\s]+)',
394
+ # نام‌های تجاری
395
+ r'([A-Z][a-z]+\s+[A-Z][a-z]+)\s*\(([A-Z][a-z]+\s+[A-Z][a-z]+)\)'
396
+ ],
397
+
398
+ 'ID_NUMBER': [
399
+ # شماره شبا ایرانی
400
+ r'IR[۰-۹0-9]{24}',
401
+ r'شبا[\s:]*IR[۰-۹0-9]{24}',
402
+ r'IBAN[\s:]*IR[۰-۹0-9]{24}',
403
+ r'شماره[\s]*شبا[\s:]*IR[۰-۹0-9]{24}',
404
+ # کد ملی
405
+ r'(?:کد[\s]*)?(?:ملی[\s:]*)?[۰-۹0-9]{10}',
406
+ r'(?:شناسه[\s]*)?(?:ملی[\s:]*)?[۰-۹0-9]{10}',
407
+ r'National[\s]*(?:ID[\s:]*)?[0-9]{10}',
408
+ # پاسپورت
409
+ r'(?:پاسپورت[\s:]*)?[A-Z][0-9]{8}',
410
+ r'(?:Passport[\s:]*)?[A-Z][0-9]{8}',
411
+ # کارت‌های بانکی
412
+ r'(?:کارت[\s:]*)?(?:[۰-۹0-9]{4}[-\s]?){3}[۰-۹0-9]{4}',
413
+ r'(?:Card[\s:]*)?(?:[0-9]{4}[-\s]?){3}[0-9]{4}',
414
+ # شماره‌های SSN و FICO
415
+ r'SSN[\s:]*[0-9]{3}-[0-9]{2}-[0-9]{4}',
416
+ r'FICO[\s]*(?:score[\s:]*)?[0-9]{3}',
417
+ # شماره‌های اداری
418
+ r'EIN[\s:]*[0-9]{2}-[0-9]{7}',
419
+ r'Meeting[\s]*ID[\s:]*[0-9]{9,11}'
420
+ ],
421
+
422
+ 'ENGLISH_TITLES': [
423
+ # عناوین تجاری
424
+ r'business\s+partner',
425
+ r'team\s+lead',
426
+ r'head\s+of\s+production',
427
+ # عناوین مهندسی
428
+ r'senior\s+architect',
429
+ r'civil\s+engineer',
430
+ r'quantity\s+surveyor',
431
+ r'system\s+administrator',
432
+ r'network\s+engineer',
433
+ # عناوین مشاوره‌ای
434
+ r'environmental\s+consultant',
435
+ r'HSE\s+coordinator',
436
+ # عناوین مالی
437
+ r'senior\s+loan\s+officer',
438
+ r'investment\s+advisor',
439
+ r'Chief\s+Financial\s+Officer',
440
+ # عناوین مدیریتی
441
+ r'facility\s+manager',
442
+ r'quality\s+control\s+manager',
443
+ r'maintenance\s+window',
444
+ r'project\s+team',
445
+ r'technical\s+support',
446
+ # فرآیندهای کاری
447
+ r'supervision',
448
+ r'troubleshooting',
449
+ r'monitoring',
450
+ r'compliance\s+certificate'
451
+ ],
452
+
453
+ # =============================================================================
454
+ # 2. اطلاعات مالی (FINANCIAL INFORMATION) - 37 الگو
455
+ # =============================================================================
456
+
457
+ 'AMOUNT': [
458
+ # مبالغ فارسی
459
+ r'\d+(?:,\d{3})*\s*(?:میلیون|میلیارد|هزار)\s*تومان',
460
+ r'مبلغ\s+\d+(?:,\d{3})*\s*(?:میلیون|میلیارد|هزار)?\s*تومان',
461
+ r'\d+\s*تومان(?=\s+به\s+ازای|\s+فروش|،)',
462
+ r'رقم\s+فعلی\s+\d+(?:,\d{3})*\s*(?:میلیون|میلیارد)\s*تومان',
463
+ r'رقم\s+\d+(?:,\d{3})*\s*(?:میلیون|میلیارد)\s*تومان',
464
+ r'به\s+\d+(?:,\d{3})*\s*(?:میلیون|میلیارد|هزار)\s*تومان',
465
+ r'از\s+\d+(?:,\d{3})*\s*(?:میلیون|میلیارد|هزار)\s*تومان',
466
+ r'برابر\s+با\s+\d+(?:,\d{3})*\s*(?:میلیون|میلیارد|هزار)\s*تومان',
467
+ r'\d+(?:میلیارد|میلیون)\s*تومان(?=\s+رسیده|\s+ثبت|\s+بوده|،)',
468
+ # مبالغ دلار
469
+ r'\$\d+(?:,\d{3})*(?:\.\d+)?\s*(?:million|billion|thousand|M|B|K)?',
470
+ r'\d+(?:,\d{3})*\s*ریال',
471
+ # یورو
472
+ r'€\d+(?:,\d{3})*(?:\.\d+)?',
473
+ # درهم
474
+ r'\d+(?:,\d{3})*\s*AED',
475
+ # فرمت‌های K/M
476
+ r'\$\d+(?:\.\d+)?[KMB]',
477
+ r'€\d+(?:\.\d+)?[KM]'
478
+ ],
479
+
480
+ 'INTERNATIONAL_CURRENCIES': [
481
+ # یورو با فرمت‌های مختلف
482
+ r'\d+(?:,\d{3})*\s+euro',
483
+ r'€\d+(?:\.\d+)?M',
484
+ r'\d+\s+EUR',
485
+ # درهم امارات
486
+ r'\d+(?:,\d{3})*\s+AED',
487
+ r'\d+(?:\.\d+)?M\s+AED',
488
+ # دلار با فرمت K/M
489
+ r'\$\d+(?:\.\d+)?M',
490
+ r'\$\d+(?:\.\d+)?K',
491
+ # پوند انگلیس
492
+ r'£\d+(?:,\d{3})*(?:\.\d+)?',
493
+ r'\d+\s+GBP',
494
+ # فرانک سوئیس
495
+ r'\d+\s+CHF',
496
+ # ین ژاپن
497
+ r'¥\d+(?:,\d{3})*',
498
+ r'\d+\s+JPY'
499
+ ],
500
+
501
+ 'ACCOUNT': [
502
+ # حساب‌های بانکی فارسی
503
+ r'(?:شماره[\s]*)?(?:حساب[\s]*)?(?:بانکی[\s:]*)?(?:[۰-۹0-9]{1,3}[-\s]?)*[۰-۹0-9]{8,20}',
504
+ r'حساب[\s]*(?:شماره[\s:]*)?(?:[۰-۹0-9]{1,3}[-\s]?)*[۰-۹0-9]{8,20}',
505
+ r'شماره[\s]*حساب[\s:]*(?:[۰-۹0-9]{1,3}[-\s]?)*[۰-۹0-9]{8,20}',
506
+ # حساب‌های انگلیسی
507
+ r'Account[\s]*(?:Number[\s:]*)?(?:[0-9]{1,3}[-\s]?)*[0-9]{8,20}',
508
+ r'[۰-۹0-9]{3}[-\s]?[۰-۹0-9]{3}[-\s]?[۰-۹0-9]{6,12}',
509
+ r'[۰-۹0-9]{2,4}[-\s]?[۰-۹0-9]{6,12}[-\s]?[۰-۹0-9]{2,4}',
510
+ # واریز و سود
511
+ r'واریز[\s]*(?:سود[\s:]*)?(?:[۰-۹0-9]{1,3}[-\s]?)*[۰-۹0-9]{8,20}',
512
+ r'سود[\s:]*(?:[۰-۹0-9]{1,3}[-\s]?)*[۰-۹0-9]{8,20}'
513
+ ],
514
+
515
+ 'FINANCIAL_TERMS': [
516
+ # اصطلاحات فروش
517
+ r'فروش\s+(?:ماهانه|تجمیعی|صادراتی)',
518
+ r'درآمد\s+شرکت',
519
+ r'سود\s+(?:خالص|نقدی)',
520
+ r'صورت‌های\s+مالی',
521
+ r'بهای\s+تمام‌شده',
522
+ r'سودآوری',
523
+ r'عملکرد\s+مالی',
524
+ r'میانگین\s+فروش',
525
+ r'بالاترین\s+رقم\s+فروش',
526
+ r'رقم\s+فروش',
527
+ r'د��آمدهای\s+عملیاتی'
528
+ ],
529
+
530
+ 'STOCK_SYMBOL': [
531
+ # نمادهای بورس ایران
532
+ r'نماد\s+([آ-یa-zA-Z0-9]+)',
533
+ r'(سبهان|غدیر|شتران|شپنا|پترول|فارس|خارک|پلاسکو|جم|کرمان|مارون|اراک|رازی|شازند|کاوه|بندر|پارس|خوزستان|ماهشهر|عسلویه)(?=\s|$|،|\.|\s+)',
534
+ r'شرکت\s+([آ-یa-zA-Z\s]+?)(?=\s+در|\s+که|\s+با|،|\.|\s+$|\s+را|\s+به)',
535
+ r'پتروشیمی\s+([آ-یa-zA-Z\s]+?)(?=\s+در|\s+که|\s+با|،|\.|\s+$|\s+توان)',
536
+ # نمادهای بین‌المللی
537
+ r'(AAPL|GOOGL|MSFT|AMZN|TSLA|META|NVDA|SABIC)(?=\s|$|,|\.)'
538
+ ],
539
+
540
+ # =============================================================================
541
+ # 3. اطلاعات زمانی (TEMPORAL INFORMATION) - 30 الگو
542
+ # =============================================================================
543
+
544
+ 'DATE': [
545
+ # تاریخ‌های فارسی
546
+ r'[۰-۹0-9]{4}[/-][۰-۹0-9]{1,2}[/-][۰-۹0-9]{1,2}',
547
+ r'[۰-۹0-9]{1,2}[/-][۰-۹0-9]{1,2}[/-][۰-۹0-9]{4}',
548
+ r'(?:[۰-۹0-9]{1,2})\s*(?:فروردین|اردیبهشت|خرداد|تیر|مرداد|شهریور|مهر|آبان|آذر|دی|بهمن|اسفند)\s*(?:[۰-۹0-9]{4})',
549
+ # ماه‌های فارسی
550
+ r'(?:فروردین|اردیبهشت|خرداد|تیر|مرداد|شهریور|مهر|آبان|آذر|دی|بهمن|اسفند)\s+[۰-۹0-9]{4}',
551
+ # تاریخ‌های انگلیسی
552
+ r'(?:[0-9]{1,2})\s*(?:January|February|March|April|May|June|July|August|September|October|November|December)\s*(?:[0-9]{4})',
553
+ r'(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s*[0-9]{1,2},?\s*[0-9]{4}',
554
+ # بازه‌های زمانی
555
+ r'سال\s+گذشته',
556
+ r'سال\s+جاری',
557
+ r'این\s+سال',
558
+ r'ماه\s+قبل',
559
+ r'ماه\s+اخیر',
560
+ r'دومین\s+ماه\s+سال',
561
+ r'ابتدای\s+سال\s+جاری',
562
+ r'مدت\s+مشابه\s+سال\s+گذشته',
563
+ r'چند\s+ماهه\s+اخیر',
564
+ # سال‌های مستقل
565
+ r'(?:13[0-9]{2}|14[0-9]{2}|20[0-9]{2}|19[0-9]{2})(?=\s|$|،|\.)'
566
+ ],
567
+
568
+ 'ADVANCED_DATE_FORMATS': [
569
+ # تاریخ انگلیسی
570
+ r'(?:March|April|May|June|July|August|September|October|November|December)\s+\d{1,2}(?:st|nd|rd|th),?\s+\d{4}',
571
+ r'(?:January|February)\s+\d{1,2}(?:st|nd|rd|th),?\s+\d{4}',
572
+ # timestamp
573
+ r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z',
574
+ # timezone
575
+ r'(?:PST|EST|GMT|UTC)(?:[+-]\d{1,2}:\d{2})?',
576
+ r'Eastern\s+Time',
577
+ r'GMT[+-]\d{1,2}:\d{2}',
578
+ # تاریخ با ساعت
579
+ r'\d{1,2}(?:st|nd|rd|th)\s+of\s+(?:January|February|March|April|May|June|July|August|September|October|November|December)\s+\d{4}',
580
+ # بازه تاریخ
581
+ r'ending\s+(?:December|January|February|March|April|May|June|July|August|September|October|November)\s+\d{1,2}(?:st|nd|rd|th)',
582
+ # fiscal year
583
+ r'end\s+of\s+fiscal\s+year\s+\d{4}/\d{2}/\d{2}',
584
+ # due date
585
+ r'\d{1,2}\s+(?:روز|days?)\s+(?:کاری|business)\s+پس\s+از\s+(?:delivery|تحویل)',
586
+ # فرمت COB
587
+ r'COB\s+(?:Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday)'
588
+ ],
589
+
590
+ 'TIME_RANGES': [
591
+ # shift time
592
+ r'\d{2}:\d{2}-\d{2}:\d{2}',
593
+ r'\d{2}:\d{2}\s+تا\s+\d{2}:\d{2}',
594
+ # maintenance window
595
+ r'(?:Saturday|Sunday|Monday|Tuesday|Wednesday|Thursday|Friday)\s+night\s+\d{1,2}:\d{2}\s+(?:AM|PM)\s+to\s+\d{1,2}:\d{2}\s+(?:AM|PM)',
596
+ # meeting time
597
+ r'\d{1,2}:\d{2}\s+(?:AM|PM)\s+(?:PST|EST|GMT|UTC)',
598
+ r'\d{1,2}:\d{2}\s+(?:AM|PM)\s+Eastern\s+Time',
599
+ # timestamp
600
+ r'\d{2}:\d{2}:\d{2}\s+(?:AM|PM)',
601
+ # business hours
602
+ r'COB\s*\(Close\s+of\s+Business\)',
603
+ # due periods
604
+ r'\d{1,3}\s+(?:business\s+days|روز\s+کاری)',
605
+ r'warranty\s+period\s+(?:دو\s+سال|\d+\s+(?:years?|سال))'
606
+ ],
607
+
608
+ # =============================================================================
609
+ # 4. اطلاعات مکانی (LOCATION INFORMATION) - 14 الگو
610
+ # =============================================================================
611
+
612
+ 'LOCATION': [
613
+ # شهرهای ایران
614
+ r'(تهران|اصفهان|ماهشهر|عسلویه|بندرعباس|اهواز|شیراز|مشهد|تبریز|کرج|قم|رشت|کرمان|یزد|زاهدان|بوشهر|خرمشهر|آبادان|اراک|قزوین)',
615
+ # استان‌ها
616
+ r'استان\s+([آ-ی\s]+)',
617
+ r'شهر\s+([آ-ی\s]+)',
618
+ # کشورها
619
+ r'(ایران|عراق|کویت|عربستان|امارات|قطر|عمان|بحرین|ترکیه|پاکستان|افغانستان|آذربایجان|ارمنستان|گرجستان)',
620
+ # داخلی/خارجی
621
+ r'داخلی|بازار\s+داخلی',
622
+ r'خارجی|بازارهای\s+خارجی',
623
+ # شهرهای بین‌المللی
624
+ r'(London|Paris|Tokyo|New\s+York|Dubai|Singapore|Hong\s+Kong|Shanghai|Mumbai|Frankfurt|Amsterdam)'
625
+ ],
626
+
627
+ 'COMPLEX_ADDRESSES': [
628
+ # آدرس با کیلومتر
629
+ r'کیلومتر\s+\d+\s+جاده\s+[آ-ی\s]+-[آ-ی\s]+',
630
+ # آدرس با مرجع
631
+ r'روبروی\s+(?:پمپ\s+بنزین|بانک|پارک|مسجد|بیمارستان)\s+[آ-یa-zA-Z\s]+',
632
+ # آدرس ساختمان
633
+ r'Building-[A-Z],?\s+Floor-\d+,?\s+Unit-[A-Z0-9]+',
634
+ # آدرس rack
635
+ r'rack\s+number\s+R-\d+,?\s+slot\s+\d+',
636
+ # آدرس plot
637
+ r'phase\s+\d+\s+development,?\s+block\s+[A-Z],?\s+plot\s+\d+-[A-Z]',
638
+ # آدرس آمریکایی
639
+ r'\d{2,5}\s+[A-Z][a-z]+\s+(?:Street|Avenue|Boulevard|Road|Drive),?\s+Floor\s+\d+,?\s+Building\s+[A-Z]',
640
+ # industrial estate
641
+ r'شهرک\s+صنعتی\s+[آ-ی\s]+،?\s+محور\s+[آ-ی\s]+',
642
+ # data center
643
+ r'[آ-ی\s]+-پارک\s+فناوری\s+[آ-ی\s]+'
644
+ ],
645
+
646
+ # =============================================================================
647
+ # 5. اطلاعات فنی و تکنولوژیکی (TECHNICAL & TECHNOLOGICAL) - 32 الگو
648
+ # =============================================================================
649
+
650
+ 'TECHNICAL_CODES': [
651
+ # کدهای سریال
652
+ r'SN-\d{4}-[A-Z]{3}-\d{4}',
653
+ r'Serial\s+Number[\s:]*[A-Z0-9-]+',
654
+ # کدهای مرجع
655
+ r'REF-[A-Z]{3}-\d{4}-\d{3}',
656
+ r'DOC-[A-Z]{2}-\d{4}-\d{4}',
657
+ # کدهای پروژه
658
+ r'INF-\d{4}-\d{4}',
659
+ r'CTR/\d{4}/\d{3}',
660
+ # شناسه‌های فنی
661
+ r'HVAC-\d{7}',
662
+ r'Generator-Model-[A-Z0-9]+',
663
+ # کدهای LOI/BOQ
664
+ r'LOI-\d{4}-[A-Z]{4}-\d{3}',
665
+ r'BOQ-\d{4}-[A-Z]{3}-\d{3}',
666
+ # شماره‌های invoice
667
+ r'#INV-\d{4}-Q\d-\d{4}',
668
+ # کدهای ESC
669
+ r'ESC-\d{4}-[A-Z]{3}-\d{3}',
670
+ # کدهای batch
671
+ r'BN-\d{6}-[A-Z]\d+'
672
+ ],
673
+
674
+ 'NETWORK_ADDRESSES': [
675
+ # آدرس IP
676
+ r'\b(?:\d{1,3}\.){3}\d{1,3}\b',
677
+ r'xxx\.xxx\.xxx\.xxx',
678
+ # آدرس MAC
679
+ r'[A-F0-9]{2}:[A-F0-9]{2}:[A-F0-9]{2}:[A-F0-9]{2}:[A-F0-9]{2}:[A-F0-9]{2}',
680
+ # hostname
681
+ r'srv-[a-z]+-[a-z]+-\d{2}',
682
+ r'[a-z]+-[a-z]+\d*\.[a-z]+\.[a-z]+',
683
+ # domain names
684
+ r'[a-zA-Z0-9-]+\.[a-zA-Z]{2,4}(?:\.[a-zA-Z]{2,4})?'
685
+ ],
686
+
687
+ 'TECHNICAL_UNITS': [
688
+ # واحدهای برق
689
+ r'\d+(?:\.\d+)?\s*MW',
690
+ r'\d+(?:\.\d+)?\s*kWh?',
691
+ # واحدهای حجم
692
+ r'\d+(?:,\d{3})*\s*cubic\s+meters',
693
+ r'\d+(?:,\d{3})*\s*m³',
694
+ r'\d+(?:,\d{3})*\s*sq\s+ft',
695
+ # واحدهای آلودگی
696
+ r'\d+(?:\.\d+)?\s*ppm',
697
+ r'\d+(?:\.\d+)?\s*mg/m³',
698
+ r'\b(?:CO2|NOx|SO2)\b',
699
+ # واحدهای دیجیتال
700
+ r'\d+(?:\.\d+)?\s*TB',
701
+ r'\d+(?:\.\d+)?\s*GB',
702
+ # واحدهای مساحت
703
+ r'\d+(?:,\d{3})*\s*square\s+meters',
704
+ r'\d+(?:\.\d+)?\s*per\s+sq\s+ft\s+NNN',
705
+ # efficiency rate
706
+ r'\d+(?:\.\d+)?\%\s*efficiency',
707
+ r'score:\s*\d+(?:\.\d+)?/10',
708
+ # FICO score
709
+ r'FICO\s+score:\s*\d{3}',
710
+ # واحدهای فشار
711
+ r'\d+(?:\.\d+)?\s*(?:bar|psi)',
712
+ # واحدهای دما
713
+ r'\d+(?:\.\d+)?\s*°[CF]',
714
+ # واحدهای سرعت
715
+ r'\d+(?:\.\d+)?\s*(?:rpm|m/s)'
716
+ ],
717
+
718
+ 'ACRONYMS_ABBREVIATIONS': [
719
+ # فنی
720
+ r'\b(?:HVAC|IT|HSE|BOQ|LC|COB)\b',
721
+ # مالی
722
+ r'\b(?:YTD|NNN|EIN|SSN|FICO)\b',
723
+ # تکنولوژی
724
+ r'\bIP\s+Address\b',
725
+ r'\bMAC\s+Address\b',
726
+ r'\bURL\b',
727
+ # کسب‌وکار
728
+ r'\b(?:LLC|Corp|Inc|Ltd)\b',
729
+ # تاریخ
730
+ r'\b(?:PST|GMT|UTC|EST)\b',
731
+ # علمی
732
+ r'\b(?:CO2|NOx|pH|UV)\b',
733
+ # مهندسی
734
+ r'\b(?:SCADA|PLC|HMI)\b',
735
+ # اقتصادی
736
+ r'\b(?:GDP|CPI|ROI|NPV)\b',
737
+ # حمل‌ونقل
738
+ r'\b(?:FOB|CIF|DDP)\b',
739
+ # بانکی
740
+ r'\b(?:ABA|SWIFT|IBAN)\b'
741
+ ],
742
+
743
+ # =============================================================================
744
+ # 6. اطلاعات کسب‌وکار (BUSINESS INFORMATION) - 39 الگو
745
+ # =============================================================================
746
+
747
+ 'COMPANY': [
748
+ # شرکت‌های فارسی
749
+ r'شرکت(?=\s+در|\s+که|\s+با|\s+را|\s+به|\s+طی)',
750
+ r'([آ-یa-zA-Z\s]+)\s+شرکت',
751
+ r'این\s+شرکت(?=\s|$|،|\.)',
752
+ # بانک‌ها
753
+ r'(بانک\s+[آ-یa-zA-Z\s]+)',
754
+ # شرکت‌های بین‌المللی
755
+ r'([A-Z][a-zA-Z\s]+(?:Inc|Corp|Corporation|Company|Ltd|Limited|LLC))'
756
+ ],
757
+
758
+ 'BUSINESS_TERMS': [
759
+ # تحلیل و گزارش
760
+ r'تحلیل\s+عملکرد',
761
+ r'گزارش\s+(?:فعالیت|عملکرد)\s+ماهانه',
762
+ r'وضعیت\s+فروش',
763
+ # تولید و بازار
764
+ r'تولید\s+پایدار',
765
+ r'سهم\s+بازار',
766
+ r'صادرات\s+هدفمند',
767
+ r'بهره‌وری',
768
+ r'ظرفیت‌های\s+داخلی',
769
+ # صنعت و رقابت
770
+ r'شرکت‌های\s+پیشرو',
771
+ r'صنعت\s+پتروشیمی',
772
+ r'سرمایه‌گذاران\s+بنیادی',
773
+ # شاخص‌ها و برنامه‌ریزی
774
+ r'شاخص‌های\s+عملیاتی',
775
+ r'برنامه‌ریزی\s+مناسب',
776
+ # فروش و انبار
777
+ r'واحد\s+فروش',
778
+ r'موجودی\s+انبار',
779
+ # رشد و توسعه
780
+ r'فاز\s+رشد\s+جدید',
781
+ r'ترکیب\s+فروش',
782
+ r'سهم\s+صادراتی',
783
+ # عملکرد و داده‌ها
784
+ r'روند\s+عملکرد',
785
+ r'اعداد\s+اعلام‌شده',
786
+ r'داده‌های\s+ثبت‌شده'
787
+ ],
788
+
789
+ 'PRODUCT': [
790
+ # محصولات پتروشیمی
791
+ r'\b(?:VCM|PVC|PE|PP|PS|ABS|SAN|PC|PMMA|PET|PBT|PA|POM|TPU)\b',
792
+ # پلیمرها
793
+ r'پلی\s*(?:اتیلن|پروپیلن|استایرن|کربنات|متیل)',
794
+ # مواد شیمیایی
795
+ r'\b(?:اتیلن|پروپیلن|بنزن|تولوئن|زایلن|متانول|اتانول|استون|فنول)\b',
796
+ # گازها
797
+ r'\b(?:کلر|هیدروژن|اکسیژن|نیتروژن|آمونیاک|اتان|پروپان|بوتان)\b',
798
+ # محصولات عمومی
799
+ r'محصول(?:ات)?',
800
+ r'تولیدات\s+شرکت'
801
+ ],
802
+
803
+ 'PETROCHEMICAL': [
804
+ # نام‌های اختصاری پتروشیمی‌ها
805
+ r'\b(?:LDPE|HDPE|LLDPE|PP|PS|EPS|ABS|SAN|PC|PMMA|PET|PBT|PA6|PA66|POM|TPU|EVA|EAA)\b',
806
+ # ترکیبات شیمیایی پیچیده
807
+ r'(?:Ethylene\s+Vinyl\s+Acetate|Ethyl\s+Acrylate|Methyl\s+Methacrylate|Polyethylene\s+Terephthalate)'
808
+ ],
809
+
810
+ # =============================================================================
811
+ # 7. اطلاعات کمیت و واحد (QUANTITY & UNIT INFORMATION) - 26 الگو
812
+ # =============================================================================
813
+
814
+ 'PERCENTAGE': [
815
+ # درصدهای فارسی
816
+ r'\d+(?:\.\d+)?\s*درصد(?:\s+افزایش|\s+رشد|\s+کاهش|\s+بالاتر|\s+پایین‌تر)?',
817
+ r'\d+(?:\.\d+)?\s*%',
818
+ r'معادل\s+\d+(?:\.\d+)?\s*درصد',
819
+ r'حدود\s+\d+(?:\.\d+)?\s*درصد',
820
+ r'با\s+\d+(?:\.\d+)?\s*درصد\s+افزایش',
821
+ r'رشد\s+\d+(?:\.\d+)?\s*درصدی',
822
+ r'\d+(?:\.\d+)?\s*درصدی(?=\s+همراه|\s+بوده)',
823
+ # عبارات کیفی
824
+ r'میزان\s+رشد(?=\s+نسبت|\s+معادل)',
825
+ r'افزایش\s+قابل‌توجهی',
826
+ r'بهبود\s+نسبی',
827
+ # درصدهای انگلیسی
828
+ r'\d+(?:\.\d+)?\%\s*(?:increase|decrease|growth|improvement)',
829
+ r'(?:approximately|about)\s+\d+(?:\.\d+)?\%'
830
+ ],
831
+
832
+ 'VOLUME': [
833
+ # حجم‌های فارسی
834
+ r'\d+(?:,\d{3})*\s*تن',
835
+ r'\d+(?:,\d{3})*\s*(?:کیلوگرم|لیتر|بشکه)',
836
+ r'میزان\s+\d+(?:,\d{3})*\s*تن',
837
+ r'مقدار\s+تولید',
838
+ r'حجم\s+فروش',
839
+ r'ظرفیت\s+(?:تولید|اسمی)',
840
+ # واحدهای انگلیسی
841
+ r'\d+(?:,\d{3})*\s*(?:tons|kg|liters|barrels)',
842
+ r'\d+(?:,\d{3})*\s*(?:metric\s+tons|MT)',
843
+ r'\d+(?:,\d{3})*\s*(?:thousand\s+tons|KT)'
844
+ ],
845
+
846
+ 'RATIOS': [
847
+ # نسبت‌ها
848
+ r'نسبت\s+(?:فروش|تولید)\s+به\s+[آ-ی\s]+',
849
+ r'\d+(?:\.\d+)?\s*نزدیک',
850
+ r'برابر\s+با\s+\d+(?:\.\d+)?',
851
+ r'معادل\s+\d+(?:\.\d+)?',
852
+ r'میزان\s+(?:رشد|افزایش)',
853
+ r'شاخص\s+(?:مهم|عملیاتی)',
854
+ r'\d+(?:\.\d+)?\s*درصد\s+کل\s+تولید'
855
+ ],
856
+
857
+ # =============================================================================
858
+ # 8. اطلاعات ارتباطی (COMMUNICATION INFORMATION) - 5 الگو
859
+ # =============================================================================
860
+
861
+ 'PHONE': [
862
+ # شماره‌های فارسی
863
+ r'(?:تلفن[\s:]*)?(?:شماره[\s:]*)?(?:0)?(?:[۰-۹0-9]{2,3}[-\s]?)?[۰-۹0-9]{7,8}',
864
+ r'(?:تماس[\s:]*)?(?:شماره[\s:]*)?(?:با[\s]*)?(?:0)?(?:[۰-۹0-9]{2,3}[-\s]?)?[۰-۹0-9]{7,8}',
865
+ r'(?:موبایل[\s:]*)?(?:شماره[\s:]*)?(?:0)?9[۰-۹0-9]{9}',
866
+ r'[۰-۹0-9]{3,4}[-\s][۰-۹0-9]{7,8}',
867
+ r'[۰-۹0-9]{11}(?!\d)',
868
+ r'(?:\+98|0098)?[۰-۹0-9]{10}',
869
+ r'[۰-۹0-9]{3,4}[-\s]?[۰-۹0-9]{3,4}[-\s]?[۰-۹0-9]{3,4}',
870
+ # شماره‌های بین‌المللی
871
+ r'\+[0-9]{1,3}-[0-9]{3}-[0-9]{3}-[0-9]{4}(?:\s+ext\.\s+[0-9]{3,4})?',
872
+ r'\([0-9]{3}\)\s+[0-9]{3}-[0-9]{4}'
873
+ ],
874
+
875
+ 'EMAIL': [
876
+ # ایمیل‌های استاندارد
877
+ r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
878
+ # ایمیل‌های با کلمات کلیدی فارسی
879
+ r'ایمیل[\s:]*[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
880
+ r'email[\s:]*[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
881
+ r'نشانی[\s]*الکترونیکی[\s:]*[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
882
+ r'آدرس[\s]*ایمیل[\s:]*[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
883
+ # ایمیل‌های کاری خاص
884
+ r'facility\.manager@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
885
+ ]
886
+ }
887
+
888
+ def anonymize_text(self, original_text, lang='fa'):
889
+ """گام 1: ناشناس‌سازی متن با الگوهای جامع"""
890
+ try:
891
+ if not original_text or not original_text.strip():
892
+ return "❌ Please enter input text!" if lang == 'en' else "❌ لطفاً متن ورودی را وارد کنید!"
893
+
894
+ # ریست متغیرها
895
+ self.mapping_table = {}
896
+ self.counters = {key: 0 for key in self.counters.keys()}
897
+
898
+ anonymized = original_text
899
+ found_entities = set()
900
+
901
+ # تشخیص زبان
902
+ detected_lang = self.detect_language(original_text)
903
+ logger.info(f"Detected language: {detected_lang}")
904
+
905
+ # مرحله 1: استخراج با Local NER
906
+ if self.models_loaded:
907
+ logger.info("🤖 Running comprehensive local NER extraction...")
908
+ ner_entities = self.extract_entities_with_ner(original_text, detected_lang)
909
+
910
+ for entity in ner_entities:
911
+ if (entity['text'] not in found_entities and
912
+ len(entity['text'].strip()) > 1 and
913
+ entity['confidence'] > 0.5):
914
+
915
+ category = self.map_ner_to_categories(entity['label'], entity['source'])
916
+
917
+ if entity['text'] not in self.mapping_table:
918
+ self.counters[category] += 1
919
+ code = f"{category}_{self.counters[category]:03d}_LOCAL_NER"
920
+ self.mapping_table[entity['text']] = code
921
+ found_entities.add(entity['text'])
922
+ logger.info(f"Local NER: {entity['text']} -> {code}")
923
+ else:
924
+ logger.info("ℹ️ Using comprehensive regex-only mode")
925
+
926
+ # مرحله 2: الگوهای Regex جامع - 221 الگو
927
+ patterns = self.get_comprehensive_patterns()
928
+
929
+ # پردازش patterns با اولویت‌بندی - از خاص به عام
930
+ logger.info("🔍 Running comprehensive priority-based regex extraction...")
931
+
932
+ # پردازش به ترتیب اولویت برای جلوگیری از تداخل
933
+ processed_entities = set() # برای جلوگیری از تکرار
934
+
935
+ # اولویت‌بندی دسته‌ها بر اساس حساسیت
936
+ priority_order = [
937
+ 'ID_NUMBER', 'EMAIL', 'PHONE', 'ACCOUNT', 'TECHNICAL_CODES',
938
+ 'NETWORK_ADDRESSES', 'INTERNATIONAL_CURRENCIES', 'AMOUNT',
939
+ 'TECHNICAL_UNITS', 'ACRONYMS_ABBREVIATIONS', 'ADVANCED_DATE_FORMATS',
940
+ 'TIME_RANGES', 'COMPLEX_ADDRESSES', 'MIXED_NAMES', 'ENGLISH_TITLES',
941
+ 'STOCK_SYMBOL', 'COMPANY', 'PERSON', 'PERCENTAGE', 'VOLUME',
942
+ 'RATIOS', 'LOCATION', 'DATE', 'FINANCIAL_TERMS', 'BUSINESS_TERMS',
943
+ 'PRODUCT', 'PETROCHEMICAL'
944
+ ]
945
+
946
+ for category in priority_order:
947
+ if category in patterns:
948
+ pattern_list = patterns[category]
949
+ for pattern in pattern_list:
950
+ matches = re.finditer(pattern, original_text, re.IGNORECASE | re.MULTILINE)
951
+ for match in matches:
952
+ if match.groups():
953
+ item = match.group(1).strip()
954
+ full_match = match.group(0).strip()
955
+ else:
956
+ item = match.group(0).strip()
957
+ full_match = item
958
+
959
+ # بررسی تداخل با entities قبلی
960
+ overlaps = False
961
+ match_start, match_end = match.span()
962
+
963
+ for proc_start, proc_end in processed_entities:
964
+ # بررسی تداخل موقعیت
965
+ if not (match_end <= proc_start or match_start >= proc_end):
966
+ overlaps = True
967
+ break
968
+
969
+ if (not overlaps and
970
+ full_match not in found_entities and
971
+ full_match not in self.mapping_table and
972
+ len(full_match) >= 2):
973
+
974
+ self.counters[category] += 1
975
+ code = f"{category}_{self.counters[category]:03d}_REGEX"
976
+ self.mapping_table[full_match] = code
977
+ found_entities.add(full_match)
978
+ processed_entities.add((match_start, match_end))
979
+ logger.info(f"Regex ({category}): {full_match} -> {code}")
980
+
981
+ # جایگزینی در متن با ترتیب طولانی‌ترین اول
982
+ sorted_items = sorted(self.mapping_table.items(), key=lambda x: len(x[0]), reverse=True)
983
+ for original_item, code in sorted_items:
984
+ anonymized = anonymized.replace(original_item, code)
985
+
986
+ logger.info(f"✅ Comprehensive anonymization completed. Found {len(self.mapping_table)} entities.")
987
+ return anonymized
988
+
989
+ except Exception as e:
990
+ return f"❌ Error in anonymization: {str(e)}" if lang == 'en' else f"❌ خطا در ناشناس‌سازی: {str(e)}"
991
+
992
+ def send_to_chatgpt(self, anonymized_text, lang='fa'):
993
+ """گام 2: ارسال به ChatGPT"""
994
+ try:
995
+ if not anonymized_text or not anonymized_text.strip():
996
+ return "❌ Anonymized text is empty!" if lang == 'en' else "❌ متن ناشناس‌شده خالی است!"
997
+
998
+ if not self.api_key:
999
+ return "❌ API Key not configured! Please set OPENAI_API_KEY environment variable." if lang == 'en' else "❌ کلید API تنظیم نشده است! لطفاً OPENAI_API_KEY را در متغیرهای محیطی تنظیم کنید."
1000
+
1001
+ system_msg = "You are a professional financial analyst. The text contains anonymous codes. Answer questions accurately." if lang == 'en' else "شما یک تحلیلگر مالی حرفه‌ای هستید. متن حاوی کدهای ناشناس است. به سوالات با دقت پاسخ دهید."
1002
+
1003
+ headers = {
1004
+ "Authorization": f"Bearer {self.api_key}",
1005
+ "Content-Type": "application/json"
1006
+ }
1007
+
1008
+ data = {
1009
+ "model": "gpt-4o-mini",
1010
+ "messages": [
1011
+ {"role": "system", "content": system_msg},
1012
+ {"role": "user", "content": anonymized_text}
1013
+ ],
1014
+ "max_tokens": 2000,
1015
+ "temperature": 0.7
1016
+ }
1017
+
1018
+ response = requests.post(
1019
+ "https://api.openai.com/v1/chat/completions",
1020
+ headers=headers,
1021
+ json=data,
1022
+ timeout=30
1023
+ )
1024
+
1025
+ if response.status_code == 200:
1026
+ result = response.json()
1027
+ return result['choices'][0]['message']['content']
1028
+ else:
1029
+ error_data = response.json() if response.content else {}
1030
+ error_message = error_data.get('error', {}).get('message', response.text)
1031
+
1032
+ if 'Incorrect API key' in error_message:
1033
+ return "❌ Invalid API key." if lang == 'en' else "❌ کلید API نامعتبر است."
1034
+ elif 'quota' in error_message:
1035
+ return "❌ API quota exceeded." if lang == 'en' else "❌ سهمیه API تمام شده است."
1036
+ else:
1037
+ return f"❌ API Error: {error_message}"
1038
+
1039
+ except Exception as e:
1040
+ return f"❌ Error connecting to ChatGPT: {str(e)}" if lang == 'en' else f"❌ خطا در ارتباط با ChatGPT: {str(e)}"
1041
+
1042
+ def deanonymize_response(self, gpt_response, lang='fa'):
1043
+ """گام 3: بازگردانی"""
1044
+ try:
1045
+ if not gpt_response or not gpt_response.strip():
1046
+ return "❌ ChatGPT response is empty!" if lang == 'en' else "❌ پاسخ ChatGPT خالی است!"
1047
+
1048
+ if not self.mapping_table:
1049
+ return "❌ Mapping table is empty!" if lang == 'en' else "❌ جدول نگاشت خالی است!"
1050
+
1051
+ final_result = gpt_response
1052
+ reverse_mapping = {code: original for original, code in self.mapping_table.items()}
1053
+
1054
+ sorted_codes = sorted(reverse_mapping.items(), key=lambda x: len(x[0]), reverse=True)
1055
+ for code, original in sorted_codes:
1056
+ final_result = final_result.replace(code, original)
1057
+ escaped_code = code.replace('_', '\\_')
1058
+ final_result = final_result.replace(escaped_code, original)
1059
+
1060
+ return final_result
1061
+
1062
+ except Exception as e:
1063
+ return f"❌ Deanonymization error: {str(e)}" if lang == 'en' else f"❌ خطا در بازگردانی: {str(e)}"
1064
+
1065
+ def get_model_status(self):
1066
+ """وضعیت مدل‌های محلی"""
1067
+ status = "🤖 **Refined Anonymization System Status (Enhanced with Precision Detection):**\n\n"
1068
+
1069
+ if hasattr(self, 'model_status') and self.model_status:
1070
+ for model_type, model_status in self.model_status.items():
1071
+ if model_type == 'persian':
1072
+ status += f"• **Persian NER**: {model_status}\n"
1073
+ elif model_type == 'english':
1074
+ status += f"• **English NER**: {model_status}\n"
1075
+ elif model_type == 'transformers':
1076
+ status += f"• **Transformers**: {model_status}\n"
1077
+ elif model_type == 'fallback':
1078
+ status += f"• **Fallback Mode**: {model_status}\n"
1079
+ elif model_type == 'critical':
1080
+ status += f"• **Critical**: {model_status}\n"
1081
+ elif model_type == 'directory':
1082
+ status += f"• **Directory**: {model_status}\n"
1083
+
1084
+ loaded_count = sum(1 for status in getattr(self, 'model_status', {}).values()
1085
+ if status.startswith("✅"))
1086
+ status += f"\n📊 **Summary**: {loaded_count}/2 local models loaded"
1087
+
1088
+ status += f"\n📁 **Models Path**: {self.models_base_path}"
1089
+ status += f"\n🔧 **Latest Features**: Refined precision detection with validation"
1090
+
1091
+ status += f"\n\n🎯 **Refined Sensitive Data Detection (High Precision):**"
1092
+
1093
+ # اطلاعات حساس اولویت‌دار
1094
+ status += f"\n\n🔐 **High-Priority Sensitive Data:**"
1095
+ status += f"\n 🆔 **ID_NUMBER**: کد ملی، شبا، کارت بانکی، SSN"
1096
+ status += f"\n 📧 **EMAIL**: آدرس‌های ایمیل معتبر"
1097
+ status += f"\n 📞 **PHONE**: شماره تلفن و موبایل"
1098
+ status += f"\n 🏦 **ACCOUNT**: شماره حساب‌های بانکی"
1099
+ status += f"\n 💰 **AMOUNT**: مبالغ مالی دقیق"
1100
+ status += f"\n 📅 **DATE**: تاریخ‌های معتبر"
1101
+
1102
+ # اطلاعات کسب‌وکار
1103
+ status += f"\n\n💼 **Business & Personal Data:**"
1104
+ status += f"\n 👤 **PERSON**: نام‌ها با عناوین مشخص"
1105
+ status += f"\n 🏢 **COMPANY**: شرکت‌ها و بانک‌ها"
1106
+ status += f"\n 📍 **LOCATION**: آدرس‌های دقیق"
1107
+ status += f("\n 📊 **PERCENTAGE**: درصدها و نسبت‌ها")
1108
+ status += f"\n 📦 **VOLUME**: حجم‌ها و واحدهای اندازه‌گیری"
1109
+
1110
+ # اطلاعات فنی
1111
+ status += f"\n\n⚙️ **Technical Information:**"
1112
+ status += f"\n 🔢 **TECHNICAL_CODES**: کدهای سریال و مرجع"
1113
+ status += f"\n 🌐 **NETWORK_ADDRESSES**: IP و MAC addresses"
1114
+ status += f("\n 🏆 **STOCK_SYMBOL**: نمادهای بورسی")
1115
+
1116
+ status += f"\n\n✨ **Key Improvements:**"
1117
+ status += f"\n 🎯 **Precision-focused**: فقط اطلاعات واقعاً حساس"
1118
+ status += f"\n 🛡️ **Validation system**: فیلتر کلمات رایج"
1119
+ status += f"\n 🔍 **Context-aware**: الگوهای دقیق‌تر"
1120
+ status += f"\n 📝 **Blacklist filtering**: حذف کلمات عمومی"
1121
+ status += f"\n ⚡ **High accuracy**: کاهش false positives"
1122
+
1123
+ status += f"\n\n📋 **Blacklisted Common Words:**"
1124
+ status += f"\n • حروف ربط: با، در، از، به، را، که، است"
1125
+ status += f"\n • کلمات مکانی: خیابان، کوچه، پلاک، طبقه"
1126
+ status += f"\n • کلمات مالی: حساب، کارت، مبلغ، تومان"
1127
+ status += f"\n • افعال: نموده، کرده، ارائه، اعلام"
1128
+
1129
+ return status
1130
+
1131
+ def process_all_steps(input_text, language):
1132
+ """پردازش خودکار تمام مراحل با دقت بالا"""
1133
+ lang = 'en' if language == 'English' else 'fa'
1134
+
1135
+ if not input_text.strip():
1136
+ error_msg = "❌ Please enter input text!" if lang == 'en' else "❌ لطفاً متن ورودی را وارد کنید!"
1137
+ return error_msg, "", "", ""
1138
+
1139
+ try:
1140
+ start_time = time.time()
1141
+
1142
+ anonymized_text = anonymizer.anonymize_text(input_text, lang)
1143
+ if anonymized_text.startswith("❌"):
1144
+ return anonymized_text, "", "", ""
1145
+
1146
+ gpt_response = anonymizer.send_to_chatgpt(anonymized_text, lang)
1147
+ if gpt_response.startswith("❌"):
1148
+ entities_found = len(anonymizer.mapping_table)
1149
+ ner_count = sum(1 for code in anonymizer.mapping_table.values() if '_NER' in code)
1150
+ regex_count = sum(1 for code in anonymizer.mapping_table.values() if '_REGEX' in code)
1151
+
1152
+ # آمار اطلاعات حساس
1153
+ critical_categories = ['ID_NUMBER', 'EMAIL', 'PHONE', 'ACCOUNT', 'AMOUNT', 'DATE']
1154
+ critical_count = sum(1 for code in anonymizer.mapping_table.values()
1155
+ if any(cat in code for cat in critical_categories))
1156
+
1157
+ method = "Refined Local NER + Precision Regex" if anonymizer.models_loaded else "Refined Precision Regex Only"
1158
+ success_msg = (f"✅ Refined anonymization completed with {method}!\n"
1159
+ f"🔐 Critical data protected: {critical_count} | 🤖 NER: {ner_count} | 🔍 Regex: {regex_count}\n"
1160
+ f"📊 Total valid entities: {entities_found} (with precision filtering)")
1161
+ return success_msg, anonymized_text, gpt_response, ""
1162
+
1163
+ final_result = anonymizer.deanonymize_response(gpt_response, lang)
1164
+
1165
+ total_time = time.time() - start_time
1166
+ entities_found = len(anonymizer.mapping_table)
1167
+ ner_count = sum(1 for code in anonymizer.mapping_table.values() if '_NER' in code)
1168
+ regex_count = sum(1 for code in anonymizer.mapping_table.values() if '_REGEX' in code)
1169
+
1170
+ # آمار تفصیلی اطلاعات حساس
1171
+ id_count = sum(1 for code in anonymizer.mapping_table.values() if 'ID_NUMBER' in code)
1172
+ email_count = sum(1 for code in anonymizer.mapping_table.values() if 'EMAIL' in code)
1173
+ phone_count = sum(1 for code in anonymizer.mapping_table.values() if 'PHONE' in code)
1174
+ account_count = sum(1 for code in anonymizer.mapping_table.values() if 'ACCOUNT' in code)
1175
+ amount_count = sum(1 for code in anonymizer.mapping_table.values() if 'AMOUNT' in code)
1176
+ person_count = sum(1 for code in anonymizer.mapping_table.values() if 'PERSON' in code)
1177
+
1178
+ critical_details = []
1179
+ if id_count > 0: critical_details.append(f"🆔 IDs: {id_count}")
1180
+ if phone_count > 0: critical_details.append(f"📞 Phones: {phone_count}")
1181
+ if email_count > 0: critical_details.append(f"📧 Emails: {email_count}")
1182
+ if account_count > 0: critical_details.append(f"🏦 Accounts: {account_count}")
1183
+ if amount_count > 0: critical_details.append(f"💰 Amounts: {amount_count}")
1184
+ if person_count > 0: critical_details.append(f"👤 Names: {person_count}")
1185
+
1186
+ method = "Refined Local NER + Precision Regex" if anonymizer.models_loaded else "Refined Precision Regex Only"
1187
+ success_msg = (f"🎉 Complete refined anonymization & restoration successful!\n"
1188
+ f"🔧 Method: {method}\n"
1189
+ f"🔐 Protected data: {' | '.join(critical_details) if critical_details else '0'}\n"
1190
+ f"📊 Total: {entities_found} entities | ⏱️ Time: {total_time:.2f}s | 🎯 High precision")
1191
+
1192
+ return success_msg, anonymized_text, gpt_response, final_result
1193
+
1194
+ except Exception as e:
1195
+ error_msg = f"❌ Processing error: {str(e)}" if lang == 'en' else f"❌ خطا در پردازش: {str(e)}"
1196
+ return error_msg, "", "", ""
1197
+
1198
+ def get_mapping_table(language):
1199
+ """نمایش جدول نگاشت"""
1200
+ lang = 'en' if language == 'English' else 'fa'
1201
+
1202
+ if not anonymizer.mapping_table:
1203
+ return "❌ Mapping table is empty! Please process some text first." if lang == 'en' else "❌ جدول نگاشت خالی است! ابتدا متنی را پردازش کنید."
1204
+
1205
+ result = "📋 **Refined High-Precision Sensitive Data Mapping Table:**\n\n" if lang == 'en' else "📋 **جدول نگاشت دقیق اطلاعات حساس:**\n\n"
1206
+
1207
+ ner_items = {k: v for k, v in anonymizer.mapping_table.items() if '_NER' in v}
1208
+ regex_items = {k: v for k, v in anonymizer.mapping_table.items() if '_REGEX' in v}
1209
+
1210
+ # دسته‌بندی بر اساس اولویت حساسیت
1211
+ critical_categories = {
1212
+ 'ID_NUMBER': '🆔 **Identity Codes (Critical)**',
1213
+ 'PHONE': '📞 **Phone Numbers**',
1214
+ 'EMAIL': '📧 **Email Addresses**',
1215
+ 'ACCOUNT': '🏦 **Bank Accounts**',
1216
+ 'AMOUNT': '💰 **Financial Amounts**',
1217
+ 'DATE': '📅 **Dates**'
1218
+ }
1219
+
1220
+ business_categories = {
1221
+ 'PERSON': '👤 **Person Names**',
1222
+ 'COMPANY': '🏢 **Companies**',
1223
+ 'LOCATION': '📍 **Locations**',
1224
+ 'PERCENTAGE': '📊 **Percentages**',
1225
+ 'VOLUME': '📦 **Volumes & Units**',
1226
+ 'STOCK_SYMBOL': '🏆 **Stock Symbols**'
1227
+ }
1228
+
1229
+ technical_categories = {
1230
+ 'TECHNICAL_CODES': '⚙️ **Technical Codes**',
1231
+ 'NETWORK_ADDRESSES': '🌐 **Network Addresses**'
1232
+ }
1233
+
1234
+ # نمایش دسته‌های حساس
1235
+ for category, title in critical_categories.items():
1236
+ category_items = {k: v for k, v in anonymizer.mapping_table.items() if category in v}
1237
+ if category_items:
1238
+ result += f"{title}:\n"
1239
+ for original, code in list(category_items.items())[:5]:
1240
+ result += f" • `{original}` → `{code}`\n"
1241
+ if len(category_items) > 5:
1242
+ result += f" ... و {len(category_items) - 5} مورد دیگر\n"
1243
+ result += "\n"
1244
+
1245
+ # نمایش NER results
1246
+ if ner_items:
1247
+ result += "🤖 **Local NER Detected**:\n"
1248
+ for original, code in list(ner_items.items())[:5]:
1249
+ result += f" • `{original}` → `{code}`\n"
1250
+ if len(ner_items) > 5:
1251
+ result += f" ... و {len(ner_items) - 5} مورد دیگر\n"
1252
+ result += "\n"
1253
+
1254
+ # نمایش دسته‌های کسب‌وکار
1255
+ business_items = {k: v for k, v in regex_items.items()
1256
+ if any(cat in v for cat in business_categories.keys())}
1257
+ if business_items:
1258
+ result += "💼 **Business Data**:\n"
1259
+ for original, code in list(business_items.items())[:8]:
1260
+ result += f" • `{original}` → `{code}`\n"
1261
+ if len(business_items) > 8:
1262
+ result += f" ... و {len(business_items) - 8} مورد دیگر\n"
1263
+ result += "\n"
1264
+
1265
+ # نمایش دسته‌های فنی
1266
+ technical_items = {k: v for k, v in regex_items.items()
1267
+ if any(cat in v for cat in technical_categories.keys())}
1268
+ if technical_items:
1269
+ result += "⚙️ **Technical Data**:\n"
1270
+ for original, code in list(technical_items.items())[:5]:
1271
+ result += f" • `{original}` → `{code}`\n"
1272
+ if len(technical_items) > 5:
1273
+ result += f" ... و {len(technical_items) - 5} مورد دیگر\n"
1274
+ result += "\n"
1275
+
1276
+ # آمار کلی
1277
+ critical_count = sum(len({k: v for k, v in anonymizer.mapping_table.items() if cat in v})
1278
+ for cat in critical_categories.keys())
1279
+
1280
+ result += f"📊 **Refined Statistics**:\n"
1281
+ result += f"🔐 **Critical Sensitive Data**: {critical_count} items\n"
1282
+ result += f"🤖 **NER Detected**: {len(ner_items)} items\n"
1283
+ result += f"💼 **Business Data**: {len(business_items)} items\n"
1284
+ result += f"⚙️ **Technical Data**: {len(technical_items)} items\n"
1285
+ result += f"📋 **Total Protected**: {len(anonymizer.mapping_table)} entities\n"
1286
+
1287
+ result += f"\n✨ **System Enhancement**: High-precision detection with validation\n"
1288
+ result += f"🎯 **Accuracy**: Minimized false positives with blacklist filtering\n"
1289
+ result += f"🛡️ **Protection Level**: Maximum sensitive data security with readable text!"
1290
+
1291
+ return result
1292
+
1293
+ def clear_all():
1294
+ """پاک کردن همه"""
1295
+ anonymizer.mapping_table = {}
1296
+ anonymizer.counters = {key: 0 for key in anonymizer.counters.keys()}
1297
+ return "", "", "", "", ""
1298
+
1299
+ def update_ui_text(language):
1300
+ """به‌روزرسانی متن‌های رابط کاربری"""
1301
+ if language == 'English':
1302
+ return {
1303
+ 'title': 'Refined High-Precision Bilingual Data Anonymization System',
1304
+ 'step1': 'Input Text & Settings',
1305
+ 'step2': 'Anonymized Text',
1306
+ 'step3': 'Raw ChatGPT Response',
1307
+ 'step4': 'Final Restored Response',
1308
+ 'input_placeholder': 'Enter your original text here...\nExample: Company reports, person names, financial amounts, phone numbers, emails, IBAN codes, bank accounts, etc.\n\n✨ Refined system with high precision detection and validation!',
1309
+ 'process_btn': 'Process with High-Precision Detection',
1310
+ 'clear_btn': 'Clear All',
1311
+ 'mapping_btn': 'Show High-Precision Mapping Table',
1312
+ 'status_btn': 'Show System Status',
1313
+ 'copy_btn': 'Copy',
1314
+ 'direction': 'ltr'
1315
+ }
1316
+ else:
1317
+ return {
1318
+ 'title': 'سیستم ناشناس‌سازی دقیق دوزبانه',
1319
+ 'step1': 'متن ورودی و تنظیمات',
1320
+ 'step2': 'متن ناشناس‌شده',
1321
+ 'step3': 'پاسخ خام ChatGPT',
1322
+ 'step4': 'پاسخ نهایی بازگردانده شده',
1323
+ 'input_placeholder': 'متن اصلی خود را اینجا وارد کنید...\nمثال: گزارش‌های شرکت، نام اشخاص، مبالغ مالی، شماره تلفن، ایمیل، شماره شبا، حساب بانکی و غیره\n\n✨ سیستم دقیق با تشخیص حساس و validation!',
1324
+ 'process_btn': 'پردازش با تشخیص دقیق',
1325
+ 'clear_btn': 'پاک کردن همه',
1326
+ 'mapping_btn': 'نمایش جدول نگاشت دقیق',
1327
+ 'status_btn': 'نمایش وضعیت سیستم',
1328
+ 'copy_btn': 'کپی',
1329
+ 'direction': 'rtl'
1330
+ }
1331
+
1332
+ def update_interface(language):
1333
+ """تغییر رابط کاربری بر اساس زبان"""
1334
+ ui_text = update_ui_text(language)
1335
+ is_english = (language == 'English')
1336
+
1337
+ # تغییر direction برای workflow
1338
+ workflow_css = "workflow ltr" if is_english else "workflow rtl"
1339
+
1340
+ return [
1341
+ gr.update(value=f"<h1 style='text-align: center; color: #FFD700; font-size: 3.5em; font-weight: bold; text-shadow: 3px 3px 6px rgba(0,0,0,0.5); margin: 20px 0; background: linear-gradient(45deg, #FFD700, #FFA500); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;'>📊 {ui_text['title']}</h1>"),
1342
+ gr.update(value=f"<h2 style='direction: {ui_text['direction']};'>🔍 {ui_text['step1']}</h2>"),
1343
+ gr.update(placeholder=ui_text['input_placeholder'], rtl=not is_english),
1344
+ gr.update(value=f"🚀 {ui_text['process_btn']}"),
1345
+ gr.update(value=f"🗑️ {ui_text['clear_btn']}"),
1346
+ gr.update(rtl=not is_english),
1347
+ gr.update(value=f"<h2 style='direction: {ui_text['direction']};'>🎭 {ui_text['step2']}</h2>"),
1348
+ gr.update(rtl=not is_english),
1349
+ gr.update(value=f"<h2 style='direction: {ui_text['direction']};'>🤖 {ui_text['step3']}</h2>"),
1350
+ gr.update(rtl=not is_english),
1351
+ gr.update(value=f"<h2 style='direction: {ui_text['direction']};'>✅ {ui_text['step4']}</h2>"),
1352
+ gr.update(rtl=not is_english),
1353
+ gr.update(value=f"📋 {ui_text['mapping_btn']}"),
1354
+ gr.update(value=f"📊 {ui_text['status_btn']}"),
1355
+ gr.update(rtl=not is_english),
1356
+ gr.update(elem_classes=workflow_css)
1357
+ ]
1358
+
1359
+ # ایجاد instance
1360
+ anonymizer = ComprehensiveBilingualDataAnonymizer()
1361
+
1362
+ # CSS اصلاح شده برای تراز‌بندی عمودی مناسب
1363
+ custom_css = """
1364
+ body, .gradio-container {
1365
+ font-family: 'Segoe UI', Tahoma, Arial, sans-serif !important;
1366
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
1367
+ min-height: 100vh !important;
1368
+ padding: 20px !important;
1369
+ }
1370
+
1371
+ .rtl {
1372
+ direction: rtl !important;
1373
+ text-align: right !important;
1374
+ }
1375
+
1376
+ .ltr {
1377
+ direction: ltr !important;
1378
+ text-align: left !important;
1379
+ }
1380
+
1381
+ .workflow {
1382
+ display: grid !important;
1383
+ grid-template-columns: 1fr 1fr 1fr 1fr !important;
1384
+ gap: 25px !important;
1385
+ padding: 30px !important;
1386
+ align-items: start !important;
1387
+ align-content: start !important;
1388
+ grid-auto-rows: auto !important;
1389
+ }
1390
+
1391
+ .workflow > * {
1392
+ align-self: start !important;
1393
+ vertical-align: top !important;
1394
+ margin-top: 0 !important;
1395
+ }
1396
+
1397
+ .workflow .gradio-column,
1398
+ .workflow-column {
1399
+ display: flex !important;
1400
+ flex-direction: column !important;
1401
+ align-items: stretch !important;
1402
+ justify-content: flex-start !important;
1403
+ height: auto !important;
1404
+ min-height: 0 !important;
1405
+ margin-top: 0 !important;
1406
+ padding-top: 0 !important;
1407
+ }
1408
+
1409
+ .gradio-textbox {
1410
+ border-radius: 10px !important;
1411
+ box-shadow: 0 4px 15px rgba(0,0,0,0.1) !important;
1412
+ flex-grow: 1 !important;
1413
+ min-height: 380px !important;
1414
+ max-height: 380px !important;
1415
+ height: 380px !important;
1416
+ }
1417
+
1418
+ .gradio-textbox textarea {
1419
+ min-height: 350px !important;
1420
+ max-height: 350px !important;
1421
+ height: 350px !important;
1422
+ resize: vertical !important;
1423
+ }
1424
+
1425
+ .workflow.rtl {
1426
+ direction: rtl !important;
1427
+ }
1428
+
1429
+ .workflow.ltr {
1430
+ direction: ltr !important;
1431
+ }
1432
+
1433
+ h1, h2, h3 {
1434
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3) !important;
1435
+ margin-top: 0 !important;
1436
+ margin-bottom: 10px !important;
1437
+ padding-top: 0 !important;
1438
+ line-height: 1.2 !important;
1439
+ }
1440
+
1441
+ h2 {
1442
+ min-height: 40px !important;
1443
+ max-height: 40px !important;
1444
+ display: flex !important;
1445
+ align-items: center !important;
1446
+ margin-bottom: 15px !important;
1447
+ }
1448
+
1449
+ .status-box {
1450
+ background: linear-gradient(135deg, #4CAF50, #45a049) !important;
1451
+ border: 3px solid #2E7D32 !important;
1452
+ border-radius: 15px !important;
1453
+ padding: 15px !important;
1454
+ margin: 10px 0 !important;
1455
+ box-shadow: 0 8px 32px rgba(76, 175, 80, 0.3) !important;
1456
+ animation: pulse 2s infinite !important;
1457
+ min-height: 120px !important;
1458
+ max-height: 120px !important;
1459
+ }
1460
+
1461
+ .status-box textarea {
1462
+ background: rgba(255, 255, 255, 0.95) !important;
1463
+ border: none !important;
1464
+ border-radius: 10px !important;
1465
+ font-weight: bold !important;
1466
+ font-size: 1.1em !important;
1467
+ color: #1B5E20 !important;
1468
+ text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8) !important;
1469
+ min-height: 80px !important;
1470
+ max-height: 80px !important;
1471
+ }
1472
+
1473
+ @keyframes pulse {
1474
+ 0% { box-shadow: 0 8px 32px rgba(76, 175, 80, 0.3); }
1475
+ 50% { box-shadow: 0 8px 40px rgba(76, 175, 80, 0.6); }
1476
+ 100% { box-shadow: 0 8px 32px rgba(76, 175, 80, 0.3); }
1477
+ }
1478
+
1479
+ .gradio-button {
1480
+ border-radius: 25px !important;
1481
+ font-weight: bold !important;
1482
+ transition: all 0.3s ease !important;
1483
+ margin: 5px 0 !important;
1484
+ min-height: 50px !important;
1485
+ max-height: 50px !important;
1486
+ }
1487
+
1488
+ .gradio-button:hover {
1489
+ transform: translateY(-2px) !important;
1490
+ box-shadow: 0 6px 20px rgba(0,0,0,0.2) !important;
1491
+ }
1492
+
1493
+ h1 {
1494
+ background: linear-gradient(45deg, #FFD700, #FFA500) !important;
1495
+ -webkit-background-clip: text !important;
1496
+ -webkit-text-fill-color: transparent !important;
1497
+ background-clip: text !important;
1498
+ min-height: 80px !important;
1499
+ }
1500
+
1501
+ @media (max-width: 1200px) {
1502
+ .workflow {
1503
+ grid-template-columns: 1fr 1fr !important;
1504
+ gap: 20px !important;
1505
+ }
1506
+ }
1507
+
1508
+ @media (max-width: 768px) {
1509
+ .workflow {
1510
+ grid-template-columns: 1fr !important;
1511
+ gap: 15px !important;
1512
+ }
1513
+
1514
+ .gradio-textbox {
1515
+ min-height: 300px !important;
1516
+ max-height: 300px !important;
1517
+ height: 300px !important;
1518
+ }
1519
+ }
1520
+
1521
+ [data-testid="textbox"]:dir(rtl) {
1522
+ text-align: right !important;
1523
+ direction: rtl !important;
1524
+ }
1525
+
1526
+ [data-testid="textbox"]:dir(ltr) {
1527
+ text-align: left !important;
1528
+ direction: ltr !important;
1529
+ }
1530
+
1531
+ .gradio-container .gradio-column {
1532
+ align-self: start !important;
1533
+ vertical-align: top !important;
1534
+ }
1535
+
1536
+ .gradio-container .gradio-row {
1537
+ align-items: flex-start !important;
1538
+ }
1539
+
1540
+ * {
1541
+ box-sizing: border-box !important;
1542
+ }
1543
+
1544
+ .gradio-container {
1545
+ align-items: start !important;
1546
+ justify-content: start !important;
1547
+ }
1548
+ """
1549
+
1550
+ # رابط کاربری Gradio با تراز‌بندی اصلاح شده
1551
+ with gr.Blocks(title="📊 Refined High-Precision Anonymization System", theme=gr.themes.Soft(), css=custom_css) as app:
1552
+
1553
+ with gr.Row():
1554
+ language_selector = gr.Radio(
1555
+ choices=["فارسی", "English"],
1556
+ value="فارسی",
1557
+ label="Language / زبان",
1558
+ interactive=True
1559
+ )
1560
+
1561
+ with gr.Column():
1562
+ title = gr.HTML("<h1 style='text-align: center; color: #FFD700; font-size: 3.5em; font-weight: bold; text-shadow: 3px 3px 6px rgba(0,0,0,0.5); margin: 20px 0; background: linear-gradient(45deg, #FFD700, #FFA500); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;'>📊 سیستم ناشناس‌سازی دقیق دوزبانه</h1>")
1563
+
1564
+ with gr.Row(elem_classes="workflow rtl") as workflow_row:
1565
+ with gr.Column(elem_classes="workflow-column"):
1566
+ step1_title = gr.HTML('<h2 style="direction: rtl;">🔍 متن ورودی و تنظیمات</h2>')
1567
+
1568
+ input_text = gr.Textbox(
1569
+ lines=15,
1570
+ placeholder="متن اصلی خود را اینجا وارد کنید...\nمثال: گزارش‌های شرکت، نام اشخاص، مبالغ مالی، شماره تلفن، ایمیل، شماره شبا، حساب بانکی و غیره\n\n✨ سیستم دقیق با تشخیص حساس و validation!",
1571
+ label="",
1572
+ rtl=True
1573
+ )
1574
+
1575
+ process_btn = gr.Button("🚀 پردازش با تشخیص دقیق", variant="primary")
1576
+ clear_btn = gr.Button("🗑️ پاک کردن همه", variant="stop")
1577
+
1578
+ status = gr.Textbox(
1579
+ label="وضعیت",
1580
+ lines=4,
1581
+ interactive=False,
1582
+ rtl=True,
1583
+ elem_classes=["status-box"]
1584
+ )
1585
+
1586
+ with gr.Column(elem_classes="workflow-column"):
1587
+ step2_title = gr.HTML('<h2 style="direction: rtl;">🎭 متن ناشناس‌شده</h2>')
1588
+
1589
+ anonymized_output = gr.Textbox(
1590
+ lines=15,
1591
+ placeholder="متن ناشناس‌شده اینجا نمایش داده می‌شود...",
1592
+ label="",
1593
+ interactive=False,
1594
+ rtl=True
1595
+ )
1596
+
1597
+ with gr.Column(elem_classes="workflow-column"):
1598
+ step3_title = gr.HTML('<h2 style="direction: rtl;">🤖 پاسخ خام ChatGPT</h2>')
1599
+
1600
+ gpt_output = gr.Textbox(
1601
+ lines=15,
1602
+ placeholder="پاسخ خام ChatGPT اینجا نمایش داده می‌شود...",
1603
+ label="",
1604
+ interactive=False,
1605
+ rtl=True
1606
+ )
1607
+
1608
+ with gr.Column(elem_classes="workflow-column"):
1609
+ step4_title = gr.HTML('<h2 style="direction: rtl;">✅ پاسخ نهایی بازگردانده شده</h2>')
1610
+
1611
+ final_output = gr.Textbox(
1612
+ lines=15,
1613
+ placeholder="پاسخ نهایی اینجا نمایش داده می‌شود...",
1614
+ label="",
1615
+ interactive=False,
1616
+ rtl=True
1617
+ )
1618
+
1619
+ with gr.Row():
1620
+ with gr.Column():
1621
+ mapping_title = gr.HTML('<h2>🗂️ جدول نگاشت دقیق</h2>')
1622
+ mapping_btn = gr.Button("📋 نمایش جدول نگاشت دقیق")
1623
+
1624
+ mapping_output = gr.Textbox(
1625
+ lines=15,
1626
+ label="جدول نگاشت اطلاعات",
1627
+ interactive=False,
1628
+ visible=False,
1629
+ rtl=True
1630
+ )
1631
+
1632
+ with gr.Row():
1633
+ with gr.Column():
1634
+ status_title = gr.HTML('<h2>⚙️ وضعیت سیستم و قابلیت‌ها</h2>')
1635
+ system_status_btn = gr.Button("📊 نمایش وضعیت سیستم دقیق")
1636
+
1637
+ system_status_output = gr.Textbox(
1638
+ lines=20,
1639
+ label="وضعیت سیستم",
1640
+ interactive=False,
1641
+ visible=False,
1642
+ rtl=True
1643
+ )
1644
+
1645
+ # Event handlers
1646
+ language_selector.change(
1647
+ fn=update_interface,
1648
+ inputs=[language_selector],
1649
+ outputs=[title, step1_title, input_text, process_btn, clear_btn,
1650
+ status, step2_title, anonymized_output, step3_title, gpt_output,
1651
+ step4_title, final_output, mapping_btn, system_status_btn,
1652
+ mapping_output, workflow_row]
1653
+ )
1654
+
1655
+ process_btn.click(
1656
+ fn=process_all_steps,
1657
+ inputs=[input_text, language_selector],
1658
+ outputs=[status, anonymized_output, gpt_output, final_output]
1659
+ )
1660
+
1661
+ clear_btn.click(
1662
+ fn=clear_all,
1663
+ outputs=[input_text, anonymized_output, gpt_output, final_output, status]
1664
+ )
1665
+
1666
+ mapping_btn.click(
1667
+ fn=get_mapping_table,
1668
+ inputs=[language_selector],
1669
+ outputs=[mapping_output]
1670
+ )
1671
+
1672
+ mapping_btn.click(
1673
+ fn=lambda: gr.update(visible=True),
1674
+ outputs=[mapping_output]
1675
+ )
1676
+
1677
+ system_status_btn.click(
1678
+ fn=lambda: anonymizer.get_model_status(),
1679
+ outputs=[system_status_output]
1680
+ )
1681
+
1682
+ system_status_btn.click(
1683
+ fn=lambda: gr.update(visible=True),
1684
+ outputs=[system_status_output]
1685
+ )
1686
+
1687
+ if __name__ == "__main__":
1688
+ # نمایش اطلاعات سیستم در startup
1689
+ print("\n" + "="*80)
1690
+ print("🚀 REFINED HIGH-PRECISION BILINGUAL DATA ANONYMIZATION SYSTEM")
1691
+ print("="*80)
1692
+ print("📊 System Features:")
1693
+ print(" • High-precision detection with validation system")
1694
+ print(" • Blacklist filtering for common words")
1695
+ print(" • Priority-based sensitive data protection")
1696
+ print(" • Bilingual support (Persian/English)")
1697
+ print(" • Local NER + Advanced Regex processing")
1698
+ print(" • OpenAI ChatGPT integration")
1699
+ print(" • Complete anonymization-restoration workflow")
1700
+ print("\n🔐 Protected Data Types (High Priority):")
1701
+ print(" • Identity Codes (کد ملی، شبا، کارت بانکی)")
1702
+ print(" • Contact Information (تلفن، ایمیل)")
1703
+ print(" • Financial Data (مبالغ، حساب‌ها)")
1704
+ print(" • Personal Names (با عناوین مشخص)")
1705
+ print(" • Business Information (شرکت‌ها، آدرس‌ها)")
1706
+ print(" • Technical Codes (کدهای سریال، شبکه)")
1707
+ print("\n⚙️ Enhanced Features:")
1708
+ print(" • Validation system prevents false positives")
1709
+ print(" • Common word blacklist filtering")
1710
+ print(" • Context-aware pattern matching")
1711
+ print(" • Overlap detection system")
1712
+ print(" • Persian/Arabic digit support")
1713
+ print(" • Refined accuracy with readable output")
1714
+ print("="*80)
1715
+ print("🎯 Now your text will remain readable while protecting sensitive data!")
1716
+
1717
+ app.launch(
1718
+ share=True,
1719
+ server_name="0.0.0.0",
1720
+ server_port=7860,
1721
+ show_error=True,
1722
+ favicon_path=None,
1723
+ ssl_verify=False
1724
+ )