EGYADMIN commited on
Commit
2d90917
·
verified ·
1 Parent(s): a854c1b

Update modules/ai_assistant/ai_app.py

Browse files
Files changed (1) hide show
  1. modules/ai_assistant/ai_app.py +145 -601
modules/ai_assistant/ai_app.py CHANGED
@@ -1,7 +1,3 @@
1
- """
2
- وحدة الذكاء الاصطناعي - التطبيق الرئيسي
3
- """
4
-
5
  import streamlit as st
6
  import pandas as pd
7
  import numpy as np
@@ -15,8 +11,6 @@ import os
15
  import json
16
  import base64
17
  from pathlib import Path
18
- import tempfile
19
- from PIL import Image
20
 
21
  # استيراد محلل المستندات
22
  from .document_analyzer import AIDocumentAnalyzer, DocumentParser
@@ -151,6 +145,10 @@ class AIAssistantApp:
151
  if 'theme' not in st.session_state:
152
  st.session_state.theme = 'light'
153
 
 
 
 
 
154
  # تهيئة محلل المستندات
155
  self.document_analyzer = AIDocumentAnalyzer()
156
 
@@ -168,13 +166,7 @@ class AIAssistantApp:
168
  تقوم بتهيئة واجهة المستخدم وعرض الوظائف المختلفة للذكاء الاصطناعي.
169
  """
170
  try:
171
- # تعيين عنوان الصفحة
172
- st.set_page_config(
173
- page_title="وحدة الذكاء الاصطناعي - نظام المناقصات",
174
- page_icon="🤖",
175
- layout="wide",
176
- initial_sidebar_state="expanded"
177
- )
178
 
179
  # تطبيق التنسيق المخصص
180
  st.markdown("""
@@ -199,126 +191,130 @@ class AIAssistantApp:
199
  padding-top: 10px;
200
  padding-bottom: 10px;
201
  }
202
- .stTabs [aria-selected="true"] {
203
- background-color: #3498db;
204
- color: white;
205
- }
206
  </style>
207
  """, unsafe_allow_html=True)
208
 
209
- # إضافة زر تبديل السمة في أعلى الصفحة
210
- col1, col2, col3 = st.columns([1, 8, 1])
211
- with col3:
212
- if st.button("🌓 تبديل السمة"):
213
- # تبديل السمة
214
- if st.session_state.theme == "light":
215
- st.session_state.theme = "dark"
216
- else:
217
- st.session_state.theme = "light"
218
-
219
- # تطبيق السمة الجديدة وإعادة تشغيل التطبيق
220
- st.rerun()
221
 
222
- # عرض الشريط الجانبي
223
  with st.sidebar:
224
- st.image("/home/ubuntu/tender_system/tender_system/assets/images/logo.png", width=200)
225
- st.markdown("## نظام تحليل المناقصات")
226
- st.markdown("### وحدة الذكاء الاصطناعي")
227
-
228
- st.markdown("---")
229
-
230
- # إضافة خيارات الذكاء الاصطناعي
231
  st.markdown("### إعدادات الذكاء الاصطناعي")
232
 
233
  # اختيار نموذج الذكاء الاصطناعي
234
  ai_model = st.selectbox(
235
- "نموذج الذكاء الاصطناعي",
236
- ["OpenAI GPT-4", "Claude 3 Opus", "Gemini Pro", "محلي"]
 
 
237
  )
238
 
239
  # إعدادات النموذج
240
  st.markdown("#### إعدادات النموذج")
241
- temperature = st.slider("درجة الإبداعية", 0.0, 1.0, 0.7, 0.1)
242
- max_tokens = st.slider("الحد الأقصى للكلمات", 100, 4000, 2000, 100)
243
 
244
- # إعدادات التكامل مع بيئة هجين فيس
245
- st.markdown("#### إعدادات التكامل")
246
- hybrid_face_integration = st.checkbox("تمكين التكامل مع بيئة هجين فيس", value=True)
 
 
 
 
 
247
 
248
- if hybrid_face_integration:
249
- api_key_source = st.radio(
250
- "مصدر مفتاح API",
251
- ["قسم الأمان", "إد��ال يدوي"]
252
- )
253
-
254
- if api_key_source == "إدخال يدوي":
255
- api_key = st.text_input("مفتاح API", type="password")
256
 
257
- st.markdown("---")
 
258
 
259
- # إضافة معلومات المستخدم
260
- st.markdown("### معلومات المستخدم")
261
- st.markdown("**المستخدم:** مهندس تامر الجوهري")
262
- st.markdown("**الدور:** محلل مناقصات")
263
- st.markdown("**تاريخ آخر دخول:** " + datetime.now().strftime("%Y-%m-%d %H:%M"))
264
-
265
- # عرض واجهة وحدة الذكاء الاصطناعي
266
- self.render()
267
-
268
- # إضافة معلومات في أسفل الصفحة
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
  st.markdown("---")
270
- st.markdown("### نظام تحليل المناقصات - وحدة الذكاء الاصطناعي")
271
- st.markdown("**الإصدار:** 2.0.0")
272
- st.markdown("**تاريخ التحديث:** 2025-03-31")
273
- st.markdown("**جميع الحقوق محفوظة © 2025**")
274
-
275
- return True
276
 
277
  except Exception as e:
278
  st.error(f"حدث خطأ أثناء تشغيل وحدة الذكاء الاصطناعي: {str(e)}")
279
- return False
280
-
281
- def render(self):
282
- """عرض واجهة وحدة الذكاء الاصطناعي"""
283
-
284
- st.markdown("<h1 class='module-title'>وحدة الذكاء الاصطناعي</h1>", unsafe_allow_html=True)
285
-
286
- tabs = st.tabs(["المساعد الذكي", "تحليل المستندات", "تقدير التكاليف", "تحليل المخاطر", "نماذج الذكاء الاصطناعي"])
287
-
288
- with tabs[0]:
289
- self._render_assistant_tab()
290
-
291
- with tabs[1]:
292
- self._render_document_analysis_tab()
293
-
294
- with tabs[2]:
295
- self._render_cost_estimation_tab()
296
-
297
- with tabs[3]:
298
- self._render_risk_analysis_tab()
299
-
300
- with tabs[4]:
301
- self._render_ai_models_tab()
302
-
303
  def _render_assistant_tab(self):
304
  """عرض تبويب المساعد الذكي"""
305
 
306
  st.markdown("### المساعد الذكي")
307
 
 
 
 
 
 
 
 
 
308
  # عرض محادثة المساعد الذكي
309
  chat_container = st.container()
310
 
311
  with chat_container:
312
  for message in st.session_state.chat_history:
313
  if message['role'] == 'user':
314
- 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)
315
  else:
316
- st.markdown(f"<div style='background-color: #e1f5fe; padding: 10px; border-radius: 10px; margin-bottom: 10px;'><strong>المساعد:</strong> {message['content']}</div>", unsafe_allow_html=True)
317
 
318
- # إضافة حقل إدخال الرسالة
319
- user_input = st.text_input("اكتب رسالتك هنا...", key="user_input")
320
 
321
- if st.button("إرسال"):
322
  if user_input:
323
  # إضافة رسالة المستخدم إلى المحادثة
324
  st.session_state.chat_history.append({
@@ -326,530 +322,78 @@ class AIAssistantApp:
326
  'content': user_input
327
  })
328
 
329
- # محاكاة استجابة المساعد الذكي
330
- response = self._generate_assistant_response(user_input)
331
-
332
- # إضافة استجابة المساعد إلى المحادثة
333
  st.session_state.chat_history.append({
334
  'role': 'assistant',
335
  'content': response
336
  })
337
 
338
- # إعادة تشغيل التطبيق لتحديث المحادثة
339
  st.rerun()
340
-
341
- # إضافة زر لمسح المحادثة
342
- if st.button("مسح المحادثة"):
343
- st.session_state.chat_history = [
344
- {
345
- 'role': 'assistant',
346
- 'content': 'مرحباً! أنا مساعدك الذكي لإدارة المناقصات. كيف يمكنني مساعدتك اليوم؟'
347
- }
348
- ]
349
- st.rerun()
350
-
351
  def _render_document_analysis_tab(self):
352
  """عرض تبويب تحليل المستندات"""
353
 
354
  st.markdown("### تحليل المستندات")
355
 
356
- # إضافة خيارات تحليل المستندات
357
- analysis_type = st.selectbox(
358
- "نوع التحليل",
359
- ["تحليل كراسة الشروط", "تحليل جدول الكميات", "تحليل العقود", "تحليل ملفات DWG"]
360
- )
 
 
 
361
 
362
- # رفع الملف
363
- uploaded_file = st.file_uploader("رفع ملف للتحليل", type=["pdf", "docx", "xlsx", "dwg"])
364
 
365
  if uploaded_file is not None:
366
  # عرض معلومات الملف
367
  file_details = {
368
  "اسم الملف": uploaded_file.name,
369
  "نوع الملف": uploaded_file.type,
370
- "حجم الملف": f"{uploaded_file.size / 1024:.1f} كيلوبايت"
371
- }
372
-
373
- st.write("### معلومات الملف")
374
- for key, value in file_details.items():
375
- st.write(f"**{key}:** {value}")
376
-
377
- # حفظ الملف مؤقتاً
378
- with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(uploaded_file.name)[1]) as tmp_file:
379
- tmp_file.write(uploaded_file.getvalue())
380
- tmp_file_path = tmp_file.name
381
-
382
- # تحليل الملف
383
- if st.button("تحليل الملف"):
384
- with st.spinner("جاري تحليل الملف..."):
385
- if analysis_type == "تحليل ملفات DWG":
386
- # استخدام وحدة تكامل البيانات لتحليل ملف DWG
387
- analysis_results = self.analyze_dwg_files(tmp_file_path)
388
- self._display_dwg_analysis_results(analysis_results)
389
- else:
390
- # استخدام محلل المستندات لتحليل الملف
391
- analysis_results = self.document_analyzer.analyze_document(tmp_file_path, analysis_type)
392
- self._display_document_analysis_results(analysis_results)
393
-
394
- # عرض ملخصات المستندات المحللة سابقاً
395
- st.markdown("### المستندات المحللة سابقاً")
396
-
397
- for doc in st.session_state.document_summaries:
398
- with st.expander(f"{doc['title']} ({doc['date']})"):
399
- st.markdown(f"**ملخص:** {doc['summary']}")
400
-
401
- st.markdown("**النقاط الرئيسية:**")
402
- for point in doc['key_points']:
403
- st.markdown(f"- {point}")
404
-
405
- st.markdown("**الكيانات المستخرجة:**")
406
- for entity, value in doc['entities'].items():
407
- st.markdown(f"- **{entity}:** {value}")
408
-
409
- def _render_cost_estimation_tab(self):
410
- """عرض تبويب تقدير التكاليف"""
411
-
412
- st.markdown("### تقدير التكاليف")
413
-
414
- # إضافة خيارات تقدير التكاليف
415
- col1, col2 = st.columns(2)
416
-
417
- with col1:
418
- project_type = st.selectbox(
419
- "نوع المشروع",
420
- ["مبنى إداري", "مبنى سكني", "مدرسة", "مستشفى", "طرق", "جسور", "بنية تحتية"]
421
- )
422
-
423
- project_location = st.selectbox(
424
- "موقع المشروع",
425
- ["الرياض", "جدة", "الدمام", "مكة", "المدينة", "أبها", "تبوك"]
426
- )
427
-
428
- project_area = st.number_input("المساحة (م²)", min_value=100, max_value=100000, value=5000)
429
-
430
- project_duration = st.number_input("المدة (شهر)", min_value=1, max_value=60, value=18)
431
-
432
- with col2:
433
- quality_level = st.selectbox(
434
- "مستوى الجودة",
435
- ["اقتصادي", "متوسط", "عالي", "فاخر"]
436
- )
437
-
438
- include_design = st.checkbox("تضمين التصميم", value=True)
439
-
440
- include_supervision = st.checkbox("تضمين الإشراف", value=True)
441
-
442
- include_contingency = st.checkbox("تضمين احتياطي الطوارئ", value=True)
443
-
444
- # زر تقدير التكاليف
445
- if st.button("تقدير التكاليف"):
446
- with st.spinner("جاري تقدير التكاليف..."):
447
- # إنشاء بيانات المناقصة
448
- tender_data = {
449
- "نوع المشروع": project_type,
450
- "الموقع": project_location,
451
- "المساحة (م2)": project_area,
452
- "المدة (شهر)": project_duration,
453
- "مستوى الجودة": quality_level,
454
- "تضمين التصميم": include_design,
455
- "تضمين الإشراف": include_supervision,
456
- "تضمين احتياطي الطوارئ": include_contingency,
457
- "الميزانية التقديرية": project_area * 5000 # قيمة افتراضية
458
- }
459
-
460
- # استخدام وحدة تكامل البيانات لتحسين التسعير
461
- pricing_results = self.optimize_pricing(tender_data)
462
-
463
- # عرض نتائج التسعير
464
- self._display_pricing_results(pricing_results)
465
-
466
- def _render_risk_analysis_tab(self):
467
- """عرض تبويب تحليل المخاطر"""
468
-
469
- st.markdown("### تحليل المخاطر")
470
-
471
- # إضافة خيارات تحليل المخاطر
472
- col1, col2 = st.columns(2)
473
-
474
- with col1:
475
- project_type = st.selectbox(
476
- "نوع المشروع",
477
- ["مبنى إداري", "مبنى سكني", "مدرسة", "مستشفى", "طرق", "جسور", "بنية تحتية"],
478
- key="risk_project_type"
479
- )
480
-
481
- project_location = st.selectbox(
482
- "موقع المشروع",
483
- ["الرياض", "جدة", "الدمام", "مكة", "المدينة", "أبها", "تبوك"],
484
- key="risk_project_location"
485
- )
486
-
487
- project_budget = st.number_input("الميزانية (ريال)", min_value=100000, max_value=1000000000, value=10000000)
488
-
489
- project_duration = st.number_input("المدة (شهر)", min_value=1, max_value=60, value=18, key="risk_project_duration")
490
-
491
- with col2:
492
- contractor_experience = st.selectbox(
493
- "خبرة المقاول",
494
- ["محدودة", "متوسطة", "عالية"]
495
- )
496
-
497
- project_complexity = st.selectbox(
498
- "تعقيد المشروع",
499
- ["بسيط", "متوسط", "معقد", "معقد جداً"]
500
- )
501
-
502
- market_conditions = st.selectbox(
503
- "ظروف السوق",
504
- ["مستقرة", "متقلبة", "غير مستقرة"]
505
- )
506
-
507
- competition_level = st.selectbox(
508
- "مستوى المنافسة",
509
- ["منخفض", "متوسط", "عالي", "عالي جداً"]
510
- )
511
-
512
- # زر تحليل المخاطر
513
- if st.button("تحليل المخاطر"):
514
- with st.spinner("جاري تحليل المخاطر..."):
515
- # إنشاء بيانات المناقصة
516
- tender_data = {
517
- "نوع المشروع": project_type,
518
- "الموقع": project_location,
519
- "الميزانية": project_budget,
520
- "المدة (شهر)": project_duration,
521
- "خبرة المقاول": contractor_experience,
522
- "تعقيد المشروع": project_complexity,
523
- "ظروف السوق": market_conditions,
524
- "مستوى المنافسة": competition_level
525
- }
526
-
527
- # استخدام وحدة تكامل البيانات لتحليل المخاطر
528
- risk_results = self.analyze_tender_data(tender_data)
529
-
530
- # عرض نتائج تحليل المخاطر
531
- self._display_risk_analysis_results(risk_results)
532
-
533
- def _render_ai_models_tab(self):
534
- """عرض تبويب نماذج الذكاء الاصطناعي"""
535
-
536
- st.markdown("### نماذج الذكاء الاصطناعي")
537
-
538
- # عرض النماذج المتاحة
539
- for model in st.session_state.ai_models:
540
- with st.expander(f"{model['name']} (دقة: {model['accuracy']}%)"):
541
- st.markdown(f"**الوصف:** {model['description']}")
542
- st.markdown(f"**النوع:** {model['type']}")
543
- st.markdown(f"**تاريخ آخر تحديث:** {model['last_updated']}")
544
-
545
- # إضافة زر لتدريب النموذج
546
- if st.button(f"تدريب النموذج", key=f"train_{model['id']}"):
547
- with st.spinner("جاري تدريب النموذج..."):
548
- # محاكاة تدريب النموذج
549
- time.sleep(2)
550
- st.success("تم تدريب النموذج بنجاح!")
551
-
552
- # تحديث دقة النموذج
553
- for i, m in enumerate(st.session_state.ai_models):
554
- if m['id'] == model['id']:
555
- st.session_state.ai_models[i]['accuracy'] = min(99, model['accuracy'] + np.random.randint(1, 3))
556
- st.session_state.ai_models[i]['last_updated'] = datetime.now().strftime("%Y-%m-%d")
557
- break
558
-
559
- st.rerun()
560
-
561
- # إضافة نموذج جديد
562
- st.markdown("### إضافة نموذج جديد")
563
-
564
- col1, col2 = st.columns(2)
565
-
566
- with col1:
567
- new_model_name = st.text_input("اسم النموذج")
568
- new_model_description = st.text_area("وصف النموذج")
569
-
570
- with col2:
571
- new_model_type = st.selectbox(
572
- "نوع النموذج",
573
- ["معالجة اللغة الطبيعية", "تعلم آلي", "رؤية حاسوبية", "شبكة عصبية"]
574
- )
575
-
576
- new_model_accuracy = st.slider("الدقة المتوقعة", 50, 99, 75)
577
-
578
- if st.button("إضافة النموذج"):
579
- if new_model_name and new_model_description:
580
- # إضافة النموذج الجديد
581
- new_model = {
582
- 'id': len(st.session_state.ai_models) + 1,
583
- 'name': new_model_name,
584
- 'description': new_model_description,
585
- 'type': new_model_type,
586
- 'accuracy': new_model_accuracy,
587
- 'last_updated': datetime.now().strftime("%Y-%m-%d")
588
- }
589
-
590
- st.session_state.ai_models.append(new_model)
591
- st.success("تم إضافة النموذج بنجاح!")
592
- st.rerun()
593
- else:
594
- st.warning("يرجى ملء جميع الحقول المطلوبة")
595
-
596
- def _generate_assistant_response(self, user_input):
597
- """توليد استجابة المساعد الذكي"""
598
-
599
- # محاكاة استجابة المساعد الذكي
600
- responses = [
601
- "يمكنني مساعدتك في تحليل كراسة الشروط والمواصفات لهذه المناقصة. هل ترغب في رفع الملف للتحليل؟",
602
- "بناءً على تحليل البيانات التاريخية، أنصحك بتقديم عرض سعر أقل بنسبة 5-10% من الميزانية التقديرية لزيادة فرص الفوز.",
603
- "يمكنني مساعدتك في تقدير تكاليف هذا المشروع. يرجى تحديد نوع المشروع والموقع والمساحة.",
604
- "تشير تحليلاتنا إلى وجود مخاطر متوسطة في هذا المشروع، أهمها ارتفاع أسعار المواد وتأخر التوريدات. هل ترغب في الحصول على تحليل مفصل للمخاطر؟",
605
- "يمكنني تحليل ملفات DWG الخاصة بالمشروع لاستخراج الكميات وتقدير التكاليف. هل ترغب في رفع الملفات للتحليل؟",
606
- "بناءً على تحليل المنافسين، نتوقع وجود 3-5 منافسين رئيسيين في هذه المناقصة. هل ترغب في الحصول على تحليل مفصل للمنافسين؟"
607
- ]
608
-
609
- return np.random.choice(responses)
610
-
611
- def _display_document_analysis_results(self, results):
612
- """عرض نتائج تحليل المستندات"""
613
-
614
- st.markdown("### نتائج التحليل")
615
-
616
- # عرض ملخص التحليل
617
- st.markdown(f"**ملخص:** {results.get('summary', 'لا يوجد ملخص متاح')}")
618
-
619
- # عرض النقاط الرئيسية
620
- st.markdown("**النقاط الرئيسية:**")
621
- for point in results.get('key_points', ['لا توجد نقاط رئيسية متاحة']):
622
- st.markdown(f"- {point}")
623
-
624
- # عرض الكيانات المستخرجة
625
- st.markdown("**الكيانات المستخرجة:**")
626
- for entity, value in results.get('entities', {}).items():
627
- st.markdown(f"- **{entity}:** {value}")
628
-
629
- # عرض التوصيات
630
- st.markdown("**التوصيات:**")
631
- for recommendation in results.get('recommendations', ['لا توجد توصيات متاحة']):
632
- st.markdown(f"- {recommendation}")
633
-
634
- # إضافة المستند إلى قائمة المستندات المحللة
635
- if 'title' in results:
636
- new_doc = {
637
- 'id': len(st.session_state.document_summaries) + 1,
638
- 'title': results['title'],
639
- 'date': datetime.now().strftime("%Y-%m-%d"),
640
- 'summary': results.get('summary', ''),
641
- 'key_points': results.get('key_points', []),
642
- 'entities': results.get('entities', {})
643
- }
644
-
645
- st.session_state.document_summaries.append(new_doc)
646
- st.success("تم إضافة المستند إلى قائمة المستندات المحللة")
647
-
648
- def _display_dwg_analysis_results(self, results):
649
- """عرض نتائج تحليل ملفات DWG"""
650
-
651
- st.markdown("### نتائج تحليل ملف DWG")
652
-
653
- # عرض معلومات الملف
654
- st.markdown("**معلومات الملف:**")
655
- st.markdown(f"- **اسم الملف:** {results.get('file_name', 'غير معروف')}")
656
- st.markdown(f"- **حجم الملف:** {results.get('file_size', 'غير معروف')}")
657
- st.markdown(f"- **عدد العناصر:** {results.get('elements_count', 'غير معروف')}")
658
- st.markdown(f"- **عدد الطبقات:** {results.get('layers_count', 'غير معروف')}")
659
-
660
- # عرض الأبعاد
661
- st.markdown("**الأبعاد:**")
662
- dimensions = results.get('dimensions', {})
663
- st.markdown(f"- **العرض:** {dimensions.get('width', 'غير معروف')}")
664
- st.markdown(f"- **الارتفاع:** {dimensions.get('height', 'غير معروف')}")
665
- st.markdown(f"- **المساحة:** {dimensions.get('area', 'غير معروف')}")
666
-
667
- # عرض العناصر
668
- st.markdown("**العناصر:**")
669
- elements = results.get('elements', {})
670
- for element, count in elements.items():
671
- st.markdown(f"- **{element}:** {count}")
672
-
673
- # عرض المواد
674
- st.markdown("**المواد:**")
675
- for material in results.get('materials', []):
676
- material_info = []
677
- for key, value in material.items():
678
- if key != 'name':
679
- material_info.append(f"{key}: {value}")
680
-
681
- st.markdown(f"- **{material.get('name', 'غير معروف')}:** {', '.join(material_info)}")
682
-
683
- # عرض تقدير التكلفة
684
- st.markdown("**تقدير التكلفة:**")
685
- cost_estimate = results.get('cost_estimate', {})
686
- st.markdown(f"- **تكلفة المواد:** {cost_estimate.get('materials', 0):,} ريال")
687
- st.markdown(f"- **تكلفة العمالة:** {cost_estimate.get('labor', 0):,} ريال")
688
- st.markdown(f"- **تكلفة المعدات:** {cost_estimate.get('equipment', 0):,} ريال")
689
- st.markdown(f"- **التكلفة الإجمالية:** {cost_estimate.get('total', 0):,} ريال")
690
-
691
- # عرض التوصيات
692
- st.markdown("**التوصيات:**")
693
- for recommendation in results.get('recommendations', ['لا توجد توصيات متاحة']):
694
- st.markdown(f"- {recommendation}")
695
-
696
- def _display_pricing_results(self, results):
697
- """عرض نتائج تحسين التسعير"""
698
-
699
- st.markdown("### نتائج تحسين التسعير")
700
-
701
- # عرض نطاق السعر المقترح
702
- st.markdown("**نطاق السعر المقترح:**")
703
- st.markdown(f"- **الحد الأدنى:** {results.get('min_price', 0):,.0f} ريال")
704
- st.markdown(f"- **السعر الأمثل:** {results.get('optimal_price', 0):,.0f} ريال")
705
- st.markdown(f"- **الحد الأقصى:** {results.get('max_price', 0):,.0f} ريال")
706
-
707
- # عرض تحليل حساسية السعر
708
- st.markdown("**تحليل حساسية السعر:**")
709
-
710
- price_sensitivity = results.get('price_sensitivity', [])
711
- if price_sensitivity:
712
- # إنشاء DataFrame لتحليل حساسية السعر
713
- sensitivity_data = {
714
- 'عامل السعر': [item['price_factor'] for item in price_sensitivity],
715
- 'السعر (ريال)': [item['price'] for item in price_sensitivity],
716
- 'احتمالية الفوز (%)': [item['win_probability'] for item in price_sensitivity],
717
- 'الربح (ريال)': [item['profit'] for item in price_sensitivity],
718
- 'القيمة المتوقعة (ريال)': [item['expected_value'] for item in price_sensitivity]
719
- }
720
-
721
- sensitivity_df = pd.DataFrame(sensitivity_data)
722
- st.dataframe(sensitivity_df)
723
-
724
- # إنشاء رسم بياني لتحليل حساسية السعر
725
- fig = px.line(sensitivity_df, x='السعر (ريال)', y=['احتمالية الفوز (%)', 'القيمة المتوقعة (ريال)'], title='تحليل حساسية السعر')
726
- st.plotly_chart(fig, use_container_width=True)
727
-
728
- # عرض الموقف التنافسي في السوق
729
- st.markdown("**الموقف التنافسي في السوق:**")
730
- market_position = results.get('market_position', {})
731
- st.markdown(f"- **الموقف التنافسي:** {market_position.get('market_position', 'غير معروف')}")
732
- st.markdown(f"- **الشريحة السعرية:** {market_position.get('price_percentile', 0)}%")
733
- st.markdown(f"- **عدد المنافسين بأسعار أقل:** {market_position.get('competitors_below', 0)}")
734
- st.markdown(f"- **عدد المنافسين بأسعار أعلى:** {market_position.get('competitors_above', 0)}")
735
- st.markdown(f"- **تنافسية السعر:** {market_position.get('price_competitiveness', 'غير معروفة')}")
736
-
737
- # عرض التوصيات
738
- st.markdown("**التوصيات:**")
739
- for recommendation in results.get('recommendations', ['لا توجد توصيات متاحة']):
740
- st.markdown(f"- {recommendation}")
741
-
742
- def _display_risk_analysis_results(self, results):
743
- """عرض نتائج تحليل المخاطر"""
744
-
745
- st.markdown("### نتائج تحليل المخاطر")
746
-
747
- # عرض ملخص تحليل المخاطر
748
- st.markdown(f"**ملخص:** {results.get('summary', 'لا يوجد ملخص متاح')}")
749
-
750
- # عرض تحليل المخاطر
751
- st.markdown("**تحليل المخاطر:**")
752
-
753
- risk_analysis = results.get('risk_analysis', [])
754
- if risk_analysis:
755
- # إنشاء DataFrame لتحليل المخاطر
756
- risk_data = {
757
- 'المخاطرة': [risk['risk'] for risk in risk_analysis],
758
- 'الاحتمالية': [risk['probability'] for risk in risk_analysis],
759
- 'التأثير': [risk['impact'] for risk in risk_analysis],
760
- 'استراتيجية التخفيف': [risk['mitigation'] for risk in risk_analysis]
761
  }
762
 
763
- risk_df = pd.DataFrame(risk_data)
764
- st.dataframe(risk_df)
765
-
766
- # إنشاء مصفوفة المخاطر
767
- st.markdown("**مصفوفة المخاطر:**")
768
-
769
- # تحويل درجات المخاطرة إلى قيم رقمية للرسم البياني
770
- probability_levels = {
771
- "منخفضة": 1,
772
- "متوسطة": 2,
773
- "عالية": 3
774
- }
775
-
776
- impact_levels = {
777
- "منخفض": 1,
778
- "متوسط": 2,
779
- "عالي": 3,
780
- "عالي جداً": 4
781
- }
782
-
783
- # إنشاء DataFrame للرسم البياني
784
- chart_data = []
785
- for risk in risk_analysis:
786
- chart_data.append({
787
- "المخاطرة": risk['risk'],
788
- "الاحتمالية": probability_levels.get(risk['probability'], 0),
789
- "التأثير": impact_levels.get(risk['impact'], 0)
790
- })
791
-
792
- chart_df = pd.DataFrame(chart_data)
793
-
794
- fig = px.scatter(
795
- chart_df,
796
- x="الاحتمالية",
797
- y="التأثير",
798
- text="المخاطرة",
799
- size=[3] * len(chart_df),
800
- color="التأثير",
801
- color_continuous_scale=px.colors.sequential.Reds
802
  )
803
 
804
- fig.update_layout(
805
- xaxis=dict(
806
- tickmode='array',
807
- tickvals=[1, 2, 3],
808
- ticktext=['منخفضة', 'متوسطة', 'عالية']
809
- ),
810
- yaxis=dict(
811
- tickmode='array',
812
- tickvals=[1, 2, 3, 4],
813
- ticktext=['منخفض', 'متوسط', 'عالي', 'عالي جداً']
814
- )
815
  )
816
 
817
- st.plotly_chart(fig, use_container_width=True)
818
-
819
- # عرض تحليل التكاليف
820
- st.markdown("**تحليل التكاليف:**")
821
-
822
- cost_analysis = results.get('cost_analysis', {})
823
- if cost_analysis:
824
- st.markdown(f"**الميزانية الإجمالية:** {cost_analysis.get('total_budget', 0):,.0f} ريال")
825
-
826
- # عرض توزيع التكاليف
827
- st.markdown("**توزيع التكاليف:**")
828
-
829
- cost_breakdown = cost_analysis.get('cost_breakdown', [])
830
- if cost_breakdown:
831
- # إنشاء DataFrame لتوزيع التكاليف
832
- cost_data = {
833
- 'الفئة': [item['category'] for item in cost_breakdown],
834
- 'المبلغ (ريال)': [item['amount'] for item in cost_breakdown],
835
- 'النسبة (%)': [item['percentage'] for item in cost_breakdown]
836
- }
837
-
838
- cost_df = pd.DataFrame(cost_data)
839
-
840
- # إنشاء رسم بياني لتوزيع التكاليف
841
- fig = px.pie(cost_df, values='المبلغ (ريال)', names='الفئة', title='توزيع التكاليف')
842
- st.plotly_chart(fig, use_container_width=True)
843
-
844
- # عرض فرص توفير التكاليف
845
- st.markdown("**فرص توفير التكاليف:**")
846
-
847
- cost_saving = cost_analysis.get('cost_saving_opportunities', [])
848
- if cost_saving:
849
- for item in cost_saving:
850
- st.markdown(f"- **{item['item']}:** {item['potential_saving']:,.0f} ريال")
851
-
852
- # عرض التوصيات
853
- st.markdown("**التوصيات:**")
854
- for recommendation in results.get('recommendations', ['لا توجد توصيات متاحة']):
855
- st.markdown(f"- {recommendation}")
 
 
 
 
 
1
  import streamlit as st
2
  import pandas as pd
3
  import numpy as np
 
11
  import json
12
  import base64
13
  from pathlib import Path
 
 
14
 
15
  # استيراد محلل المستندات
16
  from .document_analyzer import AIDocumentAnalyzer, DocumentParser
 
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
 
 
166
  تقوم بتهيئة واجهة المستخدم وعرض الوظائف المختلفة للذكاء الاصطناعي.
167
  """
168
  try:
169
+ # تم إزالة set_page_config لتجنب التعارض مع app.py
 
 
 
 
 
 
170
 
171
  # تطبيق التنسيق المخصص
172
  st.markdown("""
 
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({
 
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
+ "تاريخ المستند":
399
+ (Content truncated due to size limit. Use line ranges to read in chunks)