joermd commited on
Commit
c5905b4
·
verified ·
1 Parent(s): 788900f

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +62 -1405
index.html CHANGED
@@ -6,7 +6,6 @@
6
  <title>نظام المقارنة والترجمة الخاص بشركة موندو لينجوا</title>
7
  <link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
8
  <script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.6.0/mammoth.browser.min.js"></script>
9
- <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.10.377/pdf.min.js"></script>
10
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
11
  <style>
12
  @keyframes gradient {
@@ -82,129 +81,6 @@
82
  70% { box-shadow: 0 0 0 10px rgba(59, 130, 246, 0); }
83
  100% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); }
84
  }
85
- /* زر التنزيل */
86
- .download-btn {
87
- background-color: #10B981;
88
- transition: all 0.3s ease;
89
- }
90
- .download-btn:hover {
91
- background-color: #059669;
92
- transform: translateY(-2px);
93
- }
94
- /* تنسيق اسم الملف */
95
- .file-name {
96
- max-width: 200px;
97
- overflow: hidden;
98
- text-overflow: ellipsis;
99
- white-space: nowrap;
100
- }
101
- /* تنسيق معلومات الملف */
102
- .file-info {
103
- background-color: #F3F4F6;
104
- border-radius: 8px;
105
- padding: 8px 12px;
106
- margin-top: 8px;
107
- font-size: 0.9rem;
108
- }
109
- /* تنسيق مؤشر التقدم */
110
- .progress-bar {
111
- width: 100%;
112
- height: 8px;
113
- background-color: #E5E7EB;
114
- border-radius: 4px;
115
- overflow: hidden;
116
- margin-top: 8px;
117
- }
118
- .progress-fill {
119
- height: 100%;
120
- background-color: #3B82F6;
121
- width: 0%;
122
- transition: width 0.3s ease;
123
- }
124
- /* تنسيق قسم OCR */
125
- .ocr-section {
126
- margin-top: 20px;
127
- padding: 15px;
128
- border-radius: 8px;
129
- background-color: #EFF6FF;
130
- border: 1px solid #DBEAFE;
131
- }
132
- .ocr-result {
133
- margin-top: 15px;
134
- padding: 10px;
135
- background-color: #F9FAFB;
136
- border-radius: 6px;
137
- border: 1px solid #E5E7EB;
138
- max-height: 300px;
139
- overflow-y: auto;
140
- }
141
- /* تنسيق مؤشر التقدم الدائري */
142
- .circular-progress {
143
- position: relative;
144
- width: 60px;
145
- height: 60px;
146
- margin: 0 auto;
147
- }
148
- .circular-progress-circle {
149
- stroke-dasharray: 283;
150
- stroke-dashoffset: 283;
151
- transform: rotate(-90deg);
152
- transform-origin: 50% 50%;
153
- }
154
- .circular-progress-text {
155
- position: absolute;
156
- top: 50%;
157
- left: 50%;
158
- transform: translate(-50%, -50%);
159
- font-size: 14px;
160
- font-weight: bold;
161
- }
162
- /* تنسيق عرض صفحات PDF */
163
- .pdf-pages-grid {
164
- display: grid;
165
- grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
166
- gap: 15px;
167
- margin-top: 20px;
168
- }
169
- .pdf-page-thumbnail {
170
- border: 1px solid #E5E7EB;
171
- border-radius: 8px;
172
- overflow: hidden;
173
- position: relative;
174
- cursor: pointer;
175
- transition: all 0.2s;
176
- }
177
- .pdf-page-thumbnail:hover {
178
- transform: translateY(-3px);
179
- box-shadow: 0 5px 15px rgba(0,0,0,0.1);
180
- }
181
- .pdf-page-number {
182
- position: absolute;
183
- bottom: 0;
184
- left: 0;
185
- right: 0;
186
- background-color: rgba(0,0,0,0.6);
187
- color: white;
188
- font-size: 0.8rem;
189
- text-align: center;
190
- padding: 3px 0;
191
- }
192
- .pdf-page-selected {
193
- border: 2px solid #3B82F6;
194
- }
195
- .pdf-toolbar {
196
- display: flex;
197
- align-items: center;
198
- margin-top: 15px;
199
- padding: 10px;
200
- background-color: #F9FAFB;
201
- border-radius: 8px;
202
- justify-content: space-between;
203
- }
204
- .pdf-page-canvas {
205
- width: 100%;
206
- height: auto;
207
- }
208
  </style>
209
  </head>
210
  <body class="bg-gradient-to-br from-gray-50 via-blue-50 to-indigo-50 min-h-screen">
@@ -222,111 +98,61 @@
222
  <!-- قسم رفع الملفات -->
223
  <div class="bg-white rounded-2xl shadow-lg p-8 border border-gray-100 hover:shadow-xl transition-all animate-scale mb-8 card-hover">
224
  <h2 class="text-2xl font-bold mb-6 text-gray-800 flex items-center border-b pb-3">
225
- <i class="fas fa-file-upload text-blue-600 ml-2"></i> تحليل الملفات مباشرة
226
  </h2>
227
  <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
228
  <!-- ملف السورس -->
229
  <div class="group border-2 border-dashed border-blue-200 rounded-xl p-8 text-center hover:border-blue-500 transition-colors duration-300 bg-blue-50 hover:bg-blue-100">
230
  <label class="cursor-pointer block">
231
- <input type="file" id="sourceFile" accept=".docx,.pdf,.txt,.png,.jpg,.jpeg" class="hidden">
232
  <i class="fas fa-file-upload text-5xl text-blue-500 mb-4"></i>
233
  <span class="text-lg text-blue-600 group-hover:text-blue-700">ملف السور��</span>
234
- <p class="text-sm text-gray-500 mt-2">(.docx, .pdf, .txt, .png, .jpg)</p>
235
- <div id="sourceFileInfo" class="mt-2 text-sm text-gray-600"></div>
236
  </label>
237
  </div>
238
  <!-- ملف التارجت -->
239
  <div class="group border-2 border-dashed border-purple-200 rounded-xl p-8 text-center hover:border-purple-500 transition-colors duration-300 bg-purple-50 hover:bg-purple-100">
240
  <label class="cursor-pointer block">
241
- <input type="file" id="targetFile" accept=".docx,.pdf,.txt,.png,.jpg,.jpeg" class="hidden">
242
  <i class="fas fa-file-download text-5xl text-purple-500 mb-4"></i>
243
  <span class="text-lg text-purple-600 group-hover:text-purple-700">ملف التارجت</span>
244
- <p class="text-sm text-gray-500 mt-2">(.docx, .pdf, .txt, .png, .jpg)</p>
245
- <div id="targetFileInfo" class="mt-2 text-sm text-gray-600"></div>
246
  </label>
247
  </div>
248
  </div>
249
  <div id="processStatus" class="hidden mt-4">
250
  <div class="flex items-center justify-center space-x-3 bg-blue-100 rounded-xl p-4">
251
  <div class="animate-spin h-8 w-8 border-4 border-blue-600 rounded-full border-t-transparent"></div>
252
- <span class="text-lg text-blue-700">جارٍ معالجة الملفات...</span>
253
- </div>
254
- <div class="progress-bar mt-2">
255
- <div id="progressFill" class="progress-fill"></div>
256
  </div>
257
  </div>
258
-
259
- <!-- عرض صفحات PDF -->
260
- <div id="pdfPagesContainer" class="hidden mt-6">
261
- <div class="bg-blue-50 p-4 rounded-xl mb-4">
262
- <h3 class="text-lg font-bold text-blue-800 mb-3">صفحات ملف PDF</h3>
263
- <p class="text-sm text-blue-600 mb-4">اختر الصفحات التي تريد استخراج النص منها (انقر للتحديد/إلغاء التحديد)</p>
264
-
265
- <div class="pdf-toolbar">
266
- <div>
267
- <button id="selectAllPagesBtn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg ml-2 text-sm">
268
- تحديد الكل
269
- </button>
270
- <button id="deselectAllPagesBtn" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg text-sm">
271
- إلغاء تحديد الكل
272
- </button>
273
- </div>
274
- <button id="extractSelectedPagesBtn" class="bg-green-500 hover:bg-green-600 text-white px-6 py-2 rounded-lg text-sm flex items-center">
275
- <i class="fas fa-file-export ml-2"></i> استخراج النص من الصفحات المحددة
276
- </button>
277
- </div>
278
-
279
- <!-- هنا يتم عرض الصور المصغرة للصفحات -->
280
- <div id="pdfPagesGrid" class="pdf-pages-grid">
281
- <!-- سيتم إضافة الصفحات هنا ديناميكيًا -->
282
- </div>
283
- </div>
284
- </div>
285
-
286
- <!-- زر استخراج النصوص -->
287
- <button id="extractTextBtn" class="w-full mt-6 bg-gradient-to-r from-green-600 to-teal-600 hover:from-green-700 hover:to-teal-700 text-white font-bold py-4 px-6 rounded-xl transition-all transform hover:scale-105 focus:ring-green-200 text-lg shadow-lg hover:shadow-xl">
288
- <div class="flex items-center justify-center">
289
- <i class="fas fa-file-alt ml-2"></i> استخراج النصوص من الملفات
290
- </div>
291
- </button>
292
-
293
- <!-- زر تحليل الملفات -->
294
- <button id="analyzeFilesBtn" class="w-full mt-4 bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 text-white font-bold py-4 px-6 rounded-xl transition-all transform hover:scale-105 focus:ring-blue-200 text-lg shadow-lg hover:shadow-xl">
295
- <div class="flex items-center justify-center">
296
- <i class="fas fa-file-search ml-2"></i> تحليل الملفات
297
- </div>
298
- </button>
299
  </div>
300
 
301
  <!-- إدخال النصوص يدويًا -->
302
  <div class="bg-white rounded-2xl shadow-lg p-8 border border-gray-100 hover:shadow-xl transition-all animate-scale mb-8 card-hover">
303
- <h2 class="text-2xl font-bold mb-6 text-gray-800 flex items-center border-b pb-3">
304
- <i class="fas fa-keyboard text-blue-600 ml-2"></i> إدخال النصوص يدوياً
305
- </h2>
306
  <div class="space-y-6">
307
  <!-- النص المصدر -->
308
  <div class="group">
309
  <label class="block text-lg font-bold text-gray-700 mb-3 flex items-center">
310
  <i class="fas fa-language text-blue-600 ml-2"></i> النص المصدر
311
  </label>
312
- <textarea id="sourceText" dir="rtl" class="w-full px-6 py-4 border-2 border-gray-200 rounded-xl focus:ring-blue-200 focus:border-blue-400 transition-all resize-none text-lg" rows="10" placeholder="اكتب النص المصدر هنا..."></textarea>
313
  </div>
314
  <!-- النص الهدف -->
315
  <div class="group">
316
  <label class="block text-lg font-bold text-gray-700 mb-3 flex items-center">
317
  <i class="fas fa-language text-purple-600 ml-2"></i> النص الهدف
318
  </label>
319
- <textarea id="targetText" dir="ltr" class="w-full px-6 py-4 border-2 border-gray-200 rounded-xl focus:ring-purple-200 focus:border-purple-400 transition-all resize-none text-lg" rows="10" placeholder="اكتب النص الهدف هنا..."></textarea>
320
  </div>
321
  </div>
322
- <!-- زر تحليل النصوص -->
323
- <button id="submitBtn" class="w-full mt-6 bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white font-bold py-4 px-6 rounded-xl transition-all transform hover:scale-105 focus:ring-blue-200 text-lg shadow-lg hover:shadow-xl pulse-animation">
324
- <div class="flex items-center justify-center">
325
- <i class="fas fa-sync-alt ml-2"></i> تحليل النصوص
326
- </div>
327
- </button>
328
  </div>
329
 
 
 
 
 
 
 
 
330
  <!-- شاشة نتائج التحليل (المعاينة المقسمة) -->
331
  <div id="resultSection" class="bg-white rounded-2xl shadow-lg p-8 border border-gray-100 hover:shadow-xl transition-all animate-scale mb-8 hidden card-hover">
332
  <h2 class="text-2xl font-bold mb-6 text-gray-800 border-b pb-3 flex items-center">
@@ -350,17 +176,6 @@
350
  <div id="targetTextReview" class="bg-gray-50 rounded-xl p-6 min-h-[200px] border-2 border-gray-200 text-comparison"></div>
351
  </div>
352
  </div>
353
-
354
- <!-- أزرار التحكم -->
355
- <div class="mt-8 flex flex-wrap justify-center gap-4">
356
- <button id="downloadReportBtn" class="download-btn text-white font-bold py-4 px-8 rounded-xl shadow-lg flex items-center">
357
- <i class="fas fa-download ml-2"></i> تنزيل تقرير التحليل
358
- </button>
359
-
360
- <button id="reloadAnalysisBtn" class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-4 px-8 rounded-xl shadow-lg flex items-center transition-all">
361
- <i class="fas fa-redo-alt ml-2"></i> إعادة التحليل
362
- </button>
363
- </div>
364
  </div>
365
 
366
  <!-- صندوق شرح الاختلافات -->
@@ -379,10 +194,6 @@
379
  const API_URL = 'https://api.deepseek.com/chat/completions';
380
  const API_KEY = 'sk-15606736ed9e4aea8b7cc11a195d2b01';
381
 
382
- // API4AI OCR Configuration
383
- const RAPIDAPI_KEY = 'eb11693cddmshb8bd157e05b74acp1f6aa4jsn4369fa546e55';
384
- const OCR_API_URL = 'https://ocr43.p.rapidapi.com/v1/results';
385
-
386
  /*
387
  الـ prompt المحسن:
388
  أنت خبير في تحليل النصوص ومقارنتها. قم بمقارنة النص المصدر والنص الهدف بدقة عالية واكتشف الاختلافات التالية فقط:
@@ -419,37 +230,7 @@
419
  النص الهدف:
420
  {target}
421
 
422
- أخرج فقط الاختلافات المحددة بالعلامات المذكورة أعلاه، دون أي شرح إضافي.
423
-
424
- ملاحظة مهمة: قم بفحص النصوص بدقة عالية. إذا كانت هناك اختلافات حتى بسيطة، يجب تحديدها. لا تكتب [MATCH] إلا إذا كانت النصوص متطابقة تماماً بنسبة 100%.`;
425
-
426
- // متغيرات عامة لتخزين نتائج التحليل
427
- let analysisResults = {
428
- sourceText: "",
429
- targetText: "",
430
- analysisOutput: "",
431
- explanationHTML: "",
432
- numDiffCount: 0,
433
- missingDiffCount: 0,
434
- meaningDiffCount: 0,
435
- timestamp: "",
436
- sourceFileName: "",
437
- targetFileName: ""
438
- };
439
-
440
- // متغيرات لحفظ صفحات PDF المحددة
441
- let pdfPages = {
442
- source: {
443
- pdf: null,
444
- pages: [],
445
- selectedPages: []
446
- },
447
- target: {
448
- pdf: null,
449
- pages: [],
450
- selectedPages: []
451
- }
452
- };
453
 
454
  // دالة لحساب عدد الكلمات
455
  function countWords(text) {
@@ -552,421 +333,58 @@
552
  return explanation;
553
  }
554
 
555
- // دالة استخراج النص من ملف DOCX
556
- async function extractTextFromDocx(file) {
557
- try {
 
 
 
 
 
 
 
 
 
 
 
558
  const arrayBuffer = await file.arrayBuffer();
559
  const result = await mammoth.extractRawText({ arrayBuffer });
560
- return result.value;
561
- } catch (error) {
562
- console.error("Error extracting text from DOCX:", error);
563
- throw new Error(`فشل في استخراج النص من ملف DOCX: ${error.message}`);
564
- }
565
- }
566
-
567
- // دالة عرض صفحات PDF كصور مصغرة وإتاحة اختيار الصفحات
568
- async function displayPdfPages(file, type) {
569
- try {
570
- // تحميل ملف PDF
571
- const arrayBuffer = await file.arrayBuffer();
572
- const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
573
-
574
- // تخزين مرجع PDF
575
- pdfPages[type].pdf = pdf;
576
- pdfPages[type].pages = [];
577
- pdfPages[type].selectedPages = [];
578
-
579
- // إنشاء عناصر الصفحات المصغرة
580
- const pdfPagesGrid = document.getElementById('pdfPagesGrid');
581
- pdfPagesGrid.innerHTML = '';
582
-
583
- // إظهار قسم صفحات PDF
584
- document.getElementById('pdfPagesContainer').classList.remove('hidden');
585
-
586
- // تحديث عنوان قسم صفحات PDF
587
- const pdfTitle = document.querySelector('#pdfPagesContainer h3');
588
- pdfTitle.textContent = `صفحات ملف PDF (${type === 'source' ? 'المصدر' : 'الهدف'}) - ${pdf.numPages} صفحة`;
589
-
590
- // إنشاء صورة مصغرة لكل صفحة
591
- for (let i = 1; i <= pdf.numPages; i++) {
592
- const page = await pdf.getPage(i);
593
- pdfPages[type].pages.push(page);
594
-
595
- // إنشاء عنصر div للصفحة المصغرة
596
- const thumbnailDiv = document.createElement('div');
597
- thumbnailDiv.className = 'pdf-page-thumbnail';
598
- thumbnailDiv.dataset.page = i;
599
- thumbnailDiv.dataset.type = type;
600
-
601
- // إنشاء canvas لعرض الصفحة
602
- const canvas = document.createElement('canvas');
603
- canvas.className = 'pdf-page-canvas';
604
- const context = canvas.getContext('2d');
605
-
606
- // ضبط حجم Canvas
607
- const viewport = page.getViewport({ scale: 0.3 }); // حجم مصغر للعرض
608
- canvas.width = viewport.width;
609
- canvas.height = viewport.height;
610
-
611
- // عرض الصفحة في Canvas
612
- await page.render({
613
- canvasContext: context,
614
- viewport: viewport
615
- }).promise;
616
-
617
- // إضافة رقم الصفحة
618
- const pageNumberDiv = document.createElement('div');
619
- pageNumberDiv.className = 'pdf-page-number';
620
- pageNumberDiv.textContent = `صفحة ${i}`;
621
-
622
- // إضافة العناصر إلى div الصفحة المصغرة
623
- thumbnailDiv.appendChild(canvas);
624
- thumbnailDiv.appendChild(pageNumberDiv);
625
-
626
- // إضافة حدث النقر على الصفحة للتحديد/إلغاء التحديد
627
- thumbnailDiv.addEventListener('click', function() {
628
- // تبديل حالة التحديد
629
- if (this.classList.contains('pdf-page-selected')) {
630
- this.classList.remove('pdf-page-selected');
631
- // إزالة الصفحة من قائمة الصفحات المحددة
632
- const pageIndex = pdfPages[type].selectedPages.indexOf(parseInt(this.dataset.page));
633
- if (pageIndex > -1) {
634
- pdfPages[type].selectedPages.splice(pageIndex, 1);
635
- }
636
- } else {
637
- this.classList.add('pdf-page-selected');
638
- // إضافة الصفحة إلى قائمة الصفحات المحددة
639
- pdfPages[type].selectedPages.push(parseInt(this.dataset.page));
640
- }
641
- });
642
-
643
- // إضافة div الصفحة المصغرة إلى الشبكة
644
- pdfPagesGrid.appendChild(thumbnailDiv);
645
-
646
- // تحديث مؤشر التقدم
647
- document.getElementById('progressFill').style.width = `${Math.round((i / pdf.numPages) * 100)}%`;
648
- }
649
-
650
- return pdf.numPages;
651
- } catch (error) {
652
- console.error("Error displaying PDF pages:", error);
653
- throw new Error(`فشل في عرض صفحات PDF: ${error.message}`);
654
- }
655
- }
656
-
657
- // دالة استخراج النص من صفحات PDF محددة
658
- async function extractTextFromSelectedPdfPages(type) {
659
- try {
660
- const pdf = pdfPages[type].pdf;
661
- if (!pdf) {
662
- throw new Error('لم يتم تحميل ملف PDF');
663
- }
664
-
665
- // التحقق من وجود صفحات محددة
666
- if (pdfPages[type].selectedPages.length === 0) {
667
- throw new Error('لم يتم تحديد أي صفحات');
668
- }
669
-
670
- // ترتيب الصفحات المحددة تصاعديًا
671
- pdfPages[type].selectedPages.sort((a, b) => a - b);
672
-
673
- // استخراج النص من كل صفحة محددة
674
- let text = '';
675
- const totalPages = pdfPages[type].selectedPages.length;
676
-
677
- // إنشاء مؤشر تقدم للصفحات
678
- const progressDiv = document.createElement('div');
679
- progressDiv.className = "mt-4 p-4 bg-blue-50 rounded-xl";
680
- progressDiv.innerHTML = `
681
- <div class="text-center mb-2">جارٍ استخراج النص من ${totalPages} صفحة محددة...</div>
682
- <div class="flex items-center justify-center">
683
- <div class="circular-progress">
684
- <svg width="60" height="60" viewBox="0 0 60 60">
685
- <circle cx="30" cy="30" r="25" fill="none" stroke="#E5E7EB" stroke-width="5"></circle>
686
- <circle id="progress-circle-${type}" cx="30" cy="30" r="25" fill="none" stroke="#3B82F6" stroke-width="5" class="circular-progress-circle"></circle>
687
- </svg>
688
- <div class="circular-progress-text" id="circular-progress-text-${type}">0%</div>
689
- </div>
690
- <div class="mr-4" id="page-progress-${type}">0/${totalPages}</div>
691
- </div>
692
- `;
693
-
694
- document.getElementById('processStatus').appendChild(progressDiv);
695
-
696
- // استخراج النص من كل صفحة محددة
697
- for (let i = 0; i < totalPages; i++) {
698
- const pageNum = pdfPages[type].selectedPages[i];
699
- const page = await pdf.getPage(pageNum);
700
- const content = await page.getTextContent();
701
- const strings = content.items.map(item => item.str);
702
- text += `=== صفحة ${pageNum} ===\n` + strings.join(' ') + '\n\n';
703
-
704
- // تحديث مؤشر التقدم
705
- const progress = Math.round(((i + 1) / totalPages) * 100);
706
-
707
- // تحديث مؤشر التقدم الدائري
708
- const circle = document.getElementById(`progress-circle-${type}`);
709
- if (circle) {
710
- const circumference = 2 * Math.PI * 25; // 2πr
711
- const offset = circumference - (progress / 100) * circumference;
712
- circle.style.strokeDashoffset = offset;
713
- document.getElementById(`circular-progress-text-${type}`).textContent = `${progress}%`;
714
- document.getElementById(`page-progress-${type}`).textContent = `${i + 1}/${totalPages}`;
715
- }
716
-
717
- // إعطاء فرصة للمتصفح لتحديث واجهة المستخدم
718
- await new Promise(resolve => setTimeout(resolve, 10));
719
- }
720
-
721
- // إزالة مؤشر التقدم بعد الانتهاء
722
- if (progressDiv && progressDiv.parentNode) {
723
- progressDiv.parentNode.removeChild(progressDiv);
724
- }
725
-
726
- return text;
727
- } catch (error) {
728
- console.error("Error extracting text from selected PDF pages:", error);
729
- throw new Error(`فشل في استخراج النص من صفحات PDF المحددة: ${error.message}`);
730
- }
731
- }
732
-
733
- // دالة استخراج النص من ملف PDF كامل
734
- async function extractTextFromPdf(file) {
735
- try {
736
- const arrayBuffer = await file.arrayBuffer();
737
- const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
738
- let text = '';
739
-
740
- // تحديث إجمالي عدد الصفحات في واجهة المستخدم
741
- const totalPages = pdf.numPages;
742
-
743
- // إنشاء مؤشر تقدم للصفحات
744
- const progressDiv = document.createElement('div');
745
- progressDiv.className = "mt-4 p-4 bg-blue-50 rounded-xl";
746
- progressDiv.innerHTML = `
747
- <div class="text-center mb-2">جارٍ استخراج النص من ${totalPages} صفحة...</div>
748
- <div class="flex items-center justify-center">
749
- <div class="circular-progress">
750
- <svg width="60" height="60" viewBox="0 0 60 60">
751
- <circle cx="30" cy="30" r="25" fill="none" stroke="#E5E7EB" stroke-width="5"></circle>
752
- <circle id="progress-circle" cx="30" cy="30" r="25" fill="none" stroke="#3B82F6" stroke-width="5" class="circular-progress-circle"></circle>
753
- </svg>
754
- <div class="circular-progress-text">0%</div>
755
- </div>
756
- <div class="mr-4" id="page-progress">0/${totalPages}</div>
757
- </div>
758
- `;
759
-
760
- document.getElementById('processStatus').appendChild(progressDiv);
761
-
762
- // استخراج النص من كل صفحة
763
- for (let i = 1; i <= totalPages; i++) {
764
- const page = await pdf.getPage(i);
765
- const content = await page.getTextContent();
766
- const strings = content.items.map(item => item.str);
767
- text += `=== صفحة ${i} ===\n` + strings.join(' ') + '\n\n';
768
-
769
- // تحديث مؤشر التقدم
770
- const progress = Math.round((i / totalPages) * 100);
771
- document.getElementById('progressFill').style.width = `${progress}%`;
772
-
773
- // تحديث مؤشر التقدم الدائري
774
- const circle = document.getElementById('progress-circle');
775
- if (circle) {
776
- const circumference = 2 * Math.PI * 25; // 2πr
777
- const offset = circumference - (progress / 100) * circumference;
778
- circle.style.strokeDashoffset = offset;
779
- document.querySelector('.circular-progress-text').textContent = `${progress}%`;
780
- document.getElementById('page-progress').textContent = `${i}/${totalPages}`;
781
- }
782
-
783
- // إعطاء فرصة للمتصفح لتحديث واجهة المستخدم
784
- await new Promise(resolve => setTimeout(resolve, 10));
785
- }
786
-
787
- // إزالة مؤشر التقدم بعد الانتهاء
788
- if (progressDiv && progressDiv.parentNode) {
789
- progressDiv.parentNode.removeChild(progressDiv);
790
- }
791
-
792
- return text;
793
- } catch (error) {
794
- console.error("Error extracting text from PDF:", error);
795
- throw new Error(`فشل في استخراج النص من ملف PDF: ${error.message}`);
796
- }
797
- }
798
-
799
- // دالة استخراج النص من ملف نصي
800
- async function extractTextFromTxt(file) {
801
- try {
802
- return await file.text();
803
- } catch (error) {
804
- console.error("Error extracting text from TXT:", error);
805
- throw new Error(`فشل في استخراج النص من ملف نصي: ${error.message}`);
806
- }
807
- }
808
-
809
- // دالة استخراج النص من صورة باستخدام OCR
810
- async function extractTextFromImage(file) {
811
- try {
812
- // إنشاء مؤشر تقدم للـ OCR
813
- const progressDiv = document.createElement('div');
814
- progressDiv.className = "mt-4 p-4 bg-blue-50 rounded-xl";
815
- progressDiv.innerHTML = `
816
- <div class="text-center mb-2">جارٍ استخراج النص من الصورة باستخدام OCR...</div>
817
- <div class="flex items-center justify-center">
818
- <div class="animate-spin h-8 w-8 border-4 border-blue-600 rounded-full border-t-transparent"></div>
819
- <span class="mr-4 text-blue-700">يرجى الانتظار، قد تستغرق هذه العملية بعض الوقت</span>
820
- </div>
821
- `;
822
-
823
- document.getElementById('processStatus').appendChild(progressDiv);
824
-
825
- // تنفيذ طلب OCR باستخدام XMLHttpRequest
826
- return new Promise((resolve, reject) => {
827
- const form = new FormData();
828
- form.append('image', file);
829
-
830
- const xhr = new XMLHttpRequest();
831
- xhr.withCredentials = true;
832
-
833
- xhr.addEventListener('readystatechange', function() {
834
- if (this.readyState === this.DONE) {
835
- // إزالة مؤشر التقدم
836
- if (progressDiv && progressDiv.parentNode) {
837
- progressDiv.parentNode.removeChild(progressDiv);
838
- }
839
-
840
- if (this.status === 200) {
841
- try {
842
- const response = JSON.parse(this.responseText);
843
- if (response && response.results && response.results[0] &&
844
- response.results[0].entities && response.results[0].entities[0] &&
845
- response.results[0].entities[0].objects && response.results[0].entities[0].objects[0] &&
846
- response.results[0].entities[0].objects[0].entities && response.results[0].entities[0].objects[0].entities[0]) {
847
- const text = response.results[0].entities[0].objects[0].entities[0].text;
848
- resolve(text);
849
- } else {
850
- reject(new Error('تنسيق استجابة OCR غير ص��لح'));
851
- }
852
- } catch (error) {
853
- reject(new Error(`فشل في تحليل استجابة OCR: ${error.message}`));
854
- }
855
- } else {
856
- reject(new Error(`فشل في طلب OCR: الرمز ${this.status}`));
857
- }
858
- }
859
- });
860
-
861
- xhr.addEventListener('error', function() {
862
- if (progressDiv && progressDiv.parentNode) {
863
- progressDiv.parentNode.removeChild(progressDiv);
864
- }
865
- reject(new Error('حدث خطأ في الشبكة أثناء طلب OCR'));
866
- });
867
-
868
- xhr.open('POST', OCR_API_URL);
869
- xhr.setRequestHeader('x-rapidapi-key', RAPIDAPI_KEY);
870
- xhr.setRequestHeader('x-rapidapi-host', 'ocr43.p.rapidapi.com');
871
-
872
- xhr.send(form);
873
- });
874
- } catch (error) {
875
- console.error("Error extracting text from image:", error);
876
- throw new Error(`فشل في استخراج النص من الصورة: ${error.message}`);
877
- }
878
- }
879
-
880
- // دالة استخراج النص من أي ملف مدعوم
881
- async function extractTextFromFile(file) {
882
- const fileType = file.name.split('.').pop().toLowerCase();
883
-
884
- document.getElementById('progressFill').style.width = '10%';
885
-
886
- switch (fileType) {
887
- case 'docx':
888
- return await extractTextFromDocx(file);
889
- case 'pdf':
890
- // طلب عرض صفحات PDF للاختيار
891
- const currentType = file === document.getElementById('sourceFile').files[0] ? 'source' : 'target';
892
- await displayPdfPages(file, currentType);
893
- // في هذه المرحلة، سيتمكن المستخدم من اختيار الصفحات المطلوبة
894
- // وسيتم استخراج النص لاحقًا عند الضغط على زر استخراج النص
895
- return null;
896
- case 'txt':
897
- document.getElementById('progressFill').style.width = '50%';
898
- const text = await extractTextFromTxt(file);
899
- document.getElementById('progressFill').style.width = '100%';
900
- return text;
901
- case 'png':
902
- case 'jpg':
903
- case 'jpeg':
904
- return await extractTextFromImage(file);
905
- default:
906
- throw new Error(`نوع الملف غير مدعوم: ${fileType}`);
907
  }
 
908
  }
909
 
910
- // عرض معلومات الملف بعد اختياره
911
  document.getElementById('sourceFile')?.addEventListener('change', async (event) => {
912
  const file = event.target.files[0];
913
  if (!file) return;
914
-
915
- const fileInfo = document.getElementById('sourceFileInfo');
916
- fileInfo.innerHTML = `
917
- <div class="file-info">
918
- <div class="file-name"><strong>الملف:</strong> ${file.name}</div>
919
- <div><strong>الحجم:</strong> ${(file.size / 1024).toFixed(2)} كيلوبايت</div>
920
- <div><strong>النوع:</strong> ${file.type || 'غير محدد'}</div>
921
- </div>
922
- `;
923
-
924
- // تخزين اسم الملف
925
- analysisResults.sourceFileName = file.name;
926
-
927
- // إذا كان الملف PDF، عرض صفحاته لاختيار الصفحات المطلوبة
928
- if (file.name.toLowerCase().endsWith('.pdf')) {
929
- document.getElementById('processStatus').classList.remove('hidden');
930
- try {
931
- // عرض صفحات PDF للاختيار
932
- await displayPdfPages(file, 'source');
933
- } catch (error) {
934
- console.error('Error displaying PDF pages:', error);
935
- addError(`حدث خطأ أثناء عرض صفحات PDF: ${error.message}`);
936
- } finally {
937
- document.getElementById('processStatus').classList.add('hidden');
938
- }
939
  }
940
  });
941
 
 
942
  document.getElementById('targetFile')?.addEventListener('change', async (event) => {
943
  const file = event.target.files[0];
944
  if (!file) return;
945
-
946
- const fileInfo = document.getElementById('targetFileInfo');
947
- fileInfo.innerHTML = `
948
- <div class="file-info">
949
- <div class="file-name"><strong>الملف:</strong> ${file.name}</div>
950
- <div><strong>الحجم:</strong> ${(file.size / 1024).toFixed(2)} كيلوبايت</div>
951
- <div><strong>النوع:</strong> ${file.type || 'غير محدد'}</div>
952
- </div>
953
- `;
954
-
955
- // تخزين اسم الملف
956
- analysisResults.targetFileName = file.name;
957
-
958
- // إذا كان الملف PDF، عرض صفحاته لاختيار الصفحات المطلوبة
959
- if (file.name.toLowerCase().endsWith('.pdf')) {
960
- document.getElementById('processStatus').classList.remove('hidden');
961
- try {
962
- // عرض صفحات PDF للاختيار
963
- await displayPdfPages(file, 'target');
964
- } catch (error) {
965
- console.error('Error displaying PDF pages:', error);
966
- addError(`حدث خطأ أثناء عرض صفحات PDF: ${error.message}`);
967
- } finally {
968
- document.getElementById('processStatus').classList.add('hidden');
969
- }
970
  }
971
  });
972
 
@@ -983,8 +401,11 @@
983
  errorsList.appendChild(errorDiv);
984
  }
985
 
986
- // دالة تحليل النصوص
987
- async function analyzeTexts(sourceText, targetText) {
 
 
 
988
  // مسح الرسائل السابقة وإظهار قسم النتائج
989
  document.getElementById('errorsList').innerHTML = '';
990
  document.getElementById('resultSection').classList.remove('hidden');
@@ -998,13 +419,8 @@
998
  // مقارنة عدد الكلمات (تنبيه اختياري)
999
  const sourceWordCount = countWords(sourceText);
1000
  const targetWordCount = countWords(targetText);
1001
- if (Math.abs(sourceWordCount - targetWordCount) > sourceWordCount * 0.1) {
1002
- addError(`عدد كلمات النص المصدر (${sourceWordCount}) يختلف بشكل كبير عن النص الهدف (${targetWordCount})`, 'warning');
1003
- }
1004
-
1005
- // فحص أولي سريع للاختلافات الواضحة
1006
- if (sourceText === targetText) {
1007
- addError('النصوص متطابقة تماماً بشكل حرفي', 'warning');
1008
  }
1009
 
1010
  try {
@@ -1026,10 +442,10 @@
1026
  const payload = {
1027
  model: "deepseek-chat",
1028
  messages: [
1029
- { role: "system", content: "أنت خبير في تحليل النصوص ومقارنتها بدقة عالية. عليك تحديد جميع الاختلافات بين النصوص حتى لو كانت بسيطة." },
1030
  { role: "user", content: prompt }
1031
  ],
1032
- temperature: 0.1, // تقليل درجة الحرارة لزيادة الدقة
1033
  max_tokens: 2048,
1034
  stream: false
1035
  };
@@ -1053,25 +469,7 @@
1053
 
1054
  progressDiv.remove();
1055
 
1056
- // تخزين نتائج التحليل
1057
- analysisResults = {
1058
- sourceText: sourceText,
1059
- targetText: targetText,
1060
- analysisOutput: analysisOutput,
1061
- timestamp: new Date().toLocaleString('ar-SA'),
1062
- sourceFileName: analysisResults.sourceFileName || "إدخال يدوي",
1063
- targetFileName: analysisResults.targetFileName || "إدخال يدوي"
1064
- };
1065
-
1066
- // فحص إضافي للتأكد من دقة التحليل
1067
- const hasActualDifferences = sourceText !== targetText;
1068
- const reportedMatch = analysisOutput.includes('[MATCH]');
1069
-
1070
- if (hasActualDifferences && reportedMatch) {
1071
- addError('تنبيه: النصوص مختلفة ولكن تم الإبلاغ عن تطابقها. يرجى التحقق يدوياً.', 'warning');
1072
- }
1073
-
1074
- if (analysisOutput.includes('[MATCH]') && !hasActualDifferences) {
1075
  const checkDiv = document.createElement('div');
1076
  checkDiv.className = "p-4 rounded-xl bg-green-50 text-green-700 flex items-center";
1077
  checkDiv.innerHTML = `<i class="fas fa-check-circle ml-2 text-lg"></i> <span class="text-lg">النصوص متطابقة تماماً</span>`;
@@ -1079,11 +477,6 @@
1079
  document.getElementById('sourceTextReview').innerHTML = splitIntoLines(sourceText);
1080
  document.getElementById('targetTextReview').innerHTML = splitIntoLines(targetText);
1081
  document.getElementById('explanationText').innerHTML = `<p>[MATCH] لا توجد اختلافات.</p>`;
1082
-
1083
- analysisResults.explanationHTML = `<p>[MATCH] لا توجد اختلافات.</p>`;
1084
- analysisResults.numDiffCount = 0;
1085
- analysisResults.missingDiffCount = 0;
1086
- analysisResults.meaningDiffCount = 0;
1087
  } else {
1088
  const sourceHighlighted = applyHighlights(sourceText, analysisOutput);
1089
  const targetHighlighted = applyHighlights(targetText, analysisOutput);
@@ -1095,19 +488,10 @@
1095
  const explanationHTML = generateExplanation(sourceText, analysisOutput);
1096
  document.getElementById('explanationText').innerHTML = explanationHTML;
1097
 
1098
- // تخزين شرح الاختلافات
1099
- analysisResults.explanationHTML = explanationHTML;
1100
-
1101
  // عرض ملخص الاختلافات إن وُجدت
1102
  const numDiffCount = (analysisOutput.match(/<([^<>]+)>/g) || []).length;
1103
  const missingDiffCount = (analysisOutput.match(/__(.*?)__/g) || []).length;
1104
  const meaningDiffCount = (analysisOutput.match(/\[MEANING\](.*?)\[\/MEANING\]/g) || []).length;
1105
-
1106
- // تخزين عدد الاختلافات
1107
- analysisResults.numDiffCount = numDiffCount;
1108
- analysisResults.missingDiffCount = missingDiffCount;
1109
- analysisResults.meaningDiffCount = meaningDiffCount;
1110
-
1111
  if (numDiffCount > 0 || missingDiffCount > 0 || meaningDiffCount > 0) {
1112
  const summaryDiv = document.createElement('div');
1113
  summaryDiv.className = "p-4 rounded-xl bg-yellow-50 text-gray-800";
@@ -1118,741 +502,14 @@
1118
  summaryText += '</ul>';
1119
  summaryDiv.innerHTML = summaryText;
1120
  document.getElementById('errorsList').appendChild(summaryDiv);
1121
- } else if (hasActualDifferences) {
1122
- // إذا كانت هناك اختلافات ولكن لم يتم اكتشافها
1123
- addError('تنبيه: قد تكون هناك اختلافات لم يتم اكتشافها. يرجى التحقق يدوياً.', 'warning');
1124
  }
1125
  }
1126
 
1127
- return true;
1128
  } catch (error) {
1129
  document.getElementById('errorsList').innerHTML = '';
1130
  addError(`خطأ في التحليل: ${error.message}`);
1131
- return false;
1132
- }
1133
- }
1134
-
1135
- // دالة استخراج النصوص من الملفات المختارة
1136
- async function extractTextsFromSelectedPdfPages() {
1137
- try {
1138
- // التحقق من وجود ملفات PDF
1139
- if (!pdfPages.source.pdf && !pdfPages.target.pdf) {
1140
- addError('لا توجد ملفات PDF محددة');
1141
- return;
1142
- }
1143
-
1144
- // استخراج النص من ملف المصدر إذا تم تحميله
1145
- if (pdfPages.source.pdf) {
1146
- const statusDiv = document.createElement('div');
1147
- statusDiv.className = "p-4 rounded-xl bg-blue-50 text-blue-700 mb-4";
1148
- statusDiv.innerHTML = `<div class="flex items-center">
1149
- <i class="fas fa-spinner fa-spin ml-2"></i>
1150
- <span>جارٍ استخراج النص من صفحات PDF المحددة من ملف المصدر</span>
1151
- </div>`;
1152
- document.getElementById('errorsList').appendChild(statusDiv);
1153
-
1154
- // التحقق من وجود صفحات محددة
1155
- if (pdfPages.source.selectedPages.length === 0) {
1156
- // إذا لم يتم تحديد أي صفحات، اختر جميع الصفحات تلقائيًا
1157
- for (let i = 1; i <= pdfPages.source.pdf.numPages; i++) {
1158
- pdfPages.source.selectedPages.push(i);
1159
- }
1160
-
1161
- // تحديث الواجهة لتظهر جميع الصفحات محددة
1162
- document.querySelectorAll('.pdf-page-thumbnail[data-type="source"]').forEach(elem => {
1163
- elem.classList.add('pdf-page-selected');
1164
- });
1165
- }
1166
-
1167
- const sourceText = await extractTextFromSelectedPdfPages('source');
1168
- document.getElementById('sourceText').value = sourceText;
1169
-
1170
- statusDiv.innerHTML = `<div class="flex items-center">
1171
- <i class="fas fa-check-circle ml-2 text-green-500"></i>
1172
- <span>تم استخراج النص من صفحات PDF المحددة من ملف المصدر بنجاح (${countWords(sourceText)} كلمة)</span>
1173
- </div>`;
1174
- }
1175
-
1176
- // استخراج النص من ملف الهدف إذا تم تحميله
1177
- if (pdfPages.target.pdf) {
1178
- const statusDiv = document.createElement('div');
1179
- statusDiv.className = "p-4 rounded-xl bg-blue-50 text-blue-700 mb-4";
1180
- statusDiv.innerHTML = `<div class="flex items-center">
1181
- <i class="fas fa-spinner fa-spin ml-2"></i>
1182
- <span>جارٍ استخراج النص من صفحات PDF المحددة من ملف الهدف</span>
1183
- </div>`;
1184
- document.getElementById('errorsList').appendChild(statusDiv);
1185
-
1186
- // التحقق من وجود صفحات محددة
1187
- if (pdfPages.target.selectedPages.length === 0) {
1188
- // إذا لم يتم تحديد أي صفحات، اختر جميع الصفحات تلقائيًا
1189
- for (let i = 1; i <= pdfPages.target.pdf.numPages; i++) {
1190
- pdfPages.target.selectedPages.push(i);
1191
- }
1192
-
1193
- // تحديث الواجهة لتظهر جميع الصفحات محددة
1194
- document.querySelectorAll('.pdf-page-thumbnail[data-type="target"]').forEach(elem => {
1195
- elem.classList.add('pdf-page-selected');
1196
- });
1197
- }
1198
-
1199
- const targetText = await extractTextFromSelectedPdfPages('target');
1200
- document.getElementById('targetText').value = targetText;
1201
-
1202
- statusDiv.innerHTML = `<div class="flex items-center">
1203
- <i class="fas fa-check-circle ml-2 text-green-500"></i>
1204
- <span>تم استخراج النص من صفحات PDF المحددة من ملف الهدف بنجاح (${countWords(targetText)} كلمة)</span>
1205
- </div>`;
1206
- }
1207
-
1208
- // إخفاء قسم عرض صفحات PDF
1209
- document.getElementById('pdfPagesContainer').classList.add('hidden');
1210
-
1211
- // إضافة رسالة نجاح
1212
- const successDiv = document.createElement('div');
1213
- successDiv.className = "p-4 rounded-xl bg-green-50 text-green-700 mt-4";
1214
- successDiv.innerHTML = `<div class="flex items-center">
1215
- <i class="fas fa-check-circle ml-2"></i>
1216
- <span>تم استخراج النصوص من صفحات PDF المحددة بنجاح. يمكنك الآن تعديل النصوص يدوياً إذا لزم الأمر ثم الضغط على زر "تحليل النصوص".</span>
1217
- </div>`;
1218
- document.getElementById('errorsList').appendChild(successDiv);
1219
-
1220
- return true;
1221
- } catch (error) {
1222
- console.error('Error extracting text from selected PDF pages:', error);
1223
- addError(`خطأ في استخراج النصوص من صفحات PDF المحددة: ${error.message}`);
1224
- return false;
1225
- }
1226
- }
1227
-
1228
- // دالة استخراج النصوص من الملفات
1229
- async function extractTextsFromFiles() {
1230
- const sourceFileInput = document.getElementById('sourceFile');
1231
- const targetFileInput = document.getElementById('targetFile');
1232
-
1233
- if (!sourceFileInput.files.length && !targetFileInput.files.length) {
1234
- addError('يرجى تحميل ملف واحد على الأقل');
1235
- document.getElementById('resultSection').classList.remove('hidden');
1236
- return;
1237
- }
1238
-
1239
- // إذا كانت هناك ملفات PDF تم عرض صفحاتها بالفعل، قم باستخراج النصوص من الصفحات المحددة
1240
- if (pdfPages.source.pdf || pdfPages.target.pdf) {
1241
- await extractTextsFromSelectedPdfPages();
1242
- return;
1243
- }
1244
-
1245
- document.getElementById('processStatus').classList.remove('hidden');
1246
- document.getElementById('errorsList').innerHTML = '';
1247
-
1248
- try {
1249
- // استخراج النص من ملف المصدر إذا تم تحميله
1250
- if (sourceFileInput.files.length) {
1251
- const sourceFile = sourceFileInput.files[0];
1252
- const statusDiv = document.createElement('div');
1253
- statusDiv.className = "p-4 rounded-xl bg-blue-50 text-blue-700 mb-4";
1254
- statusDiv.innerHTML = `<div class="flex items-center">
1255
- <i class="fas fa-spinner fa-spin ml-2"></i>
1256
- <span>جارٍ استخراج النص من ملف المصدر: ${sourceFile.name}</span>
1257
- </div>`;
1258
- document.getElementById('errorsList').appendChild(statusDiv);
1259
-
1260
- // إذا كان الملف PDF، عرض صفحاته لاختيار الصفحات المطلوبة
1261
- if (sourceFile.name.toLowerCase().endsWith('.pdf')) {
1262
- try {
1263
- await displayPdfPages(sourceFile, 'source');
1264
- statusDiv.innerHTML = `<div class="flex items-center">
1265
- <i class="fas fa-info-circle ml-2 text-blue-500"></i>
1266
- <span>تم عرض صفحات ملف PDF المصدر. يرجى تحديد الصفحات المطلوبة ثم الضغط على زر "استخراج النص من الصفحات المحددة".</span>
1267
- </div>`;
1268
- } catch (error) {
1269
- statusDiv.innerHTML = `<div class="flex items-center">
1270
- <i class="fas fa-exclamation-circle ml-2 text-red-500"></i>
1271
- <span>حدث خطأ أثناء عرض صفحات PDF: ${error.message}</span>
1272
- </div>`;
1273
- }
1274
- } else {
1275
- // استخراج النص من الملفات الأخرى
1276
- const sourceText = await extractTextFromFile(sourceFile);
1277
- document.getElementById('sourceText').value = sourceText;
1278
-
1279
- statusDiv.innerHTML = `<div class="flex items-center">
1280
- <i class="fas fa-check-circle ml-2 text-green-500"></i>
1281
- <span>تم استخراج النص من ملف المصدر بنجاح (${countWords(sourceText)} كلمة)</span>
1282
- </div>`;
1283
- }
1284
- }
1285
-
1286
- // استخراج النص من ملف الهدف إذا تم تحميله
1287
- if (targetFileInput.files.length) {
1288
- const targetFile = targetFileInput.files[0];
1289
- const statusDiv = document.createElement('div');
1290
- statusDiv.className = "p-4 rounded-xl bg-blue-50 text-blue-700 mb-4";
1291
- statusDiv.innerHTML = `<div class="flex items-center">
1292
- <i class="fas fa-spinner fa-spin ml-2"></i>
1293
- <span>جارٍ استخراج النص من ملف الهدف: ${targetFile.name}</span>
1294
- </div>`;
1295
- document.getElementById('errorsList').appendChild(statusDiv);
1296
-
1297
- // إذا كان الملف PDF، عرض صفحاته لاختيار الصفحات المطلوبة
1298
- if (targetFile.name.toLowerCase().endsWith('.pdf')) {
1299
- try {
1300
- await displayPdfPages(targetFile, 'target');
1301
- statusDiv.innerHTML = `<div class="flex items-center">
1302
- <i class="fas fa-info-circle ml-2 text-blue-500"></i>
1303
- <span>تم عرض صفحات ملف PDF الهدف. يرجى تحديد الصفحات المطلوبة ثم الضغط على زر "استخراج النص من الصفحات المحددة".</span>
1304
- </div>`;
1305
- } catch (error) {
1306
- statusDiv.innerHTML = `<div class="flex items-center">
1307
- <i class="fas fa-exclamation-circle ml-2 text-red-500"></i>
1308
- <span>حدث خطأ أثناء عرض صفحات PDF: ${error.message}</span>
1309
- </div>`;
1310
- }
1311
- } else {
1312
- // استخراج النص من الملفات الأخرى
1313
- const targetText = await extractTextFromFile(targetFile);
1314
- document.getElementById('targetText').value = targetText;
1315
-
1316
- statusDiv.innerHTML = `<div class="flex items-center">
1317
- <i class="fas fa-check-circle ml-2 text-green-500"></i>
1318
- <span>تم استخراج النص من ملف الهدف بنجاح (${countWords(targetText)} كلمة)</span>
1319
- </div>`;
1320
- }
1321
- }
1322
-
1323
- // إذا لم يتم عرض صفحات PDF، أضف رسالة نجاح
1324
- if (!document.getElementById('pdfPagesContainer').classList.contains('hidden')) {
1325
- // تم عرض صفحات PDF، لا تضف رسالة النجاح هنا
1326
- } else {
1327
- // إضافة رسالة نجاح
1328
- const successDiv = document.createElement('div');
1329
- successDiv.className = "p-4 rounded-xl bg-green-50 text-green-700 mt-4";
1330
- successDiv.innerHTML = `<div class="flex items-center">
1331
- <i class="fas fa-check-circle ml-2"></i>
1332
- <span>تم استخراج النصوص بنجاح. يمكنك الآن تعديل النصوص يدوياً إذا لزم الأمر ثم الضغط على زر "تحليل النصوص".</span>
1333
- </div>`;
1334
- document.getElementById('errorsList').appendChild(successDiv);
1335
- }
1336
-
1337
- // التمرير إلى قسم النصوص
1338
- document.getElementById('sourceText').scrollIntoView({ behavior: 'smooth' });
1339
-
1340
- } catch (error) {
1341
- console.error('Error extracting texts from files:', error);
1342
- addError(`خطأ في استخراج النصوص: ${error.message}`);
1343
- } finally {
1344
- document.getElementById('processStatus').classList.add('hidden');
1345
- document.getElementById('resultSection').classList.remove('hidden');
1346
  }
1347
- }
1348
-
1349
- // دالة تحليل الملفات
1350
- async function analyzeFiles(sourceFile, targetFile) {
1351
- // مسح الرسائل السابقة وإظهار قس�� النتائج
1352
- document.getElementById('errorsList').innerHTML = '';
1353
- document.getElementById('resultSection').classList.remove('hidden');
1354
- document.getElementById('explanationBox').classList.remove('hidden');
1355
-
1356
- if (!sourceFile || !targetFile) {
1357
- addError('يرجى تحميل كلا الملفين المصدر والهدف');
1358
- return;
1359
- }
1360
-
1361
- // التحقق من أن الملفين مختلفين
1362
- if (sourceFile.name === targetFile.name && sourceFile.size === targetFile.size && sourceFile.lastModified === targetFile.lastModified) {
1363
- addError('يبدو أنك قمت بتحميل نفس الملف مرتين. يرجى التحقق من الملفات.', 'warning');
1364
- }
1365
-
1366
- try {
1367
- // عرض مؤشر التقدم أثناء انتظار الرد
1368
- const progressDiv = document.createElement('div');
1369
- progressDiv.className = "bg-blue-100 p-4 rounded-xl mb-4";
1370
- progressDiv.innerHTML = `<div class="flex items-center">
1371
- <div class="animate-spin h-6 w-6 border-4 border-blue-600 rounded-full border-t-transparent ml-3"></div>
1372
- <span>جارٍ استخراج النصوص من الملفات...</span>
1373
- </div>`;
1374
- document.getElementById('errorsList').appendChild(progressDiv);
1375
-
1376
- // استخراج النصوص من الملفات
1377
- document.getElementById('progressFill').style.width = '0%';
1378
-
1379
- // إذا كانت ملفات PDF وتم بالفعل اختيار صفحات، استخدم النصوص المستخرجة من الحقول
1380
- let sourceText = '';
1381
- let targetText = '';
1382
-
1383
- if (sourceFile.name.toLowerCase().endsWith('.pdf') && pdfPages.source.pdf) {
1384
- sourceText = document.getElementById('sourceText').value;
1385
- } else {
1386
- sourceText = await extractTextFromFile(sourceFile);
1387
- }
1388
-
1389
- document.getElementById('progressFill').style.width = '50%';
1390
-
1391
- if (targetFile.name.toLowerCase().endsWith('.pdf') && pdfPages.target.pdf) {
1392
- targetText = document.getElementById('targetText').value;
1393
- } else {
1394
- targetText = await extractTextFromFile(targetFile);
1395
- }
1396
-
1397
- document.getElementById('progressFill').style.width = '100%';
1398
-
1399
- // تحديث النص في مؤشر التقدم
1400
- progressDiv.innerHTML = `<div class="flex items-center">
1401
- <div class="animate-spin h-6 w-6 border-4 border-blue-600 rounded-full border-t-transparent ml-3"></div>
1402
- <span>جارٍ تحليل النصوص المستخرجة...</span>
1403
- </div>`;
1404
-
1405
- // عرض النصوص المستخرجة في مربعات النص إذا لم تكن موجودة بالفعل
1406
- if (!document.getElementById('sourceText').value) {
1407
- document.getElementById('sourceText').value = sourceText;
1408
- }
1409
- if (!document.getElementById('targetText').value) {
1410
- document.getElementById('targetText').value = targetText;
1411
- }
1412
-
1413
- // مقارنة عدد الكلمات (تنبيه اختياري)
1414
- const sourceWordCount = countWords(sourceText);
1415
- const targetWordCount = countWords(targetText);
1416
- if (Math.abs(sourceWordCount - targetWordCount) > sourceWordCount * 0.1) {
1417
- addError(`عدد كلمات النص المصدر (${sourceWordCount}) يختلف بشكل كبير عن النص الهدف (${targetWordCount})`, 'warning');
1418
- }
1419
-
1420
- // فحص أولي سريع للاختلافات الواضحة
1421
- if (sourceText === targetText) {
1422
- addError('النصوص المستخرجة من الملفات متطابقة تماماً بشكل حرفي', 'warning');
1423
- }
1424
-
1425
- // بناء prompt باستخدام النصوص المستخرجة
1426
- const prompt = ANALYSIS_PROMPT
1427
- .replace("{source}", sourceText)
1428
- .replace("{target}", targetText);
1429
-
1430
- // استخدام DeepSeek API
1431
- const payload = {
1432
- model: "deepseek-chat",
1433
- messages: [
1434
- { role: "system", content: "أنت خبير في تحليل النصوص ومقارنتها بدقة عالية. عليك تحديد جميع الاختلافات بين النصوص حتى لو كانت بسيطة." },
1435
- { role: "user", content: prompt }
1436
- ],
1437
- temperature: 0.1, // تقليل درجة الحرارة لزيادة الدقة
1438
- max_tokens: 2048,
1439
- stream: false
1440
- };
1441
-
1442
- // استدعاء API التحليل
1443
- const response = await fetch(API_URL, {
1444
- method: 'POST',
1445
- headers: {
1446
- 'Authorization': 'Bearer ' + API_KEY,
1447
- 'Content-Type': 'application/json'
1448
- },
1449
- body: JSON.stringify(payload)
1450
- });
1451
-
1452
- if (!response.ok) {
1453
- throw new Error('حدث خطأ بالشبكة: ' + response.statusText);
1454
- }
1455
-
1456
- const data = await response.json();
1457
- const analysisOutput = data.choices[0].message.content.trim();
1458
-
1459
- progressDiv.remove();
1460
-
1461
- // تخزين نتائج التحليل
1462
- analysisResults = {
1463
- sourceText: sourceText,
1464
- targetText: targetText,
1465
- analysisOutput: analysisOutput,
1466
- timestamp: new Date().toLocaleString('ar-SA'),
1467
- sourceFileName: sourceFile.name,
1468
- targetFileName: targetFile.name
1469
- };
1470
-
1471
- // فحص إضافي للتأكد من دقة التحليل
1472
- const hasActualDifferences = sourceText !== targetText;
1473
- const reportedMatch = analysisOutput.includes('[MATCH]');
1474
-
1475
- if (hasActualDifferences && reportedMatch) {
1476
- addError('تنبيه: النصوص مختلفة ولكن تم الإبلاغ عن تطابقها. يرجى التحقق يدوياً.', 'warning');
1477
- }
1478
-
1479
- if (analysisOutput.includes('[MATCH]') && !hasActualDifferences) {
1480
- const checkDiv = document.createElement('div');
1481
- checkDiv.className = "p-4 rounded-xl bg-green-50 text-green-700 flex items-center";
1482
- checkDiv.innerHTML = `<i class="fas fa-check-circle ml-2 text-lg"></i> <span class="text-lg">النصوص المستخرجة من الملفات متطابقة تماماً</span>`;
1483
- document.getElementById('errorsList').appendChild(checkDiv);
1484
- document.getElementById('sourceTextReview').innerHTML = splitIntoLines(sourceText);
1485
- document.getElementById('targetTextReview').innerHTML = splitIntoLines(targetText);
1486
- document.getElementById('explanationText').innerHTML = `<p>[MATCH] لا توجد اختلافات.</p>`;
1487
-
1488
- analysisResults.explanationHTML = `<p>[MATCH] لا توجد اختلافات.</p>`;
1489
- analysisResults.numDiffCount = 0;
1490
- analysisResults.missingDiffCount = 0;
1491
- analysisResults.meaningDiffCount = 0;
1492
- } else {
1493
- const sourceHighlighted = applyHighlights(sourceText, analysisOutput);
1494
- const targetHighlighted = applyHighlights(targetText, analysisOutput);
1495
- // تقسيم النصوص المُظّلّة إلى أسطر مع رقم السطر
1496
- document.getElementById('sourceTextReview').innerHTML = splitIntoLines(sourceHighlighted);
1497
- document.getElementById('targetTextReview').innerHTML = splitIntoLines(targetHighlighted);
1498
-
1499
- // توليد شرح الاختلافات
1500
- const explanationHTML = generateExplanation(sourceText, analysisOutput);
1501
- document.getElementById('explanationText').innerHTML = explanationHTML;
1502
-
1503
- // تخزين شرح الاختلافات
1504
- analysisResults.explanationHTML = explanationHTML;
1505
-
1506
- // عرض ملخص الاختلافات إن وُجدت
1507
- const numDiffCount = (analysisOutput.match(/<([^<>]+)>/g) || []).length;
1508
- const missingDiffCount = (analysisOutput.match(/__(.*?)__/g) || []).length;
1509
- const meaningDiffCount = (analysisOutput.match(/\[MEANING\](.*?)\[\/MEANING\]/g) || []).length;
1510
-
1511
- // تخزين عدد الاختلافات
1512
- analysisResults.numDiffCount = numDiffCount;
1513
- analysisResults.missingDiffCount = missingDiffCount;
1514
- analysisResults.meaningDiffCount = meaningDiffCount;
1515
-
1516
- if (numDiffCount > 0 || missingDiffCount > 0 || meaningDiffCount > 0) {
1517
- const summaryDiv = document.createElement('div');
1518
- summaryDiv.className = "p-4 rounded-xl bg-yellow-50 text-gray-800";
1519
- let summaryText = '<div class="font-bold mb-2">ملخص الاختلافات:</div><ul class="list-disc mr-6 space-y-1">';
1520
- if (numDiffCount > 0) summaryText += `<li>اختلاف في الأرقام: ${numDiffCount}</li>`;
1521
- if (missingDiffCount > 0) summaryText += `<li>نصوص مفقودة: ${missingDiffCount}</li>`;
1522
- if (meaningDiffCount > 0) summaryText += `<li>اختلاف في المعنى: ${meaningDiffCount}</li>`;
1523
- summaryText += '</ul>';
1524
- summaryDiv.innerHTML = summaryText;
1525
- document.getElementById('errorsList').appendChild(summaryDiv);
1526
- } else if (hasActualDifferences) {
1527
- // إذا كانت هناك اختلافات ولكن لم يتم اكتشافها
1528
- addError('تنبيه: قد تكون هناك اختلافات لم يتم اكتشافها. يرجى التحقق يدوياً.', 'warning');
1529
- }
1530
- }
1531
-
1532
- return true;
1533
- } catch (error) {
1534
- document.getElementById('errorsList').innerHTML = '';
1535
- addError(`خطأ في تحليل الملفات: ${error.message}`);
1536
- return false;
1537
- } finally {
1538
- document.getElementById('processStatus').classList.add('hidden');
1539
- }
1540
- }
1541
-
1542
- // دالة إنشاء تقرير HTML
1543
- function generateHTMLReport() {
1544
- const { sourceText, targetText, analysisOutput, explanationHTML, numDiffCount, missingDiffCount, meaningDiffCount, timestamp, sourceFileName, targetFileName } = analysisResults;
1545
-
1546
- // تطبيق التمييز على النصوص
1547
- const sourceHighlighted = applyHighlights(sourceText, analysisOutput);
1548
- const targetHighlighted = applyHighlights(targetText, analysisOutput);
1549
-
1550
- // إنشاء محتوى HTML للتقرير
1551
- let reportHTML = `
1552
- <!DOCTYPE html>
1553
- <html lang="ar" dir="rtl">
1554
- <head>
1555
- <meta charset="UTF-8">
1556
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
1557
- <title>تقرير تحليل النصوص - موندو لينجوا</title>
1558
- <style>
1559
- body {
1560
- font-family: Arial, sans-serif;
1561
- line-height: 1.6;
1562
- color: #333;
1563
- max-width: 1200px;
1564
- margin: 0 auto;
1565
- padding: 20px;
1566
- }
1567
- h1, h2, h3 {
1568
- color: #2563EB;
1569
- }
1570
- .header {
1571
- text-align: center;
1572
- margin-bottom: 30px;
1573
- padding-bottom: 20px;
1574
- border-bottom: 2px solid #E0E7FF;
1575
- }
1576
- .summary {
1577
- background-color: #FFFBEB;
1578
- border: 1px solid #FEF3C7;
1579
- padding: 15px;
1580
- border-radius: 8px;
1581
- margin-bottom: 20px;
1582
- }
1583
- .explanation {
1584
- background-color: #F3F4F6;
1585
- padding: 15px;
1586
- border-radius: 8px;
1587
- margin-bottom: 20px;
1588
- }
1589
- .text-container {
1590
- display: grid;
1591
- grid-template-columns: 1fr 1fr;
1592
- gap: 20px;
1593
- margin-bottom: 30px;
1594
- }
1595
- .text-box {
1596
- border: 1px solid #E5E7EB;
1597
- padding: 15px;
1598
- border-radius: 8px;
1599
- background-color: #F9FAFB;
1600
- }
1601
- .highlight-number {
1602
- background-color: #FDE68A;
1603
- padding: 0 2px;
1604
- border-radius: 2px;
1605
- }
1606
- .highlight-missing {
1607
- background-color: #BFDBFE;
1608
- padding: 0 2px;
1609
- border-radius: 2px;
1610
- }
1611
- .highlight-meaning {
1612
- color: #EF4444;
1613
- font-weight: bold;
1614
- }
1615
- .footer {
1616
- text-align: center;
1617
- margin-top: 30px;
1618
- padding-top: 20px;
1619
- border-top: 2px solid #E0E7FF;
1620
- color: #6B7280;
1621
- font-size: 0.9em;
1622
- }
1623
- .line-item {
1624
- display: flex;
1625
- margin-bottom: 8px;
1626
- }
1627
- .line-number {
1628
- width: 30px;
1629
- font-weight: bold;
1630
- color: #6B7280;
1631
- }
1632
- .line-text {
1633
- flex: 1;
1634
- }
1635
- .file-info {
1636
- background-color: #EFF6FF;
1637
- padding: 10px;
1638
- border-radius: 8px;
1639
- margin-bottom: 15px;
1640
- }
1641
- </style>
1642
- </head>
1643
- <body>
1644
- <div class="header">
1645
- <h1>تقرير تحليل النصوص</h1>
1646
- <p>شركة موندو لينجوا للترجمة والتحليل اللغوي</p>
1647
- <p>تاريخ التحليل: ${timestamp}</p>
1648
- </div>
1649
-
1650
- <div class="file-info">
1651
- <h2>معلومات الملفات</h2>
1652
- <p><strong>الملف المصدر:</strong> ${sourceFileName}</p>
1653
- <p><strong>الملف الهدف:</strong> ${targetFileName}</p>
1654
- </div>
1655
-
1656
- <div class="summary">
1657
- <h2>ملخص التحليل</h2>
1658
- `;
1659
-
1660
- if (numDiffCount === 0 && missingDiffCount === 0 && meaningDiffCount === 0) {
1661
- reportHTML += `<p>النصوص متطابقة تماماً [MATCH]</p>`;
1662
- } else {
1663
- reportHTML += `<ul>`;
1664
- if (numDiffCount > 0) reportHTML += `<li>اختلاف في الأرقام: ${numDiffCount}</li>`;
1665
- if (missingDiffCount > 0) reportHTML += `<li>نصوص مفقودة: ${missingDiffCount}</li>`;
1666
- if (meaningDiffCount > 0) reportHTML += `<li>اختلاف في المعنى: ${meaningDiffCount}</li>`;
1667
- reportHTML += `</ul>`;
1668
- }
1669
-
1670
- reportHTML += `
1671
- </div>
1672
-
1673
- <div class="explanation">
1674
- <h2>شرح الاختلافات</h2>
1675
- ${explanationHTML}
1676
- </div>
1677
-
1678
- <h2>النصوص المقارنة</h2>
1679
- <div class="text-container">
1680
- <div class="text-box">
1681
- <h3>النص المصدر</h3>
1682
- <div>
1683
- `;
1684
-
1685
- // تقسيم النص المصدر إلى أسطر مع أرقام الأسطر
1686
- const sourceLines = sourceHighlighted.split('\n');
1687
- sourceLines.forEach((line, index) => {
1688
- reportHTML += `<div class="line-item"><span class="line-number">${index + 1}:</span> <span class="line-text">${line}</span></div>`;
1689
- });
1690
-
1691
- reportHTML += `
1692
- </div>
1693
- </div>
1694
- <div class="text-box">
1695
- <h3>النص الهدف</h3>
1696
- <div>
1697
- `;
1698
-
1699
- // تقسيم النص الهدف إلى أسطر مع أرقام الأسطر
1700
- const targetLines = targetHighlighted.split('\n');
1701
- targetLines.forEach((line, index) => {
1702
- reportHTML += `<div class="line-item"><span class="line-number">${index + 1}:</span> <span class="line-text">${line}</span></div>`;
1703
- });
1704
-
1705
- reportHTML += `
1706
- </div>
1707
- </div>
1708
- </div>
1709
-
1710
- <div class="footer">
1711
- <p>© ${new Date().getFullYear()} شركة موندو لينجوا - جميع الحقوق محفوظة</p>
1712
- </div>
1713
- </body>
1714
- </html>
1715
- `;
1716
-
1717
- return reportHTML;
1718
- }
1719
-
1720
- // دالة تنزيل التقرير
1721
- function downloadReport() {
1722
- // التحقق من وجود نتائج تحليل
1723
- if (!analysisResults.sourceText || !analysisResults.targetText) {
1724
- alert('لا توجد نتائج تحليل متاحة للتنزيل');
1725
- return;
1726
- }
1727
-
1728
- // إنشاء محتوى التقرير
1729
- const reportHTML = generateHTMLReport();
1730
-
1731
- // إنشاء Blob من HTML
1732
- const blob = new Blob([reportHTML], { type: 'text/html' });
1733
-
1734
- // إنشاء رابط التنزيل
1735
- const url = URL.createObjectURL(blob);
1736
- const a = document.createElement('a');
1737
- a.href = url;
1738
- a.download = `تقرير_تحليل_النصوص_${new Date().toISOString().slice(0, 10)}.html`;
1739
-
1740
- // إضافة الرابط للصفحة وتنفيذ النقر عليه ثم إزالته
1741
- document.body.appendChild(a);
1742
- a.click();
1743
- document.body.removeChild(a);
1744
-
1745
- // تحرير الموارد
1746
- URL.revokeObjectURL(url);
1747
- }
1748
-
1749
- // دالة إعادة تحميل/تنفيذ التحليل
1750
- function reloadAnalysis() {
1751
- // إعادة تحليل النصوص الحالية في حقول النص
1752
- const sourceText = document.getElementById('sourceText').value;
1753
- const targetText = document.getElementById('targetText').value;
1754
- if (sourceText && targetText) {
1755
- analyzeTexts(sourceText, targetText);
1756
- } else {
1757
- alert('يرجى التأكد من وجود نصوص في حقول الإدخال قبل إعادة التحليل');
1758
- }
1759
- }
1760
-
1761
- // عند الضغط على زر تحليل النصوص المدخلة يدوياً
1762
- document.getElementById('submitBtn').addEventListener('click', async () => {
1763
- const sourceText = document.getElementById('sourceText').value;
1764
- const targetText = document.getElementById('targetText').value;
1765
- await analyzeTexts(sourceText, targetText);
1766
- });
1767
-
1768
- // عند الضغط على زر استخراج النصوص من الملفات
1769
- document.getElementById('extractTextBtn').addEventListener('click', async () => {
1770
- document.getElementById('resultSection').classList.remove('hidden');
1771
- document.getElementById('errorsList').innerHTML = '';
1772
- await extractTextsFromFiles();
1773
- });
1774
-
1775
- // عند الضغط على زر تحليل الملفات
1776
- document.getElementById('analyzeFilesBtn').addEventListener('click', async () => {
1777
- const sourceFileInput = document.getElementById('sourceFile');
1778
- const targetFileInput = document.getElementById('targetFile');
1779
-
1780
- if (!sourceFileInput.files.length || !targetFileInput.files.length) {
1781
- addError('يرجى تحميل كلا الملفين المصدر والهدف');
1782
- document.getElementById('resultSection').classList.remove('hidden');
1783
- return;
1784
- }
1785
-
1786
- document.getElementById('processStatus').classList.remove('hidden');
1787
-
1788
- try {
1789
- // تحليل الملفات
1790
- await analyzeFiles(sourceFileInput.files[0], targetFileInput.files[0]);
1791
- } catch (error) {
1792
- console.error('Error analyzing files:', error);
1793
- document.getElementById('resultSection').classList.remove('hidden');
1794
- addError(`خطأ في تحليل الملفات: ${error.message}`);
1795
- } finally {
1796
- document.getElementById('processStatus').classList.add('hidden');
1797
- }
1798
- });
1799
-
1800
- // إضافة مستمع حدث لزر تنزيل التقرير
1801
- document.getElementById('downloadReportBtn').addEventListener('click', downloadReport);
1802
-
1803
- // إضافة مستمع حدث لزر إعادة التحليل
1804
- document.getElementById('reloadAnalysisBtn').addEventListener('click', reloadAnalysis);
1805
-
1806
- // إضافة مستمع حدث لزر استخراج النص من الصفحات المحددة
1807
- document.getElementById('extractSelectedPagesBtn').addEventListener('click', async () => {
1808
- document.getElementById('resultSection').classList.remove('hidden');
1809
- document.getElementById('errorsList').innerHTML = '';
1810
- document.getElementById('processStatus').classList.remove('hidden');
1811
-
1812
- try {
1813
- await extractTextsFromSelectedPdfPages();
1814
- } catch (error) {
1815
- console.error('Error extracting text from selected PDF pages:', error);
1816
- addError(`خطأ في استخراج النص من صفحات PDF المحددة: ${error.message}`);
1817
- } finally {
1818
- document.getElementById('processStatus').classList.add('hidden');
1819
- }
1820
- });
1821
-
1822
- // إضافة مستمع حدث لزر تحديد كل الصفحات
1823
- document.getElementById('selectAllPagesBtn').addEventListener('click', () => {
1824
- // تحديد الصفحات بناءً على أي ملف PDF تم عرضه
1825
- let type = 'source';
1826
- if (pdfPages.target.pdf && !pdfPages.source.pdf) {
1827
- type = 'target';
1828
- }
1829
-
1830
- document.querySelectorAll(`.pdf-page-thumbnail[data-type="${type}"]`).forEach(elem => {
1831
- elem.classList.add('pdf-page-selected');
1832
- const pageNum = parseInt(elem.dataset.page);
1833
- if (!pdfPages[type].selectedPages.includes(pageNum)) {
1834
- pdfPages[type].selectedPages.push(pageNum);
1835
- }
1836
- });
1837
  });
1838
-
1839
- // إضافة مستمع حدث لزر إلغاء تحديد كل الصفحات
1840
- document.getElementById('deselectAllPagesBtn').addEventListener('click', () => {
1841
- // إلغاء تحديد الصفحات بناءً على أي ملف PDF تم عرضه
1842
- let type = 'source';
1843
- if (pdfPages.target.pdf && !pdfPages.source.pdf) {
1844
- type = 'target';
1845
- }
1846
-
1847
- document.querySelectorAll(`.pdf-page-thumbnail[data-type="${type}"]`).forEach(elem => {
1848
- elem.classList.remove('pdf-page-selected');
1849
- });
1850
-
1851
- pdfPages[type].selectedPages = [];
1852
- });
1853
-
1854
- // تهيئة PDF.js
1855
- pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.10.377/pdf.worker.min.js';
1856
  </script>
1857
  </body>
1858
  </html>
 
6
  <title>نظام المقارنة والترجمة الخاص بشركة موندو لينجوا</title>
7
  <link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
8
  <script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.6.0/mammoth.browser.min.js"></script>
 
9
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
10
  <style>
11
  @keyframes gradient {
 
81
  70% { box-shadow: 0 0 0 10px rgba(59, 130, 246, 0); }
82
  100% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); }
83
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  </style>
85
  </head>
86
  <body class="bg-gradient-to-br from-gray-50 via-blue-50 to-indigo-50 min-h-screen">
 
98
  <!-- قسم رفع الملفات -->
99
  <div class="bg-white rounded-2xl shadow-lg p-8 border border-gray-100 hover:shadow-xl transition-all animate-scale mb-8 card-hover">
100
  <h2 class="text-2xl font-bold mb-6 text-gray-800 flex items-center border-b pb-3">
101
+ <i class="fas fa-file-upload text-blue-600 ml-2"></i> تحميل الملفات
102
  </h2>
103
  <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
104
  <!-- ملف السورس -->
105
  <div class="group border-2 border-dashed border-blue-200 rounded-xl p-8 text-center hover:border-blue-500 transition-colors duration-300 bg-blue-50 hover:bg-blue-100">
106
  <label class="cursor-pointer block">
107
+ <input type="file" id="sourceFile" accept=".docx,.pdf" class="hidden">
108
  <i class="fas fa-file-upload text-5xl text-blue-500 mb-4"></i>
109
  <span class="text-lg text-blue-600 group-hover:text-blue-700">ملف السور��</span>
 
 
110
  </label>
111
  </div>
112
  <!-- ملف التارجت -->
113
  <div class="group border-2 border-dashed border-purple-200 rounded-xl p-8 text-center hover:border-purple-500 transition-colors duration-300 bg-purple-50 hover:bg-purple-100">
114
  <label class="cursor-pointer block">
115
+ <input type="file" id="targetFile" accept=".docx,.pdf" class="hidden">
116
  <i class="fas fa-file-download text-5xl text-purple-500 mb-4"></i>
117
  <span class="text-lg text-purple-600 group-hover:text-purple-700">ملف التارجت</span>
 
 
118
  </label>
119
  </div>
120
  </div>
121
  <div id="processStatus" class="hidden mt-4">
122
  <div class="flex items-center justify-center space-x-3 bg-blue-100 rounded-xl p-4">
123
  <div class="animate-spin h-8 w-8 border-4 border-blue-600 rounded-full border-t-transparent"></div>
124
+ <span class="text-lg text-blue-700">جارٍ معالجة الملف...</span>
 
 
 
125
  </div>
126
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  </div>
128
 
129
  <!-- إدخال النصوص يدويًا -->
130
  <div class="bg-white rounded-2xl shadow-lg p-8 border border-gray-100 hover:shadow-xl transition-all animate-scale mb-8 card-hover">
 
 
 
131
  <div class="space-y-6">
132
  <!-- النص المصدر -->
133
  <div class="group">
134
  <label class="block text-lg font-bold text-gray-700 mb-3 flex items-center">
135
  <i class="fas fa-language text-blue-600 ml-2"></i> النص المصدر
136
  </label>
137
+ <textarea id="sourceText" dir="rtl" class="w-full px-6 py-4 border-2 border-gray-200 rounded-xl focus:ring-blue-200 focus:border-blue-400 transition-all resize-none text-lg" rows="6" placeholder="اكتب النص المصدر هنا..."></textarea>
138
  </div>
139
  <!-- النص الهدف -->
140
  <div class="group">
141
  <label class="block text-lg font-bold text-gray-700 mb-3 flex items-center">
142
  <i class="fas fa-language text-purple-600 ml-2"></i> النص الهدف
143
  </label>
144
+ <textarea id="targetText" dir="ltr" class="w-full px-6 py-4 border-2 border-gray-200 rounded-xl focus:ring-purple-200 focus:border-purple-400 transition-all resize-none text-lg" rows="6" placeholder="اكتب النص الهدف هنا..."></textarea>
145
  </div>
146
  </div>
 
 
 
 
 
 
147
  </div>
148
 
149
+ <!-- زر التحليل -->
150
+ <button id="submitBtn" class="w-full bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white font-bold py-5 px-8 rounded-xl transition-all transform hover:scale-105 focus:ring-blue-200 text-xl shadow-lg hover:shadow-xl mb-8 pulse-animation">
151
+ <div class="flex items-center justify-center">
152
+ <i class="fas fa-sync-alt ml-2"></i> تحليل النصوص
153
+ </div>
154
+ </button>
155
+
156
  <!-- شاشة نتائج التحليل (المعاينة المقسمة) -->
157
  <div id="resultSection" class="bg-white rounded-2xl shadow-lg p-8 border border-gray-100 hover:shadow-xl transition-all animate-scale mb-8 hidden card-hover">
158
  <h2 class="text-2xl font-bold mb-6 text-gray-800 border-b pb-3 flex items-center">
 
176
  <div id="targetTextReview" class="bg-gray-50 rounded-xl p-6 min-h-[200px] border-2 border-gray-200 text-comparison"></div>
177
  </div>
178
  </div>
 
 
 
 
 
 
 
 
 
 
 
179
  </div>
180
 
181
  <!-- صندوق شرح الاختلافات -->
 
194
  const API_URL = 'https://api.deepseek.com/chat/completions';
195
  const API_KEY = 'sk-15606736ed9e4aea8b7cc11a195d2b01';
196
 
 
 
 
 
197
  /*
198
  الـ prompt المحسن:
199
  أنت خبير في تحليل النصوص ومقارنتها. قم بمقارنة النص المصدر والنص الهدف بدقة عالية واكتشف الاختلافات التالية فقط:
 
230
  النص الهدف:
231
  {target}
232
 
233
+ أخرج فقط الاختلافات المحددة بالعلامات المذكورة أعلاه، دون أي شرح إضافي.`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
 
235
  // دالة لحساب عدد الكلمات
236
  function countWords(text) {
 
333
  return explanation;
334
  }
335
 
336
+ // دالة موحدة لمعالجة الملفات (PDF و DOCX)
337
+ async function processFile(file) {
338
+ let text = "";
339
+ if (file.type === 'application/pdf') {
340
+ const form = new FormData();
341
+ form.append('image', file);
342
+ const response = await fetch('https://demo.api4ai.cloud/ocr/v1/results', {
343
+ method: 'POST',
344
+ body: form,
345
+ headers: { 'A4A-CLIENT-APP-ID': 'sample' }
346
+ });
347
+ const data = await response.json();
348
+ text = data.results[0].entities[0].objects[0].entities[0].text;
349
+ } else if (file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
350
  const arrayBuffer = await file.arrayBuffer();
351
  const result = await mammoth.extractRawText({ arrayBuffer });
352
+ text = result.value;
353
+ } else {
354
+ throw new Error('نوع الملف غير مدعوم');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
  }
356
+ return text;
357
  }
358
 
359
+ // رفع ملف السورس
360
  document.getElementById('sourceFile')?.addEventListener('change', async (event) => {
361
  const file = event.target.files[0];
362
  if (!file) return;
363
+ document.getElementById('processStatus').classList.remove('hidden');
364
+ try {
365
+ const text = await processFile(file);
366
+ document.getElementById('sourceText').value = text;
367
+ } catch (error) {
368
+ console.error('Error processing source file:', error);
369
+ addError('خطأ في معالجة ملف السورس');
370
+ } finally {
371
+ document.getElementById('processStatus').classList.add('hidden');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
372
  }
373
  });
374
 
375
+ // رفع ملف التارجت
376
  document.getElementById('targetFile')?.addEventListener('change', async (event) => {
377
  const file = event.target.files[0];
378
  if (!file) return;
379
+ document.getElementById('processStatus').classList.remove('hidden');
380
+ try {
381
+ const text = await processFile(file);
382
+ document.getElementById('targetText').value = text;
383
+ } catch (error) {
384
+ console.error('Error processing target file:', error);
385
+ addError('خطأ في معالجة ملف التارجت');
386
+ } finally {
387
+ document.getElementById('processStatus').classList.add('hidden');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  }
389
  });
390
 
 
401
  errorsList.appendChild(errorDiv);
402
  }
403
 
404
+ // عند الضغط على زر التحليل
405
+ document.getElementById('submitBtn').addEventListener('click', async () => {
406
+ const sourceText = document.getElementById('sourceText').value;
407
+ const targetText = document.getElementById('targetText').value;
408
+
409
  // مسح الرسائل السابقة وإظهار قسم النتائج
410
  document.getElementById('errorsList').innerHTML = '';
411
  document.getElementById('resultSection').classList.remove('hidden');
 
419
  // مقارنة عدد الكلمات (تنبيه اختياري)
420
  const sourceWordCount = countWords(sourceText);
421
  const targetWordCount = countWords(targetText);
422
+ if (sourceWordCount !== targetWordCount) {
423
+ addError(`عدد كلمات النص المصدر (${sourceWordCount}) يختلف عن النص الهدف (${targetWordCount})`, 'warning');
 
 
 
 
 
424
  }
425
 
426
  try {
 
442
  const payload = {
443
  model: "deepseek-chat",
444
  messages: [
445
+ { role: "system", content: "أنت خبير في تحليل النصوص ومقارنتها بدقة عالية." },
446
  { role: "user", content: prompt }
447
  ],
448
+ temperature: 0.3,
449
  max_tokens: 2048,
450
  stream: false
451
  };
 
469
 
470
  progressDiv.remove();
471
 
472
+ if (analysisOutput.includes('[MATCH]')) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473
  const checkDiv = document.createElement('div');
474
  checkDiv.className = "p-4 rounded-xl bg-green-50 text-green-700 flex items-center";
475
  checkDiv.innerHTML = `<i class="fas fa-check-circle ml-2 text-lg"></i> <span class="text-lg">النصوص متطابقة تماماً</span>`;
 
477
  document.getElementById('sourceTextReview').innerHTML = splitIntoLines(sourceText);
478
  document.getElementById('targetTextReview').innerHTML = splitIntoLines(targetText);
479
  document.getElementById('explanationText').innerHTML = `<p>[MATCH] لا توجد اختلافات.</p>`;
 
 
 
 
 
480
  } else {
481
  const sourceHighlighted = applyHighlights(sourceText, analysisOutput);
482
  const targetHighlighted = applyHighlights(targetText, analysisOutput);
 
488
  const explanationHTML = generateExplanation(sourceText, analysisOutput);
489
  document.getElementById('explanationText').innerHTML = explanationHTML;
490
 
 
 
 
491
  // عرض ملخص الاختلافات إن وُجدت
492
  const numDiffCount = (analysisOutput.match(/<([^<>]+)>/g) || []).length;
493
  const missingDiffCount = (analysisOutput.match(/__(.*?)__/g) || []).length;
494
  const meaningDiffCount = (analysisOutput.match(/\[MEANING\](.*?)\[\/MEANING\]/g) || []).length;
 
 
 
 
 
 
495
  if (numDiffCount > 0 || missingDiffCount > 0 || meaningDiffCount > 0) {
496
  const summaryDiv = document.createElement('div');
497
  summaryDiv.className = "p-4 rounded-xl bg-yellow-50 text-gray-800";
 
502
  summaryText += '</ul>';
503
  summaryDiv.innerHTML = summaryText;
504
  document.getElementById('errorsList').appendChild(summaryDiv);
 
 
 
505
  }
506
  }
507
 
 
508
  } catch (error) {
509
  document.getElementById('errorsList').innerHTML = '';
510
  addError(`خطأ في التحليل: ${error.message}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
511
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
512
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
513
  </script>
514
  </body>
515
  </html>