Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import re
|
| 3 |
import os
|
|
@@ -5,57 +11,43 @@ import requests
|
|
| 5 |
import time
|
| 6 |
import logging
|
| 7 |
|
| 8 |
-
# تنظیم logging
|
| 9 |
logging.basicConfig(level=logging.INFO)
|
| 10 |
logger = logging.getLogger(__name__)
|
| 11 |
|
| 12 |
-
class
|
| 13 |
def __init__(self):
|
| 14 |
self.mapping_table = {}
|
| 15 |
-
# دستهبندیهای الگوها برای UI
|
| 16 |
self.pattern_categories = {
|
| 17 |
'personal_identity': {
|
| 18 |
'name_fa': 'اطلاعات شخصی و هویتی',
|
| 19 |
'name_en': 'Personal & Identity Information',
|
| 20 |
-
'patterns': ['PERSON', '
|
| 21 |
'icon': '👤'
|
| 22 |
},
|
| 23 |
'financial': {
|
| 24 |
'name_fa': 'اطلاعات مالی',
|
| 25 |
'name_en': 'Financial Information',
|
| 26 |
-
'patterns': ['AMOUNT', '
|
| 27 |
'icon': '💰'
|
| 28 |
},
|
| 29 |
'temporal': {
|
| 30 |
'name_fa': 'اطلاعات زمانی',
|
| 31 |
'name_en': 'Temporal Information',
|
| 32 |
-
'patterns': ['DATE'
|
| 33 |
'icon': '📅'
|
| 34 |
},
|
| 35 |
'location': {
|
| 36 |
'name_fa': 'اطلاعات مکانی',
|
| 37 |
'name_en': 'Location Information',
|
| 38 |
-
'patterns': ['LOCATION', '
|
| 39 |
'icon': '📍'
|
| 40 |
},
|
| 41 |
-
'technical': {
|
| 42 |
-
'name_fa': 'اطلاعات فنی و تکنولوژیکی',
|
| 43 |
-
'name_en': 'Technical & Technological',
|
| 44 |
-
'patterns': ['TECHNICAL_CODES', 'NETWORK_ADDRESSES', 'TECHNICAL_UNITS', 'ACRONYMS_ABBREVIATIONS'],
|
| 45 |
-
'icon': '⚙️'
|
| 46 |
-
},
|
| 47 |
'business': {
|
| 48 |
'name_fa': 'اطلاعات کسبوکار',
|
| 49 |
'name_en': 'Business Information',
|
| 50 |
-
'patterns': ['COMPANY', '
|
| 51 |
'icon': '🏢'
|
| 52 |
},
|
| 53 |
-
'quantity': {
|
| 54 |
-
'name_fa': 'اطلاعات کمیت و واحد',
|
| 55 |
-
'name_en': 'Quantity & Unit Information',
|
| 56 |
-
'patterns': ['PERCENTAGE', 'VOLUME', 'RATIOS'],
|
| 57 |
-
'icon': '📊'
|
| 58 |
-
},
|
| 59 |
'communication': {
|
| 60 |
'name_fa': 'اطلاعات ارتباطی',
|
| 61 |
'name_en': 'Communication Information',
|
|
@@ -64,426 +56,134 @@ class LightweightDataAnonymizer:
|
|
| 64 |
}
|
| 65 |
}
|
| 66 |
|
| 67 |
-
# counters
|
| 68 |
self.counters = {
|
| 69 |
-
'PERSON': 0, '
|
| 70 |
-
'AMOUNT': 0, '
|
| 71 |
-
'
|
| 72 |
-
'
|
| 73 |
-
'
|
| 74 |
-
'TECHNICAL_CODES': 0, 'NETWORK_ADDRESSES': 0, 'TECHNICAL_UNITS': 0,
|
| 75 |
-
'ACRONYMS_ABBREVIATIONS': 0,
|
| 76 |
-
'COMPANY': 0, 'BUSINESS_TERMS': 0, 'PRODUCT': 0, 'PETROCHEMICAL': 0,
|
| 77 |
-
'PERCENTAGE': 0, 'VOLUME': 0, 'RATIOS': 0,
|
| 78 |
'PHONE': 0, 'EMAIL': 0
|
| 79 |
}
|
| 80 |
|
| 81 |
self.api_key = os.getenv("OPENAI_API_KEY", "")
|
| 82 |
-
|
| 83 |
-
def get_category_choices(self, language='fa'):
|
| 84 |
-
"""دریافت لیست دستهبندیها برای چکباکس"""
|
| 85 |
-
choices = []
|
| 86 |
-
for cat_key, cat_info in self.pattern_categories.items():
|
| 87 |
-
name = cat_info['name_fa'] if language == 'fa' else cat_info['name_en']
|
| 88 |
-
icon = cat_info['icon']
|
| 89 |
-
choices.append(f"{icon} {name}")
|
| 90 |
-
return choices
|
| 91 |
-
|
| 92 |
-
def get_selected_patterns(self, selected_categories, language='fa'):
|
| 93 |
-
"""تبدیل دستهبندیهای انتخاب شده به لیست الگوها"""
|
| 94 |
-
selected_patterns = []
|
| 95 |
-
|
| 96 |
-
for cat_key, cat_info in self.pattern_categories.items():
|
| 97 |
-
name = cat_info['name_fa'] if language == 'fa' else cat_info['name_en']
|
| 98 |
-
icon = cat_info['icon']
|
| 99 |
-
category_display = f"{icon} {name}"
|
| 100 |
-
|
| 101 |
-
if category_display in selected_categories:
|
| 102 |
-
selected_patterns.extend(cat_info['patterns'])
|
| 103 |
-
|
| 104 |
-
return selected_patterns
|
| 105 |
-
|
| 106 |
-
def detect_language(self, text):
|
| 107 |
-
"""تشخیص زبان متن"""
|
| 108 |
-
if not text:
|
| 109 |
-
return 'fa'
|
| 110 |
-
|
| 111 |
-
persian_chars = len(re.findall(r'[\u0600-\u06FF]', text))
|
| 112 |
-
english_chars = len(re.findall(r'[a-zA-Z]', text))
|
| 113 |
-
total = persian_chars + english_chars
|
| 114 |
-
|
| 115 |
-
if total == 0:
|
| 116 |
-
return 'fa'
|
| 117 |
-
|
| 118 |
-
if persian_chars / total > 0.6:
|
| 119 |
-
return 'fa'
|
| 120 |
-
elif english_chars / total > 0.6:
|
| 121 |
-
return 'en'
|
| 122 |
-
else:
|
| 123 |
-
return 'mixed'
|
| 124 |
|
| 125 |
def get_improved_patterns(self):
|
| 126 |
-
"""الگوهای
|
| 127 |
return {
|
| 128 |
-
#
|
| 129 |
-
'COMPANY': [
|
| 130 |
-
# الگوی اصلی: شرکت + نام کامل (بدون گروهبندی - capture کل)
|
| 131 |
-
r'شرکت\s+پتروشیمی\s+[آ-یی۰-۹a-zA-Z\s]+?(?=\s+مربوط|\s+در|\s+که|\s+با|\s+را|\s+به|،|\.|\s+$)',
|
| 132 |
-
r'شرکت\s+[آ-یی۰-۹a-zA-Z\s]*(?:پتروشیمی|نفت|گاز|صنایع|تولید|بانک)[آ-یی۰-۹a-zA-Z\s]+(?=\s+مربوط|\s+در|\s+که|\s+با|\s+را|\s+به|،|\.|\s+$)',
|
| 133 |
-
|
| 134 |
-
# پتروشیمی + نام
|
| 135 |
-
r'پتروشیمی\s+[آ-یی۰-۹a-zA-Z\s]+?(?=\s+مربوط|\s+در|\s+که|\s+با|\s+را|\s+به|،|\.|\s+$)',
|
| 136 |
-
|
| 137 |
-
# شرکت با اسامی مشخص
|
| 138 |
-
r'شرکت\s+(?:سبهان|غدیر|شتران|شپنا|پترول|فارس|خارک|پلاسکو|جم|کرمان|مارون|اراک|رازی|شازند|کاوه|بندر|پارس|خوزستان|ماهشهر|عسلویه)(?=\s+مربوط|\s+در|\s+که|\s+با|\s+را|\s+به|،|\.|\s+$)',
|
| 139 |
-
|
| 140 |
-
# بانک + نام
|
| 141 |
-
r'بانک\s+[آ-یی۰-۹a-zA-Z\s]+?(?=\s+مربوط|\s+در|\s+که|\s+با|\s+را|\s+به|،|\.|\s+$)',
|
| 142 |
-
|
| 143 |
-
# نام + شرکت (برعکس)
|
| 144 |
-
r'[آ-یی۰-۹a-zA-Z\s]*(?:پتروشیمی|صنایع|تولید|گاز|نفت|بانک)[آ-یی۰-۹a-zA-Z\s]*\s+شرکت(?=\s|$|،|\.)',
|
| 145 |
-
r'پتروشیمی\s+[آ-یی۰-۹a-zA-Z\s]+\s+شرکت(?=\s|$|،|\.)',
|
| 146 |
-
r'بانک\s+[آ-یی۰-۹a-zA-Z\s]+\s+شرکت(?=\s|$|،|\.)',
|
| 147 |
-
|
| 148 |
-
# شرکتهای انگلیسی
|
| 149 |
-
r'[A-Z][a-zA-Z\s]+(?:Inc|Corp|Corporation|Company|Ltd|Limited|LLC)'
|
| 150 |
-
],
|
| 151 |
-
|
| 152 |
-
# مکانها
|
| 153 |
-
'LOCATION': [
|
| 154 |
-
# بندر + نام شهر (بدون گروه - capture کل)
|
| 155 |
-
r'بندر\s+[آ-یی۰-۹a-zA-Z\s]+?(?=\s+برگزار|\s+واقع|\s+در|،|\.|\s+$)',
|
| 156 |
-
# شهرهای مهم ایران
|
| 157 |
-
r'\b(?:تهران|اصفهان|ماهشهر|عسلویه|بندرعباس|اهواز|شیراز|مشهد|تبریز|کرج|قم|رشت|کرمان|یزد|زاهدان|بوشهر|خرمشهر|آبادان|اراک|قزوین)\b(?=\s+برگزار|\s+واقع|\s|$|،|\.)',
|
| 158 |
-
# استان + نام
|
| 159 |
-
r'استان\s+[آ-یی\s]+?(?=\s+واقع|\s+در|،|\.|\s+$)',
|
| 160 |
-
# شهر + نام
|
| 161 |
-
r'شهر\s+[آ-یی\s]+?(?=\s+واقع|\s+در|،|\.|\s+$)',
|
| 162 |
-
# کشورها
|
| 163 |
-
r'\b(?:ایران|عراق|کویت|عربستان|امارات|قطر|عمان|بحریں|ترکیه|پاکستان|افغانستان)\b',
|
| 164 |
-
# شهرهای خارجی
|
| 165 |
-
r'\b(?:London|Paris|Tokyo|New\s+York|Dubai|Singapore|Hong\s+Kong|Shanghai|Mumbai|Frankfurt|Amsterdam)\b'
|
| 166 |
-
],
|
| 167 |
-
|
| 168 |
-
# تاریخها
|
| 169 |
-
'DATE': [
|
| 170 |
-
# سال مالی منتهی به
|
| 171 |
-
r'سال\s+مالی\s+منتهی\s+به\s+[۰-۹0-9]{1,2}\s+[آ-یی]+\s+[۰-۹0-9]{4}',
|
| 172 |
-
# تاریخ شمسی با عدد و ماه
|
| 173 |
-
r'[۰-۹0-9]{1,2}\s+(?:فروردین|اردیبهشت|خرداد|تیر|مرداد|شهریور|مهر|آبان|آذر|دی|بهمن|اسفند)\s+[۰-۹0-9]{4}',
|
| 174 |
-
# تاریخ کامل شمسی
|
| 175 |
-
r'[۰-۹0-9]{1,2}\s+[آ-یی]+\s+[۰-۹0-9]{4}',
|
| 176 |
-
# تاریخ با خط فاصله
|
| 177 |
-
r'[۰-۹0-9]{4}[/-][۰-۹0-9]{1,2}[/-][۰-۹0-9]{1,2}',
|
| 178 |
-
r'[۰-۹0-9]{1,2}[/-][۰-۹0-9]{1,2}[/-][۰-۹0-9]{4}',
|
| 179 |
-
# تاریخ میلادی
|
| 180 |
-
r'(?:[0-9]{1,2})\s*(?:January|February|March|April|May|June|July|August|September|October|November|December)\s*(?:[0-9]{4})',
|
| 181 |
-
# سالها
|
| 182 |
-
r'(?:13[0-9]{2}|14[0-9]{2}|20[0-9]{2}|19[0-9]{2})(?=\s|$|،|\.)'
|
| 183 |
-
],
|
| 184 |
-
|
| 185 |
-
# باقی الگوها همانند قبل...
|
| 186 |
'PERSON': [
|
| 187 |
-
r'آقای\s+[
|
| 188 |
-
r'خانم\s+[
|
| 189 |
-
r'مهندس\s+[
|
| 190 |
-
r'دکتر\s+[
|
| 191 |
-
r'
|
| 192 |
-
r'
|
| 193 |
-
r'
|
| 194 |
-
r'Dr\.\s+[a-zA-Z\s]+?(?=\s|,|\.|$)',
|
| 195 |
-
r'[آ-یی۰-۹a-zA-Z\s]+?(?:\s|،)\s*مدیرعامل(?=\s|$|،|\.)',
|
| 196 |
-
r'مدیرعامل\s+[آ-یی۰-۹a-zA-Z\s]+?(?=\s|$|،|\.)',
|
| 197 |
-
r'رئیس\s+هیأتمدیره\s+[آ-یی۰-۹a-zA-Z\s]+?(?=\s|$|،|\.)'
|
| 198 |
],
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
r
|
| 203 |
-
r'
|
|
|
|
|
|
|
| 204 |
],
|
| 205 |
-
|
|
|
|
| 206 |
'AMOUNT': [
|
| 207 |
-
r'\d
|
| 208 |
-
r'مبلغ\s+\d
|
| 209 |
-
r'
|
| 210 |
-
r'
|
| 211 |
-
r'
|
| 212 |
],
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
r'\d+(?:,\d{3})*\s+euro',
|
| 216 |
-
r'€\d+(?:\.\d+)?M',
|
| 217 |
-
r'\d+\s+EUR',
|
| 218 |
-
r'\d+(?:,\d{3})*\s+AED',
|
| 219 |
-
r'\d+(?:\.\d+)?M\s+AED',
|
| 220 |
-
r'\$\d+(?:\.\d+)?M',
|
| 221 |
-
r'\$\d+(?:\.\d+)?K',
|
| 222 |
-
r'£\d+(?:,\d{3})*(?:\.\d+)?',
|
| 223 |
-
r'\d+\s+GBP',
|
| 224 |
-
r'\d+\s+CHF',
|
| 225 |
-
r'¥\d+(?:,\d{3})*',
|
| 226 |
-
r'\d+\s+JPY'
|
| 227 |
-
],
|
| 228 |
-
|
| 229 |
'ACCOUNT': [
|
| 230 |
-
r'
|
| 231 |
-
r'
|
| 232 |
-
r'شماره[\s]*حساب[\s:]*(?:[۰-۹0-9]{1,3}[-\s]?)*[۰-۹0-9]{8,20}',
|
| 233 |
-
r'Account[\s]*(?:Number[\s:]*)?(?:[0-9]{1,3}[-\s]?)*[0-9]{8,20}',
|
| 234 |
-
r'[۰-۹0-9]{3}[-\s]?[۰-۹0-9]{3}[-\s]?[۰-۹0-9]{6,12}',
|
| 235 |
-
r'[۰-۹0-9]{2,4}[-\s]?[۰-۹0-9]{6,12}[-\s]?[۰-۹0-9]{2,4}',
|
| 236 |
-
r'واریز[\s]*(?:سود[\s:]*)?(?:[۰-۹0-9]{1,3}[-\s]?)*[۰-۹0-9]{8,20}',
|
| 237 |
-
r'سود[\s:]*(?:[۰-۹0-9]{1,3}[-\s]?)*[۰-۹0-9]{8,20}'
|
| 238 |
-
],
|
| 239 |
-
|
| 240 |
-
'FINANCIAL_TERMS': [
|
| 241 |
-
r'فروش\s+(?:ماهانه|تجمیعی|صادراتی)',
|
| 242 |
-
r'درآمد\s+شرکت',
|
| 243 |
-
r'سود\s+(?:خالص|نقدی)',
|
| 244 |
-
r'صورتهای\s+مالی',
|
| 245 |
-
r'بهای\s+تمامشده',
|
| 246 |
-
r'سودآوری',
|
| 247 |
-
r'عملکرد\s+مالی',
|
| 248 |
-
r'میانگین\s+فروش',
|
| 249 |
-
r'بالاتری��\s+رقم\s+فروش',
|
| 250 |
-
r'رقم\s+فروش',
|
| 251 |
-
r'درآمدهای\s+عملیاتی'
|
| 252 |
-
],
|
| 253 |
-
|
| 254 |
-
'STOCK_SYMBOL': [
|
| 255 |
-
r'نماد\s+[آ-یی۰-۹a-zA-Z]+',
|
| 256 |
-
r'(?:سبهان|غدیر|شتران|شپنا|پترول|فارس|خارک|پلاسکو|جم|کرمان|مارون|اراک|رازی|شازند|کاوه|بندر|پارس|خوزستان|ماهشهر|عسلویه)(?=\s|$|،|\.|\s+)',
|
| 257 |
-
r'(?:AAPL|GOOGL|MSFT|AMZN|TSLA|META|NVDA|SABIC)(?=\s|$|,|\.)'
|
| 258 |
-
],
|
| 259 |
-
|
| 260 |
-
'ADVANCED_DATE_FORMATS': [
|
| 261 |
-
r'(?:March|April|May|June|July|August|September|October|November|December)\s+\d{1,2}(?:st|nd|rd|th),?\s+\d{4}',
|
| 262 |
-
r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z',
|
| 263 |
-
r'(?:PST|EST|GMT|UTC)(?:[+-]\d{1,2}:\d{2})?',
|
| 264 |
-
r'Eastern\s+Time',
|
| 265 |
-
r'GMT[+-]\d{1,2}:\d{2}',
|
| 266 |
-
r'end\s+of\s+fiscal\s+year\s+\d{4}/\d{2}/\d{2}'
|
| 267 |
-
],
|
| 268 |
-
|
| 269 |
-
'TIME_RANGES': [
|
| 270 |
-
r'\d{2}:\d{2}-\d{2}:\d{2}',
|
| 271 |
-
r'\d{2}:\d{2}\s+تا\s+\d{2}:\d{2}',
|
| 272 |
-
r'\d{1,2}:\d{2}\s+(?:AM|PM)\s+(?:PST|EST|GMT|UTC)',
|
| 273 |
-
r'\d{2}:\d{2}:\d{2}\s+(?:AM|PM)',
|
| 274 |
-
r'COB\s*\(Close\s+of\s+Business\)',
|
| 275 |
-
r'\d{1,3}\s+(?:business\s+days|روز\s+کاری)'
|
| 276 |
-
],
|
| 277 |
-
|
| 278 |
-
'COMPLEX_ADDRESSES': [
|
| 279 |
-
r'کیلومتر\s+\d+\s+جاده\s+[آ-یی\s]+-[آ-یی\s]+',
|
| 280 |
-
r'روبروی\s+(?:پمپ\s+بنزین|بانک|پارک|مسجد|بیمارستان)\s+[آ-یی۰-۹a-zA-Z\s]+',
|
| 281 |
-
r'Building-[A-Z],?\s+Floor-\d+,?\s+Unit-[A-Z0-9]+',
|
| 282 |
-
r'rack\s+number\s+R-\d+,?\s+slot\s+\d+',
|
| 283 |
-
r'phase\s+\d+\s+development,?\s+block\s+[A-Z],?\s+plot\s+\d+-[A-Z]',
|
| 284 |
-
r'\d{2,5}\s+[A-Z][a-z]+\s+(?:Street|Avenue|Boulevard|Road|Drive),?\s+Floor\s+\d+,?\s+Building\s+[A-Z]',
|
| 285 |
-
r'شهرک\s+صنعتی\s+[آ-یی\s]+،?\s+محور\s+[آ-یی\s]+'
|
| 286 |
],
|
| 287 |
-
|
| 288 |
-
'
|
| 289 |
-
r'
|
| 290 |
-
r'
|
| 291 |
-
r'REF-[A-Z]{3}-\d{4}-\d{3}',
|
| 292 |
-
r'DOC-[A-Z]{2}-\d{4}-\d{4}',
|
| 293 |
-
r'INF-\d{4}-\d{4}',
|
| 294 |
-
r'CTR/\d{4}/\d{3}',
|
| 295 |
-
r'HVAC-\d{7}',
|
| 296 |
-
r'Generator-Model-[A-Z0-9]+',
|
| 297 |
-
r'LOI-\d{4}-[A-Z]{4}-\d{3}',
|
| 298 |
-
r'BOQ-\d{4}-[A-Z]{3}-\d{3}',
|
| 299 |
-
r'#INV-\d{4}-Q\d-\d{4}',
|
| 300 |
-
r'ESC-\d{4}-[A-Z]{3}-\d{3}',
|
| 301 |
-
r'BN-\d{6}-[A-Z]\d+'
|
| 302 |
-
],
|
| 303 |
-
|
| 304 |
-
'NETWORK_ADDRESSES': [
|
| 305 |
-
r'\b(?:\d{1,3}\.){3}\d{1,3}\b',
|
| 306 |
-
r'xxx\.xxx\.xxx\.xxx',
|
| 307 |
-
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}',
|
| 308 |
-
r'srv-[a-z]+-[a-z]+-\d{2}',
|
| 309 |
-
r'[a-z]+-[a-z]+\d*\.[a-z]+\.[a-z]+',
|
| 310 |
-
r'[a-zA-Z0-9-]+\.[a-zA-Z]{2,4}(?:\.[a-zA-Z]{2,4})?'
|
| 311 |
-
],
|
| 312 |
-
|
| 313 |
-
'TECHNICAL_UNITS': [
|
| 314 |
-
r'\d+(?:\.\d+)?\s*MW',
|
| 315 |
-
r'\d+(?:\.\d+)?\s*kWh?',
|
| 316 |
-
r'\d+(?:,\d{3})*\s*cubic\s+meters',
|
| 317 |
-
r'\d+(?:,\d{3})*\s*m³',
|
| 318 |
-
r'\d+(?:,\d{3})*\s*sq\s+ft',
|
| 319 |
-
r'\d+(?:\.\d+)?\s*ppm',
|
| 320 |
-
r'\d+(?:\.\d+)?\s*mg/m³',
|
| 321 |
-
r'\b(?:CO2|NOx|SO2)\b',
|
| 322 |
-
r'\d+(?:\.\d+)?\s*TB',
|
| 323 |
-
r'\d+(?:\.\d+)?\s*GB',
|
| 324 |
-
r'\d+(?:,\d{3})*\s*square\s+meters',
|
| 325 |
-
r'\d+(?:\.\d+)?\%\s*efficiency',
|
| 326 |
-
r'FICO\s+score:\s*\d{3}',
|
| 327 |
-
r'\d+(?:\.\d+)?\s*(?:bar|psi)',
|
| 328 |
-
r'\d+(?:\.\d+)?\s*°[CF]',
|
| 329 |
-
r'\d+(?:\.\d+)?\s*(?:rpm|m/s)'
|
| 330 |
-
],
|
| 331 |
-
|
| 332 |
-
'ACRONYMS_ABBREVIATIONS': [
|
| 333 |
-
r'\b(?:HVAC|IT|HSE|BOQ|LC|COB)\b',
|
| 334 |
-
r'\b(?:YTD|NNN|EIN|SSN|FICO)\b',
|
| 335 |
-
r'\bIP\s+Address\b',
|
| 336 |
-
r'\bMAC\s+Address\b',
|
| 337 |
-
r'\bURL\b',
|
| 338 |
-
r'\b(?:LLC|Corp|Inc|Ltd)\b',
|
| 339 |
-
r'\b(?:PST|GMT|UTC|EST)\b',
|
| 340 |
-
r'\b(?:CO2|NOx|pH|UV)\b',
|
| 341 |
-
r'\b(?:SCADA|PLC|HMI)\b',
|
| 342 |
-
r'\b(?:GDP|CPI|ROI|NPV)\b',
|
| 343 |
-
r'\b(?:FOB|CIF|DDP)\b',
|
| 344 |
-
r'\b(?:ABA|SWIFT|IBAN)\b'
|
| 345 |
-
],
|
| 346 |
-
|
| 347 |
-
'BUSINESS_TERMS': [
|
| 348 |
-
r'تحلیل\s+عملکرد',
|
| 349 |
-
r'گزارش\s+(?:فعالیت|عملکرد)\s+ماهانه',
|
| 350 |
-
r'وضعیت\s+فروش',
|
| 351 |
-
r'تولید\s+پایدار',
|
| 352 |
-
r'سهم\s+بازار',
|
| 353 |
-
r'صادرات\s+هدفمند',
|
| 354 |
-
r'بهرهوری',
|
| 355 |
-
r'ظرفیت���های\s+داخلی',
|
| 356 |
-
r'شرکتهای\s+پیشرو',
|
| 357 |
-
r'صنعت\s+پتروشیمی',
|
| 358 |
-
r'سرمایهگذاران\s+بنیادی',
|
| 359 |
-
r'شاخصهای\s+عملیاتی',
|
| 360 |
-
r'برنامهریزی\s+مناسب',
|
| 361 |
-
r'واحد\s+فروش',
|
| 362 |
-
r'موجودی\s+انبار',
|
| 363 |
-
r'فاز\s+رشد\s+جدید',
|
| 364 |
-
r'ترکیب\s+فروش',
|
| 365 |
-
r'سهم\s+صادراتی',
|
| 366 |
-
r'روند\s+عملکرد',
|
| 367 |
-
r'اعداد\s+اعلامشده',
|
| 368 |
-
r'دادههای\s+ثبتشده'
|
| 369 |
],
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
r'
|
| 374 |
-
r'\
|
| 375 |
-
r'\
|
| 376 |
-
r'محصول(?:ات)?',
|
| 377 |
-
r'تولیدات\s+شرکت'
|
| 378 |
],
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
r'
|
|
|
|
| 383 |
],
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
r'
|
| 388 |
-
r'
|
| 389 |
-
r'
|
| 390 |
-
r'با\s+\d+(?:\.\d+)?\s*درصد\s+افزایش',
|
| 391 |
-
r'رشد\s+\d+(?:\.\d+)?\s*درصدی',
|
| 392 |
-
r'\d+(?:\.\d+)?\s*درصدی(?=\s+همراه|\s+بوده)',
|
| 393 |
-
r'میزان\s+رشد(?=\s+نسبت|\s+معادل)',
|
| 394 |
-
r'افزایش\s+قابلتوجهی',
|
| 395 |
-
r'بهبود\s+نسبی',
|
| 396 |
-
r'\d+(?:\.\d+)?\%\s*(?:increase|decrease|growth|improvement)',
|
| 397 |
-
r'(?:approximately|about)\s+\d+(?:\.\d+)?\%'
|
| 398 |
],
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
r'
|
| 403 |
-
r'
|
| 404 |
-
r'مقدار\s+تولید',
|
| 405 |
-
r'حجم\s+فروش',
|
| 406 |
-
r'ظرفیت\s+(?:تولید|اسمی)',
|
| 407 |
-
r'\d+(?:,\d{3})*\s*(?:tons|kg|liters|barrels)',
|
| 408 |
-
r'\d+(?:,\d{3})*\s*(?:metric\s+tons|MT)',
|
| 409 |
-
r'\d+(?:,\d{3})*\s*(?:thousand\s+tons|KT)'
|
| 410 |
],
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
r'\
|
| 415 |
-
r'
|
| 416 |
-
r'
|
| 417 |
-
r'میزان\s+(?:رشد|افزایش)',
|
| 418 |
-
r'شاخص\s+(?:مهم|عملیاتی)',
|
| 419 |
-
r'\d+(?:\.\d+)?\s*درصد\s+کل\s+تولید'
|
| 420 |
],
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
r'
|
| 425 |
-
r'
|
| 426 |
-
r'[
|
| 427 |
-
r'[
|
| 428 |
-
r'
|
| 429 |
-
r'
|
| 430 |
-
r'
|
| 431 |
-
r'\([0-9]{3}\)\s+[0-9]{3}-[0-9]{4}'
|
| 432 |
],
|
| 433 |
-
|
|
|
|
| 434 |
'EMAIL': [
|
| 435 |
r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
|
| 436 |
-
r'ایمیل[\s:]*[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
|
| 437 |
-
r'email[\s:]*[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
|
| 438 |
-
r'نشانی[\s]*الکترونیکی[\s:]*[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
|
| 439 |
-
r'آدرس[\s]*ایمیل[\s:]*[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
|
| 440 |
-
r'facility\.manager@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
|
| 441 |
-
],
|
| 442 |
-
|
| 443 |
-
'ID_NUMBER': [
|
| 444 |
-
r'IR[۰-۹0-9]{24}',
|
| 445 |
-
r'شبا[\s:]*IR[۰-۹0-9]{24}',
|
| 446 |
-
r'IBAN[\s:]*IR[۰-۹0-9]{24}',
|
| 447 |
-
r'شماره[\s]*شبا[\s:]*IR[۰-۹0-9]{24}',
|
| 448 |
-
r'(?:کد[\s]*)?(?:ملی[\s:]*)?[۰-۹0-9]{10}',
|
| 449 |
-
r'(?:شناسه[\s]*)?(?:ملی[\s:]*)?[۰-۹0-9]{10}',
|
| 450 |
-
r'National[\s]*(?:ID[\s:]*)?[0-9]{10}',
|
| 451 |
-
r'(?:پاسپورت[\s:]*)?[A-Z][0-9]{8}',
|
| 452 |
-
r'(?:Passport[\s:]*)?[A-Z][0-9]{8}',
|
| 453 |
-
r'(?:کارت[\s:]*)?(?:[۰-۹0-9]{4}[-\s]?){3}[۰-۹0-9]{4}',
|
| 454 |
-
r'(?:Card[\s:]*)?(?:[0-9]{4}[-\s]?){3}[0-9]{4}',
|
| 455 |
-
r'SSN[\s:]*[0-9]{3}-[0-9]{2}-[0-9]{4}',
|
| 456 |
-
r'FICO[\s]*(?:score[\s:]*)?[0-9]{3}',
|
| 457 |
-
r'EIN[\s:]*[0-9]{2}-[0-9]{7}',
|
| 458 |
-
r'Meeting[\s]*ID[\s:]*[0-9]{9,11}'
|
| 459 |
],
|
| 460 |
-
|
| 461 |
-
'ENGLISH_TITLES': [
|
| 462 |
-
r'business\s+partner',
|
| 463 |
-
r'team\s+lead',
|
| 464 |
-
r'head\s+of\s+production',
|
| 465 |
-
r'senior\s+architect',
|
| 466 |
-
r'civil\s+engineer',
|
| 467 |
-
r'system\s+administrator',
|
| 468 |
-
r'network\s+engineer',
|
| 469 |
-
r'environmental\s+consultant',
|
| 470 |
-
r'senior\s+loan\s+officer',
|
| 471 |
-
r'facility\s+manager',
|
| 472 |
-
r'project\s+team',
|
| 473 |
-
r'technical\s+support'
|
| 474 |
-
]
|
| 475 |
}
|
| 476 |
|
| 477 |
-
def
|
| 478 |
-
"""
|
| 479 |
-
|
| 480 |
-
for
|
| 481 |
-
if
|
| 482 |
-
|
| 483 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 484 |
|
| 485 |
def anonymize_text(self, original_text, lang='fa', selected_categories=None):
|
| 486 |
-
"""
|
| 487 |
try:
|
| 488 |
if not original_text or not original_text.strip():
|
| 489 |
return "⚠ Please enter input text!" if lang == 'en' else "⚠ لطفاً متن ورودی را وارد کنید!"
|
|
@@ -495,37 +195,33 @@ class LightweightDataAnonymizer:
|
|
| 495 |
anonymized = original_text
|
| 496 |
found_entities = set()
|
| 497 |
|
| 498 |
-
#
|
| 499 |
-
detected_lang = self.detect_language(original_text)
|
| 500 |
-
logger.info(f"Detected language: {detected_lang}")
|
| 501 |
-
|
| 502 |
-
# استخراج با الگوهای نهایی
|
| 503 |
patterns = self.get_improved_patterns()
|
| 504 |
|
| 505 |
# فیلتر کردن الگوها بر اساس انتخاب کاربر
|
| 506 |
if selected_categories:
|
| 507 |
selected_pattern_types = self.get_selected_patterns(selected_categories, lang)
|
| 508 |
patterns = {k: v for k, v in patterns.items() if k in selected_pattern_types}
|
| 509 |
-
logger.info(f"📋 Using selected pattern categories: {len(patterns)} types")
|
| 510 |
-
else:
|
| 511 |
-
patterns = patterns
|
| 512 |
-
logger.info("📋 Using all available pattern categories")
|
| 513 |
|
| 514 |
-
logger.info("🔍 Running
|
| 515 |
|
| 516 |
processed_entities = set()
|
| 517 |
|
| 518 |
-
#
|
| 519 |
priority_order = [
|
| 520 |
-
'EMAIL',
|
| 521 |
-
'
|
| 522 |
-
'
|
| 523 |
-
'
|
| 524 |
-
'
|
| 525 |
-
'
|
| 526 |
-
'
|
| 527 |
-
'
|
| 528 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
| 529 |
]
|
| 530 |
|
| 531 |
for category in priority_order:
|
|
@@ -535,7 +231,6 @@ class LightweightDataAnonymizer:
|
|
| 535 |
try:
|
| 536 |
matches = re.finditer(pattern, original_text, re.IGNORECASE | re.MULTILINE)
|
| 537 |
for match in matches:
|
| 538 |
-
# بدون گروه - capture کل match
|
| 539 |
full_match = match.group(0).strip()
|
| 540 |
|
| 541 |
# بررسی تداخل
|
|
@@ -554,20 +249,12 @@ class LightweightDataAnonymizer:
|
|
| 554 |
len(full_match) >= 3 and
|
| 555 |
not full_match.isspace()):
|
| 556 |
|
| 557 |
-
|
| 558 |
-
|
| 559 |
-
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
|
| 563 |
-
found_entities.add(full_match)
|
| 564 |
-
processed_entities.add((match_start, match_end))
|
| 565 |
-
else:
|
| 566 |
-
self.counters[category] += 1
|
| 567 |
-
code = f"{category.lower()}_{self.counters[category]:03d}"
|
| 568 |
-
self.mapping_table[full_match] = code
|
| 569 |
-
found_entities.add(full_match)
|
| 570 |
-
processed_entities.add((match_start, match_end))
|
| 571 |
except re.error as e:
|
| 572 |
logger.error(f"Regex error in pattern {pattern}: {e}")
|
| 573 |
continue
|
|
@@ -577,7 +264,7 @@ class LightweightDataAnonymizer:
|
|
| 577 |
for original_item, code in sorted_items:
|
| 578 |
anonymized = anonymized.replace(original_item, code)
|
| 579 |
|
| 580 |
-
logger.info(f"✅
|
| 581 |
return anonymized
|
| 582 |
|
| 583 |
except Exception as e:
|
|
@@ -585,15 +272,15 @@ class LightweightDataAnonymizer:
|
|
| 585 |
return f"⚠ Error in anonymization: {str(e)}" if lang == 'en' else f"⚠ خطا در ناشناسسازی: {str(e)}"
|
| 586 |
|
| 587 |
def send_to_chatgpt(self, anonymized_text, lang='fa'):
|
| 588 |
-
"""
|
| 589 |
try:
|
| 590 |
if not anonymized_text or not anonymized_text.strip():
|
| 591 |
return "⚠ Anonymized text is empty!" if lang == 'en' else "⚠ متن ناشناسشده خالی است!"
|
| 592 |
|
| 593 |
if not self.api_key:
|
| 594 |
-
return "⚠ API Key not configured!
|
| 595 |
|
| 596 |
-
system_msg = "You are a professional analyst. Answer questions accurately." if lang == 'en' else "شما یک
|
| 597 |
|
| 598 |
headers = {
|
| 599 |
"Authorization": f"Bearer {self.api_key}",
|
|
@@ -629,7 +316,7 @@ class LightweightDataAnonymizer:
|
|
| 629 |
return f"⚠ Error connecting to ChatGPT: {str(e)}" if lang == 'en' else f"⚠ خطا در ارتباط با ChatGPT: {str(e)}"
|
| 630 |
|
| 631 |
def deanonymize_response(self, gpt_response, lang='fa'):
|
| 632 |
-
"""
|
| 633 |
try:
|
| 634 |
if not gpt_response or not gpt_response.strip():
|
| 635 |
return "⚠ ChatGPT response is empty!" if lang == 'en' else "⚠ پاسخ ChatGPT خالی است!"
|
|
@@ -651,40 +338,36 @@ class LightweightDataAnonymizer:
|
|
| 651 |
|
| 652 |
def get_model_status(self):
|
| 653 |
"""وضعیت سیستم"""
|
| 654 |
-
status = "🚀
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 655 |
|
| 656 |
-
status += "•
|
| 657 |
-
status += "
|
| 658 |
-
status += "
|
| 659 |
-
status += "
|
|
|
|
| 660 |
|
| 661 |
-
status += f"
|
| 662 |
for cat_key, cat_info in self.pattern_categories.items():
|
| 663 |
icon = cat_info['icon']
|
| 664 |
name_fa = cat_info['name_fa']
|
| 665 |
pattern_count = len(cat_info['patterns'])
|
| 666 |
-
status += f"
|
| 667 |
-
|
| 668 |
-
status += f"\n\n✨ **Final Optimizations:**"
|
| 669 |
-
status += f"\n 🏢 Company pattern priority maximized"
|
| 670 |
-
status += f"\n 🎯 Direct full-match capture (no groups)"
|
| 671 |
-
status += f"\n 📊 Simplified validation logic"
|
| 672 |
-
status += f"\n ⚡ شرکت پتروشیمی کارون guaranteed detection"
|
| 673 |
-
status += f"\n 🔥 Ultra-precise entity boundaries"
|
| 674 |
-
|
| 675 |
-
status += f"\n\n💡 **Final Guarantees:**"
|
| 676 |
-
status += f"\n ✅ شرکت پتروشیمی کارون → company_001"
|
| 677 |
-
status += f"\n ✅ ۳۰ اسفند ۱۴۰۳ → date_001"
|
| 678 |
-
status += f"\n ✅ بندر ماهشهر → location_001"
|
| 679 |
-
status += f"\n ✅ Perfect 3-entity detection for your text"
|
| 680 |
|
| 681 |
return status
|
| 682 |
|
| 683 |
# ایجاد instance
|
| 684 |
-
anonymizer =
|
| 685 |
|
| 686 |
def process_all_steps(input_text, language, selected_categories):
|
| 687 |
-
"""پردازش خودکار تمام مراحل - نسخه
|
| 688 |
lang = 'en' if language == 'English' else 'fa'
|
| 689 |
|
| 690 |
if not input_text.strip():
|
|
@@ -701,25 +384,23 @@ def process_all_steps(input_text, language, selected_categories):
|
|
| 701 |
gpt_response = anonymizer.send_to_chatgpt(anonymized_text, lang)
|
| 702 |
if gpt_response.startswith("⚠"):
|
| 703 |
entities_found = len(anonymizer.mapping_table)
|
| 704 |
-
|
| 705 |
selected_count = len(selected_categories) if selected_categories else 0
|
| 706 |
|
| 707 |
-
success_msg = (f"✅
|
| 708 |
-
f"📋
|
| 709 |
-
f"📊
|
| 710 |
return success_msg, anonymized_text, gpt_response, ""
|
| 711 |
|
| 712 |
final_result = anonymizer.deanonymize_response(gpt_response, lang)
|
| 713 |
|
| 714 |
total_time = time.time() - start_time
|
| 715 |
entities_found = len(anonymizer.mapping_table)
|
|
|
|
| 716 |
|
| 717 |
-
|
| 718 |
-
|
| 719 |
-
|
| 720 |
-
f"
|
| 721 |
-
f"📊 Total: {entities_found} entities | ⏱️ Time: {total_time:.2f}s\n"
|
| 722 |
-
f"⚡ شرکت پتروشیمی کارون detection guaranteed!")
|
| 723 |
|
| 724 |
return success_msg, anonymized_text, gpt_response, final_result
|
| 725 |
|
|
@@ -734,12 +415,12 @@ def get_mapping_table(language):
|
|
| 734 |
if not anonymizer.mapping_table:
|
| 735 |
return "⚠ Mapping table is empty!" if lang == 'en' else "⚠ جدول نگاشت خالی است!"
|
| 736 |
|
| 737 |
-
result = "📋
|
| 738 |
|
| 739 |
# نمایش آمار کلی
|
| 740 |
-
result += f"📊
|
| 741 |
-
result += f"🔍
|
| 742 |
-
result += f"⚡
|
| 743 |
|
| 744 |
# دستهبندی نتایج
|
| 745 |
category_stats = {}
|
|
@@ -752,12 +433,12 @@ def get_mapping_table(language):
|
|
| 752 |
# نمایش نتایج بر اساس دستهبندی
|
| 753 |
for category, items in category_stats.items():
|
| 754 |
if len(items) > 0:
|
| 755 |
-
result += f"🔍 **{category}** ({len(items)}
|
| 756 |
for original, code in items:
|
| 757 |
result += f" • `{original}` → `{code}`\n"
|
| 758 |
result += "\n"
|
| 759 |
|
| 760 |
-
result += "✨
|
| 761 |
|
| 762 |
return result
|
| 763 |
|
|
@@ -767,71 +448,7 @@ def clear_all():
|
|
| 767 |
anonymizer.counters = {key: 0 for key in anonymizer.counters.keys()}
|
| 768 |
return "", "", "", "", ""
|
| 769 |
|
| 770 |
-
|
| 771 |
-
"""بهروزرسانی متنهای رابط کاربری"""
|
| 772 |
-
if language == 'English':
|
| 773 |
-
return {
|
| 774 |
-
'title': 'Final Optimized Data Anonymization System',
|
| 775 |
-
'step1': 'Input Text & Category Selection',
|
| 776 |
-
'step2': 'Anonymized Text',
|
| 777 |
-
'step3': 'Raw ChatGPT Response',
|
| 778 |
-
'step4': 'Final Restored Response',
|
| 779 |
-
'input_placeholder': 'Enter your original text here...\nExample: Company reports, person names, financial amounts, phone numbers, emails, IBAN codes, bank accounts, etc.\n\n✨ Final optimized system - شرکت پتروشیمی کارون detection guaranteed!',
|
| 780 |
-
'process_btn': 'Process with Selected Categories',
|
| 781 |
-
'clear_btn': 'Clear All',
|
| 782 |
-
'mapping_btn': 'Show Final Optimized Mapping Table',
|
| 783 |
-
'status_btn': 'Show Final System Status',
|
| 784 |
-
'categories_label': 'Select Pattern Categories:',
|
| 785 |
-
'direction': 'ltr'
|
| 786 |
-
}
|
| 787 |
-
else:
|
| 788 |
-
return {
|
| 789 |
-
'title': 'سیستم ناشناسسازی نهایی و بهینهشده',
|
| 790 |
-
'step1': 'متن ورودی و انتخاب دستهبندی',
|
| 791 |
-
'step2': 'متن ناشناسشده',
|
| 792 |
-
'step3': 'پاسخ خام ChatGPT',
|
| 793 |
-
'step4': 'پاسخ نهایی بازگردانده شده',
|
| 794 |
-
'input_placeholder': 'متن اصلی خود را اینجا وارد کنید...\nمثال: گزارشهای شرکت، نام اشخاص، مبالغ مالی، شماره تلفن، ایمیل، شماره شبا، حساب بانکی و غیره\n\n✨ سیستم نهایی بهینهشده - تشخیص شرکت پتروشیمی کارون تضمینی!',
|
| 795 |
-
'process_btn': 'پردازش با دستهبندیهای انتخاب شده',
|
| 796 |
-
'clear_btn': 'پاک کردن همه',
|
| 797 |
-
'mapping_btn': 'نمایش جدول نگاشت نهایی',
|
| 798 |
-
'status_btn': 'نمایش وضعیت سیستم نهایی',
|
| 799 |
-
'categories_label': 'انتخاب دستهبندیهای الگو:',
|
| 800 |
-
'direction': 'rtl'
|
| 801 |
-
}
|
| 802 |
-
|
| 803 |
-
def update_interface(language):
|
| 804 |
-
"""تغییر رابط کاربری بر اساس زبان"""
|
| 805 |
-
ui_text = update_ui_text(language)
|
| 806 |
-
is_english = (language == 'English')
|
| 807 |
-
|
| 808 |
-
# تغییر direction برای workflow
|
| 809 |
-
workflow_css = "workflow ltr" if is_english else "workflow rtl"
|
| 810 |
-
|
| 811 |
-
# دریافت دستهبندیها بر اساس زبان
|
| 812 |
-
category_choices = anonymizer.get_category_choices('en' if is_english else 'fa')
|
| 813 |
-
|
| 814 |
-
return [
|
| 815 |
-
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>"),
|
| 816 |
-
gr.update(value=f"<h2 style='direction: {ui_text['direction']};'>🔍 {ui_text['step1']}</h2>"),
|
| 817 |
-
gr.update(placeholder=ui_text['input_placeholder'], rtl=not is_english),
|
| 818 |
-
gr.update(value=f"🚀 {ui_text['process_btn']}"),
|
| 819 |
-
gr.update(value=f"🗑️ {ui_text['clear_btn']}"),
|
| 820 |
-
gr.update(rtl=not is_english),
|
| 821 |
-
gr.update(value=f"<h2 style='direction: {ui_text['direction']};'>🎭 {ui_text['step2']}</h2>"),
|
| 822 |
-
gr.update(rtl=not is_english),
|
| 823 |
-
gr.update(value=f"<h2 style='direction: {ui_text['direction']};'>🤖 {ui_text['step3']}</h2>"),
|
| 824 |
-
gr.update(rtl=not is_english),
|
| 825 |
-
gr.update(value=f"<h2 style='direction: {ui_text['direction']};'>✅ {ui_text['step4']}</h2>"),
|
| 826 |
-
gr.update(rtl=not is_english),
|
| 827 |
-
gr.update(value=f"📋 {ui_text['mapping_btn']}"),
|
| 828 |
-
gr.update(value=f"📊 {ui_text['status_btn']}"),
|
| 829 |
-
gr.update(rtl=not is_english),
|
| 830 |
-
gr.update(elem_classes=workflow_css),
|
| 831 |
-
gr.update(label=ui_text['categories_label'], choices=category_choices, value=category_choices)
|
| 832 |
-
]
|
| 833 |
-
|
| 834 |
-
# CSS اصلاح شده برای ترازبندی عمودی مناسب
|
| 835 |
custom_css = """
|
| 836 |
body, .gradio-container {
|
| 837 |
font-family: 'Segoe UI', Tahoma, Arial, sans-serif !important;
|
|
@@ -840,82 +457,10 @@ body, .gradio-container {
|
|
| 840 |
padding: 20px !important;
|
| 841 |
}
|
| 842 |
|
| 843 |
-
.rtl {
|
| 844 |
-
direction: rtl !important;
|
| 845 |
-
text-align: right !important;
|
| 846 |
-
}
|
| 847 |
-
|
| 848 |
-
.ltr {
|
| 849 |
-
direction: ltr !important;
|
| 850 |
-
text-align: left !important;
|
| 851 |
-
}
|
| 852 |
-
|
| 853 |
-
.workflow {
|
| 854 |
-
display: grid !important;
|
| 855 |
-
grid-template-columns: 1fr 1fr 1fr 1fr !important;
|
| 856 |
-
gap: 25px !important;
|
| 857 |
-
padding: 30px !important;
|
| 858 |
-
align-items: start !important;
|
| 859 |
-
align-content: start !important;
|
| 860 |
-
grid-auto-rows: auto !important;
|
| 861 |
-
}
|
| 862 |
-
|
| 863 |
-
.workflow > * {
|
| 864 |
-
align-self: start !important;
|
| 865 |
-
vertical-align: top !important;
|
| 866 |
-
margin-top: 0 !important;
|
| 867 |
-
}
|
| 868 |
-
|
| 869 |
-
.workflow .gradio-column,
|
| 870 |
-
.workflow-column {
|
| 871 |
-
display: flex !important;
|
| 872 |
-
flex-direction: column !important;
|
| 873 |
-
align-items: stretch !important;
|
| 874 |
-
justify-content: flex-start !important;
|
| 875 |
-
height: auto !important;
|
| 876 |
-
min-height: 0 !important;
|
| 877 |
-
margin-top: 0 !important;
|
| 878 |
-
padding-top: 0 !important;
|
| 879 |
-
}
|
| 880 |
-
|
| 881 |
.gradio-textbox {
|
| 882 |
border-radius: 10px !important;
|
| 883 |
box-shadow: 0 4px 15px rgba(0,0,0,0.1) !important;
|
| 884 |
-
|
| 885 |
-
min-height: 380px !important;
|
| 886 |
-
max-height: 380px !important;
|
| 887 |
-
height: 380px !important;
|
| 888 |
-
}
|
| 889 |
-
|
| 890 |
-
.gradio-textbox textarea {
|
| 891 |
-
min-height: 350px !important;
|
| 892 |
-
max-height: 350px !important;
|
| 893 |
-
height: 350px !important;
|
| 894 |
-
resize: vertical !important;
|
| 895 |
-
}
|
| 896 |
-
|
| 897 |
-
.workflow.rtl {
|
| 898 |
-
direction: rtl !important;
|
| 899 |
-
}
|
| 900 |
-
|
| 901 |
-
.workflow.ltr {
|
| 902 |
-
direction: ltr !important;
|
| 903 |
-
}
|
| 904 |
-
|
| 905 |
-
h1, h2, h3 {
|
| 906 |
-
text-shadow: 2px 2px 4px rgba(0,0,0,0.3) !important;
|
| 907 |
-
margin-top: 0 !important;
|
| 908 |
-
margin-bottom: 10px !important;
|
| 909 |
-
padding-top: 0 !important;
|
| 910 |
-
line-height: 1.2 !important;
|
| 911 |
-
}
|
| 912 |
-
|
| 913 |
-
h2 {
|
| 914 |
-
min-height: 40px !important;
|
| 915 |
-
max-height: 40px !important;
|
| 916 |
-
display: flex !important;
|
| 917 |
-
align-items: center !important;
|
| 918 |
-
margin-bottom: 15px !important;
|
| 919 |
}
|
| 920 |
|
| 921 |
.status-box {
|
|
@@ -925,43 +470,6 @@ h2 {
|
|
| 925 |
padding: 15px !important;
|
| 926 |
margin: 10px 0 !important;
|
| 927 |
box-shadow: 0 8px 32px rgba(76, 175, 80, 0.3) !important;
|
| 928 |
-
animation: pulse 2s infinite !important;
|
| 929 |
-
min-height: 120px !important;
|
| 930 |
-
max-height: 120px !important;
|
| 931 |
-
}
|
| 932 |
-
|
| 933 |
-
.status-box textarea {
|
| 934 |
-
background: rgba(255, 255, 255, 0.95) !important;
|
| 935 |
-
border: none !important;
|
| 936 |
-
border-radius: 10px !important;
|
| 937 |
-
font-weight: bold !important;
|
| 938 |
-
font-size: 1.1em !important;
|
| 939 |
-
color: #1B5E20 !important;
|
| 940 |
-
text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8) !important;
|
| 941 |
-
min-height: 80px !important;
|
| 942 |
-
max-height: 80px !important;
|
| 943 |
-
}
|
| 944 |
-
|
| 945 |
-
.category-selection {
|
| 946 |
-
background: linear-gradient(135deg, #E3F2FD, #BBDEFB) !important;
|
| 947 |
-
border: 2px solid #1976D2 !important;
|
| 948 |
-
border-radius: 15px !important;
|
| 949 |
-
padding: 20px !important;
|
| 950 |
-
margin: 15px 0 !important;
|
| 951 |
-
box-shadow: 0 6px 20px rgba(25, 118, 210, 0.2) !important;
|
| 952 |
-
}
|
| 953 |
-
|
| 954 |
-
.gradio-checkboxgroup {
|
| 955 |
-
background: rgba(255, 255, 255, 0.9) !important;
|
| 956 |
-
border-radius: 10px !important;
|
| 957 |
-
padding: 15px !important;
|
| 958 |
-
margin: 10px 0 !important;
|
| 959 |
-
}
|
| 960 |
-
|
| 961 |
-
@keyframes pulse {
|
| 962 |
-
0% { box-shadow: 0 8px 32px rgba(76, 175, 80, 0.3); }
|
| 963 |
-
50% { box-shadow: 0 8px 40px rgba(76, 175, 80, 0.6); }
|
| 964 |
-
100% { box-shadow: 0 8px 32px rgba(76, 175, 80, 0.3); }
|
| 965 |
}
|
| 966 |
|
| 967 |
.gradio-button {
|
|
@@ -970,12 +478,6 @@ h2 {
|
|
| 970 |
transition: all 0.3s ease !important;
|
| 971 |
margin: 5px 0 !important;
|
| 972 |
min-height: 50px !important;
|
| 973 |
-
max-height: 50px !important;
|
| 974 |
-
}
|
| 975 |
-
|
| 976 |
-
.gradio-button:hover {
|
| 977 |
-
transform: translateY(-2px) !important;
|
| 978 |
-
box-shadow: 0 6px 20px rgba(0,0,0,0.2) !important;
|
| 979 |
}
|
| 980 |
|
| 981 |
h1 {
|
|
@@ -983,106 +485,57 @@ h1 {
|
|
| 983 |
-webkit-background-clip: text !important;
|
| 984 |
-webkit-text-fill-color: transparent !important;
|
| 985 |
background-clip: text !important;
|
| 986 |
-
|
| 987 |
-
}
|
| 988 |
-
|
| 989 |
-
@media (max-width: 1200px) {
|
| 990 |
-
.workflow {
|
| 991 |
-
grid-template-columns: 1fr 1fr !important;
|
| 992 |
-
gap: 20px !important;
|
| 993 |
-
}
|
| 994 |
-
}
|
| 995 |
-
|
| 996 |
-
@media (max-width: 768px) {
|
| 997 |
-
.workflow {
|
| 998 |
-
grid-template-columns: 1fr !important;
|
| 999 |
-
gap: 15px !important;
|
| 1000 |
-
}
|
| 1001 |
-
|
| 1002 |
-
.gradio-textbox {
|
| 1003 |
-
min-height: 300px !important;
|
| 1004 |
-
max-height: 300px !important;
|
| 1005 |
-
height: 300px !important;
|
| 1006 |
-
}
|
| 1007 |
-
}
|
| 1008 |
-
|
| 1009 |
-
[data-testid="textbox"]:dir(rtl) {
|
| 1010 |
-
text-align: right !important;
|
| 1011 |
-
direction: rtl !important;
|
| 1012 |
-
}
|
| 1013 |
-
|
| 1014 |
-
[data-testid="textbox"]:dir(ltr) {
|
| 1015 |
-
text-align: left !important;
|
| 1016 |
-
direction: ltr !important;
|
| 1017 |
-
}
|
| 1018 |
-
|
| 1019 |
-
.gradio-container .gradio-column {
|
| 1020 |
-
align-self: start !important;
|
| 1021 |
-
vertical-align: top !important;
|
| 1022 |
-
}
|
| 1023 |
-
|
| 1024 |
-
.gradio-container .gradio-row {
|
| 1025 |
-
align-items: flex-start !important;
|
| 1026 |
-
}
|
| 1027 |
-
|
| 1028 |
-
* {
|
| 1029 |
-
box-sizing: border-box !important;
|
| 1030 |
-
}
|
| 1031 |
-
|
| 1032 |
-
.gradio-container {
|
| 1033 |
-
align-items: start !important;
|
| 1034 |
-
justify-content: start !important;
|
| 1035 |
}
|
| 1036 |
"""
|
| 1037 |
|
| 1038 |
-
|
| 1039 |
-
with gr.Blocks(title="⚡ Final Optimized Anonymization System", theme=gr.themes.Soft(), css=custom_css) as app:
|
| 1040 |
-
|
| 1041 |
-
with gr.Row():
|
| 1042 |
-
language_selector = gr.Radio(
|
| 1043 |
-
choices=["فارسی", "English"],
|
| 1044 |
-
value="فارسی",
|
| 1045 |
-
label="Language / زبان",
|
| 1046 |
-
interactive=True
|
| 1047 |
-
)
|
| 1048 |
|
| 1049 |
with gr.Column():
|
| 1050 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1051 |
|
| 1052 |
# بخش انتخاب دستهبندیها
|
| 1053 |
-
with gr.Row(
|
| 1054 |
with gr.Column():
|
| 1055 |
-
|
| 1056 |
|
| 1057 |
pattern_categories = gr.CheckboxGroup(
|
| 1058 |
choices=anonymizer.get_category_choices('fa'),
|
| 1059 |
-
value=anonymizer.get_category_choices('fa'),
|
| 1060 |
label="انتخاب دستهبندیهای الگو:",
|
| 1061 |
-
interactive=True
|
| 1062 |
-
elem_classes=["gradio-checkboxgroup"]
|
| 1063 |
)
|
| 1064 |
|
| 1065 |
-
|
| 1066 |
<div style='background: rgba(255, 255, 255, 0.9); padding: 15px; border-radius: 10px; margin-top: 10px;'>
|
| 1067 |
<p style='margin: 0; color: #666; font-size: 0.9em; text-align: center;'>
|
| 1068 |
-
|
| 1069 |
</p>
|
| 1070 |
</div>
|
| 1071 |
""")
|
| 1072 |
-
|
| 1073 |
-
with gr.Row(
|
| 1074 |
-
with gr.Column(
|
| 1075 |
-
|
| 1076 |
|
| 1077 |
input_text = gr.Textbox(
|
| 1078 |
lines=15,
|
| 1079 |
-
placeholder="متن اصلی خود را اینجا وارد کنید...\n
|
| 1080 |
label="",
|
| 1081 |
rtl=True
|
| 1082 |
)
|
| 1083 |
|
| 1084 |
-
|
| 1085 |
-
|
|
|
|
| 1086 |
|
| 1087 |
status = gr.Textbox(
|
| 1088 |
label="وضعیت",
|
|
@@ -1092,33 +545,34 @@ with gr.Blocks(title="⚡ Final Optimized Anonymization System", theme=gr.themes
|
|
| 1092 |
elem_classes=["status-box"]
|
| 1093 |
)
|
| 1094 |
|
| 1095 |
-
with gr.Column(
|
| 1096 |
-
|
| 1097 |
|
| 1098 |
anonymized_output = gr.Textbox(
|
| 1099 |
lines=15,
|
| 1100 |
-
placeholder="متن ناشناسشده اینجا نمایش داده
|
| 1101 |
label="",
|
| 1102 |
interactive=False,
|
| 1103 |
rtl=True
|
| 1104 |
)
|
| 1105 |
|
| 1106 |
-
|
| 1107 |
-
|
|
|
|
| 1108 |
|
| 1109 |
gpt_output = gr.Textbox(
|
| 1110 |
-
lines=
|
| 1111 |
placeholder="پاسخ خام ChatGPT اینجا نمایش داده میشود...",
|
| 1112 |
label="",
|
| 1113 |
interactive=False,
|
| 1114 |
rtl=True
|
| 1115 |
)
|
| 1116 |
|
| 1117 |
-
with gr.Column(
|
| 1118 |
-
|
| 1119 |
|
| 1120 |
final_output = gr.Textbox(
|
| 1121 |
-
lines=
|
| 1122 |
placeholder="پاسخ نهایی اینجا نمایش داده میشود...",
|
| 1123 |
label="",
|
| 1124 |
interactive=False,
|
|
@@ -1127,8 +581,8 @@ with gr.Blocks(title="⚡ Final Optimized Anonymization System", theme=gr.themes
|
|
| 1127 |
|
| 1128 |
with gr.Row():
|
| 1129 |
with gr.Column():
|
| 1130 |
-
|
| 1131 |
-
mapping_btn = gr.Button("📋 نمایش جدول نگاشت
|
| 1132 |
|
| 1133 |
mapping_output = gr.Textbox(
|
| 1134 |
lines=15,
|
|
@@ -1140,8 +594,8 @@ with gr.Blocks(title="⚡ Final Optimized Anonymization System", theme=gr.themes
|
|
| 1140 |
|
| 1141 |
with gr.Row():
|
| 1142 |
with gr.Column():
|
| 1143 |
-
|
| 1144 |
-
system_status_btn = gr.Button("📊 نمایش وضعیت سیستم
|
| 1145 |
|
| 1146 |
system_status_output = gr.Textbox(
|
| 1147 |
lines=20,
|
|
@@ -1152,15 +606,6 @@ with gr.Blocks(title="⚡ Final Optimized Anonymization System", theme=gr.themes
|
|
| 1152 |
)
|
| 1153 |
|
| 1154 |
# Event handlers
|
| 1155 |
-
language_selector.change(
|
| 1156 |
-
fn=update_interface,
|
| 1157 |
-
inputs=[language_selector],
|
| 1158 |
-
outputs=[title, step1_title, input_text, process_btn, clear_btn,
|
| 1159 |
-
status, step2_title, anonymized_output, step3_title, gpt_output,
|
| 1160 |
-
step4_title, final_output, mapping_btn, system_status_btn,
|
| 1161 |
-
mapping_output, workflow_row, pattern_categories]
|
| 1162 |
-
)
|
| 1163 |
-
|
| 1164 |
process_btn.click(
|
| 1165 |
fn=process_all_steps,
|
| 1166 |
inputs=[input_text, language_selector, pattern_categories],
|
|
@@ -1194,9 +639,9 @@ with gr.Blocks(title="⚡ Final Optimized Anonymization System", theme=gr.themes
|
|
| 1194 |
)
|
| 1195 |
|
| 1196 |
if __name__ == "__main__":
|
| 1197 |
-
logger.info("
|
| 1198 |
-
logger.info("
|
| 1199 |
-
logger.info("
|
| 1200 |
|
| 1201 |
app.launch(
|
| 1202 |
share=False,
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
# -*- coding: utf-8 -*-
|
| 3 |
+
"""
|
| 4 |
+
سیستم ناشناسسازی اصلاح شده - حل مشکلات شناسایی شده
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
import gradio as gr
|
| 8 |
import re
|
| 9 |
import os
|
|
|
|
| 11 |
import time
|
| 12 |
import logging
|
| 13 |
|
|
|
|
| 14 |
logging.basicConfig(level=logging.INFO)
|
| 15 |
logger = logging.getLogger(__name__)
|
| 16 |
|
| 17 |
+
class ImprovedDataAnonymizer:
|
| 18 |
def __init__(self):
|
| 19 |
self.mapping_table = {}
|
|
|
|
| 20 |
self.pattern_categories = {
|
| 21 |
'personal_identity': {
|
| 22 |
'name_fa': 'اطلاعات شخصی و هویتی',
|
| 23 |
'name_en': 'Personal & Identity Information',
|
| 24 |
+
'patterns': ['PERSON', 'ID_NUMBER', 'MIXED_NAMES'],
|
| 25 |
'icon': '👤'
|
| 26 |
},
|
| 27 |
'financial': {
|
| 28 |
'name_fa': 'اطلاعات مالی',
|
| 29 |
'name_en': 'Financial Information',
|
| 30 |
+
'patterns': ['AMOUNT', 'ACCOUNT', 'CARD_NUMBER'],
|
| 31 |
'icon': '💰'
|
| 32 |
},
|
| 33 |
'temporal': {
|
| 34 |
'name_fa': 'اطلاعات زمانی',
|
| 35 |
'name_en': 'Temporal Information',
|
| 36 |
+
'patterns': ['DATE'],
|
| 37 |
'icon': '📅'
|
| 38 |
},
|
| 39 |
'location': {
|
| 40 |
'name_fa': 'اطلاعات مکانی',
|
| 41 |
'name_en': 'Location Information',
|
| 42 |
+
'patterns': ['LOCATION', 'FULL_ADDRESS'],
|
| 43 |
'icon': '📍'
|
| 44 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
'business': {
|
| 46 |
'name_fa': 'اطلاعات کسبوکار',
|
| 47 |
'name_en': 'Business Information',
|
| 48 |
+
'patterns': ['COMPANY', 'BRANCH'],
|
| 49 |
'icon': '🏢'
|
| 50 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
'communication': {
|
| 52 |
'name_fa': 'اطلاعات ارتباطی',
|
| 53 |
'name_en': 'Communication Information',
|
|
|
|
| 56 |
}
|
| 57 |
}
|
| 58 |
|
|
|
|
| 59 |
self.counters = {
|
| 60 |
+
'PERSON': 0, 'ID_NUMBER': 0, 'MIXED_NAMES': 0,
|
| 61 |
+
'AMOUNT': 0, 'ACCOUNT': 0, 'CARD_NUMBER': 0,
|
| 62 |
+
'DATE': 0,
|
| 63 |
+
'LOCATION': 0, 'FULL_ADDRESS': 0,
|
| 64 |
+
'COMPANY': 0, 'BRANCH': 0,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
'PHONE': 0, 'EMAIL': 0
|
| 66 |
}
|
| 67 |
|
| 68 |
self.api_key = os.getenv("OPENAI_API_KEY", "")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
|
| 70 |
def get_improved_patterns(self):
|
| 71 |
+
"""الگوهای بهبود یافته با حل مشکلات شناسایی شده"""
|
| 72 |
return {
|
| 73 |
+
# اسامی اشخاص - اصلاح شده برای گرفتن نام کامل
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
'PERSON': [
|
| 75 |
+
r'آقای\s+[آ-ییٰ-ٹ]+\s+[آ-ییٰ-ٹ]+(?=\s+با\s+کد|\s+مدیر|$|،|\.)',
|
| 76 |
+
r'خانم\s+[آ-ییٰ-ٹ]+\s+[آ-ییٰ-ٹ]+(?=\s+با\s+کد|\s+همسر|$|،|\.)',
|
| 77 |
+
r'مهندس\s+[آ-ییٰ-ٹ]+\s+[آ-ییٰ-ٹ]+(?=\s+با\s+کد|$|،|\.)',
|
| 78 |
+
r'دکتر\s+[آ-ییٰ-ٹ]+\s+[آ-ییٰ-ٹ]+(?=\s+با\s+کد|$|،|\.)',
|
| 79 |
+
r'Mr\.\s+[A-Z][a-z]+\s+[A-Z][a-z]+(?=\s|,|\.|$)',
|
| 80 |
+
r'Ms\.\s+[A-Z][a-z]+\s+[A-Z][a-z]+(?=\s|,|\.|$)',
|
| 81 |
+
r'Dr\.\s+[A-Z][a-z]+\s+[A-Z][a-z]+(?=\s|,|\.|$)',
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
],
|
| 83 |
+
|
| 84 |
+
# کدهای ملی و شناسهها - جداسازی از شماره تلفن
|
| 85 |
+
'ID_NUMBER': [
|
| 86 |
+
r'کد\s+ملی\s+\d{10}',
|
| 87 |
+
r'شناسه\s+ملی\s+\d{11}',
|
| 88 |
+
r'(?<![0-9])\d{10}(?![0-9])', # کد ملی 10 رقمی مستقل
|
| 89 |
+
r'(?<![0-9])\d{11}(?![0-9])', # شناسه 11 رقمی مستقل
|
| 90 |
],
|
| 91 |
+
|
| 92 |
+
# مبالغ مالی - جداسازی از شماره تلفن
|
| 93 |
'AMOUNT': [
|
| 94 |
+
r'\d{6,}\s*تومان', # مبالغ 6 رقمی یا بیشتر با کلمه تومان
|
| 95 |
+
r'مبلغ\s+\d{6,}(?:\s*تومان)?',
|
| 96 |
+
r'موجودی\s+حساب\s+[^\s]+\s+حدود\s+\d{6,}\s*تومان',
|
| 97 |
+
r'ارزش\s+روز\s+آن\s+\d{6,}\s*تومان',
|
| 98 |
+
r'\$\d+(?:,\d{3})*(?:\.\d+)?',
|
| 99 |
],
|
| 100 |
+
|
| 101 |
+
# شماره حساب و کارت بانکی - جداسازی دقیق
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
'ACCOUNT': [
|
| 103 |
+
r'حساب\s+جاری\s+شماره\s+[\d-]+',
|
| 104 |
+
r'شماره\s+[\d-]{8,}(?=\s+در)', # شماره حساب
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
],
|
| 106 |
+
|
| 107 |
+
'CARD_NUMBER': [
|
| 108 |
+
r'شماره\s+\d{4}-\d{4}-\d{4}-\d{4}', # شماره کارت
|
| 109 |
+
r'\d{4}-\d{4}-\d{4}-\d{4}(?=\s+نیز)',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
],
|
| 111 |
+
|
| 112 |
+
# شماره تلفن - دقیقتر شده
|
| 113 |
+
'PHONE': [
|
| 114 |
+
r'شماره\s+تماس\s+09\d{9}',
|
| 115 |
+
r'(?<![0-9])09\d{9}(?![0-9])', # شماره موبایل مستقل
|
| 116 |
+
r'تلفن[\s:]*0\d{2,3}[-\s]?\d{7,8}',
|
|
|
|
|
|
|
| 117 |
],
|
| 118 |
+
|
| 119 |
+
# تاریخ
|
| 120 |
+
'DATE': [
|
| 121 |
+
r'\d{4}/\d{1,2}/\d{1,2}',
|
| 122 |
+
r'[۰-۹]{1,2}\s+(?:فروردین|اردیبهشت|خرداد|تیر|مرداد|شهریور|مهر|آبان|آذر|دی|بهمن|اسفند)\s+[۰-۹]{4}',
|
| 123 |
],
|
| 124 |
+
|
| 125 |
+
# شرکتها
|
| 126 |
+
'COMPANY': [
|
| 127 |
+
r'شرکت\s+[آ-ییٰ-ٹ\s]+(?=\s|$|،|\.)',
|
| 128 |
+
r'بانک\s+[آ-ییٰ-ٹ\s]+(?=\s|$|،|\.)',
|
| 129 |
+
r'[A-Z][a-zA-Z\s]+(?:Inc|Corp|Corporation|Company|Ltd|Limited|LLC)',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
],
|
| 131 |
+
|
| 132 |
+
# شعب و واحدهای تجاری
|
| 133 |
+
'BRANCH': [
|
| 134 |
+
r'شعبه\s+[آ-ییٰ-ٹ\s]+\s+بانک\s+[آ-ییٰ-ٹ\s]+',
|
| 135 |
+
r'شعبه\s+مرکزی\s+بانک\s+[آ-ییٰ-ٹ\s]+',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
],
|
| 137 |
+
|
| 138 |
+
# مکانها - شهرها
|
| 139 |
+
'LOCATION': [
|
| 140 |
+
r'\b(?:تهران|اصفهان|ماهشهر|عسلویه|کرج|شیراز|مشهد|تبریز|اهواز|قم|رشت|کرمان|یزد|بوشهر)\b',
|
| 141 |
+
r'استان\s+[آ-ییٰ-ٹ\s]+',
|
| 142 |
+
r'شهر\s+[آ-ییٰ-ٹ\s]+',
|
|
|
|
|
|
|
|
|
|
| 143 |
],
|
| 144 |
+
|
| 145 |
+
# آدرس کامل - الگوی جدید برای آدرسهای تفصیلی
|
| 146 |
+
'FULL_ADDRESS': [
|
| 147 |
+
r'خیابان\s+[آ-ییٰ-ٹ\s]+،\s+کوچه\s+[آ-ییٰ-ٹ\s]+،\s+پلاک\s+\d+،\s+طبقه\s+[آ-ییٰ-ٹ\d\s]+',
|
| 148 |
+
r'شهرک\s+[آ-ییٰ-ٹ\s]+،\s+خیابان\s+[آ-ییٰ-ٹ\s]+،\s+پلاک\s+\d+',
|
| 149 |
+
r'خیابان\s+[آ-ییٰ-ٹ\s]+',
|
| 150 |
+
r'کوچه\s+[آ-ییٰ-ٹ\s]+',
|
| 151 |
+
r'شهرک\s+[آ-ییٰ-ٹ\s]+',
|
| 152 |
+
r'پلاک\s+\d+',
|
| 153 |
+
r'طبقه\s+[آ-ییٰ-ٹ\d\s]+',
|
|
|
|
| 154 |
],
|
| 155 |
+
|
| 156 |
+
# ایمیل
|
| 157 |
'EMAIL': [
|
| 158 |
r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
}
|
| 161 |
|
| 162 |
+
def get_category_choices(self, language='fa'):
|
| 163 |
+
"""دریافت لیست دستهبندیها برای چکباکس"""
|
| 164 |
+
choices = []
|
| 165 |
+
for cat_key, cat_info in self.pattern_categories.items():
|
| 166 |
+
name = cat_info['name_fa'] if language == 'fa' else cat_info['name_en']
|
| 167 |
+
icon = cat_info['icon']
|
| 168 |
+
choices.append(f"{icon} {name}")
|
| 169 |
+
return choices
|
| 170 |
+
|
| 171 |
+
def get_selected_patterns(self, selected_categories, language='fa'):
|
| 172 |
+
"""تبدیل دستهبندیهای انتخاب شده به لیست الگوها"""
|
| 173 |
+
selected_patterns = []
|
| 174 |
+
|
| 175 |
+
for cat_key, cat_info in self.pattern_categories.items():
|
| 176 |
+
name = cat_info['name_fa'] if language == 'fa' else cat_info['name_en']
|
| 177 |
+
icon = cat_info['icon']
|
| 178 |
+
category_display = f"{icon} {name}"
|
| 179 |
+
|
| 180 |
+
if category_display in selected_categories:
|
| 181 |
+
selected_patterns.extend(cat_info['patterns'])
|
| 182 |
+
|
| 183 |
+
return selected_patterns
|
| 184 |
|
| 185 |
def anonymize_text(self, original_text, lang='fa', selected_categories=None):
|
| 186 |
+
"""ناشناسسازی متن با الگوهای بهبود یافته"""
|
| 187 |
try:
|
| 188 |
if not original_text or not original_text.strip():
|
| 189 |
return "⚠ Please enter input text!" if lang == 'en' else "⚠ لطفاً متن ورودی را وارد کنید!"
|
|
|
|
| 195 |
anonymized = original_text
|
| 196 |
found_entities = set()
|
| 197 |
|
| 198 |
+
# استخراج با الگوهای بهبود یافته
|
|
|
|
|
|
|
|
|
|
|
|
|
| 199 |
patterns = self.get_improved_patterns()
|
| 200 |
|
| 201 |
# فیلتر کردن الگوها بر اساس انتخاب کاربر
|
| 202 |
if selected_categories:
|
| 203 |
selected_pattern_types = self.get_selected_patterns(selected_categories, lang)
|
| 204 |
patterns = {k: v for k, v in patterns.items() if k in selected_pattern_types}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
|
| 206 |
+
logger.info("🔍 Running improved regex extraction...")
|
| 207 |
|
| 208 |
processed_entities = set()
|
| 209 |
|
| 210 |
+
# ترتیب اولویت بهبود یافته - مهمترینها اول
|
| 211 |
priority_order = [
|
| 212 |
+
'EMAIL', # بالاترین اولویت
|
| 213 |
+
'ID_NUMBER', # کدهای ملی و شناسهها
|
| 214 |
+
'CARD_NUMBER', # شماره کارتهای بانکی
|
| 215 |
+
'ACCOUNT', # شماره حسابهای بانکی
|
| 216 |
+
'PHONE', # شماره تلفنها
|
| 217 |
+
'AMOUNT', # مبالغ مالی
|
| 218 |
+
'FULL_ADDRESS', # آدرسهای کامل
|
| 219 |
+
'BRANCH', # شعب بانکها
|
| 220 |
+
'COMPANY', # شرکتها
|
| 221 |
+
'LOCATION', # مکانها
|
| 222 |
+
'DATE', # تاریخها
|
| 223 |
+
'PERSON', # اسامی اشخاص - اولویت پایینتر برای گرفتن نام کامل
|
| 224 |
+
'MIXED_NAMES' # کمترین اولویت
|
| 225 |
]
|
| 226 |
|
| 227 |
for category in priority_order:
|
|
|
|
| 231 |
try:
|
| 232 |
matches = re.finditer(pattern, original_text, re.IGNORECASE | re.MULTILINE)
|
| 233 |
for match in matches:
|
|
|
|
| 234 |
full_match = match.group(0).strip()
|
| 235 |
|
| 236 |
# بررسی تداخل
|
|
|
|
| 249 |
len(full_match) >= 3 and
|
| 250 |
not full_match.isspace()):
|
| 251 |
|
| 252 |
+
self.counters[category] += 1
|
| 253 |
+
code = f"{category.lower()}_{self.counters[category]:03d}"
|
| 254 |
+
self.mapping_table[full_match] = code
|
| 255 |
+
found_entities.add(full_match)
|
| 256 |
+
processed_entities.add((match_start, match_end))
|
| 257 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 258 |
except re.error as e:
|
| 259 |
logger.error(f"Regex error in pattern {pattern}: {e}")
|
| 260 |
continue
|
|
|
|
| 264 |
for original_item, code in sorted_items:
|
| 265 |
anonymized = anonymized.replace(original_item, code)
|
| 266 |
|
| 267 |
+
logger.info(f"✅ Improved anonymization completed. Found {len(self.mapping_table)} entities.")
|
| 268 |
return anonymized
|
| 269 |
|
| 270 |
except Exception as e:
|
|
|
|
| 272 |
return f"⚠ Error in anonymization: {str(e)}" if lang == 'en' else f"⚠ خطا در ناشناسسازی: {str(e)}"
|
| 273 |
|
| 274 |
def send_to_chatgpt(self, anonymized_text, lang='fa'):
|
| 275 |
+
"""ارسال به ChatGPT"""
|
| 276 |
try:
|
| 277 |
if not anonymized_text or not anonymized_text.strip():
|
| 278 |
return "⚠ Anonymized text is empty!" if lang == 'en' else "⚠ متن ناشناسشده خالی است!"
|
| 279 |
|
| 280 |
if not self.api_key:
|
| 281 |
+
return "⚠ API Key not configured!" if lang == 'en' else "⚠ کلید API تنظیم نشده است!"
|
| 282 |
|
| 283 |
+
system_msg = "You are a professional analyst. Answer questions accurately." if lang == 'en' else "شما یک تحلیلگر حرفهای هستید. به سوالات با دقت پاسخ دهید."
|
| 284 |
|
| 285 |
headers = {
|
| 286 |
"Authorization": f"Bearer {self.api_key}",
|
|
|
|
| 316 |
return f"⚠ Error connecting to ChatGPT: {str(e)}" if lang == 'en' else f"⚠ خطا در ارتباط با ChatGPT: {str(e)}"
|
| 317 |
|
| 318 |
def deanonymize_response(self, gpt_response, lang='fa'):
|
| 319 |
+
"""بازگردانی"""
|
| 320 |
try:
|
| 321 |
if not gpt_response or not gpt_response.strip():
|
| 322 |
return "⚠ ChatGPT response is empty!" if lang == 'en' else "⚠ پاسخ ChatGPT خالی است!"
|
|
|
|
| 338 |
|
| 339 |
def get_model_status(self):
|
| 340 |
"""وضعیت سیستم"""
|
| 341 |
+
status = "🚀 **سیستم ناشناسسازی بهبود یافته:**\n\n"
|
| 342 |
+
|
| 343 |
+
status += "• **حل مشکلات شناسایی شده:**\n"
|
| 344 |
+
status += " ✅ اسامی کامل (آقای + نام + نام خانوادگی)\n"
|
| 345 |
+
status += " ✅ آدرسهای تفصیلی (خیابان، کوچه، پلاک، طبقه)\n"
|
| 346 |
+
status += " ✅ شعب بانکی (شعبه مرکزی بانک ملی)\n"
|
| 347 |
+
status += " ✅ جداسازی دقیق کد ملی از شماره تلفن\n"
|
| 348 |
+
status += " ✅ جداسازی مبالغ مالی از شماره تلفن\n"
|
| 349 |
+
status += " ✅ شماره حساب و کارت بانکی جداگانه\n\n"
|
| 350 |
|
| 351 |
+
status += "• **بهبودهای الگو:**\n"
|
| 352 |
+
status += " 🎯 الگوهای دقیقتر برای اسامی\n"
|
| 353 |
+
status += " 🎯 تشخیص آدرسهای کامل\n"
|
| 354 |
+
status += " 🎯 اولویتبندی بهتر پردازش\n"
|
| 355 |
+
status += " 🎯 حذف تداخلهای غلط\n\n"
|
| 356 |
|
| 357 |
+
status += f"📊 **دستهبندیهای موجود:**\n"
|
| 358 |
for cat_key, cat_info in self.pattern_categories.items():
|
| 359 |
icon = cat_info['icon']
|
| 360 |
name_fa = cat_info['name_fa']
|
| 361 |
pattern_count = len(cat_info['patterns'])
|
| 362 |
+
status += f" {icon} {name_fa}: {pattern_count} الگو\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 363 |
|
| 364 |
return status
|
| 365 |
|
| 366 |
# ایجاد instance
|
| 367 |
+
anonymizer = ImprovedDataAnonymizer()
|
| 368 |
|
| 369 |
def process_all_steps(input_text, language, selected_categories):
|
| 370 |
+
"""پردازش خودکار تمام مراحل - نسخه بهبود یافته"""
|
| 371 |
lang = 'en' if language == 'English' else 'fa'
|
| 372 |
|
| 373 |
if not input_text.strip():
|
|
|
|
| 384 |
gpt_response = anonymizer.send_to_chatgpt(anonymized_text, lang)
|
| 385 |
if gpt_response.startswith("⚠"):
|
| 386 |
entities_found = len(anonymizer.mapping_table)
|
|
|
|
| 387 |
selected_count = len(selected_categories) if selected_categories else 0
|
| 388 |
|
| 389 |
+
success_msg = (f"✅ ناشناسسازی بهبود یافته انجام شد!\n"
|
| 390 |
+
f"📋 دستههای انتخابی: {selected_count} | 🔍 پردازش بهبود یافته\n"
|
| 391 |
+
f"📊 کل entities محافظت شده: {entities_found} | 🎯 مشکلات حل شده!")
|
| 392 |
return success_msg, anonymized_text, gpt_response, ""
|
| 393 |
|
| 394 |
final_result = anonymizer.deanonymize_response(gpt_response, lang)
|
| 395 |
|
| 396 |
total_time = time.time() - start_time
|
| 397 |
entities_found = len(anonymizer.mapping_table)
|
| 398 |
+
selected_count = len(selected_categories) if selected_categories else 6
|
| 399 |
|
| 400 |
+
success_msg = (f"🎉 ناشناسسازی کامل و بازگردانی موفق!\n"
|
| 401 |
+
f"🔧 روش: پردازش بهبود یافته | 📋 دستهها: {selected_count}/6\n"
|
| 402 |
+
f"📊 کل: {entities_found} entities | ⏱️ زمان: {total_time:.2f}s\n"
|
| 403 |
+
f"⚡ مشکلات شناسایی شده حل شدند!")
|
|
|
|
|
|
|
| 404 |
|
| 405 |
return success_msg, anonymized_text, gpt_response, final_result
|
| 406 |
|
|
|
|
| 415 |
if not anonymizer.mapping_table:
|
| 416 |
return "⚠ Mapping table is empty!" if lang == 'en' else "⚠ جدول نگاشت خالی است!"
|
| 417 |
|
| 418 |
+
result = "📋 **جدول نگاشت بهبود یافته:**\n\n"
|
| 419 |
|
| 420 |
# نمایش آمار کلی
|
| 421 |
+
result += f"📊 **آمار**: {len(anonymizer.mapping_table)} entity\n"
|
| 422 |
+
result += f"🔍 **روش**: پردازش بهبود یافته (مشکلات حل شده)\n"
|
| 423 |
+
result += f"⚡ **حالت**: شناسایی دقیق entities\n\n"
|
| 424 |
|
| 425 |
# دستهبندی نتایج
|
| 426 |
category_stats = {}
|
|
|
|
| 433 |
# نمایش نتایج بر اساس دستهبندی
|
| 434 |
for category, items in category_stats.items():
|
| 435 |
if len(items) > 0:
|
| 436 |
+
result += f"🔍 **{category}** ({len(items)} مورد):\n"
|
| 437 |
for original, code in items:
|
| 438 |
result += f" • `{original}` → `{code}`\n"
|
| 439 |
result += "\n"
|
| 440 |
|
| 441 |
+
result += "✨ **سیستم بهبود یافته**: تشخیص دقیق و کامل entities!"
|
| 442 |
|
| 443 |
return result
|
| 444 |
|
|
|
|
| 448 |
anonymizer.counters = {key: 0 for key in anonymizer.counters.keys()}
|
| 449 |
return "", "", "", "", ""
|
| 450 |
|
| 451 |
+
# رابط کاربری Gradio
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 452 |
custom_css = """
|
| 453 |
body, .gradio-container {
|
| 454 |
font-family: 'Segoe UI', Tahoma, Arial, sans-serif !important;
|
|
|
|
| 457 |
padding: 20px !important;
|
| 458 |
}
|
| 459 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 460 |
.gradio-textbox {
|
| 461 |
border-radius: 10px !important;
|
| 462 |
box-shadow: 0 4px 15px rgba(0,0,0,0.1) !important;
|
| 463 |
+
min-height: 300px !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 464 |
}
|
| 465 |
|
| 466 |
.status-box {
|
|
|
|
| 470 |
padding: 15px !important;
|
| 471 |
margin: 10px 0 !important;
|
| 472 |
box-shadow: 0 8px 32px rgba(76, 175, 80, 0.3) !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 473 |
}
|
| 474 |
|
| 475 |
.gradio-button {
|
|
|
|
| 478 |
transition: all 0.3s ease !important;
|
| 479 |
margin: 5px 0 !important;
|
| 480 |
min-height: 50px !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 481 |
}
|
| 482 |
|
| 483 |
h1 {
|
|
|
|
| 485 |
-webkit-background-clip: text !important;
|
| 486 |
-webkit-text-fill-color: transparent !important;
|
| 487 |
background-clip: text !important;
|
| 488 |
+
text-align: center !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 489 |
}
|
| 490 |
"""
|
| 491 |
|
| 492 |
+
with gr.Blocks(title="🔧 سیستم ناشناسسازی بهبود یافته", theme=gr.themes.Soft(), css=custom_css) as app:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 493 |
|
| 494 |
with gr.Column():
|
| 495 |
+
gr.HTML("<h1>🔧 سیستم ناشناسسازی بهبود یافته - حل مشکلات شناسایی شده</h1>")
|
| 496 |
+
|
| 497 |
+
with gr.Row():
|
| 498 |
+
language_selector = gr.Radio(
|
| 499 |
+
choices=["فارسی", "English"],
|
| 500 |
+
value="فارسی",
|
| 501 |
+
label="Language / زبان",
|
| 502 |
+
interactive=True
|
| 503 |
+
)
|
| 504 |
|
| 505 |
# بخش انتخاب دستهبندیها
|
| 506 |
+
with gr.Row():
|
| 507 |
with gr.Column():
|
| 508 |
+
gr.HTML("<h3 style='text-align: center; color: #1976D2;'>🎯 انتخاب دستهبندیهای الگو</h3>")
|
| 509 |
|
| 510 |
pattern_categories = gr.CheckboxGroup(
|
| 511 |
choices=anonymizer.get_category_choices('fa'),
|
| 512 |
+
value=anonymizer.get_category_choices('fa'),
|
| 513 |
label="انتخاب دستهبندیهای الگو:",
|
| 514 |
+
interactive=True
|
|
|
|
| 515 |
)
|
| 516 |
|
| 517 |
+
gr.HTML("""
|
| 518 |
<div style='background: rgba(255, 255, 255, 0.9); padding: 15px; border-radius: 10px; margin-top: 10px;'>
|
| 519 |
<p style='margin: 0; color: #666; font-size: 0.9em; text-align: center;'>
|
| 520 |
+
🔧 <strong>بهبودها:</strong> اسامی کامل، آدرسهای تفصیلی، جداسازی کد ملی از شماره تلفن
|
| 521 |
</p>
|
| 522 |
</div>
|
| 523 |
""")
|
| 524 |
+
|
| 525 |
+
with gr.Row():
|
| 526 |
+
with gr.Column(scale=1):
|
| 527 |
+
gr.HTML('<h2>📝 متن ورودی</h2>')
|
| 528 |
|
| 529 |
input_text = gr.Textbox(
|
| 530 |
lines=15,
|
| 531 |
+
placeholder="متن اصلی خود را اینجا وارد کنید...\nمثال متن مشکلدار شما:\nآقای علی احمدی با کد ملی 0123456789 در تاریخ 1402/09/15 درخواست تسهیلات بانکی به مبلغ 500000000 تومان از شعبه مرکزی بانک ملی ارائه نموده است. ایشان ساکن تهران، خیابان ولیعصر، کوچه نیلوفر، پلاک 128، طبقه سوم بوده و شماره تماس 09123456789 را اعلام نمودهاند...\n\n🔧 حالا مشکلات حل شدهاند!",
|
| 532 |
label="",
|
| 533 |
rtl=True
|
| 534 |
)
|
| 535 |
|
| 536 |
+
with gr.Row():
|
| 537 |
+
process_btn = gr.Button("🚀 پردازش با الگوهای بهبود یافته", variant="primary")
|
| 538 |
+
clear_btn = gr.Button("🗑️ پاک کردن همه", variant="stop")
|
| 539 |
|
| 540 |
status = gr.Textbox(
|
| 541 |
label="وضعیت",
|
|
|
|
| 545 |
elem_classes=["status-box"]
|
| 546 |
)
|
| 547 |
|
| 548 |
+
with gr.Column(scale=1):
|
| 549 |
+
gr.HTML('<h2>🎭 متن ناشناسشده</h2>')
|
| 550 |
|
| 551 |
anonymized_output = gr.Textbox(
|
| 552 |
lines=15,
|
| 553 |
+
placeholder="متن ناشناسشده اینجا نمایش داده میشود...\nانتظار میرود:\n- person_001 به جای آقای علی احمدی\n- company_001 به جای شعبه مرکزی بانک ملی\n- full_address_001 به جای خیابان ولیعصر، کوچه نیلوفر، پلاک 128، طبقه سوم\n- amount_001 به جای 500000000 تومان\n- و سایر موارد...",
|
| 554 |
label="",
|
| 555 |
interactive=False,
|
| 556 |
rtl=True
|
| 557 |
)
|
| 558 |
|
| 559 |
+
with gr.Row():
|
| 560 |
+
with gr.Column(scale=1):
|
| 561 |
+
gr.HTML('<h2>🤖 پاسخ خام ChatGPT</h2>')
|
| 562 |
|
| 563 |
gpt_output = gr.Textbox(
|
| 564 |
+
lines=10,
|
| 565 |
placeholder="پاسخ خام ChatGPT اینجا نمایش داده میشود...",
|
| 566 |
label="",
|
| 567 |
interactive=False,
|
| 568 |
rtl=True
|
| 569 |
)
|
| 570 |
|
| 571 |
+
with gr.Column(scale=1):
|
| 572 |
+
gr.HTML('<h2>✅ پاسخ نهایی بازگردانده شده</h2>')
|
| 573 |
|
| 574 |
final_output = gr.Textbox(
|
| 575 |
+
lines=10,
|
| 576 |
placeholder="پاسخ نهایی اینجا نمایش داده میشود...",
|
| 577 |
label="",
|
| 578 |
interactive=False,
|
|
|
|
| 581 |
|
| 582 |
with gr.Row():
|
| 583 |
with gr.Column():
|
| 584 |
+
gr.HTML('<h2>📋 جدول نگاشت</h2>')
|
| 585 |
+
mapping_btn = gr.Button("📋 نمایش جدول نگاشت بهبود یافته")
|
| 586 |
|
| 587 |
mapping_output = gr.Textbox(
|
| 588 |
lines=15,
|
|
|
|
| 594 |
|
| 595 |
with gr.Row():
|
| 596 |
with gr.Column():
|
| 597 |
+
gr.HTML('<h2>⚙️ وضعیت سیستم</h2>')
|
| 598 |
+
system_status_btn = gr.Button("📊 نمایش وضعیت سیستم بهبود یافته")
|
| 599 |
|
| 600 |
system_status_output = gr.Textbox(
|
| 601 |
lines=20,
|
|
|
|
| 606 |
)
|
| 607 |
|
| 608 |
# Event handlers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 609 |
process_btn.click(
|
| 610 |
fn=process_all_steps,
|
| 611 |
inputs=[input_text, language_selector, pattern_categories],
|
|
|
|
| 639 |
)
|
| 640 |
|
| 641 |
if __name__ == "__main__":
|
| 642 |
+
logger.info("🔧 Starting Improved Anonymization System...")
|
| 643 |
+
logger.info("✅ Fixed issues: complete names, full addresses, proper categorization")
|
| 644 |
+
logger.info("🎯 Ready for accurate entity detection!")
|
| 645 |
|
| 646 |
app.launch(
|
| 647 |
share=False,
|