import gradio as gr import pandas as pd from transformers import pipeline import re import os # 1. โหลดโมเดล NER (เหมือนเดิม) print("กำลังโหลดโมเดล...") hf_token = os.getenv("HF_TOKEN") ner_pipeline = pipeline( "token-classification", model="loolootech/no-name-ner-th", device=-1, token=hf_token ) print("โมเดลพร้อมใช้งานแล้ว") # 2. ฟังก์ชันสำหรับรวม Token (เหมือนเดิม) def merge_entities(ner_results): merged_entities = [] current_entity = None for entity in ner_results: entity_type = re.sub(r'^[BI]-', '', entity['entity']) if current_entity and entity['start'] == current_entity['end'] and entity_type == current_entity['type']: current_entity['word'] += entity['word'] current_entity['end'] = entity['end'] current_entity['score'] = max(current_entity['score'], entity['score']) else: if current_entity: merged_entities.append(current_entity) current_entity = { 'type': entity_type, 'word': entity['word'], 'start': entity['start'], 'end': entity['end'], 'score': entity['score'] } if current_entity: merged_entities.append(current_entity) return merged_entities # 3. ฟังก์ชันสำหรับ De-identification ของข้อความ 1 บรรทัด (เหมือนเดิม) def deidentify_single_text(text): if pd.isna(text) or not isinstance(text, str) or not text.strip(): return "" ner_results = ner_pipeline(text) merged = merge_entities(ner_results) redacted_text = text for entity in reversed(merged): start, end, label = entity['start'], entity['end'], entity['type'] redacted_text = redacted_text[:start] + f"[{label}]" + redacted_text[end:] return redacted_text # 4. [อัปเดต] ฟังก์ชันสำหรับประมวลผลไฟล์ (ไม่ต้องรับชื่อคอลัมน์แล้ว) def process_entire_file(uploaded_file, progress=gr.Progress(track_tqdm=True)): if uploaded_file is None: raise gr.Error("กรุณาอัปโหลดไฟล์ก่อน") file_path = uploaded_file.name # อ่านไฟล์ด้วย Pandas try: if file_path.endswith('.csv'): df = pd.read_csv(file_path) elif file_path.endswith(('.xlsx', '.xls')): df = pd.read_excel(file_path) else: raise gr.Error("ไฟล์ไม่รองรับ กรุณาอัปโหลด .csv หรือ .xlsx เท่านั้น") except Exception as e: raise gr.Error(f"ไม่สามารถอ่านไฟล์ได้: {e}") # สร้าง DataFrame ใหม่สำหรับเก็บผลลัพธ์ df_redacted = df.copy() # [Key Change] ค้นหาคอลัมน์ทั้งหมดที่มีข้อมูลเป็นประเภทข้อความ (object) text_columns = df.select_dtypes(include=['object']).columns if len(text_columns) == 0: raise gr.Error("ไม่พบคอลัมน์ที่เป็นข้อมูลประเภทข้อความ (text) ในไฟล์นี้เลย") # วนลูปและประมวลผลทุกคอลัมน์ที่หาเจอ print(f"กำลังประมวลผลคอลัมน์: {list(text_columns)}") for col_name in progress.tqdm(text_columns, desc="Processing text columns"): df_redacted[col_name] = df[col_name].astype(str).apply(deidentify_single_text) # สร้างไฟล์ผลลัพธ์เพื่อให้ผู้ใช้ดาวน์โหลด output_filepath = "processed_output_full.csv" df_redacted.to_csv(output_filepath, index=False, encoding='utf-8-sig') return df_redacted, output_filepath # 5. [อัปเดต] สร้างหน้าเว็บ Gradio (ตัดช่องใส่ชื่อคอลัมน์ออก) iface = gr.Interface( fn=process_entire_file, inputs=[ gr.File(label="อัปโหลดไฟล์ CSV หรือ Excel ที่ต้องการตรวจสอบทั้งตาราง", file_types=[".csv", ".xlsx", ".xls"]) ], outputs=[ gr.DataFrame(label="ตารางผลลัพธ์ (Output Table Preview)", wrap=True, max_rows=10), gr.File(label="ดาวน์โหลดผลลัพธ์ (Download Result as CSV)") ], title="📁 Automatic Table De-identification", description="อัปโหลดไฟล์ตาราง (CSV, Excel) แล้วระบบจะค้นหาคอลัมน์ที่เป็น 'ข้อความ' ทั้งหมดโดยอัตโนมัติ และทำการปกปิดข้อมูลส่วนบุคคลให้ทันที", allow_flagging="never" ) # รันแอป iface.launch()