toolb1 / anonymizer.py
Wilasineek's picture
Upload 8 files
ef7c180 verified
# File: anonymizer.py
import streamlit as st
from transformers import pipeline
import re
# ใช้ @st.cache_resource เพื่อให้แน่ใจว่าโมเดลจะถูกโหลดแค่ครั้งเดียว
# ซึ่งจะช่วยให้แอปทำงานเร็วขึ้นมากหลังจากการรันครั้งแรก
@st.cache_resource
def load_ner_model():
"""Loads the NER pipeline model and caches it."""
print("Loading NER model for the first time...")
try:
# เพิ่ม argument token เข้าไป
model = pipeline(
"token-classification",
model="loolootech/no-name-ner-th",
device=-1,
token=st.secrets.get("HUGGING_FACE_TOKEN") # ดึง Token จาก secrets
)
print("NER model loaded successfully.")
return model
except Exception as e:
st.error(f"Failed to load NER model: {e}")
return None
# กำหนดประเภทของข้อมูลที่จะถูกแทนที่ และ Token ที่จะใช้แทน
ENTITY_TO_ANONYMIZED_TOKEN_MAP = {
"PERSON": "[PERSON]",
"PHONE": "[PHONE]",
"EMAIL": "[EMAIL]",
"ADDRESS": "[LOCATION]",
"DATE": "[DATE]",
"NATIONAL_ID": "[NATIONAL_ID]",
"HOSPITAL_IDS": "[HOSPITAL_IDS]",
"HN": "[HOSPITAL_NUMBER]",
"ORGANIZATION": "[ORGANIZATION]",
"LOCATION": "[LOCATION]",
"URL": "[URL]",
}
def anonymize_text(original_text: str, ner_model):
"""
ใช้โมเดล NER และ RegEx เพื่อปกปิดข้อมูลส่วนบุคคลในข้อความ
"""
if not isinstance(original_text, str) or not original_text.strip():
return original_text
# ==========================================================
# ✨ ขั้นตอนที่ 1 (เพิ่มใหม่): ใช้ RegEx ค้นหาและแทนที่ HN ก่อน ✨
# ==========================================================
# รูปแบบ: ค้นหา HN หรือ hn, ตามด้วยเว้นวรรคหรือไม่ก็ได้ ( \s? ), ตามด้วยตัวเลข 1 ตัวขึ้นไป ( \d+ )
hn_pattern = r'[Hh][Nn]([\s.]?\d+|\s[a-zA-Z]{2}\d+)'
text_after_regex = re.sub(hn_pattern, ENTITY_TO_ANONYMIZED_TOKEN_MAP["HN"], original_text)
# ถ้าไม่มี ner_model ก็ให้คืนค่าหลังจากทำ RegEx ไปเลย
if not ner_model:
return text_after_regex
try:
# ==========================================================
# ✨ ขั้นตอนที่ 2 (ของเดิม): ทำ NER กับข้อความที่ผ่าน RegEx มาแล้ว ✨
# ==========================================================
ner_results = ner_model(text_after_regex)
if not ner_results:
return text_after_regex
# 2. จัดการ Entity ที่ต่อเนื่องกัน
combined_entities = []
for entity in ner_results:
entity_name = re.sub(r'^[BI]-', '', entity['entity'])
entity['entity'] = entity_name
if (combined_entities and
combined_entities[-1]['entity'] == entity_name and
entity['start'] == combined_entities[-1]['end']):
combined_entities[-1]['word'] += entity['word']
combined_entities[-1]['end'] = entity['end']
elif (combined_entities and
combined_entities[-1]['entity'] == entity_name and
entity['start'] == combined_entities[-1]['end'] + 1 and
text_after_regex[entity['start'] - 1].isspace()):
combined_entities[-1]['word'] += " " + entity['word']
combined_entities[-1]['end'] = entity['end']
else:
combined_entities.append(entity)
# 3. คัดกรองเฉพาะ entity ที่เราต้องการปกปิด
entities_to_anonymize = [
e for e in combined_entities if e['entity'] in ENTITY_TO_ANONYMIZED_TOKEN_MAP
]
# 4. เรียงลำดับจากท้ายมาหน้า
entities_to_anonymize.sort(key=lambda x: x['start'], reverse=True)
# 5. แทนที่ข้อความ
anonymized_text = text_after_regex
for entity in entities_to_anonymize:
start, end = entity['start'], entity['end']
token = ENTITY_TO_ANONYMIZED_TOKEN_MAP.get(entity['entity'])
if token:
anonymized_text = anonymized_text[:start] + token + anonymized_text[end:]
return anonymized_text
except Exception:
# หากเกิดข้อผิดพลาดใดๆ ให้คืนค่าข้อความที่ผ่าน RegEx แล้วไปก่อน
return text_after_regex