EGYADMIN commited on
Commit
75eb61b
·
verified ·
1 Parent(s): 28a8e3d

Update modules/ai_assistant/ai_app.py

Browse files
Files changed (1) hide show
  1. modules/ai_assistant/ai_app.py +912 -379
modules/ai_assistant/ai_app.py CHANGED
@@ -1,419 +1,952 @@
1
- import streamlit as st
2
- import pandas as pd
3
- import numpy as np
4
- import matplotlib.pyplot as plt
5
- import plotly.express as px
6
- import plotly.graph_objects as go
7
- from datetime import datetime
8
- import time
9
- import io
10
- import os
11
- import json
12
- import base64
13
- from pathlib import Path
14
-
15
- # استيراد محلل المستندات
16
- from .document_analyzer import AIDocumentAnalyzer, DocumentParser
17
-
18
- # استيراد وحدة تكامل البيانات
19
- from .data_integration import DataAIIntegration
20
-
21
- class AIAssistantApp:
22
- """وحدة الذكاء الاصطناعي"""
23
 
24
- def __init__(self):
25
- """تهيئة وحدة الذكاء الاصطناعي"""
 
 
 
 
 
 
 
 
 
 
26
 
27
- # تهيئة حالة الجلسة
28
- if 'chat_history' not in st.session_state:
29
- st.session_state.chat_history = [
30
- {
31
- 'role': 'assistant',
32
- 'content': 'مرحباً! أنا مساعدك الذكي لإدارة المناقصات. كيف يمكنني مساعدتك اليوم؟'
33
- }
34
- ]
35
 
36
- if 'document_summaries' not in st.session_state:
37
- st.session_state.document_summaries = [
38
- {
39
- 'id': 1,
40
- 'title': 'كراسة الشروط والمواصفات - مشروع إنشاء مبنى إداري',
41
- 'date': '2024-03-15',
42
- 'summary': 'تتضمن كراسة الشروط والمواصفات لمشروع إنشاء مبنى إداري متطلبات المشروع وشروط التنفيذ والمواصفات الفنية للأعمال المطلوبة. يتكون المبنى من 5 طوابق بمساحة إجمالية 5000 متر مربع. تشمل الأعمال الأساسية: الأعمال الإنشائية، الأعمال المعمارية، الأعمال الكهربائية، الأعمال الميكانيكية، وأعمال التشطيبات.',
43
- 'key_points': [
44
- 'مدة التنفيذ: 18 شهراً',
45
- 'قيمة الضمان الابتدائي: 2% من قيمة العطاء',
46
- 'قيمة الضمان النهائي: 5% من قيمة العقد',
47
- 'غرامة التأخير: 1% من قيمة العقد عن كل أسبوع تأخير بحد أقصى 10%',
48
- 'شروط الدفع: دفعات شهرية حسب نسبة الإنجاز'
49
- ],
50
- 'entities': {
51
- 'الجهة المالكة': 'وزارة المالية',
52
- 'موقع المشروع': 'الرياض - حي العليا',
53
- 'رقم المناقصة': 'T-2024-001',
54
- 'تاريخ الطرح': '2024-03-01',
55
- 'تاريخ الإقفال': '2024-04-15'
56
- }
57
- },
58
- {
59
- 'id': 2,
60
- 'title': 'جدول الكميات - مشروع تطوير شبكة طرق',
61
- 'date': '2024-03-20',
62
- 'summary': 'يتضمن جدول الكميات لمشروع تطوير شبكة طرق تفاصيل الأعمال المطلوبة والكميات التقديرية. يشمل المشروع إنشاء طرق جديدة بطول 15 كم وتطوير طرق قائمة بطول 10 كم، بالإضافة إلى إنشاء 3 جسور و5 أنفاق.',
63
- 'key_points': [
64
- 'إجمالي أعمال الحفر: 250,000 م3',
65
- 'إجمالي أعمال الردم: 180,000 م3',
66
- 'إجمالي أعمال الخرسانة: 45,000 م3',
67
- 'إجمالي أعمال الأسفلت: 120,000 م2',
68
- 'إجمالي أعمال الإنارة: 500 عمود إنارة'
69
- ],
70
- 'entities': {
71
- 'الجهة المالكة': 'وزارة النقل',
72
- 'موقع المشروع': 'جدة',
73
- 'رقم المناقصة': 'T-2024-002',
74
- 'تاريخ الطرح': '2024-03-10',
75
- 'تاريخ الإقفال': '2024-04-20'
76
- }
77
- },
78
- {
79
- 'id': 3,
80
- 'title': 'المواصفات الفنية - مشروع بناء مدرسة',
81
- 'date': '2024-03-25',
82
- 'summary': 'تتضمن المواصفات الفنية لمشروع بناء مدرسة تفاصيل المتطلبات الفنية للمشروع. تتكون المدرسة من 3 طوابق بمساحة إجمالية 3000 متر مربع، وتشمل 20 فصلاً دراسياً، ومختبرات علوم، وقاعة متعددة الأغراض، ومكتبة، وغرف إدارية.',
83
- 'key_points': [
84
- 'نوع الهيكل: خرساني مسلح',
85
- 'نظام التكييف: نظام مركزي',
86
- 'نظام الإنارة: LED موفر للطاقة',
87
- 'نظام مكافحة الحريق: نظام رش آلي',
88
- 'متطلبات خاصة: نظام طاقة شمسية لتوفير 30% من احتياجات الطاقة'
89
- ],
90
- 'entities': {
91
- 'الجهة المالكة': 'وزارة التعليم',
92
- 'موقع المشروع': 'الدمام',
93
- 'رقم المناقصة': 'T-2024-003',
94
- 'تاريخ الطرح': '2024-03-15',
95
- 'تاريخ الإقفال': '2024-04-25'
96
- }
97
- }
98
- ]
99
-
100
- if 'ai_models' not in st.session_state:
101
- st.session_state.ai_models = [
102
- {
103
- 'id': 1,
104
- 'name': 'نموذج تحليل المستندات',
105
- 'description': 'نموذج ذكاء اصطناعي لتحليل مستندات المناقصات واستخراج المعلومات الرئيسية منها.',
106
- 'type': 'معالجة اللغة الطبيعية',
107
- 'accuracy': 92,
108
- 'last_updated': '2024-03-01'
109
- },
110
- {
111
- 'id': 2,
112
- 'name': 'نموذج تقدير التكاليف',
113
- 'description': 'نموذج ذكاء اصطناعي لتقدير تكاليف المشاريع بناءً على بيانات المشاريع السابقة.',
114
- 'type': 'تعلم آلي',
115
- 'accuracy': 85,
116
- 'last_updated': '2024-02-15'
117
- },
118
- {
119
- 'id': 3,
120
- 'name': 'نموذج تحليل المخاطر',
121
- 'description': 'نموذج ذكاء اصطناعي لتحليل المخاطر المحتملة للمشاريع وتقديم توصيات للتخفيف منها.',
122
- 'type': 'تعلم آلي',
123
- 'accuracy': 88,
124
- 'last_updated': '2024-02-20'
125
- },
126
- {
127
- 'id': 4,
128
- 'name': 'نموذج تحليل المنافسين',
129
- 'description': 'نموذج ذكاء اصطناعي لتحليل المنافسين وتقديم توصيات لزيادة فرص الفوز بالمناقصات.',
130
- 'type': 'تعلم آلي',
131
- 'accuracy': 80,
132
- 'last_updated': '2024-02-10'
133
- },
134
- {
135
- 'id': 5,
136
- 'name': 'نموذج تحليل ملفات DWG',
137
- 'description': 'نموذج ذكاء اصطناعي لتحليل ملفات DWG واستخراج المعلومات الرئيسية منها.',
138
- 'type': 'رؤية حاسوبية',
139
- 'accuracy': 90,
140
- 'last_updated': '2024-03-10'
141
  }
142
- ]
143
-
144
- # تهيئة متغير السمة في حالة الجلسة إذا لم يكن موجوداً
145
- if 'theme' not in st.session_state:
146
- st.session_state.theme = 'light'
147
-
148
- # تهيئة متغير استيراد البنود من تحليل المستندات
149
- if 'imported_items' not in st.session_state:
150
- st.session_state.imported_items = []
151
-
152
- # تهيئة محلل المستندات
153
- self.document_analyzer = AIDocumentAnalyzer()
154
-
155
- # تهيئة وحدة تكامل البيانات
156
- self.data_integration = DataAIIntegration()
157
-
158
- # تكامل وحدة تحليل البيانات مع وحدة الذكاء الاصطناعي
159
- self.data_integration.integrate_with_ai_assistant(self)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
 
161
- def run(self):
162
- """
163
- تشغيل وحدة الذكاء الاصطناعي
164
 
165
- هذه الدالة هي نقطة الدخول الرئيسية لوحدة الذكاء الاصطناعي.
166
- تقوم بتهيئة واجهة المستخدم وعرض الوظائف المختلفة للذكاء الاصطناعي.
167
- """
168
- try:
169
- # تم إزالة set_page_config لتجنب التعارض مع app.py
170
-
171
- # تطبيق التنسيق المخصص
172
- st.markdown("""
173
- <style>
174
- .module-title {
175
- color: #2c3e50;
176
- text-align: center;
177
- font-size: 2.5rem;
178
- margin-bottom: 1rem;
179
- padding-bottom: 1rem;
180
- border-bottom: 2px solid #3498db;
181
- }
182
- .stTabs [data-baseweb="tab-list"] {
183
- gap: 10px;
184
- }
185
- .stTabs [data-baseweb="tab"] {
186
- height: 50px;
187
- white-space: pre-wrap;
188
- background-color: #f8f9fa;
189
- border-radius: 4px 4px 0px 0px;
190
- gap: 1px;
191
- padding-top: 10px;
192
- padding-bottom: 10px;
193
- }
194
- </style>
195
- """, unsafe_allow_html=True)
196
 
197
- # عرض عنوان الوحدة
198
- st.markdown('<h1 class="module-title">وحدة الذكاء الاصطناعي</h1>', unsafe_allow_html=True)
199
 
200
- # إضافة شريط جانبي يحتوي على معلومات المستخدم وإعدادات الذكاء الاصطناعي
201
- with st.sidebar:
202
- st.markdown("### إعدادات الذكاء الاصطناعي")
203
-
204
- # اختيار نموذج الذكاء الاصطناعي
205
- ai_model = st.selectbox(
206
- "اختر نموذج الذكاء الاصطناعي",
207
- options=["OpenAI GPT-4", "Claude 3 Opus", "Gemini Pro", "نموذج محلي"],
208
- index=0,
209
- key="ai_model_selector"
210
  )
211
 
212
- # إعدادات النموذج
213
- st.markdown("#### إعدادات النموذج")
214
-
215
- temperature = st.slider(
216
- "درجة الإبداعية",
217
- min_value=0.0,
218
- max_value=1.0,
219
- value=0.7,
220
- step=0.1,
221
- key="temperature_slider"
222
  )
223
-
224
- max_tokens = st.slider(
225
- "الحد الأقصى للكلمات",
 
226
  min_value=100,
227
- max_value=4000,
228
- value=2000,
229
  step=100,
230
- key="max_tokens_slider"
231
  )
232
 
233
- # إضافة زر لتحليل ملفات DWG
234
- st.markdown("#### تحليل ملفات DWG")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
 
236
- dwg_file = st.file_uploader(
237
- "ارفع ملف DWG للتحليل",
238
- type=["dwg"],
239
- key="dwg_file_uploader"
240
  )
241
 
242
- if dwg_file is not None:
243
- if st.button("تحليل ملف DWG", key="analyze_dwg_button"):
244
- st.info("جاري تحليل ملف DWG...")
245
- # هنا يتم استدعاء دالة تحليل ملف DWG
246
- st.success("تم تحليل ملف DWG بنجاح!")
247
 
248
- # إضافة معلومات عن التكامل مع بيئة هجين فيس
249
- st.markdown("#### التكامل مع بيئة هجين فيس")
250
- st.markdown("""
251
- تم تكامل وحدة الذكاء الاصطناعي مع بيئة هجين فيس بنجاح.
252
- يمكنك الآن استخدام جميع ميزات الذكاء الاصطناعي في بيئة آمنة ومتكاملة.
253
- """)
254
-
255
- # إنشاء تبويبات لعرض الوظائف المختلفة للذكاء الاصطناعي
256
- tabs = st.tabs([
257
- "المساعد الذكي",
258
- "تحليل المستندات",
259
- "تقدير التكاليف",
260
- "تحليل المخاطر",
261
- "نماذج الذكاء الاصطناعي"
262
- ])
263
-
264
- # تبويب المساعد الذكي
265
- with tabs[0]:
266
- self._render_assistant_tab()
267
-
268
- # تبويب تحليل المستندات
269
- with tabs[1]:
270
- self._render_document_analysis_tab()
271
-
272
- # تبويب تقدير التكاليف
273
- with tabs[2]:
274
- self._render_cost_estimation_tab()
275
-
276
- # تبويب تحليل المخاطر
277
- with tabs[3]:
278
- self._render_risk_analysis_tab()
279
-
280
- # تبويب نماذج الذكاء الاصطناعي
281
- with tabs[4]:
282
- self._render_ai_models_tab()
283
-
284
- # عرض حقوق النشر
285
- st.markdown("---")
286
- st.markdown('<div style="text-align: center;">© 2025 جميع الحقوق محفوظة</div>', unsafe_allow_html=True)
287
-
288
- except Exception as e:
289
- st.error(f"حدث خطأ أثناء تشغيل وحدة الذكاء الاصطناعي: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
 
291
- def _render_assistant_tab(self):
292
- """عرض تبويب المساعد الذكي"""
293
-
294
- st.markdown("### المساعد الذكي")
295
-
296
- st.markdown("""
297
- المساعد الذكي يساعدك في:
298
- - تحليل المناقصات والعقود
299
- - تقدير التكاليف والمخاطر
300
- - الإجابة على الأسئلة المتعلقة بالمناقصات
301
- - تقديم توصيات لزيادة فرص الفوز بالمناقصات
302
- """)
303
-
304
- # عرض محادثة المساعد الذكي
305
- chat_container = st.container()
306
-
307
- with chat_container:
308
- for message in st.session_state.chat_history:
309
- if message['role'] == 'user':
310
- st.markdown(f'<div style="background-color: #e6f7ff; padding: 10px; border-radius: 10px; margin-bottom: 10px;"><strong>أنت:</strong> {message["content"]}</div>', unsafe_allow_html=True)
311
- else:
312
- st.markdown(f'<div style="background-color: #f0f0f0; padding: 10px; border-radius: 10px; margin-bottom: 10px;"><strong>المساعد:</strong> {message["content"]}</div>', unsafe_allow_html=True)
313
-
314
- # إدخال رسالة جديدة
315
- user_input = st.text_area("اكتب رسالتك هنا", key="user_input_area")
316
 
317
- if st.button("إرسال", key="send_message_button"):
318
- if user_input:
319
- # إضافة رسالة المستخدم إلى المحادثة
320
- st.session_state.chat_history.append({
321
- 'role': 'user',
322
- 'content': user_input
323
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
 
325
- # إضافة رد المساعد الذكي
326
- response = self._generate_ai_response(user_input)
327
- st.session_state.chat_history.append({
328
- 'role': 'assistant',
329
- 'content': response
330
- })
331
 
332
- # إعادة تحميل الصفحة لعرض الرسائل الجديدة
333
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
 
335
- def _render_document_analysis_tab(self):
336
- """عرض تبويب تحليل المستندات"""
337
-
338
- st.markdown("### تحليل المستندات")
339
-
340
- st.markdown("""
341
- يمكنك تحليل المستندات التالية:
342
- - كراسات الشروط والمواصفات
343
- - العقود
344
- - جداول الكميات
345
- - المواصفات الفنية
346
- - ملفات DWG
347
- """)
348
-
349
- # رفع مستند للتحليل
350
- uploaded_file = st.file_uploader("ارفع مستنداً للتحليل", type=["pdf", "docx", "txt", "dwg"], key="document_analysis_uploader")
351
 
352
- if uploaded_file is not None:
353
- # عرض معلومات الملف
354
- file_details = {
355
- "اسم الملف": uploaded_file.name,
356
- "نوع الملف": uploaded_file.type,
357
- "حجم الملف": f"{uploaded_file.size / 1024:.2f} كيلوبايت"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  }
359
 
360
- st.json(file_details)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
 
362
- # اختيار نوع التحليل
363
- analysis_type = st.selectbox(
364
- "اختر نوع التحليل",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  options=[
366
- "تحليل شامل",
367
- "استخراج البنود الرئيسية",
368
- "تحليل الشروط والمتطلبات",
369
- "تحليل المخاطر",
370
- "تحليل التكاليف"
371
  ],
372
- key="analysis_type_selector"
373
  )
374
 
375
- # اختيار نموذج الذكاء الاصطناعي
376
- ai_model = st.selectbox(
377
- "اختر نموذج الذكاء الاصطناعي للتحليل",
378
- options=["OpenAI GPT-4", "Claude 3 Opus", "Gemini Pro", "نموذج محلي"],
379
- key="analysis_model_selector"
380
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
 
382
- # زر تحليل المستند
383
- if st.button("تحليل المستند", key="analyze_document_button"):
384
- with st.spinner("جاري تحليل المستند..."):
385
- # محاكاة عملية التحليل
386
  progress_bar = st.progress(0)
387
  for i in range(100):
388
- time.sleep(0.01)
389
  progress_bar.progress(i + 1)
390
 
391
- # عرض نتائج التحليل
392
- st.success("تم تحليل المستند بنجاح!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
 
394
- # إنشاء نتائج تحليل افتراضية
395
- analysis_results = {
396
- "عنوان المستند": "كراسة الشروط والمواصفات - مشروع إنشاء مبنى إداري",
397
- "نوع المستند": "كراسة شروط ومواصفات",
398
- "تاريخ المستند": "2024-03-15",
399
- "الجهة المصدرة": "وزارة الأشغال العامة",
400
- "ملخص المستند": "كراسة شروط ومواصفات لمشروع إنشاء مبنى إداري جديد بمساحة 5000 متر مربع",
401
- "الكلمات المفتاحية": ["مبنى إداري", "إنشاءات", "مناقصة حكومية", "شروط ومواصفات"],
402
- "البنود الرئيسية": [
403
- "مواصفات الأعمال الإنشائية",
404
- "مواصفات الأعمال المعمارية",
405
- "مواصفات الأعمال الكهربائية",
406
- "مواصفات الأعمال الميكانيكية",
407
- "شروط المناقصة والترسية"
408
- ],
409
- "المتطلبات الفنية": [
410
- "خبرة لا تقل عن 10 سنوات في المشاريع المماثلة",
411
- "سابقة أعمال لمشاريع مماثلة بقيمة 50 مليون ريال",
412
- "كادر فني مؤهل لا يقل عن 50 ��هندس وفني",
413
- "معدات وأدوات كافية لتنفيذ المشروع"
414
- ],
415
- "الميزانية التقديرية": 35000000
416
- }
 
 
 
 
 
 
 
 
 
417
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
 
419
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def _render_cost_estimation_tab(self):
2
+ """عرض تبويب تقدير التكاليف باستخدام نماذج هجين فيس"""
3
+
4
+ st.markdown("### تقدير التكاليف")
5
+
6
+ st.markdown("""
7
+ يمكنك استخدام هذه الأداة لتقدير تكاليف المشاريع باستخدام نماذج الذكاء الاصطناعي المتقدمة من بيئة هجين فيس.
8
+ الأداة تدعم تحليل الملفات التالية:
9
+ - ملفات PDF (كراسات الشروط، المواصفات الفنية)
10
+ - ملفات DWG (المخططات الهندسية)
11
+ - ملفات Excel (جداول الكميات، التكاليف)
12
+ - ملفات Word (العقود، المستندات)
13
+ - ملفات النصوص TXT
14
+ - ملفات الصور (PNG, JPG) للمخططات والرسومات
15
+ """)
 
 
 
 
 
 
 
16
 
17
+ # إنشاء تبويبات فرعية
18
+ cost_tabs = st.tabs([
19
+ "تحميل الملفات",
20
+ "تقدير التكاليف",
21
+ "تحليل البنود",
22
+ "المقارنة مع السوق",
23
+ "التقارير"
24
+ ])
25
+
26
+ # تبويب تحميل الملفات
27
+ with cost_tabs[0]:
28
+ st.markdown("#### تحميل ملفات المشروع")
29
 
30
+ # دعم تحميل أنواع متعددة من الملفات
31
+ uploaded_files = st.file_uploader(
32
+ "قم بتحميل ملفات المشروع (يمكن اختيار أكثر من ملف)",
33
+ type=["pdf", "dwg", "xlsx", "xls", "docx", "doc", "txt", "png", "jpg", "jpeg"],
34
+ accept_multiple_files=True,
35
+ key="cost_estimation_files"
36
+ )
 
37
 
38
+ if uploaded_files:
39
+ st.success(f"تم تحميل {len(uploaded_files)} ملفات بنجاح")
40
+
41
+ # عرض قائمة الملفات المحملة
42
+ st.markdown("#### الملفات المحملة:")
43
+ for i, file in enumerate(uploaded_files):
44
+ file_details = {
45
+ "اسم الملف": file.name,
46
+ "نوع الملف": file.type if file.type else "غير محدد",
47
+ "حجم الملف": f"{file.size / 1024:.2f} كيلوبايت"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  }
49
+
50
+ with st.expander(f"{i+1}. {file.name}"):
51
+ st.json(file_details)
52
+
53
+ # زر تحليل الملفات
54
+ if st.button("تحليل الملفات", key="analyze_cost_files_button"):
55
+ with st.spinner("جاري تحليل الملفات..."):
56
+ # محاكاة تقدم التحليل
57
+ progress_bar = st.progress(0)
58
+ for i in range(100):
59
+ time.sleep(0.02)
60
+ progress_bar.progress(i + 1)
61
+
62
+ st.success("تم تحليل الملفات بنجاح!")
63
+
64
+ # حفظ نتائج التحليل في حالة الجلسة
65
+ if 'analyzed_files' not in st.session_state:
66
+ st.session_state.analyzed_files = []
67
+
68
+ # إضافة الملفات المحللة إلى حالة الجلسة
69
+ for file in uploaded_files:
70
+ file_info = {
71
+ "name": file.name,
72
+ "type": file.type if file.type else self._detect_file_type(file.name),
73
+ "size": file.size,
74
+ "analyzed": True,
75
+ "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
76
+ }
77
+ st.session_state.analyzed_files.append(file_info)
78
+
79
+ # عرض رسالة تأكيد
80
+ st.markdown(f"**تم تحليل {len(uploaded_files)} ملفات بنجاح. يمكنك الآن الانتقال إلى تبويب 'تقدير التكاليف' للحصول على التقديرات.**")
81
 
82
+ # تبويب تقدير التكاليف
83
+ with cost_tabs[1]:
84
+ st.markdown("#### تقدير التكاليف باستخدام الذكاء الاصطناعي")
85
 
86
+ # التحقق من وجود ملفات محللة
87
+ if 'analyzed_files' in st.session_state and st.session_state.analyzed_files:
88
+ # اختيار نموذج الذكاء الاصطناعي
89
+ ai_model = st.radio(
90
+ "اختر نموذج الذكاء الاصطناعي:",
91
+ options=["ai (OpenAI)", "anthropic (Claude)"],
92
+ horizontal=True,
93
+ key="cost_ai_model_selector"
94
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
+ st.markdown("#### إعدادات التقدير")
 
97
 
98
+ # إعدادات المشروع
99
+ col1, col2 = st.columns(2)
100
+ with col1:
101
+ project_type = st.selectbox(
102
+ "نوع المشروع:",
103
+ options=["مبنى سكني", "مبنى تجاري", "مبنى حكومي", "بنية تحتية", "طرق", "جسور", "أنفاق", "أخرى"],
104
+ key="project_type_selector"
 
 
 
105
  )
106
 
107
+ project_location = st.selectbox(
108
+ "موقع المشروع:",
109
+ options=["الرياض", "جدة", "الدمام", "مكة", "المدينة", "تبوك", "أبها", "الخبر", "الطائف", "أخرى"],
110
+ key="project_location_selector"
 
 
 
 
 
 
111
  )
112
+
113
+ with col2:
114
+ project_size = st.number_input(
115
+ "حجم المشروع (متر مربع):",
116
  min_value=100,
117
+ max_value=1000000,
118
+ value=5000,
119
  step=100,
120
+ key="project_size_input"
121
  )
122
 
123
+ project_duration = st.number_input(
124
+ "مدة المشروع (شهر):",
125
+ min_value=1,
126
+ max_value=60,
127
+ value=12,
128
+ step=1,
129
+ key="project_duration_input"
130
+ )
131
+
132
+ # إعدادات متقدمة
133
+ with st.expander("إعدادات متقدمة"):
134
+ quality_level = st.select_slider(
135
+ "مستوى الجودة:",
136
+ options=["اقتصادي", "متوسط", "عالي", "ممتاز"],
137
+ value="متوسط",
138
+ key="quality_level_slider"
139
+ )
140
 
141
+ include_contingency = st.checkbox(
142
+ "تضمين احتياطي للطوارئ (10%)",
143
+ value=True,
144
+ key="include_contingency_checkbox"
145
  )
146
 
147
+ include_inflation = st.checkbox(
148
+ "تضمين معدل التضخم",
149
+ value=True,
150
+ key="include_inflation_checkbox"
151
+ )
152
 
153
+ if include_inflation:
154
+ inflation_rate = st.slider(
155
+ "معدل التضخم السنوي (%):",
156
+ min_value=1.0,
157
+ max_value=10.0,
158
+ value=3.5,
159
+ step=0.5,
160
+ key="inflation_rate_slider"
161
+ )
162
+
163
+ # زر تقدير التكاليف
164
+ if st.button("تقدير التكاليف", key="estimate_costs_button"):
165
+ with st.spinner(f"جاري تقدير التكاليف باستخدام نموذج {ai_model}..."):
166
+ # محاكاة استدعاء نموذج هجين فيس
167
+ try:
168
+ # هنا سيتم استدعاء النموذج المحدد من بيئة هجين فيس
169
+ # في التنفيذ الفعلي، سيتم استبدال هذا الكود بالاستدعاء الحقيقي للنموذج
170
+
171
+ # محاكاة تقدم العملية
172
+ progress_bar = st.progress(0)
173
+ for i in range(100):
174
+ time.sleep(0.02)
175
+ progress_bar.progress(i + 1)
176
+
177
+ # حساب التكلفة التقديرية (محاكاة)
178
+ base_cost_per_sqm = {
179
+ "مبنى سكني": 2500,
180
+ "مبنى تجاري": 3000,
181
+ "مبنى حكومي": 3500,
182
+ "بنية تحتية": 4000,
183
+ "طرق": 2000,
184
+ "جسور": 5000,
185
+ "أنفاق": 7000,
186
+ "أخرى": 3000
187
+ }
188
+
189
+ quality_factor = {
190
+ "اقتصادي": 0.8,
191
+ "متوسط": 1.0,
192
+ "عالي": 1.2,
193
+ "ممتاز": 1.5
194
+ }
195
+
196
+ location_factor = {
197
+ "الرياض": 1.1,
198
+ "جدة": 1.15,
199
+ "الدمام": 1.05,
200
+ "مكة": 1.2,
201
+ "المدينة": 1.1,
202
+ "تبوك": 1.0,
203
+ "أبها": 0.95,
204
+ "الخبر": 1.05,
205
+ "الطائف": 0.9,
206
+ "أخرى": 1.0
207
+ }
208
+
209
+ # حساب التكلفة الأساسية
210
+ base_cost = base_cost_per_sqm[project_type] * project_size * quality_factor[quality_level] * location_factor[project_location]
211
+
212
+ # إضافة احتياطي الطوارئ إذا تم اختياره
213
+ if include_contingency:
214
+ contingency_amount = base_cost * 0.1
215
+ else:
216
+ contingency_amount = 0
217
+
218
+ # إضافة التضخم إذا تم اختياره
219
+ if include_inflation:
220
+ inflation_amount = base_cost * (inflation_rate / 100) * (project_duration / 12)
221
+ else:
222
+ inflation_amount = 0
223
+
224
+ # حساب التكلفة الإجمالية
225
+ total_cost = base_cost + contingency_amount + inflation_amount
226
+
227
+ # عرض نتائج التقدير
228
+ st.success("تم تقدير التكاليف بنجاح!")
229
+
230
+ # عرض ملخص التكاليف
231
+ st.markdown("### ملخص تقدير التكاليف")
232
+
233
+ col1, col2 = st.columns(2)
234
+
235
+ with col1:
236
+ st.metric(
237
+ label="التكلفة الأساسية",
238
+ value=f"{base_cost:,.2f} ريال سعودي",
239
+ delta=f"{base_cost/project_size:,.2f} ريال/م²"
240
+ )
241
+
242
+ if include_contingency:
243
+ st.metric(
244
+ label="احتياطي الطوارئ (10%)",
245
+ value=f"{contingency_amount:,.2f} ريال سعودي"
246
+ )
247
+
248
+ with col2:
249
+ if include_inflation:
250
+ st.metric(
251
+ label=f"تكلفة التضخم ({inflation_rate}% سنوياً)",
252
+ value=f"{inflation_amount:,.2f} ريال سعودي"
253
+ )
254
+
255
+ st.metric(
256
+ label="التكلفة الإجمالية",
257
+ value=f"{total_cost:,.2f} ريال سعودي",
258
+ delta=f"{total_cost/project_size:,.2f} ريال/م²"
259
+ )
260
+
261
+ # عرض تفاصيل التكاليف
262
+ st.markdown("### تفاصيل التكاليف")
263
+
264
+ # إنشاء بيانات تفصيلية للتكاليف (محاكاة)
265
+ cost_breakdown = {
266
+ "الأعمال الإنشائية": total_cost * 0.35,
267
+ "الأعمال المعمارية": total_cost * 0.25,
268
+ "الأعمال الكهربائية": total_cost * 0.15,
269
+ "الأعمال الميكانيكية": total_cost * 0.12,
270
+ "أعمال الموقع والتجهيزات": total_cost * 0.08,
271
+ "أخرى": total_cost * 0.05
272
+ }
273
+
274
+ # عرض مخطط دائري للتكاليف
275
+ fig = px.pie(
276
+ values=list(cost_breakdown.values()),
277
+ names=list(cost_breakdown.keys()),
278
+ title="توزيع التكاليف حسب نوع العمل"
279
+ )
280
+ st.plotly_chart(fig, use_container_width=True)
281
+
282
+ # عرض جدول تفصيلي للتكاليف
283
+ cost_df = pd.DataFrame({
284
+ "نوع العمل": list(cost_breakdown.keys()),
285
+ "التكلفة (ريال سعودي)": list(cost_breakdown.values()),
286
+ "النسبة (%)": [v/total_cost*100 for v in cost_breakdown.values()]
287
+ })
288
+
289
+ st.dataframe(cost_df.style.format({
290
+ "التكلفة (ريال سعودي)": "{:,.2f}",
291
+ "النسبة (%)": "{:.2f}%"
292
+ }))
293
+
294
+ # إضافة زر لتصدير التقرير
295
+ col1, col2 = st.columns(2)
296
+ with col1:
297
+ st.download_button(
298
+ label="تصدير التقرير (PDF)",
299
+ data=b"تقرير تقدير التكاليف", # في التنفيذ الفعلي، سيتم إنشاء ملف PDF حقيقي
300
+ file_name=f"تقرير_تقدير_التكاليف_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf",
301
+ mime="application/pdf",
302
+ key="export_cost_report_pdf"
303
+ )
304
+
305
+ with col2:
306
+ st.download_button(
307
+ label="تصدير البيانات (Excel)",
308
+ data=b"بيانات تقدير التكاليف", # في التنفيذ الفعلي، سيتم إنشاء ملف Excel حقيقي
309
+ file_name=f"بيانات_تقدير_التكاليف_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx",
310
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
311
+ key="export_cost_data_excel"
312
+ )
313
+
314
+ except Exception as e:
315
+ st.error(f"حدث خطأ أثناء تقدير التكاليف: {str(e)}")
316
+ st.markdown("""
317
+ **ملاحظة**: قد يكون هناك تعارض بين حزم pydantic و anthropic.
318
+ إذا كنت تستخدم نموذج anthropic، تأكد من تثبيت إصدار متوافق من pydantic (أقل من 2.0.0)
319
+ أو استخدم إصدارًا محدثًا من anthropic يدعم pydantic 2.x.
320
+ """)
321
+ else:
322
+ st.info("الرجاء تحميل وتحليل ملفات المشروع أولاً من تبويب 'تحميل الملفات'.")
323
 
324
+ # تبويب تحليل البنود
325
+ with cost_tabs[2]:
326
+ st.markdown("#### تحليل بنود المشروع")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
 
328
+ # التحقق من وجود ملفات محللة
329
+ if 'analyzed_files' in st.session_state and st.session_state.analyzed_files:
330
+ # إنشاء بيانات افتراضية لبنود المشروع
331
+ if 'project_items' not in st.session_state:
332
+ st.session_state.project_items = [
333
+ {"id": 1, "code": "01-001", "description": "أعمال الحفر والردم", "unit": "م³", "quantity": 5000, "unit_price": 35, "total": 175000},
334
+ {"id": 2, "code": "01-002", "description": "أعمال الخرسانة العادية", "unit": "م³", "quantity": 1200, "unit_price": 450, "total": 540000},
335
+ {"id": 3, "code": "01-003", "description": "أعمال الخرسانة المسلحة", "unit": "م³", "quantity": 2500, "unit_price": 850, "total": 2125000},
336
+ {"id": 4, "code": "02-001", "description": "أعمال البلوك", "unit": "م²", "quantity": 3500, "unit_price": 120, "total": 420000},
337
+ {"id": 5, "code": "02-002", "description": "أعمال اللياسة", "unit": "م²", "quantity": 7000, "unit_price": 45, "total": 315000},
338
+ {"id": 6, "code": "02-003", "description": "أعمال البلاط", "unit": "م²", "quantity": 4500, "unit_price": 180, "total": 810000},
339
+ {"id": 7, "code": "03-001", "description": "أعمال التمديدات الكهربائية", "unit": "نقطة", "quantity": 350, "unit_price": 250, "total": 87500},
340
+ {"id": 8, "code": "03-002", "description": "أعمال الإنارة", "unit": "وحدة", "quantity": 200, "unit_price": 350, "total": 70000},
341
+ {"id": 9, "code": "04-001", "description": "أعمال التمديدات الصحية", "unit": "نقطة", "quantity": 120, "unit_price": 450, "total": 54000},
342
+ {"id": 10, "code": "04-002", "description": "أعمال التكييف", "unit": "وحدة", "quantity": 50, "unit_price": 3500, "total": 175000}
343
+ ]
344
+
345
+ # عرض جدول البنود
346
+ st.markdown("#### بنود المشروع")
347
+
348
+ # تحويل البنود إلى DataFrame
349
+ items_df = pd.DataFrame(st.session_state.project_items)
350
+
351
+ # عرض الجدول مع تنسيق
352
+ st.dataframe(
353
+ items_df.style.format({
354
+ "unit_price": "{:,.2f}",
355
+ "total": "{:,.2f}"
356
+ }),
357
+ use_container_width=True,
358
+ hide_index=True
359
+ )
360
+
361
+ # تحليل البنود
362
+ st.markdown("#### تحليل البنود")
363
+
364
+ col1, col2 = st.columns(2)
365
+
366
+ with col1:
367
+ # عرض إجمالي التكلفة
368
+ total_cost = sum(item["total"] for item in st.session_state.project_items)
369
+ st.metric(
370
+ label="إجمالي التكلفة",
371
+ value=f"{total_cost:,.2f} ريال سعودي"
372
+ )
373
+
374
+ # عرض عدد البنود
375
+ st.metric(
376
+ label="عدد البنود",
377
+ value=len(st.session_state.project_items)
378
+ )
379
+
380
+ with col2:
381
+ # عرض متوسط تكلفة البند
382
+ avg_item_cost = total_cost / len(st.session_state.project_items)
383
+ st.metric(
384
+ label="متوسط تكلفة البند",
385
+ value=f"{avg_item_cost:,.2f} ريال سعودي"
386
+ )
387
+
388
+ # عرض أعلى بند من حيث التكلفة
389
+ max_item = max(st.session_state.project_items, key=lambda x: x["total"])
390
+ st.metric(
391
+ label="أعلى بند من حيث التكلفة",
392
+ value=f"{max_item['total']:,.2f} ريال سعودي",
393
+ delta=max_item["description"]
394
+ )
395
+
396
+ # عرض مخطط شريطي للبنود حسب التكلفة
397
+ st.markdown("#### توزيع التكاليف حسب البنود")
398
+
399
+ # إنشاء DataFrame للمخطط
400
+ chart_df = pd.DataFrame({
401
+ "البند": [item["description"] for item in st.session_state.project_items],
402
+ "التكلفة": [item["total"] for item in st.session_state.project_items]
403
+ })
404
+
405
+ # ترتيب البيانات تنازلياً حسب التكلفة
406
+ chart_df = chart_df.sort_values("التكلفة", ascending=False)
407
+
408
+ # إنشاء المخطط الشريطي
409
+ fig = px.bar(
410
+ chart_df,
411
+ x="البند",
412
+ y="التكلفة",
413
+ title="توزيع التكاليف حسب البنود",
414
+ labels={"البند": "البند", "التكلفة": "التكلفة (ريال سعودي)"}
415
+ )
416
+
417
+ # تعديل المخطط
418
+ fig.update_layout(
419
+ xaxis_tickangle=-45,
420
+ yaxis=dict(title="التكلفة (ريال سعودي)")
421
+ )
422
+
423
+ # عرض المخطط
424
+ st.plotly_chart(fig, use_container_width=True)
425
+
426
+ # تحليل البنود حسب الفئة
427
+ st.markdown("#### تحليل البنود حسب الفئة")
428
+
429
+ # تصنيف البنود حسب الكود
430
+ categories = {}
431
+ for item in st.session_state.project_items:
432
+ category_code = item["code"].split("-")[0]
433
+ category_name = {
434
+ "01": "الأعمال الإنشائية",
435
+ "02": "الأعمال المعمارية",
436
+ "03": "الأعمال الكهربائية",
437
+ "04": "الأعمال الميكانيكية"
438
+ }.get(category_code, "أخرى")
439
 
440
+ if category_name not in categories:
441
+ categories[category_name] = 0
 
 
 
 
442
 
443
+ categories[category_name] += item["total"]
444
+
445
+ # إنشاء DataFrame للمخطط
446
+ category_df = pd.DataFrame({
447
+ "الفئة": list(categories.keys()),
448
+ "التكلفة": list(categories.values())
449
+ })
450
+
451
+ # إنشاء المخطط الدائري
452
+ fig = px.pie(
453
+ category_df,
454
+ values="التكلفة",
455
+ names="الفئة",
456
+ title="توزيع التكاليف حسب الفئة"
457
+ )
458
+
459
+ # عرض المخطط
460
+ st.plotly_chart(fig, use_container_width=True)
461
+ else:
462
+ st.info("الرجاء تحميل وتحليل ملفات المشروع أولاً من تبويب 'تحميل الملفات'.")
463
 
464
+ # تبويب المقارنة مع السوق
465
+ with cost_tabs[3]:
466
+ st.markdown("#### مقارنة التكاليف مع السوق")
 
 
 
 
 
 
 
 
 
 
 
 
 
467
 
468
+ # التحقق من وجود ملفات محللة
469
+ if 'analyzed_files' in st.session_state and st.session_state.analyzed_files:
470
+ # إنشاء بيانات افتراضية لأسعار السوق
471
+ market_prices = {
472
+ "الخرسانة المسلحة (م³)": {
473
+ "السعر المقدر": 850,
474
+ "متوسط السوق": 900,
475
+ "الحد الأدنى": 800,
476
+ "الحد الأقصى": 1000,
477
+ "الفرق (%)": -5.56
478
+ },
479
+ "البلوك (م²)": {
480
+ "السعر المقدر": 120,
481
+ "متوسط السوق": 115,
482
+ "الحد الأدنى": 100,
483
+ "الحد الأقصى": 130,
484
+ "الفرق (%)": 4.35
485
+ },
486
+ "اللياسة (م²)": {
487
+ "السعر المقدر": 45,
488
+ "متوسط السوق": 50,
489
+ "الحد الأدنى": 40,
490
+ "الحد الأقصى": 60,
491
+ "الفرق (%)": -10.00
492
+ },
493
+ "البلاط (م²)": {
494
+ "السعر المقدر": 180,
495
+ "متوسط السوق": 175,
496
+ "الحد الأدنى": 150,
497
+ "الحد الأقصى": 200,
498
+ "الفرق (%)": 2.86
499
+ },
500
+ "التمديدات الكهربائية (نقطة)": {
501
+ "السعر المقدر": 250,
502
+ "متوسط السوق": 275,
503
+ "الحد الأدنى": 225,
504
+ "الحد الأقصى": 325,
505
+ "الفرق (%)": -9.09
506
+ }
507
  }
508
 
509
+ # تحويل البيانات إلى DataFrame
510
+ market_df = pd.DataFrame(market_prices).T.reset_index()
511
+ market_df.columns = ["البند", "السعر المقدر", "متوسط السوق", "الحد الأدنى", "الحد الأقصى", "الفرق (%)"]
512
+
513
+ # عرض جدول المقارنة
514
+ st.markdown("#### مقارنة الأسعار مع السوق")
515
+ st.dataframe(
516
+ market_df.style.format({
517
+ "السعر المقدر": "{:,.2f}",
518
+ "متوسط السوق": "{:,.2f}",
519
+ "الحد الأدنى": "{:,.2f}",
520
+ "الحد الأقصى": "{:,.2f}",
521
+ "الفرق (%)": "{:+.2f}%"
522
+ }).background_gradient(
523
+ cmap="RdYlGn",
524
+ subset=["الفرق (%)"],
525
+ vmin=-15,
526
+ vmax=15
527
+ ),
528
+ use_container_width=True,
529
+ hide_index=True
530
+ )
531
+
532
+ # عرض مخطط المقارنة
533
+ st.markdown("#### مقارنة الأسعار المقدرة مع متوسط السوق")
534
+
535
+ # إنشاء DataFrame للمخطط
536
+ chart_df = pd.DataFrame({
537
+ "البند": market_df["البند"],
538
+ "السعر المقدر": market_df["السعر المقدر"],
539
+ "متوسط السوق": market_df["متوسط السوق"]
540
+ })
541
+
542
+ # تحويل البيانات إلى الشكل المناسب للمخطط
543
+ chart_df_melted = pd.melt(
544
+ chart_df,
545
+ id_vars=["البند"],
546
+ value_vars=["السعر المقدر", "متوسط السوق"],
547
+ var_name="النوع",
548
+ value_name="السعر"
549
+ )
550
+
551
+ # إنشاء المخطط
552
+ fig = px.bar(
553
+ chart_df_melted,
554
+ x="البند",
555
+ y="السعر",
556
+ color="النوع",
557
+ barmode="group",
558
+ title="مقارنة الأسعار المقدرة مع متوسط السوق",
559
+ labels={"البند": "البند", "السعر": "السعر (ريال سعودي)", "النوع": ""}
560
+ )
561
+
562
+ # تعديل المخطط
563
+ fig.update_layout(
564
+ xaxis_tickangle=-45,
565
+ yaxis=dict(title="السعر (ريال سعودي)")
566
+ )
567
+
568
+ # عرض المخطط
569
+ st.plotly_chart(fig, use_container_width=True)
570
 
571
+ # عرض نطاق الأسعار في السوق
572
+ st.markdown("#### نطاق الأسعار في السوق")
573
+
574
+ # إنشاء مخطط نطاق الأسعار
575
+ fig = go.Figure()
576
+
577
+ for i, row in market_df.iterrows():
578
+ fig.add_trace(go.Scatter(
579
+ x=[row["البند"], row["البند"]],
580
+ y=[row["الحد الأدنى"], row["الحد الأقصى"]],
581
+ mode="lines",
582
+ line=dict(width=2, color="rgba(0,0,255,0.3)"),
583
+ showlegend=False
584
+ ))
585
+
586
+ fig.add_trace(go.Scatter(
587
+ x=[row["البند"]],
588
+ y=[row["متوسط السوق"]],
589
+ mode="markers",
590
+ marker=dict(size=10, color="blue"),
591
+ name="متوسط السوق" if i == 0 else None,
592
+ showlegend=i == 0
593
+ ))
594
+
595
+ fig.add_trace(go.Scatter(
596
+ x=[row["البند"]],
597
+ y=[row["السعر المقدر"]],
598
+ mode="markers",
599
+ marker=dict(size=10, color="red"),
600
+ name="السعر المقدر" if i == 0 else None,
601
+ showlegend=i == 0
602
+ ))
603
+
604
+ # تعديل المخطط
605
+ fig.update_layout(
606
+ title="نطاق الأسعار في السوق",
607
+ xaxis_title="البند",
608
+ yaxis_title="السعر (ريال سعودي)",
609
+ xaxis_tickangle=-45
610
+ )
611
+
612
+ # عرض المخطط
613
+ st.plotly_chart(fig, use_container_width=True)
614
+
615
+ # تحليل الفروقات
616
+ st.markdown("#### تحليل الفروقات عن متوسط السوق")
617
+
618
+ # حساب متوسط الفرق
619
+ avg_diff = market_df["الفرق (%)"].mean()
620
+
621
+ # عرض متوسط الفرق
622
+ st.metric(
623
+ label="متوسط الفرق عن السوق",
624
+ value=f"{avg_diff:.2f}%",
625
+ delta=f"{'أقل' if avg_diff < 0 else 'أعلى'} من متوسط السوق"
626
+ )
627
+
628
+ # تصنيف البنود حسب الفرق
629
+ lower_items = market_df[market_df["الفرق (%)"] < -5]
630
+ higher_items = market_df[market_df["الفرق (%)"] > 5]
631
+
632
+ col1, col2 = st.columns(2)
633
+
634
+ with col1:
635
+ st.markdown("##### بنود أقل من متوسط السوق بأكثر من 5%")
636
+ if not lower_items.empty:
637
+ st.dataframe(
638
+ lower_items[["البند", "السعر المقدر", "متوسط السوق", "الفرق (%)"]].style.format({
639
+ "السعر المقدر": "{:,.2f}",
640
+ "متوسط السوق": "{:,.2f}",
641
+ "الفرق (%)": "{:+.2f}%"
642
+ }),
643
+ use_container_width=True,
644
+ hide_index=True
645
+ )
646
+ else:
647
+ st.info("لا توجد بنود أقل من متوسط السوق بأكثر من 5%")
648
+
649
+ with col2:
650
+ st.markdown("##### بنود أعلى من متوسط السوق بأكثر من 5%")
651
+ if not higher_items.empty:
652
+ st.dataframe(
653
+ higher_items[["البند", "السعر المقدر", "متوسط السوق", "الفرق (%)"]].style.format({
654
+ "السعر المقدر": "{:,.2f}",
655
+ "متوسط السوق": "{:,.2f}",
656
+ "الفرق (%)": "{:+.2f}%"
657
+ }),
658
+ use_container_width=True,
659
+ hide_index=True
660
+ )
661
+ else:
662
+ st.info("لا توجد بنود أعلى من متوسط السوق بأكثر من 5%")
663
+ else:
664
+ st.info("الرجاء تحميل وتحليل ملفات المشروع أولاً من تبويب 'تحميل الملفات'.")
665
+
666
+ # تبويب التقارير
667
+ with cost_tabs[4]:
668
+ st.markdown("#### تقارير تقدير التكاليف")
669
+
670
+ # التحقق من وجود ملفات محللة
671
+ if 'analyzed_files' in st.session_state and st.session_state.analyzed_files:
672
+ # أنواع التقارير
673
+ report_type = st.selectbox(
674
+ "اختر نوع التقرير:",
675
  options=[
676
+ "تقرير ملخص التكاليف",
677
+ "تقرير تفصيلي للبنود",
678
+ "تقرير المقارنة مع السوق",
679
+ "تقرير تحليل المخاطر",
680
+ "تقرير شامل"
681
  ],
682
+ key="cost_report_type_selector"
683
  )
684
 
685
+ # إعدادات التقرير
686
+ with st.expander("إعدادات التقرير"):
687
+ col1, col2 = st.columns(2)
688
+
689
+ with col1:
690
+ include_charts = st.checkbox(
691
+ "تضمين الرسوم البيانية",
692
+ value=True,
693
+ key="include_charts_checkbox"
694
+ )
695
+
696
+ include_analysis = st.checkbox(
697
+ "تضمين التحليل",
698
+ value=True,
699
+ key="include_analysis_checkbox"
700
+ )
701
+
702
+ with col2:
703
+ report_format = st.radio(
704
+ "صيغة التقرير:",
705
+ options=["PDF", "Excel", "Word"],
706
+ horizontal=True,
707
+ key="report_format_radio"
708
+ )
709
+
710
+ include_logo = st.checkbox(
711
+ "تضمين شعار الشركة",
712
+ value=True,
713
+ key="include_logo_checkbox"
714
+ )
715
 
716
+ # زر إنشاء التقرير
717
+ if st.button("إنشاء التقرير", key="create_report_button"):
718
+ with st.spinner("جاري إنشاء التقرير..."):
719
+ # محاكاة إنشاء التقرير
720
  progress_bar = st.progress(0)
721
  for i in range(100):
722
+ time.sleep(0.02)
723
  progress_bar.progress(i + 1)
724
 
725
+ st.success("تم إنشاء التقرير بنجاح!")
726
+
727
+ # عرض معاينة التقرير
728
+ st.markdown("#### معاينة التقرير")
729
+
730
+ # إنشاء معاينة للتقرير حسب النوع المحدد
731
+ if report_type == "تقرير ملخص التكاليف":
732
+ st.markdown("""
733
+ ### تقرير ملخص التكاليف
734
+
735
+ **اسم المشروع:** مشروع إنشاء مبنى إداري
736
+
737
+ **تاريخ التقرير:** {date}
738
+
739
+ **إعداد:** نظام تحليل المناقصات - وحدة الذكاء الاصطناعي
740
+
741
+ #### ملخص التكاليف
742
+
743
+ - **التكلفة الأساسية:** 4,500,000 ريال سعودي
744
+ - **احتياطي الطوارئ (10%):** 450,000 ريال سعودي
745
+ - **تكلفة التضخم:** 157,500 ريال سعودي
746
+ - **التكلفة الإجمالية:** 5,107,500 ريال سعودي
747
+
748
+ #### توزيع التكاليف حسب نوع العمل
749
+
750
+ - الأعمال الإنشائية: 1,787,625 ريال سعودي (35%)
751
+ - الأعمال المعمارية: 1,276,875 ريال سعودي (25%)
752
+ - الأعمال الكهربائية: 766,125 ريال سعودي (15%)
753
+ - الأعمال الميكانيكية: 612,900 ريال سعودي (12%)
754
+ - أعمال الموقع والتجهيزات: 408,600 ريال سعودي (8%)
755
+ - أخرى: 255,375 ريال سعودي (5%)
756
+ """.format(date=datetime.now().strftime("%Y-%m-%d")))
757
+
758
+ elif report_type == "تقرير تفصيلي للبنود":
759
+ st.markdown("""
760
+ ### تقرير تفصيلي للبنود
761
+
762
+ **اسم المشروع:** مشروع إنشاء مبنى إداري
763
+
764
+ **تاريخ التقرير:** {date}
765
+
766
+ **إعداد:** نظام تحليل المناقصات - وحدة الذكاء الاصطناعي
767
+
768
+ #### تفاصيل البنود
769
+
770
+ | الكود | الوصف | الوحدة | الكمية | سعر الوحدة | الإجمالي |
771
+ |-------|-------|--------|--------|------------|----------|
772
+ | 01-001 | أعمال الحفر والردم | م³ | 5,000 | 35 | 175,000 |
773
+ | 01-002 | أعمال الخرسانة العادية | م³ | 1,200 | 450 | 540,000 |
774
+ | 01-003 | أعمال الخرسانة المسلحة | م³ | 2,500 | 850 | 2,125,000 |
775
+ | 02-001 | أعمال البلوك | م² | 3,500 | 120 | 420,000 |
776
+ | 02-002 | أعمال اللياسة | م² | 7,000 | 45 | 315,000 |
777
+ | 02-003 | أعمال البلاط | م² | 4,500 | 180 | 810,000 |
778
+ | 03-001 | أعمال التمديدات الكهربائية | نقطة | 350 | 250 | 87,500 |
779
+ | 03-002 | أعمال الإنارة | وحدة | 200 | 350 | 70,000 |
780
+ | 04-001 | أعمال التمديدات الصحية | نقطة | 120 | 450 | 54,000 |
781
+ | 04-002 | أعمال التكييف | وحدة | 50 | 3,500 | 175,000 |
782
+
783
+ **الإجمالي:** 4,771,500 ريال سعودي
784
+ """.format(date=datetime.now().strftime("%Y-%m-%d")))
785
 
786
+ elif report_type == "تقرير المقارنة مع السوق":
787
+ st.markdown("""
788
+ ### تقرير المقارنة مع السوق
789
+
790
+ **اسم المشروع:** مشروع إنشاء مبنى إداري
791
+
792
+ **تاريخ التقرير:** {date}
793
+
794
+ **إعداد:** نظام تحليل المناقصات - وحدة الذكاء الاصطناعي
795
+
796
+ #### مقارنة الأسعار مع السوق
797
+
798
+ | البند | السعر المقدر | متوسط السوق | الحد الأدنى | الحد الأقصى | الفرق (%) |
799
+ |-------|--------------|-------------|------------|------------|----------|
800
+ | الخرسانة المسلحة (م³) | 850 | 900 | 800 | 1,000 | -5.56% |
801
+ | البلوك (م²) | 120 | 115 | 100 | 130 | +4.35% |
802
+ | اللياسة (م²) | 45 | 50 | 40 | 60 | -10.00% |
803
+ | البلاط (م²) | 180 | 175 | 150 | 200 | +2.86% |
804
+ | التمديدات الكهربائية (نقطة) | 250 | 275 | 225 | 325 | -9.09% |
805
+
806
+ **متوسط الفرق عن السوق:** -3.49%
807
+
808
+ #### تحليل الفروقات
809
+
810
+ - البنود التي تقل عن متوسط السوق بأكثر من 5%:
811
+ - الخرسانة المسلحة: -5.56%
812
+ - اللياسة: -10.00%
813
+ - التمديدات الكهربائية: -9.09%
814
+
815
+ - البنود التي تزيد عن متوسط السوق بأكثر من 5%:
816
+ - لا توجد
817
+ """.format(date=datetime.now().strftime("%Y-%m-%d")))
818
 
819
+ elif report_type == "تقرير تحليل المخاطر":
820
+ st.markdown("""
821
+ ### تقرير تحليل المخاطر
822
+
823
+ **اسم المشروع:** مشروع إنشاء مبنى إداري
824
+
825
+ **تاريخ التقرير:** {date}
826
+
827
+ **إعداد:** نظام تحليل المناقصات - وحدة الذكاء الاصطناعي
828
+
829
+ #### تحليل مخاطر التكلفة
830
+
831
+ | المخاطرة | الاحتمالية | التأثير | درجة المخاطرة | الإجراءات المقترحة |
832
+ |----------|------------|---------|---------------|-------------------|
833
+ | ارتفاع أسعار مواد البناء | متوسطة | عالي | عالية | تأمين المواد الرئيسية مبكراً، إبرام عقود توريد بأسعار ثابتة |
834
+ | تأخر تنفيذ المشروع | منخفضة | متوسط | متوسطة | وضع جدول زمني واقعي، متابعة دورية للتقدم |
835
+ | تغيير نطاق العمل | متوسطة | عالي | عالية | توثيق نطاق العمل بدقة، إدارة التغييرات بفعالية |
836
+ | نقص العمالة الماهرة | منخفضة | متوسط | متوسطة | التعاقد مع مقاولي باطن موثوقين، خطة بديلة للموارد |
837
+ | مشاكل فنية غير متوقعة | منخفضة | عالي | متوسطة | مراجعة التصاميم بدقة، إجراء فحوصات للموقع |
838
+
839
+ #### تأثير المخاطر على التكلفة
840
+
841
+ - **التكلفة الأساسية:** 5,107,500 ريال سعودي
842
+ - **تأثير المخاطر (الحد الأدنى):** +2% (102,150 ريال سعودي)
843
+ - **تأثير المخاطر (المتوقع):** +5% (255,375 ريال سعودي)
844
+ - **تأثير المخاطر (الحد الأقصى):** +12% (612,900 ريال سعودي)
845
+ - **نطاق التكلفة المتوقع:** 5,209,650 - 5,720,400 ريال سعودي
846
+ """.format(date=datetime.now().strftime("%Y-%m-%d")))
847
+
848
+ else: # تقرير شامل
849
+ st.markdown("""
850
+ ### تقرير شامل لتقدير التكاليف
851
+
852
+ **اسم المشروع:** مشروع إنشاء مبنى إداري
853
+
854
+ **تاريخ التقرير:** {date}
855
+
856
+ **إعداد:** نظام تحليل المناقصات - وحدة الذكاء الاصطناعي
857
+
858
+ #### ملخص المشروع
859
+
860
+ - **نوع المشروع:** مبنى إداري
861
+ - **الموقع:** الرياض
862
+ - **المساحة:** 5,000 متر مربع
863
+ - **مدة التنفيذ:** 12 شهر
864
+
865
+ #### ملخص التكاليف
866
+
867
+ - **التكلفة الأساسية:** 4,500,000 ريال سعودي (900 ريال/م²)
868
+ - **احتياطي الطوارئ (10%):** 450,000 ريال سعودي
869
+ - **تكلفة التضخم:** 157,500 ريال سعودي
870
+ - **التكلفة الإجمالية:** 5,107,500 ريال سعودي (1,021.5 ريال/م²)
871
+
872
+ #### توزيع التكاليف حسب نوع العمل
873
+
874
+ - الأعمال الإنشائية: 1,787,625 ريال سعودي (35%)
875
+ - الأعمال المعمارية: 1,276,875 ريال سعودي (25%)
876
+ - الأعمال الكهربائية: 766,125 ريال سعودي (15%)
877
+ - الأعمال الميكانيكية: 612,900 ريال سعودي (12%)
878
+ - أعمال الموقع والتجهيزات: 408,600 ريال سعودي (8%)
879
+ - أخرى: 255,375 ريال سعودي (5%)
880
+
881
+ #### مقارنة الأسعار مع السوق
882
+
883
+ - متوسط الفرق عن السوق: -3.49%
884
+ - البنود التي تقل عن متوسط السوق بأكثر من 5%:
885
+ - الخرسانة المسلحة: -5.56%
886
+ - اللياسة: -10.00%
887
+ - التمديدات الكهربائية: -9.09%
888
+
889
+ #### تحليل المخاطر
890
+
891
+ - نطاق التكلفة المتوقع: 5,209,650 - 5,720,400 ريال سعودي
892
+ - المخاطر الرئيسية: ارتفاع أسعار مواد البناء، تغيير نطاق العمل
893
+
894
+ #### التوصيات
895
+
896
+ 1. تأمين المواد الرئيسية مبكراً لتجنب ارتفاع الأسعار
897
+ 2. مراجعة بنود اللياسة والتمديدات الكهربائية للتأكد من دقة التقدير
898
+ 3. توثيق نطاق العمل بدقة لتجنب التغييرات غير المخطط لها
899
+ 4. إضافة احتياطي للطوارئ بنسبة 10% لتغطية المخاطر المحتملة
900
+ 5. مراقبة أسعار السوق بشكل دوري وتحديث التقديرات عند الحاجة
901
+ """.format(date=datetime.now().strftime("%Y-%m-%d")))
902
+
903
+ # إضافة زر لتنزيل التقرير
904
+ report_file_name = f"تقرير_{report_type.replace(' ', '_')}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
905
+
906
+ if report_format == "PDF":
907
+ st.download_button(
908
+ label="تنزيل التقرير (PDF)",
909
+ data=b"تقرير تقدير التكاليف", # في التنفيذ الفعلي، سيتم إنشاء ملف PDF حقيقي
910
+ file_name=f"{report_file_name}.pdf",
911
+ mime="application/pdf",
912
+ key="download_report_pdf"
913
+ )
914
+ elif report_format == "Excel":
915
+ st.download_button(
916
+ label="تنزيل التقرير (Excel)",
917
+ data=b"بيانات تقدير التكاليف", # في التنفيذ الفعلي، سيتم إنشاء ملف Excel حقيقي
918
+ file_name=f"{report_file_name}.xlsx",
919
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
920
+ key="download_report_excel"
921
+ )
922
+ else: # Word
923
+ st.download_button(
924
+ label="تنزيل التقرير (Word)",
925
+ data=b"تقرير تقدير التكاليف", # في التنفيذ الفعلي، سيتم إنشاء ملف Word حقيقي
926
+ file_name=f"{report_file_name}.docx",
927
+ mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
928
+ key="download_report_word"
929
+ )
930
+ else:
931
+ st.info("الرجاء تحميل وتحليل ملفات المشروع أولاً من تبويب 'تحميل الملفات'.")
932
 
933
+ def _detect_file_type(self, file_name):
934
+ """تحديد نوع الملف بناءً على الامتداد"""
935
+ extension = file_name.split('.')[-1].lower()
936
+
937
+ if extension in ['pdf']:
938
+ return 'application/pdf'
939
+ elif extension in ['dwg']:
940
+ return 'application/acad'
941
+ elif extension in ['xlsx', 'xls']:
942
+ return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
943
+ elif extension in ['docx', 'doc']:
944
+ return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
945
+ elif extension in ['txt']:
946
+ return 'text/plain'
947
+ elif extension in ['png']:
948
+ return 'image/png'
949
+ elif extension in ['jpg', 'jpeg']:
950
+ return 'image/jpeg'
951
+ else:
952
+ return 'application/octet-stream'