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): """تحديد نوع الملف بناءً على الامتداد"""