leilaghomashchi commited on
Commit
0c48d4b
·
verified ·
1 Parent(s): d486ae8

Upload final_app.py

Browse files
Files changed (1) hide show
  1. final_app.py +271 -0
final_app.py ADDED
@@ -0,0 +1,271 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import re
4
+
5
+ class AnonymizationEvaluator:
6
+ def __init__(self):
7
+ # فهرست بانک‌های ایران
8
+ self.iranian_banks = [
9
+ 'بانک ملی', 'بانک صادرات', 'بانک پاسارگاد', 'بانک کشاورزی',
10
+ 'بانک ملت', 'بانک تجارت', 'بانک صنعت و معدن', 'بانک رسالت',
11
+ 'بانک دی', 'بانک پارسیان', 'بانک کارآفرین', 'بانک سامان',
12
+ 'بانک اقتصاد نوین', 'بانک مهر اقتصاد', 'بانک آینده', 'بانک کشاورزی'
13
+ ]
14
+
15
+ # فهرست سازمان‌های دولتی
16
+ self.government_orgs = [
17
+ 'بانک مرکزی جمهوری اسلامی ایران',
18
+ 'دفتر اسناد رسمی',
19
+ 'اداره کل مالیات',
20
+ 'تامین اجتماعی',
21
+ 'وزارت دادگستری'
22
+ ]
23
+
24
+ self.patterns = {
25
+ 'person_names': {
26
+ 'pattern': re.compile(r'(?:آقای|خانم)\s+[\u0600-\u06FF\s]+?(?=\s+با|$)', re.UNICODE),
27
+ 'replacement': re.compile(r'person_\d+'),
28
+ 'name': 'اسامی اشخاص'
29
+ },
30
+ 'national_ids': {
31
+ 'pattern': re.compile(r'\b\d{10,11}\b'),
32
+ 'replacement': re.compile(r'id_number_\d+'),
33
+ 'name': 'کدهای ملی'
34
+ },
35
+ 'phone_numbers': {
36
+ 'pattern': re.compile(r'(?:09\d{9}|021-\d{8}|0\d{2,3}-\d{8})'),
37
+ 'replacement': re.compile(r'phone_\d+'),
38
+ 'name': 'شماره تلفن‌ها'
39
+ },
40
+ 'account_numbers': {
41
+ 'pattern': re.compile(r'\b\d{3}-\d{3}-\d{3}-\d{1}\b'),
42
+ 'replacement': re.compile(r'account_\d+'),
43
+ 'name': 'شماره حساب‌ها'
44
+ },
45
+ 'card_numbers': {
46
+ 'pattern': re.compile(r'\b\d{4}-\d{4}-\d{4}-\d{4}\b'),
47
+ 'replacement': re.compile(r'card_number_\d+'),
48
+ 'name': 'شماره کارت‌ها'
49
+ },
50
+ 'amounts': {
51
+ 'pattern': re.compile(r'\b\d+\s*تومان'),
52
+ 'replacement': re.compile(r'amount_\d+'),
53
+ 'name': 'مبالغ مالی'
54
+ },
55
+ 'dates': {
56
+ 'pattern': re.compile(r'(?:\d{4}\/\d{2}\/\d{2}|۳۰\s*اسفند\s*۱۴۰۳|\b\d{4}\b(?=\s*سال))'),
57
+ 'replacement': re.compile(r'date_\d+'),
58
+ 'name': 'تاریخ‌ها'
59
+ },
60
+ 'iranian_banks': {
61
+ 'pattern': re.compile(f"({'|'.join(self.iranian_banks)})", re.UNICODE),
62
+ 'replacement': re.compile(r'company_\d+'),
63
+ 'name': 'بانک‌های ایران'
64
+ },
65
+ 'government_orgs': {
66
+ 'pattern': re.compile(f"({'|'.join(self.government_orgs)})", re.UNICODE),
67
+ 'replacement': re.compile(r'company_\d+'),
68
+ 'name': 'سازمان‌های دولتی'
69
+ },
70
+ 'other_companies': {
71
+ 'pattern': re.compile(r'شرکت\s+[\u0600-\u06FF\s]+?(?=\s|$|،|\.)', re.UNICODE),
72
+ 'replacement': re.compile(r'company_\d+'),
73
+ 'name': 'سایر شرکت‌ها'
74
+ },
75
+ 'addresses': {
76
+ 'pattern': re.compile(r'(?:تهران|کرج|اصفهان|بندر\s*ماهشهر)[،\s]+[^،\.]+', re.UNICODE),
77
+ 'replacement': re.compile(r'(?:full_address_\d+|location_\d+)'),
78
+ 'name': 'آدرس‌ها'
79
+ },
80
+ 'documents': {
81
+ 'pattern': re.compile(r'(?:INV-\d{4}-\d{4}|RPT-\d{4}-\d{4}|\b\d{4}(?=\s+تهران)|\b\d{7}\b)'),
82
+ 'replacement': re.compile(r'(?:invoice_\d+|report_\d+|contract_\d+|cheque_\d+)'),
83
+ 'name': 'شماره اسناد'
84
+ }
85
+ }
86
+
87
+ def analyze_entities(self, original_text, anonymized_text):
88
+ results = {}
89
+ for entity_type, config in self.patterns.items():
90
+ original_matches = config['pattern'].findall(original_text)
91
+ replacement_matches = config['replacement'].findall(anonymized_text)
92
+
93
+ anonymized_count = 0
94
+ for match in original_matches:
95
+ if not anonymized_text.count(match.strip()):
96
+ anonymized_count += 1
97
+
98
+ if len(replacement_matches) > anonymized_count:
99
+ anonymized_count = min(len(replacement_matches), len(original_matches))
100
+
101
+ percentage = (anonymized_count / len(original_matches) * 100) if original_matches else 0
102
+
103
+ results[entity_type] = {
104
+ 'name': config['name'],
105
+ 'total': len(original_matches),
106
+ 'anonymized': anonymized_count,
107
+ 'percentage': round(percentage, 1),
108
+ 'samples': original_matches[:3] if original_matches else []
109
+ }
110
+ return results
111
+
112
+ def evaluate_csv(self, csv_file):
113
+ try:
114
+ if csv_file is None:
115
+ return "لطفاً یک فایل CSV آپلود کنید."
116
+
117
+ try:
118
+ df = pd.read_csv(csv_file.name, encoding='utf-8')
119
+ except:
120
+ df = pd.read_csv(csv_file.name, encoding='utf-8', sep='\t')
121
+
122
+ if 'original_text' not in df.columns or 'anonymized_text' not in df.columns:
123
+ return "فایل CSV باید شامل ستون‌های 'original_text' و 'anonymized_text' باشد."
124
+
125
+ overall_stats = {}
126
+ total_entities = 0
127
+ total_anonymized = 0
128
+
129
+ for _, row in df.iterrows():
130
+ if pd.isna(row['original_text']) or pd.isna(row['anonymized_text']):
131
+ continue
132
+
133
+ row_analysis = self.analyze_entities(str(row['original_text']), str(row['anonymized_text']))
134
+
135
+ for entity_type, data in row_analysis.items():
136
+ if entity_type not in overall_stats:
137
+ overall_stats[entity_type] = {
138
+ 'name': data['name'],
139
+ 'total': 0,
140
+ 'anonymized': 0,
141
+ 'samples': []
142
+ }
143
+
144
+ overall_stats[entity_type]['total'] += data['total']
145
+ overall_stats[entity_type]['anonymized'] += data['anonymized']
146
+ overall_stats[entity_type]['samples'].extend(data['samples'])
147
+
148
+ total_entities += data['total']
149
+ total_anonymized += data['anonymized']
150
+
151
+ for entity_type in overall_stats:
152
+ stats = overall_stats[entity_type]
153
+ stats['percentage'] = round((stats['anonymized'] / stats['total'] * 100) if stats['total'] > 0 else 0, 1)
154
+ stats['samples'] = list(set(stats['samples']))[:3]
155
+
156
+ return self.generate_report(overall_stats, total_entities, total_anonymized, len(df))
157
+
158
+ except Exception as e:
159
+ return f"خطا در پردازش فایل: {str(e)}"
160
+
161
+ def generate_report(self, stats, total_entities, total_anonymized, total_rows):
162
+ report = f"""# گزارش ارزیابی ناشناس‌سازی متن
163
+
164
+ ## خلاصه کلی
165
+ - **تعداد ردیف‌های پردازش شده**: {total_rows:,} ردیف
166
+ - **تعداد موجودیت‌های حساس شناسایی شده**: {total_entities:,} مورد
167
+ - **تعداد موجودیت‌های ناشناس شده**: {total_anonymized:,} مورد
168
+ - **درصد پوشش کلی**: {(total_anonymized/total_entities*100) if total_entities > 0 else 0:.1f}%
169
+
170
+ ## تحلیل تفصیلی دسته‌بندی موجودیت‌ها
171
+
172
+ """
173
+
174
+ excellent = []
175
+ good = []
176
+ poor = []
177
+ not_found = []
178
+
179
+ for entity_type, data in stats.items():
180
+ if data['total'] == 0:
181
+ not_found.append((entity_type, data))
182
+ elif data['percentage'] == 100:
183
+ excellent.append((entity_type, data))
184
+ elif data['percentage'] >= 80:
185
+ good.append((entity_type, data))
186
+ else:
187
+ poor.append((entity_type, data))
188
+
189
+ if excellent:
190
+ report += "### ✅ عملکرد عالی (100% موفقیت)\n"
191
+ for entity_type, data in excellent:
192
+ report += f"- **{data['name']}**: {data['anonymized']}/{data['total']} (100%)\n"
193
+ report += "\n"
194
+
195
+ if good:
196
+ report += "### 🟡 عملکرد خوب (80-99% موفقیت)\n"
197
+ for entity_type, data in good:
198
+ report += f"- **{data['name']}**: {data['anonymized']}/{data['total']} ({data['percentage']}%)\n"
199
+ report += "\n"
200
+
201
+ if poor:
202
+ report += "### 🔴 عملکرد ضعیف (<80% موفقیت)\n"
203
+ for entity_type, data in poor:
204
+ missed = data['total'] - data['anonymized']
205
+ report += f"- **{data['name']}**: {data['anonymized']}/{data['total']} ({data['percentage']}%) - {missed} مورد جا مانده\n"
206
+ report += "\n"
207
+
208
+ if not_found:
209
+ report += "### ⚪ موجودیت‌های یافت نشده\n"
210
+ for entity_type, data in not_found:
211
+ report += f"- **{data['name']}**: هیچ موجودیتی یافت نشد\n"
212
+ report += "\n"
213
+
214
+ report += "## جدول خلاصه متریک‌ها\n\n"
215
+ report += "| دسته موجودیت | یافته شده | ناشناس شده | درصد موفقیت | موارد جا مانده |\n"
216
+ report += "|---------------|-----------|-------------|-------------|----------------|\n"
217
+
218
+ for entity_type, data in stats.items():
219
+ if data['total'] > 0:
220
+ missed = data['total'] - data['anonymized']
221
+ report += f"| {data['name']} | {data['total']} | {data['anonymized']} | {data['percentage']}% | {missed} |\n"
222
+
223
+ major_issues = [(k, v) for k, v in stats.items() if v['total'] > 0 and v['percentage'] < 80]
224
+ major_issues.sort(key=lambda x: x[1]['total'] - x[1]['anonymized'], reverse=True)
225
+
226
+ if major_issues:
227
+ report += "\n## 🚨 مشکلات اصلی شناسایی شده\n\n"
228
+ for i, (entity_type, data) in enumerate(major_issues, 1):
229
+ missed = data['total'] - data['anonymized']
230
+ impact = round(missed / total_entities * 100, 1) if total_entities > 0 else 0
231
+ report += f"### {i}. {data['name']}\n"
232
+ report += f"- **وضعیت**: {data['percentage']}% موفقیت\n"
233
+ report += f"- **موارد جا مانده**: {missed} مورد از {data['total']} مورد\n"
234
+ report += f"- **تاثیر بر کل**: {impact}% از کل موجودیت‌ها\n\n"
235
+
236
+ precision = round((total_anonymized / total_entities * 100) if total_entities > 0 else 0, 1)
237
+
238
+ report += f"""## 📊 آمار نهایی
239
+
240
+ - **کل موجودیت‌های شناسایی شده**: {total_entities:,}
241
+ - **کل موجودیت‌های ناشناس شده**: {total_anonymized:,}
242
+ - **موجودیت‌های جا مانده**: {total_entities - total_anonymized:,}
243
+ - **دقت (Precision)**: {precision}%
244
+ - **پوشش (Recall)**: {precision}%
245
+ - **امتیاز F1**: {precision}%
246
+ """
247
+
248
+ return report
249
+
250
+ def create_interface():
251
+ evaluator = AnonymizationEvaluator()
252
+
253
+ def process_file(csv_file):
254
+ if csv_file is None:
255
+ return "لطفاً یک فایل CSV آپلود کنید."
256
+ return evaluator.evaluate_csv(csv_file)
257
+
258
+ with gr.Blocks(title="ارزیاب متریک‌های ناشناس‌سازی") as demo:
259
+ gr.Markdown("# ارزیاب متریک‌های ناشناس‌سازی متن فارسی")
260
+
261
+ file_input = gr.File(label="آپلود فایل CSV", file_types=[".csv"])
262
+ analyze_btn = gr.Button("محاسبه متریک‌ها", variant="primary")
263
+ output = gr.Markdown(value="فایل CSV خود را آپلود کنید.")
264
+
265
+ analyze_btn.click(fn=process_file, inputs=[file_input], outputs=[output])
266
+
267
+ return demo
268
+
269
+ if __name__ == "__main__":
270
+ app = create_interface()
271
+ app.launch()