Spaces:
Sleeping
Sleeping
File size: 4,078 Bytes
8b1f68b a9e89a3 8b1f68b a9e89a3 8b1f68b a9e89a3 8b1f68b a9e89a3 8b1f68b a9e89a3 8b1f68b a9e89a3 24ca47b 8b1f68b a9e89a3 a916de4 a9e89a3 a916de4 8b1f68b 24ca47b a9e89a3 8b1f68b a9e89a3 75208b4 a9e89a3 7fa25d5 a9e89a3 7fa25d5 16c2c8f a916de4 7fa25d5 a916de4 a9e89a3 a916de4 a9e89a3 7fa25d5 16c2c8f a9e89a3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | import os
import shutil
import zipfile
import gradio as gr
import torch
from transformers import AutoModelForSequenceClassification, AutoTokenizer
ZIP_PATH = "model.zip"
EXTRACT_DIR = "./model"
MODEL_DIR = os.path.join(EXTRACT_DIR, "final_model")
DEVICE = torch.device("cpu")
def prepare_model_files():
config_path = os.path.join(MODEL_DIR, "config.json")
weights_path = os.path.join(MODEL_DIR, "model.safetensors")
if os.path.isfile(config_path) and os.path.isfile(weights_path):
print("模型已經解壓完成。", flush=True)
return
if not os.path.isfile(ZIP_PATH):
raise FileNotFoundError("找不到 model.zip")
if os.path.exists(EXTRACT_DIR):
shutil.rmtree(EXTRACT_DIR)
os.makedirs(EXTRACT_DIR, exist_ok=True)
print("正在解壓模型……", flush=True)
with zipfile.ZipFile(ZIP_PATH, "r") as zip_ref:
zip_ref.extractall(EXTRACT_DIR)
print("模型解壓完成。", flush=True)
if not os.path.isfile(config_path):
raise FileNotFoundError(
f"找不到 {config_path},請確認 ZIP 裡面有 final_model 資料夾。"
)
if not os.path.isfile(weights_path):
raise FileNotFoundError(
f"找不到 {weights_path},請確認 model.safetensors 已包含在 ZIP 中。"
)
prepare_model_files()
print("正在載入 tokenizer……", flush=True)
tokenizer = AutoTokenizer.from_pretrained(
MODEL_DIR,
local_files_only=True
)
print("正在載入 BERT 模型到 CPU……", flush=True)
model = AutoModelForSequenceClassification.from_pretrained(
MODEL_DIR,
local_files_only=True
)
model.to(DEVICE)
model.eval()
print("模型載入成功。", flush=True)
LABEL_MAP = {
0: "詐騙訊息",
1: "真實訊息"
}
def predict(text: str) -> str:
text = text.strip()
if not text:
return "請先輸入要判斷的訊息。"
inputs = tokenizer(
text,
return_tensors="pt",
truncation=True,
padding=True,
max_length=256
)
inputs = {
key: value.to(DEVICE)
for key, value in inputs.items()
}
with torch.inference_mode():
outputs = model(**inputs)
probabilities = torch.softmax(outputs.logits, dim=-1)[0]
probabilities = probabilities.cpu()
pred_id = int(torch.argmax(probabilities).item())
confidence = float(probabilities[pred_id].item() * 100)
scam_probability = float(probabilities[0].item() * 100)
real_probability = float(probabilities[1].item() * 100)
pred_label = LABEL_MAP.get(
pred_id,
f"未知類別 {pred_id}"
)
if pred_id == 0:
advice = (
"請勿立即匯款、提供銀行帳號、密碼、信用卡資料或簡訊驗證碼。"
"建議透過官方管道查證,必要時撥打 165 反詐騙專線。"
)
else:
advice = (
"模型判斷較接近真實訊息,但模型仍可能誤判。"
"若內容涉及金錢、帳戶或個人資料,仍應再次查證。"
)
return (
f"🔍 判斷結果:{pred_label}\n\n"
f"📊 模型信心度:{confidence:.2f}%\n\n"
f"🚨 詐騙機率:{scam_probability:.2f}%\n"
f"✅ 真實機率:{real_probability:.2f}%\n\n"
f"⚠️ 提醒:{advice}"
)
demo = gr.Interface(
fn=predict,
inputs=gr.Textbox(
lines=6,
label="訊息內容",
placeholder="請輸入要判斷的新聞、貼文或可疑訊息……"
),
outputs=gr.Textbox(
label="辨識結果",
lines=8
),
title="LINE Bot BERT 詐騙/真實訊息辨識 API",
description=(
"輸入文字後,系統會判斷內容較接近詐騙訊息或真實訊息。"
"建議輸入較完整的內容,文字過短可能降低辨識效果。"
),
api_name="predict"
)
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
ssr_mode=False,
show_error=True
) |