leilaghomashchi's picture
Rename text_anonymizer (1).py to app.py
a06db1a verified
raw
history blame
17.6 kB
import gradio as gr
import pandas as pd
import re
from collections import defaultdict
import io
class TextAnonymizer:
def __init__(self):
self.person_counter = 0
self.company_counter = 0
self.amount_counter = 0
self.percent_counter = 0
# دیکشنری برای نگه‌داری تبدیل‌ها
self.person_mapping = {}
self.company_mapping = {}
self.amount_mapping = {}
self.percent_mapping = {}
def reset_counters(self):
"""بازنشانی شمارنده‌ها برای پردازش جدید"""
self.person_counter = 0
self.company_counter = 0
self.amount_counter = 0
self.percent_counter = 0
self.person_mapping.clear()
self.company_mapping.clear()
self.amount_mapping.clear()
self.percent_mapping.clear()
def detect_financial_amounts(self, text):
"""تشخیص مبالغ مالی"""
patterns = [
r'\$[\d,]+(?:\.\d{2})?', # $1,000.00
r'[\d,]+\s*(?:dollars?|USD|usd|Dollars?)', # 1000 dollars
r'[\d,]+\s*(?:million|billion|thousand|Million|Billion|Thousand)', # 1 million
r'[\d,]+(?:\.\d+)?\s*(?:M|B|K|m|b|k)', # 1.5M, 2B, 500K
r'€[\d,]+(?:\.\d{2})?', # €1,000.00
r'£[\d,]+(?:\.\d{2})?', # £1,000.00
]
amounts = []
for pattern in patterns:
matches = re.finditer(pattern, text, re.IGNORECASE)
for match in matches:
amounts.append((match.start(), match.end(), match.group()))
return amounts
def detect_percentages(self, text):
"""تشخیص درصدها"""
pattern = r'\d+(?:\.\d+)?%'
percentages = []
matches = re.finditer(pattern, text)
for match in matches:
percentages.append((match.start(), match.end(), match.group()))
return percentages
def detect_names_regex(self, text):
"""تشخیص اسامی با regex (بدون spaCy)"""
patterns = [
r'\b[A-Z][a-z]+ [A-Z][a-z]+\b', # John Smith
r'\b[A-Z][a-z]+ [A-Z]\. [A-Z][a-z]+\b', # John M. Smith
r'\b[A-Z][a-z]+ [A-Z][a-z]+ [A-Z][a-z]+\b', # John Michael Smith
r'\bMr\. [A-Z][a-z]+\b', # Mr. Smith
r'\bMs\. [A-Z][a-z]+\b', # Ms. Johnson
r'\bDr\. [A-Z][a-z]+\b', # Dr. Brown
]
names = []
for pattern in patterns:
matches = re.finditer(pattern, text)
for match in matches:
names.append((match.start(), match.end(), match.group()))
return names
def detect_companies_regex(self, text):
"""تشخیص شرکت‌ها با regex"""
patterns = [
r'\b[A-Z][a-z]+ (?:Inc|Corp|LLC|Ltd|Company|Co|Corporation|Group|Technologies|Tech|Systems|Solutions|Services|International|Global|Enterprises)\.?\b',
r'\b(?:Apple|Microsoft|Google|Amazon|Facebook|Meta|Netflix|Tesla|Oracle|IBM|Intel|Cisco|Adobe|Salesforce|PayPal|Uber|Airbnb|Twitter|LinkedIn|Samsung|Sony|LG|HP|Dell|Lenovo|Huawei|Xiaomi|OnePlus|NVIDIA|AMD|Qualcomm|Broadcom|Texas Instruments|Micron|SK Hynix|TSMC|ASML|Shopify|Square|Stripe|Zoom|Slack|Dropbox|Spotify|Pinterest|Snapchat|TikTok|ByteDance|Alibaba|Tencent|Baidu|JD|Meituan|Didi|WeChat|Ant Group|Ping An|ICBC|China Mobile|China Telecom|China Unicom|SoftBank|NTT|KDDI|Rakuten|Nintendo|Panasonic|Canon|Nikon|Olympus|Fujifilm|Sharp|Toshiba|Hitachi|Mitsubishi|Suzuki|Nissan|Toyota|Honda|Mazda|Subaru|Yamaha|Kawasaki|Bridgestone|Michelin|Goodyear|Continental|Bosch|Siemens|SAP|Volkswagen|BMW|Mercedes|Audi|Porsche|Ferrari|Lamborghini|Rolls Royce|Bentley|Aston Martin|McLaren|Bugatti|Koenigsegg|Pagani|Maserati|Alfa Romeo|Fiat|Peugeot|Renault|Citroen|Opel|Volvo|Saab|IKEA|H&M|Zara|Uniqlo|Nike|Adidas|Puma|Under Armour|Lululemon|Patagonia|North Face|Columbia|REI|Dick's|Foot Locker|Finish Line|JD Sports|Decathlon|Walmart|Target|Costco|Home Depot|Lowe's|Best Buy|GameStop|Barnes & Noble|Starbucks|McDonald's|Burger King|KFC|Pizza Hut|Domino's|Subway|Taco Bell|Chipotle|Panera|Dunkin|Tim Hortons|Costa|Nescafe|Coca Cola|Pepsi|Red Bull|Monster|Gatorade|Powerade|Vitamin Water|Smartwater|Evian|Perrier|San Pellegrino|Fiji|Dasani|Aquafina|Sprite|Fanta|Dr Pepper|Mountain Dew|7UP|Schweppes|Heineken|Budweiser|Corona|Stella Artois|Guinness|Beck's|Carlsberg|Tuborg|Amstel|Kronenbourg|Peroni|Moretti|Nastro Azzurro|Blue Moon|Coors|Miller|Bud Light|Michelob|Samuel Adams|Sierra Nevada|New Belgium|Dogfish Head|Stone|Lagunitas|Ballast Point|Anchor|Founders|Bell's|Great Lakes|Deschutes|Widmer|Rogue|Ninkasi|Hopworks|Bridgeport|Full Sail|Deschutes|Bend|10 Barrel|Crux|Boneyard|Goodlife|Worthy|Sunriver|Pelican|Rogue|Hair of the Dog|Upright|Cascade|Commons|Base Camp|Migration|StormBreaker|Culmination|Great Notion|Modern Times|Other Half|Tree House|Trillium|The Alchemist|Hill Farmstead|Lawson's Finest|The Veil|Monkish|Russian River|Pliny|Blind Pig|Row 2|Hill 2|Knee Deep|Auburn|Device|Moksa|Eight Bridges|Knee Deep|Abnormal|Fieldwork|New Glory|Fort Point|Cellarmaker|Toronado|Magnolia|Beach Chalet|Golden Gate Park|Ocean Beach|Land's End|Cliff House|Sutro Baths|Baker Beach|Presidio|Crissy Field|Marina|Fisherman's Wharf|Pier 39|Alcatraz|Angel Island|Treasure Island|Bay Bridge|Golden Gate Bridge|Twin Peaks|Mission Dolores|Castro|Haight Ashbury|North Beach|Chinatown|Union Square|Financial District|SOMA|Mission Bay|Potrero Hill|Dogpatch|Bernal Heights|Noe Valley|Glen Park|Excelsior|Sunset|Richmond|Avenues|Parkside|West Portal|Forest Hill|St Francis Wood|Sea Cliff|Pacific Heights|Russian Hill|Nob Hill|Telegraph Hill|North Beach|Lombard Street|Coit Tower|Transamerica Pyramid|Salesforce Tower|555 California|Bank of America|Wells Fargo|Chase|Citibank|US Bank|PNC|Capital One|Ally|American Express|Discover|Mastercard|Visa|JPMorgan|Goldman Sachs|Morgan Stanley|Bank of America|Merrill Lynch|Charles Schwab|Fidelity|Vanguard|BlackRock|State Street|T Rowe Price|Franklin Templeton|Invesco|Northern Trust|BNY Mellon|Credit Suisse|UBS|Deutsche Bank|Barclays|HSBC|Standard Chartered|RBS|Lloyds|Santander|BBVA|BNP Paribas|Societe Generale|Credit Agricole|ING|ABN AMRO|Rabobank|Danske Bank|Nordea|SEB|Handelsbanken|Swedbank|DNB|SpareBank|Storebrand)\\b',
]
companies = []
for pattern in patterns:
matches = re.finditer(pattern, text, re.IGNORECASE)
for match in matches:
companies.append((match.start(), match.end(), match.group()))
return companies
def anonymize_text(self, text):
"""ناشناس‌سازی متن با regex"""
if not text or pd.isna(text):
return text
replacements = []
# تشخیص اسامی اشخاص
names = self.detect_names_regex(text)
for start, end, name in names:
if name not in self.person_mapping:
self.person_counter += 1
self.person_mapping[name] = f"person-{self.person_counter:02d}"
replacements.append((start, end, self.person_mapping[name]))
# تشخیص شرکت‌ها
companies = self.detect_companies_regex(text)
for start, end, company in companies:
if company not in self.company_mapping:
self.company_counter += 1
self.company_mapping[company] = f"company-{self.company_counter:02d}"
replacements.append((start, end, self.company_mapping[company]))
# تشخیص مبالغ مالی
amounts = self.detect_financial_amounts(text)
for start, end, amount in amounts:
if amount not in self.amount_mapping:
self.amount_counter += 1
self.amount_mapping[amount] = f"amount-{self.amount_counter:02d}"
replacements.append((start, end, self.amount_mapping[amount]))
# تشخیص درصدها
percentages = self.detect_percentages(text)
for start, end, percent in percentages:
if percent not in self.percent_mapping:
self.percent_counter += 1
self.percent_mapping[percent] = f"percent-{self.percent_counter:02d}"
replacements.append((start, end, self.percent_mapping[percent]))
# حذف تداخل‌ها و مرتب‌سازی
replacements = self.remove_overlaps(replacements)
replacements.sort(key=lambda x: x[0], reverse=True)
# اعمال جایگزینی‌ها
result = text
for start, end, replacement in replacements:
result = result[:start] + replacement + result[end:]
return result
def remove_overlaps(self, replacements):
"""حذف تداخل‌ها در جایگزینی‌ها"""
if not replacements:
return []
# مرتب‌سازی بر اساس موقعیت شروع
replacements.sort(key=lambda x: x[0])
filtered = []
for start, end, replacement in replacements:
# بررسی تداخل با آخرین جایگزینی اضافه شده
if not filtered or start >= filtered[-1][1]:
filtered.append((start, end, replacement))
return filtered
def get_mapping_summary(self):
"""خلاصه‌ای از تبدیل‌های انجام شده"""
summary = []
if self.person_mapping:
summary.append("**اسامی اشخاص:**")
for original, anonymized in self.person_mapping.items():
summary.append(f"- {original} → {anonymized}")
summary.append("")
if self.company_mapping:
summary.append("**نام شرکت‌ها:**")
for original, anonymized in self.company_mapping.items():
summary.append(f"- {original} → {anonymized}")
summary.append("")
if self.amount_mapping:
summary.append("**مبالغ مالی:**")
for original, anonymized in self.amount_mapping.items():
summary.append(f"- {original} → {anonymized}")
summary.append("")
if self.percent_mapping:
summary.append("**درصدها:**")
for original, anonymized in self.percent_mapping.items():
summary.append(f"- {original} → {anonymized}")
return "\n".join(summary) if summary else "هیچ موجودیت حساسی یافت نشد."
# ایجاد نمونه از کلاس ناشناس‌ساز
anonymizer = TextAnonymizer()
def process_csv(file):
"""پردازش فایل CSV"""
try:
# بازنشانی شمارنده‌ها
anonymizer.reset_counters()
# بررسی فایل
if file is None:
return None, "لطفاً فایل CSV آپلود کنید.", "", None
# خواندن فایل CSV
if file.name.endswith('.csv'):
df = pd.read_csv(file.name)
else:
return None, "لطفاً فایل CSV آپلود کنید.", "", None
# بررسی وجود ستون original_text
if 'original_text' not in df.columns:
available_columns = ', '.join(df.columns.tolist())
return None, f"ستون 'original_text' در فایل یافت نشد. ستون‌های موجود: {available_columns}", "", None
# ایجاد کپی از دیتافریم
result_df = df.copy()
# ناشناس‌سازی متن‌های ستون original_text
result_df['anonymized_text'] = df['original_text'].apply(anonymizer.anonymize_text)
# تبدیل به CSV برای دانلود
output = io.StringIO()
result_df.to_csv(output, index=False, encoding='utf-8')
csv_content = output.getvalue()
# ایجاد فایل CSV برای دانلود
output_file = "anonymized_data.csv"
with open(output_file, 'w', encoding='utf-8') as f:
f.write(csv_content)
# نمایش نمونه از نتایج
sample_df = result_df[['original_text', 'anonymized_text']].head(10)
# خلاصه تبدیل‌ها
mapping_summary = anonymizer.get_mapping_summary()
return output_file, f"✅ پردازش کامل شد! {len(df)} ردیف پردازش شد.", mapping_summary, sample_df
except Exception as e:
return None, f"❌ خطا در پردازش فایل: {str(e)}", "", None
def process_single_text(text):
"""پردازش تک متن"""
if not text.strip():
return "", "لطفاً متنی وارد کنید."
anonymizer.reset_counters()
anonymized = anonymizer.anonymize_text(text)
mapping_summary = anonymizer.get_mapping_summary()
return anonymized, mapping_summary
# ایجاد رابط کاربری Gradio
with gr.Blocks(title="ناشناس‌سازی متن", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# 🔒 برنامه ناشناس‌سازی متن (نسخه Regex)
⚡ **وضعیت:** حالت سریع - بدون نیاز به spaCy
این برنامه متن‌های شما را ناشناس می‌کند و اطلاعات حساس زیر را جایگزین می‌کند:
- 👤 **اسامی اشخاص** → person-01, person-02, ...
- 🏢 **نام شرکت‌ها** → company-01, company-02, ...
- 💰 **مبالغ مالی** → amount-01, amount-02, ...
- 📊 **درصدها** → percent-01, percent-02, ...
**نسخه ۱:** آدرس‌ها، مکان‌ها و تاریخ‌ها ناشناس‌سازی نمی‌شوند.
""")
with gr.Tabs():
# تب پردازش فایل CSV
with gr.TabItem("📁 پردازش فایل CSV"):
gr.Markdown("### آپلود فایل CSV با ستون 'original_text'")
with gr.Row():
with gr.Column():
file_input = gr.File(
label="فایل CSV را انتخاب کنید",
file_types=[".csv"],
type="filepath"
)
process_btn = gr.Button("🚀 شروع پردازش", variant="primary")
with gr.Column():
status_output = gr.Textbox(
label="وضعیت",
interactive=False
)
download_file = gr.File(
label="دانلود فایل ناشناس‌سازی شده",
interactive=False
)
with gr.Row():
with gr.Column():
mapping_output = gr.Markdown(
label="خلاصه تبدیل‌ها",
value="خلاصه تبدیل‌ها اینجا نمایش داده می‌شود..."
)
with gr.Column():
sample_output = gr.Dataframe(
label="نمونه نتایج (۱۰ ردیف اول)",
interactive=False
)
# تب تست تک متن
with gr.TabItem("📝 تست تک متن"):
gr.Markdown("### تست ناشناس‌سازی روی یک متن")
with gr.Row():
with gr.Column():
text_input = gr.Textbox(
label="متن اصلی",
placeholder="متن خود را اینجا وارد کنید...",
lines=5
)
test_btn = gr.Button("🔍 ناشناس‌سازی", variant="primary")
with gr.Column():
text_output = gr.Textbox(
label="متن ناشناس‌سازی شده",
lines=5,
interactive=False
)
text_mapping = gr.Markdown(
label="تبدیل‌های انجام شده"
)
# اتصال رویدادها
process_btn.click(
fn=process_csv,
inputs=[file_input],
outputs=[download_file, status_output, mapping_output, sample_output]
)
test_btn.click(
fn=process_single_text,
inputs=[text_input],
outputs=[text_output, text_mapping]
)
# مثال در بخش تست
gr.Examples(
examples=[
["John Smith works at Microsoft and earned $50,000 with a 15% bonus."],
["Sarah Johnson from Google Inc. reported revenues of $2.5 million, representing a 25% increase."],
["The CEO of Apple, Tim Cook, announced profits of $1.2B with 18.5% growth rate."],
["Dr. Michael Brown from IBM Corp. received €75,000 salary increase of 12%."],
["Ms. Lisa Wilson at Amazon reported quarterly results of £500K with 8.7% margin."]
],
inputs=[text_input],
label="نمونه متن‌ها"
)
# اجرای برنامه
if __name__ == "__main__":
demo.launch()