Boulbaba commited on
Commit
735c7d6
·
1 Parent(s): 291f07d

Add application file

Browse files
Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ WORKDIR /app
4
+
5
+ ENV PYTHONDONTWRITEBYTECODE=1
6
+ ENV PYTHONUNBUFFERED=1
7
+ ENV PIP_NO_CACHE_DIR=1
8
+
9
+ RUN apt-get update && apt-get install -y --no-install-recommends \
10
+ gcc \
11
+ g++ \
12
+ && rm -rf /var/lib/apt/lists/*
13
+
14
+ COPY requirements.txt .
15
+ RUN pip install -r requirements.txt
16
+
17
+ COPY . .
18
+
19
+ EXPOSE 7860
20
+
21
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Union
2
+ from fastapi import FastAPI, HTTPException
3
+ from pydantic import BaseModel
4
+ from transformers import AutoTokenizer
5
+ from optimum.onnxruntime import ORTModelForSequenceClassification
6
+ import torch
7
+
8
+ MODEL_DIR = "onnx_model"
9
+
10
+ CLASS_LABELS = [
11
+ "الطويل", "البسيط", "الكامل", "الوافر", "الهزج",
12
+ "الرجز", "الرمل", "السريع", "المنسرح", "الخفيف",
13
+ "المضارع", "المقتضب", "المجتث", "المتقارب", "المحدث"
14
+ ]
15
+
16
+ app = FastAPI(title="Arabic Poetry Meter Predictor (ONNX)")
17
+
18
+ tokenizer = None
19
+ model = None
20
+ id2label = None
21
+
22
+
23
+ class PredictRequest(BaseModel):
24
+ sentences: Union[str, List[str]]
25
+
26
+
27
+ @app.on_event("startup")
28
+ def startup_event():
29
+ global tokenizer, model, id2label
30
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_DIR)
31
+ model = ORTModelForSequenceClassification.from_pretrained(MODEL_DIR)
32
+
33
+ config_labels = getattr(model.config, "id2label", None)
34
+ if isinstance(config_labels, dict) and config_labels:
35
+ fixed = {}
36
+ for k, v in config_labels.items():
37
+ try:
38
+ fixed[int(k)] = v
39
+ except Exception:
40
+ fixed[k] = v
41
+ id2label = fixed
42
+ else:
43
+ id2label = {i: label for i, label in enumerate(CLASS_LABELS)}
44
+
45
+
46
+ def normalize_sentences(value: Union[str, List[str]]) -> List[str]:
47
+ if isinstance(value, str):
48
+ value = value.strip()
49
+ return [value] if value else []
50
+
51
+ if isinstance(value, list):
52
+ return [str(v).strip() for v in value if str(v).strip()]
53
+
54
+ return []
55
+
56
+
57
+ @app.get("/")
58
+ def root():
59
+ return {"message": "Arabic Poetry Meter Predictor API is running"}
60
+
61
+
62
+ @app.get("/health")
63
+ def health():
64
+ return {"status": "ok"}
65
+
66
+
67
+
68
+ @app.get("/test")
69
+ def test():
70
+ return {"arabic": "مرحبا هذا اختبار"}
71
+
72
+
73
+ @app.post("/predict")
74
+ def predict(req: PredictRequest):
75
+ if tokenizer is None or model is None:
76
+ raise HTTPException(status_code=500, detail="Model is not loaded")
77
+
78
+ sentences = normalize_sentences(req.sentences)
79
+ if not sentences:
80
+ raise HTTPException(status_code=400, detail="No poetry lines provided")
81
+
82
+ try:
83
+ inputs = tokenizer(
84
+ sentences,
85
+ return_tensors="pt",
86
+ padding=True,
87
+ truncation=True,
88
+ max_length=256,
89
+ )
90
+
91
+ outputs = model(**inputs)
92
+ probs = torch.softmax(outputs.logits, dim=-1)
93
+ top_scores, top_indices = torch.max(probs, dim=-1)
94
+
95
+ except Exception as e:
96
+ raise HTTPException(status_code=500, detail=f"Prediction failed: {str(e)}")
97
+
98
+ results = []
99
+ for line, score, idx in zip(sentences, top_scores.tolist(), top_indices.tolist()):
100
+ label = id2label.get(int(idx), f"LABEL_{idx}")
101
+ results.append({
102
+ "line": line,
103
+ "predictions": [
104
+ {
105
+ "rank": 1,
106
+ "label": label,
107
+ "score": float(score),
108
+ }
109
+ ],
110
+ })
111
+
112
+ return results
onnx_model/config.json ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "BertForSequenceClassification"
4
+ ],
5
+ "attention_probs_dropout_prob": 0.1,
6
+ "classifier_dropout": null,
7
+ "directionality": "bidi",
8
+ "dtype": "float32",
9
+ "gradient_checkpointing": false,
10
+ "hidden_act": "gelu",
11
+ "hidden_dropout_prob": 0.1,
12
+ "hidden_size": 768,
13
+ "id2label": {
14
+ "0": "\u0627\u0644\u0628\u0633\u064a\u0637",
15
+ "1": "\u0627\u0644\u062e\u0641\u064a\u0641",
16
+ "2": "\u0627\u0644\u062f\u0648\u0628\u064a\u062a",
17
+ "3": "\u0627\u0644\u0631\u062c\u0632",
18
+ "4": "\u0627\u0644\u0631\u0645\u0644",
19
+ "5": "\u0627\u0644\u0633\u0631\u064a\u0639",
20
+ "6": "\u0627\u0644\u0633\u0644\u0633\u0644\u0629",
21
+ "7": "\u0627\u0644\u0637\u0648\u064a\u0644",
22
+ "8": "\u0627\u0644\u0643\u0627\u0645\u0644",
23
+ "9": "\u0627\u0644\u0645\u062a\u062f\u0627\u0631\u0643",
24
+ "10": "\u0627\u0644\u0645\u062a\u0642\u0627\u0631\u0628",
25
+ "11": "\u0627\u0644\u0645\u062c\u062a\u062b",
26
+ "12": "\u0627\u0644\u0645\u062f\u064a\u062f",
27
+ "13": "\u0627\u0644\u0645\u0636\u0627\u0631\u0639",
28
+ "14": "\u0627\u0644\u0645\u0642\u062a\u0636\u0628",
29
+ "15": "\u0627\u0644\u0645\u0646\u0633\u0631\u062d",
30
+ "16": "\u0627\u0644\u0645\u0648\u0627\u0644\u064a\u0627",
31
+ "17": "\u0627\u0644\u0647\u0632\u062c",
32
+ "18": "\u0627\u0644\u0648\u0627\u0641\u0631",
33
+ "19": "\u0634\u0639\u0631 \u0627\u0644\u062a\u0641\u0639\u064a\u0644\u0629",
34
+ "20": "\u0634\u0639\u0631 \u062d\u0631",
35
+ "21": "\u0639\u0627\u0645\u064a",
36
+ "22": "\u0645\u0648\u0634\u062d"
37
+ },
38
+ "initializer_range": 0.02,
39
+ "intermediate_size": 3072,
40
+ "label2id": {
41
+ "\u0627\u0644\u0628\u0633\u064a\u0637": 0,
42
+ "\u0627\u0644\u062e\u0641\u064a\u0641": 1,
43
+ "\u0627\u0644\u062f\u0648\u0628\u064a\u062a": 2,
44
+ "\u0627\u0644\u0631\u062c\u0632": 3,
45
+ "\u0627\u0644\u0631\u0645\u0644": 4,
46
+ "\u0627\u0644\u0633\u0631\u064a\u0639": 5,
47
+ "\u0627\u0644\u0633\u0644\u0633\u0644\u0629": 6,
48
+ "\u0627\u0644\u0637\u0648\u064a\u0644": 7,
49
+ "\u0627\u0644\u0643\u0627\u0645\u0644": 8,
50
+ "\u0627\u0644\u0645\u062a\u062f\u0627\u0631\u0643": 9,
51
+ "\u0627\u0644\u0645\u062a\u0642\u0627\u0631\u0628": 10,
52
+ "\u0627\u0644\u0645\u062c\u062a\u062b": 11,
53
+ "\u0627\u0644\u0645\u062f\u064a\u062f": 12,
54
+ "\u0627\u0644\u0645\u0636\u0627\u0631\u0639": 13,
55
+ "\u0627\u0644\u0645\u0642\u062a\u0636\u0628": 14,
56
+ "\u0627\u0644\u0645\u0646\u0633\u0631\u062d": 15,
57
+ "\u0627\u0644\u0645\u0648\u0627\u0644\u064a\u0627": 16,
58
+ "\u0627\u0644\u0647\u0632\u062c": 17,
59
+ "\u0627\u0644\u0648\u0627\u0641\u0631": 18,
60
+ "\u0634\u0639\u0631 \u0627\u0644\u062a\u0641\u0639\u064a\u0644\u0629": 19,
61
+ "\u0634\u0639\u0631 \u062d\u0631": 20,
62
+ "\u0639\u0627\u0645\u064a": 21,
63
+ "\u0645\u0648\u0634\u062d": 22
64
+ },
65
+ "layer_norm_eps": 1e-12,
66
+ "max_position_embeddings": 512,
67
+ "model_type": "bert",
68
+ "num_attention_heads": 12,
69
+ "num_hidden_layers": 12,
70
+ "pad_token_id": 0,
71
+ "pooler_fc_size": 768,
72
+ "pooler_num_attention_heads": 12,
73
+ "pooler_num_fc_layers": 3,
74
+ "pooler_size_per_head": 128,
75
+ "pooler_type": "first_token_transform",
76
+ "position_embedding_type": "absolute",
77
+ "problem_type": "single_label_classification",
78
+ "transformers_version": "4.57.6",
79
+ "type_vocab_size": 2,
80
+ "use_cache": true,
81
+ "vocab_size": 100000
82
+ }
onnx_model/special_tokens_map.json ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": {
3
+ "content": "[CLS]",
4
+ "lstrip": false,
5
+ "normalized": false,
6
+ "rstrip": false,
7
+ "single_word": false
8
+ },
9
+ "mask_token": {
10
+ "content": "[MASK]",
11
+ "lstrip": false,
12
+ "normalized": false,
13
+ "rstrip": false,
14
+ "single_word": false
15
+ },
16
+ "pad_token": {
17
+ "content": "[PAD]",
18
+ "lstrip": false,
19
+ "normalized": false,
20
+ "rstrip": false,
21
+ "single_word": false
22
+ },
23
+ "sep_token": {
24
+ "content": "[SEP]",
25
+ "lstrip": false,
26
+ "normalized": false,
27
+ "rstrip": false,
28
+ "single_word": false
29
+ },
30
+ "unk_token": {
31
+ "content": "[UNK]",
32
+ "lstrip": false,
33
+ "normalized": false,
34
+ "rstrip": false,
35
+ "single_word": false
36
+ }
37
+ }
onnx_model/tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
onnx_model/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
+ "1": {
12
+ "content": "[UNK]",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "2": {
20
+ "content": "[CLS]",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "3": {
28
+ "content": "[SEP]",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ },
35
+ "4": {
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": false,
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": 1000000000000000019884624838656,
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
+ }
onnx_model/vocab.txt ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ transformers
4
+ optimum[onnxruntime]
5
+ torch
6
+ sentencepiece