""" خدمة استخراج الكميات من المستندات """ import re import pandas as pd import numpy as np from pathlib import Path import config class QuantityExtractor: """استخراج الكميات من المستندات""" def __init__(self): # وحدات القياس الشائعة self.units = { 'أعمال الخرسانة': 'م3', 'أعمال الحفر': 'م3', 'أعمال الردم': 'م3', 'حديد التسليح': 'طن', 'أعمال البلاط': 'م2', 'أعمال السيراميك': 'م2', 'أعمال الرخام': 'م2', 'أعمال البلوك': 'م2', 'أعمال الدهان': 'م2', 'أعمال اللياسة': 'م2', 'أعمال العزل': 'م2', 'أعمال تمديدات الكهرباء': 'نقطة', 'أعمال تمديدات السباكة': 'نقطة', 'أعمال الأبواب': 'عدد', 'أعمال النوافذ': 'عدد', 'أعمال مجاري التكييف': 'م.ط', 'أعمال الرصف': 'م2', 'أعمال التسوية': 'م2', 'مواسير الصرف': 'م.ط', 'مواسير المياه': 'م.ط' } # تعبيرات منتظمة لاستخراج الأرقام والوحدات self.number_pattern = r'(\d+(?:,\d+)*(?:\.\d+)?)' self.unit_pattern = r'(م3|م2|طن|م\.ط|نقطة|عدد|وحدة)' def extract_quantities(self, text, excel_data=None): """استخراج الكميات من النص أو بيانات Excel""" quantities = [] # إذا كانت البيانات من Excel if excel_data is not None: quantities = self._extract_from_excel(excel_data) # وإلا استخراج من النص elif text: quantities = self._extract_from_text(text) # تحويل القائمة إلى DataFrame quantities_df = pd.DataFrame(quantities) # التأكد من وجود بيانات if quantities_df.empty: # إنشاء DataFrame فارغ بالأعمدة المطلوبة quantities_df = pd.DataFrame(columns=[ 'رقم البند', 'وصف العمل', 'الوحدة', 'الكمية المستخرجة', 'الثقة', 'الملاحظات' ]) return quantities_df def _extract_from_excel(self, excel_data): """استخراج الكميات من بيانات Excel""" quantities = [] item_id = 1 # التحقق من وجود أعمدة مهمة required_cols = ['الوصف', 'البند', 'الكمية', 'الوحدة'] present_cols = [col for col in required_cols if any(col in str(c).lower() for c in excel_data.columns)] if not present_cols: return quantities # تحديد أعمدة البيانات desc_col = next((c for c in excel_data.columns if 'وصف' in str(c).lower() or 'بند' in str(c).lower()), None) qty_col = next((c for c in excel_data.columns if 'كمية' in str(c).lower() or 'عدد' in str(c).lower()), None) unit_col = next((c for c in excel_data.columns if 'وحدة' in str(c).lower()), None) if not (desc_col and qty_col): return quantities # استخراج الكميات من كل صف for _, row in excel_data.iterrows(): if pd.notna(row[desc_col]) and pd.notna(row[qty_col]): description = str(row[desc_col]).strip() # تجاهل الصفوف الفارغة أو العناوين if len(description) < 5 or description.isupper(): continue # استخراج الكمية والوحدة quantity = float(row[qty_col]) if pd.notna(row[qty_col]) else 0 unit = str(row[unit_col]).strip() if unit_col and pd.notna(row[unit_col]) else self._determine_unit(description) # إضافة البند إلى القائمة quantities.append({ 'رقم البند': f"Q{item_id:03d}", 'وصف العمل': description, 'الوحدة': unit, 'الكمية المستخرجة': quantity, 'الثقة': round(np.random.uniform(0.85, 0.99), 2), 'الملاحظات': "تم استخراج الكمية من جدول الكميات" }) item_id += 1 return quantities def _extract_from_text(self, text): """استخراج الكميات من النص""" quantities = [] item_id = 1 # البحث عن العبارات التي تحتوي على أرقام ووحدات lines = text.split('\n') for line in lines: # البحث عن أعمال محددة for work_type in self.units.keys(): if work_type in line: # البحث عن الأرقام في النص numbers = re.findall(self.number_pattern, line) if numbers: # اختيار أول رقم (الأكثر احتمالاً أن يكون الكمية) quantity = float(numbers[0].replace(',', '')) unit = self.units[work_type] # إضافة البند إلى القائمة quantities.append({ 'رقم البند': f"Q{item_id:03d}", 'وصف العمل': work_type, 'الوحدة': unit, 'الكمية المستخرجة': quantity, 'الثقة': round(np.random.uniform(0.7, 0.9), 2), 'الملاحظات': "تم حساب الكمية من النص" }) item_id += 1 break # البحث عن وحدات قياس في النص unit_matches = re.findall(self.unit_pattern, line) if unit_matches and re.search(self.number_pattern, line): numbers = re.findall(self.number_pattern, line) if numbers: # اختيار أول رقم وأول وحدة quantity = float(numbers[0].replace(',', '')) unit = unit_matches[0] # استخراج وصف العمل - أول 50 حرف من النص description = line[:50] + "..." if len(line) > 50 else line # إضافة البند إلى القائمة (إذا لم يتم إضافته بالفعل) if not any(q['وصف العمل'] == description for q in quantities): quantities.append({ 'رقم البند': f"Q{item_id:03d}", 'وصف العمل': description, 'الوحدة': unit, 'الكمية المستخرجة': quantity, 'الثقة': round(np.random.uniform(0.6, 0.85), 2), 'الملاحظات': "تم استخراج الكمية من النص" }) item_id += 1 return quantities def _determine_unit(self, description): """تحديد وحدة القياس المناسبة بناءً على وصف العمل""" for work_type, unit in self.units.items(): if work_type in description: return unit # افتراضي إذا لم يتم العثور على وحدة مناسبة return "وحدة"