Spaces:
Sleeping
Sleeping
add model mmBERT
Browse files
app.py
CHANGED
|
@@ -101,6 +101,15 @@ custom_css = """
|
|
| 101 |
font-size: 0.9rem;
|
| 102 |
margin-bottom: 0;
|
| 103 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
.batch-sample {
|
| 105 |
border: 1px solid #e5e7eb;
|
| 106 |
border-radius: 10px;
|
|
@@ -168,6 +177,10 @@ custom_css = """
|
|
| 168 |
background: #ede9fe;
|
| 169 |
color: #5b21b6;
|
| 170 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
.dark .batch-model-label.gliner {
|
| 172 |
background: #1e3a5f;
|
| 173 |
color: #93c5fd;
|
|
@@ -176,6 +189,10 @@ custom_css = """
|
|
| 176 |
background: #2e1065;
|
| 177 |
color: #c4b5fd;
|
| 178 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
.batch-entity-tags {
|
| 180 |
display: flex;
|
| 181 |
flex-wrap: wrap;
|
|
@@ -959,11 +976,18 @@ _MODEL_FACTORIES = {
|
|
| 959 |
threshold=0.5,
|
| 960 |
use_rules=False,
|
| 961 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 962 |
}
|
| 963 |
|
| 964 |
MODEL_DISPLAY_NAMES = {
|
| 965 |
"multi_1": "GLiNER2 — multi-v7 (ep3)",
|
| 966 |
"XLMBERT": "XLM-RoBERTa (BERT)",
|
|
|
|
| 967 |
}
|
| 968 |
|
| 969 |
|
|
@@ -1014,12 +1038,13 @@ def run_single_model(text: str, model_key: str):
|
|
| 1014 |
|
| 1015 |
|
| 1016 |
# ==========================================
|
| 1017 |
-
# 6. Wrapper cho Gradio (
|
| 1018 |
# ==========================================
|
| 1019 |
def process_both(text: str):
|
| 1020 |
html1, json1 = run_single_model(text, "multi_1")
|
| 1021 |
html2, json2 = run_single_model(text, "XLMBERT")
|
| 1022 |
-
|
|
|
|
| 1023 |
|
| 1024 |
|
| 1025 |
# ==========================================
|
|
@@ -1055,10 +1080,12 @@ def process_test_file(file, model_choice: str):
|
|
| 1055 |
return "<div style='color:red;padding:20px;'>File JSON phải là một mảng (array) các object có trường \"text\".</div>", []
|
| 1056 |
|
| 1057 |
model_keys = []
|
| 1058 |
-
if model_choice in ("GLiNER2", "
|
| 1059 |
model_keys.append("multi_1")
|
| 1060 |
-
if model_choice in ("XLM-RoBERTa", "
|
| 1061 |
model_keys.append("XLMBERT")
|
|
|
|
|
|
|
| 1062 |
|
| 1063 |
total = len(data)
|
| 1064 |
all_results = []
|
|
@@ -1067,6 +1094,7 @@ def process_test_file(file, model_choice: str):
|
|
| 1067 |
# Summary header placeholder
|
| 1068 |
total_pii_gliner = 0
|
| 1069 |
total_pii_bert = 0
|
|
|
|
| 1070 |
|
| 1071 |
for idx, item in enumerate(data):
|
| 1072 |
text = item.get("text", "")
|
|
@@ -1081,7 +1109,7 @@ def process_test_file(file, model_choice: str):
|
|
| 1081 |
result_entry = {"sample": sample_num, "text_preview": text[:100]}
|
| 1082 |
|
| 1083 |
# Run models
|
| 1084 |
-
html_gliner = preds_gliner = html_bert = preds_bert = None
|
| 1085 |
if "multi_1" in model_keys:
|
| 1086 |
html_gliner, preds_gliner = run_single_model(text, "multi_1")
|
| 1087 |
result_entry["gliner"] = preds_gliner
|
|
@@ -1092,6 +1120,11 @@ def process_test_file(file, model_choice: str):
|
|
| 1092 |
result_entry["xlmbert"] = preds_bert
|
| 1093 |
if isinstance(preds_bert, list):
|
| 1094 |
total_pii_bert += len(preds_bert)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1095 |
|
| 1096 |
all_results.append(result_entry)
|
| 1097 |
|
|
@@ -1105,34 +1138,35 @@ def process_test_file(file, model_choice: str):
|
|
| 1105 |
)
|
| 1106 |
html_parts.append(f'<div class="batch-sample-input">{short_text}</div>')
|
| 1107 |
|
| 1108 |
-
if len(model_keys) =
|
| 1109 |
-
|
| 1110 |
-
|
| 1111 |
-
|
| 1112 |
-
|
| 1113 |
-
|
| 1114 |
-
|
| 1115 |
-
|
| 1116 |
-
|
| 1117 |
-
|
| 1118 |
-
|
| 1119 |
-
|
| 1120 |
-
|
| 1121 |
-
|
| 1122 |
-
|
| 1123 |
-
|
| 1124 |
-
|
| 1125 |
-
|
| 1126 |
-
|
| 1127 |
-
html_parts.append('</div></div>')
|
| 1128 |
html_parts.append('</div>') # end batch-models-row
|
| 1129 |
else:
|
| 1130 |
# Single model
|
| 1131 |
mk = model_keys[0]
|
| 1132 |
-
|
| 1133 |
-
|
| 1134 |
-
|
| 1135 |
-
|
|
|
|
|
|
|
| 1136 |
html_parts.append(f'<div style="padding:12px 16px;">')
|
| 1137 |
html_parts.append(f'<div class="batch-model-label {cls}">{name}</div>')
|
| 1138 |
if h:
|
|
@@ -1152,7 +1186,9 @@ def process_test_file(file, model_choice: str):
|
|
| 1152 |
if "multi_1" in model_keys:
|
| 1153 |
summary_lines.append(f"🤖 <strong>GLiNER2:</strong> {total_pii_gliner} PII entities phát hiện<br>")
|
| 1154 |
if "XLMBERT" in model_keys:
|
| 1155 |
-
summary_lines.append(f"🧠 <strong>XLM-RoBERTa:</strong> {total_pii_bert} PII entities phát hiện")
|
|
|
|
|
|
|
| 1156 |
summary_lines.append("</div>")
|
| 1157 |
|
| 1158 |
final_html = "".join(summary_lines) + "".join(html_parts)
|
|
@@ -1175,15 +1211,15 @@ DEFAULT_TEXT = (
|
|
| 1175 |
"our support team at 555-0198.\n\n"
|
| 1176 |
)
|
| 1177 |
|
| 1178 |
-
with gr.Blocks(title="PII Extractor — So sánh
|
| 1179 |
-
gr.Markdown("# 🔍 Hệ thống Trích xuất PII — So sánh
|
| 1180 |
|
| 1181 |
with gr.Tabs():
|
| 1182 |
# ── Tab 1: Nhập văn bản ──────────────────────────────────────
|
| 1183 |
with gr.TabItem("📝 Nhập văn bản"):
|
| 1184 |
gr.Markdown(
|
| 1185 |
"Nhập văn bản bên dưới và nhấn **Trích xuất PII**. "
|
| 1186 |
-
"Kết quả của **GLiNER2 multi-v7**
|
| 1187 |
)
|
| 1188 |
|
| 1189 |
with gr.Row():
|
|
@@ -1194,7 +1230,7 @@ with gr.Blocks(title="PII Extractor — So sánh 2 Model", theme=gr.themes.Soft(
|
|
| 1194 |
scale=1,
|
| 1195 |
)
|
| 1196 |
|
| 1197 |
-
submit_btn = gr.Button("⚡ Trích xuất PII (Cả
|
| 1198 |
|
| 1199 |
gr.Markdown("## 📊 Kết quả nhận diện")
|
| 1200 |
with gr.Row(equal_height=True):
|
|
@@ -1210,6 +1246,12 @@ with gr.Blocks(title="PII Extractor — So sánh 2 Model", theme=gr.themes.Soft(
|
|
| 1210 |
)
|
| 1211 |
out_html_bert = gr.HTML(label="XLM-RoBERTa Output")
|
| 1212 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1213 |
gr.Markdown("## 🗂️ Dữ liệu JSON thô")
|
| 1214 |
with gr.Row(equal_height=True):
|
| 1215 |
with gr.Column():
|
|
@@ -1220,10 +1262,14 @@ with gr.Blocks(title="PII Extractor — So sánh 2 Model", theme=gr.themes.Soft(
|
|
| 1220 |
gr.Markdown("**XLM-RoBERTa JSON**")
|
| 1221 |
out_json_bert = gr.JSON(label="XLM-RoBERTa Raw JSON")
|
| 1222 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1223 |
submit_btn.click(
|
| 1224 |
fn=process_both,
|
| 1225 |
inputs=[input_text],
|
| 1226 |
-
outputs=[out_html_gliner, out_json_gliner, out_html_bert, out_json_bert],
|
| 1227 |
)
|
| 1228 |
|
| 1229 |
# ── Tab 2: Test File ─────────────────────────────────────────
|
|
@@ -1242,8 +1288,8 @@ with gr.Blocks(title="PII Extractor — So sánh 2 Model", theme=gr.themes.Soft(
|
|
| 1242 |
)
|
| 1243 |
with gr.Column(scale=1):
|
| 1244 |
model_choice = gr.Radio(
|
| 1245 |
-
choices=["
|
| 1246 |
-
value="
|
| 1247 |
label="🔧 Chọn model",
|
| 1248 |
)
|
| 1249 |
|
|
|
|
| 101 |
font-size: 0.9rem;
|
| 102 |
margin-bottom: 0;
|
| 103 |
}
|
| 104 |
+
.model-header-mmbert {
|
| 105 |
+
background: linear-gradient(135deg, #f97316, #c2410c);
|
| 106 |
+
color: white;
|
| 107 |
+
padding: 8px 16px;
|
| 108 |
+
border-radius: 8px 8px 0 0;
|
| 109 |
+
font-weight: bold;
|
| 110 |
+
font-size: 0.9rem;
|
| 111 |
+
margin-bottom: 0;
|
| 112 |
+
}
|
| 113 |
.batch-sample {
|
| 114 |
border: 1px solid #e5e7eb;
|
| 115 |
border-radius: 10px;
|
|
|
|
| 177 |
background: #ede9fe;
|
| 178 |
color: #5b21b6;
|
| 179 |
}
|
| 180 |
+
.batch-model-label.mmbert {
|
| 181 |
+
background: #ffedd5;
|
| 182 |
+
color: #c2410c;
|
| 183 |
+
}
|
| 184 |
.dark .batch-model-label.gliner {
|
| 185 |
background: #1e3a5f;
|
| 186 |
color: #93c5fd;
|
|
|
|
| 189 |
background: #2e1065;
|
| 190 |
color: #c4b5fd;
|
| 191 |
}
|
| 192 |
+
.dark .batch-model-label.mmbert {
|
| 193 |
+
background: #431407;
|
| 194 |
+
color: #fdba74;
|
| 195 |
+
}
|
| 196 |
.batch-entity-tags {
|
| 197 |
display: flex;
|
| 198 |
flex-wrap: wrap;
|
|
|
|
| 976 |
threshold=0.5,
|
| 977 |
use_rules=False,
|
| 978 |
),
|
| 979 |
+
"mmBERT-multilingual": lambda: mmBERTWrapper(
|
| 980 |
+
hf_repo="quynong/multilingual",
|
| 981 |
+
subfolder="jhu-clsp-mmBERT-base",
|
| 982 |
+
threshold=0.5,
|
| 983 |
+
use_rules=False,
|
| 984 |
+
),
|
| 985 |
}
|
| 986 |
|
| 987 |
MODEL_DISPLAY_NAMES = {
|
| 988 |
"multi_1": "GLiNER2 — multi-v7 (ep3)",
|
| 989 |
"XLMBERT": "XLM-RoBERTa (BERT)",
|
| 990 |
+
"mmBERT-multilingual": "mmBERT-multilingual",
|
| 991 |
}
|
| 992 |
|
| 993 |
|
|
|
|
| 1038 |
|
| 1039 |
|
| 1040 |
# ==========================================
|
| 1041 |
+
# 6. Wrapper cho Gradio (3 model song song)
|
| 1042 |
# ==========================================
|
| 1043 |
def process_both(text: str):
|
| 1044 |
html1, json1 = run_single_model(text, "multi_1")
|
| 1045 |
html2, json2 = run_single_model(text, "XLMBERT")
|
| 1046 |
+
html3, json3 = run_single_model(text, "mmBERT-multilingual")
|
| 1047 |
+
return html1, json1, html2, json2, html3, json3
|
| 1048 |
|
| 1049 |
|
| 1050 |
# ==========================================
|
|
|
|
| 1080 |
return "<div style='color:red;padding:20px;'>File JSON phải là một mảng (array) các object có trường \"text\".</div>", []
|
| 1081 |
|
| 1082 |
model_keys = []
|
| 1083 |
+
if model_choice in ("GLiNER2", "Tất cả"):
|
| 1084 |
model_keys.append("multi_1")
|
| 1085 |
+
if model_choice in ("XLM-RoBERTa", "Tất cả"):
|
| 1086 |
model_keys.append("XLMBERT")
|
| 1087 |
+
if model_choice in ("mmBERT-multilingual", "Tất cả"):
|
| 1088 |
+
model_keys.append("mmBERT-multilingual")
|
| 1089 |
|
| 1090 |
total = len(data)
|
| 1091 |
all_results = []
|
|
|
|
| 1094 |
# Summary header placeholder
|
| 1095 |
total_pii_gliner = 0
|
| 1096 |
total_pii_bert = 0
|
| 1097 |
+
total_pii_mmbert = 0
|
| 1098 |
|
| 1099 |
for idx, item in enumerate(data):
|
| 1100 |
text = item.get("text", "")
|
|
|
|
| 1109 |
result_entry = {"sample": sample_num, "text_preview": text[:100]}
|
| 1110 |
|
| 1111 |
# Run models
|
| 1112 |
+
html_gliner = preds_gliner = html_bert = preds_bert = html_mmbert = preds_mmbert = None
|
| 1113 |
if "multi_1" in model_keys:
|
| 1114 |
html_gliner, preds_gliner = run_single_model(text, "multi_1")
|
| 1115 |
result_entry["gliner"] = preds_gliner
|
|
|
|
| 1120 |
result_entry["xlmbert"] = preds_bert
|
| 1121 |
if isinstance(preds_bert, list):
|
| 1122 |
total_pii_bert += len(preds_bert)
|
| 1123 |
+
if "mmBERT-multilingual" in model_keys:
|
| 1124 |
+
html_mmbert, preds_mmbert = run_single_model(text, "mmBERT-multilingual")
|
| 1125 |
+
result_entry["mmbert_multilingual"] = preds_mmbert
|
| 1126 |
+
if isinstance(preds_mmbert, list):
|
| 1127 |
+
total_pii_mmbert += len(preds_mmbert)
|
| 1128 |
|
| 1129 |
all_results.append(result_entry)
|
| 1130 |
|
|
|
|
| 1138 |
)
|
| 1139 |
html_parts.append(f'<div class="batch-sample-input">{short_text}</div>')
|
| 1140 |
|
| 1141 |
+
if len(model_keys) >= 2:
|
| 1142 |
+
cols = f"repeat({len(model_keys)}, 1fr)"
|
| 1143 |
+
html_parts.append(f'<div class="batch-models-row" style="grid-template-columns:{cols};">')
|
| 1144 |
+
_batch_cols = [
|
| 1145 |
+
("multi_1", "gliner", "GLiNER2", html_gliner, preds_gliner),
|
| 1146 |
+
("XLMBERT", "bert", "XLM-RoBERTa", html_bert, preds_bert),
|
| 1147 |
+
("mmBERT-multilingual", "mmbert", "mmBERT-multi", html_mmbert, preds_mmbert),
|
| 1148 |
+
]
|
| 1149 |
+
for mk, cls, name, h, p in _batch_cols:
|
| 1150 |
+
if mk not in model_keys:
|
| 1151 |
+
continue
|
| 1152 |
+
html_parts.append('<div class="batch-model-col">')
|
| 1153 |
+
html_parts.append(f'<div class="batch-model-label {cls}">{name}</div>')
|
| 1154 |
+
if h:
|
| 1155 |
+
html_parts.append(h)
|
| 1156 |
+
n = len(p) if isinstance(p, list) else 0
|
| 1157 |
+
html_parts.append(f'<div class="batch-entity-tags"><strong style="font-size:0.75rem;margin-right:6px;">{n} entities:</strong>')
|
| 1158 |
+
html_parts.append(_build_entity_tags_html(p))
|
| 1159 |
+
html_parts.append('</div></div>')
|
|
|
|
| 1160 |
html_parts.append('</div>') # end batch-models-row
|
| 1161 |
else:
|
| 1162 |
# Single model
|
| 1163 |
mk = model_keys[0]
|
| 1164 |
+
_single_map = {
|
| 1165 |
+
"multi_1": ("gliner", "GLiNER2", html_gliner, preds_gliner),
|
| 1166 |
+
"XLMBERT": ("bert", "XLM-RoBERTa", html_bert, preds_bert),
|
| 1167 |
+
"mmBERT-multilingual": ("mmbert", "mmBERT-multi", html_mmbert, preds_mmbert),
|
| 1168 |
+
}
|
| 1169 |
+
cls, name, h, p = _single_map[mk]
|
| 1170 |
html_parts.append(f'<div style="padding:12px 16px;">')
|
| 1171 |
html_parts.append(f'<div class="batch-model-label {cls}">{name}</div>')
|
| 1172 |
if h:
|
|
|
|
| 1186 |
if "multi_1" in model_keys:
|
| 1187 |
summary_lines.append(f"🤖 <strong>GLiNER2:</strong> {total_pii_gliner} PII entities phát hiện<br>")
|
| 1188 |
if "XLMBERT" in model_keys:
|
| 1189 |
+
summary_lines.append(f"🧠 <strong>XLM-RoBERTa:</strong> {total_pii_bert} PII entities phát hiện<br>")
|
| 1190 |
+
if "mmBERT-multilingual" in model_keys:
|
| 1191 |
+
summary_lines.append(f"🔶 <strong>mmBERT-multilingual:</strong> {total_pii_mmbert} PII entities phát hiện")
|
| 1192 |
summary_lines.append("</div>")
|
| 1193 |
|
| 1194 |
final_html = "".join(summary_lines) + "".join(html_parts)
|
|
|
|
| 1211 |
"our support team at 555-0198.\n\n"
|
| 1212 |
)
|
| 1213 |
|
| 1214 |
+
with gr.Blocks(title="PII Extractor — So sánh 3 Model", theme=gr.themes.Soft(), css=custom_css) as demo:
|
| 1215 |
+
gr.Markdown("# 🔍 Hệ thống Trích xuất PII — So sánh 3 Model Song Song")
|
| 1216 |
|
| 1217 |
with gr.Tabs():
|
| 1218 |
# ── Tab 1: Nhập văn bản ──────────────────────────────────────
|
| 1219 |
with gr.TabItem("📝 Nhập văn bản"):
|
| 1220 |
gr.Markdown(
|
| 1221 |
"Nhập văn bản bên dưới và nhấn **Trích xuất PII**. "
|
| 1222 |
+
"Kết quả của **GLiNER2 multi-v7**, **XLM-RoBERTa** và **mmBERT-multilingual** sẽ hiển thị đồng thời."
|
| 1223 |
)
|
| 1224 |
|
| 1225 |
with gr.Row():
|
|
|
|
| 1230 |
scale=1,
|
| 1231 |
)
|
| 1232 |
|
| 1233 |
+
submit_btn = gr.Button("⚡ Trích xuất PII (Cả 3 Model)", variant="primary", size="lg")
|
| 1234 |
|
| 1235 |
gr.Markdown("## 📊 Kết quả nhận diện")
|
| 1236 |
with gr.Row(equal_height=True):
|
|
|
|
| 1246 |
)
|
| 1247 |
out_html_bert = gr.HTML(label="XLM-RoBERTa Output")
|
| 1248 |
|
| 1249 |
+
with gr.Column():
|
| 1250 |
+
gr.HTML(
|
| 1251 |
+
'<div class="model-header-mmbert">🔶 Model 3 — mmBERT-multilingual (jhu-clsp, threshold=0.5)</div>'
|
| 1252 |
+
)
|
| 1253 |
+
out_html_mmbert = gr.HTML(label="mmBERT-multilingual Output")
|
| 1254 |
+
|
| 1255 |
gr.Markdown("## 🗂️ Dữ liệu JSON thô")
|
| 1256 |
with gr.Row(equal_height=True):
|
| 1257 |
with gr.Column():
|
|
|
|
| 1262 |
gr.Markdown("**XLM-RoBERTa JSON**")
|
| 1263 |
out_json_bert = gr.JSON(label="XLM-RoBERTa Raw JSON")
|
| 1264 |
|
| 1265 |
+
with gr.Column():
|
| 1266 |
+
gr.Markdown("**mmBERT-multilingual JSON**")
|
| 1267 |
+
out_json_mmbert = gr.JSON(label="mmBERT-multilingual Raw JSON")
|
| 1268 |
+
|
| 1269 |
submit_btn.click(
|
| 1270 |
fn=process_both,
|
| 1271 |
inputs=[input_text],
|
| 1272 |
+
outputs=[out_html_gliner, out_json_gliner, out_html_bert, out_json_bert, out_html_mmbert, out_json_mmbert],
|
| 1273 |
)
|
| 1274 |
|
| 1275 |
# ── Tab 2: Test File ─────────────────────────────────────────
|
|
|
|
| 1288 |
)
|
| 1289 |
with gr.Column(scale=1):
|
| 1290 |
model_choice = gr.Radio(
|
| 1291 |
+
choices=["Tất cả", "GLiNER2", "XLM-RoBERTa", "mmBERT-multilingual"],
|
| 1292 |
+
value="Tất cả",
|
| 1293 |
label="🔧 Chọn model",
|
| 1294 |
)
|
| 1295 |
|