phuongsuga's picture
Update app.py
8a4f04c verified
Raw
History Blame Contribute Delete
5.08 kB
import os
import re
import json
import torch
import torch.nn.functional as F
from flask import Flask, request, jsonify
from transformers import AutoTokenizer, AutoModelForSequenceClassification
from pyvi import ViTokenizer
from PIL import Image
from torchvision import transforms
import timm
import requests
from flask_cors import CORS
# =====================
# CONFIG
# =====================
os.environ["TRANSFORMERS_CACHE"] = "/tmp/hf_cache" # tránh vượt storage limit
TEXT_MODEL_REPO = "phuongsuga/PBL6_AI_Model_Text_Image"
IMAGE_MODEL_REPO = "phuongsuga/PBL6_AI_Model_Image"
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
THRESHOLD = 0.65
# =====================
# LOAD TEXT MODEL
# =====================
print("🔹 Downloading text model...")
tokenizer = AutoTokenizer.from_pretrained(
TEXT_MODEL_REPO,
subfolder="text_model",
use_fast=False
)
text_model = AutoModelForSequenceClassification.from_pretrained(
TEXT_MODEL_REPO,
subfolder="text_model/checkpoint-3390"
)
text_model.to(DEVICE).eval()
# load label2id.json
label_url = f"https://huggingface.co/{TEXT_MODEL_REPO}/resolve/main/text_model/label2id.json"
label2id = requests.get(label_url).json()
id2label_text = {i: l for l, i in label2id.items()}
# =====================
# LOAD IMAGE MODEL
# =====================
print("🔹 Downloading image model...")
class_names = ["an_toan", "bao_luc", "khieu_dam_doi_truy", "nhay_cam_chinh_tri"]
def build_model(num_classes=4):
return timm.create_model("efficientnet_b3", pretrained=False, num_classes=num_classes)
image_model = build_model()
# tải model tạm trong /tmp để không chiếm storage
image_model_path = "/tmp/efficientnet_b3.pth"
if not os.path.exists(image_model_path):
url = f"https://huggingface.co/{IMAGE_MODEL_REPO}/resolve/main/image_model/efficientnet_b3.pth"
torch.hub.download_url_to_file(url, image_model_path)
image_model.load_state_dict(torch.load(image_model_path, map_location=DEVICE))
image_model.to(DEVICE).eval()
# chuẩn hóa ảnh
val_transforms = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225])
])
# =====================
# UTILS
# =====================
def seg_pyvi(text: str) -> str:
try:
seg = ViTokenizer.tokenize(text)
seg = seg.replace(" ", "_")
except Exception:
seg = text
return seg
def split_sentences(text: str):
sents = re.split(r'(?<=[.!?])\s+|\n+', text.strip())
return [s for s in sents if s.strip()]
def predict_text(text: str):
sentences = split_sentences(text)
results = []
for sent in sentences:
seg = seg_pyvi(sent)
inputs = tokenizer(seg, truncation=True, padding="max_length",
max_length=128, return_tensors="pt").to(DEVICE)
with torch.no_grad():
logits = text_model(**inputs).logits
probs = F.softmax(logits, dim=-1).cpu().numpy()[0]
pred_id = probs.argmax()
label = id2label_text[int(pred_id)]
prob = float(probs[pred_id])
if label != "an_toan" and prob >= THRESHOLD:
results.append({"sentence": sent, "label": label, "confidence": prob})
else:
results.append({
"sentence": sent,
"label": "an_toan",
"confidence": float(probs[label2id["an_toan"]])
})
return results
def predict_image(pil_image: Image.Image):
img = val_transforms(pil_image).unsqueeze(0).to(DEVICE)
with torch.no_grad():
outputs = image_model(img)
probs = F.softmax(outputs, dim=1)[0].cpu().numpy()
pred_id = probs.argmax()
label = class_names[pred_id]
prob = float(probs[pred_id])
if label != "an_toan" and prob >= THRESHOLD:
return {"label": label, "confidence": prob}
else:
return {
"label": "an_toan",
"confidence": float(probs[class_names.index("an_toan")])
}
# =====================
# FLASK APP
# =====================
app = Flask(__name__)
CORS(app)
@app.route("/")
def home():
return jsonify({"message": "✅ AI moderation API is running!"})
@app.route("/analyze", methods=["POST"])
def analyze():
result = {"text_result": [], "image_result": []}
# 🧠 PHÂN TÍCH TEXT
if "content" in request.form:
text_input = request.form["content"]
result["text_result"] = predict_text(text_input)
# 🧠 PHÂN TÍCH NHIỀU ẢNH
if "image" in request.files:
image_files = request.files.getlist("image")
for image_file in image_files:
image = Image.open(image_file.stream).convert("RGB")
image_result = predict_image(image)
result["image_result"].append(image_result)
return jsonify(result)
# =====================
# RUN APP
# =====================
if __name__ == "__main__":
port = int(os.environ.get("PORT", 7860)) # Hugging Face Space truyền PORT vào
app.run(host="0.0.0.0", port=port)