joermd commited on
Commit
7359e36
·
verified ·
1 Parent(s): e75e1b2

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +79 -155
index.html CHANGED
@@ -9,9 +9,9 @@
9
  <script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.6.0/mammoth.browser.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
- /* ================================
13
  الحركات والتأثيرات
14
- ================================= */
15
  @keyframes gradient {
16
  0% { background-position: 0% 50%; }
17
  50% { background-position: 100% 50%; }
@@ -26,52 +26,43 @@
26
  .animate-scale:hover { transform: scale(1.02); }
27
  .pulse-animation { animation: pulse 2s infinite; }
28
  @keyframes pulse {
29
- 0% { box-shadow: 0 0 0 0 rgba(156,39,176,0.4); }
30
- 70% { box-shadow: 0 0 0 10px rgba(156,39,176,0); }
31
- 100% { box-shadow: 0 0 0 0 rgba(156,39,176,0); }
32
  }
33
 
34
- /* ================================
35
- تنسيقات النص والتظليل
36
- ================================= */
37
  .text-comparison { line-height: 1.8; white-space: pre-wrap; }
38
- .highlight-number {
39
- background-color: #FDE68A;
40
- padding: 0 4px;
41
- border-radius: 3px;
42
- font-weight: bold;
43
- }
44
  .highlight-missing {
45
- background-color: #FECACA;
46
- color: #B91C1C;
47
- padding: 0 4px;
48
- border-radius: 3px;
49
- font-style: italic;
50
- }
51
- .highlight-extra {
52
- background-color: #D1FAE5;
53
- color: #065F46;
54
  padding: 0 4px;
 
55
  border-radius: 3px;
56
  font-weight: bold;
57
  }
58
- .highlight-meaning {
59
- background-color: #E0E7FF;
 
60
  padding: 0 4px;
 
61
  border-radius: 3px;
62
  font-weight: bold;
63
  }
64
- .highlight-doubt {
65
- background-color: #DBEAFE;
66
- color: #1E3A8A;
67
  padding: 0 4px;
 
68
  border-radius: 3px;
69
  font-weight: bold;
70
  }
71
 
72
- /* ================================
73
  تنسيق الفقرات وترقيمها
74
- ================================= */
75
  .line-item {
76
  margin-bottom: 1rem;
77
  padding: 0.5rem;
@@ -84,18 +75,18 @@
84
  }
85
  .line-text { display: inline-block; }
86
 
87
- /* ================================
88
  تصميم البطاقات والأيقونات
89
- ================================= */
90
  .card {
91
  background-color: #fff;
92
  border-radius: 1rem;
93
- box-shadow: 0 10px 25px -5px rgba(156,39,176,0.1);
94
  padding: 2rem;
95
  border: 1px solid #f3f4f6;
96
  }
97
  .card-hover:hover {
98
- box-shadow: 0 10px 25px -5px rgba(156,39,176,0.2);
99
  transform: translateY(-3px);
100
  }
101
  .icon { margin-right: 0.5rem; }
@@ -110,7 +101,7 @@
110
  <i class="fas fa-chart-line icon"></i> نظام المقارنة والتحليل المتقدم
111
  </h1>
112
  <p class="text-xl opacity-90">
113
- <i class="fas fa-info-circle icon"></i> دقة عالية في استخراج وتحليل النصوص
114
  </p>
115
  </div>
116
  </header>
@@ -228,14 +219,6 @@
228
  </h2>
229
  <div id="explanationText" class="text-lg text-gray-700"></div>
230
  </div>
231
-
232
- <!-- قسم الكلمات المفقودة (الكلمات التي لم تُترجم) -->
233
- <div id="missingWordsSection" class="card hidden">
234
- <h2 class="text-2xl font-bold text-gray-800 border-b pb-3 mb-6">
235
- <i class="fas fa-exclamation-triangle icon text-red-500"></i> الكلمات المفقودة
236
- </h2>
237
- <div id="missingWordsList" class="text-lg text-red-700"></div>
238
- </div>
239
  </main>
240
  </div>
241
 
@@ -245,20 +228,28 @@
245
  <script>
246
  (function() {
247
  "use strict";
248
-
249
- // تنبيه: يُفضل عدم تضمين مفتاح API في الكود العام بل تخزينه على الخادم
 
 
 
 
 
 
 
 
250
  const API_URL = 'https://api.deepseek.com/chat/completions';
251
  const API_KEY = 'sk-15606736ed9e4aea8b7cc11a195d2b01';
252
- const ANALYSIS_PROMPT = `أنت خبير لغوي وتقني متخصص في مراجعة الترجمة التقنية وتحليل النصوص بدقة. مهمتك مقارنة النص المصدر والنص الهدف واستخراج الاختلافات مع تحسين التظليل والتعليم.
253
- تعليمات:
254
- 1. قم بتحليل النص إلى فقرات منفصلة، مع التأكد من انتهاء كل فقرة بنقطة.
255
- 2. لا تقم بتعديل العلامات التالية:
256
- - الأرقام والتواريخ محاطة بـ < و >.
257
- - النصوص المفقودة محاطة بـ __ و __.
258
- - النصوص الزائدة محاطة بـ <<EXTRA>> و <<\/EXTRA>>.
259
- - اختلافات المعنى محاطة بـ [MEANING] و [/MEANING].
260
- - علامات الشك أو الأخطاء البسيطة محاطة بـ [DOUBT] و [/DOUBT].
261
- 3. يجب أن يقدم التحليل تعليمات دقيقة مع أيقونات توضيحية لكل نوع من الاختلافات.
262
 
263
  النص المصدر:
264
  {source}
@@ -266,9 +257,9 @@
266
  النص الهدف:
267
  {target}`;
268
 
269
- /* ===============================
270
  دوال مساعدة عامة
271
- =============================== */
272
  const countWords = text =>
273
  text.trim().split(/\s+/).filter(word => word !== "").length;
274
 
@@ -290,43 +281,33 @@
290
  return text.substring(0, index).split("\n").length;
291
  };
292
 
293
- /* ===============================
294
- دوال تظليل الاختلافات
295
- =============================== */
296
  const applyHighlights = (originalText, analysisOutput) => {
297
  let highlightedText = originalText;
298
  let match;
299
- // اختلافات الأرقام/التواريخ
300
- const numberRegex = /<([^<>]+)>/g;
301
- while ((match = numberRegex.exec(analysisOutput)) !== null) {
302
- const phrase = match[1].trim();
303
- if (phrase) {
304
- const replacement = `<span class="highlight-number">${phrase}</span>`;
305
- const phraseRegex = new RegExp(escapeRegExp(phrase), 'g');
306
- highlightedText = highlightedText.replace(phraseRegex, replacement);
307
- }
308
- }
309
- // النصوص المفقودة
310
  const missingRegex = /__(.*?)__/g;
311
  while ((match = missingRegex.exec(analysisOutput)) !== null) {
312
  const phrase = match[1].trim();
313
  if (phrase) {
314
- const replacement = `<span class="highlight-missing">__${phrase}__</span>`;
315
  const phraseRegex = new RegExp(escapeRegExp(phrase), 'g');
316
  highlightedText = highlightedText.replace(phraseRegex, replacement);
317
  }
318
  }
319
- // النصوص الزائدة
320
- const extraRegex = /<<EXTRA>>(.*?)<<\/EXTRA>>/g;
321
- while ((match = extraRegex.exec(analysisOutput)) !== null) {
322
  const phrase = match[1].trim();
323
  if (phrase) {
324
- const replacement = `<span class="highlight-extra">${phrase}</span>`;
325
  const phraseRegex = new RegExp(escapeRegExp(phrase), 'g');
326
  highlightedText = highlightedText.replace(phraseRegex, replacement);
327
  }
328
  }
329
- // اختلافات المعنى
330
  const meaningRegex = /\[MEANING\](.*?)\[\/MEANING\]/g;
331
  while ((match = meaningRegex.exec(analysisOutput)) !== null) {
332
  const phrase = match[1].trim();
@@ -336,101 +317,53 @@
336
  highlightedText = highlightedText.replace(phraseRegex, replacement);
337
  }
338
  }
339
- // علامات الشك أو الأخطاء البسيطة
340
- const doubtRegex = /\[DOUBT\](.*?)\[\/DOUBT\]/g;
341
- while ((match = doubtRegex.exec(analysisOutput)) !== null) {
342
- const phrase = match[1].trim();
343
- if (phrase) {
344
- const replacement = `<span class="highlight-doubt">${phrase}</span>`;
345
- const phraseRegex = new RegExp(escapeRegExp(phrase), 'g');
346
- highlightedText = highlightedText.replace(phraseRegex, replacement);
347
- }
348
- }
349
  return highlightedText;
350
  };
351
 
352
- // توليد شرح تفصيلي للاختلافات مع أيقونات توضيحية
353
  const generateExplanation = (sourceText, analysisOutput) => {
354
  let steps = [];
355
  let match;
356
- const iconMissing = `<i class="fas fa-exclamation-triangle text-red-500 mr-1"></i>`;
357
- const iconNumber = `<i class="fas fa-hashtag text-yellow-600 mr-1"></i>`;
358
- const iconExtra = `<i class="fas fa-plus-circle text-green-600 mr-1"></i>`;
359
- const iconMeaning = `<i class="fas fa-info-circle text-blue-600 mr-1"></i>`;
360
- const iconDoubt = `<i class="fas fa-question-circle text-indigo-600 mr-1"></i>`;
361
 
362
- // النصوص المفقودة (المعلمة مسبقاً)
363
  const missingRegex = /__(.*?)__/g;
364
  while ((match = missingRegex.exec(analysisOutput)) !== null) {
365
  const phrase = match[1].trim();
366
  if (phrase) {
367
  const lineNum = getLineNumber(sourceText, phrase);
368
- steps.push(`<li>${iconMissing} في السطر ${lineNum}، النص المفقود: <span class="highlight-missing">__${phrase}__</span> غير موجود في النص الهدف.</li>`);
369
  }
370
  }
371
- // اختلافات الأرقام/التواريخ
372
  const numberRegex = /<([^<>]+)>/g;
373
  while ((match = numberRegex.exec(analysisOutput)) !== null) {
374
  const phrase = match[1].trim();
375
  if (phrase) {
376
  const lineNum = getLineNumber(sourceText, phrase);
377
- steps.push(`<li>${iconNumber} في السطر ${lineNum}، الرقم/التاريخ: <span class="highlight-number">${phrase}</span> لا يتطابق بين المصدر والهدف.</li>`);
378
  }
379
  }
380
- // النصوص الزائدة
381
- const extraRegex = /<<EXTRA>>(.*?)<<\/EXTRA>>/g;
382
- while ((match = extraRegex.exec(analysisOutput)) !== null) {
383
- const phrase = match[1].trim();
384
- if (phrase) {
385
- const lineNum = getLineNumber(sourceText, phrase);
386
- steps.push(`<li>${iconExtra} في السطر ${lineNum}، النص الزائد: <span class="highlight-extra">${phrase}</span> موجود بشكل غير متوقع في النص الهدف.</li>`);
387
- }
388
- }
389
- // اختلافات المعنى
390
  const meaningRegex = /\[MEANING\](.*?)\[\/MEANING\]/g;
391
  while ((match = meaningRegex.exec(analysisOutput)) !== null) {
392
  const phrase = match[1].trim();
393
  if (phrase) {
394
  const lineNum = getLineNumber(sourceText, phrase);
395
- steps.push(`<li>${iconMeaning} في السطر ${lineNum}، اختلاف في المعنى: <span class="highlight-meaning">${phrase}</span> بين المصدر والهدف.</li>`);
396
- }
397
- }
398
- // علامات الشك أو الأخطاء البسيطة
399
- const doubtRegex = /\[DOUBT\](.*?)\[\/DOUBT\]/g;
400
- while ((match = doubtRegex.exec(analysisOutput)) !== null) {
401
- const phrase = match[1].trim();
402
- if (phrase) {
403
- const lineNum = getLineNumber(sourceText, phrase);
404
- steps.push(`<li>${iconDoubt} في السطر ${lineNum}، علامة شك: <span class="highlight-doubt">${phrase}</span> قد تشير إلى غموض أو خطأ بسيط يحتاج مراجعة.</li>`);
405
  }
406
  }
407
  if (steps.length === 0) {
408
- return `<p class="text-green-700"><i class="fas fa-check-circle mr-2"></i> لا توجد اختلافات ملحوظة بين النصين.</p>`;
409
  }
410
  return `<ol class="list-decimal ml-6 space-y-2">${steps.join('')}</ol>`;
411
  };
412
 
413
- /* =======================================
414
- دالة اكتشاف الكلمات المفقودة (غير المُترجمة)
415
- يتم التطبيع (إزالة علامات الترقيم وتحويل الأحرف لحروف صغيرة)
416
- ثم مقارنة كلمات المصدر مع كلمات الهدف
417
- ======================================= */
418
- const detectMissingWords = (source, target) => {
419
- // دالة لتطبيع النص (إزالة علامات الترقيم وتحويل النص لحروف صغيرة)
420
- const normalize = text =>
421
- text.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()؟،؛"']/g, '').toLowerCase();
422
- const sourceTokens = normalize(source).split(/\s+/).filter(word => word);
423
- const targetTokens = normalize(target).split(/\s+/).filter(word => word);
424
- const targetSet = new Set(targetTokens);
425
- // الكلمات المفقودة هي التي تظهر في المصدر وغير موجودة في الهدف
426
- const missing = sourceTokens.filter(word => !targetSet.has(word));
427
- // إزالة التكرارات إن وُجدت
428
- return [...new Set(missing)];
429
- };
430
-
431
- /* ===============================
432
  دالة معالجة الملفات (PDF و DOCX)
433
- =============================== */
434
  const processFile = async file => {
435
  let text = "";
436
  try {
@@ -458,9 +391,9 @@
458
  return text;
459
  };
460
 
461
- /* ===============================
462
  التعامل مع رفع الملفات وإدخال النصوص
463
- =============================== */
464
  const processFileInput = (inputId, targetTextAreaId, errorMsg) => {
465
  document.getElementById(inputId)?.addEventListener('change', async (event) => {
466
  const file = event.target.files[0];
@@ -482,9 +415,9 @@
482
  processFileInput('targetFile', 'targetText', 'خطأ في معالجة ملف الهدف');
483
  processFileInput('sourceExtraFile', 'sourceExtraText', 'خطأ في معالجة ملف المصدر الإضافي');
484
 
485
- /* ===============================
486
  دالة عرض الأخطاء
487
- =============================== */
488
  const addError = (message, type = 'error') => {
489
  const errorsList = document.getElementById('errorsList');
490
  if (!errorsList) return;
@@ -497,9 +430,9 @@
497
  errorsList.appendChild(errorDiv);
498
  };
499
 
500
- /* ===============================
501
  التعامل مع عملية التحليل والمقارنة
502
- =============================== */
503
  document.getElementById('submitBtn').addEventListener('click', async () => {
504
  const sourceText = document.getElementById('sourceText').value;
505
  const targetText = document.getElementById('targetText').value;
@@ -558,6 +491,7 @@
558
  const analysisOutput = data.choices[0].message.content.trim();
559
  progressDiv.remove();
560
 
 
561
  if (analysisOutput.includes('[MATCH]')) {
562
  const checkDiv = document.createElement('div');
563
  checkDiv.className = "p-4 rounded-xl bg-green-50 text-green-700 flex items-center";
@@ -567,6 +501,7 @@
567
  document.getElementById('targetTextReview').innerHTML = splitIntoLines(targetText);
568
  document.getElementById('explanationText').innerHTML = `<p>النصوص متطابقة ولا يوجد اختلاف يجب الإشارة إليه.</p>`;
569
  } else {
 
570
  const sourceHighlighted = applyHighlights(sourceText, analysisOutput);
571
  const targetHighlighted = applyHighlights(targetText, analysisOutput);
572
  document.getElementById('sourceTextReview').innerHTML = splitIntoLines(sourceHighlighted);
@@ -574,17 +509,6 @@
574
  const explanationHTML = generateExplanation(sourceText, analysisOutput);
575
  document.getElementById('explanationText').innerHTML = explanationHTML;
576
  }
577
-
578
- // اكتشاف الكلمات المفقودة التي لم تُترجم من المصدر (تظهر في المصدر وغير موجودة في الهدف)
579
- const missingWords = detectMissingWords(sourceText, targetText);
580
- if (missingWords.length > 0) {
581
- const missingWordsSection = document.getElementById('missingWordsSection');
582
- const missingWordsList = document.getElementById('missingWordsList');
583
- missingWordsList.innerHTML = `<ul class="list-disc ml-4">${missingWords.map(word => `<li>${word}</li>`).join('')}</ul>`;
584
- missingWordsSection.classList.remove('hidden');
585
- } else {
586
- document.getElementById('missingWordsSection').classList.add('hidden');
587
- }
588
  } catch (error) {
589
  document.getElementById('errorsList').innerHTML = '';
590
  addError(`خطأ في التحليل: ${error.message}`);
 
9
  <script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.6.0/mammoth.browser.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
+ /* -------------------------------
13
  الحركات والتأثيرات
14
+ ------------------------------- */
15
  @keyframes gradient {
16
  0% { background-position: 0% 50%; }
17
  50% { background-position: 100% 50%; }
 
26
  .animate-scale:hover { transform: scale(1.02); }
27
  .pulse-animation { animation: pulse 2s infinite; }
28
  @keyframes pulse {
29
+ 0% { box-shadow: 0 0 0 0 rgba(0,0,0,0.2); }
30
+ 70% { box-shadow: 0 0 0 10px rgba(0,0,0,0); }
31
+ 100% { box-shadow: 0 0 0 0 rgba(0,0,0,0); }
32
  }
33
 
34
+ /* -------------------------------
35
+ تنسيقات النص والتظليل (ألوان بيضاء)
36
+ ------------------------------- */
37
  .text-comparison { line-height: 1.8; white-space: pre-wrap; }
 
 
 
 
 
 
38
  .highlight-missing {
39
+ background-color: #ffffff;
40
+ color: #000;
 
 
 
 
 
 
 
41
  padding: 0 4px;
42
+ border: 1px solid #ccc;
43
  border-radius: 3px;
44
  font-weight: bold;
45
  }
46
+ .highlight-number {
47
+ background-color: #ffffff;
48
+ color: #000;
49
  padding: 0 4px;
50
+ border: 1px solid #ccc;
51
  border-radius: 3px;
52
  font-weight: bold;
53
  }
54
+ .highlight-meaning {
55
+ background-color: #ffffff;
56
+ color: #000;
57
  padding: 0 4px;
58
+ border: 1px solid #ccc;
59
  border-radius: 3px;
60
  font-weight: bold;
61
  }
62
 
63
+ /* -------------------------------
64
  تنسيق الفقرات وترقيمها
65
+ ------------------------------- */
66
  .line-item {
67
  margin-bottom: 1rem;
68
  padding: 0.5rem;
 
75
  }
76
  .line-text { display: inline-block; }
77
 
78
+ /* -------------------------------
79
  تصميم البطاقات والأيقونات
80
+ ------------------------------- */
81
  .card {
82
  background-color: #fff;
83
  border-radius: 1rem;
84
+ box-shadow: 0 10px 25px -5px rgba(0,0,0,0.1);
85
  padding: 2rem;
86
  border: 1px solid #f3f4f6;
87
  }
88
  .card-hover:hover {
89
+ box-shadow: 0 10px 25px -5px rgba(0,0,0,0.2);
90
  transform: translateY(-3px);
91
  }
92
  .icon { margin-right: 0.5rem; }
 
101
  <i class="fas fa-chart-line icon"></i> نظام المقارنة والتحليل المتقدم
102
  </h1>
103
  <p class="text-xl opacity-90">
104
+ <i class="fas fa-info-circle icon"></i> تحليل دقيق لاكتشاف النصوص المفقودة والأرقام/التواريخ واختلاف المعنى
105
  </p>
106
  </div>
107
  </header>
 
219
  </h2>
220
  <div id="explanationText" class="text-lg text-gray-700"></div>
221
  </div>
 
 
 
 
 
 
 
 
222
  </main>
223
  </div>
224
 
 
228
  <script>
229
  (function() {
230
  "use strict";
231
+
232
+ /* تحديث برومبت التحليل لتحديد ثلاثة بنود فقط:
233
+ 1. النصوص المفقودة (الكلمات التي لم تُترجم أبداً)
234
+ 2. الأرقام والتواريخ غير المتطا��قة
235
+ 3. اختلاف المعنى إن وجد
236
+ يتم تمييز:
237
+ - النصوص المفقودة باستخدام __الكلمة__
238
+ - الأرقام والتواريخ باستخدام <الرقم/التاريخ>
239
+ - اختلاف المعنى باستخدام [MEANING] الاختلاف [/MEANING]
240
+ */
241
  const API_URL = 'https://api.deepseek.com/chat/completions';
242
  const API_KEY = 'sk-15606736ed9e4aea8b7cc11a195d2b01';
243
+ const ANALYSIS_PROMPT = `أنت خبير لغوي وتقني متخصص في مراجعة الترجمة التقنية وتحليل النصوص بدقة.
244
+ مهمتك مقارنة النص المصدر والنص الهدف واستخراج الآتي:
245
+ 1. **النصوص المفقودة:** الكلمات التي لم تُترجم أبداً من النص المصدر (لا يوجد لها مقابل في النص الهدف).
246
+ 2. **الأرقام والتواريخ:** التي لا تتطابق بين المصدر والهدف.
247
+ 3. **اختلاف المعنى:** في حال وجود اختلاف واضح.
248
+ يرجى تمييز:
249
+ - النصوص المفقودة بـ __الكلمة__
250
+ - الأرقام والتواريخ بـ <الرقم/التاريخ>
251
+ - اختلاف المعنى بـ [MEANING] الاختلاف [/MEANING]
252
+ قدم ناتجك في شكل قائمة تفصيلية مع شرح مختصر لكل اختلاف.
253
 
254
  النص المصدر:
255
  {source}
 
257
  النص الهدف:
258
  {target}`;
259
 
260
+ /* -------------------------------
261
  دوال مساعدة عامة
262
+ ------------------------------- */
263
  const countWords = text =>
264
  text.trim().split(/\s+/).filter(word => word !== "").length;
265
 
 
281
  return text.substring(0, index).split("\n").length;
282
  };
283
 
284
+ /* -------------------------------
285
+ دوال تظليل الاختلافات (العلامات: __ للنص المفقود، < > للأرقام/التواريخ، [MEANING] اختلاف المعنى)
286
+ ------------------------------- */
287
  const applyHighlights = (originalText, analysisOutput) => {
288
  let highlightedText = originalText;
289
  let match;
290
+ // تظليل النصوص المفقودة
 
 
 
 
 
 
 
 
 
 
291
  const missingRegex = /__(.*?)__/g;
292
  while ((match = missingRegex.exec(analysisOutput)) !== null) {
293
  const phrase = match[1].trim();
294
  if (phrase) {
295
+ const replacement = `<span class="highlight-missing">${phrase}</span>`;
296
  const phraseRegex = new RegExp(escapeRegExp(phrase), 'g');
297
  highlightedText = highlightedText.replace(phraseRegex, replacement);
298
  }
299
  }
300
+ // تظليل الأرقام والتواريخ
301
+ const numberRegex = /<([^<>]+)>/g;
302
+ while ((match = numberRegex.exec(analysisOutput)) !== null) {
303
  const phrase = match[1].trim();
304
  if (phrase) {
305
+ const replacement = `<span class="highlight-number">${phrase}</span>`;
306
  const phraseRegex = new RegExp(escapeRegExp(phrase), 'g');
307
  highlightedText = highlightedText.replace(phraseRegex, replacement);
308
  }
309
  }
310
+ // تظليل اختلاف المعنى
311
  const meaningRegex = /\[MEANING\](.*?)\[\/MEANING\]/g;
312
  while ((match = meaningRegex.exec(analysisOutput)) !== null) {
313
  const phrase = match[1].trim();
 
317
  highlightedText = highlightedText.replace(phraseRegex, replacement);
318
  }
319
  }
 
 
 
 
 
 
 
 
 
 
320
  return highlightedText;
321
  };
322
 
323
+ // توليد شرح تفصيلي للاختلافات مع أيقونات بسيطة
324
  const generateExplanation = (sourceText, analysisOutput) => {
325
  let steps = [];
326
  let match;
327
+ const iconMissing = `<i class="fas fa-exclamation-triangle mr-1"></i>`;
328
+ const iconNumber = `<i class="fas fa-hashtag mr-1"></i>`;
329
+ const iconMeaning = `<i class="fas fa-info-circle mr-1"></i>`;
 
 
330
 
331
+ // النصوص المفقودة
332
  const missingRegex = /__(.*?)__/g;
333
  while ((match = missingRegex.exec(analysisOutput)) !== null) {
334
  const phrase = match[1].trim();
335
  if (phrase) {
336
  const lineNum = getLineNumber(sourceText, phrase);
337
+ steps.push(`<li>${iconMissing} في السطر ${lineNum}، النص المفقود: <span class="highlight-missing">${phrase}</span></li>`);
338
  }
339
  }
340
+ // الأرقام والتواريخ
341
  const numberRegex = /<([^<>]+)>/g;
342
  while ((match = numberRegex.exec(analysisOutput)) !== null) {
343
  const phrase = match[1].trim();
344
  if (phrase) {
345
  const lineNum = getLineNumber(sourceText, phrase);
346
+ steps.push(`<li>${iconNumber} في السطر ${lineNum}، الرقم/التاريخ: <span class="highlight-number">${phrase}</span></li>`);
347
  }
348
  }
349
+ // اختلاف المعنى
 
 
 
 
 
 
 
 
 
350
  const meaningRegex = /\[MEANING\](.*?)\[\/MEANING\]/g;
351
  while ((match = meaningRegex.exec(analysisOutput)) !== null) {
352
  const phrase = match[1].trim();
353
  if (phrase) {
354
  const lineNum = getLineNumber(sourceText, phrase);
355
+ steps.push(`<li>${iconMeaning} في السطر ${lineNum}، اختلاف المعنى: <span class="highlight-meaning">${phrase}</span></li>`);
 
 
 
 
 
 
 
 
 
356
  }
357
  }
358
  if (steps.length === 0) {
359
+ return `<p><i class="fas fa-check-circle mr-2"></i> لا توجد اختلافات ملحوظة بين النصين.</p>`;
360
  }
361
  return `<ol class="list-decimal ml-6 space-y-2">${steps.join('')}</ol>`;
362
  };
363
 
364
+ /* -------------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  دالة معالجة الملفات (PDF و DOCX)
366
+ ------------------------------- */
367
  const processFile = async file => {
368
  let text = "";
369
  try {
 
391
  return text;
392
  };
393
 
394
+ /* -------------------------------
395
  التعامل مع رفع الملفات وإدخال النصوص
396
+ ------------------------------- */
397
  const processFileInput = (inputId, targetTextAreaId, errorMsg) => {
398
  document.getElementById(inputId)?.addEventListener('change', async (event) => {
399
  const file = event.target.files[0];
 
415
  processFileInput('targetFile', 'targetText', 'خطأ في معالجة ملف الهدف');
416
  processFileInput('sourceExtraFile', 'sourceExtraText', 'خطأ في معالجة ملف المصدر الإضافي');
417
 
418
+ /* -------------------------------
419
  دالة عرض الأخطاء
420
+ ------------------------------- */
421
  const addError = (message, type = 'error') => {
422
  const errorsList = document.getElementById('errorsList');
423
  if (!errorsList) return;
 
430
  errorsList.appendChild(errorDiv);
431
  };
432
 
433
+ /* -------------------------------
434
  التعامل مع عملية التحليل والمقارنة
435
+ ------------------------------- */
436
  document.getElementById('submitBtn').addEventListener('click', async () => {
437
  const sourceText = document.getElementById('sourceText').value;
438
  const targetText = document.getElementById('targetText').value;
 
491
  const analysisOutput = data.choices[0].message.content.trim();
492
  progressDiv.remove();
493
 
494
+ // إذا كان الناتج يحتوي على علامة التطابق التام
495
  if (analysisOutput.includes('[MATCH]')) {
496
  const checkDiv = document.createElement('div');
497
  checkDiv.className = "p-4 rounded-xl bg-green-50 text-green-700 flex items-center";
 
501
  document.getElementById('targetTextReview').innerHTML = splitIntoLines(targetText);
502
  document.getElementById('explanationText').innerHTML = `<p>النصوص متطابقة ولا يوجد اختلاف يجب الإشارة إليه.</p>`;
503
  } else {
504
+ // تطبيق التظليل على النصوص بناءً على العلامات المستخرجة
505
  const sourceHighlighted = applyHighlights(sourceText, analysisOutput);
506
  const targetHighlighted = applyHighlights(targetText, analysisOutput);
507
  document.getElementById('sourceTextReview').innerHTML = splitIntoLines(sourceHighlighted);
 
509
  const explanationHTML = generateExplanation(sourceText, analysisOutput);
510
  document.getElementById('explanationText').innerHTML = explanationHTML;
511
  }
 
 
 
 
 
 
 
 
 
 
 
512
  } catch (error) {
513
  document.getElementById('errorsList').innerHTML = '';
514
  addError(`خطأ في التحليل: ${error.message}`);