Last commit not found
""" | |
وحدة الترجمة - نظام تحليل المناقصات | |
""" | |
import streamlit as st | |
import pandas as pd | |
import numpy as np | |
import os | |
import sys | |
from pathlib import Path | |
import re | |
import datetime | |
# إضافة مسار المشروع للنظام | |
sys.path.append(str(Path(__file__).parent.parent)) | |
# استيراد محسن واجهة المستخدم | |
from styling.enhanced_ui import UIEnhancer | |
class TranslationApp: | |
"""تطبيق الترجمة""" | |
def __init__(self): | |
"""تهيئة تطبيق الترجمة""" | |
self.ui = UIEnhancer(page_title="الترجمة - نظام تحليل المناقصات", page_icon="🌐") | |
self.ui.apply_theme_colors() | |
# قائمة اللغات المدعومة | |
self.supported_languages = { | |
"ar": "العربية", | |
"en": "الإنجليزية", | |
"fr": "الفرنسية", | |
"de": "الألمانية", | |
"es": "الإسبانية", | |
"it": "الإيطالية", | |
"zh": "الصينية", | |
"ja": "اليابانية", | |
"ru": "الروسية", | |
"tr": "التركية" | |
} | |
# بيانات نموذجية للمصطلحات الفنية | |
self.technical_terms = [ | |
{"ar": "كراسة الشروط", "en": "Terms and Conditions Document", "category": "مستندات"}, | |
{"ar": "جدول الكميات", "en": "Bill of Quantities (BOQ)", "category": "مستندات"}, | |
{"ar": "المواصفات الفنية", "en": "Technical Specifications", "category": "مستندات"}, | |
{"ar": "ضمان ابتدائي", "en": "Bid Bond", "category": "ضمانات"}, | |
{"ar": "ضمان حسن التنفيذ", "en": "Performance Bond", "category": "ضمانات"}, | |
{"ar": "ضمان دفعة مقدمة", "en": "Advance Payment Guarantee", "category": "ضمانات"}, | |
{"ar": "ضمان صيانة", "en": "Maintenance Bond", "category": "ضمانات"}, | |
{"ar": "مناقصة عامة", "en": "Public Tender", "category": "أنواع المناقصات"}, | |
{"ar": "مناقصة محدودة", "en": "Limited Tender", "category": "أنواع المناقصات"}, | |
{"ar": "منافسة", "en": "Competition", "category": "أنواع المناقصات"}, | |
{"ar": "أمر شراء", "en": "Purchase Order", "category": "عقود"}, | |
{"ar": "عقد إطاري", "en": "Framework Agreement", "category": "عقود"}, | |
{"ar": "عقد زمني", "en": "Time-based Contract", "category": "عقود"}, | |
{"ar": "عقد تسليم مفتاح", "en": "Turnkey Contract", "category": "عقود"}, | |
{"ar": "مقاول من الباطن", "en": "Subcontractor", "category": "أطراف"}, | |
{"ar": "استشاري", "en": "Consultant", "category": "أطراف"}, | |
{"ar": "مالك المشروع", "en": "Project Owner", "category": "أطراف"}, | |
{"ar": "مدير المشروع", "en": "Project Manager", "category": "أطراف"}, | |
{"ar": "مهندس الموقع", "en": "Site Engineer", "category": "أطراف"}, | |
{"ar": "مراقب الجودة", "en": "Quality Control", "category": "أطراف"}, | |
{"ar": "أعمال مدنية", "en": "Civil Works", "category": "أعمال"}, | |
{"ar": "أعمال كهربائية", "en": "Electrical Works", "category": "أعمال"}, | |
{"ar": "أعمال ميكانيكية", "en": "Mechanical Works", "category": "أعمال"}, | |
{"ar": "أعمال معمارية", "en": "Architectural Works", "category": "أعمال"}, | |
{"ar": "أعمال تشطيبات", "en": "Finishing Works", "category": "أعمال"}, | |
{"ar": "غرامة تأخير", "en": "Delay Penalty", "category": "شروط"}, | |
{"ar": "مدة التنفيذ", "en": "Execution Period", "category": "شروط"}, | |
{"ar": "فترة الضمان", "en": "Warranty Period", "category": "شروط"}, | |
{"ar": "شروط الدفع", "en": "Payment Terms", "category": "شروط"}, | |
{"ar": "تسوية النزاعات", "en": "Dispute Resolution", "category": "شروط"} | |
] | |
# بيانات نموذجية للمستندات المترجمة | |
self.translated_documents = [ | |
{ | |
"id": "TD001", | |
"name": "كراسة الشروط - مناقصة إنشاء مبنى إداري", | |
"source_language": "ar", | |
"target_language": "en", | |
"original_file": "specs_v2.0_ar.pdf", | |
"translated_file": "specs_v2.0_en.pdf", | |
"translation_date": "2025-03-15", | |
"translated_by": "أحمد محمد", | |
"status": "مكتمل", | |
"pages": 52, | |
"related_entity": "T-2025-001" | |
}, | |
{ | |
"id": "TD002", | |
"name": "جدول الكميات - مناقصة إنشاء مبنى إداري", | |
"source_language": "ar", | |
"target_language": "en", | |
"original_file": "boq_v1.1_ar.xlsx", | |
"translated_file": "boq_v1.1_en.xlsx", | |
"translation_date": "2025-02-25", | |
"translated_by": "سارة عبدالله", | |
"status": "مكتمل", | |
"pages": 22, | |
"related_entity": "T-2025-001" | |
}, | |
{ | |
"id": "TD003", | |
"name": "المخططات - مناقصة إنشاء مبنى إداري", | |
"source_language": "ar", | |
"target_language": "en", | |
"original_file": "drawings_v2.0_ar.pdf", | |
"translated_file": "drawings_v2.0_en.pdf", | |
"translation_date": "2025-03-20", | |
"translated_by": "محمد علي", | |
"status": "مكتمل", | |
"pages": 35, | |
"related_entity": "T-2025-001" | |
}, | |
{ | |
"id": "TD004", | |
"name": "كراسة الشروط - مناقصة صيانة طرق", | |
"source_language": "ar", | |
"target_language": "en", | |
"original_file": "specs_v1.1_ar.pdf", | |
"translated_file": "specs_v1.1_en.pdf", | |
"translation_date": "2025-03-25", | |
"translated_by": "فاطمة أحمد", | |
"status": "مكتمل", | |
"pages": 34, | |
"related_entity": "T-2025-002" | |
}, | |
{ | |
"id": "TD005", | |
"name": "جدول الكميات - مناقصة صيانة طرق", | |
"source_language": "ar", | |
"target_language": "en", | |
"original_file": "boq_v1.0_ar.xlsx", | |
"translated_file": "boq_v1.0_en.xlsx", | |
"translation_date": "2025-03-10", | |
"translated_by": "خالد عمر", | |
"status": "مكتمل", | |
"pages": 15, | |
"related_entity": "T-2025-002" | |
}, | |
{ | |
"id": "TD006", | |
"name": "كراسة الشروط - مناقصة توريد معدات", | |
"source_language": "en", | |
"target_language": "ar", | |
"original_file": "specs_v1.0_en.pdf", | |
"translated_file": "specs_v1.0_ar.pdf", | |
"translation_date": "2025-02-15", | |
"translated_by": "أحمد محمد", | |
"status": "مكتمل", | |
"pages": 28, | |
"related_entity": "T-2025-003" | |
}, | |
{ | |
"id": "TD007", | |
"name": "عقد توريد - مناقصة توريد معدات", | |
"source_language": "en", | |
"target_language": "ar", | |
"original_file": "contract_v1.0_en.pdf", | |
"translated_file": "contract_v1.0_ar.pdf", | |
"translation_date": "2025-03-05", | |
"translated_by": "سارة عبدالله", | |
"status": "مكتمل", | |
"pages": 20, | |
"related_entity": "T-2025-003" | |
}, | |
{ | |
"id": "TD008", | |
"name": "كراسة الشروط - مناقصة تجهيز مختبرات", | |
"source_language": "ar", | |
"target_language": "en", | |
"original_file": "specs_v1.0_ar.pdf", | |
"translated_file": "specs_v1.0_en.pdf", | |
"translation_date": "2025-03-28", | |
"translated_by": "محمد علي", | |
"status": "قيد التنفيذ", | |
"pages": 30, | |
"related_entity": "T-2025-004" | |
} | |
] | |
# بيانات نموذجية للنصوص المترجمة | |
self.sample_translations = { | |
"text1": { | |
"ar": """ | |
# كراسة الشروط والمواصفات | |
## مناقصة إنشاء مبنى إداري | |
### 1. مقدمة | |
تدعو شركة شبه الجزيرة للمقاولات الشركات المتخصصة للتقدم بعروضها لتنفيذ مشروع إنشاء مبنى إداري في مدينة الرياض. | |
### 2. نطاق العمل | |
يشمل نطاق العمل تصميم وتنفيذ مبنى إداري مكون من 6 طوابق بمساحة إجمالية 6000 متر مربع، ويشمل ذلك: | |
- أعمال الهيكل الإنشائي | |
- أعمال التشطيبات الداخلية والخارجية | |
- أعمال الكهرباء والميكانيكا | |
- أعمال تنسيق الموقع | |
- أعمال أنظمة الأمن والسلامة | |
- أعمال أنظمة المباني الذكية | |
""", | |
"en": """ | |
# Terms and Conditions Document | |
## Administrative Building Construction Tender | |
### 1. Introduction | |
Peninsula Contracting Company invites specialized companies to submit their offers for the implementation of an administrative building construction project in Riyadh. | |
### 2. Scope of Work | |
The scope of work includes the design and implementation of a 6-floor administrative building with a total area of 6000 square meters, including: | |
- Structural works | |
- Interior and exterior finishing works | |
- Electrical and mechanical works | |
- Site coordination works | |
- Security and safety systems works | |
- Smart building systems works | |
""" | |
}, | |
"text2": { | |
"ar": """ | |
### 3. المواصفات الفنية | |
#### 3.1 أعمال الخرسانة | |
- يجب أن تكون الخرسانة المسلحة بقوة لا تقل عن 40 نيوتن/مم² | |
- يجب استخدام حديد تسليح مطابق للمواصفات السعودية | |
- يجب استخدام إضافات للخرسانة لزيادة مقاومتها للعوامل الجوية | |
#### 3.2 أعمال التشطيبات | |
- يجب استخدام مواد عالية الجودة للتشطيبات الداخلية | |
- يجب أن تكون الواجهات الخارجية مقاومة للعوامل الجوية | |
- يجب استخدام زجاج عاكس للحرارة للواجهات | |
- يجب استخدام مواد صديقة للبيئة | |
""", | |
"en": """ | |
### 3. Technical Specifications | |
#### 3.1 Concrete Works | |
- Reinforced concrete must have a strength of not less than 40 Newton/mm² | |
- Reinforcement steel must comply with Saudi specifications | |
- Concrete additives must be used to increase its resistance to weather conditions | |
#### 3.2 Finishing Works | |
- High-quality materials must be used for interior finishes | |
- Exterior facades must be weather-resistant | |
- Heat-reflective glass must be used for facades | |
- Environmentally friendly materials must be used | |
""" | |
} | |
} | |
def run(self): | |
"""تشغيل تطبيق الترجمة""" | |
# إنشاء قائمة العناصر | |
menu_items = [ | |
{"name": "لوحة المعلومات", "icon": "house"}, | |
{"name": "المناقصات والعقود", "icon": "file-text"}, | |
{"name": "تحليل المستندات", "icon": "file-earmark-text"}, | |
{"name": "نظام التسعير", "icon": "calculator"}, | |
{"name": "حاسبة تكاليف البناء", "icon": "building"}, | |
{"name": "الموارد والتكاليف", "icon": "people"}, | |
{"name": "تحليل المخاطر", "icon": "exclamation-triangle"}, | |
{"name": "إدارة المشاريع", "icon": "kanban"}, | |
{"name": "الخرائط والمواقع", "icon": "geo-alt"}, | |
{"name": "الجدول الزمني", "icon": "calendar3"}, | |
{"name": "الإشعارات", "icon": "bell"}, | |
{"name": "مقارنة المستندات", "icon": "files"}, | |
{"name": "الترجمة", "icon": "translate"}, | |
{"name": "المساعد الذكي", "icon": "robot"}, | |
{"name": "التقارير", "icon": "bar-chart"}, | |
{"name": "الإعدادات", "icon": "gear"} | |
] | |
# إنشاء الشريط الجانبي | |
selected = self.ui.create_sidebar(menu_items) | |
# إنشاء ترويسة الصفحة | |
self.ui.create_header("الترجمة", "أدوات ترجمة المستندات والنصوص") | |
# إنشاء علامات تبويب للوظائف المختلفة | |
tabs = st.tabs(["ترجمة النصوص", "ترجمة المستندات", "قاموس المصطلحات", "المستندات المترجمة"]) | |
# علامة تبويب ترجمة النصوص | |
with tabs[0]: | |
self.translate_text() | |
# علامة تبويب ترجمة المستندات | |
with tabs[1]: | |
self.translate_documents() | |
# علامة تبويب قاموس المصطلحات | |
with tabs[2]: | |
self.technical_terms_dictionary() | |
# علامة تبويب المستندات المترجمة | |
with tabs[3]: | |
self.show_translated_documents() | |
def translate_text(self): | |
"""ترجمة النصوص""" | |
st.markdown("### ترجمة النصوص") | |
# اختيار لغات الترجمة | |
col1, col2 = st.columns(2) | |
with col1: | |
source_language = st.selectbox( | |
"لغة المصدر", | |
options=list(self.supported_languages.keys()), | |
format_func=lambda x: self.supported_languages[x], | |
index=0 # العربية كلغة افتراضية | |
) | |
with col2: | |
# استبعاد لغة المصدر من خيارات لغة الهدف | |
target_languages = {k: v for k, v in self.supported_languages.items() if k != source_language} | |
target_language = st.selectbox( | |
"لغة الهدف", | |
options=list(target_languages.keys()), | |
format_func=lambda x: self.supported_languages[x], | |
index=0 # أول لغة متاحة | |
) | |
# خيارات الترجمة | |
st.markdown("#### خيارات الترجمة") | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
translation_engine = st.radio( | |
"محرك الترجمة", | |
options=["OpenAI", "Google Translate", "Microsoft Translator", "محلي"] | |
) | |
with col2: | |
use_technical_terms = st.checkbox("استخدام قاموس المصطلحات الفنية", value=True) | |
with col3: | |
preserve_formatting = st.checkbox("الحفاظ على التنسيق", value=True) | |
# إدخال النص المراد ترجمته | |
st.markdown("#### النص المراد ترجمته") | |
# إضافة أمثلة نصية | |
examples = st.expander("أمثلة نصية") | |
with examples: | |
if st.button("مثال 1: مقدمة كراسة الشروط"): | |
source_text = self.sample_translations["text1"][source_language] if source_language in self.sample_translations["text1"] else self.sample_translations["text1"]["ar"] | |
elif st.button("مثال 2: المواصفات الفنية"): | |
source_text = self.sample_translations["text2"][source_language] if source_language in self.sample_translations["text2"] else self.sample_translations["text2"]["ar"] | |
else: | |
source_text = "" | |
if "source_text" not in locals(): | |
source_text = "" | |
source_text = st.text_area( | |
"أدخل النص المراد ترجمته", | |
value=source_text, | |
height=200 | |
) | |
# زر الترجمة | |
if st.button("ترجمة النص", use_container_width=True): | |
if not source_text: | |
st.error("يرجى إدخال النص المراد ترجمته") | |
else: | |
# في تطبيق حقيقي، سيتم استدعاء واجهة برمجة التطبيقات للترجمة | |
# هنا نستخدم النصوص النموذجية المحددة مسبقاً للعرض | |
with st.spinner("جاري الترجمة..."): | |
# محاكاة تأخير الترجمة | |
import time | |
time.sleep(1) | |
# التحقق من وجود ترجمة نموذجية | |
if source_language == "ar" and target_language == "en" and source_text.strip() in [self.sample_translations["text1"]["ar"].strip(), self.sample_translations["text2"]["ar"].strip()]: | |
if source_text.strip() == self.sample_translations["text1"]["ar"].strip(): | |
translated_text = self.sample_translations["text1"]["en"] | |
else: | |
translated_text = self.sample_translations["text2"]["en"] | |
elif source_language == "en" and target_language == "ar" and source_text.strip() in [self.sample_translations["text1"]["en"].strip(), self.sample_translations["text2"]["en"].strip()]: | |
if source_text.strip() == self.sample_translations["text1"]["en"].strip(): | |
translated_text = self.sample_translations["text1"]["ar"] | |
else: | |
translated_text = self.sample_translations["text2"]["ar"] | |
else: | |
# ترجمة نموذجية للعرض فقط | |
translated_text = f"[هذا نص مترجم نموذجي من {self.supported_languages[source_language]} إلى {self.supported_languages[target_language]}]\n\n{source_text}" | |
# عرض النص المترجم | |
st.markdown("#### النص المترجم") | |
st.text_area( | |
"النص المترجم", | |
value=translated_text, | |
height=200 | |
) | |
# أزرار إضافية | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
if st.button("نسخ النص المترجم", use_container_width=True): | |
st.success("تم نسخ النص المترجم إلى الحافظة") | |
with col2: | |
if st.button("حفظ الترجمة", use_container_width=True): | |
st.success("تم حفظ الترجمة بنجاح") | |
with col3: | |
if st.button("تصدير كملف", use_container_width=True): | |
st.success("تم تصدير الترجمة كملف بنجاح") | |
# عرض إحصائيات الترجمة | |
st.markdown("#### إحصائيات الترجمة") | |
col1, col2, col3, col4 = st.columns(4) | |
with col1: | |
self.ui.create_metric_card( | |
"عدد الكلمات", | |
str(len(source_text.split())), | |
None, | |
self.ui.COLORS['primary'] | |
) | |
with col2: | |
self.ui.create_metric_card( | |
"عدد الأحرف", | |
str(len(source_text)), | |
None, | |
self.ui.COLORS['secondary'] | |
) | |
with col3: | |
self.ui.create_metric_card( | |
"وقت الترجمة", | |
"1.2 ثانية", | |
None, | |
self.ui.COLORS['success'] | |
) | |
with col4: | |
self.ui.create_metric_card( | |
"المصطلحات الفنية", | |
"5", | |
None, | |
self.ui.COLORS['accent'] | |
) | |
def translate_documents(self): | |
"""ترجمة المستندات""" | |
st.markdown("### ترجمة المستندات") | |
# اختيار لغات الترجمة | |
col1, col2 = st.columns(2) | |
with col1: | |
source_language = st.selectbox( | |
"لغة المصدر", | |
options=list(self.supported_languages.keys()), | |
format_func=lambda x: self.supported_languages[x], | |
index=0, # العربية كلغة افتراضية | |
key="doc_source_lang" | |
) | |
with col2: | |
# استبعاد لغة المصدر من خيارات لغة الهدف | |
target_languages = {k: v for k, v in self.supported_languages.items() if k != source_language} | |
target_language = st.selectbox( | |
"لغة الهدف", | |
options=list(target_languages.keys()), | |
format_func=lambda x: self.supported_languages[x], | |
index=0, # أول لغة متاحة | |
key="doc_target_lang" | |
) | |
# تحميل المستند | |
st.markdown("#### تحميل المستند") | |
uploaded_file = st.file_uploader("اختر المستند المراد ترجمته", type=["pdf", "docx", "xlsx", "txt"]) | |
if uploaded_file is not None: | |
st.success(f"تم تحميل الملف: {uploaded_file.name}") | |
# عرض معلومات الملف | |
file_details = { | |
"اسم الملف": uploaded_file.name, | |
"نوع الملف": uploaded_file.type, | |
"حجم الملف": f"{uploaded_file.size / 1024:.1f} كيلوبايت" | |
} | |
st.json(file_details) | |
# خيارات الترجمة | |
st.markdown("#### خيارات الترجمة") | |
col1, col2 = st.columns(2) | |
with col1: | |
translation_engine = st.radio( | |
"محرك الترجمة", | |
options=["OpenAI", "Google Translate", "Microsoft Translator", "محلي"], | |
key="doc_engine" | |
) | |
use_technical_terms = st.checkbox("استخدام قاموس المصطلحات الفنية", value=True, key="doc_terms") | |
with col2: | |
preserve_formatting = st.checkbox("الحفاظ على التنسيق", value=True, key="doc_format") | |
translate_images = st.checkbox("ترجمة النصوص في الصور", value=False) | |
maintain_layout = st.checkbox("الحفاظ على تخطيط المستند", value=True) | |
# معلومات إضافية | |
st.markdown("#### معلومات إضافية") | |
col1, col2 = st.columns(2) | |
with col1: | |
document_name = st.text_input("اسم المستند") | |
with col2: | |
related_entity = st.text_input("الكيان المرتبط (مثل: رقم المناقصة أو المشروع)") | |
# زر بدء الترجمة | |
if st.button("بدء ترجمة المستند", use_container_width=True): | |
if uploaded_file is None: | |
st.error("يرجى تحميل المستند المراد ترجمته") | |
else: | |
# في تطبيق حقيقي، سيتم إرسال المستند إلى خدمة الترجمة | |
# هنا نعرض محاكاة لعملية الترجمة | |
progress_bar = st.progress(0) | |
status_text = st.empty() | |
# محاكاة تقدم الترجمة | |
import time | |
for i in range(101): | |
progress_bar.progress(i) | |
if i < 10: | |
status_text.text("جاري تحليل المستند...") | |
elif i < 30: | |
status_text.text("جاري استخراج النصوص...") | |
elif i < 70: | |
status_text.text("جاري ترجمة المحتوى...") | |
elif i < 90: | |
status_text.text("جاري إعادة بناء المستند...") | |
else: | |
status_text.text("جاري إنهاء الترجمة...") | |
time.sleep(0.05) | |
# عرض نتيجة الترجمة | |
st.success("تمت ترجمة المستند بنجاح!") | |
# إنشاء اسم الملف المترجم | |
file_name_parts = uploaded_file.name.split('.') | |
translated_file_name = f"{'.'.join(file_name_parts[:-1])}_{target_language}.{file_name_parts[-1]}" | |
# عرض معلومات الملف المترجم | |
st.markdown("#### معلومات الملف المترجم") | |
col1, col2 = st.columns(2) | |
with col1: | |
st.markdown(f"**اسم الملف:** {translated_file_name}") | |
st.markdown(f"**لغة المصدر:** {self.supported_languages[source_language]}") | |
st.markdown(f"**لغة الهدف:** {self.supported_languages[target_language]}") | |
with col2: | |
st.markdown(f"**محرك الترجمة:** {translation_engine}") | |
st.markdown(f"**تاريخ الترجمة:** {datetime.datetime.now().strftime('%Y-%m-%d')}") | |
st.markdown(f"**حالة الترجمة:** مكتمل") | |
# أزرار إضافية | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
if st.button("تنزيل الملف المترجم", use_container_width=True): | |
st.success("تم بدء تنزيل الملف المترجم") | |
with col2: | |
if st.button("حفظ في المستندات المترجمة", use_container_width=True): | |
st.success("تم حفظ الملف في المستندات المترجمة") | |
with col3: | |
if st.button("مشاركة الملف", use_container_width=True): | |
st.success("تم نسخ رابط مشاركة الملف") | |
# عرض إحصائيات الترجمة | |
st.markdown("#### إحصائيات الترجمة") | |
col1, col2, col3, col4 = st.columns(4) | |
with col1: | |
self.ui.create_metric_card( | |
"عدد الصفحات", | |
"12", | |
None, | |
self.ui.COLORS['primary'] | |
) | |
with col2: | |
self.ui.create_metric_card( | |
"عدد الكلمات", | |
"2,450", | |
None, | |
self.ui.COLORS['secondary'] | |
) | |
with col3: | |
self.ui.create_metric_card( | |
"وقت الترجمة", | |
"45 ثانية", | |
None, | |
self.ui.COLORS['success'] | |
) | |
with col4: | |
self.ui.create_metric_card( | |
"المصطلحات الفنية", | |
"28", | |
None, | |
self.ui.COLORS['accent'] | |
) | |
def technical_terms_dictionary(self): | |
"""قاموس المصطلحات الفنية""" | |
st.markdown("### قاموس المصطلحات الفنية") | |
# إضافة مصطلح جديد | |
with st.expander("إضافة مصطلح جديد"): | |
with st.form("add_term_form"): | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
term_ar = st.text_input("المصطلح بالعربية") | |
with col2: | |
term_en = st.text_input("المصطلح بالإنجليزية") | |
with col3: | |
term_category = st.selectbox( | |
"الفئة", | |
options=["مستندات", "ضمانات", "أنواع المناقصات", "عقود", "أطراف", "أعمال", "شروط", "أخرى"] | |
) | |
# زر إضافة المصطلح | |
submit_button = st.form_submit_button("إضافة المصطلح") | |
if submit_button: | |
if not term_ar or not term_en: | |
st.error("يرجى ملء جميع الحقول المطلوبة") | |
else: | |
# في تطبيق حقيقي، سيتم إضافة المصطلح إلى قاعدة البيانات | |
st.success("تمت إضافة المصطلح بنجاح") | |
# البحث في المصطلحات | |
st.markdown("#### البحث في المصطلحات") | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
search_term = st.text_input("البحث عن مصطلح") | |
with col2: | |
search_language = st.radio( | |
"لغة البحث", | |
options=["الكل", "العربية", "الإنجليزية"], | |
horizontal=True | |
) | |
with col3: | |
category_filter = st.selectbox( | |
"تصفية حسب الفئة", | |
options=["الكل", "مستندات", "ضمانات", "أنواع المناقصات", "عقود", "أطراف", "أعمال", "شروط", "أخرى"] | |
) | |
# تطبيق الفلاتر | |
filtered_terms = self.technical_terms | |
if search_term: | |
if search_language == "العربية": | |
filtered_terms = [term for term in filtered_terms if search_term.lower() in term["ar"].lower()] | |
elif search_language == "الإنجليزية": | |
filtered_terms = [term for term in filtered_terms if search_term.lower() in term["en"].lower()] | |
else: | |
filtered_terms = [term for term in filtered_terms if search_term.lower() in term["ar"].lower() or search_term.lower() in term["en"].lower()] | |
if category_filter != "الكل": | |
filtered_terms = [term for term in filtered_terms if term["category"] == category_filter] | |
# عرض المصطلحات | |
st.markdown("#### المصطلحات الفنية") | |
if not filtered_terms: | |
st.info("لا توجد مصطلحات تطابق معايير البحث") | |
else: | |
# تحويل البيانات إلى DataFrame | |
terms_df = pd.DataFrame(filtered_terms) | |
# إعادة تسمية الأعمدة | |
terms_df = terms_df.rename(columns={ | |
"ar": "المصطلح بالعربية", | |
"en": "المصطلح بالإنجليزية", | |
"category": "الفئة" | |
}) | |
# عرض الجدول | |
st.dataframe( | |
terms_df, | |
use_container_width=True, | |
hide_index=True | |
) | |
# أزرار إضافية | |
col1, col2 = st.columns([1, 5]) | |
with col1: | |
if st.button("تصدير القاموس", use_container_width=True): | |
st.success("تم تصدير القاموس بنجاح") | |
# عرض إحصائيات القاموس | |
st.markdown("#### إحصائيات القاموس") | |
# حساب عدد المصطلحات في كل فئة | |
category_counts = {} | |
for term in self.technical_terms: | |
if term["category"] not in category_counts: | |
category_counts[term["category"]] = 0 | |
category_counts[term["category"]] += 1 | |
# عرض الإحصائيات | |
col1, col2 = st.columns(2) | |
with col1: | |
st.markdown("##### عدد المصطلحات حسب الفئة") | |
# تحويل البيانات إلى DataFrame | |
category_df = pd.DataFrame({ | |
"الفئة": list(category_counts.keys()), | |
"العدد": list(category_counts.values()) | |
}) | |
# عرض الرسم البياني | |
st.bar_chart(category_df.set_index("الفئة")) | |
with col2: | |
st.markdown("##### إحصائيات عامة") | |
total_terms = len(self.technical_terms) | |
categories_count = len(category_counts) | |
st.markdown(f"**إجمالي المصطلحات:** {total_terms}") | |
st.markdown(f"**عدد الفئات:** {categories_count}") | |
st.markdown(f"**متوسط المصطلحات لكل فئة:** {total_terms / categories_count:.1f}") | |
st.markdown(f"**آخر تحديث للقاموس:** {datetime.datetime.now().strftime('%Y-%m-%d')}") | |
def show_translated_documents(self): | |
"""عرض المستندات المترجمة""" | |
st.markdown("### المستندات المترجمة") | |
# إنشاء فلاتر للمستندات | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
entity_filter = st.selectbox( | |
"تصفية حسب الكيان", | |
options=["الكل"] + list(set([doc["related_entity"] for doc in self.translated_documents])) | |
) | |
with col2: | |
language_pair_filter = st.selectbox( | |
"تصفية حسب زوج اللغات", | |
options=["الكل"] + list(set([f"{doc['source_language']} -> {doc['target_language']}" for doc in self.translated_documents])) | |
) | |
with col3: | |
status_filter = st.selectbox( | |
"تصفية حسب الحالة", | |
options=["الكل", "مكتمل", "قيد التنفيذ"] | |
) | |
# تطبيق الفلاتر | |
filtered_docs = self.translated_documents | |
if entity_filter != "الكل": | |
filtered_docs = [doc for doc in filtered_docs if doc["related_entity"] == entity_filter] | |
if language_pair_filter != "الكل": | |
source_lang, target_lang = language_pair_filter.split(" -> ") | |
filtered_docs = [doc for doc in filtered_docs if doc["source_language"] == source_lang and doc["target_language"] == target_lang] | |
if status_filter != "الكل": | |
filtered_docs = [doc for doc in filtered_docs if doc["status"] == status_filter] | |
# عرض المستندات المترجمة | |
if not filtered_docs: | |
st.info("لا توجد مستندات مترجمة تطابق معايير التصفية") | |
else: | |
# تحويل البيانات إلى DataFrame | |
docs_df = pd.DataFrame(filtered_docs) | |
# تحويل رموز اللغات إلى أسماء اللغات | |
docs_df["source_language"] = docs_df["source_language"].map(self.supported_languages) | |
docs_df["target_language"] = docs_df["target_language"].map(self.supported_languages) | |
# إعادة ترتيب الأعمدة وتغيير أسمائها | |
display_df = docs_df[[ | |
"id", "name", "source_language", "target_language", "translation_date", "status", "pages", "related_entity" | |
]].rename(columns={ | |
"id": "الرقم", | |
"name": "اسم المستند", | |
"source_language": "لغة المصدر", | |
"target_language": "لغة الهدف", | |
"translation_date": "تاريخ الترجمة", | |
"status": "الحالة", | |
"pages": "عدد الصفحات", | |
"related_entity": "الكيان المرتبط" | |
}) | |
# عرض الجدول | |
st.dataframe( | |
display_df, | |
use_container_width=True, | |
hide_index=True | |
) | |
# عرض تفاصيل المستند المحدد | |
st.markdown("#### تفاصيل المستند المترجم") | |
selected_doc_id = st.selectbox( | |
"اختر مستنداً لعرض التفاصيل", | |
options=[doc["id"] for doc in filtered_docs], | |
format_func=lambda x: next((f"{doc['id']} - {doc['name']}" for doc in filtered_docs if doc["id"] == x), "") | |
) | |
# العثور على المستند المحدد | |
selected_doc = next((doc for doc in filtered_docs if doc["id"] == selected_doc_id), None) | |
if selected_doc: | |
col1, col2 = st.columns(2) | |
with col1: | |
st.markdown(f"**اسم المستند:** {selected_doc['name']}") | |
st.markdown(f"**لغة المصدر:** {self.supported_languages[selected_doc['source_language']]}") | |
st.markdown(f"**لغة الهدف:** {self.supported_languages[selected_doc['target_language']]}") | |
st.markdown(f"**تاريخ الترجمة:** {selected_doc['translation_date']}") | |
with col2: | |
st.markdown(f"**الملف الأصلي:** {selected_doc['original_file']}") | |
st.markdown(f"**الملف المترجم:** {selected_doc['translated_file']}") | |
st.markdown(f"**المترجم:** {selected_doc['translated_by']}") | |
st.markdown(f"**الحالة:** {selected_doc['status']}") | |
# أزرار الإجراءات | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
if st.button("تنزيل الملف الأصلي", use_container_width=True): | |
st.success("تم بدء تنزيل الملف الأصلي") | |
with col2: | |
if st.button("تنزيل الملف المترجم", use_container_width=True): | |
st.success("تم بدء تنزيل الملف المترجم") | |
with col3: | |
if st.button("مشاركة الملف المترجم", use_container_width=True): | |
st.success("تم نسخ رابط مشاركة الملف المترجم") | |
# عرض إحصائيات الترجمة | |
st.markdown("#### إحصائيات الترجمة") | |
col1, col2, col3 = st.columns(3) | |
with col1: | |
# إحصائيات حسب زوج اللغات | |
language_pairs = {} | |
for doc in self.translated_documents: | |
pair = f"{self.supported_languages[doc['source_language']]} -> {self.supported_languages[doc['target_language']]}" | |
if pair not in language_pairs: | |
language_pairs[pair] = 0 | |
language_pairs[pair] += 1 | |
st.markdown("##### المستندات حسب زوج اللغات") | |
# تحويل البيانات إلى DataFrame | |
language_df = pd.DataFrame({ | |
"زوج اللغات": list(language_pairs.keys()), | |
"العدد": list(language_pairs.values()) | |
}) | |
# عرض الرسم البياني | |
st.bar_chart(language_df.set_index("زوج اللغات")) | |
with col2: | |
# إحصائيات حسب الكيان المرتبط | |
entity_counts = {} | |
for doc in self.translated_documents: | |
if doc["related_entity"] not in entity_counts: | |
entity_counts[doc["related_entity"]] = 0 | |
entity_counts[doc["related_entity"]] += 1 | |
st.markdown("##### المستندات حسب الكيان المرتبط") | |
# تحويل البيانات إلى DataFrame | |
entity_df = pd.DataFrame({ | |
"الكيان المرتبط": list(entity_counts.keys()), | |
"العدد": list(entity_counts.values()) | |
}) | |
# عرض الرسم البياني | |
st.bar_chart(entity_df.set_index("الكيان المرتبط")) | |
with col3: | |
# إحصائيات عامة | |
total_docs = len(self.translated_documents) | |
completed_docs = len([doc for doc in self.translated_documents if doc["status"] == "مكتمل"]) | |
in_progress_docs = len([doc for doc in self.translated_documents if doc["status"] == "قيد التنفيذ"]) | |
total_pages = sum([doc["pages"] for doc in self.translated_documents]) | |
st.markdown("##### إحصائيات عامة") | |
st.markdown(f"**إجمالي المستندات المترجمة:** {total_docs}") | |
st.markdown(f"**المستندات المكتملة:** {completed_docs}") | |
st.markdown(f"**المستندات قيد التنفيذ:** {in_progress_docs}") | |
st.markdown(f"**إجمالي الصفحات المترجمة:** {total_pages}") | |
st.markdown(f"**متوسط الصفحات لكل مستند:** {total_pages / total_docs:.1f}") | |
# تشغيل التطبيق | |
if __name__ == "__main__": | |
translation_app = TranslationApp() | |
translation_app.run() | |