joermd commited on
Commit
f2ebb4e
·
verified ·
1 Parent(s): a6752fa

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +388 -257
index.html CHANGED
@@ -10,7 +10,7 @@
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%; }
@@ -30,8 +30,9 @@
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
  .text-comparison { line-height: 1.8; white-space: pre-wrap; }
37
  .highlight-number {
@@ -53,8 +54,9 @@
53
  border-radius: 3px;
54
  font-weight: bold;
55
  }
 
56
  /* ================================
57
- تنسيق عرض السطور في المعاينة (من الكود الأول)
58
  ================================= */
59
  .split-view {
60
  display: grid;
@@ -73,8 +75,9 @@
73
  flex-shrink: 0;
74
  }
75
  .line-text { flex: 1; }
 
76
  /* ================================
77
- تحسين تنسيق البطاقات والعناصر (من الكود الأول)
78
  ================================= */
79
  .card-hover {
80
  transition: all 0.3s ease;
@@ -83,37 +86,6 @@
83
  box-shadow: 0 10px 25px -5px rgba(156,39,176,0.1), 0 10px 10px -5px rgba(156,39,176,0.04);
84
  transform: translateY(-2px);
85
  }
86
- /* ================================
87
- إضافات من الكود الثاني للتنسيق المفصل للاختلافات
88
- ================================= */
89
- .diff-highlight {
90
- display: inline;
91
- padding: 2px 0;
92
- }
93
- .diff-added {
94
- background-color: #c8e6c9;
95
- text-decoration: none;
96
- }
97
- .diff-removed {
98
- background-color: #ffcdd2;
99
- text-decoration: line-through;
100
- }
101
- .diff-changed {
102
- background-color: #fff9c4;
103
- text-decoration: none;
104
- }
105
- /* تنسيق قسم مفتاح الـ API باستخدام Tailwind */
106
- .api-key-input input {
107
- width: 100%;
108
- padding: 0.75rem;
109
- border: 2px solid #ddd;
110
- border-radius: 0.5rem;
111
- outline: none;
112
- transition: border-color 0.3s;
113
- }
114
- .api-key-input input:focus {
115
- border-color: #6366F1;
116
- }
117
  </style>
118
  </head>
119
  <body class="bg-gradient-to-br from-gray-100 via-blue-100 to-indigo-100 min-h-screen">
@@ -121,25 +93,15 @@
121
  <!-- ============ رأس الصفحة ============ -->
122
  <header class="bg-gradient-to-r from-indigo-700 via-purple-700 to-pink-700 animate-gradient text-white py-10 mb-10 shadow-xl">
123
  <div class="max-w-6xl mx-auto px-4">
124
- <h1 class="text-5xl font-bold text-center mb-4 animate-scale">نظام شركة موندو لينجوا - مراجعة النصوص</h1>
125
- <p class="text-center text-xl text-blue-100 opacity-90">مقارنة وتحليل النصوص بدقة عالية</p>
126
  </div>
127
  </header>
128
 
129
  <!-- ============ المحتوى الرئيسي ============ -->
130
- <main class="max-w-6xl mx-auto px-4 space-y-8">
131
- <!-- قسم مفتاح API -->
132
- <div class="bg-white rounded-2xl shadow-lg p-8 border border-gray-100 hover:shadow-xl transition-all animate-scale card-hover">
133
- <div class="api-key-input">
134
- <label class="block text-lg font-bold text-gray-700 mb-3 flex items-center">
135
- <i class="fas fa-key text-green-600 ml-2"></i> مفتاح API
136
- </label>
137
- <input type="text" id="apiKey" value="sk-21a46269cd8e449f8aeb0cc129c36c33" placeholder="أدخل مفتاح API هنا...">
138
- </div>
139
- </div>
140
-
141
  <!-- قسم رفع الملفات -->
142
- <div class="bg-white rounded-2xl shadow-lg p-8 border border-gray-100 hover:shadow-xl transition-all animate-scale card-hover">
143
  <h2 class="text-2xl font-bold mb-6 text-gray-800 flex items-center border-b pb-3">
144
  <i class="fas fa-file-upload text-indigo-600 ml-2"></i> تحميل الملفات
145
  </h2>
@@ -170,7 +132,7 @@
170
  </div>
171
 
172
  <!-- قسم إدخال النصوص يدويًا -->
173
- <div class="bg-white rounded-2xl shadow-lg p-8 border border-gray-100 hover:shadow-xl transition-all animate-scale card-hover">
174
  <div class="space-y-6">
175
  <!-- النص المصدر -->
176
  <div class="group">
@@ -189,21 +151,79 @@
189
  </div>
190
  </div>
191
 
192
- <!-- زر المقارنة / التحليل -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  <button id="submitBtn" class="w-full bg-gradient-to-r from-indigo-600 to-pink-600 hover:from-indigo-700 hover:to-pink-700 text-white font-bold py-5 px-8 rounded-xl transition-all transform hover:scale-105 focus:ring-indigo-200 text-xl shadow-lg hover:shadow-xl mb-8 pulse-animation">
194
  <div class="flex items-center justify-center">
195
- <i class="fas fa-sync-alt ml-2"></i> قارن النصوص
196
  </div>
197
  </button>
198
 
199
- <!-- شاشة عرض النتائج -->
200
- <div id="resultSection" class="bg-white rounded-2xl shadow-lg p-8 border border-gray-100 hover:shadow-xl transition-all animate-scale hidden card-hover">
201
  <h2 class="text-2xl font-bold mb-6 text-gray-800 border-b pb-3 flex items-center">
202
  <i class="fas fa-search text-green-600 ml-2"></i> نتائج التحليل والمقارنة
203
  </h2>
204
- <!-- هنا سيتم عرض الشرح التفصيلي مع مقارنة سطرية -->
205
- <div id="comparisonResults" class="space-y-6"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  </main>
208
  </div>
209
 
@@ -211,227 +231,338 @@
211
  جافا سكريبت: الوظائف والمعالجة
212
  ================================= -->
213
  <script>
214
- document.addEventListener('DOMContentLoaded', function() {
215
- // إعدادات API الأساسية
216
- const API_URL = 'https://api.deepseek.com/chat/completions';
 
217
 
218
- /* =====================================
219
- دوال مساعدة للتعامل مع النصوص (من الكود الأول)
220
- ===================================== */
221
- function countWords(text) {
222
- return text.trim().split(/\s+/).filter(word => word !== "").length;
223
- }
224
- function escapeRegExp(string) {
225
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  }
227
- function splitIntoLines(text) {
228
- return text.split('\n').map((line, i) => `<div class="line-item"><span class="line-number">${i+1}:</span> <span class="line-text">${line}</span></div>`).join('');
 
 
 
 
 
 
 
229
  }
230
- function getLineNumber(text, substring) {
231
- const index = text.indexOf(substring);
232
- if (index === -1) return "غير محدد";
233
- return text.substring(0, index).split("\n").length;
 
 
 
 
 
234
  }
 
 
235
 
236
- /* =====================================
237
- دالة تنسيق النتيجة بالشكل المفصل (من الكود الثاني)
238
- ===================================== */
239
- function formatAnalysisResult(analysisText, sourceText, targetText) {
240
- let formattedText = analysisText
241
- .replace(/\n/g, '<br>')
242
- .replace(/الأرقام المكتوبة بشكل خاطئ:|الأرقام غير الصحيحة:/gi, '<strong class="text-red-600">الأرقام المكتوبة بشكل خاطئ:</strong>')
243
- .replace(/النصوص المفقودة:/gi, '<strong class="text-red-600">النصوص المفقودة:</strong>')
244
- .replace(/النصوص الفاسدة:|النصوص غير المفهومة:/gi, '<strong class="text-red-600">النصوص الفاسدة:</strong>')
245
- .replace(/النصوص المختلفة في المعنى:/gi, '<strong class="text-red-600">النصوص المختلفة في المعنى:</strong>')
246
- .replace(/في النص المصدر: "(.*?)"/g, 'في النص المصدر: "<span class="diff-highlight diff-removed">$1</span>"')
247
- .replace(/في النص الهدف: "(.*?)"/g, 'في النص الهدف: "<span class="diff-highlight diff-added">$1</span>"');
248
-
249
- // مقارنة سطرية مرئية
250
- const sourceLines = sourceText.split('\n');
251
- const targetLines = targetText.split('\n');
252
- const maxLines = Math.max(sourceLines.length, targetLines.length);
253
-
254
- let visualComparison = '<h3 class="text-lg font-bold text-gray-700 mt-6 mb-3">المقارنة السطرية:</h3><div class="flex flex-col md:flex-row gap-6">';
255
-
256
- visualComparison += '<div class="flex-1"><h4 class="font-bold text-indigo-600 mb-2">النص المصدر:</h4><div class="bg-indigo-50 p-4 rounded-lg border border-indigo-100 overflow-x-auto">';
257
- for (let i = 0; i < maxLines; i++) {
258
- if(i < sourceLines.length) {
259
- visualComparison += `<div>${i+1}. ${sourceLines[i]}</div>`;
260
- }
261
  }
262
- visualComparison += '</div></div>';
263
-
264
- visualComparison += '<div class="flex-1"><h4 class="font-bold text-pink-600 mb-2">النص الهدف:</h4><div class="bg-pink-50 p-4 rounded-lg border border-pink-100 overflow-x-auto">';
265
- for (let i = 0; i < maxLines; i++) {
266
- if(i < targetLines.length) {
267
- visualComparison += `<div>${i+1}. ${targetLines[i]}</div>`;
268
- }
 
269
  }
270
- visualComparison += '</div></div>';
271
-
272
- visualComparison += '</div>';
273
-
274
- return formattedText + '<br><br>' + visualComparison;
275
  }
276
-
277
- /* =====================================
278
- دالة معالجة الملفات (PDF و DOCX) - من الكود الأول
279
- ===================================== */
280
- async function processFile(file) {
281
- let text = "";
282
- if (file.type === 'application/pdf') {
283
- const form = new FormData();
284
- form.append('image', file);
285
- const response = await fetch('https://demo.api4ai.cloud/ocr/v1/results', {
286
- method: 'POST',
287
- body: form,
288
- headers: { 'A4A-CLIENT-APP-ID': 'sample' }
289
- });
290
- const data = await response.json();
291
- text = data.results[0].entities[0].objects[0].entities[0].text;
292
- } else if (file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
293
- const arrayBuffer = await file.arrayBuffer();
294
- const result = await mammoth.extractRawText({ arrayBuffer });
295
- text = result.value;
296
- } else {
297
- throw new Error('نوع الملف غير مدعوم');
298
  }
299
- return text;
300
  }
 
 
 
 
 
 
301
 
302
- /* =====================================
303
- ربط أحداث رفع الملفات (من الكود الأول)
304
- ===================================== */
305
- const sourceFileEl = document.getElementById('sourceFile');
306
- if (sourceFileEl) {
307
- sourceFileEl.addEventListener('change', async (event) => {
308
- const file = event.target.files[0];
309
- if (!file) return;
310
- document.getElementById('processStatus').classList.remove('hidden');
311
- try {
312
- const text = await processFile(file);
313
- document.getElementById('sourceText').value = text;
314
- } catch (error) {
315
- console.error('Error processing source file:', error);
316
- alert('خطأ في معالجة ملف السورس');
317
- } finally {
318
- document.getElementById('processStatus').classList.add('hidden');
319
- }
320
  });
 
 
 
 
 
 
 
 
321
  }
322
- const targetFileEl = document.getElementById('targetFile');
323
- if (targetFileEl) {
324
- targetFileEl.addEventListener('change', async (event) => {
325
- const file = event.target.files[0];
326
- if (!file) return;
327
- document.getElementById('processStatus').classList.remove('hidden');
328
- try {
329
- const text = await processFile(file);
330
- document.getElementById('targetText').value = text;
331
- } catch (error) {
332
- console.error('Error processing target file:', error);
333
- alert('خطأ في معالجة ملف التارجت');
334
- } finally {
335
- document.getElementById('processStatus').classList.add('hidden');
336
- }
337
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
338
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
 
340
- /* =====================================
341
- حدث النقر على زر المقارنة / التحليل
342
- ===================================== */
343
- const submitBtn = document.getElementById('submitBtn');
344
- if (submitBtn) {
345
- submitBtn.addEventListener('click', async () => {
346
- const sourceText = document.getElementById('sourceText').value.trim();
347
- const targetText = document.getElementById('targetText').value.trim();
348
- const apiKey = document.getElementById('apiKey').value.trim();
349
- const resultsContainer = document.getElementById('comparisonResults');
350
- const resultSection = document.getElementById('resultSection');
 
 
 
351
 
352
- resultsContainer.innerHTML = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
 
354
- if (!sourceText || !targetText) {
355
- alert('الرجاء إدخال كلا النصين المصدر والهدف');
356
- return;
357
- }
358
- if (!apiKey) {
359
- alert('الرجاء إدخال مفتاح API صالح');
360
- return;
361
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
 
363
- // مقارنة عدد الكلمات وتنبيه إن وجد اختلاف (اختياري)
364
- const sourceWordCount = countWords(sourceText);
365
- const targetWordCount = countWords(targetText);
366
- if (sourceWordCount !== targetWordCount) {
367
- resultsContainer.innerHTML += `<div class="p-4 rounded-xl bg-yellow-50 text-yellow-700 mb-4"><i class="fas fa-info-circle ml-2"></i> عدد كلمات النص المصدر (${sourceWordCount}) يختلف عن النص الهدف (${targetWordCount}).</div>`;
 
 
 
 
 
 
 
 
 
368
  }
369
-
370
- // عرض مؤشر التقدم
371
- resultsContainer.innerHTML += `<div id="progressIndicator" class="bg-indigo-100 p-4 rounded-xl mb-4 flex items-center justify-center">
372
- <div class="animate-spin h-8 w-8 border-4 border-indigo-600 rounded-full border-t-transparent mr-3"></div>
373
- <span class="text-indigo-700 text-lg">جارٍ التحليل...</span>
374
- </div>`;
375
-
376
- // بناء prompt باستخدام نصوص المصدر والهدف
377
- const prompt = `
378
- قارن بين النص المصدر والنص الهدف وحدد الاختلافات بينهما، بما في ذلك:
379
- 1. الأرقام المكتوبة بشكل خاطئ
380
- 2. النصوص المفقودة
381
- 3. النصوص الفاسدة أو غير المفهومة
382
- 4. النصوص المختلفة في المعنى
383
-
384
- قدم تحليلاً مفصلاً للاختلافات وتصنيفها حسب نوع الخطأ.
385
-
386
- النص المصدر:
387
- ${sourceText}
388
 
389
- النص الهدف:
390
- ${targetText}
391
- `;
392
-
393
- try {
394
- const payload = {
395
- model: 'deepseek-reasoner',
396
- messages: [
397
- { role: 'system', content: 'أنت مساعد متخصص في مراجعة النصوص وتحديد الاختلافات بينها بدقة عالية.' },
398
- { role: 'user', content: prompt }
399
- ],
400
- temperature: 0.3,
401
- max_tokens: 2048,
402
- stream: false
403
- };
404
-
405
- const response = await fetch(API_URL, {
406
- method: 'POST',
407
- headers: {
408
- 'Content-Type': 'application/json',
409
- 'Authorization': 'Bearer ' + apiKey
410
- },
411
- body: JSON.stringify(payload)
412
- });
413
-
414
- if (!response.ok) {
415
- throw new Error('خطأ في الاتصال بالـ API: ' + response.statusText);
416
- }
417
-
418
- const data = await response.json();
419
- const analysisResult = data.choices[0].message.content.trim();
420
-
421
- // إزالة مؤشر التقدم
422
- const progressIndicator = document.getElementById('progressIndicator');
423
- if (progressIndicator) progressIndicator.remove();
424
-
425
- // عرض النتيجة باستخدام دالة التنسيق
426
- const formattedResult = formatAnalysisResult(analysisResult, sourceText, targetText);
427
- resultsContainer.innerHTML += formattedResult;
428
- resultSection.classList.remove('hidden');
429
- } catch (error) {
430
- resultsContainer.innerHTML = '';
431
- alert('حدث خطأ في التحليل: ' + error.message);
432
- console.error('Error:', error);
433
- }
434
- });
435
  }
436
  });
437
  </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%; }
 
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 {
 
54
  border-radius: 3px;
55
  font-weight: bold;
56
  }
57
+
58
  /* ================================
59
+ تنسيق عرض السطور في المعاينة
60
  ================================= */
61
  .split-view {
62
  display: grid;
 
75
  flex-shrink: 0;
76
  }
77
  .line-text { flex: 1; }
78
+
79
  /* ================================
80
+ تحسين تنسيق البطاقات والعناصر
81
  ================================= */
82
  .card-hover {
83
  transition: all 0.3s ease;
 
86
  box-shadow: 0 10px 25px -5px rgba(156,39,176,0.1), 0 10px 10px -5px rgba(156,39,176,0.04);
87
  transform: translateY(-2px);
88
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  </style>
90
  </head>
91
  <body class="bg-gradient-to-br from-gray-100 via-blue-100 to-indigo-100 min-h-screen">
 
93
  <!-- ============ رأس الصفحة ============ -->
94
  <header class="bg-gradient-to-r from-indigo-700 via-purple-700 to-pink-700 animate-gradient text-white py-10 mb-10 shadow-xl">
95
  <div class="max-w-6xl mx-auto px-4">
96
+ <h1 class="text-5xl font-bold text-center mb-4 animate-scale">نظام شركة موندو لينجوا</h1>
97
+ <p class="text-center text-xl text-blue-100 opacity-90">مقارنة وتحليل النصوص المصدر مرجع أساسي</p>
98
  </div>
99
  </header>
100
 
101
  <!-- ============ المحتوى الرئيسي ============ -->
102
+ <main class="max-w-6xl mx-auto px-4">
 
 
 
 
 
 
 
 
 
 
103
  <!-- قسم رفع الملفات -->
104
+ <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">
105
  <h2 class="text-2xl font-bold mb-6 text-gray-800 flex items-center border-b pb-3">
106
  <i class="fas fa-file-upload text-indigo-600 ml-2"></i> تحميل الملفات
107
  </h2>
 
132
  </div>
133
 
134
  <!-- قسم إدخال النصوص يدويًا -->
135
+ <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">
136
  <div class="space-y-6">
137
  <!-- النص المصدر -->
138
  <div class="group">
 
151
  </div>
152
  </div>
153
 
154
+ <!-- قسم المصادر الإضافية -->
155
+ <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">
156
+ <h2 class="text-2xl font-bold mb-6 text-gray-800 flex items-center border-b pb-3">
157
+ <i class="fas fa-book-open text-green-600 ml-2"></i> مصادر إضافية
158
+ </h2>
159
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
160
+ <!-- رفع ملف المصادر الإضافية -->
161
+ <div class="group border-2 border-dashed border-green-300 rounded-xl p-8 text-center hover:border-green-500 transition-colors duration-300 bg-green-50 hover:bg-green-100">
162
+ <label class="cursor-pointer block">
163
+ <input type="file" id="sourceExtraFile" accept=".docx,.pdf" class="hidden">
164
+ <i class="fas fa-upload text-5xl text-green-500 mb-4"></i>
165
+ <span class="text-lg text-green-600 group-hover:text-green-700">تحميل ملف المصدر</span>
166
+ </label>
167
+ </div>
168
+ <!-- إدخال المصادر يدويًا -->
169
+ <div class="group">
170
+ <label class="block text-lg font-bold text-gray-700 mb-3 flex items-center">
171
+ <i class="fas fa-edit text-green-600 ml-2"></i> إدخال المصادر يدويًا
172
+ </label>
173
+ <textarea id="sourceExtraText" dir="rtl" class="w-full px-6 py-4 border-2 border-green-200 rounded-xl focus:ring-green-200 focus:border-green-400 transition-all resize-none text-lg" rows="6" placeholder="اكتب المصادر هنا..."></textarea>
174
+ </div>
175
+ </div>
176
+ </div>
177
+
178
+ <!-- زر التحليل -->
179
  <button id="submitBtn" class="w-full bg-gradient-to-r from-indigo-600 to-pink-600 hover:from-indigo-700 hover:to-pink-700 text-white font-bold py-5 px-8 rounded-xl transition-all transform hover:scale-105 focus:ring-indigo-200 text-xl shadow-lg hover:shadow-xl mb-8 pulse-animation">
180
  <div class="flex items-center justify-center">
181
+ <i class="fas fa-sync-alt ml-2"></i> تحليل النصوص
182
  </div>
183
  </button>
184
 
185
+ <!-- شاشة عرض نتائج التحليل -->
186
+ <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">
187
  <h2 class="text-2xl font-bold mb-6 text-gray-800 border-b pb-3 flex items-center">
188
  <i class="fas fa-search text-green-600 ml-2"></i> نتائج التحليل والمقارنة
189
  </h2>
190
+ <div id="errorsList" class="space-y-3 mb-6"></div>
191
+ <div class="result-section split-view">
192
+ <!-- عرض النص المصدر بعد التحديد مع ترقيم السطور -->
193
+ <div>
194
+ <h4 class="text-lg font-bold text-gray-700 mb-3 flex items-center">
195
+ <i class="fas fa-file-alt text-indigo-600 ml-2"></i> النص المصدر (مع التعليم)
196
+ </h4>
197
+ <div id="sourceTextReview" class="bg-indigo-50 rounded-xl p-6 min-h-[200px] border-2 border-indigo-100 text-comparison"></div>
198
+ </div>
199
+ <!-- عرض النص الهدف بعد التحديد مع ترقيم السطور -->
200
+ <div>
201
+ <h4 class="text-lg font-bold text-gray-700 mb-3 flex items-center">
202
+ <i class="fas fa-file-alt text-pink-600 ml-2"></i> النص الهدف (مع التعليم)
203
+ </h4>
204
+ <div id="targetTextReview" class="bg-gray-50 rounded-xl p-6 min-h-[200px] border-2 border-gray-200 text-comparison"></div>
205
+ </div>
206
+ </div>
207
  </div>
208
+
209
+ <!-- صندوق عرض الشرح التفصيلي للنتائج -->
210
+ <div id="explanationBox" 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">
211
+ <h2 class="text-2xl font-bold mb-6 text-gray-800 border-b pb-3 flex items-center">
212
+ <i class="fas fa-info-circle text-green-600 ml-2"></i> شرح الاختلافات
213
+ </h2>
214
+ <div id="explanationText" class="text-lg text-gray-700"></div>
215
+ </div>
216
+
217
+ <!-- قسم عرض المسودة (التحليل النصي الكامل) مع زر التبديل -->
218
+ <div id="fullTextDraftSection" class="bg-white rounded-2xl shadow-lg p-8 border border-gray-100 transition-all animate-scale mb-8 hidden card-hover">
219
+ <h2 class="text-2xl font-bold mb-6 text-gray-800 border-b pb-3 flex items-center">
220
+ <i class="fas fa-file-alt text-blue-600 ml-2"></i> مسودة التحليل النصي الكامل
221
+ </h2>
222
+ <div id="fullTextDraft" class="bg-gray-50 rounded-xl p-6 border border-gray-200 text-comparison"></div>
223
+ </div>
224
+ <button id="toggleDraftBtn" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mb-8">
225
+ عرض/إخفاء التحليل النصي الكامل
226
+ </button>
227
  </main>
228
  </div>
229
 
 
231
  جافا سكريبت: الوظائف والمعالجة
232
  ================================= -->
233
  <script>
234
+ // إعدادات API
235
+ const API_URL = 'https://api.deepseek.com/chat/completions';
236
+ const API_KEY = 'sk-15606736ed9e4aea8b7cc11a195d2b01';
237
+ let fullAnalysisText = ''; // متغير لتخزين النص الكامل للتحليل
238
 
239
+ /*
240
+ البرومبت الجديد: يتم فيه تحديد أن النصوص مليئة بالأخطاء والنواقص،
241
+ مع ضرورة الحفاظ على علامات التحديد (التعليم) كما هي.
242
+ */
243
+ const ANALYSIS_PROMPT = `أنت خبير لغوي متخصص في مراجعة الترجمة التقنية. مهمتك مقارنة النص المصدر والنص الهدف بدقة عالية مع العلم أن النصوص مليانة بالأخطاء والنواقص.
244
+ لا تقم بإزالة أو تعديل العلامات التالية:
245
+ الأرقام: تحافظ على علامات < و >.
246
+ النصوص المفقودة: تحافظ على علامات __ و __.
247
+ • اختلافات المعنى: تحافظ على علامات [MEANING] و [/MEANING].
248
+
249
+ اعتمد النص المصدر كأساس للمقارنة، وقم بتحديد:
250
+ 1. اختلافات الأرقام باستخدام <الرقم_في_المصدر> → <الرقم_في_الهدف>.
251
+ 2. النصوص المفقودة كما هي بين علامتي __.
252
+ 3. اختلافات المعنى باستخدام [MEANING] مع الحفاظ على التعليم.
253
+
254
+ النص المصدر:
255
+ {source}
256
+
257
+ النص الهدف:
258
+ {target}`;
259
+
260
+ /* =====================================
261
+ دوال مساعدة للتعامل مع النصوص
262
+ ===================================== */
263
+ // حساب عدد الكلمات في النص
264
+ function countWords(text) {
265
+ return text.trim().split(/\s+/).filter(word => word !== "").length;
266
+ }
267
+ // هروب أحرف Regex الخاصة
268
+ function escapeRegExp(string) {
269
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
270
+ }
271
+ // تقسيم النص إلى أسطر مع عرض رقم السطر
272
+ function splitIntoLines(text) {
273
+ return text.split('\n').map((line, i) => `<div class="line-item"><span class="line-number">${i+1}:</span> <span class="line-text">${line}</span></div>`).join('');
274
+ }
275
+ // الحصول على رقم السطر لظهور عبارة معينة
276
+ function getLineNumber(text, substring) {
277
+ const index = text.indexOf(substring);
278
+ if (index === -1) return "غير محدد";
279
+ return text.substring(0, index).split("\n").length;
280
+ }
281
+
282
+ /* =====================================
283
+ دوال التمييز (Highlighting) للنتائج
284
+ ===================================== */
285
+ function applyHighlights(originalText, analysisOutput) {
286
+ let highlightedText = originalText;
287
+ // تمييز اختلافات الأرقام
288
+ const numberRegex = /<([^<>]+)>/g;
289
+ let match;
290
+ while ((match = numberRegex.exec(analysisOutput)) !== null) {
291
+ const phrase = match[1].trim();
292
+ if (phrase) {
293
+ const replacement = `<span class="highlight-number">${phrase}</span>`;
294
+ const phraseRegex = new RegExp(escapeRegExp(phrase), 'g');
295
+ highlightedText = highlightedText.replace(phraseRegex, replacement);
296
+ }
297
  }
298
+ // تمييز النصوص المفقودة
299
+ const missingRegex = /__(.*?)__/g;
300
+ while ((match = missingRegex.exec(analysisOutput)) !== null) {
301
+ const phrase = match[1].trim();
302
+ if (phrase) {
303
+ const replacement = `<span class="highlight-missing">__${phrase}__</span>`;
304
+ const phraseRegex = new RegExp(escapeRegExp(phrase), 'g');
305
+ highlightedText = highlightedText.replace(phraseRegex, replacement);
306
+ }
307
  }
308
+ // تمييز اختلافات المعنى
309
+ const meaningRegex = /\[MEANING\](.*?)\[\/MEANING\]/g;
310
+ while ((match = meaningRegex.exec(analysisOutput)) !== null) {
311
+ const phrase = match[1].trim();
312
+ if (phrase) {
313
+ const replacement = `<span class="highlight-meaning">${phrase}</span>`;
314
+ const phraseRegex = new RegExp(escapeRegExp(phrase), 'g');
315
+ highlightedText = highlightedText.replace(phraseRegex, replacement);
316
+ }
317
  }
318
+ return highlightedText;
319
+ }
320
 
321
+ /* =====================================
322
+ دالة توليد الشرح التفصيلي Organized Explanation
323
+ يتم تقسيم الشرح إلى خطوات منظمة
324
+ ===================================== */
325
+ function generateExplanation(sourceText, analysisOutput) {
326
+ let steps = [];
327
+ // الخطوة 1: النصوص المفقودة
328
+ const missingRegex = /__(.*?)__/g;
329
+ let match;
330
+ while ((match = missingRegex.exec(analysisOutput)) !== null) {
331
+ const phrase = match[1].trim();
332
+ if (phrase) {
333
+ const lineNum = getLineNumber(sourceText, phrase);
334
+ steps.push(`<li><strong>الخطوة 1:</strong> في السطر ${lineNum}، الجزء "<span class="highlight-missing">__${phrase}__</span>" من النص المصدر مفقود في النص الهدف. تأكد من إضافته لتحسين الدقة.</li>`);
 
 
 
 
 
 
 
 
 
 
 
335
  }
336
+ }
337
+ // الخطوة 2: اختلافات الأرقام
338
+ const numberRegex = /<([^<>]+)>/g;
339
+ while ((match = numberRegex.exec(analysisOutput)) !== null) {
340
+ const phrase = match[1].trim();
341
+ if (phrase) {
342
+ const lineNum = getLineNumber(sourceText, phrase);
343
+ steps.push(`<li><strong>الخطوة 2:</strong> في السطر ${lineNum}، الرقم "<span class="highlight-number">${phrase}</span>" في المصدر لا يتطابق مع الرقم في ��لهدف. يرجى المراجعة.</li>`);
344
  }
 
 
 
 
 
345
  }
346
+ // الخطوة 3: اختلافات المعنى
347
+ const meaningRegex = /\[MEANING\](.*?)\[\/MEANING\]/g;
348
+ while ((match = meaningRegex.exec(analysisOutput)) !== null) {
349
+ const phrase = match[1].trim();
350
+ if (phrase) {
351
+ const lineNum = getLineNumber(sourceText, phrase);
352
+ steps.push(`<li><strong>الخطوة 3:</strong> في السطر ${lineNum}، تم العثور على اختلاف في المعنى مع التعبير "<span class="highlight-meaning">${phrase}</span>". تحقق من الدقة.</li>`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
  }
 
354
  }
355
+ // إذا لم يكن هناك اختلافات
356
+ if (steps.length === 0) {
357
+ return `<p>النصوص متطابقة تماماً ولا توجد فروقات تحتاج للتنبيه.</p>`;
358
+ }
359
+ return `<ol class="list-decimal ml-6 space-y-2">${steps.join('')}</ol>`;
360
+ }
361
 
362
+ /* =====================================
363
+ دالة معالجة الملفات (PDF و DOCX)
364
+ ===================================== */
365
+ async function processFile(file) {
366
+ let text = "";
367
+ if (file.type === 'application/pdf') {
368
+ const form = new FormData();
369
+ form.append('image', file);
370
+ const response = await fetch('https://demo.api4ai.cloud/ocr/v1/results', {
371
+ method: 'POST',
372
+ body: form,
373
+ headers: { 'A4A-CLIENT-APP-ID': 'sample' }
 
 
 
 
 
 
374
  });
375
+ const data = await response.json();
376
+ text = data.results[0].entities[0].objects[0].entities[0].text;
377
+ } else if (file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
378
+ const arrayBuffer = await file.arrayBuffer();
379
+ const result = await mammoth.extractRawText({ arrayBuffer });
380
+ text = result.value;
381
+ } else {
382
+ throw new Error('نوع الملف غير مدعوم');
383
  }
384
+ return text;
385
+ }
386
+
387
+ /* =====================================
388
+ دوال رفع الملفات وإدخال النصوص
389
+ ===================================== */
390
+ // رفع ملف السورس
391
+ document.getElementById('sourceFile')?.addEventListener('change', async (event) => {
392
+ const file = event.target.files[0];
393
+ if (!file) return;
394
+ document.getElementById('processStatus').classList.remove('hidden');
395
+ try {
396
+ const text = await processFile(file);
397
+ document.getElementById('sourceText').value = text;
398
+ } catch (error) {
399
+ console.error('Error processing source file:', error);
400
+ addError('خطأ في معالجة ملف السورس');
401
+ } finally {
402
+ document.getElementById('processStatus').classList.add('hidden');
403
+ }
404
+ });
405
+ // رفع ملف التارجت
406
+ document.getElementById('targetFile')?.addEventListener('change', async (event) => {
407
+ const file = event.target.files[0];
408
+ if (!file) return;
409
+ document.getElementById('processStatus').classList.remove('hidden');
410
+ try {
411
+ const text = await processFile(file);
412
+ document.getElementById('targetText').value = text;
413
+ } catch (error) {
414
+ console.error('Error processing target file:', error);
415
+ addError('خطأ في معالجة ملف التارجت');
416
+ } finally {
417
+ document.getElementById('processStatus').classList.add('hidden');
418
  }
419
+ });
420
+ // رفع ملف المصادر الإضافية
421
+ document.getElementById('sourceExtraFile')?.addEventListener('change', async (event) => {
422
+ const file = event.target.files[0];
423
+ if (!file) return;
424
+ document.getElementById('processStatus').classList.remove('hidden');
425
+ try {
426
+ const text = await processFile(file);
427
+ document.getElementById('sourceExtraText').value = text;
428
+ } catch (error) {
429
+ console.error('Error processing extra source file:', error);
430
+ addError('خطأ في معالجة ملف المصدر الإضافي');
431
+ } finally {
432
+ document.getElementById('processStatus').classList.add('hidden');
433
+ }
434
+ });
435
 
436
+ /* =====================================
437
+ دالة عرض الأخطاء والرسائل
438
+ ===================================== */
439
+ function addError(message, type = 'error') {
440
+ const errorsList = document.getElementById('errorsList');
441
+ if (!errorsList) return;
442
+ const errorDiv = document.createElement('div');
443
+ errorDiv.className = `p-4 rounded-xl ${type === 'error' ? 'bg-red-50 text-red-700' : 'bg-yellow-50 text-yellow-700'}`;
444
+ errorDiv.innerHTML = `<div class="flex items-center">
445
+ <i class="fas fa-${type === 'error' ? 'exclamation-circle' : 'info-circle'} ml-2 text-${type === 'error' ? 'red' : 'yellow'}-500"></i>
446
+ <span>${message}</span>
447
+ </div>`;
448
+ errorsList.appendChild(errorDiv);
449
+ }
450
 
451
+ /* =====================================
452
+ معالجة عملية التحليل عند الضغط على الزر
453
+ ===================================== */
454
+ document.getElementById('submitBtn').addEventListener('click', async () => {
455
+ const sourceText = document.getElementById('sourceText').value;
456
+ const targetText = document.getElementById('targetText').value;
457
+ // مسح الرسائل السابقة وإظهار النتائج
458
+ document.getElementById('errorsList').innerHTML = '';
459
+ document.getElementById('resultSection').classList.remove('hidden');
460
+ document.getElementById('explanationBox').classList.remove('hidden');
461
+
462
+ if (!sourceText || !targetText) {
463
+ addError('يرجى إدخال كلا النصين المصدر والهدف');
464
+ return;
465
+ }
466
+
467
+ // مقارنة عدد الكلمات وتنبيه إن وجد اختلاف
468
+ const sourceWordCount = countWords(sourceText);
469
+ const targetWordCount = countWords(targetText);
470
+ if (sourceWordCount !== targetWordCount) {
471
+ addError(`عدد كلمات النص المصدر (${sourceWordCount}) يختلف عن النص الهدف (${targetWordCount})`, 'warning');
472
+ }
473
+
474
+ try {
475
+ // عرض مؤشر التقدم
476
+ const progressDiv = document.createElement('div');
477
+ progressDiv.className = "bg-indigo-100 p-4 rounded-xl mb-4";
478
+ progressDiv.innerHTML = `<div class="flex items-center">
479
+ <div class="animate-spin h-6 w-6 border-4 border-indigo-600 rounded-full border-t-transparent ml-3"></div>
480
+ <span>جارٍ التحليل...</span>
481
+ </div>`;
482
+ document.getElementById('errorsList').appendChild(progressDiv);
483
 
484
+ // بناء الـ prompt باستخدام النصين المُدخلين
485
+ const prompt = ANALYSIS_PROMPT
486
+ .replace("{source}", sourceText)
487
+ .replace("{target}", targetText);
488
+
489
+ // استدعاء DeepSeek API
490
+ const payload = {
491
+ model: "deepseek-chat",
492
+ messages: [
493
+ { role: "system", content: "أنت خبير في تحليل النصوص ومقارنتها بدقة عالية." },
494
+ { role: "user", content: prompt }
495
+ ],
496
+ temperature: 0.3,
497
+ max_tokens: 2048,
498
+ stream: false
499
+ };
500
+ const response = await fetch(API_URL, {
501
+ method: 'POST',
502
+ headers: {
503
+ 'Authorization': 'Bearer ' + API_KEY,
504
+ 'Content-Type': 'application/json'
505
+ },
506
+ body: JSON.stringify(payload)
507
+ });
508
+ if (!response.ok) {
509
+ throw new Error('حدث خطأ بالشبكة: ' + response.statusText);
510
+ }
511
+ const data = await response.json();
512
+ const analysisOutput = data.choices[0].message.content.trim();
513
+ fullAnalysisText = analysisOutput; // حفظ التحليل النصي الكامل في المتغير
514
+ progressDiv.remove();
515
+
516
+ // إذا كانت النصوص متطابقة تمامًا
517
+ if (analysisOutput.includes('[MATCH]')) {
518
+ const checkDiv = document.createElement('div');
519
+ checkDiv.className = "p-4 rounded-xl bg-green-50 text-green-700 flex items-center";
520
+ checkDiv.innerHTML = `<i class="fas fa-check-circle ml-2 text-lg"></i> <span class="text-lg">النصوص متطابقة تماماً</span>`;
521
+ document.getElementById('errorsList').appendChild(checkDiv);
522
+ document.getElementById('sourceTextReview').innerHTML = splitIntoLines(sourceText);
523
+ document.getElementById('targetTextReview').innerHTML = splitIntoLines(targetText);
524
+ document.getElementById('explanationText').innerHTML = `<p>النصوص متطابقة ولا يوجد اختلاف يجب الإشارة إليه.</p>`;
525
+ } else {
526
+ // تطبيق التحديد على النصوص
527
+ const sourceHighlighted = applyHighlights(sourceText, analysisOutput);
528
+ const targetHighlighted = applyHighlights(targetText, analysisOutput);
529
+ document.getElementById('sourceTextReview').innerHTML = splitIntoLines(sourceHighlighted);
530
+ document.getElementById('targetTextReview').innerHTML = splitIntoLines(targetHighlighted);
531
+ // توليد شرح منظم على شكل خطوات
532
+ const explanationHTML = generateExplanation(sourceText, analysisOutput);
533
+ document.getElementById('explanationText').innerHTML = explanationHTML;
534
 
535
+ // عرض ملخص الاختلافات (اختياري)
536
+ const numDiffCount = (analysisOutput.match(/<([^<>]+)>/g) || []).length;
537
+ const missingDiffCount = (analysisOutput.match(/__(.*?)__/g) || []).length;
538
+ const meaningDiffCount = (analysisOutput.match(/\[MEANING\](.*?)\[\/MEANING\]/g) || []).length;
539
+ if (numDiffCount > 0 || missingDiffCount > 0 || meaningDiffCount > 0) {
540
+ const summaryDiv = document.createElement('div');
541
+ summaryDiv.className = "p-4 rounded-xl bg-yellow-50 text-gray-800";
542
+ let summaryText = '<div class="font-bold mb-2">ملخص الاختلافات:</div><ul class="list-disc mr-6 space-y-1">';
543
+ if (numDiffCount > 0) summaryText += `<li>اختلاف في الأرقام: ${numDiffCount}</li>`;
544
+ if (missingDiffCount > 0) summaryText += `<li>النصوص المفقودة: ${missingDiffCount}</li>`;
545
+ if (meaningDiffCount > 0) summaryText += `<li>اختلاف في المعنى: ${meaningDiffCount}</li>`;
546
+ summaryText += '</ul>';
547
+ summaryDiv.innerHTML = summaryText;
548
+ document.getElementById('errorsList').appendChild(summaryDiv);
549
  }
550
+ }
551
+ } catch (error) {
552
+ document.getElementById('errorsList').innerHTML = '';
553
+ addError(`خطأ في التحليل: ${error.message}`);
554
+ }
555
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
556
 
557
+ // زر تبديل عرض/إخفاء المسودة (التحليل النصي الكامل)
558
+ document.getElementById('toggleDraftBtn').addEventListener('click', function() {
559
+ const draftSection = document.getElementById('fullTextDraftSection');
560
+ if (draftSection.classList.contains('hidden')) {
561
+ draftSection.classList.remove('hidden');
562
+ // عرض النص الكامل للتحليل مع تنسيق النصوص كما هي
563
+ document.getElementById('fullTextDraft').innerText = fullAnalysisText;
564
+ } else {
565
+ draftSection.classList.add('hidden');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
566
  }
567
  });
568
  </script>