leilaghomashchi's picture
Rename app.py to new-last.py
a601aa4 verified
import gradio as gr
import pandas as pd
import re
class AnonymizationEvaluator:
def __init__(self):
# فهرست بانک‌های ایران
self.iranian_banks = [
'بانک ملی', 'بانک صادرات', 'بانک پاسارگاد', 'بانک کشاورزی',
'بانک ملت', 'بانک تجارت', 'بانک صنعت و معدن', 'بانک رسالت',
'بانک دی', 'بانک پارسیان', 'بانک کارآفرین', 'بانک سامان',
'بانک اقتصاد نوین', 'بانک مهر اقتصاد', 'بانک آینده', 'بانک کشاورزی'
]
# فهرست سازمان‌های دولتی
self.government_orgs = [
'بانک مرکزی جمهوری اسلامی ایران',
'دفتر اسناد رسمی',
'اداره کل مالیات',
'تامین اجتماعی',
'وزارت دادگستری'
]
self.patterns = {
'person_names': {
'pattern': re.compile(r'(?:آقای|خانم)\s+[\u0600-\u06FF\s]+?(?=\s+با|$)', re.UNICODE),
'replacement': re.compile(r'person_\d+'),
'name': 'اسامی اشخاص'
},
'national_ids': {
'pattern': re.compile(r'\b\d{10,11}\b'),
'replacement': re.compile(r'id_number_\d+'),
'name': 'کدهای ملی'
},
'phone_numbers': {
'pattern': re.compile(r'(?:09\d{9}|021-\d{8}|0\d{2,3}-\d{8})'),
'replacement': re.compile(r'phone_\d+'),
'name': 'شماره تلفن‌ها'
},
'account_numbers': {
'pattern': re.compile(r'\b\d{3}-\d{3}-\d{3}-\d{1}\b'),
'replacement': re.compile(r'account_\d+'),
'name': 'شماره حساب‌ها'
},
'card_numbers': {
'pattern': re.compile(r'\b\d{4}-\d{4}-\d{4}-\d{4}\b'),
'replacement': re.compile(r'card_number_\d+'),
'name': 'شماره کارت‌ها'
},
'amounts': {
'pattern': re.compile(r'\b\d+\s*تومان'),
'replacement': re.compile(r'amount_\d+'),
'name': 'مبالغ مالی'
},
'dates': {
'pattern': re.compile(r'(?:\d{4}\/\d{2}\/\d{2}|۳۰\s*اسفند\s*۱۴۰۳|\b\d{4}\b(?=\s*سال))'),
'replacement': re.compile(r'date_\d+'),
'name': 'تاریخ‌ها'
},
'iranian_banks': {
'pattern': re.compile(f"({'|'.join(self.iranian_banks)})", re.UNICODE),
'replacement': re.compile(r'company_\d+'),
'name': 'بانک‌های ایران'
},
'government_orgs': {
'pattern': re.compile(f"({'|'.join(self.government_orgs)})", re.UNICODE),
'replacement': re.compile(r'company_\d+'),
'name': 'سازمان‌های دولتی'
},
'other_companies': {
'pattern': re.compile(r'شرکت\s+[\u0600-\u06FF\s]+?(?=\s|$|،|\.)', re.UNICODE),
'replacement': re.compile(r'company_\d+'),
'name': 'سایر شرکت‌ها'
},
'addresses': {
'pattern': re.compile(r'(?:تهران|کرج|اصفهان|بندر\s*ماهشهر)[،\s]+[^،\.]+', re.UNICODE),
'replacement': re.compile(r'(?:full_address_\d+|location_\d+)'),
'name': 'آدرس‌ها'
},
'documents': {
'pattern': re.compile(r'(?:INV-\d{4}-\d{4}|RPT-\d{4}-\d{4}|\b\d{4}(?=\s+تهران)|\b\d{7}\b)'),
'replacement': re.compile(r'(?:invoice_\d+|report_\d+|contract_\d+|cheque_\d+)'),
'name': 'شماره اسناد'
}
}
def analyze_entities(self, original_text, anonymized_text):
results = {}
for entity_type, config in self.patterns.items():
original_matches = config['pattern'].findall(original_text)
replacement_matches = config['replacement'].findall(anonymized_text)
anonymized_count = 0
for match in original_matches:
if not anonymized_text.count(match.strip()):
anonymized_count += 1
if len(replacement_matches) > anonymized_count:
anonymized_count = min(len(replacement_matches), len(original_matches))
percentage = (anonymized_count / len(original_matches) * 100) if original_matches else 0
results[entity_type] = {
'name': config['name'],
'total': len(original_matches),
'anonymized': anonymized_count,
'percentage': round(percentage, 1),
'samples': original_matches[:3] if original_matches else []
}
return results
def evaluate_csv(self, csv_file):
try:
if csv_file is None:
return "لطفاً یک فایل CSV آپلود کنید."
try:
df = pd.read_csv(csv_file.name, encoding='utf-8')
except:
df = pd.read_csv(csv_file.name, encoding='utf-8', sep='\t')
if 'original_text' not in df.columns or 'anonymized_text' not in df.columns:
return "فایل CSV باید شامل ستون‌های 'original_text' و 'anonymized_text' باشد."
overall_stats = {}
total_entities = 0
total_anonymized = 0
for _, row in df.iterrows():
if pd.isna(row['original_text']) or pd.isna(row['anonymized_text']):
continue
row_analysis = self.analyze_entities(str(row['original_text']), str(row['anonymized_text']))
for entity_type, data in row_analysis.items():
if entity_type not in overall_stats:
overall_stats[entity_type] = {
'name': data['name'],
'total': 0,
'anonymized': 0,
'samples': []
}
overall_stats[entity_type]['total'] += data['total']
overall_stats[entity_type]['anonymized'] += data['anonymized']
overall_stats[entity_type]['samples'].extend(data['samples'])
total_entities += data['total']
total_anonymized += data['anonymized']
for entity_type in overall_stats:
stats = overall_stats[entity_type]
stats['percentage'] = round((stats['anonymized'] / stats['total'] * 100) if stats['total'] > 0 else 0, 1)
stats['samples'] = list(set(stats['samples']))[:3]
return self.generate_report(overall_stats, total_entities, total_anonymized, len(df))
except Exception as e:
return f"خطا در پردازش فایل: {str(e)}"
def generate_report(self, stats, total_entities, total_anonymized, total_rows):
report = f"""# گزارش ارزیابی ناشناس‌سازی متن
## خلاصه کلی
- **تعداد ردیف‌های پردازش شده**: {total_rows:,} ردیف
- **تعداد موجودیت‌های حساس شناسایی شده**: {total_entities:,} مورد
- **تعداد موجودیت‌های ناشناس شده**: {total_anonymized:,} مورد
- **درصد پوشش کلی**: {(total_anonymized/total_entities*100) if total_entities > 0 else 0:.1f}%
## تحلیل تفصیلی دسته‌بندی موجودیت‌ها
"""
excellent = []
good = []
poor = []
not_found = []
for entity_type, data in stats.items():
if data['total'] == 0:
not_found.append((entity_type, data))
elif data['percentage'] == 100:
excellent.append((entity_type, data))
elif data['percentage'] >= 80:
good.append((entity_type, data))
else:
poor.append((entity_type, data))
if excellent:
report += "### ✅ عملکرد عالی (100% موفقیت)\n"
for entity_type, data in excellent:
report += f"- **{data['name']}**: {data['anonymized']}/{data['total']} (100%)\n"
report += "\n"
if good:
report += "### 🟡 عملکرد خوب (80-99% موفقیت)\n"
for entity_type, data in good:
report += f"- **{data['name']}**: {data['anonymized']}/{data['total']} ({data['percentage']}%)\n"
report += "\n"
if poor:
report += "### 🔴 عملکرد ضعیف (<80% موفقیت)\n"
for entity_type, data in poor:
missed = data['total'] - data['anonymized']
report += f"- **{data['name']}**: {data['anonymized']}/{data['total']} ({data['percentage']}%) - {missed} مورد جا مانده\n"
report += "\n"
if not_found:
report += "### ⚪ موجودیت‌های یافت نشده\n"
for entity_type, data in not_found:
report += f"- **{data['name']}**: هیچ موجودیتی یافت نشد\n"
report += "\n"
report += "## جدول خلاصه متریک‌ها\n\n"
report += "| دسته موجودیت | یافته شده | ناشناس شده | درصد موفقیت | موارد جا مانده |\n"
report += "|---------------|-----------|-------------|-------------|----------------|\n"
for entity_type, data in stats.items():
if data['total'] > 0:
missed = data['total'] - data['anonymized']
report += f"| {data['name']} | {data['total']} | {data['anonymized']} | {data['percentage']}% | {missed} |\n"
major_issues = [(k, v) for k, v in stats.items() if v['total'] > 0 and v['percentage'] < 80]
major_issues.sort(key=lambda x: x[1]['total'] - x[1]['anonymized'], reverse=True)
if major_issues:
report += "\n## 🚨 مشکلات اصلی شناسایی شده\n\n"
for i, (entity_type, data) in enumerate(major_issues, 1):
missed = data['total'] - data['anonymized']
impact = round(missed / total_entities * 100, 1) if total_entities > 0 else 0
report += f"### {i}. {data['name']}\n"
report += f"- **وضعیت**: {data['percentage']}% موفقیت\n"
report += f"- **موارد جا مانده**: {missed} مورد از {data['total']} مورد\n"
report += f"- **تاثیر بر کل**: {impact}% از کل موجودیت‌ها\n\n"
precision = round((total_anonymized / total_entities * 100) if total_entities > 0 else 0, 1)
report += f"""## 📊 آمار نهایی
- **کل موجودیت‌های شناسایی شده**: {total_entities:,}
- **کل موجودیت‌های ناشناس شده**: {total_anonymized:,}
- **موجودیت‌های جا مانده**: {total_entities - total_anonymized:,}
- **دقت (Precision)**: {precision}%
- **پوشش (Recall)**: {precision}%
- **امتیاز F1**: {precision}%
"""
return report
def create_interface():
evaluator = AnonymizationEvaluator()
def process_file(csv_file):
if csv_file is None:
return "لطفاً یک فایل CSV آپلود کنید."
return evaluator.evaluate_csv(csv_file)
with gr.Blocks(title="ارزیاب متریک‌های ناشناس‌سازی") as demo:
gr.Markdown("# ارزیاب متریک‌های ناشناس‌سازی متن فارسی")
file_input = gr.File(label="آپلود فایل CSV", file_types=[".csv"])
analyze_btn = gr.Button("محاسبه متریک‌ها", variant="primary")
output = gr.Markdown(value="فایل CSV خود را آپلود کنید.")
analyze_btn.click(fn=process_file, inputs=[file_input], outputs=[output])
return demo
if __name__ == "__main__":
app = create_interface()
app.launch()