leilaghomashchi commited on
Commit
214d724
·
verified ·
1 Parent(s): 032a488

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -914
app.py DELETED
@@ -1,914 +0,0 @@
1
- import gradio as gr
2
- import re
3
- import os
4
- 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 LightweightDataAnonymizer:
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', 'MIXED_NAMES', 'ID_NUMBER', 'ENGLISH_TITLES'],
21
- 'icon': '👤'
22
- },
23
- 'financial': {
24
- 'name_fa': 'اطلاعات مالی',
25
- 'name_en': 'Financial Information',
26
- 'patterns': ['AMOUNT', 'INTERNATIONAL_CURRENCIES', 'ACCOUNT', 'FINANCIAL_TERMS', 'STOCK_SYMBOL'],
27
- 'icon': '💰'
28
- },
29
- 'temporal': {
30
- 'name_fa': 'اطلاعات زمانی',
31
- 'name_en': 'Temporal Information',
32
- 'patterns': ['DATE', 'ADVANCED_DATE_FORMATS', 'TIME_RANGES'],
33
- 'icon': '📅'
34
- },
35
- 'location': {
36
- 'name_fa': 'اطلاعات مکانی',
37
- 'name_en': 'Location Information',
38
- 'patterns': ['LOCATION', 'COMPLEX_ADDRESSES'],
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', 'BUSINESS_TERMS', 'PRODUCT', 'PETROCHEMICAL'],
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',
62
- 'patterns': ['PHONE', 'EMAIL'],
63
- 'icon': '📞'
64
- }
65
- }
66
-
67
- # counters
68
- self.counters = {
69
- 'PERSON': 0, 'MIXED_NAMES': 0, 'ID_NUMBER': 0, 'ENGLISH_TITLES': 0,
70
- 'AMOUNT': 0, 'INTERNATIONAL_CURRENCIES': 0, 'ACCOUNT': 0,
71
- 'FINANCIAL_TERMS': 0, 'STOCK_SYMBOL': 0,
72
- 'DATE': 0, 'ADVANCED_DATE_FORMATS': 0, 'TIME_RANGES': 0,
73
- 'LOCATION': 0, 'COMPLEX_ADDRESSES': 0,
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_comprehensive_patterns(self):
126
- """الگوهای جامع ناشناس‌سازی - نسخه کامل"""
127
- return {
128
- 'PERSON': [
129
- r'آقای\s+([آ-یa-zA-Z]+(?:\s+[آ-یa-zA-Z]+)*)',
130
- r'خانم\s+([آ-یa-zA-Z]+(?:\s+[آ-یa-zA-Z]+)*)',
131
- r'مهندس\s+([آ-یa-zA-Z]+(?:\s+[آ-یa-zA-Z]+)*)',
132
- r'دکتر\s+([آ-یa-zA-Z]+(?:\s+[آ-یa-zA-Z]+)*)',
133
- r'استاد\s+([آ-یa-zA-Z]+(?:\s+[آ-یa-zA-Z]+)*)',
134
- r'Mr\.\s+([a-zA-Z]+(?:\s+[a-zA-Z]+)*)',
135
- r'Ms\.\s+([a-zA-Z]+(?:\s+[a-zA-Z]+)*)',
136
- r'Dr\.\s+([a-zA-Z]+(?:\s+[a-zA-Z]+)*)',
137
- r'([آ-یa-zA-Z]+\s+[آ-یa-zA-Z]+)(?:، مدیرعامل|\s+مدیرعامل|\s+رئیس)',
138
- r'مدیرعامل(?=\s|$|،|\.)',
139
- r'سرپرست(?=\s+و|\s|$|،|\.)',
140
- r'رئیس\s+هیأت‌مدیره'
141
- ],
142
-
143
- 'MIXED_NAMES': [
144
- r'([آ-یa-zA-Z]{2,}\s+[آ-یa-zA-Z]{2,})',
145
- r'([A-Z][a-z]+-[A-Z][a-z]+)',
146
- r"([A-Z]'[A-Z][a-z]+)",
147
- r'Dr\.\s+([آ-یa-zA-Z\s‌]+)'
148
- ],
149
-
150
- 'ID_NUMBER': [
151
- r'IR[۰-۹0-9]{24}',
152
- r'شبا[\s:]*IR[۰-۹0-9]{24}',
153
- r'IBAN[\s:]*IR[۰-۹0-9]{24}',
154
- r'شماره[\s]*شبا[\s:]*IR[۰-۹0-9]{24}',
155
- r'(?:کد[\s]*)?(?:ملی[\s:]*)?[۰-۹0-9]{10}',
156
- r'(?:شناسه[\s]*)?(?:ملی[\s:]*)?[۰-۹0-9]{10}',
157
- r'National[\s]*(?:ID[\s:]*)?[0-9]{10}',
158
- r'(?:پاسپورت[\s:]*)?[A-Z][0-9]{8}',
159
- r'(?:Passport[\s:]*)?[A-Z][0-9]{8}',
160
- r'(?:کارت[\s:]*)?(?:[۰-۹0-9]{4}[-\s]?){3}[۰-۹0-9]{4}',
161
- r'(?:Card[\s:]*)?(?:[0-9]{4}[-\s]?){3}[0-9]{4}',
162
- r'SSN[\s:]*[0-9]{3}-[0-9]{2}-[0-9]{4}',
163
- r'FICO[\s]*(?:score[\s:]*)?[0-9]{3}',
164
- r'EIN[\s:]*[0-9]{2}-[0-9]{7}',
165
- r'Meeting[\s]*ID[\s:]*[0-9]{9,11}'
166
- ],
167
-
168
- 'ENGLISH_TITLES': [
169
- r'business\s+partner',
170
- r'team\s+lead',
171
- r'head\s+of\s+production',
172
- r'senior\s+architect',
173
- r'civil\s+engineer',
174
- r'system\s+administrator',
175
- r'network\s+engineer',
176
- r'environmental\s+consultant',
177
- r'senior\s+loan\s+officer',
178
- r'facility\s+manager',
179
- r'project\s+team',
180
- r'technical\s+support'
181
- ],
182
-
183
- 'AMOUNT': [
184
- r'\d+(?:,\d{3})*\s*(?:میلیون|میلیارد|هزار)\s*تومان',
185
- r'مبلغ\s+\d+(?:,\d{3})*\s*(?:میلیون|میلیارد|هزار)?\s*تومان',
186
- r'\d+\s*تومان(?=\s+به\s+ازای|\s+فروش|،)',
187
- r'رقم\s+فعلی\s+\d+(?:,\d{3})*\s*(?:میلیون|میلیارد)\s*تومان',
188
- r'رقم\s+\d+(?:,\d{3})*\s*(?:میلیون|میلیارد)\s*تومان',
189
- r'به\s+\d+(?:,\d{3})*\s*(?:میلیون|میلیارد|هزار)\s*تومان',
190
- r'\$\d+(?:,\d{3})*(?:\.\d+)?\s*(?:million|billion|thousand|M|B|K)?',
191
- r'\d+(?:,\d{3})*\s*ریال',
192
- r'€\d+(?:,\d{3})*(?:\.\d+)?',
193
- r'\d+(?:,\d{3})*\s*AED',
194
- r'\$\d+(?:\.\d+)?[KMB]',
195
- r'€\d+(?:\.\d+)?[KM]'
196
- ],
197
-
198
- 'INTERNATIONAL_CURRENCIES': [
199
- r'\d+(?:,\d{3})*\s+euro',
200
- r'€\d+(?:\.\d+)?M',
201
- r'\d+\s+EUR',
202
- r'\d+(?:,\d{3})*\s+AED',
203
- r'\d+(?:\.\d+)?M\s+AED',
204
- r'\$\d+(?:\.\d+)?M',
205
- r'\$\d+(?:\.\d+)?K',
206
- r'£\d+(?:,\d{3})*(?:\.\d+)?',
207
- r'\d+\s+GBP',
208
- r'\d+\s+CHF',
209
- r'¥\d+(?:,\d{3})*',
210
- r'\d+\s+JPY'
211
- ],
212
-
213
- 'ACCOUNT': [
214
- r'(?:شماره[\s]*)?(?:حساب[\s]*)?(?:بانکی[\s:]*)?(?:[۰-۹0-9]{1,3}[-\s]?)*[۰-۹0-9]{8,20}',
215
- r'حساب[\s]*(?:شماره[\s:]*)?(?:[۰-۹0-9]{1,3}[-\s]?)*[۰-۹0-9]{8,20}',
216
- r'شماره[\s]*حساب[\s:]*(?:[۰-۹0-9]{1,3}[-\s]?)*[۰-۹0-9]{8,20}',
217
- r'Account[\s]*(?:Number[\s:]*)?(?:[0-9]{1,3}[-\s]?)*[0-9]{8,20}',
218
- r'[۰-۹0-9]{3}[-\s]?[۰-۹0-9]{3}[-\s]?[۰-۹0-9]{6,12}',
219
- r'[۰-۹0-9]{2,4}[-\s]?[۰-۹0-9]{6,12}[-\s]?[۰-۹0-9]{2,4}',
220
- r'واریز[\s]*(?:سود[\s:]*)?(?:[۰-۹0-9]{1,3}[-\s]?)*[۰-۹0-9]{8,20}',
221
- r'سود[\s:]*(?:[۰-۹0-9]{1,3}[-\s]?)*[۰-۹0-9]{8,20}'
222
- ],
223
-
224
- 'FINANCIAL_TERMS': [
225
- r'فروش\s+(?:ماهانه|تجمیعی|صادراتی)',
226
- r'درآمد\s+شرکت',
227
- r'سود\s+(?:خالص|نقدی)',
228
- r'صورت��های\s+مالی',
229
- r'بهای\s+تمام‌شده',
230
- r'سودآوری',
231
- r'عملکرد\s+مالی',
232
- r'میانگین\s+فروش',
233
- r'بالاترین\s+رقم\s+فروش',
234
- r'رقم\s+فروش',
235
- r'درآمدهای\s+عملیاتی'
236
- ],
237
-
238
- 'STOCK_SYMBOL': [
239
- r'نماد\s+([آ-یa-zA-Z0-9]+)',
240
- r'(سبهان|غدیر|شتران|شپنا|پترول|فارس|خارک|پلاسکو|جم|کرمان|مارون|اراک|رازی|شازند|کاوه|بندر|پارس|خوزستان|ماهشهر|عسلویه)(?=\s|$|،|\.|\s+)',
241
- r'شرکت\s+([آ-یa-zA-Z\s]+?)(?=\s+در|\s+که|\s+با|،|\.|\s+$|\s+را|\s+به)',
242
- r'پتروشیمی\s+([آ-یa-zA-Z\s]+?)(?=\s+در|\s+که|\s+با|،|\.|\s+$|\s+توان)',
243
- r'(AAPL|GOOGL|MSFT|AMZN|TSLA|META|NVDA|SABIC)(?=\s|$|,|\.)'
244
- ],
245
-
246
- 'DATE': [
247
- r'[۰-۹0-9]{4}[/-][۰-۹0-9]{1,2}[/-][۰-۹0-9]{1,2}',
248
- r'[۰-۹0-9]{1,2}[/-][۰-۹0-9]{1,2}[/-][۰-۹0-9]{4}',
249
- r'(?:[۰-۹0-9]{1,2})\s*(?:فروردین|اردیبهشت|خرداد|تیر|مرداد|شهریور|مهر|آبان|آذر|دی|بهمن|اسفند)\s*(?:[۰-۹0-9]{4})',
250
- r'(?:فروردین|اردیبهشت|خرداد|تیر|مرداد|شهریور|مهر|آبان|آذر|دی|بهمن|اسفند)\s+[۰-۹0-9]{4}',
251
- r'(?:[0-9]{1,2})\s*(?:January|February|March|April|May|June|July|August|September|October|November|December)\s*(?:[0-9]{4})',
252
- r'(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s*[0-9]{1,2},?\s*[0-9]{4}',
253
- r'سال\s+گذشته',
254
- r'سال\s+جاری',
255
- r'این\s+سال',
256
- r'ماه\s+قبل',
257
- r'ماه\s+اخیر',
258
- r'(?:13[0-9]{2}|14[0-9]{2}|20[0-9]{2}|19[0-9]{2})(?=\s|$|،|\.)'
259
- ],
260
-
261
- 'ADVANCED_DATE_FORMATS': [
262
- r'(?:March|April|May|June|July|August|September|October|November|December)\s+\d{1,2}(?:st|nd|rd|th),?\s+\d{4}',
263
- r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z',
264
- r'(?:PST|EST|GMT|UTC)(?:[+-]\d{1,2}:\d{2})?',
265
- r'Eastern\s+Time',
266
- r'GMT[+-]\d{1,2}:\d{2}',
267
- r'end\s+of\s+fiscal\s+year\s+\d{4}/\d{2}/\d{2}'
268
- ],
269
-
270
- 'TIME_RANGES': [
271
- r'\d{2}:\d{2}-\d{2}:\d{2}',
272
- r'\d{2}:\d{2}\s+تا\s+\d{2}:\d{2}',
273
- r'\d{1,2}:\d{2}\s+(?:AM|PM)\s+(?:PST|EST|GMT|UTC)',
274
- r'\d{2}:\d{2}:\d{2}\s+(?:AM|PM)',
275
- r'COB\s*\(Close\s+of\s+Business\)',
276
- r'\d{1,3}\s+(?:business\s+days|روز\s+کاری)'
277
- ],
278
-
279
- 'LOCATION': [
280
- r'(تهران|اصفهان|ماهشهر|عسلویه|بندرعباس|اهواز|شیراز|مشهد|تبریز|کرج|قم|رشت|کرمان|یزد|زاهدان|بوشهر|خرمشهر|آبادان|اراک|قزوین)',
281
- r'استان\s+([آ-ی\s]+)',
282
- r'شهر\s+([آ-ی\s]+)',
283
- r'(ایران|عراق|کویت|عربستان|امارات|قطر|عمان|بحرین|ترکیه|پاکستان|افغانستان)',
284
- r'داخلی|بازار\s+داخلی',
285
- r'خارجی|بازارهای\s+خارجی',
286
- r'(London|Paris|Tokyo|New\s+York|Dubai|Singapore|Hong\s+Kong|Shanghai|Mumbai|Frankfurt|Amsterdam)'
287
- ],
288
-
289
- 'COMPLEX_ADDRESSES': [
290
- r'کیلومتر\s+\d+\s+جاده\s+[آ-ی\s]+-[آ-ی\s]+',
291
- r'روبروی\s+(?:پمپ\s+بنزین|بانک|پارک|مسجد|بیمارستان)\s+[آ-یa-zA-Z\s]+',
292
- r'Building-[A-Z],?\s+Floor-\d+,?\s+Unit-[A-Z0-9]+',
293
- r'rack\s+number\s+R-\d+,?\s+slot\s+\d+',
294
- r'phase\s+\d+\s+development,?\s+block\s+[A-Z],?\s+plot\s+\d+-[A-Z]',
295
- r'\d{2,5}\s+[A-Z][a-z]+\s+(?:Street|Avenue|Boulevard|Road|Drive),?\s+Floor\s+\d+,?\s+Building\s+[A-Z]',
296
- r'شهرک\s+صنعتی\s+[آ-ی\s]+،?\s+محور\s+[آ-ی\s]+'
297
- ],
298
-
299
- 'TECHNICAL_CODES': [
300
- r'SN-\d{4}-[A-Z]{3}-\d{4}',
301
- r'Serial\s+Number[\s:]*[A-Z0-9-]+',
302
- r'REF-[A-Z]{3}-\d{4}-\d{3}',
303
- r'DOC-[A-Z]{2}-\d{4}-\d{4}',
304
- r'INF-\d{4}-\d{4}',
305
- r'CTR/\d{4}/\d{3}',
306
- r'HVAC-\d{7}',
307
- r'Generator-Model-[A-Z0-9]+',
308
- r'LOI-\d{4}-[A-Z]{4}-\d{3}',
309
- r'BOQ-\d{4}-[A-Z]{3}-\d{3}',
310
- r'#INV-\d{4}-Q\d-\d{4}',
311
- r'ESC-\d{4}-[A-Z]{3}-\d{3}',
312
- r'BN-\d{6}-[A-Z]\d+'
313
- ],
314
-
315
- 'NETWORK_ADDRESSES': [
316
- r'\b(?:\d{1,3}\.){3}\d{1,3}\b',
317
- r'xxx\.xxx\.xxx\.xxx',
318
- 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}',
319
- r'srv-[a-z]+-[a-z]+-\d{2}',
320
- r'[a-z]+-[a-z]+\d*\.[a-z]+\.[a-z]+',
321
- r'[a-zA-Z0-9-]+\.[a-zA-Z]{2,4}(?:\.[a-zA-Z]{2,4})?'
322
- ],
323
-
324
- 'TECHNICAL_UNITS': [
325
- r'\d+(?:\.\d+)?\s*MW',
326
- r'\d+(?:\.\d+)?\s*kWh?',
327
- r'\d+(?:,\d{3})*\s*cubic\s+meters',
328
- r'\d+(?:,\d{3})*\s*m³',
329
- r'\d+(?:,\d{3})*\s*sq\s+ft',
330
- r'\d+(?:\.\d+)?\s*ppm',
331
- r'\d+(?:\.\d+)?\s*mg/m³',
332
- r'\b(?:CO2|NOx|SO2)\b',
333
- r'\d+(?:\.\d+)?\s*TB',
334
- r'\d+(?:\.\d+)?\s*GB',
335
- r'\d+(?:,\d{3})*\s*square\s+meters',
336
- r'\d+(?:\.\d+)?\%\s*efficiency',
337
- r'FICO\s+score:\s*\d{3}',
338
- r'\d+(?:\.\d+)?\s*(?:bar|psi)',
339
- r'\d+(?:\.\d+)?\s*°[CF]',
340
- r'\d+(?:\.\d+)?\s*(?:rpm|m/s)'
341
- ],
342
-
343
- 'ACRONYMS_ABBREVIATIONS': [
344
- r'\b(?:HVAC|IT|HSE|BOQ|LC|COB)\b',
345
- r'\b(?:YTD|NNN|EIN|SSN|FICO)\b',
346
- r'\bIP\s+Address\b',
347
- r'\bMAC\s+Address\b',
348
- r'\bURL\b',
349
- r'\b(?:LLC|Corp|Inc|Ltd)\b',
350
- r'\b(?:PST|GMT|UTC|EST)\b',
351
- r'\b(?:CO2|NOx|pH|UV)\b',
352
- r'\b(?:SCADA|PLC|HMI)\b',
353
- r'\b(?:GDP|CPI|ROI|NPV)\b',
354
- r'\b(?:FOB|CIF|DDP)\b',
355
- r'\b(?:ABA|SWIFT|IBAN)\b'
356
- ],
357
-
358
- 'COMPANY': [
359
- r'شرکت(?=\s+در|\s+که|\s+با|\s+را|\s+به|\s+طی)',
360
- r'([آ-یa-zA-Z\s]+)\s+شرکت',
361
- r'این\s+شرکت(?=\s|$|،|\.)',
362
- r'(بانک\s+[آ-یa-zA-Z\s]+)',
363
- r'([A-Z][a-zA-Z\s]+(?:Inc|Corp|Corporation|Company|Ltd|Limited|LLC))'
364
- ],
365
-
366
- 'BUSINESS_TERMS': [
367
- r'تحلیل\s+عملکرد',
368
- r'گزارش\s+(?:فعالیت|عملکرد)\s+ماهانه',
369
- r'وضعیت\s+فروش',
370
- r'تولید\s+پایدار',
371
- r'سهم\s+بازار',
372
- r'صادرات\s+هدفمند',
373
- r'بهره‌وری',
374
- r'ظرفیت‌های\s+داخلی',
375
- r'شرکت‌های\s+پیشرو',
376
- r'صنعت\s+پتروشیمی',
377
- r'سرمایه‌گذاران\s+بنیادی',
378
- r'شاخص‌های\s+عملیاتی',
379
- r'برنامه‌ریزی\s+مناسب',
380
- r'واحد\s+فروش',
381
- r'موجودی\s+انبار',
382
- r'فاز\s+رشد\s+جدید',
383
- r'ترکیب\s+فروش',
384
- r'سهم\s+صادراتی',
385
- r'روند\s+عملکرد',
386
- r'اعداد\s+اعلام‌شده',
387
- r'داده‌های\s+ثبت‌شده'
388
- ],
389
-
390
- 'PRODUCT': [
391
- r'\b(?:VCM|PVC|PE|PP|PS|ABS|SAN|PC|PMMA|PET|PBT|PA|POM|TPU)\b',
392
- r'پلی\s*(?:اتیلن|پروپیلن|استایرن|کربنات|متیل)',
393
- r'\b(?:اتیلن|پروپیلن|بنزن|تولوئن|زایلن|متانول|اتانول|استون|فنول)\b',
394
- r'\b(?:کلر|هیدروژن|اکسیژن|نیتروژن|آمونیاک|اتان|پروپان|بوتان)\b',
395
- r'محصول(?:ات)?',
396
- r'تولیدات\s+شرکت'
397
- ],
398
-
399
- 'PETROCHEMICAL': [
400
- r'\b(?:LDPE|HDPE|LLDPE|PP|PS|EPS|ABS|SAN|PC|PMMA|PET|PBT|PA6|PA66|POM|TPU|EVA|EAA)\b',
401
- r'(?:Ethylene\s+Vinyl\s+Acetate|Ethyl\s+Acrylate|Methyl\s+Methacrylate|Polyethylene\s+Terephthalate)'
402
- ],
403
-
404
- 'PERCENTAGE': [
405
- r'\d+(?:\.\d+)?\s*درصد(?:\s+افزایش|\s+رشد|\s+کاهش|\s+بالاتر|\s+پایین‌تر)?',
406
- r'\d+(?:\.\d+)?\s*%',
407
- r'معادل\s+\d+(?:\.\d+)?\s*درصد',
408
- r'حدود\s+\d+(?:\.\d+)?\s*درصد',
409
- r'با\s+\d+(?:\.\d+)?\s*درصد\s+افزایش',
410
- r'رشد\s+\d+(?:\.\d+)?\s*درصدی',
411
- r'\d+(?:\.\d+)?\s*درصدی(?=\s+همراه|\s+بوده)',
412
- r'میزان\s+رشد(?=\s+نسبت|\s+معادل)',
413
- r'افزایش\s+قابل‌توجهی',
414
- r'بهبود\s+نسبی',
415
- r'\d+(?:\.\d+)?\%\s*(?:increase|decrease|growth|improvement)',
416
- r'(?:approximately|about)\s+\d+(?:\.\d+)?\%'
417
- ],
418
-
419
- 'VOLUME': [
420
- r'\d+(?:,\d{3})*\s*تن',
421
- r'\d+(?:,\d{3})*\s*(?:کیلوگرم|لیتر|بشکه)',
422
- r'میزان\s+\d+(?:,\d{3})*\s*تن',
423
- r'مقدار\s+تولید',
424
- r'حجم\s+فروش',
425
- r'ظرفیت\s+(?:تولید|اسمی)',
426
- r'\d+(?:,\d{3})*\s*(?:tons|kg|liters|barrels)',
427
- r'\d+(?:,\d{3})*\s*(?:metric\s+tons|MT)',
428
- r'\d+(?:,\d{3})*\s*(?:thousand\s+tons|KT)'
429
- ],
430
-
431
- 'RATIOS': [
432
- r'نسبت\s+(?:فروش|تولید)\s+به\s+[آ-ی\s]+',
433
- r'\d+(?:\.\d+)?\s*نزدیک',
434
- r'برابر\s+با\s+\d+(?:\.\d+)?',
435
- r'معادل\s+\d+(?:\.\d+)?',
436
- r'میزان\s+(?:رشد|افزایش)',
437
- r'شاخص\s+(?:مهم|عملیاتی)',
438
- r'\d+(?:\.\d+)?\s*درصد\s+کل\s+تولید'
439
- ],
440
-
441
- 'PHONE': [
442
- r'(?:تلفن[\s:]*)?(?:شماره[\s:]*)?(?:0)?(?:[۰-۹0-9]{2,3}[-\s]?)?[۰-۹0-9]{7,8}',
443
- r'(?:تماس[\s:]*)?(?:شماره[\s:]*)?(?:با[\s]*)?(?:0)?(?:[۰-۹0-9]{2,3}[-\s]?)?[۰-۹0-9]{7,8}',
444
- r'(?:موبایل[\s:]*)?(?:شماره[\s:]*)?(?:0)?9[۰-۹0-9]{9}',
445
- r'[۰-۹0-9]{3,4}[-\s][۰-۹0-9]{7,8}',
446
- r'[۰-۹0-9]{11}(?!\d)',
447
- r'(?:\+98|0098)?[۰-۹0-9]{10}',
448
- r'[۰-۹0-9]{3,4}[-\s]?[۰-۹0-9]{3,4}[-\s]?[۰-۹0-9]{3,4}',
449
- r'\+[0-9]{1,3}-[0-9]{3}-[0-9]{3}-[0-9]{4}(?:\s+ext\.\s+[0-9]{3,4})?',
450
- r'\([0-9]{3}\)\s+[0-9]{3}-[0-9]{4}'
451
- ],
452
-
453
- 'EMAIL': [
454
- r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
455
- r'ایمیل[\s:]*[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
456
- r'email[\s:]*[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
457
- r'نشانی[\s]*الکترونیکی[\s:]*[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
458
- r'آدرس[\s]*ایمیل[\s:]*[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
459
- r'facility\.manager@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
460
- ]
461
- }
462
-
463
- def anonymize_text(self, original_text, lang='fa', selected_categories=None):
464
- """گام 1: ناشناس‌سازی متن با الگوهای انتخاب شده - نسخه Lightweight"""
465
- try:
466
- if not original_text or not original_text.strip():
467
- return "❌ Please enter input text!" if lang == 'en' else "❌ لطفاً متن ورودی را وارد کنید!"
468
-
469
- # ریست متغیرها
470
- self.mapping_table = {}
471
- self.counters = {key: 0 for key in self.counters.keys()}
472
-
473
- anonymized = original_text
474
- found_entities = set()
475
-
476
- # تشخیص زبان
477
- detected_lang = self.detect_language(original_text)
478
- logger.info(f"Detected language: {detected_lang}")
479
-
480
- # استخراج با الگوهای Regex - Lightweight mode
481
- all_patterns = self.get_comprehensive_patterns()
482
-
483
- # فیلتر کردن الگوها بر اساس انتخاب کاربر
484
- if selected_categories:
485
- selected_pattern_types = self.get_selected_patterns(selected_categories, lang)
486
- patterns = {k: v for k, v in all_patterns.items() if k in selected_pattern_types}
487
- logger.info(f"📋 Using selected pattern categories: {len(patterns)} types")
488
- else:
489
- patterns = all_patterns
490
- logger.info("📋 Using all available pattern categories")
491
-
492
- # پردازش patterns
493
- logger.info("🔍 Running lightweight regex extraction...")
494
-
495
- processed_entities = set()
496
-
497
- # اولویت‌بندی دسته‌ها
498
- priority_order = [
499
- 'ID_NUMBER', 'EMAIL', 'PHONE', 'ACCOUNT', 'TECHNICAL_CODES',
500
- 'NETWORK_ADDRESSES', 'INTERNATIONAL_CURRENCIES', 'AMOUNT',
501
- 'TECHNICAL_UNITS', 'ACRONYMS_ABBREVIATIONS', 'ADVANCED_DATE_FORMATS',
502
- 'TIME_RANGES', 'COMPLEX_ADDRESSES', 'MIXED_NAMES', 'ENGLISH_TITLES',
503
- 'STOCK_SYMBOL', 'COMPANY', 'PERSON', 'PERCENTAGE', 'VOLUME',
504
- 'RATIOS', 'LOCATION', 'DATE', 'FINANCIAL_TERMS', 'BUSINESS_TERMS',
505
- 'PRODUCT', 'PETROCHEMICAL'
506
- ]
507
-
508
- for category in priority_order:
509
- if category in patterns:
510
- pattern_list = patterns[category]
511
- for pattern in pattern_list:
512
- try:
513
- matches = re.finditer(pattern, original_text, re.IGNORECASE | re.MULTILINE)
514
- for match in matches:
515
- if match.groups():
516
- item = match.group(1).strip()
517
- full_match = match.group(0).strip()
518
- else:
519
- item = match.group(0).strip()
520
- full_match = item
521
-
522
- # بررسی تداخل
523
- overlaps = False
524
- match_start, match_end = match.span()
525
-
526
- for proc_start, proc_end in processed_entities:
527
- if not (match_end <= proc_start or match_start >= proc_end):
528
- overlaps = True
529
- break
530
-
531
- if (not overlaps and
532
- full_match not in found_entities and
533
- full_match not in self.mapping_table and
534
- len(full_match) >= 2):
535
-
536
- self.counters[category] += 1
537
- code = f"{category}_{self.counters[category]:03d}_REGEX"
538
- self.mapping_table[full_match] = code
539
- found_entities.add(full_match)
540
- processed_entities.add((match_start, match_end))
541
- except re.error as e:
542
- logger.error(f"Regex error in pattern {pattern}: {e}")
543
- continue
544
-
545
- # جایگزینی در متن
546
- sorted_items = sorted(self.mapping_table.items(), key=lambda x: len(x[0]), reverse=True)
547
- for original_item, code in sorted_items:
548
- anonymized = anonymized.replace(original_item, code)
549
-
550
- logger.info(f"✅ Lightweight anonymization completed. Found {len(self.mapping_table)} entities.")
551
- return anonymized
552
-
553
- except Exception as e:
554
- logger.error(f"Anonymization error: {e}")
555
- return f"❌ Error in anonymization: {str(e)}" if lang == 'en' else f"❌ خطا در ناشناس‌سازی: {str(e)}"
556
-
557
- def send_to_chatgpt(self, anonymized_text, lang='fa'):
558
- """گام 2: ارسال به ChatGPT"""
559
- try:
560
- if not anonymized_text or not anonymized_text.strip():
561
- return "❌ Anonymized text is empty!" if lang == 'en' else "❌ متن ناشناس‌شده خالی است!"
562
-
563
- if not self.api_key:
564
- return "❌ API Key not configured! Please set OPENAI_API_KEY environment variable." if lang == 'en' else "❌ کلید API تنظیم نشده است!"
565
-
566
- system_msg = "You are a professional analyst. Answer questions accurately." if lang == 'en' else "شما یک تحلیلگر حرفه‌ای هستید. به سوالات با دقت پاسخ دهید."
567
-
568
- headers = {
569
- "Authorization": f"Bearer {self.api_key}",
570
- "Content-Type": "application/json"
571
- }
572
-
573
- data = {
574
- "model": "gpt-4o-mini",
575
- "messages": [
576
- {"role": "system", "content": system_msg},
577
- {"role": "user", "content": anonymized_text}
578
- ],
579
- "max_tokens": 2000,
580
- "temperature": 0.7
581
- }
582
-
583
- response = requests.post(
584
- "https://api.openai.com/v1/chat/completions",
585
- headers=headers,
586
- json=data,
587
- timeout=30
588
- )
589
-
590
- if response.status_code == 200:
591
- result = response.json()
592
- return result['choices'][0]['message']['content']
593
- else:
594
- error_data = response.json() if response.content else {}
595
- error_message = error_data.get('error', {}).get('message', response.text)
596
- return f"❌ API Error: {error_message}"
597
-
598
- except Exception as e:
599
- return f"❌ Error connecting to ChatGPT: {str(e)}" if lang == 'en' else f"❌ خطا در ارتباط با ChatGPT: {str(e)}"
600
-
601
- def deanonymize_response(self, gpt_response, lang='fa'):
602
- """گام 3: بازگردانی"""
603
- try:
604
- if not gpt_response or not gpt_response.strip():
605
- return "❌ ChatGPT response is empty!" if lang == 'en' else "❌ پاسخ ChatGPT خالی است!"
606
-
607
- if not self.mapping_table:
608
- return "❌ Mapping table is empty!" if lang == 'en' else "❌ جدول نگاشت خالی است!"
609
-
610
- final_result = gpt_response
611
- reverse_mapping = {code: original for original, code in self.mapping_table.items()}
612
-
613
- sorted_codes = sorted(reverse_mapping.items(), key=lambda x: len(x[0]), reverse=True)
614
- for code, original in sorted_codes:
615
- final_result = final_result.replace(code, original)
616
-
617
- return final_result
618
-
619
- except Exception as e:
620
- return f"❌ Deanonymization error: {str(e)}" if lang == 'en' else f"❌ خطا در بازگردانی: {str(e)}"
621
-
622
- def get_model_status(self):
623
- """وضعیت سیستم"""
624
- status = "🚀 **Lightweight Anonymization System Status (No Dependencies):**\n\n"
625
-
626
- status += "• **Mode**: Pure Regex Processing (No torch/transformers required)\n"
627
- status += "• **Performance**: High-speed lightweight processing\n"
628
- status += "• **Compatibility**: Works on any Python environment\n"
629
- status += "• **Memory Usage**: Minimal (< 100MB)\n"
630
-
631
- status += f"\n🎯 **Available Pattern Categories:**"
632
- for cat_key, cat_info in self.pattern_categories.items():
633
- icon = cat_info['icon']
634
- name_fa = cat_info['name_fa']
635
- pattern_count = len(cat_info['patterns'])
636
- status += f"\n {icon} {name_fa}: {pattern_count} patterns"
637
-
638
- status += f"\n\n✨ **Lightweight Features:**"
639
- status += f"\n 🎯 User-controlled category selection"
640
- status += f"\n 🛡️ High-precision regex patterns (221 total)"
641
- status += f"\n 📊 Efficient targeted processing"
642
- status += f"\n ⚡ Zero external model dependencies"
643
- status += f"\n 🔥 Works perfectly in HuggingFace Spaces"
644
-
645
- status += f"\n\n💡 **Advantages of Lightweight Mode:**"
646
- status += f"\n ✅ No dependency issues"
647
- status += f"\n ✅ Fast processing speed"
648
- status += f"\n ✅ Low memory usage"
649
- status += f"\n ✅ Consistent results"
650
- status += f"\n ✅ Easy deployment anywhere"
651
-
652
- return status
653
-
654
- # ایجاد instance
655
- anonymizer = LightweightDataAnonymizer()
656
-
657
- def process_all_steps(input_text, language, selected_categories):
658
- """پردازش خودکار تمام مراحل - نسخه Lightweight"""
659
- lang = 'en' if language == 'English' else 'fa'
660
-
661
- if not input_text.strip():
662
- error_msg = "❌ Please enter input text!" if lang == 'en' else "❌ لطفاً متن ورودی را وارد کنید!"
663
- return error_msg, "", "", ""
664
-
665
- try:
666
- start_time = time.time()
667
-
668
- anonymized_text = anonymizer.anonymize_text(input_text, lang, selected_categories)
669
- if anonymized_text.startswith("❌"):
670
- return anonymized_text, "", "", ""
671
-
672
- gpt_response = anonymizer.send_to_chatgpt(anonymized_text, lang)
673
- if gpt_response.startswith("❌"):
674
- entities_found = len(anonymizer.mapping_table)
675
-
676
- selected_count = len(selected_categories) if selected_categories else 0
677
-
678
- success_msg = (f"✅ Lightweight anonymization completed successfully!\n"
679
- f"📋 Selected categories: {selected_count} | 🔍 Pure Regex Processing\n"
680
- f"📊 Total protected entities: {entities_found} | ⚡ High-speed lightweight mode")
681
- return success_msg, anonymized_text, gpt_response, ""
682
-
683
- final_result = anonymizer.deanonymize_response(gpt_response, lang)
684
-
685
- total_time = time.time() - start_time
686
- entities_found = len(anonymizer.mapping_table)
687
-
688
- selected_count = len(selected_categories) if selected_categories else 8
689
-
690
- success_msg = (f"🎉 Complete lightweight anonymization & restoration successful!\n"
691
- f"🔧 Method: Pure Regex Processing | 📋 Categories: {selected_count}/8\n"
692
- f"📊 Total: {entities_found} entities | ⏱️ Time: {total_time:.2f}s\n"
693
- f"⚡ Zero dependencies - Maximum compatibility!")
694
-
695
- return success_msg, anonymized_text, gpt_response, final_result
696
-
697
- except Exception as e:
698
- error_msg = f"❌ Processing error: {str(e)}" if lang == 'en' else f"❌ خطا در پردازش: {str(e)}"
699
- return error_msg, "", "", ""
700
-
701
- def get_mapping_table(language):
702
- """نمایش جدول نگاشت"""
703
- lang = 'en' if language == 'English' else 'fa'
704
-
705
- if not anonymizer.mapping_table:
706
- return "❌ Mapping table is empty!" if lang == 'en' else "❌ جدول نگاشت خالی است!"
707
-
708
- result = "📋 **Lightweight Mapping Table (Pure Regex):**\n\n"
709
-
710
- # نمایش آمار کلی
711
- result += f"📊 **Statistics**: {len(anonymizer.mapping_table)} total entities\n"
712
- result += f"🔍 **Method**: Pure Regex Processing (221 patterns)\n"
713
- result += f"⚡ **Mode**: Lightweight (No external dependencies)\n\n"
714
-
715
- # دسته‌بندی نتایج
716
- category_stats = {}
717
- for original, code in anonymizer.mapping_table.items():
718
- category = code.split('_')[0]
719
- if category not in category_stats:
720
- category_stats[category] = []
721
- category_stats[category].append((original, code))
722
-
723
- # نمایش نتایج بر اساس دسته‌بندی
724
- for category, items in category_stats.items():
725
- if len(items) > 0:
726
- result += f"🔍 **{category}** ({len(items)} items):\n"
727
- for original, code in items[:3]: # نمایش 3 نمونه اول
728
- result += f" • `{original}` → `{code}`\n"
729
- if len(items) > 3:
730
- result += f" ... و {len(items) - 3} مورد دیگر\n"
731
- result += "\n"
732
-
733
- result += "✨ **Lightweight System**: Maximum efficiency with minimal dependencies!"
734
-
735
- return result
736
-
737
- def clear_all():
738
- """پاک کردن همه"""
739
- anonymizer.mapping_table = {}
740
- anonymizer.counters = {key: 0 for key in anonymizer.counters.keys()}
741
- return "", "", "", "", ""
742
-
743
- # CSS ساده
744
- custom_css = """
745
- .gradio-container {
746
- font-family: 'Segoe UI', Arial, sans-serif !important;
747
- max-width: 1400px !important;
748
- margin: 0 auto !important;
749
- }
750
-
751
- .rtl {
752
- direction: rtl !important;
753
- text-align: right !important;
754
- }
755
-
756
- .gradio-textbox {
757
- border-radius: 8px !important;
758
- min-height: 120px !important;
759
- }
760
-
761
- .gradio-button {
762
- border-radius: 8px !important;
763
- font-weight: bold !important;
764
- margin: 5px !important;
765
- }
766
-
767
- .status-success {
768
- background-color: #d4edda !important;
769
- border: 1px solid #c3e6cb !important;
770
- color: #155724 !important;
771
- padding: 10px !important;
772
- border-radius: 8px !important;
773
- }
774
- """
775
-
776
- # رابط کاربری Gradio ساده
777
- with gr.Blocks(title="Lightweight Anonymization System", theme=gr.themes.Soft(), css=custom_css) as app:
778
-
779
- gr.HTML("<h1 style='text-align: center; color: #2563eb;'>⚡ سیستم ناشناس‌سازی سبک و سریع</h1>")
780
- gr.HTML("<p style='text-align: center; color: #6b7280;'>بدون وابستگی به torch/transformers - سازگار با تمام محیط‌ها</p>")
781
-
782
- with gr.Row():
783
- language_selector = gr.Radio(
784
- choices=["فارسی", "English"],
785
- value="فارسی",
786
- label="Language / زبان"
787
- )
788
-
789
- with gr.Row():
790
- with gr.Column(scale=1):
791
- gr.HTML("<h3>🎯 انتخاب دسته‌بندی‌ها:</h3>")
792
- pattern_categories = gr.CheckboxGroup(
793
- choices=anonymizer.get_category_choices('fa'),
794
- value=anonymizer.get_category_choices('fa'),
795
- label="دسته‌بندی‌های الگو",
796
- interactive=True
797
- )
798
-
799
- gr.HTML("<p style='color: #6b7280; font-size: 0.9em;'>💡 فقط دسته‌هایی که نیاز دارید انتخاب کنید</p>")
800
-
801
- with gr.Column(scale=2):
802
- input_text = gr.Textbox(
803
- lines=10,
804
- placeholder="متن خود را اینجا وارد کنید...\n\nمثال: آقای احمد رضایی با شماره تماس 09123456789 و ایمیل ahmad@company.com درخواست وام به مبلغ 500 میلیون تومان داده است.",
805
- label="متن ورودی",
806
- rtl=True
807
- )
808
-
809
- with gr.Row():
810
- process_btn = gr.Button("🚀 پردازش سریع با دسته‌بندی‌های انتخاب شده", variant="primary", scale=2)
811
- clear_btn = gr.Button("🗑️ پاک کردن", variant="secondary", scale=1)
812
-
813
- status = gr.Textbox(
814
- label="وضعیت پردازش",
815
- lines=4,
816
- interactive=False,
817
- rtl=True,
818
- elem_classes=["status-success"]
819
- )
820
-
821
- with gr.Accordion("📄 نتایج پردازش", open=True):
822
- with gr.Row():
823
- with gr.Column():
824
- gr.HTML("<h4>🎭 متن ناشناس‌شده</h4>")
825
- anonymized_output = gr.Textbox(
826
- lines=6,
827
- interactive=False,
828
- rtl=True,
829
- placeholder="متن ناشناس‌شده اینجا نمایش داده می‌شود..."
830
- )
831
-
832
- with gr.Column():
833
- gr.HTML("<h4>🤖 پاسخ ChatGPT</h4>")
834
- gpt_output = gr.Textbox(
835
- lines=6,
836
- interactive=False,
837
- rtl=True,
838
- placeholder="پاسخ ChatGPT اینجا نمایش داده می‌شود..."
839
- )
840
-
841
- gr.HTML("<h4>✅ پاسخ نهایی بازگردانده شده</h4>")
842
- final_output = gr.Textbox(
843
- lines=6,
844
- interactive=False,
845
- rtl=True,
846
- placeholder="پاسخ نهایی با اطلاعات اصلی بازگردانده شده اینجا نمایش داده می‌شود..."
847
- )
848
-
849
- with gr.Accordion("📊 جزئیات و وضعیت", open=False):
850
- with gr.Row():
851
- mapping_btn = gr.Button("📋 نمایش جدول نگاشت")
852
- status_btn = gr.Button("⚡ وضعیت سیستم سبک")
853
-
854
- with gr.Row():
855
- mapping_output = gr.Textbox(
856
- lines=12,
857
- label="جدول نگاشت",
858
- interactive=False,
859
- visible=False,
860
- rtl=True
861
- )
862
-
863
- system_status_output = gr.Textbox(
864
- lines=15,
865
- label="وضعیت سیستم",
866
- interactive=False,
867
- visible=False,
868
- rtl=True
869
- )
870
-
871
- # Event handlers
872
- process_btn.click(
873
- fn=process_all_steps,
874
- inputs=[input_text, language_selector, pattern_categories],
875
- outputs=[status, anonymized_output, gpt_output, final_output]
876
- )
877
-
878
- clear_btn.click(
879
- fn=clear_all,
880
- outputs=[input_text, anonymized_output, gpt_output, final_output, status]
881
- )
882
-
883
- mapping_btn.click(
884
- fn=get_mapping_table,
885
- inputs=[language_selector],
886
- outputs=[mapping_output]
887
- )
888
-
889
- mapping_btn.click(
890
- fn=lambda: gr.update(visible=True),
891
- outputs=[mapping_output]
892
- )
893
-
894
- status_btn.click(
895
- fn=lambda: anonymizer.get_model_status(),
896
- outputs=[system_status_output]
897
- )
898
-
899
- status_btn.click(
900
- fn=lambda: gr.update(visible=True),
901
- outputs=[system_status_output]
902
- )
903
-
904
- if __name__ == "__main__":
905
- logger.info("⚡ Starting Lightweight Anonymization System...")
906
- logger.info("🔥 No torch/transformers dependencies required!")
907
- logger.info("✅ Ready for any environment including HuggingFace Spaces!")
908
-
909
- app.launch(
910
- share=False,
911
- server_name="0.0.0.0",
912
- server_port=7860,
913
- show_error=True
914
- )