Spaces:
Paused
Paused
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| import plotly.express as px | |
| def show_requirements_analysis(): | |
| """ | |
| عرض صفحة تحليل متطلبات المناقصة | |
| """ | |
| st.subheader("تحليل متطلبات المناقصة") | |
| # التحقق من وجود نتائج تحليل سابقة | |
| if "analysis_results" not in st.session_state or not st.session_state.analysis_results: | |
| st.warning("لا توجد نتائج تحليل متاحة. يرجى تحليل مناقصة أولاً.") | |
| if st.button("الانتقال إلى صفحة تحليل المناقصات"): | |
| st.session_state.page = "تحليل المناقصات" | |
| st.experimental_rerun() | |
| # عرض بيانات توضيحية | |
| st.markdown("### بيانات توضيحية لمتطلبات المناقصة") | |
| sample_requirements = [ | |
| {"المتطلب": "توريد وتركيب معدات الشبكة", "النوع": "فني", "الأولوية": "عالية", "التخصص": "تقنية المعلومات"}, | |
| {"المتطلب": "تدريب الموظفين", "النوع": "إداري", "الأولوية": "متوسطة", "التخصص": "تدريب"}, | |
| {"المتطلب": "توفير الصيانة لمدة 3 سنوات", "النوع": "تعاقدي", "الأولوية": "عالية", "التخصص": "صيانة"}, | |
| {"المتطلب": "الالتزام بمعايير الأمن السيبراني", "النوع": "تنظيمي", "الأولوية": "عالية", "التخصص": "أمن المعلومات"}, | |
| {"المتطلب": "نسبة محتوى محلي لا تقل عن 50%", "النوع": "تنظيمي", "الأولوية": "عالية", "التخصص": "محتوى محلي"}, | |
| {"المتطلب": "تقديم ضمان بنكي بنسبة 10%", "النوع": "مالي", "الأولوية": "متوسطة", "التخصص": "مالي"}, | |
| {"المتطلب": "تنفيذ المشروع في مدة لا تتجاوز 18 شهر", "النوع": "زمني", "الأولوية": "عالية", "التخصص": "إدارة مشاريع"}, | |
| ] | |
| sample_df = pd.DataFrame(sample_requirements) | |
| st.table(sample_df) | |
| return | |
| # عرض معلومات المناقصة | |
| results = st.session_state.analysis_results | |
| st.markdown(f"### تحليل متطلبات المناقصة رقم {results['tender_id']}") | |
| # إنشاء بيانات المتطلبات (نستخدم البيانات المتاحة أو نضيف تفاصيل إضافية) | |
| # في التطبيق الفعلي، ستكون هذه البيانات من نتائج التحليل الحقيقي | |
| requirements = [] | |
| for i, req in enumerate(results.get("requirements", [])): | |
| # إنشاء تفاصيل عشوائية لكل متطلب للتوضيح | |
| req_type = np.random.choice(["فني", "إداري", "تعاقدي", "تنظيمي", "مالي", "زمني"]) | |
| priority = np.random.choice(["عالية", "متوسطة", "منخفضة"], p=[0.5, 0.3, 0.2]) | |
| specializations = { | |
| "فني": ["هندسة", "تقنية المعلومات", "اتصالات", "كهرباء", "ميكانيكا"], | |
| "إداري": ["إدارة مشاريع", "موارد بشرية", "تدريب", "جودة"], | |
| "تعاقدي": ["قانوني", "مشتريات", "عقود", "صيانة"], | |
| "تنظيمي": ["امتثال", "أمن المعلومات", "محتوى محلي", "بيئة"], | |
| "مالي": ["محاسبة", "ضمانات", "تمويل", "مالي"], | |
| "زمني": ["إدارة مشاريع", "جدولة", "تخطيط"] | |
| } | |
| specialization = np.random.choice(specializations.get(req_type, ["عام"])) | |
| requirements.append({ | |
| "المتطلب": req, | |
| "النوع": req_type, | |
| "الأولوية": priority, | |
| "التخصص": specialization | |
| }) | |
| # إذا لم تكن هناك متطلبات، إنشاء بيانات توضيحية | |
| if not requirements: | |
| requirements = [ | |
| {"المتطلب": "توريد وتركيب معدات", "النوع": "فني", "الأولوية": "عالية", "التخصص": "هندسة"}, | |
| {"المتطلب": "تدريب الموظفين", "النوع": "إداري", "الأولوية": "متوسطة", "التخصص": "تدريب"}, | |
| {"المتطلب": "صيانة دورية", "النوع": "تعاقدي", "الأولوية": "متوسطة", "التخصص": "صيانة"}, | |
| {"المتطلب": "الامتثال للمعايير", "النوع": "تنظيمي", "الأولوية": "عالية", "التخصص": "امتثال"}, | |
| {"المتطلب": "تقديم ضمانات مالية", "النوع": "مالي", "الأولوية": "عالية", "التخصص": "مالي"} | |
| ] | |
| # تحويل البيانات إلى DataFrame | |
| requirements_df = pd.DataFrame(requirements) | |
| # تبويبات لعرض المتطلبات بطرق مختلفة | |
| tab1, tab2, tab3 = st.tabs(["قائمة المتطلبات", "تصنيف المتطلبات", "تحليل المتطلبات"]) | |
| # تبويب قائمة المتطلبات | |
| with tab1: | |
| st.markdown("### قائمة متطلبات المناقصة") | |
| st.dataframe(requirements_df, use_container_width=True) | |
| # خيار تصفية المتطلبات | |
| st.markdown("### تصفية المتطلبات") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| selected_type = st.selectbox( | |
| "تصفية حسب النوع", | |
| ["الكل"] + sorted(requirements_df["النوع"].unique().tolist()) | |
| ) | |
| with col2: | |
| selected_priority = st.selectbox( | |
| "تصفية حسب الأولوية", | |
| ["الكل"] + sorted(requirements_df["الأولوية"].unique().tolist()) | |
| ) | |
| # تطبيق التصفية | |
| filtered_df = requirements_df.copy() | |
| if selected_type != "الكل": | |
| filtered_df = filtered_df[filtered_df["النوع"] == selected_type] | |
| if selected_priority != "الكل": | |
| filtered_df = filtered_df[filtered_df["الأولوية"] == selected_priority] | |
| if selected_type != "الكل" or selected_priority != "الكل": | |
| st.markdown("### المتطلبات المصفاة") | |
| st.dataframe(filtered_df, use_container_width=True) | |
| # تبويب تصنيف المتطلبات | |
| with tab2: | |
| st.markdown("### تصنيف المتطلبات حسب النوع والأولوية") | |
| # رسم بياني للمتطلبات حسب النوع | |
| type_counts = requirements_df["النوع"].value_counts().reset_index() | |
| type_counts.columns = ["النوع", "العدد"] | |
| fig1 = px.bar( | |
| type_counts, | |
| x="النوع", | |
| y="العدد", | |
| color="النوع", | |
| title="توزيع المتطلبات حسب النوع" | |
| ) | |
| st.plotly_chart(fig1, use_container_width=True) | |
| # رسم بياني للمتطلبات حسب الأولوية | |
| priority_counts = requirements_df["الأولوية"].value_counts().reset_index() | |
| priority_counts.columns = ["الأولوية", "العدد"] | |
| # ترتيب الأولويات | |
| priority_order = {"عالية": 1, "متوسطة": 2, "منخفضة": 3} | |
| priority_counts["الترتيب"] = priority_counts["الأولوية"].map(priority_order) | |
| priority_counts = priority_counts.sort_values("الترتيب") | |
| # اختيار الألوان حسب الأولوية | |
| color_map = {"عالية": "#FF5733", "متوسطة": "#FFC300", "منخفضة": "#33FF57"} | |
| colors = priority_counts["الأولوية"].map(color_map) | |
| fig2 = px.bar( | |
| priority_counts, | |
| x="الأولوية", | |
| y="العدد", | |
| color="الأولوية", | |
| color_discrete_map=color_map, | |
| title="توزيع المتطلبات حسب الأولوية" | |
| ) | |
| st.plotly_chart(fig2, use_container_width=True) | |
| # تبويب تحليل المتطلبات | |
| with tab3: | |
| st.markdown("### تحليل المتطلبات") | |
| # توزيع المتطلبات حسب التخصص | |
| specialization_counts = requirements_df["التخصص"].value_counts().reset_index() | |
| specialization_counts.columns = ["التخصص", "العدد"] | |
| fig3 = px.pie( | |
| specialization_counts, | |
| values="العدد", | |
| names="التخصص", | |
| title="توزيع المتطلبات حسب التخصص", | |
| color_discrete_sequence=px.colors.qualitative.Bold | |
| ) | |
| fig3.update_traces(textposition="inside", textinfo="percent+label") | |
| st.plotly_chart(fig3, use_container_width=True) | |
| # مصفوفة المتطلبات (النوع × الأولوية) | |
| heatmap_data = pd.crosstab( | |
| requirements_df["النوع"], | |
| requirements_df["الأولوية"], | |
| margins=True, | |
| margins_name="الإجمالي" | |
| ) | |
| # ترتيب الأعمدة (الأولويات) | |
| priority_columns = ["عالية", "متوسطة", "منخفضة", "الإجمالي"] | |
| heatmap_data = heatmap_data.reindex(columns=priority_columns, fill_value=0) | |
| st.markdown("### مصفوفة المتطلبات (النوع × الأولوية)") | |
| st.dataframe(heatmap_data, use_container_width=True) | |
| # خيارات إضافية | |
| st.markdown("### خيارات إضافية") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| if st.button("تصدير المتطلبات إلى Excel"): | |
| st.success("تم تصدير المتطلبات إلى ملف Excel بنجاح!") | |
| with col2: | |
| if st.button("العودة إلى تحليل المناقصة"): | |
| st.session_state.page = "تحليل المناقصات" | |
| st.experimental_rerun() | |
| # اختبار مستقل للصفحة | |
| if __name__ == "__main__": | |
| st.set_page_config( | |
| page_title="نظام تحليل المناقصات - تحليل المتطلبات", | |
| page_icon="📊", | |
| layout="wide", | |
| ) | |
| show_requirements_analysis() |