yuu1234 commited on
Commit
c7483ea
·
1 Parent(s): f4cf167
Dockerfile ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Base image
2
+ FROM python:3.10-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Copy requirements and install
8
+ COPY requirements.txt .
9
+ RUN pip install --no-cache-dir -r requirements.txt
10
+
11
+ # Copy app code and model
12
+ COPY app.py .
13
+ COPY model_save/ ./model_save/
14
+ COPY best_model.pt .
15
+
16
+ # Expose ports
17
+ EXPOSE 7860 # Gradio UI
18
+ EXPOSE 5000 # Flask API
19
+
20
+ # HF Spaces sẽ run CMD này
21
+ # Gunicorn chạy Flask API trên port 5000
22
+ # Gradio UI chạy song song trong cùng container
23
+ CMD bash -c "python app.py & gunicorn -w 4 -b 0.0.0.0:5000 app:app"
app.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from flask import Flask, request, jsonify
3
+ import torch
4
+ from transformers import BertTokenizer, BertForSequenceClassification
5
+ import threading
6
+
7
+ # ------------------- Device -------------------
8
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
9
+
10
+ # ------------------- Load model -------------------
11
+ tokenizer = BertTokenizer.from_pretrained("./model_save")
12
+ model = BertForSequenceClassification.from_pretrained("./model_save")
13
+ model.load_state_dict(torch.load("best_model.pt", map_location=device))
14
+ model.to(device)
15
+ model.eval()
16
+
17
+ # ------------------- Prediction function -------------------
18
+ def predict_offensive(text):
19
+ encoded = tokenizer(
20
+ text,
21
+ return_tensors="pt",
22
+ truncation=True,
23
+ padding="max_length",
24
+ max_length=128
25
+ )
26
+ input_ids = encoded["input_ids"].to(device)
27
+ attention_mask = encoded["attention_mask"].to(device)
28
+
29
+ with torch.no_grad():
30
+ logits = model(input_ids, attention_mask=attention_mask).logits
31
+
32
+ pred = torch.argmax(logits, dim=1).item()
33
+ return "Offensive" if pred == 1 else "Not Offensive"
34
+
35
+ # ------------------- Flask API -------------------
36
+ app = Flask(__name__)
37
+
38
+ @app.route("/predict", methods=["POST"])
39
+ def api_predict():
40
+ data = request.json
41
+ if not data or "text" not in data:
42
+ return jsonify({"error": "Missing 'text' field"}), 400
43
+
44
+ text = data["text"]
45
+ prediction = predict_offensive(text)
46
+ return jsonify({"prediction": prediction})
47
+
48
+ # ------------------- Gradio UI -------------------
49
+ iface = gr.Interface(
50
+ fn=predict_offensive,
51
+ inputs=gr.Textbox(lines=2, placeholder="Enter text here..."),
52
+ outputs="text",
53
+ title="Offensive Language Detector",
54
+ description="Enter a sentence and the model predicts if it contains offensive language."
55
+ )
56
+
57
+ def run_gradio():
58
+ iface.launch(server_name="0.0.0.0", server_port=7860, share=False, prevent_thread_lock=True)
59
+
60
+ # ------------------- Main -------------------
61
+ if __name__ == "__main__":
62
+ # Start Gradio in a separate thread
63
+ threading.Thread(target=run_gradio).start()
64
+
65
+ # Flask API will be served by Gunicorn (HF Spaces sẽ build và chạy)
66
+ # gunicorn -w 4 -b 0.0.0.0:5000 app:app
67
+ print("Flask API ready. Use Gunicorn to serve for concurrent requests.")
best_model.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:275976b05aebfa9922f12e79f5b0ba1fcb7074adf5d15a38d3058564f95a8e0a
3
+ size 438020423
model_save/config.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "BertForSequenceClassification"
4
+ ],
5
+ "attention_probs_dropout_prob": 0.1,
6
+ "classifier_dropout": null,
7
+ "gradient_checkpointing": false,
8
+ "hidden_act": "gelu",
9
+ "hidden_dropout_prob": 0.1,
10
+ "hidden_size": 768,
11
+ "id2label": {
12
+ "0": "LABEL_0",
13
+ "1": "LABEL_1",
14
+ "2": "LABEL_2"
15
+ },
16
+ "initializer_range": 0.02,
17
+ "intermediate_size": 3072,
18
+ "label2id": {
19
+ "LABEL_0": 0,
20
+ "LABEL_1": 1,
21
+ "LABEL_2": 2
22
+ },
23
+ "layer_norm_eps": 1e-12,
24
+ "max_position_embeddings": 512,
25
+ "model_type": "bert",
26
+ "num_attention_heads": 12,
27
+ "num_hidden_layers": 12,
28
+ "pad_token_id": 0,
29
+ "position_embedding_type": "absolute",
30
+ "problem_type": "single_label_classification",
31
+ "torch_dtype": "float32",
32
+ "transformers_version": "4.52.4",
33
+ "type_vocab_size": 2,
34
+ "use_cache": true,
35
+ "vocab_size": 30522
36
+ }
model_save/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:40ea5cf1edbb4e292ac44e02f69aa3c3fb4437da2ac453ced2a6a6e31c23f8e8
3
+ size 437961724
model_save/special_tokens_map.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": "[CLS]",
3
+ "mask_token": "[MASK]",
4
+ "pad_token": "[PAD]",
5
+ "sep_token": "[SEP]",
6
+ "unk_token": "[UNK]"
7
+ }
model_save/tokenizer_config.json ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "[PAD]",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "100": {
12
+ "content": "[UNK]",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "101": {
20
+ "content": "[CLS]",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "102": {
28
+ "content": "[SEP]",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ },
35
+ "103": {
36
+ "content": "[MASK]",
37
+ "lstrip": false,
38
+ "normalized": false,
39
+ "rstrip": false,
40
+ "single_word": false,
41
+ "special": true
42
+ }
43
+ },
44
+ "clean_up_tokenization_spaces": true,
45
+ "cls_token": "[CLS]",
46
+ "do_basic_tokenize": true,
47
+ "do_lower_case": true,
48
+ "extra_special_tokens": {},
49
+ "mask_token": "[MASK]",
50
+ "model_max_length": 512,
51
+ "never_split": null,
52
+ "pad_token": "[PAD]",
53
+ "sep_token": "[SEP]",
54
+ "strip_accents": null,
55
+ "tokenize_chinese_chars": true,
56
+ "tokenizer_class": "BertTokenizer",
57
+ "unk_token": "[UNK]"
58
+ }
model_save/vocab.txt ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ torch
2
+ transformers
3
+ flask
4
+ gunicorn
5
+ gradio
6
+ numpy