diff --git "a/modules/ai_assistant/ai_app.py" "b/modules/ai_assistant/ai_app.py"
--- "a/modules/ai_assistant/ai_app.py"
+++ "b/modules/ai_assistant/ai_app.py"
@@ -14,7 +14,17 @@ from datetime import datetime
import time
import os
import sys
+import json
+import requests
from pathlib import Path
+import io
+import base64
+import re
+from PIL import Image
+import PyPDF2
+import docx
+import anthropic
+import tempfile
# إضافة المسار للوصول إلى الوحدات الأخرى
current_dir = os.path.dirname(os.path.abspath(__file__))
@@ -27,8 +37,19 @@ class AIAssistantApp:
def __init__(self):
"""تهيئة تطبيق مساعد الذكاء الاصطناعي"""
- self.data = None
- self.file_path = None
+ self.uploaded_files = {}
+ self.analysis_results = {}
+
+ # تهيئة مفاتيح API لنماذج هجين فيس
+ if 'ai_api_key' not in st.session_state:
+ st.session_state.ai_api_key = os.environ.get('AI_API_KEY', '')
+
+ if 'anthropic_api_key' not in st.session_state:
+ st.session_state.anthropic_api_key = os.environ.get('ANTHROPIC_API_KEY', '')
+
+ # تهيئة سجل المحادثة
+ if 'chat_history' not in st.session_state:
+ st.session_state.chat_history = []
def run(self):
"""تشغيل تطبيق مساعد الذكاء الاصطناعي"""
@@ -48,85 +69,161 @@ class AIAssistantApp:
# إنشاء تبويبات التطبيق
tabs = st.tabs([
- "الرئيسية",
+ "المحادثة مع الذكاء الاصطناعي",
"تحليل المستندات",
"تحليل العقود",
"تقدير التكاليف",
- "تحليل المخاطر",
- "المساعدة"
+ "تحليل المخاطر"
])
- # تبويب الرئيسية
+ # عرض محتوى كل تبويب
with tabs[0]:
- self._render_home_tab()
+ self._render_chat_tab()
- # تبويب تحليل المستندات
with tabs[1]:
self._render_document_analysis_tab()
- # تبويب تحليل العقود
with tabs[2]:
self._render_contract_analysis_tab()
- # تبويب تقدير التكاليف
with tabs[3]:
self._render_cost_estimation_tab()
- # تبويب تحليل المخاطر
with tabs[4]:
self._render_risk_analysis_tab()
-
- # تبويب المساعدة
- with tabs[5]:
- self._render_help_tab()
- def _render_home_tab(self):
- """عرض تبويب الرئيسية"""
- st.markdown("### مرحبًا بك في مساعد الذكاء الاصطناعي")
+ def _render_chat_tab(self):
+ """عرض تبويب المحادثة مع الذكاء الاصطناعي"""
+ st.markdown("### المحادثة مع الذكاء الاصطناعي")
st.markdown("""
- يمكنك استخدام هذا المساعد للقيام بالمهام التالية:
-
- - **تحليل المستندات**: تحليل المستندات والتقارير باستخدام الذكاء الاصطناعي
- - **تحليل العقود**: تحليل العقود واستخراج البنود المهمة
- - **تقدير التكاليف**: تقدير تكاليف المشاريع باستخدام نماذج الذكاء الاصطناعي
- - **تحليل المخاطر**: تحليل المخاطر المحتملة في المشاريع
-
- اختر أحد التبويبات أعلاه للبدء.
+ يمكنك استخدام هذه الأداة للتواصل مع نماذج الذكاء الاصطناعي المتقدمة للحصول على المساعدة في:
+ - الاستفسارات حول مشاريع البناء والمقاولات
+ - تحليل بيانات المشاريع
+ - الحصول على توصيات وأفضل الممارسات
+ - حل المشكلات الفنية
+ - أي استفسارات أخرى متعلقة بالمشاريع
""")
- # عرض إحصائيات استخدام التطبيق
- st.markdown("### إحصائيات الاستخدام")
-
- col1, col2, col3, col4 = st.columns(4)
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = st.selectbox(
+ "اختر نموذج الذكاء الاصطناعي:",
+ ["ai", "anthropic"],
+ index=0
+ )
- with col1:
- st.metric(
- label="المستندات المحللة",
- value="125",
- delta="+12 هذا الأسبوع"
- )
+ # عرض سجل المحادثة
+ chat_container = st.container()
+ with chat_container:
+ for message in st.session_state.chat_history:
+ if message["role"] == "user":
+ st.markdown(f"**أنت**: {message['content']}")
+ else:
+ st.markdown(f"**الذكاء الاصطناعي**: {message['content']}")
- with col2:
- st.metric(
- label="العقود المحللة",
- value="78",
- delta="+5 هذا الأسبوع"
- )
+ # إدخال رسالة جديدة
+ with st.form(key="chat_form", clear_on_submit=True):
+ user_input = st.text_area("اكتب رسالتك هنا:", height=100)
+ submit_button = st.form_submit_button("إرسال")
+
+ if submit_button and user_input:
+ # إضافة رسالة المستخدم إلى سجل المحادثة
+ st.session_state.chat_history.append({"role": "user", "content": user_input})
+
+ # الحصول على رد من نموذج الذكاء الاصطناعي
+ with st.spinner("جاري التفكير..."):
+ ai_response = self._get_ai_response(user_input, ai_model)
+
+ # إضافة رد الذكاء الاصطناعي إلى سجل المحادثة
+ st.session_state.chat_history.append({"role": "assistant", "content": ai_response})
+
+ # إعادة تحميل الصفحة لعرض الرسائل الجديدة
+ st.experimental_rerun()
- with col3:
- st.metric(
- label="تقديرات التكلفة",
- value="42",
- delta="+8 هذا الأسبوع"
- )
+ # زر لمسح سجل المحادثة
+ if st.button("مسح المحادثة"):
+ st.session_state.chat_history = []
+ st.experimental_rerun()
+
+ def _get_ai_response(self, user_input, model):
+ """الحصول على رد من نموذج الذكاء الاصطناعي"""
+ try:
+ if model == "ai":
+ # استخدام نموذج ai من هجين فيس
+ api_key = st.session_state.ai_api_key
+ if not api_key:
+ return "لم يتم تكوين مفتاح API لنموذج ai. يرجى تكوين المفتاح في الإعدادات."
+
+ # إعداد سجل المحادثة بتنسيق مناسب لنموذج ai
+ messages = []
+ for message in st.session_state.chat_history:
+ messages.append({
+ "role": message["role"],
+ "content": message["content"]
+ })
+
+ # إضافة الرسالة الحالية
+ messages.append({
+ "role": "user",
+ "content": user_input
+ })
+
+ # استدعاء API
+ headers = {
+ "Authorization": f"Bearer {api_key}",
+ "Content-Type": "application/json"
+ }
+
+ payload = {
+ "model": "gpt-4", # يمكن تغييره حسب النموذج المتاح
+ "messages": messages,
+ "temperature": 0.7
+ }
+
+ response = requests.post(
+ "https://api.openai.com/v1/chat/completions",
+ headers=headers,
+ json=payload
+ )
+
+ if response.status_code == 200:
+ return response.json()["choices"][0]["message"]["content"]
+ else:
+ return f"حدث خطأ أثناء الاتصال بنموذج ai: {response.text}"
+
+ elif model == "anthropic":
+ # استخدام نموذج anthropic من هجين فيس
+ api_key = st.session_state.anthropic_api_key
+ if not api_key:
+ return "لم يتم تكوين مفتاح API لنموذج anthropic. يرجى تكوين المفتاح في الإعدادات."
+
+ # إعداد سجل المحادثة بتنسيق مناسب لنموذج anthropic
+ messages = []
+ for message in st.session_state.chat_history:
+ messages.append({
+ "role": message["role"],
+ "content": message["content"]
+ })
+
+ # إنشاء عميل anthropic
+ client = anthropic.Anthropic(api_key=api_key)
+
+ # استدعاء API
+ response = client.messages.create(
+ model="claude-2", # يمكن تغييره حسب النموذج المتاح
+ max_tokens=1000,
+ temperature=0.7,
+ system="أنت مساعد ذكي متخصص في مجال البناء والمقاولات في المملكة العربية السعودية. تقدم معلومات دقيقة وموثوقة.",
+ messages=messages + [{"role": "user", "content": user_input}]
+ )
+
+ return response.content[0].text
+
+ else:
+ return "النموذج المحدد غير مدعوم."
- with col4:
- st.metric(
- label="تحليلات المخاطر",
- value="36",
- delta="+3 هذا الأسبوع"
- )
+ except Exception as e:
+ return f"حدث خطأ أثناء الاتصال بنموذج الذكاء الاصطناعي: {str(e)}"
def _render_document_analysis_tab(self):
"""عرض تبويب تحليل المستندات"""
@@ -140,8 +237,224 @@ class AIAssistantApp:
- ملفات النصوص TXT
""")
- # إضافة محتوى تبويب تحليل المستندات هنا
- st.info("هذه الميزة قيد التطوير. ستكون متاحة قريبًا.")
+ # إنشاء تبويبات فرعية
+ doc_tabs = st.tabs([
+ "تحميل المستندات",
+ "استخراج النص",
+ "تحليل المحتوى",
+ "الملخص والتوصيات"
+ ])
+
+ # تبويب تحميل المستندات
+ with doc_tabs[0]:
+ st.markdown("#### تحميل المستندات")
+
+ uploaded_file = st.file_uploader(
+ "اختر ملفًا للتحليل (PDF, DOCX, TXT):",
+ type=["pdf", "docx", "txt"],
+ key="document_file_uploader"
+ )
+
+ if uploaded_file:
+ # حفظ الملف المرفوع
+ file_details = {
+ "filename": uploaded_file.name,
+ "filetype": uploaded_file.type,
+ "filesize": uploaded_file.size
+ }
+
+ st.write(f"**تم تحميل الملف:** {file_details['filename']}")
+ st.write(f"**نوع الملف:** {file_details['filetype']}")
+ st.write(f"**حجم الملف:** {file_details['filesize']} بايت")
+
+ # حفظ الملف في الجلسة
+ self.uploaded_files["document"] = uploaded_file
+
+ st.success("تم تحميل الملف بنجاح. انتقل إلى تبويب 'استخراج النص' للمتابعة.")
+
+ # تبويب استخراج النص
+ with doc_tabs[1]:
+ st.markdown("#### استخراج النص")
+
+ if "document" not in self.uploaded_files:
+ st.info("الرجاء تحميل مستند أولاً من تبويب 'تحميل المستندات'.")
+ else:
+ if st.button("استخراج النص من المستند"):
+ with st.spinner("جاري استخراج النص..."):
+ # استخراج النص من الملف
+ extracted_text = self._extract_text_from_file(self.uploaded_files["document"])
+
+ # حفظ النص المستخرج في الجلسة
+ if "analysis_results" not in st.session_state:
+ st.session_state.analysis_results = {}
+
+ st.session_state.analysis_results["extracted_text"] = extracted_text
+
+ # عرض النص المستخرج
+ st.markdown("##### النص المستخرج:")
+ st.text_area("", extracted_text, height=400, disabled=True)
+
+ st.success("تم استخراج النص بنجاح. انتقل إلى تبويب 'تحليل المحتوى' للمتابعة.")
+
+ # إذا كان النص قد تم استخراجه بالفعل
+ if "analysis_results" in st.session_state and "extracted_text" in st.session_state.analysis_results:
+ st.markdown("##### النص المستخرج:")
+ st.text_area("", st.session_state.analysis_results["extracted_text"], height=400, disabled=True)
+
+ # تبويب تحليل المحتوى
+ with doc_tabs[2]:
+ st.markdown("#### تحليل المحتوى")
+
+ if "analysis_results" not in st.session_state or "extracted_text" not in st.session_state.analysis_results:
+ st.info("الرجاء استخراج النص أولاً من تبويب 'استخراج النص'.")
+ else:
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = st.selectbox(
+ "اختر نموذج الذكاء الاصطناعي للتحليل:",
+ ["ai", "anthropic"],
+ index=0,
+ key="doc_analysis_model"
+ )
+
+ analysis_type = st.selectbox(
+ "اختر نوع التحليل:",
+ [
+ "تحليل عام",
+ "استخراج المعلومات الرئيسية",
+ "تحديد الكلمات المفتاحية",
+ "تحليل المتطلبات الفنية",
+ "تحليل التكاليف والأسعار"
+ ]
+ )
+
+ if st.button("تحليل المحتوى"):
+ with st.spinner("جاري تحليل المحتوى..."):
+ # إعداد السؤال بناءً على نوع التحليل
+ if analysis_type == "تحليل عام":
+ prompt = "قم بتحليل النص التالي وتقديم ملخص شامل له:\n\n"
+ elif analysis_type == "استخراج المعلومات الرئيسية":
+ prompt = "استخرج المعلومات الرئيسية والنقاط المهمة من النص التالي:\n\n"
+ elif analysis_type == "تحديد الكلمات المفتاحية":
+ prompt = "حدد الكلمات المفتاحية والمصطلحات المهمة في النص التالي:\n\n"
+ elif analysis_type == "تحليل المتطلبات الفنية":
+ prompt = "استخرج المتطلبات الفنية والمواصفات من النص التالي:\n\n"
+ elif analysis_type == "تحليل التكاليف والأسعار":
+ prompt = "استخرج جميع المعلومات المتعلقة بالتكاليف والأسعار من النص التالي:\n\n"
+
+ # إضافة النص المستخرج إلى السؤال
+ prompt += st.session_state.analysis_results["extracted_text"]
+
+ # الحصول على التحليل من نموذج الذكاء الاصطناعي
+ analysis_result = self._get_ai_response(prompt, ai_model)
+
+ # حفظ نتيجة التحليل في الجلسة
+ st.session_state.analysis_results["content_analysis"] = analysis_result
+
+ # عرض نتيجة التحليل
+ st.markdown("##### نتيجة التحليل:")
+ st.markdown(analysis_result)
+
+ st.success("تم تحليل المحتوى بنجاح. انتقل إلى تبويب 'الملخص والتوصيات' للمتابعة.")
+
+ # إذا كان التحليل قد تم بالفعل
+ if "content_analysis" in st.session_state.analysis_results:
+ st.markdown("##### نتيجة التحليل:")
+ st.markdown(st.session_state.analysis_results["content_analysis"])
+
+ # تبويب الملخص والتوصيات
+ with doc_tabs[3]:
+ st.markdown("#### الملخص والتوصيات")
+
+ if "analysis_results" not in st.session_state or "content_analysis" not in st.session_state.analysis_results:
+ st.info("الرجاء تحليل المحتوى أولاً من تبويب 'تحليل المحتوى'.")
+ else:
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = st.selectbox(
+ "اختر نموذج الذكاء الاصطناعي للتوصيات:",
+ ["ai", "anthropic"],
+ index=0,
+ key="doc_summary_model"
+ )
+
+ if st.button("إنشاء ملخص وتوصيات"):
+ with st.spinner("جاري إنشاء الملخص والتوصيات..."):
+ # إعداد السؤال
+ prompt = f"""
+ بناءً على التحليل التالي للمستند:
+
+ {st.session_state.analysis_results['content_analysis']}
+
+ قم بإنشاء:
+ 1. ملخص موجز للمستند (لا يزيد عن 3 فقرات)
+ 2. النقاط الرئيسية (5-7 نقاط)
+ 3. توصيات عملية (3-5 توصيات)
+ 4. الخطوات التالية المقترحة
+ """
+
+ # الحصول على الملخص والتوصيات من نموذج الذكاء الاصطناعي
+ summary_result = self._get_ai_response(prompt, ai_model)
+
+ # حفظ الملخص والتوصيات في الجلسة
+ st.session_state.analysis_results["summary_recommendations"] = summary_result
+
+ # عرض الملخص والتوصيات
+ st.markdown("##### الملخص والتوصيات:")
+ st.markdown(summary_result)
+
+ # إذا كان الملخص والتوصيات قد تم إنشاؤهما بالفعل
+ if "summary_recommendations" in st.session_state.analysis_results:
+ st.markdown("##### الملخص والتوصيات:")
+ st.markdown(st.session_state.analysis_results["summary_recommendations"])
+
+ # تصدير التقرير
+ report_file_name = f"تحليل_المستند_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
+
+ col1, col2, col3 = st.columns(3)
+
+ with col1:
+ # تصدير كملف PDF
+ report_content = f"""
+ # تقرير تحليل المستند
+
+ **تاريخ التحليل:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+
+ ## النص المستخرج
+ {st.session_state.analysis_results['extracted_text'][:1000]}...
+
+ ## نتيجة التحليل
+ {st.session_state.analysis_results['content_analysis']}
+
+ ## الملخص والتوصيات
+ {st.session_state.analysis_results['summary_recommendations']}
+ """
+
+ st.download_button(
+ label="تصدير التقرير (PDF)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.pdf",
+ mime="application/pdf",
+ key="export_doc_report_pdf"
+ )
+
+ with col2:
+ # تصدير كملف Word
+ st.download_button(
+ label="تصدير التقرير (Word)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.docx",
+ mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ key="export_doc_report_word"
+ )
+
+ with col3:
+ # تصدير كملف نصي
+ st.download_button(
+ label="تصدير التقرير (TXT)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.txt",
+ mime="text/plain",
+ key="export_doc_report_txt"
+ )
def _render_contract_analysis_tab(self):
"""عرض تبويب تحليل العقود"""
@@ -155,8 +468,233 @@ class AIAssistantApp:
- ملفات النصوص TXT
""")
- # إضافة محتوى تبويب تحليل العقود هنا
- st.info("هذه الميزة قيد التطوير. ستكون متاحة قريبًا.")
+ # إنشاء تبويبات فرعية
+ contract_tabs = st.tabs([
+ "تحميل العقد",
+ "استخراج البنود",
+ "تحليل المخاطر",
+ "التقرير النهائي"
+ ])
+
+ # تبويب تحميل العقد
+ with contract_tabs[0]:
+ st.markdown("#### تحميل العقد")
+
+ uploaded_file = st.file_uploader(
+ "اختر ملف العقد للتحليل (PDF, DOCX, TXT):",
+ type=["pdf", "docx", "txt"],
+ key="contract_file_uploader"
+ )
+
+ if uploaded_file:
+ # حفظ الملف المرفوع
+ file_details = {
+ "filename": uploaded_file.name,
+ "filetype": uploaded_file.type,
+ "filesize": uploaded_file.size
+ }
+
+ st.write(f"**تم تحميل الملف:** {file_details['filename']}")
+ st.write(f"**نوع الملف:** {file_details['filetype']}")
+ st.write(f"**حجم الملف:** {file_details['filesize']} بايت")
+
+ # حفظ الملف في الجلسة
+ self.uploaded_files["contract"] = uploaded_file
+
+ st.success("تم تحميل العقد بنجاح. انتقل إلى تبويب 'استخراج البنود' للمتابعة.")
+
+ # تبويب استخراج البنود
+ with contract_tabs[1]:
+ st.markdown("#### استخراج البنود")
+
+ if "contract" not in self.uploaded_files:
+ st.info("الرجاء تحميل عقد أولاً من تبويب 'تحميل العقد'.")
+ else:
+ if st.button("استخراج بنود العقد"):
+ with st.spinner("جاري استخراج بنود العقد..."):
+ # استخراج النص من الملف
+ contract_text = self._extract_text_from_file(self.uploaded_files["contract"])
+
+ # حفظ النص المستخرج في الجلسة
+ if "contract_analysis" not in st.session_state:
+ st.session_state.contract_analysis = {}
+
+ st.session_state.contract_analysis["contract_text"] = contract_text
+
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = "ai" # يمكن تغييره لاستخدام نموذج آخر
+
+ # إعداد السؤال لاستخراج البنود
+ prompt = """
+ استخرج البنود الرئيسية من العقد التالي وصنفها حسب النوع (مثل: بنود مالية، بنود قانونية، بنود فنية، إلخ).
+ لكل بند، قدم:
+ 1. رقم البند (إن وجد)
+ 2. عنوان البند
+ 3. ملخص موجز للبند
+ 4. تصنيف البند
+
+ نص العقد:
+ """
+ prompt += contract_text
+
+ # الحصول على البنود المستخرجة من نموذج الذكاء الاصطناعي
+ clauses_result = self._get_ai_response(prompt, ai_model)
+
+ # حفظ البنود المستخرجة في الجلسة
+ st.session_state.contract_analysis["extracted_clauses"] = clauses_result
+
+ # عرض البنود المستخرجة
+ st.markdown("##### البنود المستخرجة:")
+ st.markdown(clauses_result)
+
+ st.success("تم استخراج بنود العقد بنجاح. انتقل إلى تبويب 'تحليل المخاطر' للمتابعة.")
+
+ # إذا كانت البنود قد تم استخراجها بالفعل
+ if "contract_analysis" in st.session_state and "extracted_clauses" in st.session_state.contract_analysis:
+ st.markdown("##### البنود المستخرجة:")
+ st.markdown(st.session_state.contract_analysis["extracted_clauses"])
+
+ # تبويب تحليل المخاطر
+ with contract_tabs[2]:
+ st.markdown("#### تحليل المخاطر")
+
+ if "contract_analysis" not in st.session_state or "extracted_clauses" not in st.session_state.contract_analysis:
+ st.info("الرجاء استخراج بنود العقد أولاً من تبويب 'استخراج البنود'.")
+ else:
+ if st.button("تحليل المخاطر في العقد"):
+ with st.spinner("جاري تحليل المخاطر..."):
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = "anthropic" # يمكن تغييره لاستخدام نموذج آخر
+
+ # إعداد السؤال لتحليل المخاطر
+ prompt = f"""
+ بناءً على البنود المستخرجة من العقد:
+
+ {st.session_state.contract_analysis['extracted_clauses']}
+
+ قم بتحليل المخاطر المحتملة في هذا العقد، وتصنيفها ��لى:
+ 1. مخاطر عالية (تتطلب اهتمامًا فوريًا)
+ 2. مخاطر متوسطة (تتطلب مراقبة)
+ 3. مخاطر منخفضة (تتطلب وعيًا)
+
+ لكل مخاطرة، قدم:
+ - وصف المخاطرة
+ - البند المرتبط بها
+ - التأثير المحتمل
+ - توصيات للتخفيف من المخاطرة
+ """
+
+ # الحصول على تحليل المخاطر من نموذج الذكاء الاصطناعي
+ risk_analysis = self._get_ai_response(prompt, ai_model)
+
+ # حفظ تحليل المخاطر في الجلسة
+ st.session_state.contract_analysis["risk_analysis"] = risk_analysis
+
+ # عرض تحليل المخاطر
+ st.markdown("##### تحليل المخاطر:")
+ st.markdown(risk_analysis)
+
+ st.success("تم تحليل المخاطر بنجاح. انتقل إلى تبويب 'التقرير النهائي' للمتابعة.")
+
+ # إذا كان تحليل المخاطر قد تم بالفعل
+ if "risk_analysis" in st.session_state.contract_analysis:
+ st.markdown("##### تحليل المخاطر:")
+ st.markdown(st.session_state.contract_analysis["risk_analysis"])
+
+ # تبويب التقرير النهائي
+ with contract_tabs[3]:
+ st.markdown("#### التقرير النهائي")
+
+ if "contract_analysis" not in st.session_state or "risk_analysis" not in st.session_state.contract_analysis:
+ st.info("الرجاء تحليل المخاطر أولاً من تبويب 'تحليل المخاطر'.")
+ else:
+ if st.button("إنشاء التقرير النهائي"):
+ with st.spinner("جاري إنشاء التقرير النهائي..."):
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = "ai" # يمكن تغييره لاستخدام نموذج آخر
+
+ # إعداد السؤال لإنشاء التقرير النهائي
+ prompt = f"""
+ بناءً على تحليل العقد وتحليل المخاطر:
+
+ البنود المستخرجة:
+ {st.session_state.contract_analysis['extracted_clauses']}
+
+ تحليل المخاطر:
+ {st.session_state.contract_analysis['risk_analysis']}
+
+ قم بإنشاء تقرير نهائي يتضمن:
+ 1. ملخص تنفيذي للعقد
+ 2. أهم البنود وتأثيرها
+ 3. ملخص المخاطر الرئيسية
+ 4. التوصيات والاقتراحات
+ 5. الخطوات التالية الموصى بها
+ """
+
+ # الحصول على التقرير النهائي من نموذج الذكاء الاصطناعي
+ final_report = self._get_ai_response(prompt, ai_model)
+
+ # حفظ التقرير النهائي في الجلسة
+ st.session_state.contract_analysis["final_report"] = final_report
+
+ # عرض التقرير النهائي
+ st.markdown("##### التقرير النهائي:")
+ st.markdown(final_report)
+
+ # إذا كان التقرير النهائي قد تم إنشاؤه بالفعل
+ if "final_report" in st.session_state.contract_analysis:
+ st.markdown("##### التقرير النهائي:")
+ st.markdown(st.session_state.contract_analysis["final_report"])
+
+ # تصدير التقرير
+ report_file_name = f"تحليل_العقد_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
+
+ col1, col2, col3 = st.columns(3)
+
+ with col1:
+ # تصدير كملف PDF
+ report_content = f"""
+ # تقرير تحليل العقد
+
+ **ت��ريخ التحليل:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+
+ ## البنود المستخرجة
+ {st.session_state.contract_analysis['extracted_clauses']}
+
+ ## تحليل المخاطر
+ {st.session_state.contract_analysis['risk_analysis']}
+
+ ## التقرير النهائي
+ {st.session_state.contract_analysis['final_report']}
+ """
+
+ st.download_button(
+ label="تصدير التقرير (PDF)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.pdf",
+ mime="application/pdf",
+ key="export_contract_report_pdf"
+ )
+
+ with col2:
+ # تصدير كملف Word
+ st.download_button(
+ label="تصدير التقرير (Word)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.docx",
+ mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ key="export_contract_report_word"
+ )
+
+ with col3:
+ # تصدير كملف نصي
+ st.download_button(
+ label="تصدير التقرير (TXT)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.txt",
+ mime="text/plain",
+ key="export_contract_report_txt"
+ )
def _render_cost_estimation_tab(self):
"""عرض تبويب تقدير التكاليف باستخدام نماذج هجين فيس"""
@@ -187,908 +725,380 @@ class AIAssistantApp:
with cost_tabs[0]:
st.markdown("#### تحميل ملفات المشروع")
- # دعم تحميل أنواع متعددة من الملفات
uploaded_files = st.file_uploader(
- "قم بتحميل ملفات المشروع (يمكن اختيار أكثر من ملف)",
+ "اختر ملفات المشروع للتحليل:",
type=["pdf", "dwg", "xlsx", "xls", "docx", "doc", "txt", "png", "jpg", "jpeg"],
accept_multiple_files=True,
- key="cost_estimation_files"
+ key="cost_files_uploader"
)
if uploaded_files:
- st.success(f"تم تحميل {len(uploaded_files)} ملفات بنجاح")
+ # حفظ الملفات المرفوعة
+ if "cost_files" not in st.session_state:
+ st.session_state.cost_files = []
- # عرض قائمة الملفات المحملة
- st.markdown("#### الملفات المحملة:")
- for i, file in enumerate(uploaded_files):
+ for uploaded_file in uploaded_files:
file_details = {
- "اسم الملف": file.name,
- "نوع الملف": file.type if file.type else "غير محدد",
- "حجم الملف": f"{file.size / 1024:.2f} كيلوبايت"
+ "filename": uploaded_file.name,
+ "filetype": uploaded_file.type,
+ "filesize": uploaded_file.size,
+ "file": uploaded_file
}
- with st.expander(f"{i+1}. {file.name}"):
- st.json(file_details)
+ # إضافة الملف إلى القائمة إذا لم يكن موجودًا بالفعل
+ if not any(f["filename"] == file_details["filename"] for f in st.session_state.cost_files):
+ st.session_state.cost_files.append(file_details)
- # زر تحليل الملفات
- if st.button("تحليل الملفات", key="analyze_cost_files_button"):
- with st.spinner("جاري تحليل الملفات..."):
- # محاكاة تقدم التحليل
- progress_bar = st.progress(0)
- for i in range(100):
- time.sleep(0.02)
- progress_bar.progress(i + 1)
-
- st.success("تم تحليل الملفات بنجاح!")
-
- # حفظ ن��ائج التحليل في حالة الجلسة
- if 'analyzed_files' not in st.session_state:
- st.session_state.analyzed_files = []
-
- # إضافة الملفات المحللة إلى حالة الجلسة
- for file in uploaded_files:
- file_info = {
- "name": file.name,
- "type": file.type if file.type else self._detect_file_type(file.name),
- "size": file.size,
- "analyzed": True,
- "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- }
- st.session_state.analyzed_files.append(file_info)
-
- # عرض رسالة تأكيد
- st.markdown(f"**تم تحليل {len(uploaded_files)} ملفات بنجاح. يمكنك الآن الانتقال إلى تبويب 'تقدير التكاليف' للحصول على التقديرات.**")
-
- # تبويب تقدير التكاليف
- with cost_tabs[1]:
- st.markdown("#### تقدير التكاليف باستخدام الذكاء الاصطناعي")
-
- # التحقق من وجود ملفات محللة
- if 'analyzed_files' in st.session_state and st.session_state.analyzed_files:
- # اختيار نموذج الذكاء الاصطناعي
- ai_model = st.radio(
- "اختر نموذج الذكاء الاصطناعي:",
- options=["ai (OpenAI)", "anthropic (Claude)"],
- horizontal=True,
- key="cost_ai_model_selector"
- )
-
- st.markdown("#### إعدادات التقدير")
-
- # إعدادات المشروع
- col1, col2 = st.columns(2)
- with col1:
- project_type = st.selectbox(
- "نوع المشروع:",
- options=["مبنى سكني", "مبنى تجاري", "مبنى حكومي", "بنية تحتية", "طرق", "جسور", "أنفاق", "أخرى"],
- key="project_type_selector"
- )
-
- project_location = st.selectbox(
- "موقع المشروع:",
- options=["الرياض", "جدة", "الدمام", "مكة", "المدينة", "تبوك", "أبها", "الخبر", "الطائف", "أخرى"],
- key="project_location_selector"
- )
+ # عرض الملفات المرفوعة
+ st.markdown("##### الملفات المرفوعة:")
- with col2:
- project_size = st.number_input(
- "حجم المشروع (متر مربع):",
- min_value=100,
- max_value=1000000,
- value=5000,
- step=100,
- key="project_size_input"
- )
+ for i, file in enumerate(st.session_state.cost_files):
+ col1, col2, col3, col4 = st.columns([3, 2, 2, 1])
- project_duration = st.number_input(
- "مدة المشروع (شهر):",
- min_value=1,
- max_value=60,
- value=12,
- step=1,
- key="project_duration_input"
- )
-
- # إعدادات متقدمة
- with st.expander("إعدادات متقدمة"):
- quality_level = st.select_slider(
- "مستوى الجودة:",
- options=["اقتصادي", "متوسط", "عالي", "ممتاز"],
- value="متوسط",
- key="quality_level_slider"
- )
+ with col1:
+ st.write(f"{i+1}. {file['filename']}")
- include_contingency = st.checkbox(
- "تضمين احتياطي للطوارئ (10%)",
- value=True,
- key="include_contingency_checkbox"
- )
+ with col2:
+ st.write(f"النوع: {self._detect_file_type(file['filename'])}")
- include_inflation = st.checkbox(
- "تضمين معدل التضخم",
- value=True,
- key="include_inflation_checkbox"
- )
+ with col3:
+ st.write(f"الحجم: {file['filesize']} بايت")
- if include_inflation:
- inflation_rate = st.slider(
- "معدل التضخم السنوي (%):",
- min_value=1.0,
- max_value=10.0,
- value=3.5,
- step=0.5,
- key="inflation_rate_slider"
- )
+ with col4:
+ if st.button("حذف", key=f"delete_file_{i}"):
+ st.session_state.cost_files.pop(i)
+ st.experimental_rerun()
- # زر تقدير التكاليف
- if st.button("تقدير التكاليف", key="estimate_costs_button"):
- with st.spinner(f"جاري تقدير التكاليف باستخدام نموذج {ai_model}..."):
- # محاكاة استدعاء نموذج هجين فيس
- try:
- # هنا سيتم استدعاء النموذج المحدد من بيئة هجين فيس
- # في التنفيذ الفعلي، سيتم استبدال هذا الكود بالاستدعاء الحقيقي للنموذج
-
- # محاكاة تقدم العملية
- progress_bar = st.progress(0)
- for i in range(100):
- time.sleep(0.02)
- progress_bar.progress(i + 1)
-
- # حساب التكلفة التقديرية (محاكاة)
- base_cost_per_sqm = {
- "مبنى سكني": 2500,
- "مبنى تجاري": 3000,
- "مبنى حكومي": 3500,
- "بنية تحتية": 4000,
- "طرق": 2000,
- "جسور": 5000,
- "أنفاق": 7000,
- "أخرى": 3000
- }
-
- quality_factor = {
- "اقتصادي": 0.8,
- "متوسط": 1.0,
- "عالي": 1.2,
- "ممتاز": 1.5
- }
-
- location_factor = {
- "الرياض": 1.1,
- "جدة": 1.15,
- "الدمام": 1.05,
- "مكة": 1.2,
- "المدينة": 1.1,
- "تبوك": 1.0,
- "أبها": 0.95,
- "الخبر": 1.05,
- "الطائف": 0.9,
- "أخرى": 1.0
- }
-
- # حساب التكلفة الأساسية
- base_cost = base_cost_per_sqm[project_type] * project_size * quality_factor[quality_level] * location_factor[project_location]
-
- # إضافة احتياطي الطوارئ إذا تم اختياره
- if include_contingency:
- contingency_amount = base_cost * 0.1
- else:
- contingency_amount = 0
-
- # إضافة التضخم إذا تم اختياره
- if include_inflation:
- inflation_amount = base_cost * (inflation_rate / 100) * (project_duration / 12)
- else:
- inflation_amount = 0
-
- # حساب التكلفة الإجمالية
- total_cost = base_cost + contingency_amount + inflation_amount
-
- # عرض نتائج التقدير
- st.success("تم تقدير التكاليف بنجاح!")
-
- # عرض ملخص التكاليف
- st.markdown("### ملخص تقدير التكاليف")
-
- col1, col2 = st.columns(2)
-
- with col1:
- st.metric(
- label="التكلفة ��لأساسية",
- value=f"{base_cost:,.2f} ريال سعودي",
- delta=f"{base_cost/project_size:,.2f} ريال/م²"
- )
-
- if include_contingency:
- st.metric(
- label="احتياطي الطوارئ (10%)",
- value=f"{contingency_amount:,.2f} ريال سعودي"
- )
-
- with col2:
- if include_inflation:
- st.metric(
- label=f"تكلفة التضخم ({inflation_rate}% سنوياً)",
- value=f"{inflation_amount:,.2f} ريال سعودي"
- )
-
- st.metric(
- label="التكلفة الإجمالية",
- value=f"{total_cost:,.2f} ريال سعودي",
- delta=f"{total_cost/project_size:,.2f} ريال/م²"
- )
-
- # عرض تفاصيل التكاليف
- st.markdown("### تفاصيل التكاليف")
-
- # إنشاء بيانات تفصيلية للتكاليف (محاكاة)
- cost_breakdown = {
- "الأعمال الإنشائية": total_cost * 0.35,
- "الأعمال المعمارية": total_cost * 0.25,
- "الأعمال الكهربائية": total_cost * 0.15,
- "الأعمال الميكانيكية": total_cost * 0.12,
- "أعمال الموقع والتجهيزات": total_cost * 0.08,
- "أخرى": total_cost * 0.05
- }
-
- # عرض مخطط دائري للتكاليف
- fig = px.pie(
- values=list(cost_breakdown.values()),
- names=list(cost_breakdown.keys()),
- title="توزيع التكاليف حسب نوع العمل"
- )
- st.plotly_chart(fig, use_container_width=True)
-
- # عرض جدول تفصيلي للتكاليف
- cost_df = pd.DataFrame({
- "نوع العمل": list(cost_breakdown.keys()),
- "التكلفة (ريال سعودي)": list(cost_breakdown.values()),
- "النسبة (%)": [v/total_cost*100 for v in cost_breakdown.values()]
- })
-
- st.dataframe(cost_df.style.format({
- "التكلفة (ريال سعودي)": "{:,.2f}",
- "النسبة (%)": "{:.2f}%"
- }))
-
- # إضافة زر لتصدير التقرير
- col1, col2 = st.columns(2)
- with col1:
- st.download_button(
- label="تصدير التقرير (PDF)",
- data="تقرير تقدير التكاليف".encode('utf-8'),
- file_name=f"تقرير_تقدير_التكاليف_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf",
- mime="application/pdf",
- key="export_cost_report_pdf"
- )
-
- with col2:
- st.download_button(
- label="تصدير البيانات (Excel)",
- data="بيانات تقدير التكاليف".encode('utf-8'),
- file_name=f"بيانات_تقدير_التكاليف_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx",
- mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- key="export_cost_data_excel"
- )
-
- except Exception as e:
- st.error(f"حدث خطأ أثناء تقدير التكاليف: {str(e)}")
- st.markdown("""
- **ملاحظة**: قد يكون هناك تعارض بين حزم pydantic و anthropic.
- إذا كنت تستخدم نموذج anthropic، تأكد من تثبيت إصدار متوافق من pydantic (أقل من 2.0.0)
- أو استخدم إصدارًا محدثًا من anthropic يدعم pydantic 2.x.
- """)
- else:
- st.info("الرجاء تحميل وتحليل ملفات المشروع أولاً من تبويب 'تحميل الملفات'.")
+ st.success(f"تم تحميل {len(st.session_state.cost_files)} ملف بنجاح. انتقل إلى تبويب 'تقدير التكاليف' للمتابعة.")
- # تبويب تحليل البنود
- with cost_tabs[2]:
- st.markdown("#### تحليل بنود المشروع")
+ # تبويب تقدير التكاليف
+ with cost_tabs[1]:
+ st.markdown("#### تقدير التكاليف")
- # التحقق من وجود ملفات محللة
- if 'analyzed_files' in st.session_state and st.session_state.analyzed_files:
- # إنشاء بيانات افتراضية لبنود المشروع
- if 'project_items' not in st.session_state:
- st.session_state.project_items = [
- {"id": 1, "code": "01-001", "description": "أعمال الحفر والردم", "unit": "م³", "quantity": 5000, "unit_price": 35, "total": 175000},
- {"id": 2, "code": "01-002", "description": "أعمال الخرسانة العادية", "unit": "م³", "quantity": 1200, "unit_price": 450, "total": 540000},
- {"id": 3, "code": "01-003", "description": "أعمال الخرسانة المسلحة", "unit": "م³", "quantity": 2500, "unit_price": 850, "total": 2125000},
- {"id": 4, "code": "02-001", "description": "أعمال البلوك", "unit": "م²", "quantity": 3500, "unit_price": 120, "total": 420000},
- {"id": 5, "code": "02-002", "description": "أعمال اللياسة", "unit": "م²", "quantity": 7000, "unit_price": 45, "total": 315000},
- {"id": 6, "code": "02-003", "description": "أعمال البلاط", "unit": "م²", "quantity": 4500, "unit_price": 180, "total": 810000},
- {"id": 7, "code": "03-001", "description": "أعمال التمديدات الكهربائية", "unit": "نقطة", "quantity": 350, "unit_price": 250, "total": 87500},
- {"id": 8, "code": "03-002", "description": "أعمال الإنارة", "unit": "وحدة", "quantity": 200, "unit_price": 350, "total": 70000},
- {"id": 9, "code": "04-001", "description": "أعمال التمديدات الصحية", "unit": "نقطة", "quantity": 120, "unit_price": 450, "total": 54000},
- {"id": 10, "code": "04-002", "description": "أعمال التكييف", "unit": "وحدة", "quantity": 50, "unit_price": 3500, "total": 175000}
- ]
-
- # عرض جدول البنود
- st.markdown("#### بنود المشروع")
-
- # تحويل البنود إلى DataFrame
- items_df = pd.DataFrame(st.session_state.project_items)
-
- # عرض الجدول مع تنسيق
- st.dataframe(
- items_df.style.format({
- "unit_price": "{:,.2f}",
- "total": "{:,.2f}"
- }),
- use_container_width=True,
- hide_index=True
- )
-
- # تحليل البنود
- st.markdown("#### تحليل البنود")
+ if "cost_files" not in st.session_state or not st.session_state.cost_files:
+ st.info("الرجاء تحميل ملفات المشروع أولاً من تبويب 'تحميل الملفات'.")
+ else:
+ # معلومات المشروع
+ st.markdown("##### معلومات المشروع")
col1, col2 = st.columns(2)
with col1:
- # عرض إجمالي التكلفة
- total_cost = sum(item["total"] for item in st.session_state.project_items)
- st.metric(
- label="إجمالي التكلفة",
- value=f"{total_cost:,.2f} ريال سعودي"
- )
-
- # عرض عدد البنود
- st.metric(
- label="عدد البنود",
- value=len(st.session_state.project_items)
- )
+ project_name = st.text_input("اسم المشروع:", key="project_name")
+ project_location = st.text_input("موقع المشروع:", key="project_location")
with col2:
- # عرض متوسط تكلفة البند
- avg_item_cost = total_cost / len(st.session_state.project_items)
- st.metric(
- label="متوسط تكلفة البند",
- value=f"{avg_item_cost:,.2f} ريال سعودي"
+ project_type = st.selectbox(
+ "نوع المشروع:",
+ [
+ "سكني",
+ "تجاري",
+ "صناعي",
+ "بنية تحتية",
+ "طرق",
+ "أخرى"
+ ],
+ key="project_type"
)
- # عرض أعلى بند من حيث التكلفة
- max_item = max(st.session_state.project_items, key=lambda x: x["total"])
- st.metric(
- label="أعلى بند من حيث التكلفة",
- value=f"{max_item['total']:,.2f} ريال سعودي",
- delta=max_item["description"]
- )
-
- # عرض مخطط شريطي للبنود حسب التكلفة
- st.markdown("#### توزيع التكاليف حسب البنود")
-
- # إنشاء DataFrame للمخطط
- chart_df = pd.DataFrame({
- "البند": [item["description"] for item in st.session_state.project_items],
- "التكلفة": [item["total"] for item in st.session_state.project_items]
- })
-
- # ترتيب البيانات تنازلياً حسب التكلفة
- chart_df = chart_df.sort_values("التكلفة", ascending=False)
+ project_area = st.number_input("مساحة المشروع (م²):", min_value=0, key="project_area")
- # إنشاء المخطط الشريطي
- fig = px.bar(
- chart_df,
- x="البند",
- y="التكلفة",
- title="توزيع التكاليف حسب البنود",
- labels={"البند": "البند", "التكلفة": "التكلفة (ريال سعودي)"}
- )
-
- # تعديل المخطط
- fig.update_layout(
- xaxis_tickangle=-45,
- yaxis=dict(title="التكلفة (ريال سعودي)")
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = st.selectbox(
+ "اختر نموذج الذكاء الاصطناعي للتقدير:",
+ ["ai", "anthropic"],
+ index=0,
+ key="cost_estimation_model"
)
- # عرض المخطط
- st.plotly_chart(fig, use_container_width=True)
-
- # تحليل البنود حسب الفئة
- st.markdown("#### تحليل البنود حسب الفئة")
+ if st.button("تقدير التكاليف"):
+ with st.spinner("جاري تقدير التكاليف..."):
+ # استخراج النصوص من الملفات
+ all_texts = []
+
+ for file_info in st.session_state.cost_files:
+ try:
+ text = self._extract_text_from_file(file_info["file"])
+ all_texts.append(f"من ملف {file_info['filename']}:\n{text[:2000]}") # أخذ أول 2000 حرف من كل ملف
+ except Exception as e:
+ st.warning(f"تعذر استخراج النص من الملف {file_info['filename']}: {str(e)}")
+
+ combined_text = "\n\n".join(all_texts)
+
+ # إعداد السؤال لتقدير التكاليف
+ prompt = f"""
+ أنت خبير في تقدير تكاليف مشاريع البناء والمقاولات في المملكة العربية السعودية.
+
+ معلومات المشروع:
+ - اسم المشروع: {project_name}
+ - موقع المشروع: {project_location}
+ - نوع المشروع: {project_type}
+ - مساحة المشروع: {project_area} م²
+
+ بناءً على المعلومات التالية المستخرجة من ملفات المشروع، قم بتقدير:
+ 1. التكلفة الإجمالية التقديرية للمشروع
+ 2. تفصيل التكاليف حسب البنود الرئيسية (مواد، عمالة، معدات، إلخ)
+ 3. تكلفة المتر المربع
+ 4. المدة الزمنية المتوقعة للتنفيذ
+ 5. العوامل التي قد تؤثر على التكلفة
+
+ المعلومات المستخرجة من الملفات:
+ {combined_text}
+
+ قدم النتائج بتنسيق منظم وواضح، مع تفصيل الافتراضات التي اعتمدت عليها في التقدير.
+ """
+
+ # الحصول على تقدير التكاليف من نموذج الذكاء الاصطناعي
+ cost_estimation = self._get_ai_response(prompt, ai_model)
+
+ # حفظ تقدير التكاليف في الجلسة
+ if "cost_analysis" not in st.session_state:
+ st.session_state.cost_analysis = {}
+
+ st.session_state.cost_analysis["cost_estimation"] = cost_estimation
+
+ # عرض تقدير التكاليف
+ st.markdown("##### نتيجة تقدير التكاليف:")
+ st.markdown(cost_estimation)
+
+ st.success("تم تقدير التكاليف بنجاح. انتقل إلى تبويب 'تحليل البنود' للمتابعة.")
- # تصنيف البنود حسب الكود
- categories = {}
- for item in st.session_state.project_items:
- category_code = item["code"].split("-")[0]
- category_name = {
- "01": "الأعمال الإنشائية",
- "02": "الأعمال المعمارية",
- "03": "الأعمال الكهربائية",
- "04": "الأعمال الميكانيكية"
- }.get(category_code, "أخرى")
+ # إذا كان تقدير التكاليف قد تم بالفعل
+ if "cost_analysis" in st.session_state and "cost_estimation" in st.session_state.cost_analysis:
+ st.markdown("##### نتيجة تقدير التكاليف:")
+ st.markdown(st.session_state.cost_analysis["cost_estimation"])
- if category_name not in categories:
- categories[category_name] = 0
+ # تصدير التقرير
+ report_file_name = f"تقدير_التكاليف_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
- categories[category_name] += item["total"]
-
- # إنشاء DataFrame للمخطط
- category_df = pd.DataFrame({
- "الفئة": list(categories.keys()),
- "التكلفة": list(categories.values())
- })
-
- # إنشاء المخطط الدائري
- fig = px.pie(
- category_df,
- values="التكلفة",
- names="الفئة",
- title="توزيع التكاليف حسب الفئة"
- )
-
- # عرض المخطط
- st.plotly_chart(fig, use_container_width=True)
+ col1, col2 = st.columns(2)
+
+ with col1:
+ # تصدير كملف PDF
+ report_content = f"""
+ # تقرير تقدير التكاليف
+
+ **تاريخ التقدير:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+
+ ## معلومات المشروع
+ - **اسم المشروع:** {project_name}
+ - **موقع المشروع:** {project_location}
+ - **نوع المشروع:** {project_type}
+ - **مساحة المشروع:** {project_area} م²
+
+ ## نتيجة تقدير التكاليف
+ {st.session_state.cost_analysis['cost_estimation']}
+ """
+
+ st.download_button(
+ label="تصدير التقرير (PDF)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.pdf",
+ mime="application/pdf",
+ key="export_cost_report_pdf"
+ )
+
+ with col2:
+ # تصدير كملف Excel
+ st.download_button(
+ label="تصدير البيانات (Excel)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.xlsx",
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ key="export_cost_report_excel"
+ )
+
+ # تبويب تحليل البنود
+ with cost_tabs[2]:
+ st.markdown("#### تحليل البنود")
+
+ if "cost_analysis" not in st.session_state or "cost_estimation" not in st.session_state.cost_analysis:
+ st.info("الرجاء تقدير التكاليف أولاً من تبويب 'تقدير التكاليف'.")
else:
- st.info("الرجاء تحميل وتحليل ملفات المشروع أولاً من تبويب 'تحميل الملفات'.")
+ if st.button("تحليل بنود التكاليف"):
+ with st.spinner("جاري تحليل البنود..."):
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = "anthropic" # يمكن تغييره لاستخدام نموذج آخر
+
+ # إعداد السؤال لتحليل البنود
+ prompt = f"""
+ بناءً على تقدير التكاليف التالي:
+
+ {st.session_state.cost_analysis['cost_estimation']}
+
+ قم بتحليل بنود التكاليف بالتفصيل:
+ 1. استخرج جميع بنود التكاليف وقيمها
+ 2. صنف البنود حسب النوع (مواد، عمالة، معدات، إلخ)
+ 3. حدد البنود ذات التكلفة الأعلى والتي تشكل نسبة كبيرة من التكلفة الإجمالية
+ 4. اقترح بدائل أو طرق لتقليل تكلفة البنود الرئيسية
+ 5. قدم توصيات لتحسين كفاءة التكلفة
+
+ قدم النتائج بتنسيق جدولي منظم وواضح.
+ """
+
+ # الحصول على تحليل البنود من نموذج الذكاء الاصطناعي
+ items_analysis = self._get_ai_response(prompt, ai_model)
+
+ # حفظ تحليل البنود في الجلسة
+ st.session_state.cost_analysis["items_analysis"] = items_analysis
+
+ # عرض تحليل البنود
+ st.markdown("##### نتيجة تحليل البنود:")
+ st.markdown(items_analysis)
+
+ st.success("تم تحليل البنود بنجاح. انتقل إلى تبويب 'المقارنة مع السوق' للمتابعة.")
+
+ # إذا كان تحليل البنود قد تم بالفعل
+ if "items_analysis" in st.session_state.cost_analysis:
+ st.markdown("##### نتيجة تحليل البنود:")
+ st.markdown(st.session_state.cost_analysis["items_analysis"])
# تبويب المقارنة مع السوق
with cost_tabs[3]:
- st.markdown("#### مقارنة التكاليف مع السوق")
+ st.markdown("#### المقارنة مع السوق")
- # التحقق من وجود ملفات محللة
- if 'analyzed_files' in st.session_state and st.session_state.analyzed_files:
- # إنشاء بيانات افتراضية لأسعار السوق
- market_prices = {
- "الخرسانة المسلحة (م³)": {
- "السعر المقدر": 850,
- "متوسط السوق": 900,
- "الحد الأدنى": 800,
- "الحد الأقصى": 1000,
- "الفرق (%)": -5.56
- },
- "البلوك (م²)": {
- "السعر المقدر": 120,
- "متوسط السوق": 115,
- "الحد الأدنى": 100,
- "الحد الأقصى": 130,
- "الفرق (%)": 4.35
- },
- "اللياسة (م²)": {
- "السعر المقدر": 45,
- "متوسط السوق": 50,
- "الحد الأدنى": 40,
- "الحد الأقصى": 60,
- "الفرق (%)": -10.00
- },
- "البلاط (م²)": {
- "السعر المقدر": 180,
- "متوسط السوق": 175,
- "الحد الأدنى": 150,
- "الحد الأقصى": 200,
- "الفرق (%)": 2.86
- },
- "التمديدات الكهربائية (نقطة)": {
- "السعر المقدر": 250,
- "متوسط السوق": 275,
- "الحد الأدنى": 225,
- "الحد الأقصى": 325,
- "الفرق (%)": -9.09
- }
- }
-
- # تحويل البيانات إلى DataFrame
- market_df = pd.DataFrame(market_prices).T.reset_index()
- market_df.columns = ["البند", "السعر المقدر", "متوسط السوق", "الحد الأدنى", "الحد الأقصى", "الفرق (%)"]
-
- # عرض جدول المقارنة
- st.markdown("#### مقارنة الأسعار مع السوق")
- st.dataframe(
- market_df.style.format({
- "السعر المقدر": "{:,.2f}",
- "متوسط السوق": "{:,.2f}",
- "الحد الأدنى": "{:,.2f}",
- "الحد الأقصى": "{:,.2f}",
- "الفرق (%)": "{:+.2f}%"
- }).background_gradient(
- cmap="RdYlGn",
- subset=["الفرق (%)"],
- vmin=-15,
- vmax=15
- ),
- use_container_width=True,
- hide_index=True
- )
-
- # عرض مخطط المقارنة
- st.markdown("#### مقارنة الأسعار المقدرة مع متوسط السوق")
-
- # إنشاء DataFrame للمخطط
- chart_df = pd.DataFrame({
- "البند": market_df["البند"],
- "السعر المقدر": market_df["السعر المقدر"],
- "متوسط السوق": market_df["متوسط السوق"]
- })
-
- # تحويل البيانات إلى الشكل المناسب للمخطط
- chart_df_melted = pd.melt(
- chart_df,
- id_vars=["البند"],
- value_vars=["السعر المقدر", "متوسط السوق"],
- var_name="النوع",
- value_name="السعر"
- )
-
- # إنشاء المخطط
- fig = px.bar(
- chart_df_melted,
- x="البند",
- y="السعر",
- color="النوع",
- barmode="group",
- title="مقارنة الأسعار المقدرة مع متوسط السوق",
- labels={"البند": "البند", "السعر": "السعر (ريال سعودي)", "النوع": ""}
- )
-
- # تعديل المخطط
- fig.update_layout(
- xaxis_tickangle=-45,
- yaxis=dict(title="السعر (ريال سعودي)")
- )
-
- # عرض المخطط
- st.plotly_chart(fig, use_container_width=True)
-
- # عرض نطاق الأسعار في السوق
- st.markdown("#### نطاق الأسعار في السوق")
-
- # إنشاء مخطط نطاق الأسعار
- fig = go.Figure()
-
- for i, row in market_df.iterrows():
- fig.add_trace(go.Scatter(
- x=[row["البند"], row["البند"]],
- y=[row["الحد الأدنى"], row["الحد الأقصى"]],
- mode="lines",
- line=dict(width=2, color="rgba(0,0,255,0.3)"),
- showlegend=False
- ))
-
- fig.add_trace(go.Scatter(
- x=[row["البند"]],
- y=[row["متوسط السوق"]],
- mode="markers",
- marker=dict(size=10, color="blue"),
- name="متوسط السوق" if i == 0 else None,
- showlegend=i == 0
- ))
-
- fig.add_trace(go.Scatter(
- x=[row["البند"]],
- y=[row["السعر المقدر"]],
- mode="markers",
- marker=dict(size=10, color="red"),
- name="السعر المقدر" if i == 0 else None,
- showlegend=i == 0
- ))
-
- # تعديل المخطط
- fig.update_layout(
- title="نطاق الأسعار في السوق",
- xaxis_title="البند",
- yaxis_title="السعر (ريال سعودي)",
- xaxis_tickangle=-45
- )
-
- # عرض المخطط
- st.plotly_chart(fig, use_container_width=True)
-
- # تحليل الفروقات
- st.markdown("#### تحليل الفروقات عن متوسط السوق")
-
- # حساب متوسط الفرق
- avg_diff = market_df["الفرق (%)"].mean()
-
- # عرض متوسط الفرق
- st.metric(
- label="متوسط الفرق عن السوق",
- value=f"{avg_diff:.2f}%",
- delta=f"{'أقل' if avg_diff < 0 else 'أعلى'} من متوسط السوق"
- )
-
- # تصنيف البنود حسب الفرق
- lower_items = market_df[market_df["الفرق (%)"] < -5]
- higher_items = market_df[market_df["الفرق (%)"] > 5]
-
- col1, col2 = st.columns(2)
-
- with col1:
- st.markdown("##### بنود أقل من متوسط السوق بأكثر من 5%")
- if not lower_items.empty:
- st.dataframe(
- lower_items[["البند", "السعر المقدر", "متوسط السوق", "الفرق (%)"]].style.format({
- "السعر المقدر": "{:,.2f}",
- "متوسط السوق": "{:,.2f}",
- "الفرق (%)": "{:+.2f}%"
- }),
- use_container_width=True,
- hide_index=True
- )
- else:
- st.info("لا توجد بنود أقل من متوسط السوق بأكثر من 5%")
-
- with col2:
- st.markdown("##### بنود أعلى من متوسط السوق بأكثر من 5%")
- if not higher_items.empty:
- st.dataframe(
- higher_items[["البند", "السعر المقدر", "متوسط السوق", "الفرق (%)"]].style.format({
- "السعر المقدر": "{:,.2f}",
- "متوسط السوق": "{:,.2f}",
- "الفرق (%)": "{:+.2f}%"
- }),
- use_container_width=True,
- hide_index=True
- )
- else:
- st.info("لا توجد بنود أعلى من متوسط السوق بأكثر من 5%")
+ if "cost_analysis" not in st.session_state or "items_analysis" not in st.session_state.cost_analysis:
+ st.info("الرجاء تحليل البنود أولاً من تبويب 'تحليل البنود'.")
else:
- st.info("الرجاء تحميل وتحليل ملفات المشروع أولاً من تبويب 'تحميل الملفات'.")
+ if st.button("مقارنة التكاليف مع السوق"):
+ with st.spinner("جاري مقارنة التكاليف مع السوق..."):
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = "ai" # يمكن تغييره لاستخدام نموذج آخر
+
+ # إعداد السؤال للمقارنة مع السوق
+ prompt = f"""
+ أنت خبير في أسعار مواد البناء والمقاولات في المملكة العربية السعودية.
+
+ بناءً على تقدير التكاليف وتحليل البنود ال��اليين:
+
+ تقدير التكاليف:
+ {st.session_state.cost_analysis['cost_estimation']}
+
+ تحليل البنود:
+ {st.session_state.cost_analysis['items_analysis']}
+
+ قم بمقارنة هذه التكاليف مع متوسط أسعار السوق السعودي الحالية (2025):
+ 1. قارن تكلفة المتر المربع مع متوسط السوق للمشاريع المماثلة
+ 2. قارن أسعار المواد الرئيسية (الخرسانة، حديد التسليح، الإسمنت، إلخ) مع أسعار السوق
+ 3. قارن تكاليف العمالة مع متوسط السوق
+ 4. حدد البنود التي تختلف تكلفتها بشكل كبير عن متوسط السوق (أعلى أو أقل)
+ 5. قدم توصيات للحصول على أفضل الأسعار
+
+ استخدم بيانات حقيقية عن أسعار السوق السعودي الحالية قدر الإمكان.
+ """
+
+ # الحصول على المقارنة مع السوق من نموذج الذكاء الاصطناعي
+ market_comparison = self._get_ai_response(prompt, ai_model)
+
+ # حفظ المقارنة مع السوق في الجلسة
+ st.session_state.cost_analysis["market_comparison"] = market_comparison
+
+ # عرض المقارنة مع السوق
+ st.markdown("##### نتيجة المقارنة مع السوق:")
+ st.markdown(market_comparison)
+
+ st.success("تمت المقارنة مع السوق بنجاح. انتقل إلى تبويب 'التقارير' للمتابعة.")
+
+ # إذا كانت المقارنة مع السوق قد تمت بالفعل
+ if "market_comparison" in st.session_state.cost_analysis:
+ st.markdown("##### نتيجة المقارنة مع السوق:")
+ st.markdown(st.session_state.cost_analysis["market_comparison"])
# تبويب التقارير
with cost_tabs[4]:
- st.markdown("#### تقارير تقدير التكاليف")
+ st.markdown("#### التقارير")
- # التحقق من وجود ملفات محللة
- if 'analyzed_files' in st.session_state and st.session_state.analyzed_files:
- # أنواع التقارير
- report_type = st.selectbox(
- "اختر نوع التقرير:",
- options=[
- "تقرير ملخص التكاليف",
- "تقرير تفصيلي للبنود",
- "تقرير المقارنة مع السوق",
- "تقرير تحليل المخاطر",
- "تقرير شامل"
- ],
- key="cost_report_type_selector"
- )
+ if "cost_analysis" not in st.session_state or "market_comparison" not in st.session_state.cost_analysis:
+ st.info("الرجاء مقارنة التكاليف مع السوق أولاً من تبويب 'المقارنة مع السوق'.")
+ else:
+ if st.button("إنشاء التقرير النهائي"):
+ with st.spinner("جاري إنشاء التقرير النهائي..."):
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = "anthropic" # يمكن تغييره لاستخدام نموذج آخر
+
+ # إعداد السؤال لإنشاء التقرير النهائي
+ prompt = f"""
+ بناءً على التحليلات التالية:
+
+ تقدير التكاليف:
+ {st.session_state.cost_analysis['cost_estimation']}
+
+ تحليل البنود:
+ {st.session_state.cost_analysis['items_analysis']}
+
+ المقارنة مع السوق:
+ {st.session_state.cost_analysis['market_comparison']}
+
+ قم بإنشاء تقرير نهائي شامل يتضمن:
+ 1. ملخص تنفيذي
+ 2. نظرة عامة على المشروع
+ 3. ملخص التكاليف الإجمالية والتفصيلية
+ 4. مقارنة مع متوسط السوق
+ 5. فرص تحسين التكلفة
+ 6. المخاطر المحتملة وتأثيرها على التكلفة
+ 7. التوصيات النهائية
+ 8. الخطوات التالية
+
+ قدم التقرير بتنسيق احترافي ومنظم.
+ """
+
+ # الحصول على التقرير النهائي من نموذج الذكاء الاصطناعي
+ final_report = self._get_ai_response(prompt, ai_model)
+
+ # حفظ التقرير النهائي في الجلسة
+ st.session_state.cost_analysis["final_report"] = final_report
+
+ # عرض التقرير النهائي
+ st.markdown("##### التقرير النهائي:")
+ st.markdown(final_report)
- # إعدادات التقرير
- with st.expander("إعدادات التقرير"):
- col1, col2 = st.columns(2)
+ # إذا كان التقرير النهائي قد تم إنشاؤه بالفعل
+ if "final_report" in st.session_state.cost_analysis:
+ st.markdown("##### التقرير النهائي:")
+ st.markdown(st.session_state.cost_analysis["final_report"])
+
+ # تصدير التقرير
+ report_file_name = f"تقرير_تقدير_التكاليف_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
+
+ col1, col2, col3 = st.columns(3)
with col1:
- include_charts = st.checkbox(
- "تضمين الرسوم البيانية",
- value=True,
- key="include_charts_checkbox"
- )
+ # تصدير كملف PDF
+ report_content = f"""
+ # التقرير النهائي لتقدير التكاليف
+
+ **تاريخ التقرير:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+
+ {st.session_state.cost_analysis['final_report']}
+ """
- include_analysis = st.checkbox(
- "تضمين التحليل",
- value=True,
- key="include_analysis_checkbox"
+ st.download_button(
+ label="تنزيل التقرير (PDF)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.pdf",
+ mime="application/pdf",
+ key="download_report_pdf"
)
with col2:
- report_format = st.radio(
- "صيغة التقرير:",
- options=["PDF", "Excel", "Word"],
- horizontal=True,
- key="report_format_radio"
+ # تصدير كملف Excel
+ st.download_button(
+ label="تنزيل التقرير (Excel)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.xlsx",
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ key="download_report_excel"
)
-
- include_logo = st.checkbox(
- "تضمين شعار الشركة",
- value=True,
- key="include_logo_checkbox"
+
+ with col3:
+ # تصدير كملف Word
+ st.download_button(
+ label="تنزيل التقرير (Word)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.docx",
+ mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ key="download_report_word"
)
-
- # زر إنشاء التقرير
- if st.button("إنشاء التقرير", key="create_report_button"):
- with st.spinner("جاري إنشاء التقرير..."):
- # محاكاة إنشاء التقرير
- progress_bar = st.progress(0)
- for i in range(100):
- time.sleep(0.02)
- progress_bar.progress(i + 1)
-
- st.success("تم إنشاء التقرير بنجاح!")
-
- # عرض معاينة التقرير
- st.markdown("#### معاينة التقرير")
-
- # إنشاء معاينة للتقرير حسب النوع المحدد
- if report_type == "تقرير ملخص التكاليف":
- st.markdown("""
- ### تقرير ملخص التكاليف
-
- **اسم المشروع:** مشروع إنشاء مبنى إداري
-
- **تاريخ التقرير:** {date}
-
- **إعداد:** نظام تحليل المناقصات - وحدة الذكاء الاصطناعي
-
- #### ملخص التكاليف
-
- - **التكلفة الأساسية:** 4,500,000 ريال سعودي
- - **احتياطي الطوارئ (10%):** 450,000 ريال سعودي
- - **تكلفة التضخم:** 157,500 ريال سعودي
- - **التكلفة الإجمالية:** 5,107,500 ريال سعودي
-
- #### توزيع التكاليف حسب نوع العمل
-
- - الأعمال الإنشائية: 1,787,625 ريال سعودي (35%)
- - الأعمال المعمارية: 1,276,875 ريال سعودي (25%)
- - الأعمال الكهربائية: 766,125 ريال سعودي (15%)
- - الأعمال الميكانيكية: 612,900 ريال سعودي (12%)
- - أعمال الموقع والتجهيزات: 408,600 ريال سعودي (8%)
- - أخرى: 255,375 ريال سعودي (5%)
- """.format(date=datetime.now().strftime("%Y-%m-%d")))
-
- elif report_type == "تقرير تفصيلي للبنود":
- st.markdown("""
- ### تقرير تفصيلي للبنود
-
- **اسم المشروع:** مشروع إنشاء مبنى إداري
-
- **تاريخ التقرير:** {date}
-
- **إعداد:** نظام تحليل المناقصات - وحدة الذكاء الاصطناعي
-
- #### تفاصيل البنود
-
- | الكود | الوصف | الوحدة | الكمية | سعر الوحدة | الإجمالي |
- |-------|-------|--------|--------|------------|----------|
- | 01-001 | أعمال الحفر والردم | م³ | 5,000 | 35 | 175,000 |
- | 01-002 | أعمال الخرسانة العادية | م³ | 1,200 | 450 | 540,000 |
- | 01-003 | أعمال الخرسانة المسلحة | م³ | 2,500 | 850 | 2,125,000 |
- | 02-001 | أعمال البلوك | م² | 3,500 | 120 | 420,000 |
- | 02-002 | أعمال اللياسة | م² | 7,000 | 45 | 315,000 |
- | 02-003 | أعمال البلاط | م² | 4,500 | 180 | 810,000 |
- | 03-001 | أعمال التمديدات الكهربائية | نقطة | 350 | 250 | 87,500 |
- | 03-002 | أعمال الإنارة | وحدة | 200 | 350 | 70,000 |
- | 04-001 | أعمال التمديدات الصحية | نقطة | 120 | 450 | 54,000 |
- | 04-002 | أعمال التكييف | وحدة | 50 | 3,500 | 175,000 |
-
- **الإجمالي:** 4,771,500 ريال سعودي
- """.format(date=datetime.now().strftime("%Y-%m-%d")))
-
- elif report_type == "تقرير المقارنة مع السوق":
- st.markdown("""
- ### تقرير المقارنة مع السو��
-
- **اسم المشروع:** مشروع إنشاء مبنى إداري
-
- **تاريخ التقرير:** {date}
-
- **إعداد:** نظام تحليل المناقصات - وحدة الذكاء الاصطناعي
-
- #### مقارنة الأسعار مع السوق
-
- | البند | السعر المقدر | متوسط السوق | الحد الأدنى | الحد الأقصى | الفرق (%) |
- |-------|--------------|-------------|------------|------------|----------|
- | الخرسانة المسلحة (م³) | 850 | 900 | 800 | 1,000 | -5.56% |
- | البلوك (م²) | 120 | 115 | 100 | 130 | +4.35% |
- | اللياسة (م²) | 45 | 50 | 40 | 60 | -10.00% |
- | البلاط (م²) | 180 | 175 | 150 | 200 | +2.86% |
- | التمديدات الكهربائية (نقطة) | 250 | 275 | 225 | 325 | -9.09% |
-
- **متوسط الفرق عن السوق:** -3.49%
-
- #### تحليل الفروقات
-
- - البنود التي تقل عن متوسط السوق بأكثر من 5%:
- - الخرسانة المسلحة: -5.56%
- - اللياسة: -10.00%
- - التمديدات الكهربائية: -9.09%
-
- - البنود التي تزيد عن متوسط السوق بأكثر من 5%:
- - لا توجد
- """.format(date=datetime.now().strftime("%Y-%m-%d")))
-
- elif report_type == "تقرير تحليل المخاطر":
- st.markdown("""
- ### تقرير تحليل المخاطر
-
- **اسم المشروع:** مشروع إنشاء مبنى إداري
-
- **تاريخ التقرير:** {date}
-
- **إعداد:** نظام تحليل المناقصات - وحدة الذكاء الاصطناعي
-
- #### تحليل مخاطر التكلفة
-
- | المخاطرة | الاحتمالية | التأثير | درجة المخاطرة | الإجراءات المقترحة |
- |----------|------------|---------|---------------|-------------------|
- | ارتفاع أسعار مواد البناء | متوسطة | عالي | عالية | تأمين المواد الرئيسية مبكراً، إبرام عقود توريد بأسعار ثابتة |
- | تأخر تنفيذ المشروع | منخفضة | متوسط | متوسطة | وضع جدول زمني واقعي، متابعة دورية للتقدم |
- | تغيير نطاق العمل | متوسطة | عالي | عالية | توثيق نطاق العمل بدقة، إدارة التغييرات بفعالية |
- | نقص العمالة الماهرة | منخفضة | متوسط | متوسطة | التعاقد مع مقاولي باطن موثوقين، خطة بديلة للموارد |
- | مشاكل فنية غير متوقعة | منخفضة | عالي | متوسطة | مراجعة التصاميم بدقة، إجراء فحوصات للموقع |
-
- #### تأثير المخاطر على التكلفة
-
- - **التكلفة الأساسية:** 5,107,500 ريال سعودي
- - **تأثير المخاطر (الحد الأدنى):** +2% (102,150 ريال سعودي)
- - **تأثير المخاطر (المتوقع):** +5% (255,375 ريال سعودي)
- - **تأثير المخاطر (الحد الأقصى):** +12% (612,900 ريال سعودي)
- - **نطاق التكلفة المتوقع:** 5,209,650 - 5,720,400 ريال سعودي
- """.format(date=datetime.now().strftime("%Y-%m-%d")))
-
- else: # تقرير شامل
- st.markdown("""
- ### تقرير شامل لتقدير التكاليف
-
- **اسم المشروع:** مشروع إنشاء مبنى إداري
-
- **تاريخ التقرير:** {date}
-
- **إعداد:** نظام تحليل المناقصات - وحدة الذكاء الاصطناعي
-
- #### ملخص المشروع
-
- - **نوع المشروع:** مبنى إداري
- - **الموقع:** الرياض
- - **المساحة:** 5,000 متر مربع
- - **مدة التنفيذ:** 12 شهر
-
- #### ملخص التكاليف
-
- - **التكلفة الأساسية:** 4,500,000 ريال سعودي (900 ريال/م²)
- - **احتياطي الطوارئ (10%):** 450,000 ريال سعودي
- - **تكلفة التضخم:** 157,500 ريال سعودي
- - **التكلفة الإجمالية:** 5,107,500 ريال سعودي (1,021.5 ريال/م²)
-
- #### توزيع التكاليف حسب نوع العمل
-
- - الأعمال الإنشائية: 1,787,625 ريال سعودي (35%)
- - الأعمال المعمارية: 1,276,875 ريال سعودي (25%)
- - الأعمال الكهربائية: 766,125 ريال سعودي (15%)
- - الأعمال الميكانيكية: 612,900 ريال سعودي (12%)
- - أعمال الموقع والتجهيزات: 408,600 ريال سعودي (8%)
- - أخرى: 255,375 ريال سعودي (5%)
-
- #### مقارنة الأسعار مع السوق
-
- - متوسط الفرق عن السوق: -3.49%
- - البنود التي تقل عن متوسط السوق بأكثر من 5%:
- - الخرسانة المسلحة: -5.56%
- - اللياسة: -10.00%
- - التمديدات الكهربائية: -9.09%
-
- #### تحليل المخاطر
-
- - نطاق التكلفة المتوقع: 5,209,650 - 5,720,400 ريال سعودي
- - المخاطر الرئيسية: ارتفاع أسعار مواد البناء، تغيير نطاق العمل
-
- #### التوصيات
-
- 1. تأمين المواد الرئيسية مبكراً لتجنب ارتفاع الأسعار
- 2. مراجعة بنود اللياسة والتمديدات الكهربائية للتأكد من دقة التقدير
- 3. توثيق نطاق العمل بدقة لتجنب التغييرات غير المخطط لها
- 4. إضافة احتياطي للطوارئ بنسبة 10% لتغطية المخاطر المحتملة
- 5. مراقبة أسعار السوق بشكل دوري وتحديث التقديرات عند الحاجة
- """.format(date=datetime.now().strftime("%Y-%m-%d")))
-
- # إضافة زر لتنزيل التقرير
- report_file_name = f"تقرير_{report_type.replace(' ', '_')}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
-
- if report_format == "PDF":
- st.download_button(
- label="تنزيل التقرير (PDF)",
- data="تقرير تقدير التكاليف".encode('utf-8'),
- file_name=f"{report_file_name}.pdf",
- mime="application/pdf",
- key="download_report_pdf"
- )
- elif report_format == "Excel":
- st.download_button(
- label="تنزيل التقرير (Excel)",
- data="بيانات تقدير التكاليف".encode('utf-8'),
- file_name=f"{report_file_name}.xlsx",
- mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- key="download_report_excel"
- )
- else: # Word
- st.download_button(
- label="تنزيل التقرير (Word)",
- data="تقرير تقدير التكاليف".encode('utf-8'),
- file_name=f"{report_file_name}.docx",
- mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- key="download_report_word"
- )
- else:
- st.info("الرجاء تحميل وتحليل ملفات المشروع أولاً من تبويب 'تحميل الملفات'.")
def _render_risk_analysis_tab(self):
"""عرض تبويب تحليل المخاطر"""
@@ -1098,42 +1108,370 @@ class AIAssistantApp:
يمكنك استخدام هذه الأداة لتحليل المخاطر المحتملة في المشاريع باستخدام الذكاء الاصطناعي.
""")
- # إضافة محتوى تبويب تحليل المخاطر هنا
- st.info("هذه الميزة قيد التطوير. ستكون متاحة قريبًا.")
-
- def _render_help_tab(self):
- """عرض تبويب المساعدة"""
- st.markdown("### المساعدة")
-
- st.markdown("""
- #### كيفية استخدام مساعد الذكاء الاصطناعي
-
- 1. **تحليل المستندات**: قم بتحميل المستندات والتقارير لتحليلها باستخدام الذكاء الاصطناعي.
- 2. **تحليل العقود**: قم بتحميل العقود لتحليلها واستخراج البنود المهمة.
- 3. **تقدير التكاليف**: قم بتحميل ملفات المشروع لتقدير التكاليف باستخدام نماذج الذكاء الاصطناعي.
- 4. **تحليل المخاطر**: قم بتحليل المخاطر المحتملة في المشاريع.
-
- #### الأسئلة الشائعة
+ # إنشاء تبويبات فرعية
+ risk_tabs = st.tabs([
+ "تحديد المخاطر",
+ "تقييم المخاطر",
+ "خطة الاستجابة",
+ "التقرير النهائي"
+ ])
-
- ما هي أنواع الملفات المدعومة؟
- يدعم النظام ملفات PDF، Word، Excel، DWG، TXT، PNG، JPG.
-
+ # تبويب تحديد المخاطر
+ with risk_tabs[0]:
+ st.markdown("#### تحديد المخاطر")
+
+ # معلومات المشروع
+ st.markdown("##### معلومات المشروع")
+
+ col1, col2 = st.columns(2)
+
+ with col1:
+ project_name = st.text_input("اسم المشروع:", key="risk_project_name")
+ project_location = st.text_input("موقع المشروع:", key="risk_project_location")
+
+ with col2:
+ project_type = st.selectbox(
+ "نوع المشروع:",
+ [
+ "سكني",
+ "تجاري",
+ "صناعي",
+ "بنية تحتية",
+ "طرق",
+ "أخرى"
+ ],
+ key="risk_project_type"
+ )
+
+ project_budget = st.number_input("ميزانية المشروع (ريال سعودي):", min_value=0, key="risk_project_budget")
+
+ # وصف المشروع
+ project_description = st.text_area("وصف المشروع:", height=150, key="risk_project_description")
+
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = st.selectbox(
+ "اختر نموذج الذكاء الاصطناعي:",
+ ["ai", "anthropic"],
+ index=0,
+ key="risk_identification_model"
+ )
+
+ if st.button("تحديد المخاطر المحتملة"):
+ with st.spinner("جاري تحديد المخاطر..."):
+ # إعداد السؤال لتحديد المخاطر
+ prompt = f"""
+ أنت خبير في تحليل المخاطر لمشاريع البناء والمقاولات في المملكة العربية السعودية.
+
+ معلومات المشروع:
+ - اسم المشروع: {project_name}
+ - موقع المشروع: {project_location}
+ - نوع المشروع: {project_type}
+ - ميزانية المشروع: {project_budget} ريال سعودي
+ - وصف المشروع: {project_description}
+
+ قم بتحديد المخاطر المحتملة لهذا المشروع، مصنفة حسب الفئات التالية:
+ 1. المخاطر الفنية
+ 2. المخاطر المالية
+ 3. المخاطر التعاقدية والقانونية
+ 4. المخاطر البيئية
+ 5. المخاطر المتعلقة بالموارد البشرية
+ 6. المخاطر المتعلقة بالجدول الزمني
+ 7. المخاطر المتعلقة بالموردين والمقاولين من الباطن
+ 8. المخاطر المتعلقة بالسوق والاقتصاد
+
+ لكل مخاطرة، قدم:
+ - وصف المخاطرة
+ - الأسباب المحتملة
+ - التأثير المحتمل على المشروع
+
+ قدم قائمة شاملة بالمخاطر المحتملة مع مراعاة خصوصية السوق السعودي والظروف المحلية.
+ """
+
+ # الحصول على المخاطر المحددة من نموذج الذكاء الاصطناعي
+ identified_risks = self._get_ai_response(prompt, ai_model)
+
+ # حفظ المخاطر المحددة في الجلسة
+ if "risk_analysis" not in st.session_state:
+ st.session_state.risk_analysis = {}
+
+ st.session_state.risk_analysis["project_info"] = {
+ "name": project_name,
+ "location": project_location,
+ "type": project_type,
+ "budget": project_budget,
+ "description": project_description
+ }
+
+ st.session_state.risk_analysis["identified_risks"] = identified_risks
+
+ # عرض المخاطر المحددة
+ st.markdown("##### المخاطر المحددة:")
+ st.markdown(identified_risks)
+
+ st.success("تم تحديد المخاطر بنجاح. انتقل إلى تبويب 'تقييم المخاطر' للمتابعة.")
+
+ # إذا كانت المخاطر قد تم تحديدها بالفعل
+ if "risk_analysis" in st.session_state and "identified_risks" in st.session_state.risk_analysis:
+ st.markdown("##### المخاطر المحددة:")
+ st.markdown(st.session_state.risk_analysis["identified_risks"])
-
- هل يمكن تصدير النتائج؟
- نعم، يمكن تصدير النتائج بصيغ مختلفة مثل PDF، Excel، Word.
-
+ # تبويب تقييم المخاطر
+ with risk_tabs[1]:
+ st.markdown("#### تقييم المخاطر")
+
+ if "risk_analysis" not in st.session_state or "identified_risks" not in st.session_state.risk_analysis:
+ st.info("الرجاء تحديد المخاطر أولاً من تبويب 'تحديد المخاطر'.")
+ else:
+ if st.button("تقييم المخاطر المحددة"):
+ with st.spinner("جاري تقييم المخاطر..."):
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = "anthropic" # يمكن تغييره لاستخدام نموذج آخر
+
+ # إعداد السؤال لتقييم المخاطر
+ prompt = f"""
+ بناءً على المخاطر المحددة التالية:
+
+ {st.session_state.risk_analysis['identified_risks']}
+
+ قم بتقييم كل مخاطرة من حيث:
+ 1. احتمالية الحدوث (منخفضة، متوسطة، عالية)
+ 2. التأثير (منخفض، متوسط، عالي)
+ 3. درجة الخطورة الإجمالية (منخفضة، متوسطة، عالية، حرجة)
+
+ قدم النتائج في شكل جدول منظم يتضمن:
+ - وصف المخاطرة
+ - الفئة
+ - احتمالية الحدوث
+ - التأثير
+ - درجة الخطورة الإجمالية
+ - الأولوية (من 1 إلى 5، حيث 1 هي الأعلى)
+
+ ثم قم بترتيب المخاطر حسب الأولوية، مع التركيز على المخاطر ذات الأولوية العالية.
+ """
+
+ # الحصول على تقييم المخاطر من نموذج الذكاء الاصطناعي
+ risk_assessment = self._get_ai_response(prompt, ai_model)
+
+ # حفظ تقييم المخاطر في الجلسة
+ st.session_state.risk_analysis["risk_assessment"] = risk_assessment
+
+ # عرض تقييم المخاطر
+ st.markdown("##### تقييم المخاطر:")
+ st.markdown(risk_assessment)
+
+ st.success("تم تقييم المخاطر بنجاح. انتقل إلى تبويب 'خطة الاستجابة' للمتابعة.")
+
+ # إذا كان تقييم المخاطر قد تم بالفعل
+ if "risk_assessment" in st.session_state.risk_analysis:
+ st.markdown("##### تقييم المخاطر:")
+ st.markdown(st.session_state.risk_analysis["risk_assessment"])
-
- هل البيانات آمنة؟
- نعم، جميع البيانات تتم معالجتها بشكل آمن ولا يتم مشاركتها مع أي طرف ثالث.
-
+ # تبويب خطة الاستجابة
+ with risk_tabs[2]:
+ st.markdown("#### خطة الاستجابة للمخاطر")
+
+ if "risk_analysis" not in st.session_state or "risk_assessment" not in st.session_state.risk_analysis:
+ st.info("الرجاء تقييم المخاطر أولاً من تبويب 'تقييم المخاطر'.")
+ else:
+ if st.button("إنشاء خطة الاستجابة للمخاطر"):
+ with st.spinner("جاري إنشاء خطة الاستجابة..."):
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = "ai" # يمكن تغييره لاستخدام نموذج آخر
+
+ # إعداد السؤال لإنشاء خطة الاستجابة
+ prompt = f"""
+ بناءً على تقييم المخاطر التالي:
+
+ {st.session_state.risk_analysis['risk_assessment']}
+
+ قم بإنشاء خطة استجابة للمخاطر تتضمن:
+
+ 1. لكل مخاطرة ذات أولوية عالية (1-2):
+ - استراتيجية الاستجابة (تجنب، نقل، تخفيف، قبول)
+ - إجراءات محددة للتعامل مع المخاطرة
+ - المسؤول عن تنفيذ الإجراءات
+ - الموارد المطلوبة
+ - المؤشرات التي تدل على حدوث المخاطرة
+ - خطة الطوارئ في حال حدوث المخاطرة
+
+ 2. للمخاطر ذات الأولوية المتوسطة (3):
+ - استراتيجية الاستجابة
+ - إجراءات رئيسية للتعامل مع المخاطرة
+ - المسؤول عن المتابعة
+
+ 3. للمخاطر ذات الأولوية المنخفضة (4-5):
+ - استراتيجية الاستجابة العامة
+ - إجراءات المراقبة
+
+ قدم خطة استجابة شاملة وعملية، مع مراعاة الموارد المتاحة وظروف المشروع.
+ """
+
+ # الحصول على خطة الاستجابة من نموذج الذكاء الاصطناعي
+ response_plan = self._get_ai_response(prompt, ai_model)
+
+ # حفظ خطة الاستجابة في الجلسة
+ st.session_state.risk_analysis["response_plan"] = response_plan
+
+ # عرض خطة الاستجابة
+ st.markdown("##### خطة الاستجابة للمخاطر:")
+ st.markdown(response_plan)
+
+ st.success("تم إنشاء خطة الاستجابة بنجاح. انتقل إلى تبويب 'التقرير النهائي' للمتابعة.")
+
+ # إذا كانت خطة الاستجابة قد تم إنشاؤها بالفعل
+ if "response_plan" in st.session_state.risk_analysis:
+ st.markdown("##### خطة الاستجابة للمخاطر:")
+ st.markdown(st.session_state.risk_analysis["response_plan"])
- #### الدعم الفني
+ # تبويب التقرير النهائي
+ with risk_tabs[3]:
+ st.markdown("#### التقرير النهائي")
+
+ if "risk_analysis" not in st.session_state or "response_plan" not in st.session_state.risk_analysis:
+ st.info("الرجاء إنشاء خطة الاستجابة أولاً من تبويب 'خطة الاستجابة'.")
+ else:
+ if st.button("إنشاء التقرير النهائي لتحليل المخاطر"):
+ with st.spinner("جاري إنشاء التقرير النهائي..."):
+ # اختيار نموذج الذكاء الاصطناعي
+ ai_model = "anthropic" # يمكن تغييره لاستخدام نموذج آخر
+
+ # إعداد السؤال لإنشاء التقرير النهائي
+ prompt = f"""
+ بناءً على المعلومات التالية:
+
+ معلومات المشروع:
+ - اسم المشروع: {st.session_state.risk_analysis['project_info']['name']}
+ - موقع المشروع: {st.session_state.risk_analysis['project_info']['location']}
+ - نوع المشروع: {st.session_state.risk_analysis['project_info']['type']}
+ - ميزانية المشروع: {st.session_state.risk_analysis['project_info']['budget']} ريال سعودي
+ - وصف المشروع: {st.session_state.risk_analysis['project_info']['description']}
+
+ المخاطر المحددة:
+ {st.session_state.risk_analysis['identified_risks']}
+
+ تقييم المخاطر:
+ {st.session_state.risk_analysis['risk_assessment']}
+
+ خطة الاستجابة للمخاطر:
+ {st.session_state.risk_analysis['response_plan']}
+
+ قم بإنشاء تقرير نهائي شامل لتحليل المخاطر يتضمن:
+ 1. ملخص تنفيذي
+ 2. نظرة عامة على المشروع
+ 3. منهجية تحليل المخاطر
+ 4. ملخص المخاطر الرئيسية
+ 5. تقييم المخاطر وترتيبها حسب الأولوية
+ 6. خطة الاستجابة للمخاطر
+ 7. إجراءات المراقبة والتحكم
+ 8. التوصيات النهائية
+ 9. الخطوات التالية
+
+ قدم التقرير بتنسيق احترافي ومنظم.
+ """
+
+ # الحصول على التقرير النهائي من نموذج الذكاء الاصطناعي
+ final_report = self._get_ai_response(prompt, ai_model)
+
+ # حفظ التقرير النهائي في الجلسة
+ st.session_state.risk_analysis["final_report"] = final_report
+
+ # عرض التقرير النهائي
+ st.markdown("##### التقرير النهائي لتحليل المخاطر:")
+ st.markdown(final_report)
+
+ # إذا كان التقرير النهائي قد تم إنشاؤه بالفعل
+ if "final_report" in st.session_state.risk_analysis:
+ st.markdown("##### التقرير النهائي لتحليل المخاطر:")
+ st.markdown(st.session_state.risk_analysis["final_report"])
+
+ # تصدير التقرير
+ report_file_name = f"تقرير_تحليل_المخاطر_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
+
+ col1, col2, col3 = st.columns(3)
+
+ with col1:
+ # تصدير كملف PDF
+ report_content = f"""
+ # التقرير النهائي لتحليل المخاطر
+
+ **تاريخ التقرير:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+
+ {st.session_state.risk_analysis['final_report']}
+ """
+
+ st.download_button(
+ label="تنزيل التقرير (PDF)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.pdf",
+ mime="application/pdf",
+ key="download_risk_report_pdf"
+ )
+
+ with col2:
+ # تصدير كملف Word
+ st.download_button(
+ label="تنزيل التقرير (Word)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.docx",
+ mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ key="download_risk_report_word"
+ )
+
+ with col3:
+ # تصدير كملف Excel
+ st.download_button(
+ label="تنزيل التقرير (Excel)",
+ data=report_content.encode('utf-8'),
+ file_name=f"{report_file_name}.xlsx",
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ key="download_risk_report_excel"
+ )
+
+ def _extract_text_from_file(self, file):
+ """استخراج النص من الملف"""
+ try:
+ # تحديد نوع الملف
+ file_name = file.name
+ file_extension = file_name.split('.')[-1].lower()
+
+ # استخراج النص حسب نوع الملف
+ if file_extension == 'pdf':
+ # استخراج النص من ملف PDF
+ pdf_reader = PyPDF2.PdfReader(file)
+ text = ""
+ for page in pdf_reader.pages:
+ text += page.extract_text() + "\n"
+ return text
+
+ elif file_extension in ['docx', 'doc']:
+ # استخراج النص من ملف Word
+ doc = docx.Document(file)
+ text = ""
+ for para in doc.paragraphs:
+ text += para.text + "\n"
+ return text
+
+ elif file_extension == 'txt':
+ # استخراج النص من ملف نصي
+ return file.getvalue().decode('utf-8')
+
+ elif file_extension in ['png', 'jpg', 'jpeg']:
+ # استخراج النص من الصورة (يتطلب مكتبات إضافية)
+ return "استخراج النص من الصور غير مدعوم حاليًا."
+
+ elif file_extension in ['xlsx', 'xls']:
+ # استخراج النص من ملف Excel (يتطلب مكتبات إضافية)
+ return "استخراج النص من ملفات Excel غير مدعوم حاليًا."
+
+ elif file_extension == 'dwg':
+ # استخراج النص من ملف DWG (يتطلب مكتبات إضافية)
+ return "استخراج النص من ملفات DWG غير مدعوم حاليًا."
+
+ else:
+ return f"نوع الملف {file_extension} غير مدعوم."
- للحصول على المساعدة، يرجى التواصل مع فريق الدعم الفني على البريد الإلكتروني: support@example.com
- """)
+ except Exception as e:
+ return f"حدث خطأ أثناء استخراج النص: {str(e)}"
def _detect_file_type(self, file_name):
"""تحديد نوع الملف بناءً على الامتداد"""