|
|
|
|
|
|
|
""" |
|
وحدة المساعد الذكي التفاعلية |
|
تتيح للمستخدمين التفاعل مع نماذج الذكاء الاصطناعي المتقدمة للحصول على مساعدة في تحليل العقود والمناقصات |
|
""" |
|
|
|
import os |
|
import sys |
|
import json |
|
import re |
|
import time |
|
import base64 |
|
import tempfile |
|
import logging |
|
from datetime import datetime |
|
import streamlit as st |
|
import pandas as pd |
|
import numpy as np |
|
import requests |
|
from io import BytesIO |
|
from PIL import Image |
|
import openai |
|
import plotly.express as px |
|
import plotly.graph_objects as go |
|
|
|
|
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))) |
|
|
|
|
|
from utils.helpers import create_directory_if_not_exists, format_time, get_user_info, render_credits, load_css |
|
|
|
|
|
class AIAssistant: |
|
"""فئة المساعد الذكي التفاعلية""" |
|
|
|
def __init__(self): |
|
"""تهيئة المساعد الذكي""" |
|
self.conversations_dir = os.path.join(os.path.dirname(__file__), '..', '..', 'data', 'assistant_conversations') |
|
create_directory_if_not_exists(self.conversations_dir) |
|
|
|
|
|
self.openai_api_key = os.environ.get("OPENAI_API_KEY") |
|
if self.openai_api_key: |
|
openai.api_key = self.openai_api_key |
|
self.is_api_available = True |
|
else: |
|
self.is_api_available = False |
|
|
|
|
|
self.model = "gpt-4o" |
|
|
|
|
|
if "assistant_messages" not in st.session_state: |
|
st.session_state.assistant_messages = [] |
|
|
|
if "assistant_mode" not in st.session_state: |
|
st.session_state.assistant_mode = "general" |
|
|
|
if "document_context" not in st.session_state: |
|
st.session_state.document_context = None |
|
|
|
|
|
self.assistant_modes = { |
|
"general": "مساعد عام", |
|
"contract_analysis": "تحليل العقود", |
|
"cost_estimation": "تقدير التكاليف", |
|
"risk_assessment": "تقييم المخاطر", |
|
"project_planning": "تخطيط المشاريع" |
|
} |
|
|
|
|
|
self.system_prompts = { |
|
"general": """ |
|
أنت مساعد ذكي متخصص في شركة شبه الجزيرة للمقاولات، وتعمل ضمن نظام WAHBi لتحليل العقود والمناقصات. |
|
دورك هو مساعدة المستخدمين في: |
|
1. تحليل المستندات والعقود، وتوضيح بنود العقود وفهم الالتزامات والشروط. |
|
2. المساعدة في تسعير المشاريع وحساب التكاليف والموارد. |
|
3. تقييم مخاطر العقود والمشاريع والمساعدة في اتخاذ القرارات. |
|
4. المساعدة في إدارة المشاريع ومتابعة الإنجاز. |
|
|
|
استخدم لغة مهنية واضحة ومباشرة. قدم إجابات دقيقة ومختصرة. |
|
عند قيام المستخدم بسؤال عن كيفية استخدام النظام، قم بإرشاده إلى الوحدة المناسبة في النظام. |
|
|
|
معلومات هامة عن وحدات النظام: |
|
- وحدة تحليل المستندات: لتحليل العقود والمناقصات باستخدام الذكاء الاصطناعي. |
|
- وحدة مقارنة المستندات: لمقارنة نسخ مختلفة من المستندات وتحديد التغييرات. |
|
- وحدة التسعير المتكاملة: لحساب تكاليف المشاريع بناءً على الموارد والمواد والعمالة. |
|
- وحدة تقييم مخاطر العقود: لتحليل وتقييم المخاطر المحتملة في العقود والمشاريع. |
|
- وحدة متتبع حالة المشروع: لمتابعة تقدم المشاريع وعرض مؤشرات الأداء. |
|
- وحدة خريطة المشاريع: لعرض مواقع المشاريع على الخريطة بشكل تفاعلي. |
|
- وحدة الإشعارات الذكية: لإرسال تنبيهات وإشعارات للمستخدمين حول المشاريع. |
|
|
|
تذكر أن تكون مفيداً ودقيقاً ومهنياً في جميع إجاباتك. |
|
""", |
|
|
|
"contract_analysis": """ |
|
أنت محلل عقود متخصص في تحليل العقود والمناقصات لشركات المقاولات. |
|
مهمتك هي تحليل العقود وتحديد: |
|
- الالتزامات الرئيسية |
|
- المواعيد النهائية والتسليمات |
|
- الشروط الجزائية والغرامات |
|
- آلية الدفع والمستحقات المالية |
|
- الشروط الخاصة والاستثناءات |
|
- المخاطر المحتملة وكيفية التخفيف منها |
|
|
|
عند تحليل عقد، قم بتوضيح البنود غير المواتية التي قد تسبب مشاكل مستقبلية. |
|
استخدم لغة قانونية دقيقة مع شرح المصطلحات القانونية بلغة مبسطة. |
|
قدم توصيات عملية لكيفية التعامل مع بنود العقد وتجنب المخاطر. |
|
""", |
|
|
|
"cost_estimation": """ |
|
أنت خبير في تقدير تكاليف مشاريع البناء والمقاولات. |
|
مهمتك هي مساعدة المستخدم في: |
|
- تقدير تكاليف المشاريع بناءً على وصف المشروع ومتطلباته |
|
- حساب تكاليف المواد والعمالة والمعدات والنفقات العامة |
|
- توضيح كيفية تخصيص الميزانية بين مختلف عناصر المشروع |
|
- تحديد التكاليف غير المباشرة التي قد يغفل عنها المستخدم |
|
- اقتراح طرق لتقليل التكاليف دون التأثير على جودة المشروع |
|
|
|
استخدم أسلوب منهجي في تقدير التكاليف واشرح افتراضاتك بوضوح. |
|
قدم نطاقات تقديرية بدلاً من أرقام دقيقة للتكاليف حيثما كان ذلك مناسباً. |
|
عند الإشارة إلى تكاليف، وضح ما إذا كانت التكاليف تشمل ضريبة القيمة المضافة أم لا. |
|
""", |
|
|
|
"risk_assessment": """ |
|
أنت خبير في تقييم مخاطر مشاريع البناء والمقاولات. |
|
مهمتك هي مساعدة المستخدم في: |
|
- تحديد المخاطر المحتملة في المشاريع والعقود |
|
- تقييم احتمالية وتأثير كل خطر |
|
- اقتراح استراتيجيات للتخفيف من المخاطر |
|
- تحليل السيناريوهات المحتملة وخطط الطوارئ |
|
- تقديم أفضل الممارسات لإدارة المخاطر في مشاريع المقاولات |
|
|
|
صنف المخاطر إلى فئات (عالية، متوسطة، منخفضة) بناءً على احتماليتها وتأثيرها. |
|
اشرح كيف يمكن للشركة أن تحول بعض المخاطر إلى فرص. |
|
قدم أمثلة عملية من مشاريع مماثلة لتوضيح كيفية إدارة المخاطر المحددة. |
|
""", |
|
|
|
"project_planning": """ |
|
أنت خبير في تخطيط وإدارة مشاريع البناء والمقاولات. |
|
مهمتك هي مساعدة المستخدم في: |
|
- تخطيط المشاريع وتقسيمها إلى مراحل ومهام |
|
- تحديد الموارد اللازمة والجداول الزمنية |
|
- إنشاء مخطط جانت وتحديد المسار الحرج |
|
- التخطيط للموارد البشرية والمعدات والمواد |
|
- متابعة تقدم المشروع ومؤشرات الأداء |
|
|
|
قدم نصائح عملية لإدارة المشاريع بكفاءة وتجنب التأخيرات. |
|
اشرح كيفية التعامل مع التغييرات والمطالبات خلال تنفيذ المشروع. |
|
قدم أفضل الممارسات للتواصل مع أصحاب المصلحة وإدارة التوقعات. |
|
""" |
|
} |
|
|
|
def _call_openai_api(self, messages, model=None, max_tokens=2000): |
|
"""استدعاء OpenAI API للحصول على استجابة""" |
|
if not self.is_api_available: |
|
return { |
|
"choices": [{"message": {"content": "عذراً، مفتاح OpenAI API غير متوفر. يرجى التواصل مع مسؤول النظام."}}] |
|
} |
|
|
|
try: |
|
if model is None: |
|
model = self.model |
|
|
|
response = openai.ChatCompletion.create( |
|
model=model, |
|
messages=messages, |
|
max_tokens=max_tokens, |
|
temperature=0.7, |
|
top_p=0.9, |
|
frequency_penalty=0, |
|
presence_penalty=0 |
|
) |
|
|
|
return response |
|
except Exception as e: |
|
logging.error(f"خطأ في استدعاء OpenAI API: {e}") |
|
return { |
|
"choices": [{"message": {"content": f"عذراً، حدث خطأ في الاتصال بـ OpenAI API: {str(e)}"}}] |
|
} |
|
|
|
def _call_backend_api(self, endpoint, data): |
|
"""استدعاء واجهة API الخلفية للنظام""" |
|
try: |
|
response = requests.post( |
|
f"http://localhost:5000/api/{endpoint}", |
|
json=data, |
|
timeout=60 |
|
) |
|
|
|
if response.status_code == 200: |
|
return response.json() |
|
else: |
|
logging.error(f"خطأ في استدعاء واجهة API الخلفية: {response.status_code} - {response.text}") |
|
return {"error": f"خطأ في استدعاء واجهة API الخلفية: {response.status_code}"} |
|
except Exception as e: |
|
logging.error(f"خطأ في الاتصال بواجهة API الخلفية: {e}") |
|
return {"error": f"خطأ في الاتصال بواجهة API الخلفية: {str(e)}"} |
|
|
|
def _process_user_message(self, user_message, mode=None): |
|
"""معالجة رسالة المستخدم والحصول على رد من المساعد الذكي""" |
|
if mode is None: |
|
mode = st.session_state.assistant_mode |
|
|
|
|
|
messages = [ |
|
{"role": "system", "content": self.system_prompts[mode]} |
|
] |
|
|
|
|
|
if st.session_state.document_context: |
|
messages.append({ |
|
"role": "system", |
|
"content": f"معلومات سياقية عن المستند: {st.session_state.document_context}" |
|
}) |
|
|
|
|
|
for msg in st.session_state.assistant_messages: |
|
messages.append({ |
|
"role": msg["role"], |
|
"content": msg["content"] |
|
}) |
|
|
|
|
|
messages.append({ |
|
"role": "user", |
|
"content": user_message |
|
}) |
|
|
|
|
|
response = self._call_openai_api(messages) |
|
|
|
|
|
assistant_response = response["choices"][0]["message"]["content"] |
|
|
|
|
|
st.session_state.assistant_messages.append({"role": "user", "content": user_message}) |
|
st.session_state.assistant_messages.append({"role": "assistant", "content": assistant_response}) |
|
|
|
return assistant_response |
|
|
|
def _clear_chat(self): |
|
"""مسح المحادثة الحالية""" |
|
st.session_state.assistant_messages = [] |
|
st.session_state.document_context = None |
|
|
|
def _save_conversation(self): |
|
"""حفظ المحادثة الحالية""" |
|
if not st.session_state.assistant_messages: |
|
st.warning("لا توجد محادثة لحفظها.") |
|
return False |
|
|
|
timestamp = datetime.now().strftime("%Y%m%d%H%M%S") |
|
user_info = get_user_info() |
|
|
|
conversation_data = { |
|
"timestamp": timestamp, |
|
"user": user_info["username"], |
|
"mode": st.session_state.assistant_mode, |
|
"messages": st.session_state.assistant_messages, |
|
"document_context": st.session_state.document_context |
|
} |
|
|
|
filename = f"conversation_{user_info['username']}_{timestamp}.json" |
|
file_path = os.path.join(self.conversations_dir, filename) |
|
|
|
try: |
|
with open(file_path, 'w', encoding='utf-8') as f: |
|
json.dump(conversation_data, f, ensure_ascii=False, indent=2) |
|
|
|
return True |
|
except Exception as e: |
|
logging.error(f"خطأ في حفظ المحادثة: {e}") |
|
return False |
|
|
|
def _load_conversation(self, filename): |
|
"""تحميل محادثة محفوظة""" |
|
file_path = os.path.join(self.conversations_dir, filename) |
|
|
|
try: |
|
with open(file_path, 'r', encoding='utf-8') as f: |
|
conversation_data = json.load(f) |
|
|
|
st.session_state.assistant_messages = conversation_data["messages"] |
|
st.session_state.assistant_mode = conversation_data["mode"] |
|
st.session_state.document_context = conversation_data.get("document_context") |
|
|
|
return True |
|
except Exception as e: |
|
logging.error(f"خطأ في تحميل المحادثة: {e}") |
|
return False |
|
|
|
def _get_saved_conversations(self): |
|
"""الحصول على قائمة المحادثات المحفوظة""" |
|
conversations = [] |
|
|
|
try: |
|
for filename in os.listdir(self.conversations_dir): |
|
if filename.endswith(".json") and filename.startswith("conversation_"): |
|
file_path = os.path.join(self.conversations_dir, filename) |
|
|
|
with open(file_path, 'r', encoding='utf-8') as f: |
|
data = json.load(f) |
|
|
|
conversations.append({ |
|
"filename": filename, |
|
"timestamp": data.get("timestamp", ""), |
|
"user": data.get("user", ""), |
|
"mode": data.get("mode", "general"), |
|
"message_count": len(data.get("messages", [])) |
|
}) |
|
except Exception as e: |
|
logging.error(f"خطأ في قراءة المحادثات المحفوظة: {e}") |
|
|
|
|
|
conversations.sort(key=lambda x: x["timestamp"], reverse=True) |
|
|
|
return conversations |
|
|
|
def render_chat_interface(self): |
|
"""عرض واجهة المحادثة الرئيسية""" |
|
st.markdown("<h2 class='module-title'>المساعد الذكي</h2>", unsafe_allow_html=True) |
|
|
|
|
|
if not self.is_api_available: |
|
st.warning("⚠️ مفتاح OpenAI API غير متوفر. لن يكون المساعد الذكي قادراً على الرد. يرجى التواصل مع مسؤول النظام.") |
|
|
|
|
|
st.markdown(""" |
|
<style> |
|
.chat-container { |
|
background-color: #f8f9fa; |
|
border-radius: 10px; |
|
padding: 20px; |
|
margin-bottom: 20px; |
|
max-height: 500px; |
|
overflow-y: auto; |
|
} |
|
|
|
.chat-message { |
|
margin-bottom: 15px; |
|
display: flex; |
|
flex-direction: row; |
|
} |
|
|
|
.user-message { |
|
justify-content: flex-end; |
|
} |
|
|
|
.assistant-message { |
|
justify-content: flex-start; |
|
} |
|
|
|
.message-bubble { |
|
padding: 10px 15px; |
|
border-radius: 15px; |
|
max-width: 75%; |
|
} |
|
|
|
.user-bubble { |
|
background-color: #1E88E5; |
|
color: white; |
|
border-top-left-radius: 15px; |
|
border-top-right-radius: 15px; |
|
border-bottom-left-radius: 15px; |
|
border-bottom-right-radius: 0; |
|
} |
|
|
|
.assistant-bubble { |
|
background-color: #f0f0f0; |
|
color: #333; |
|
border-top-left-radius: 15px; |
|
border-top-right-radius: 15px; |
|
border-bottom-left-radius: 0; |
|
border-bottom-right-radius: 15px; |
|
} |
|
|
|
.message-avatar { |
|
width: 40px; |
|
height: 40px; |
|
border-radius: 50%; |
|
background-color: #ccc; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
margin: 0 10px; |
|
font-weight: bold; |
|
color: white; |
|
} |
|
|
|
.user-avatar { |
|
background-color: #78909C; |
|
} |
|
|
|
.assistant-avatar { |
|
background-color: #1E88E5; |
|
} |
|
|
|
.message-content { |
|
white-space: pre-wrap; |
|
} |
|
|
|
.message-time { |
|
font-size: 0.8em; |
|
color: #888; |
|
margin-top: 5px; |
|
text-align: right; |
|
} |
|
|
|
.chat-input { |
|
background-color: #f8f9fa; |
|
border-radius: 10px; |
|
padding: 20px; |
|
} |
|
|
|
.suggestions-container { |
|
display: flex; |
|
flex-wrap: wrap; |
|
gap: 10px; |
|
margin-top: 10px; |
|
} |
|
|
|
.suggestion-chip { |
|
background-color: #e9ecef; |
|
border-radius: 20px; |
|
padding: 5px 15px; |
|
cursor: pointer; |
|
text-align: center; |
|
transition: background-color 0.3s; |
|
} |
|
|
|
.suggestion-chip:hover { |
|
background-color: #dee2e6; |
|
} |
|
</style> |
|
""", unsafe_allow_html=True) |
|
|
|
|
|
st.markdown("#### اختر وضع المساعد الذكي") |
|
|
|
col1, col2, col3, col4, col5 = st.columns(5) |
|
|
|
with col1: |
|
if st.button("مساعد عام", key="mode_general", |
|
help="مساعد عام للإجابة على الأسئلة المتعلقة بالعقود والمناقصات"): |
|
st.session_state.assistant_mode = "general" |
|
st.rerun() |
|
|
|
with col2: |
|
if st.button("تحليل العقود", key="mode_contract_analysis", |
|
help="متخصص في تحليل العقود وتحديد البنود والشروط والمخاطر"): |
|
st.session_state.assistant_mode = "contract_analysis" |
|
st.rerun() |
|
|
|
with col3: |
|
if st.button("تقدير التكاليف", key="mode_cost_estimation", |
|
help="متخصص في تقدير تكاليف المشاريع والبنود"): |
|
st.session_state.assistant_mode = "cost_estimation" |
|
st.rerun() |
|
|
|
with col4: |
|
if st.button("تقييم المخاطر", key="mode_risk_assessment", |
|
help="متخصص في تحديد وتقييم المخاطر المحتملة في المشاريع والعقود"): |
|
st.session_state.assistant_mode = "risk_assessment" |
|
st.rerun() |
|
|
|
with col5: |
|
if st.button("تخطيط المشاريع", key="mode_project_planning", |
|
help="متخصص في تخطيط وإدارة المشاريع وتحديد المراحل والموارد"): |
|
st.session_state.assistant_mode = "project_planning" |
|
st.rerun() |
|
|
|
st.markdown(f"**الوضع الحالي:** {self.assistant_modes[st.session_state.assistant_mode]}") |
|
|
|
|
|
st.markdown("---") |
|
with st.expander("إضافة سياق من مستند", expanded=False): |
|
context_text = st.text_area( |
|
"نص المستند (اختياري)", |
|
value=st.session_state.document_context if st.session_state.document_context else "", |
|
height=150, |
|
help="أضف نص المستند هنا ليتم استخدامه كسياق للمحادثة" |
|
) |
|
|
|
uploaded_file = st.file_uploader( |
|
"أو قم بتحميل ملف نصي أو PDF", |
|
type=["txt", "pdf"], |
|
help="يمكنك تحميل ملف نصي أو PDF ليتم استخدامه كسياق للمحادثة" |
|
) |
|
|
|
doc_col1, doc_col2 = st.columns(2) |
|
|
|
with doc_col1: |
|
if st.button("إضافة السياق", disabled=not context_text and not uploaded_file): |
|
if uploaded_file: |
|
try: |
|
|
|
if uploaded_file.name.endswith(".pdf"): |
|
import PyPDF2 |
|
reader = PyPDF2.PdfReader(uploaded_file) |
|
context = "" |
|
for page in reader.pages: |
|
context += page.extract_text() + "\n" |
|
else: |
|
context = uploaded_file.read().decode("utf-8") |
|
|
|
st.session_state.document_context = context |
|
st.success("تم إضافة نص المستند كسياق للمحادثة بنجاح.") |
|
except Exception as e: |
|
st.error(f"حدث خطأ أثناء قراءة الملف: {str(e)}") |
|
elif context_text: |
|
st.session_state.document_context = context_text |
|
st.success("تم إضافة نص المستند كسياق للمحادثة بنجاح.") |
|
|
|
with doc_col2: |
|
if st.button("مسح السياق", disabled=not st.session_state.document_context): |
|
st.session_state.document_context = None |
|
st.success("تم مسح سياق المستند بنجاح.") |
|
|
|
|
|
st.markdown("---") |
|
st.markdown("#### المحادثة مع المساعد الذكي") |
|
|
|
|
|
chat_container = st.container() |
|
|
|
with chat_container: |
|
with st.container(): |
|
if not st.session_state.assistant_messages: |
|
st.markdown(""" |
|
<div style="text-align: center; padding: 30px; color: #666;"> |
|
<p>مرحباً بك في المساعد الذكي!</p> |
|
<p>يمكنك البدء بطرح سؤال أو طلب مساعدة.</p> |
|
</div> |
|
""", unsafe_allow_html=True) |
|
else: |
|
message_html = "" |
|
|
|
for msg in st.session_state.assistant_messages: |
|
if msg["role"] == "user": |
|
message_html += f""" |
|
<div class="chat-message user-message"> |
|
<div class="message-bubble user-bubble"> |
|
<div class="message-content">{msg["content"]}</div> |
|
</div> |
|
<div class="message-avatar user-avatar">أ</div> |
|
</div> |
|
""" |
|
else: |
|
message_html += f""" |
|
<div class="chat-message assistant-message"> |
|
<div class="message-avatar assistant-avatar">W</div> |
|
<div class="message-bubble assistant-bubble"> |
|
<div class="message-content">{msg["content"]}</div> |
|
</div> |
|
</div> |
|
""" |
|
|
|
st.markdown(f""" |
|
<div class="chat-container"> |
|
{message_html} |
|
</div> |
|
""", unsafe_allow_html=True) |
|
|
|
|
|
st.markdown("#### أدخل رسالتك") |
|
|
|
with st.container(): |
|
with st.form(key="chat_form"): |
|
user_message = st.text_area("رسالتك", height=100, placeholder="اكتب سؤالك أو طلبك هنا...") |
|
|
|
col1, col2, col3 = st.columns([2, 2, 1]) |
|
|
|
with col1: |
|
send_button = st.form_submit_button( |
|
"إرسال", |
|
help="إرسال الرسالة إلى المساعد الذكي" |
|
) |
|
|
|
with col2: |
|
suggested_questions = [ |
|
"كيف يمكنني تحليل بنود الدفع في العقد؟", |
|
"ما هي أفضل طريقة لتقدير تكاليف مشروع بناء؟", |
|
"كيف أحدد المخاطر المحتملة في مشروع جديد؟", |
|
"كيف يمكنني إنشاء جدول زمني فعال للمشروع؟", |
|
"ما هي أهم البنود التي يجب الانتباه إليها في عقود المقاولات؟" |
|
] |
|
|
|
if st.session_state.assistant_mode == "contract_analysis": |
|
suggested_questions = [ |
|
"كيف أحدد البنود غير المواتية في العقد؟", |
|
"ما هي العناصر الأساسية التي يجب أن يتضمنها عقد المقاولة؟", |
|
"كيف أتعامل مع بنود الغرامات والتعويضات؟", |
|
"كيف يمكنني التفاوض على تحسين شروط الدفع؟", |
|
"ما هي الفروق الرئيسية بين عقد الثمن الثابت وعقد التكلفة زائد أتعاب؟" |
|
] |
|
elif st.session_state.assistant_mode == "cost_estimation": |
|
suggested_questions = [ |
|
"كيف أقدر تكلفة المواد في مشروع بناء؟", |
|
"ما هي نسبة النفقات العامة المعقولة لمشروع مقاولات؟", |
|
"كيف أحسب تكلفة العمالة بدقة؟", |
|
"ما هي العوامل التي تؤثر على تكلفة المعدات؟", |
|
"كيف أقدر هامش الربح المناسب للمشروع؟" |
|
] |
|
|
|
selected_question = st.selectbox( |
|
"أو اختر سؤال مقترح", |
|
[""] + suggested_questions, |
|
index=0 |
|
) |
|
|
|
with col3: |
|
clear_button = st.form_submit_button( |
|
"مسح المحادثة", |
|
help="مسح جميع الرسائل في المحادثة الحالية" |
|
) |
|
|
|
if send_button and user_message: |
|
|
|
with st.spinner("جاري معالجة الرسالة..."): |
|
self._process_user_message(user_message) |
|
st.rerun() |
|
|
|
if send_button and selected_question and not user_message: |
|
|
|
with st.spinner("جاري معالجة الرسالة..."): |
|
self._process_user_message(selected_question) |
|
st.rerun() |
|
|
|
if clear_button: |
|
self._clear_chat() |
|
st.rerun() |
|
|
|
|
|
col1, col2, col3 = st.columns([1, 1, 2]) |
|
|
|
with col1: |
|
if st.button("حفظ المحادثة", key="save_conversation", disabled=not st.session_state.assistant_messages): |
|
if self._save_conversation(): |
|
st.success("تم حفظ المحادثة بنجاح.") |
|
else: |
|
st.error("حدث خطأ أثناء حفظ المحادثة.") |
|
|
|
with col2: |
|
if st.button("تحميل محادثة سابقة", key="show_load_conversation"): |
|
st.session_state.show_conversations = True |
|
st.rerun() |
|
|
|
|
|
if "show_conversations" in st.session_state and st.session_state.show_conversations: |
|
st.markdown("---") |
|
st.markdown("#### المحادثات المحفوظة") |
|
|
|
conversations = self._get_saved_conversations() |
|
|
|
if not conversations: |
|
st.info("لا توجد محادثات محفوظة.") |
|
else: |
|
|
|
conversation_data = [] |
|
for conv in conversations: |
|
timestamp = datetime.strptime(conv["timestamp"], "%Y%m%d%H%M%S") if conv["timestamp"] else "" |
|
formatted_time = timestamp.strftime("%Y-%m-%d %H:%M:%S") if timestamp else "" |
|
|
|
conversation_data.append({ |
|
"التاريخ": formatted_time, |
|
"المستخدم": conv["user"], |
|
"وضع المساعد": self.assistant_modes.get(conv["mode"], "غير معروف"), |
|
"عدد الرسائل": conv["message_count"], |
|
"الملف": conv["filename"] |
|
}) |
|
|
|
df = pd.DataFrame(conversation_data) |
|
st.dataframe(df, height=300) |
|
|
|
|
|
selected_filename = st.selectbox( |
|
"اختر محادثة لتحميلها", |
|
options=[""] + [conv["filename"] for conv in conversations], |
|
format_func=lambda x: next((f"{c['user']} - {datetime.strptime(c['timestamp'], '%Y%m%d%H%M%S').strftime('%Y-%m-%d %H:%M:%S')}" for c in conversations if c["filename"] == x), x), |
|
index=0 |
|
) |
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
if st.button("تحميل المحادثة المختارة", disabled=not selected_filename): |
|
if self._load_conversation(selected_filename): |
|
st.success("تم تحميل المحادثة بنجاح.") |
|
st.session_state.show_conversations = False |
|
st.rerun() |
|
else: |
|
st.error("حدث خطأ أثناء تحميل المحادثة.") |
|
|
|
with col2: |
|
if st.button("إلغاء", key="cancel_load_conversation"): |
|
st.session_state.show_conversations = False |
|
st.rerun() |
|
|
|
|
|
st.markdown("---") |
|
st.markdown(f"#### معلومات عن وضع المساعد: {self.assistant_modes[st.session_state.assistant_mode]}") |
|
|
|
if st.session_state.assistant_mode == "general": |
|
st.markdown(""" |
|
المساعد العام يمكنه مساعدتك في مجموعة متنوعة من المهام المتعلقة بالعقود والمناقصات وإدارة المشاريع. يمكنه: |
|
- الإجابة على الأسئلة العامة حول العقود والمناقصات |
|
- توجيهك إلى الوحدات المناسبة في النظام |
|
- تقديم معلومات عامة عن إدارة المشاريع وأفضل الممارسات |
|
- المساعدة في فهم المصطلحات والمفاهيم المتعلقة بمجال المقاولات |
|
""") |
|
elif st.session_state.assistant_mode == "contract_analysis": |
|
st.markdown(""" |
|
مساعد تحليل العقود متخصص في: |
|
- تحليل بنود العقود وتوضيح معانيها |
|
- تحديد الالتزامات والحقوق لكل طرف |
|
- تسليط الضوء على البنود غير المواتية أو الغامضة |
|
- تقديم توصيات للتفاوض على تحسين شروط العقد |
|
- مقارنة العقد مع أفضل الممارسات في القطاع |
|
""") |
|
elif st.session_state.assistant_mode == "cost_estimation": |
|
st.markdown(""" |
|
مساعد تقدير التكاليف متخصص في: |
|
- حساب تكاليف المشاريع بناءً على المتطلبات والمواصفات |
|
- تقدير تكاليف المواد والعمالة والمعدات |
|
- تحليل التكاليف المباشرة وغير المباشرة |
|
- تقديم نصائح لتقليل التكاليف وزيادة الكفاءة |
|
- تحديد العوامل التي قد تؤثر على التكلفة الإجمالية |
|
""") |
|
elif st.session_state.assistant_mode == "risk_assessment": |
|
st.markdown(""" |
|
مساعد تقييم المخاطر متخصص في: |
|
- تحديد المخاطر المحتملة في المشاريع والعقود |
|
- تقييم احتمالية وتأثير كل خطر |
|
- اقتراح استراتيجيات للتخفيف من المخاطر |
|
- إنشاء خطط للطوارئ والاستجابة للمخاطر |
|
- تحليل تأثير المخاطر على الجدول الزمني والتكلفة |
|
""") |
|
elif st.session_state.assistant_mode == "project_planning": |
|
st.markdown(""" |
|
مساعد تخطيط المشاريع متخصص في: |
|
- تقسيم المشروع إلى مراحل ومهام وأنشطة |
|
- تحديد الموارد اللازمة لكل نشاط |
|
- إنشاء الجداول الزمنية والمسار الحرج |
|
- التخطيط للموارد البشرية والمعدات والمواد |
|
- مراقبة تقدم المشروع وإدارة التغييرات |
|
""") |
|
|
|
|
|
render_credits() |
|
|
|
def render(self): |
|
"""عرض واجهة المساعد الذكي الرئيسية""" |
|
|
|
load_css() |
|
|
|
|
|
self.render_chat_interface() |
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
st.set_page_config( |
|
page_title="المساعد الذكي | WAHBi AI", |
|
page_icon="🤖", |
|
layout="wide", |
|
initial_sidebar_state="expanded" |
|
) |
|
|
|
assistant = AIAssistant() |
|
assistant.render() |