| |
| """Untitled18.ipynb |
| |
| Automatically generated by Colab. |
| |
| Original file is located at |
| https://colab.research.google.com/drive/1ebBGzEo4wbwwvReea_n0PRHdfYescKcs |
| """ |
|
|
| import os |
| import torch |
| from transformers import EncoderDecoderModel, AutoTokenizer |
| import re |
|
|
| |
| HF_REPO_ID = "bayan10/PuncAra-v1" |
|
|
| |
| device = None |
| test_model = None |
| test_tokenizer = None |
|
|
| def initialize_model(repo_id=HF_REPO_ID): |
| """ |
| تهيئة وإعداد كرت الشاشة وتحميل النموذج والـ Tokenizer من Hugging Face Hub. |
| يتم استدعاء هذه الدالة مرة واحدة فقط في بداية تشغيل المشروع. |
| """ |
| global device, test_model, test_tokenizer |
| print(f"Loading test model directly from Hugging Face Hub: {repo_id}") |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") |
| print(f"Loading test model to: {device}") |
|
|
| if device.type == "cuda" and not torch.cuda.is_available(): |
| print("Warning: CUDA device requested, but torch.cuda.is_available() is False. Model will be loaded to CPU.") |
| device = torch.device("cpu") |
|
|
| test_model = EncoderDecoderModel.from_pretrained(repo_id).to(device) |
| test_tokenizer = AutoTokenizer.from_pretrained(repo_id) |
|
|
| |
| test_model.config.decoder_start_token_id = test_tokenizer.cls_token_id |
| test_model.config.bos_token_id = test_tokenizer.cls_token_id |
| test_model.config.eos_token_id = test_tokenizer.sep_token_id |
| test_model.config.pad_token_id = test_tokenizer.pad_token_id |
| print("Model and Tokenizer loaded successfully!") |
|
|
| def predict_chunk(text_chunk): |
| """توليد التوقعات لعلامات الترقيم لقطعة نصية صغيرة لا تتعدى الـ 128 Token.""" |
| global device, test_model, test_tokenizer |
| if test_model is None or test_tokenizer is None: |
| raise RuntimeError("الموديل لم يتم تهيئته بعد. يرجى استدعاء initialize_model() أولاً.") |
|
|
| |
| text_chunk = arabic_preprocessing(text_chunk) |
|
|
| inputs = test_tokenizer(text_chunk, return_tensors="pt", padding=True, truncation=True, max_length=128).to(device) |
|
|
| outputs = test_model.generate( |
| inputs.input_ids, |
| attention_mask=inputs.attention_mask, |
| decoder_start_token_id=test_tokenizer.cls_token_id, |
| bos_token_id=test_tokenizer.cls_token_id, |
| eos_token_id=test_tokenizer.sep_token_id, |
| pad_token_id=test_tokenizer.pad_token_id, |
| max_length=128, |
| num_beams=3, |
| repetition_penalty=1.2, |
| length_penalty=1.0, |
| early_stopping=True, |
| do_sample=False |
| ) |
| return test_tokenizer.decode(outputs[0], skip_special_tokens=True) |
|
|
| def arabic_preprocessing(text): |
| """حذف الحركات التشكيلية لتوحيد المدخلات وتسهيل عمل الموديل.""" |
| arabic_diacritics = re.compile(r'[\u064B-\u0652]') |
| return re.sub(arabic_diacritics, '', text).strip() |
|
|
| def arabic_postprocessing(text): |
| """ |
| التنظيف والتحسين المطبعي وعلاج مشاكل دمج النصوص وعلامات الترقيم الزائدة. |
| """ |
| if not text: |
| return text |
|
|
| |
| text = re.sub(r'(?<=\d),(?=\d)', '٪TEMP_COMMA٪', text) |
| text = re.sub(r'(?<=\d):(?=\d)', '٪TEMP_COLON٪', text) |
|
|
| |
| text = text.replace(',', '،').replace(';', '؛').replace('?', '؟') |
|
|
| |
| text = re.sub(r'\(\s+', '(', text) |
| text = re.sub(r'\s+\)', ')', text) |
| text = re.sub(r'\[\s+', '[', text) |
| text = re.sub(r'\s+\]', ']', text) |
| text = re.sub(r'«\s+', '«', text) |
| text = re.sub(r'\s+»', '»', text) |
|
|
| |
| text = re.sub(r'([،؛:!؟])\1+', r'\1', text) |
| text = re.sub(r'\.{4,}', '...', text) |
|
|
| |
| text = re.sub(r'[،؛:]+([.!؟])', r'\1', text) |
| text = re.sub(r'،؛|؛،', '؛', text) |
| text = re.sub(r'([!؟])\.', r'\1', text) |
|
|
| |
| text = re.sub(r'^[،؛:!؟. \t]+', '', text) |
|
|
| |
| text = re.sub(r'([،؛:!؟.])(?=\S)', r'\1 ', text) |
|
|
| |
| text = text.replace('٪TEMP_COMMA٪', ',').replace('٪TEMP_COLON٪', ':') |
|
|
| |
| text = re.sub(r'\s+([،؛:!؟.])', r'\1', text) |
|
|
| |
| text = re.sub(r'[ \t]+', ' ', text).strip() |
| return text |
|
|
| def fix_punctuation(text): |
| """معالجة الفقرة الواحدة الطويلة عبر تقسيمها لقطع غير متداخلة لمنع التكرار.""" |
| words = text.split() |
| total_words = len(words) |
|
|
| |
| window_size = 50 |
| stride = 50 |
|
|
| if total_words <= window_size: |
| result = predict_chunk(text) |
| else: |
| segments_output = [] |
|
|
| for i in range(0, total_words, stride): |
| chunk_words = words[i : i + window_size] |
| chunk_text = " ".join(chunk_words) |
|
|
| if not chunk_text.strip(): |
| continue |
|
|
| processed_segment = predict_chunk(chunk_text).strip() |
|
|
| |
| is_last_segment = (i + window_size) >= total_words |
| if not is_last_segment: |
| punctuation_marks = ".?!،؛:؟!" |
| if processed_segment and processed_segment[-1] in punctuation_marks: |
| |
| processed_segment = processed_segment[:-1] |
|
|
| segments_output.append(processed_segment) |
|
|
| result = " ".join(segments_output) |
|
|
| |
| result = re.sub(r'\s+', ' ', result).strip() |
| return result |
|
|
| def process_full_document(text): |
| if not text: |
| return text |
|
|
| |
| paragraphs = [p.strip() for p in text.split('\n') if p.strip()] |
| processed_paragraphs = [] |
|
|
| for paragraph in paragraphs: |
| |
| punctuated_paragraph = fix_punctuation(paragraph) |
| cleaned_paragraph = arabic_postprocessing(punctuated_paragraph) |
| processed_paragraphs.append(cleaned_paragraph) |
|
|
| |
| return "\n\n".join(processed_paragraphs) |