| import os |
| import re |
| import functools |
| import torch |
| import gradio as gr |
| from transformers import AutoTokenizer, AutoModelForSequenceClassification |
|
|
| |
| MODEL_ID = os.getenv("HF_MODEL_ID", "ArabicNewsAnalyzer/MARBERTv2-Single-Arabic-Dialect-Scrapped-MSA-Mask-epoch3") |
| LOCAL_MODEL_PATH = os.path.join(os.path.dirname(__file__), "..", "results", "best_model") |
| MAX_LENGTH = 128 |
|
|
| COUNTRY_DETAILS = { |
| "Algeria": {"flag": "๐ฉ๐ฟ", "name_ar": "ุงูุฌุฒุงุฆุฑ", "region": "Maghrebi"}, |
| "Bahrain": {"flag": "๐ง๐ญ", "name_ar": "ุงูุจุญุฑูู", "region": "Gulf"}, |
| "Egypt": {"flag": "๐ช๐ฌ", "name_ar": "ู
ุตุฑ", "region": "Egyptian"}, |
| "Iraq": {"flag": "๐ฎ๐ถ", "name_ar": "ุงูุนุฑุงู", "region": "Iraqi"}, |
| "Jordan": {"flag": "๐ฏ๐ด", "name_ar": "ุงูุฃุฑุฏู", "region": "Levantine"}, |
| "Kuwait": {"flag": "๐ฐ๐ผ", "name_ar": "ุงููููุช", "region": "Gulf"}, |
| "Lebanon": {"flag": "๐ฑ๐ง", "name_ar": "ูุจูุงู", "region": "Levantine"}, |
| "Libya": {"flag": "๐ฑ๐พ", "name_ar": "ููุจูุง", "region": "Maghrebi"}, |
| "Morocco": {"flag": "๐ฒ๐ฆ", "name_ar": "ุงูู
ุบุฑุจ", "region": "Maghrebi"}, |
| "Oman": {"flag": "๐ด๐ฒ", "name_ar": "ุนูู
ุงู", "region": "Gulf"}, |
| "Palestine": {"flag": "๐ต๐ธ", "name_ar": "ููุณุทูู", "region": "Levantine"}, |
| "Qatar": {"flag": "๐ถ๐ฆ", "name_ar": "ูุทุฑ", "region": "Gulf"}, |
| "Saudi_Arabia": {"flag": "๐ธ๐ฆ", "name_ar": "ุงูุณุนูุฏูุฉ", "region": "Gulf"}, |
| "Sudan": {"flag": "๐ธ๐ฉ", "name_ar": "ุงูุณูุฏุงู", "region": "Nilo-Saharan"}, |
| "Syria": {"flag": "๐ธ๐พ", "name_ar": "ุณูุฑูุง", "region": "Levantine"}, |
| "Tunisia": {"flag": "๐น๐ณ", "name_ar": "ุชููุณ", "region": "Maghrebi"}, |
| "UAE": {"flag": "๐ฆ๐ช", "name_ar": "ุงูุฅู
ุงุฑุงุช", "region": "Gulf"}, |
| "Yemen": {"flag": "๐พ๐ช", "name_ar": "ุงููู
ู", "region": "Peninsular"}, |
| "MSA": {"flag": "๐", "name_ar": "ุงููุตุญู", "region": "MSA"} |
| } |
|
|
| |
| @functools.lru_cache(maxsize=1) |
| def load_model_and_tokenizer(): |
| path_to_load = MODEL_ID |
| if os.path.exists(LOCAL_MODEL_PATH) and os.path.exists(os.path.join(LOCAL_MODEL_PATH, "config.json")): |
| path_to_load = LOCAL_MODEL_PATH |
|
|
| tokenizer = AutoTokenizer.from_pretrained(path_to_load) |
| model = AutoModelForSequenceClassification.from_pretrained(path_to_load) |
| |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") |
| model.to(device) |
| model.eval() |
|
|
| id2label = model.config.id2label |
| if not id2label or isinstance(list(id2label.keys())[0], str): |
| id2label = {int(k): str(v) for k, v in id2label.items()} |
|
|
| return tokenizer, model, id2label, device |
|
|
| |
| def preprocess_text(text: str) -> str: |
| if not text: |
| return "" |
| text = re.sub(r"[\u200b\u200c\u200d\u200e\u200f\ufeff\u00ad]", "", text) |
| return re.sub(r"\s+", " ", text).strip() |
|
|
| |
| @torch.inference_mode() |
| def predict_dialect(text: str) -> dict: |
| cleaned_text = preprocess_text(text) |
| if not cleaned_text: |
| return {"error": "Invalid or empty text input."} |
|
|
| tokenizer, model, id2label, device = load_model_and_tokenizer() |
|
|
| inputs = tokenizer( |
| cleaned_text, |
| return_tensors="pt", |
| truncation=True, |
| max_length=MAX_LENGTH |
| ) |
| inputs = {k: v.to(device) for k, v in inputs.items()} |
|
|
| outputs = model(**inputs) |
| probs = torch.softmax(outputs.logits, dim=-1).squeeze(0).cpu().numpy() |
|
|
| |
| sorted_indices = probs.argsort()[::-1] |
|
|
| all_predictions = [] |
| for idx in sorted_indices: |
| label = id2label[int(idx)] |
| details = COUNTRY_DETAILS.get(label, {"flag": "๐ณ๏ธ", "name_ar": label, "region": "Unknown"}) |
| all_predictions.append({ |
| "country": label, |
| "name_ar": details["name_ar"], |
| "flag": details["flag"], |
| "region": details["region"], |
| "confidence": round(float(probs[idx]), 4) |
| }) |
|
|
| top_prediction = all_predictions[0] |
|
|
| return { |
| "text": cleaned_text, |
| "prediction": top_prediction["country"], |
| "confidence": top_prediction["confidence"], |
| "details": top_prediction, |
| "probabilities": {p["country"]: p["confidence"] for p in all_predictions} |
| } |
|
|
| |
| examples = [ |
| ["ูุงุด ูุงูู ุงูุฒูู ููุงุฏ ุงูุจูุงุฏ ุบุงุจ ุนูููุง ูุงุฏ ุงูุฃูุงู
"], |
| ["ูุง ุฒูู
ุฉ ุดู ูุงูุญูู ุงููุงุถู ุดู ุนู
ุชุญูู ุงูุช"], |
| ["ุดูู ูุฐุง ุงูุญุฌู ู
ุง ูุตูุฑ ููุฌ ุงุจุฏ ูุงููู"], |
| ["ุงููุง ูุฏู ุงูููุงู
ุฏู ุญูู ุงูู ุชุณูู
ุงูุฏู ูุง ููุงู"], |
| ["ูุงููู ูุง ุฎูู ูุงูู
ุทุนู
ุฃููู ุทูุจ ุจุฒุงู ุชุจุงุฑู ุงููู"], |
| ["ุงูู ูุงููู ููุงู
ู ุตุญ ูุงูุบุงูู ู
ุง ูุตุฑุช ุฑุจู ูุญูุธู"], |
| ["ูููู ุญุจูุจู ุดูููู ุงูููู
ุนุณุงู ุทูุจ"], |
| ["ูุงุฐู ุงูุณุงููุฉ ู
ุง ุชููุน ุฎูุงุต ูุงุฒู
ูููู ุญู ุณุฑูุน"], |
| ["ููุงูุฉ ุชุณููู
ุนู ู
ุตุงุฏุฑ ุฅูุฑุงููุฉ: ุฏูู ุงููุฌุงุฑูู ูู ุฌุฒูุฑุฉ ูุดู
ุณุจุจู ุงูุชุตุฏู ูุฃูุฏุงู ู
ุนุงุฏูุฉ ุนูุฏ ู
ุฏุฎู ู
ุถูู ูุฑู
ุฒ"], |
| ] |
|
|
| |
| demo = gr.Interface( |
| fn=predict_dialect, |
| inputs=gr.Textbox(lines=3, placeholder="ุฃุฏุฎู ุงููุต ุงูุนุฑุจู ููุง...", label="Input Text"), |
| outputs=gr.JSON(label="API Response"), |
| examples=examples, |
| cache_examples=False, |
| title="Arabic Dialect Classifier", |
| api_name="predict" |
| ) |
|
|
| if __name__ == "__main__": |
| demo.launch() |