"""
وحدة مقارنة الملفات
"""
import streamlit as st
import pandas as pd
import random
from datetime import datetime
import difflib
class FileComparisonApp:
"""
وحدة مقارنة الملفات للنظام
"""
def __init__(self):
"""
تهيئة وحدة مقارنة الملفات
"""
# تهيئة حالة الجلسة الخاصة بمقارنة الملفات إذا لم تكن موجودة
if 'comparison_history' not in st.session_state:
# إنشاء بيانات تجريبية لسجل المقارنات
st.session_state.comparison_history = self._generate_sample_history()
def run(self):
"""
تشغيل وحدة مقارنة الملفات
"""
st.markdown("
وحدة مقارنة الملفات
", unsafe_allow_html=True)
# إنشاء تبويبات لمقارنة الملفات المختلفة
tabs = st.tabs(["مقارنة المستندات", "مقارنة جداول البيانات", "مقارنة النصوص", "سجل المقارنات"])
with tabs[0]:
self._render_document_comparison()
with tabs[1]:
self._render_spreadsheet_comparison()
with tabs[2]:
self._render_text_comparison()
with tabs[3]:
self._render_comparison_history()
def _render_document_comparison(self):
"""
عرض واجهة مقارنة المستندات
"""
st.markdown("### مقارنة المستندات")
st.markdown("مقارنة مستندات PDF أو Word مع إظهار الاختلافات بشكل مرئي")
# رفع الملفات
col1, col2 = st.columns(2)
with col1:
st.markdown("#### المستند الأول")
file1 = st.file_uploader("اختر المستند الأول", type=["pdf", "docx"], key="doc_file1")
with col2:
st.markdown("#### المستند الثاني")
file2 = st.file_uploader("اختر المستند الثاني", type=["pdf", "docx"], key="doc_file2")
# خيارات المقارنة
st.markdown("#### خيارات المقارنة")
col1, col2, col3 = st.columns(3)
with col1:
st.checkbox("تجاهل التنسيق", value=False, key="ignore_formatting")
with col2:
st.checkbox("تجاهل الهوامش", value=True, key="ignore_headers_footers")
with col3:
st.checkbox("إظهار التغييرات الطفيفة", value=False, key="show_minor_changes")
# زر المقارنة
if st.button("مقارنة المستندات", key="compare_docs_btn"):
if file1 is not None and file2 is not None:
# محاكاة عملية المقارنة
with st.spinner("جاري مقارنة المستندات..."):
# محاكاة وقت المعالجة
import time
time.sleep(2)
st.success("تمت مقارنة المستندات بنجاح!", icon="✅")
# عرض ملخص المقارنة
st.markdown("#### ملخص المقارنة")
comparison_summary = {
"عدد الصفحات المتطابقة": random.randint(3, 8),
"عدد الصفحات المختلفة": random.randint(1, 5),
"إجمالي التغييرات": random.randint(10, 50),
"إضافات": random.randint(5, 20),
"حذف": random.randint(5, 20),
"تعديلات": random.randint(5, 20)
}
summary_df = pd.DataFrame({
"المعيار": list(comparison_summary.keys()),
"القيمة": list(comparison_summary.values())
})
st.dataframe(summary_df, use_container_width=True, hide_index=True)
# عرض صورة توضيحية للمقارنة
st.markdown("#### معاينة المقارنة")
st.info("سيتم عرض معاينة المقارنة هنا مع تمييز الاختلافات بألوان مختلفة", icon="ℹ️")
# زر تنزيل تقرير المقارنة
st.download_button(
label="تنزيل تقرير المقارنة",
data=b"محتوى وهمي لتقرير المقارنة",
file_name="document_comparison_report.pdf",
mime="application/pdf",
key="download_doc_comparison"
)
# إضافة المقارنة إلى السجل
new_entry = {
'id': len(st.session_state.comparison_history) + 1,
'type': 'مستند',
'file1': file1.name,
'file2': file2.name,
'changes': comparison_summary["إجمالي التغييرات"],
'date': datetime.now().strftime("%Y-%m-%d %H:%M")
}
st.session_state.comparison_history.insert(0, new_entry)
else:
st.warning("يرجى رفع المستندين للمقارنة", icon="⚠️")
def _render_spreadsheet_comparison(self):
"""
عرض واجهة مقارنة جداول البيانات
"""
st.markdown("### مقارنة جداول البيانات")
st.markdown("مقارنة ملفات Excel أو CSV مع تحديد الاختلافات في البيانات")
# رفع الملفات
col1, col2 = st.columns(2)
with col1:
st.markdown("#### الجدول الأول")
sheet1 = st.file_uploader("اختر الجدول الأول", type=["xlsx", "csv"], key="sheet_file1")
with col2:
st.markdown("#### الجدول الثاني")
sheet2 = st.file_uploader("اختر الجدول الثاني", type=["xlsx", "csv"], key="sheet_file2")
# خيارات المقارنة
st.markdown("#### خيارات المقارنة")
col1, col2 = st.columns(2)
with col1:
st.checkbox("مقارنة الصيغ", value=True, key="compare_formulas")
st.checkbox("مقارنة التنسيق", value=False, key="compare_formatting")
with col2:
st.checkbox("تجاهل الأوراق المخفية", value=True, key="ignore_hidden_sheets")
st.checkbox("مقارنة حسب القيمة فقط", value=False, key="compare_by_value")
# زر المقارنة
if st.button("مقارنة الجداول", key="compare_sheets_btn"):
if sheet1 is not None and sheet2 is not None:
# محاكاة عملية المقارنة
with st.spinner("جاري مقارنة جداول البيانات..."):
# محاكاة وقت المعالجة
import time
time.sleep(2)
st.success("تمت مقارنة جداول البيانات بنجاح!", icon="✅")
# عرض ملخص المقارنة
st.markdown("#### ملخص المقارنة")
comparison_summary = {
"عدد الخلايا المتطابقة": random.randint(500, 2000),
"عدد الخلايا المختلفة": random.randint(50, 200),
"صفوف مضافة": random.randint(5, 20),
"صفوف محذوفة": random.randint(5, 20),
"أعمدة مضافة": random.randint(1, 5),
"أعمدة محذوفة": random.randint(1, 5)
}
summary_df = pd.DataFrame({
"المعيار": list(comparison_summary.keys()),
"القيمة": list(comparison_summary.values())
})
st.dataframe(summary_df, use_container_width=True, hide_index=True)
# عرض جدول الاختلافات
st.markdown("#### الاختلافات الرئيسية")
# إنشاء بيانات تجريبية للاختلافات
diff_data = []
for i in range(10):
diff_data.append({
"الورقة": f"الورقة {random.randint(1, 3)}",
"الخلية": f"{chr(65 + random.randint(0, 5))}{random.randint(1, 20)}",
"القيمة الأولى": f"القيمة {i} (الأولى)",
"القيمة الثانية": f"القيمة {i} (الثانية)",
"نوع الاختلاف": random.choice(["تعديل", "إضافة", "حذف"])
})
diff_df = pd.DataFrame(diff_data)
st.dataframe(diff_df, use_container_width=True)
# زر تنزيل تقرير المقارنة
st.download_button(
label="تنزيل تقرير المقارنة",
data=b"محتوى وهمي لتقرير المقارنة",
file_name="spreadsheet_comparison_report.xlsx",
mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
key="download_sheet_comparison"
)
# إضافة المقارنة إلى السجل
new_entry = {
'id': len(st.session_state.comparison_history) + 1,
'type': 'جدول بيانات',
'file1': sheet1.name,
'file2': sheet2.name,
'changes': comparison_summary["عدد الخلايا المختلفة"],
'date': datetime.now().strftime("%Y-%m-%d %H:%M")
}
st.session_state.comparison_history.insert(0, new_entry)
else:
st.warning("يرجى رفع جدولي البيانات للمقارنة", icon="⚠️")
def _render_text_comparison(self):
"""
عرض واجهة مقارنة النصوص
"""
st.markdown("### مقارنة النصوص")
st.markdown("مقارنة نصوص مباشرة أو ملفات نصية مع إظهار الاختلافات")
# اختيار طريقة الإدخال
input_method = st.radio(
"طريقة الإدخال",
options=["إدخال مباشر", "رفع ملفات"],
horizontal=True,
key="text_input_method"
)
if input_method == "إدخال مباشر":
# إدخال النصوص مباشرة
col1, col2 = st.columns(2)
with col1:
st.markdown("#### النص الأول")
text1 = st.text_area("أدخل النص الأول", height=200, key="direct_text1")
with col2:
st.markdown("#### النص الثاني")
text2 = st.text_area("أدخل النص الثاني", height=200, key="direct_text2")
# زر المقارنة
if st.button("مقارنة النصوص", key="compare_direct_text_btn"):
if text1 and text2:
self._show_text_comparison_results(text1, text2)
else:
st.warning("يرجى إدخال النصين للمقارنة", icon="⚠️")
else:
# رفع ملفات نصية
col1, col2 = st.columns(2)
with col1:
st.markdown("#### الملف الأول")
text_file1 = st.file_uploader("اختر الملف الأول", type=["txt", "md", "json", "xml", "html", "css", "js", "py"], key="text_file1")
with col2:
st.markdown("#### الملف الثاني")
text_file2 = st.file_uploader("اختر الملف الثاني", type=["txt", "md", "json", "xml", "html", "css", "js", "py"], key="text_file2")
# زر المقارنة
if st.button("مقارنة الملفات النصية", key="compare_text_files_btn"):
if text_file1 is not None and text_file2 is not None:
# قراءة محتوى الملفات
text1 = text_file1.getvalue().decode("utf-8")
text2 = text_file2.getvalue().decode("utf-8")
self._show_text_comparison_results(text1, text2, text_file1.name, text_file2.name)
else:
st.warning("يرجى رفع الملفين النصيين للمقارنة", icon="⚠️")
def _show_text_comparison_results(self, text1, text2, file1_name=None, file2_name=None):
"""
عرض نتائج مقارنة النصوص
"""
# محاكاة عملية المقارنة
with st.spinner("جاري مقارنة النصوص..."):
# استخدام difflib للمقارنة
d = difflib.Differ()
diff = list(d.compare(text1.splitlines(), text2.splitlines()))
# عرض ملخص المقارنة
st.markdown("#### ملخص المقارنة")
# حساب الإحصائيات
added = len([line for line in diff if line.startswith('+ ')])
removed = len([line for line in diff if line.startswith('- ')])
changed = len([line for line in diff if line.startswith('? ')])
unchanged = len([line for line in diff if line.startswith(' ')])
comparison_summary = {
"الأسطر المتطابقة": unchanged,
"الأسطر المضافة": added,
"الأسطر المحذوفة": removed,
"الأسطر المتغيرة": changed,
"إجمالي الاختلافات": added + removed + changed
}
summary_df = pd.DataFrame({
"المعيار": list(comparison_summary.keys()),
"القيمة": list(comparison_summary.values())
})
st.dataframe(summary_df, use_container_width=True, hide_index=True)
# عرض الاختلافات
st.markdown("#### عرض الاختلافات")
# تنسيق الاختلافات بألوان مختلفة
html_diff = []
for line in diff:
if line.startswith('+ '):
html_diff.append(f'{line}
')
elif line.startswith('- '):
html_diff.append(f'{line}
')
elif line.startswith('? '):
html_diff.append(f'{line}
')
else:
html_diff.append(f'{line}
')
st.markdown(''.join(html_diff), unsafe_allow_html=True)
# زر تنزيل تقرير المقارنة
st.download_button(
label="تنزيل تقرير المقارنة",
data='\n'.join(diff),
file_name="text_comparison_report.txt",
mime="text/plain",
key="download_text_comparison"
)
# إضافة المقارنة إلى السجل
new_entry = {
'id': len(st.session_state.comparison_history) + 1,
'type': 'نص',
'file1': file1_name or "نص مباشر 1",
'file2': file2_name or "نص مباشر 2",
'changes': comparison_summary["إجمالي الاختلافات"],
'date': datetime.now().strftime("%Y-%m-%d %H:%M")
}
st.session_state.comparison_history.insert(0, new_entry)
def _render_comparison_history(self):
"""
عرض سجل المقارنات
"""
st.markdown("### سجل المقارنات")
st.markdown("عرض سجل المقارنات السابقة مع إمكانية البحث والتصفية")
# خيارات التصفية
col1, col2 = st.columns(2)
with col1:
filter_type = st.multiselect(
"نوع المقارنة",
options=["الكل", "مستند", "جدول بيانات", "نص"],
default=["الكل"]
)
with col2:
date_range = st.selectbox(
"النطاق الزمني",
options=["الكل", "اليوم", "الأسبوع الماضي", "الشهر الماضي"]
)
# تطبيق التصفية
filtered_history = st.session_state.comparison_history
if "الكل" not in filter_type:
filtered_history = [h for h in filtered_history if h['type'] in filter_type]
# تحويل البيانات إلى DataFrame
if filtered_history:
df = pd.DataFrame(filtered_history)
df = df[['date', 'type', 'file1', 'file2', 'changes']]
df.columns = ['التاريخ', 'النوع', 'الملف الأول', 'الملف الثاني', 'عدد الاختلافات']
# عرض الجدول
st.dataframe(df, use_container_width=True)
else:
st.info("لا توجد مقارنات تطابق معايير التصفية", icon="ℹ️")
def _generate_sample_history(self):
"""
إنشاء بيانات تجريبية لسجل المقارنات
"""
comparison_types = ['مستند', 'جدول بيانات', 'نص']
file_names = {
'مستند': [
'مواصفات_المشروع_v1.pdf', 'مواصفات_المشروع_v2.pdf',
'العقد_النهائي.docx', 'العقد_المعدل.docx',
'تقرير_المشروع_2025.pdf', 'تقرير_المشروع_2025_مراجعة.pdf'
],
'جدول بيانات': [
'جدول_الكميات_v1.xlsx', 'جدول_الكميات_v2.xlsx',
'تحليل_الأسعار_2025.xlsx', 'تحليل_الأسعار_2025_محدث.xlsx',
'الميزانية_التقديرية.xlsx', 'الميزانية_النهائية.xlsx'
],
'نص': [
'ملاحظات_الاجتماع.txt', 'ملاحظات_الاجتماع_محدثة.txt',
'شروط_المناقصة.txt', 'شروط_المناقصة_معدلة.txt',
'config.json', 'config_new.json'
]
}
history = []
for i in range(15):
comp_type = random.choice(comparison_types)
# اختيار ملفين من نفس النوع
file_index = random.randint(0, 2) * 2
file1 = file_names[comp_type][file_index]
file2 = file_names[comp_type][file_index + 1]
# تحديد تاريخ عشوائي خلال الشهر الماضي
days_ago = random.randint(0, 30)
entry_date = (datetime.now() - pd.Timedelta(days=days_ago)).strftime("%Y-%m-%d %H:%M")
entry = {
'id': i + 1,
'type': comp_type,
'file1': file1,
'file2': file2,
'changes': random.randint(10, 100),
'date': entry_date
}
history.append(entry)
# ترتيب السجل حسب التاريخ (الأحدث أولاً)
history.sort(key=lambda x: x['date'], reverse=True)
return history