phuongsuga commited on
Commit
6f78861
·
verified ·
1 Parent(s): 57ea215

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +159 -155
app.py CHANGED
@@ -1,159 +1,163 @@
1
- import gradio as gr
2
- import numpy as np
3
- import random
4
- from diffusers import DiffusionPipeline
5
  import torch
6
-
7
- device = "cuda" if torch.cuda.is_available() else "cpu"
8
- model_repo_id = "stabilityai/sdxl-turbo"
9
-
10
- if torch.cuda.is_available():
11
- torch_dtype = torch.float16
12
- else:
13
- torch_dtype = torch.float32
14
-
15
- pipe = DiffusionPipeline.from_pretrained(
16
- model_repo_id,
17
- torch_dtype=torch_dtype,
18
- variant="fp16"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  )
20
 
21
- pipe = pipe.to(device)
22
- pipe.enable_attention_slicing()
23
- pipe.to("cuda" if torch.cuda.is_available() else "cpu")
24
-
25
- MAX_SEED = np.iinfo(np.int32).max
26
- MAX_IMAGE_SIZE = 1024
27
-
28
-
29
- # @spaces.GPU #[uncomment to use ZeroGPU]
30
- def infer(
31
- prompt,
32
- negative_prompt,
33
- seed,
34
- randomize_seed,
35
- width,
36
- height,
37
- guidance_scale,
38
- num_inference_steps,
39
- progress=gr.Progress(track_tqdm=True),
40
- ):
41
- if randomize_seed:
42
- seed = random.randint(0, MAX_SEED)
43
-
44
- generator = torch.Generator().manual_seed(seed)
45
-
46
- image = pipe(
47
- prompt=prompt,
48
- negative_prompt=negative_prompt,
49
- guidance_scale=guidance_scale,
50
- num_inference_steps=num_inference_steps,
51
- width=width,
52
- height=height,
53
- generator=generator,
54
- ).images[0]
55
-
56
- return image, seed
57
-
58
-
59
- examples = [
60
- "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k",
61
- "An astronaut riding a green horse",
62
- "A delicious ceviche cheesecake slice",
63
- ]
64
-
65
- css = """
66
- #col-container {
67
- margin: 0 auto;
68
- max-width: 640px;
69
- }
70
- """
71
-
72
- with gr.Blocks(css=css) as demo:
73
- with gr.Column(elem_id="col-container"):
74
- gr.Markdown(" # Text-to-Image Gradio Template")
75
-
76
- with gr.Row():
77
- prompt = gr.Text(
78
- label="Prompt",
79
- show_label=False,
80
- max_lines=1,
81
- placeholder="Enter your prompt",
82
- container=False,
83
- )
84
-
85
- run_button = gr.Button("Run", scale=0, variant="primary")
86
-
87
- result = gr.Image(label="Result", show_label=False)
88
-
89
- with gr.Accordion("Advanced Settings", open=False):
90
- negative_prompt = gr.Text(
91
- label="Negative prompt",
92
- max_lines=1,
93
- placeholder="Enter a negative prompt",
94
- visible=False,
95
- )
96
-
97
- seed = gr.Slider(
98
- label="Seed",
99
- minimum=0,
100
- maximum=MAX_SEED,
101
- step=1,
102
- value=0,
103
- )
104
-
105
- randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
106
-
107
- with gr.Row():
108
- width = gr.Slider(
109
- label="Width",
110
- minimum=256,
111
- maximum=MAX_IMAGE_SIZE,
112
- step=32,
113
- value=1024, # Replace with defaults that work for your model
114
- )
115
-
116
- height = gr.Slider(
117
- label="Height",
118
- minimum=256,
119
- maximum=MAX_IMAGE_SIZE,
120
- step=32,
121
- value=1024, # Replace with defaults that work for your model
122
- )
123
-
124
- with gr.Row():
125
- guidance_scale = gr.Slider(
126
- label="Guidance scale",
127
- minimum=0.0,
128
- maximum=10.0,
129
- step=0.1,
130
- value=0.0, # Replace with defaults that work for your model
131
- )
132
-
133
- num_inference_steps = gr.Slider(
134
- label="Number of inference steps",
135
- minimum=1,
136
- maximum=50,
137
- step=1,
138
- value=2, # Replace with defaults that work for your model
139
- )
140
-
141
- gr.Examples(examples=examples, inputs=[prompt])
142
- gr.on(
143
- triggers=[run_button.click, prompt.submit],
144
- fn=infer,
145
- inputs=[
146
- prompt,
147
- negative_prompt,
148
- seed,
149
- randomize_seed,
150
- width,
151
- height,
152
- guidance_scale,
153
- num_inference_steps,
154
- ],
155
- outputs=[result, seed],
156
- )
157
-
158
  if __name__ == "__main__":
159
- demo.launch()
 
 
1
+ import os
2
+ import re
3
+ import json
 
4
  import torch
5
+ import torch.nn.functional as F
6
+ from flask import Flask, request, jsonify
7
+ from transformers import AutoTokenizer, AutoModelForSequenceClassification
8
+ from pyvi import ViTokenizer
9
+ from PIL import Image
10
+ from torchvision import transforms
11
+ import timm
12
+ import requests
13
+ from flask_cors import CORS
14
+
15
+ # =====================
16
+ # CONFIG
17
+ # =====================
18
+ os.environ["TRANSFORMERS_CACHE"] = "/tmp/hf_cache" # tránh vượt storage limit
19
+ TEXT_MODEL_REPO = "phuongsuga/PBL6_AI_Model_Text_Image"
20
+ IMAGE_MODEL_REPO = "phuongsuga/PBL6_AI_Model_Image"
21
+ DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
22
+ THRESHOLD = 0.65
23
+
24
+ # =====================
25
+ # LOAD TEXT MODEL
26
+ # =====================
27
+ print("🔹 Downloading text model...")
28
+
29
+ tokenizer = AutoTokenizer.from_pretrained(
30
+ TEXT_MODEL_REPO,
31
+ subfolder="text_model",
32
+ use_fast=False
33
  )
34
 
35
+ text_model = AutoModelForSequenceClassification.from_pretrained(
36
+ TEXT_MODEL_REPO,
37
+ subfolder="text_model/checkpoint-3390"
38
+ )
39
+ text_model.to(DEVICE).eval()
40
+
41
+ # load label2id.json
42
+ label_url = f"https://huggingface.co/{TEXT_MODEL_REPO}/resolve/main/text_model/label2id.json"
43
+ label2id = requests.get(label_url).json()
44
+ id2label_text = {i: l for l, i in label2id.items()}
45
+
46
+ # =====================
47
+ # LOAD IMAGE MODEL
48
+ # =====================
49
+ print("🔹 Downloading image model...")
50
+
51
+ class_names = ["an_toan", "bao_luc", "khieu_dam_doi_truy", "nhay_cam_chinh_tri"]
52
+
53
+ def build_model(num_classes=4):
54
+ return timm.create_model("efficientnet_b3", pretrained=False, num_classes=num_classes)
55
+
56
+ image_model = build_model()
57
+
58
+ # tải model tạm trong /tmp để không chiếm storage
59
+ image_model_path = "/tmp/efficientnet_b3.pth"
60
+ if not os.path.exists(image_model_path):
61
+ url = f"https://huggingface.co/{IMAGE_MODEL_REPO}/resolve/main/image_model/efficientnet_b3.pth"
62
+ torch.hub.download_url_to_file(url, image_model_path)
63
+
64
+ image_model.load_state_dict(torch.load(image_model_path, map_location=DEVICE))
65
+ image_model.to(DEVICE).eval()
66
+
67
+ # chuẩn hóa ảnh
68
+ val_transforms = transforms.Compose([
69
+ transforms.Resize((224, 224)),
70
+ transforms.ToTensor(),
71
+ transforms.Normalize([0.485, 0.456, 0.406],
72
+ [0.229, 0.224, 0.225])
73
+ ])
74
+
75
+ # =====================
76
+ # UTILS
77
+ # =====================
78
+ def seg_pyvi(text: str) -> str:
79
+ try:
80
+ seg = ViTokenizer.tokenize(text)
81
+ seg = seg.replace(" ", "_")
82
+ except Exception:
83
+ seg = text
84
+ return seg
85
+
86
+ def split_sentences(text: str):
87
+ sents = re.split(r'(?<=[.!?])\s+|\n+', text.strip())
88
+ return [s for s in sents if s.strip()]
89
+
90
+ def predict_text(text: str):
91
+ sentences = split_sentences(text)
92
+ results = []
93
+ for sent in sentences:
94
+ seg = seg_pyvi(sent)
95
+ inputs = tokenizer(seg, truncation=True, padding="max_length",
96
+ max_length=128, return_tensors="pt").to(DEVICE)
97
+ with torch.no_grad():
98
+ logits = text_model(**inputs).logits
99
+ probs = F.softmax(logits, dim=-1).cpu().numpy()[0]
100
+ pred_id = probs.argmax()
101
+ label = id2label_text[int(pred_id)]
102
+ prob = float(probs[pred_id])
103
+ if label != "an_toan" and prob >= THRESHOLD:
104
+ results.append({"sentence": sent, "label": label, "confidence": prob})
105
+ else:
106
+ results.append({
107
+ "sentence": sent,
108
+ "label": "an_toan",
109
+ "confidence": float(probs[label2id["an_toan"]])
110
+ })
111
+ return results
112
+
113
+ def predict_image(pil_image: Image.Image):
114
+ img = val_transforms(pil_image).unsqueeze(0).to(DEVICE)
115
+ with torch.no_grad():
116
+ outputs = image_model(img)
117
+ probs = F.softmax(outputs, dim=1)[0].cpu().numpy()
118
+ pred_id = probs.argmax()
119
+ label = class_names[pred_id]
120
+ prob = float(probs[pred_id])
121
+ if label != "an_toan" and prob >= THRESHOLD:
122
+ return {"label": label, "confidence": prob}
123
+ else:
124
+ return {
125
+ "label": "an_toan",
126
+ "confidence": float(probs[class_names.index("an_toan")])
127
+ }
128
+
129
+ # =====================
130
+ # FLASK APP
131
+ # =====================
132
+ app = Flask(__name__)
133
+ CORS(app)
134
+
135
+ @app.route("/")
136
+ def home():
137
+ return jsonify({"message": "✅ AI moderation API is running!"})
138
+
139
+ @app.route("/analyze", methods=["POST"])
140
+ def analyze():
141
+ result = {"text_result": [], "image_result": []}
142
+
143
+ # 🧠 PHÂN TÍCH TEXT
144
+ if "content" in request.form:
145
+ text_input = request.form["content"]
146
+ result["text_result"] = predict_text(text_input)
147
+
148
+ # 🧠 PHÂN TÍCH NHIỀU ẢNH
149
+ if "image" in request.files:
150
+ image_files = request.files.getlist("image")
151
+ for image_file in image_files:
152
+ image = Image.open(image_file.stream).convert("RGB")
153
+ image_result = predict_image(image)
154
+ result["image_result"].append(image_result)
155
+
156
+ return jsonify(result)
157
+
158
+ # =====================
159
+ # RUN APP
160
+ # =====================
 
 
 
 
 
 
 
 
 
 
 
161
  if __name__ == "__main__":
162
+ port = int(os.environ.get("PORT", 7860)) # Hugging Face Space truyền PORT vào
163
+ app.run(host="0.0.0.0", port=port)