Update index.html
Browse files- index.html +130 -179
index.html
CHANGED
@@ -3,14 +3,14 @@
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
-
<title>نظام المقارنة
|
7 |
<!-- استيراد مكتبات Tailwind وFont Awesome وMammoth -->
|
8 |
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
|
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%; }
|
@@ -30,9 +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 |
================================= */
|
37 |
.text-comparison { line-height: 1.8; white-space: pre-wrap; }
|
38 |
.highlight-number {
|
@@ -62,78 +62,81 @@
|
|
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 |
-
.split-view {
|
76 |
-
display: grid;
|
77 |
-
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
78 |
-
gap: 1rem;
|
79 |
-
}
|
80 |
.line-item {
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
}
|
85 |
.line-number {
|
86 |
-
width: 30px;
|
87 |
font-weight: bold;
|
88 |
color: #4B5563;
|
89 |
-
|
90 |
}
|
91 |
-
.line-text {
|
92 |
-
|
93 |
/* ================================
|
94 |
-
تحسين
|
95 |
================================= */
|
96 |
-
.card
|
97 |
-
|
|
|
|
|
|
|
|
|
98 |
}
|
99 |
.card-hover:hover {
|
100 |
-
box-shadow: 0 10px 25px -5px rgba(156,39,176,0.
|
101 |
-
transform: translateY(-
|
102 |
}
|
|
|
103 |
</style>
|
104 |
</head>
|
105 |
<body class="bg-gradient-to-br from-gray-100 via-blue-100 to-indigo-100 min-h-screen">
|
106 |
<div class="min-h-screen pb-12">
|
107 |
-
<!--
|
108 |
<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">
|
109 |
-
<div class="max-w-6xl mx-auto px-4">
|
110 |
-
<h1 class="text-5xl font-bold
|
111 |
-
|
|
|
|
|
|
|
|
|
112 |
</div>
|
113 |
</header>
|
114 |
|
115 |
-
<!--
|
116 |
-
<main class="max-w-6xl mx-auto px-4">
|
117 |
<!-- قسم رفع الملفات -->
|
118 |
-
<div class="
|
119 |
-
<h2 class="text-2xl font-bold
|
120 |
-
<i class="fas fa-file-upload text-indigo-600
|
121 |
</h2>
|
122 |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
123 |
-
<!-- ملف
|
124 |
-
<div class="group border-2 border-dashed border-indigo-300 rounded-xl p-8 text-center hover:
|
125 |
<label class="cursor-pointer block">
|
126 |
<input type="file" id="sourceFile" accept=".docx,.pdf" class="hidden">
|
127 |
-
<i class="fas fa-
|
128 |
-
<span class="text-lg text-indigo-600 group-hover:text-indigo-700">ملف
|
129 |
</label>
|
130 |
</div>
|
131 |
-
<!-- ملف
|
132 |
-
<div class="group border-2 border-dashed border-pink-300 rounded-xl p-8 text-center hover:
|
133 |
<label class="cursor-pointer block">
|
134 |
<input type="file" id="targetFile" accept=".docx,.pdf" class="hidden">
|
135 |
-
<i class="fas fa-
|
136 |
-
<span class="text-lg text-pink-600 group-hover:text-pink-700">ملف
|
137 |
</label>
|
138 |
</div>
|
139 |
</div>
|
@@ -146,19 +149,19 @@
|
|
146 |
</div>
|
147 |
|
148 |
<!-- قسم إدخال النصوص يدويًا -->
|
149 |
-
<div class="
|
150 |
<div class="space-y-6">
|
151 |
<!-- النص المصدر -->
|
152 |
<div class="group">
|
153 |
-
<label class="block text-lg font-bold text-gray-700 mb-3
|
154 |
-
<i class="fas fa-language text-indigo-600
|
155 |
</label>
|
156 |
<textarea id="sourceText" dir="rtl" class="w-full px-6 py-4 border-2 border-gray-200 rounded-xl focus:ring-indigo-200 focus:border-indigo-400 transition-all resize-none text-lg" rows="6" placeholder="اكتب النص المصدر هنا..."></textarea>
|
157 |
</div>
|
158 |
<!-- النص الهدف -->
|
159 |
<div class="group">
|
160 |
-
<label class="block text-lg font-bold text-gray-700 mb-3
|
161 |
-
<i class="fas fa-language text-pink-600
|
162 |
</label>
|
163 |
<textarea id="targetText" dir="ltr" class="w-full px-6 py-4 border-2 border-gray-200 rounded-xl focus:ring-pink-200 focus:border-pink-400 transition-all resize-none text-lg" rows="6" placeholder="اكتب النص الهدف هنا..."></textarea>
|
164 |
</div>
|
@@ -166,13 +169,13 @@
|
|
166 |
</div>
|
167 |
|
168 |
<!-- قسم المصادر الإضافية -->
|
169 |
-
<div class="
|
170 |
-
<h2 class="text-2xl font-bold
|
171 |
-
<i class="fas fa-book-open text-green-600
|
172 |
</h2>
|
173 |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
174 |
<!-- رفع ملف المصادر الإضافية -->
|
175 |
-
<div class="group border-2 border-dashed border-green-300 rounded-xl p-8 text-center hover:
|
176 |
<label class="cursor-pointer block">
|
177 |
<input type="file" id="sourceExtraFile" accept=".docx,.pdf" class="hidden">
|
178 |
<i class="fas fa-upload text-5xl text-green-500 mb-4"></i>
|
@@ -181,49 +184,47 @@
|
|
181 |
</div>
|
182 |
<!-- إدخال المصادر يدويًا -->
|
183 |
<div class="group">
|
184 |
-
<label class="block text-lg font-bold text-gray-700 mb-3
|
185 |
-
<i class="fas fa-edit text-green-600
|
186 |
</label>
|
187 |
<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>
|
188 |
</div>
|
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
|
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="
|
201 |
-
<h2 class="text-2xl font-bold
|
202 |
-
<i class="fas fa-search text-green-600
|
203 |
</h2>
|
204 |
<div id="errorsList" class="space-y-3 mb-6"></div>
|
205 |
-
<div class="
|
206 |
-
<!-- عرض النص المصدر بعد التحديد مع ترقيم السطور -->
|
207 |
<div>
|
208 |
-
<h4 class="text-lg font-bold text-gray-700 mb-3
|
209 |
-
<i class="fas fa-file-alt text-indigo-600
|
210 |
</h4>
|
211 |
<div id="sourceTextReview" class="bg-indigo-50 rounded-xl p-6 min-h-[200px] border-2 border-indigo-100 text-comparison"></div>
|
212 |
</div>
|
213 |
-
<!-- عرض النص الهدف بعد التحديد مع ترقيم السطور -->
|
214 |
<div>
|
215 |
-
<h4 class="text-lg font-bold text-gray-700 mb-3
|
216 |
-
<i class="fas fa-file-alt text-pink-600
|
217 |
</h4>
|
218 |
<div id="targetTextReview" class="bg-gray-50 rounded-xl p-6 min-h-[200px] border-2 border-gray-200 text-comparison"></div>
|
219 |
</div>
|
220 |
</div>
|
221 |
</div>
|
222 |
|
223 |
-
<!--
|
224 |
-
<div id="explanationBox" class="
|
225 |
-
<h2 class="text-2xl font-bold
|
226 |
-
<i class="fas fa-info-circle text-green-600
|
227 |
</h2>
|
228 |
<div id="explanationText" class="text-lg text-gray-700"></div>
|
229 |
</div>
|
@@ -231,78 +232,53 @@
|
|
231 |
</div>
|
232 |
|
233 |
<!-- ================================
|
234 |
-
جافا سكريبت: الوظائف
|
235 |
================================= -->
|
236 |
<script>
|
237 |
-
// إعدادات API
|
238 |
const API_URL = 'https://api.deepseek.com/chat/completions';
|
239 |
const API_KEY = 'sk-15606736ed9e4aea8b7cc11a195d2b01';
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
const ANALYSIS_PROMPT = `أنت خبير لغوي متخصص في مراجعة الترجمة التقنية. مهمتك مقارنة النص المصدر والنص الهدف بدقة عالية وتحليل النص كفقرات منفصلة مع التأكد من أن كل فقرة تنتهي بنقطة. النصوص مليئة بالأخطاء والنواقص.
|
251 |
-
لا تقم بإزالة أو تعديل العلامات التالية:
|
252 |
-
• الأرقام والتواريخ: تحافظ على علامات < و >.
|
253 |
-
• النصوص المفقودة: تحافظ على علامات __ و __.
|
254 |
-
• النصوص الزائدة: ضعها بين <<EXTRA>> و <<\/EXTRA>>.
|
255 |
-
• اختلافات المعنى: تحافظ على علامات [MEANING] و [/MEANING].
|
256 |
-
• علامات الشك أو الأخطاء البسيطة: ضعها بين [DOUBT] و [/DOUBT].
|
257 |
-
|
258 |
-
اعتمد النص المصدر كأساس للمقارنة، وقم بتحديد:
|
259 |
-
1. اختلافات الأرقام/التواريخ باستخدام <الرقم/التاريخ_في_المصدر> → <الرقم/التاريخ_في_الهدف>.
|
260 |
-
2. النصوص المفقودة كما هي بين علامتي __.
|
261 |
-
3. النصوص الزائدة كما هي بين <<EXTRA>> و <<\/EXTRA>>.
|
262 |
-
4. اختلافات المعنى باستخدام [MEANING] مع الحفاظ على التعليم.
|
263 |
-
5. علامات الشك أو الأخطاء البسيطة باستخدام [DOUBT] مع ضرورة مراجعة دقيقة لتفادي التظليل الوهمي.
|
264 |
|
265 |
النص المصدر:
|
266 |
{source}
|
267 |
|
268 |
النص الهدف:
|
269 |
{target}`;
|
270 |
-
|
271 |
-
|
272 |
-
دوال مساعدة للتعامل مع النصوص
|
273 |
-
===================================== */
|
274 |
-
// حساب عدد الكلمات في النص
|
275 |
function countWords(text) {
|
276 |
return text.trim().split(/\s+/).filter(word => word !== "").length;
|
277 |
}
|
278 |
-
// هروب أحرف Regex الخاصة
|
279 |
function escapeRegExp(string) {
|
280 |
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
281 |
}
|
282 |
-
// تقسيم النص إلى فقرات مع التأكد من انتهاء كل فقرة بنقطة وترقيمها
|
283 |
function splitIntoLines(text) {
|
284 |
return text.split(/\n+/).map((line, i) => {
|
285 |
line = line.trim();
|
286 |
-
if(line && !line.endsWith('.')) {
|
287 |
-
|
288 |
-
}
|
289 |
-
return `<div class="line-item"><span class="line-number">${i+1}:</span> <span class="line-text">${line}</span></div>`;
|
290 |
}).join('');
|
291 |
}
|
292 |
-
// الحصول على رقم السطر لظهور عبارة معينة
|
293 |
function getLineNumber(text, substring) {
|
294 |
const index = text.indexOf(substring);
|
295 |
if (index === -1) return "غير محدد";
|
296 |
return text.substring(0, index).split("\n").length;
|
297 |
}
|
298 |
-
|
299 |
-
|
300 |
-
دوال التمييز (Highlighting) للنتائج
|
301 |
-
===================================== */
|
302 |
function applyHighlights(originalText, analysisOutput) {
|
303 |
let highlightedText = originalText;
|
304 |
let match;
|
305 |
-
//
|
306 |
const numberRegex = /<([^<>]+)>/g;
|
307 |
while ((match = numberRegex.exec(analysisOutput)) !== null) {
|
308 |
const phrase = match[1].trim();
|
@@ -312,7 +288,7 @@
|
|
312 |
highlightedText = highlightedText.replace(phraseRegex, replacement);
|
313 |
}
|
314 |
}
|
315 |
-
//
|
316 |
const missingRegex = /__(.*?)__/g;
|
317 |
while ((match = missingRegex.exec(analysisOutput)) !== null) {
|
318 |
const phrase = match[1].trim();
|
@@ -322,7 +298,7 @@
|
|
322 |
highlightedText = highlightedText.replace(phraseRegex, replacement);
|
323 |
}
|
324 |
}
|
325 |
-
//
|
326 |
const extraRegex = /<<EXTRA>>(.*?)<<\/EXTRA>>/g;
|
327 |
while ((match = extraRegex.exec(analysisOutput)) !== null) {
|
328 |
const phrase = match[1].trim();
|
@@ -332,7 +308,7 @@
|
|
332 |
highlightedText = highlightedText.replace(phraseRegex, replacement);
|
333 |
}
|
334 |
}
|
335 |
-
//
|
336 |
const meaningRegex = /\[MEANING\](.*?)\[\/MEANING\]/g;
|
337 |
while ((match = meaningRegex.exec(analysisOutput)) !== null) {
|
338 |
const phrase = match[1].trim();
|
@@ -342,7 +318,7 @@
|
|
342 |
highlightedText = highlightedText.replace(phraseRegex, replacement);
|
343 |
}
|
344 |
}
|
345 |
-
//
|
346 |
const doubtRegex = /\[DOUBT\](.*?)\[\/DOUBT\]/g;
|
347 |
while ((match = doubtRegex.exec(analysisOutput)) !== null) {
|
348 |
const phrase = match[1].trim();
|
@@ -354,69 +330,64 @@
|
|
354 |
}
|
355 |
return highlightedText;
|
356 |
}
|
357 |
-
|
358 |
-
|
359 |
-
دالة توليد الشرح التفصيلي Organized Explanation
|
360 |
-
يتم تقسيم الشرح إلى خطوات منظمة
|
361 |
-
===================================== */
|
362 |
function generateExplanation(sourceText, analysisOutput) {
|
363 |
let steps = [];
|
364 |
let match;
|
365 |
-
|
|
|
|
|
|
|
|
|
|
|
366 |
const missingRegex = /__(.*?)__/g;
|
367 |
while ((match = missingRegex.exec(analysisOutput)) !== null) {
|
368 |
const phrase = match[1].trim();
|
369 |
if (phrase) {
|
370 |
const lineNum = getLineNumber(sourceText, phrase);
|
371 |
-
steps.push(`<li
|
372 |
}
|
373 |
}
|
374 |
-
// الخطوة 2: اختلافات الأرقام/التواريخ
|
375 |
const numberRegex = /<([^<>]+)>/g;
|
376 |
while ((match = numberRegex.exec(analysisOutput)) !== null) {
|
377 |
const phrase = match[1].trim();
|
378 |
if (phrase) {
|
379 |
const lineNum = getLineNumber(sourceText, phrase);
|
380 |
-
steps.push(`<li
|
381 |
}
|
382 |
}
|
383 |
-
// الخطوة 3: النصوص الزائدة
|
384 |
const extraRegex = /<<EXTRA>>(.*?)<<\/EXTRA>>/g;
|
385 |
while ((match = extraRegex.exec(analysisOutput)) !== null) {
|
386 |
const phrase = match[1].trim();
|
387 |
if (phrase) {
|
388 |
const lineNum = getLineNumber(sourceText, phrase);
|
389 |
-
steps.push(`<li
|
390 |
}
|
391 |
}
|
392 |
-
// الخطوة 4: اختلافات المعنى
|
393 |
const meaningRegex = /\[MEANING\](.*?)\[\/MEANING\]/g;
|
394 |
while ((match = meaningRegex.exec(analysisOutput)) !== null) {
|
395 |
const phrase = match[1].trim();
|
396 |
if (phrase) {
|
397 |
const lineNum = getLineNumber(sourceText, phrase);
|
398 |
-
steps.push(`<li
|
399 |
}
|
400 |
}
|
401 |
-
// الخطوة 5: علامات الشك أو الأخطاء البسيطة
|
402 |
const doubtRegex = /\[DOUBT\](.*?)\[\/DOUBT\]/g;
|
403 |
while ((match = doubtRegex.exec(analysisOutput)) !== null) {
|
404 |
const phrase = match[1].trim();
|
405 |
if (phrase) {
|
406 |
const lineNum = getLineNumber(sourceText, phrase);
|
407 |
-
steps.push(`<li
|
408 |
}
|
409 |
}
|
410 |
-
// إذا لم يكن هناك اختلافات
|
411 |
if (steps.length === 0) {
|
412 |
-
return `<p
|
413 |
}
|
414 |
return `<ol class="list-decimal ml-6 space-y-2">${steps.join('')}</ol>`;
|
415 |
}
|
416 |
-
|
417 |
-
|
418 |
-
دالة معالجة الملفات (PDF و DOCX)
|
419 |
-
===================================== */
|
420 |
async function processFile(file) {
|
421 |
let text = "";
|
422 |
if (file.type === 'application/pdf') {
|
@@ -438,11 +409,8 @@
|
|
438 |
}
|
439 |
return text;
|
440 |
}
|
441 |
-
|
442 |
-
|
443 |
-
دوال رفع الملفات وإدخال النصوص
|
444 |
-
===================================== */
|
445 |
-
// رفع ملف السورس
|
446 |
document.getElementById('sourceFile')?.addEventListener('change', async (event) => {
|
447 |
const file = event.target.files[0];
|
448 |
if (!file) return;
|
@@ -452,12 +420,11 @@
|
|
452 |
document.getElementById('sourceText').value = text;
|
453 |
} catch (error) {
|
454 |
console.error('Error processing source file:', error);
|
455 |
-
addError('خطأ في معالجة ملف
|
456 |
} finally {
|
457 |
document.getElementById('processStatus').classList.add('hidden');
|
458 |
}
|
459 |
});
|
460 |
-
// رفع ملف التارجت
|
461 |
document.getElementById('targetFile')?.addEventListener('change', async (event) => {
|
462 |
const file = event.target.files[0];
|
463 |
if (!file) return;
|
@@ -467,12 +434,11 @@
|
|
467 |
document.getElementById('targetText').value = text;
|
468 |
} catch (error) {
|
469 |
console.error('Error processing target file:', error);
|
470 |
-
addError('خطأ في معالجة ملف
|
471 |
} finally {
|
472 |
document.getElementById('processStatus').classList.add('hidden');
|
473 |
}
|
474 |
});
|
475 |
-
// رفع ملف المصادر الإضافية
|
476 |
document.getElementById('sourceExtraFile')?.addEventListener('change', async (event) => {
|
477 |
const file = event.target.files[0];
|
478 |
if (!file) return;
|
@@ -487,29 +453,24 @@
|
|
487 |
document.getElementById('processStatus').classList.add('hidden');
|
488 |
}
|
489 |
});
|
490 |
-
|
491 |
-
|
492 |
-
دالة عرض الأخطاء والرسائل
|
493 |
-
===================================== */
|
494 |
function addError(message, type = 'error') {
|
495 |
const errorsList = document.getElementById('errorsList');
|
496 |
if (!errorsList) return;
|
497 |
const errorDiv = document.createElement('div');
|
498 |
errorDiv.className = `p-4 rounded-xl ${type === 'error' ? 'bg-red-50 text-red-700' : 'bg-yellow-50 text-yellow-700'}`;
|
499 |
errorDiv.innerHTML = `<div class="flex items-center">
|
500 |
-
<i class="fas fa-${type === 'error' ? 'exclamation-circle' : 'info-circle'}
|
501 |
<span>${message}</span>
|
502 |
</div>`;
|
503 |
errorsList.appendChild(errorDiv);
|
504 |
}
|
505 |
-
|
506 |
-
|
507 |
-
معالجة عملية التحليل عند الضغط على الزر
|
508 |
-
===================================== */
|
509 |
document.getElementById('submitBtn').addEventListener('click', async () => {
|
510 |
const sourceText = document.getElementById('sourceText').value;
|
511 |
const targetText = document.getElementById('targetText').value;
|
512 |
-
// مسح الرسائل السابقة وإظهار النتائج
|
513 |
document.getElementById('errorsList').innerHTML = '';
|
514 |
document.getElementById('resultSection').classList.remove('hidden');
|
515 |
document.getElementById('explanationBox').classList.remove('hidden');
|
@@ -519,7 +480,6 @@
|
|
519 |
return;
|
520 |
}
|
521 |
|
522 |
-
// مقارنة عدد الكلمات وتنبيه إن وجد اختلاف
|
523 |
const sourceWordCount = countWords(sourceText);
|
524 |
const targetWordCount = countWords(targetText);
|
525 |
if (sourceWordCount !== targetWordCount) {
|
@@ -527,25 +487,22 @@
|
|
527 |
}
|
528 |
|
529 |
try {
|
530 |
-
// عرض مؤشر التقدم
|
531 |
const progressDiv = document.createElement('div');
|
532 |
progressDiv.className = "bg-indigo-100 p-4 rounded-xl mb-4";
|
533 |
progressDiv.innerHTML = `<div class="flex items-center">
|
534 |
-
<div class="animate-spin h-6 w-6 border-4 border-indigo-600 rounded-full border-t-transparent
|
535 |
<span>جارٍ التحليل...</span>
|
536 |
</div>`;
|
537 |
document.getElementById('errorsList').appendChild(progressDiv);
|
538 |
-
|
539 |
-
// بناء الـ prompt باستخدام النصين المُدخلين
|
540 |
const prompt = ANALYSIS_PROMPT
|
541 |
.replace("{source}", sourceText)
|
542 |
.replace("{target}", targetText);
|
543 |
|
544 |
-
// استدعاء DeepSeek API
|
545 |
const payload = {
|
546 |
model: "deepseek-chat",
|
547 |
messages: [
|
548 |
-
{ role: "system", content: "أنت خبير في تحليل النصوص
|
549 |
{ role: "user", content: prompt }
|
550 |
],
|
551 |
temperature: 0.3,
|
@@ -560,47 +517,41 @@
|
|
560 |
},
|
561 |
body: JSON.stringify(payload)
|
562 |
});
|
563 |
-
if (!response.ok) {
|
564 |
-
throw new Error('حدث خطأ بالشبكة: ' + response.statusText);
|
565 |
-
}
|
566 |
const data = await response.json();
|
567 |
const analysisOutput = data.choices[0].message.content.trim();
|
568 |
progressDiv.remove();
|
569 |
|
570 |
-
// إذا كانت النصوص متطابقة تمامًا
|
571 |
if (analysisOutput.includes('[MATCH]')) {
|
572 |
const checkDiv = document.createElement('div');
|
573 |
checkDiv.className = "p-4 rounded-xl bg-green-50 text-green-700 flex items-center";
|
574 |
-
checkDiv.innerHTML = `<i class="fas fa-check-circle
|
575 |
document.getElementById('errorsList').appendChild(checkDiv);
|
576 |
document.getElementById('sourceTextReview').innerHTML = splitIntoLines(sourceText);
|
577 |
document.getElementById('targetTextReview').innerHTML = splitIntoLines(targetText);
|
578 |
document.getElementById('explanationText').innerHTML = `<p>النصوص متطابقة ولا يوجد اختلاف يجب الإشارة إليه.</p>`;
|
579 |
} else {
|
580 |
-
// تطبيق التحديد على النصوص
|
581 |
const sourceHighlighted = applyHighlights(sourceText, analysisOutput);
|
582 |
const targetHighlighted = applyHighlights(targetText, analysisOutput);
|
583 |
document.getElementById('sourceTextReview').innerHTML = splitIntoLines(sourceHighlighted);
|
584 |
document.getElementById('targetTextReview').innerHTML = splitIntoLines(targetHighlighted);
|
585 |
-
// توليد شرح منظم على شكل خطوات
|
586 |
const explanationHTML = generateExplanation(sourceText, analysisOutput);
|
587 |
document.getElementById('explanationText').innerHTML = explanationHTML;
|
588 |
|
589 |
-
// عرض ملخص ��لاختلافات في الأسفل (اختياري)
|
590 |
const numDiffCount = (analysisOutput.match(/<([^<>]+)>/g) || []).length;
|
591 |
const missingDiffCount = (analysisOutput.match(/__(.*?)__/g) || []).length;
|
592 |
const extraDiffCount = (analysisOutput.match(/<<EXTRA>>(.*?)<<\/EXTRA>>/g) || []).length;
|
593 |
const meaningDiffCount = (analysisOutput.match(/\[MEANING\](.*?)\[\/MEANING\]/g) || []).length;
|
594 |
const doubtDiffCount = (analysisOutput.match(/\[DOUBT\](.*?)\[\/DOUBT\]/g) || []).length;
|
595 |
-
if (numDiffCount
|
596 |
const summaryDiv = document.createElement('div');
|
597 |
summaryDiv.className = "p-4 rounded-xl bg-yellow-50 text-gray-800";
|
598 |
-
let summaryText = '<div class="font-bold mb-2">ملخص الاختلافات:</div><ul class="list-disc
|
599 |
-
if (numDiffCount
|
600 |
-
if (missingDiffCount
|
601 |
-
if (extraDiffCount
|
602 |
-
if (meaningDiffCount
|
603 |
-
if (doubtDiffCount
|
604 |
summaryText += '</ul>';
|
605 |
summaryDiv.innerHTML = summaryText;
|
606 |
document.getElementById('errorsList').appendChild(summaryDiv);
|
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>نظام المقارنة والتحليل المتقدم - شركة موندو لينجوا</title>
|
7 |
<!-- استيراد مكتبات Tailwind وFont Awesome وMammoth -->
|
8 |
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
|
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%; }
|
|
|
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 {
|
|
|
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;
|
78 |
+
border-bottom: 1px dashed #ccc;
|
79 |
}
|
80 |
.line-number {
|
|
|
81 |
font-weight: bold;
|
82 |
color: #4B5563;
|
83 |
+
margin-left: 0.5rem;
|
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; }
|
102 |
</style>
|
103 |
</head>
|
104 |
<body class="bg-gradient-to-br from-gray-100 via-blue-100 to-indigo-100 min-h-screen">
|
105 |
<div class="min-h-screen pb-12">
|
106 |
+
<!-- رأس الصفحة -->
|
107 |
<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">
|
108 |
+
<div class="max-w-6xl mx-auto px-4 text-center">
|
109 |
+
<h1 class="text-5xl font-bold mb-4 animate-scale">
|
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>
|
117 |
|
118 |
+
<!-- المحتوى الرئيسي -->
|
119 |
+
<main class="max-w-6xl mx-auto px-4 space-y-8">
|
120 |
<!-- قسم رفع الملفات -->
|
121 |
+
<div class="card card-hover">
|
122 |
+
<h2 class="text-2xl font-bold text-gray-800 border-b pb-3 mb-6">
|
123 |
+
<i class="fas fa-file-upload icon text-indigo-600"></i> تحميل الملفات
|
124 |
</h2>
|
125 |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
126 |
+
<!-- ملف المصدر -->
|
127 |
+
<div class="group border-2 border-dashed border-indigo-300 rounded-xl p-8 text-center bg-indigo-50 hover:bg-indigo-100 transition-colors duration-300">
|
128 |
<label class="cursor-pointer block">
|
129 |
<input type="file" id="sourceFile" accept=".docx,.pdf" class="hidden">
|
130 |
+
<i class="fas fa-upload text-5xl text-indigo-500 mb-4"></i>
|
131 |
+
<span class="text-lg text-indigo-600 group-hover:text-indigo-700">ملف المصدر</span>
|
132 |
</label>
|
133 |
</div>
|
134 |
+
<!-- ملف الهدف -->
|
135 |
+
<div class="group border-2 border-dashed border-pink-300 rounded-xl p-8 text-center bg-pink-50 hover:bg-pink-100 transition-colors duration-300">
|
136 |
<label class="cursor-pointer block">
|
137 |
<input type="file" id="targetFile" accept=".docx,.pdf" class="hidden">
|
138 |
+
<i class="fas fa-download text-5xl text-pink-500 mb-4"></i>
|
139 |
+
<span class="text-lg text-pink-600 group-hover:text-pink-700">ملف الهدف</span>
|
140 |
</label>
|
141 |
</div>
|
142 |
</div>
|
|
|
149 |
</div>
|
150 |
|
151 |
<!-- قسم إدخال النصوص يدويًا -->
|
152 |
+
<div class="card card-hover">
|
153 |
<div class="space-y-6">
|
154 |
<!-- النص المصدر -->
|
155 |
<div class="group">
|
156 |
+
<label class="block text-lg font-bold text-gray-700 mb-3">
|
157 |
+
<i class="fas fa-language icon text-indigo-600"></i> النص المصدر
|
158 |
</label>
|
159 |
<textarea id="sourceText" dir="rtl" class="w-full px-6 py-4 border-2 border-gray-200 rounded-xl focus:ring-indigo-200 focus:border-indigo-400 transition-all resize-none text-lg" rows="6" placeholder="اكتب النص المصدر هنا..."></textarea>
|
160 |
</div>
|
161 |
<!-- النص الهدف -->
|
162 |
<div class="group">
|
163 |
+
<label class="block text-lg font-bold text-gray-700 mb-3">
|
164 |
+
<i class="fas fa-language icon text-pink-600"></i> النص الهدف
|
165 |
</label>
|
166 |
<textarea id="targetText" dir="ltr" class="w-full px-6 py-4 border-2 border-gray-200 rounded-xl focus:ring-pink-200 focus:border-pink-400 transition-all resize-none text-lg" rows="6" placeholder="اكتب النص الهدف هنا..."></textarea>
|
167 |
</div>
|
|
|
169 |
</div>
|
170 |
|
171 |
<!-- قسم المصادر الإضافية -->
|
172 |
+
<div class="card card-hover">
|
173 |
+
<h2 class="text-2xl font-bold text-gray-800 border-b pb-3 mb-6">
|
174 |
+
<i class="fas fa-book-open icon text-green-600"></i> مصادر إضافية
|
175 |
</h2>
|
176 |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
177 |
<!-- رفع ملف المصادر الإضافية -->
|
178 |
+
<div class="group border-2 border-dashed border-green-300 rounded-xl p-8 text-center bg-green-50 hover:bg-green-100 transition-colors duration-300">
|
179 |
<label class="cursor-pointer block">
|
180 |
<input type="file" id="sourceExtraFile" accept=".docx,.pdf" class="hidden">
|
181 |
<i class="fas fa-upload text-5xl text-green-500 mb-4"></i>
|
|
|
184 |
</div>
|
185 |
<!-- إدخال المصادر يدويًا -->
|
186 |
<div class="group">
|
187 |
+
<label class="block text-lg font-bold text-gray-700 mb-3">
|
188 |
+
<i class="fas fa-edit icon text-green-600"></i> إدخال المصادر يدويًا
|
189 |
</label>
|
190 |
<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>
|
191 |
</div>
|
192 |
</div>
|
193 |
</div>
|
194 |
|
195 |
+
<!-- زر التحليل والمراجعة -->
|
196 |
+
<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 pulse-animation">
|
197 |
<div class="flex items-center justify-center">
|
198 |
+
<i class="fas fa-sync-alt icon ml-2"></i> تحليل ومراجعة النصوص
|
199 |
</div>
|
200 |
</button>
|
201 |
|
202 |
+
<!-- نتائج التحليل -->
|
203 |
+
<div id="resultSection" class="card hidden">
|
204 |
+
<h2 class="text-2xl font-bold text-gray-800 border-b pb-3 mb-6">
|
205 |
+
<i class="fas fa-search icon text-green-600"></i> نتائج التحليل والمقارنة
|
206 |
</h2>
|
207 |
<div id="errorsList" class="space-y-3 mb-6"></div>
|
208 |
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
|
209 |
<div>
|
210 |
+
<h4 class="text-lg font-bold text-gray-700 mb-3">
|
211 |
+
<i class="fas fa-file-alt icon text-indigo-600"></i> النص المصدر (مع التعليم)
|
212 |
</h4>
|
213 |
<div id="sourceTextReview" class="bg-indigo-50 rounded-xl p-6 min-h-[200px] border-2 border-indigo-100 text-comparison"></div>
|
214 |
</div>
|
|
|
215 |
<div>
|
216 |
+
<h4 class="text-lg font-bold text-gray-700 mb-3">
|
217 |
+
<i class="fas fa-file-alt icon text-pink-600"></i> النص الهدف (مع التعليم)
|
218 |
</h4>
|
219 |
<div id="targetTextReview" class="bg-gray-50 rounded-xl p-6 min-h-[200px] border-2 border-gray-200 text-comparison"></div>
|
220 |
</div>
|
221 |
</div>
|
222 |
</div>
|
223 |
|
224 |
+
<!-- شرح تفصيلي للاختلافات -->
|
225 |
+
<div id="explanationBox" class="card hidden">
|
226 |
+
<h2 class="text-2xl font-bold text-gray-800 border-b pb-3 mb-6">
|
227 |
+
<i class="fas fa-info-circle icon text-green-600"></i> شرح الاختلافات
|
228 |
</h2>
|
229 |
<div id="explanationText" class="text-lg text-gray-700"></div>
|
230 |
</div>
|
|
|
232 |
</div>
|
233 |
|
234 |
<!-- ================================
|
235 |
+
جافا سكريبت: الوظائف والتحليل
|
236 |
================================= -->
|
237 |
<script>
|
|
|
238 |
const API_URL = 'https://api.deepseek.com/chat/completions';
|
239 |
const API_KEY = 'sk-15606736ed9e4aea8b7cc11a195d2b01';
|
240 |
+
const ANALYSIS_PROMPT = `أنت خبير لغوي وتقني متخصص في مراجعة الترجمة التقنية وتحليل النصوص بدقة. مهمتك مقارنة النص المصدر والنص الهدف واستخراج الاختلافات بدقة مع تحسين التظليل والتعليم.
|
241 |
+
تعليمات:
|
242 |
+
1. قم بتحليل النص إلى فقرات منفصلة، مع التأكد من انتهاء كل فقرة بنقطة.
|
243 |
+
2. لا تقم بتعديل العلامات التالية:
|
244 |
+
- الأرقام والتواريخ محاطة بـ < و >.
|
245 |
+
- النصوص المفقودة محاطة بـ __ و __.
|
246 |
+
- النصوص الزائدة محاطة بـ <<EXTRA>> و <<\/EXTRA>>.
|
247 |
+
- اختلافات المعنى محاطة بـ [MEANING] و [/MEANING].
|
248 |
+
- علامات الشك أو الأخطاء البسيطة محاطة بـ [DOUBT] و [/DOUBT].
|
249 |
+
3. يجب أن يقدم التحليل تعليمات دقيقة مع أيقونات توضيحية لكل نوع من الاختلافات.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
250 |
|
251 |
النص المصدر:
|
252 |
{source}
|
253 |
|
254 |
النص الهدف:
|
255 |
{target}`;
|
256 |
+
|
257 |
+
// دوال مساعدة
|
|
|
|
|
|
|
258 |
function countWords(text) {
|
259 |
return text.trim().split(/\s+/).filter(word => word !== "").length;
|
260 |
}
|
|
|
261 |
function escapeRegExp(string) {
|
262 |
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
263 |
}
|
|
|
264 |
function splitIntoLines(text) {
|
265 |
return text.split(/\n+/).map((line, i) => {
|
266 |
line = line.trim();
|
267 |
+
if(line && !line.endsWith('.')) { line += '.'; }
|
268 |
+
return `<div class="line-item"><span class="line-number">${i+1}:</span><span class="line-text">${line}</span></div>`;
|
|
|
|
|
269 |
}).join('');
|
270 |
}
|
|
|
271 |
function getLineNumber(text, substring) {
|
272 |
const index = text.indexOf(substring);
|
273 |
if (index === -1) return "غير محدد";
|
274 |
return text.substring(0, index).split("\n").length;
|
275 |
}
|
276 |
+
|
277 |
+
// دوال التظليل (Highlighting)
|
|
|
|
|
278 |
function applyHighlights(originalText, analysisOutput) {
|
279 |
let highlightedText = originalText;
|
280 |
let match;
|
281 |
+
// اختلافات الأرقام/التواريخ
|
282 |
const numberRegex = /<([^<>]+)>/g;
|
283 |
while ((match = numberRegex.exec(analysisOutput)) !== null) {
|
284 |
const phrase = match[1].trim();
|
|
|
288 |
highlightedText = highlightedText.replace(phraseRegex, replacement);
|
289 |
}
|
290 |
}
|
291 |
+
// النصوص المفقودة
|
292 |
const missingRegex = /__(.*?)__/g;
|
293 |
while ((match = missingRegex.exec(analysisOutput)) !== null) {
|
294 |
const phrase = match[1].trim();
|
|
|
298 |
highlightedText = highlightedText.replace(phraseRegex, replacement);
|
299 |
}
|
300 |
}
|
301 |
+
// النصوص الزائدة
|
302 |
const extraRegex = /<<EXTRA>>(.*?)<<\/EXTRA>>/g;
|
303 |
while ((match = extraRegex.exec(analysisOutput)) !== null) {
|
304 |
const phrase = match[1].trim();
|
|
|
308 |
highlightedText = highlightedText.replace(phraseRegex, replacement);
|
309 |
}
|
310 |
}
|
311 |
+
// اختلافات المعنى
|
312 |
const meaningRegex = /\[MEANING\](.*?)\[\/MEANING\]/g;
|
313 |
while ((match = meaningRegex.exec(analysisOutput)) !== null) {
|
314 |
const phrase = match[1].trim();
|
|
|
318 |
highlightedText = highlightedText.replace(phraseRegex, replacement);
|
319 |
}
|
320 |
}
|
321 |
+
// علامات الشك أو الأخطاء البسيطة
|
322 |
const doubtRegex = /\[DOUBT\](.*?)\[\/DOUBT\]/g;
|
323 |
while ((match = doubtRegex.exec(analysisOutput)) !== null) {
|
324 |
const phrase = match[1].trim();
|
|
|
330 |
}
|
331 |
return highlightedText;
|
332 |
}
|
333 |
+
|
334 |
+
// دالة توليد شرح تفصيلي للاختلافات مع أيقونات
|
|
|
|
|
|
|
335 |
function generateExplanation(sourceText, analysisOutput) {
|
336 |
let steps = [];
|
337 |
let match;
|
338 |
+
const iconMissing = `<i class="fas fa-exclamation-triangle text-red-500 mr-1"></i>`;
|
339 |
+
const iconNumber = `<i class="fas fa-hashtag text-yellow-600 mr-1"></i>`;
|
340 |
+
const iconExtra = `<i class="fas fa-plus-circle text-green-600 mr-1"></i>`;
|
341 |
+
const iconMeaning = `<i class="fas fa-info-circle text-blue-600 mr-1"></i>`;
|
342 |
+
const iconDoubt = `<i class="fas fa-question-circle text-indigo-600 mr-1"></i>`;
|
343 |
+
|
344 |
const missingRegex = /__(.*?)__/g;
|
345 |
while ((match = missingRegex.exec(analysisOutput)) !== null) {
|
346 |
const phrase = match[1].trim();
|
347 |
if (phrase) {
|
348 |
const lineNum = getLineNumber(sourceText, phrase);
|
349 |
+
steps.push(`<li>${iconMissing} في السطر ${lineNum}، النص المفقود: <span class="highlight-missing">__${phrase}__</span> غير موجود في النص الهدف.</li>`);
|
350 |
}
|
351 |
}
|
|
|
352 |
const numberRegex = /<([^<>]+)>/g;
|
353 |
while ((match = numberRegex.exec(analysisOutput)) !== null) {
|
354 |
const phrase = match[1].trim();
|
355 |
if (phrase) {
|
356 |
const lineNum = getLineNumber(sourceText, phrase);
|
357 |
+
steps.push(`<li>${iconNumber} في السطر ${lineNum}، الرقم/التاريخ: <span class="highlight-number">${phrase}</span> لا يتطابق بين المصدر والهدف.</li>`);
|
358 |
}
|
359 |
}
|
|
|
360 |
const extraRegex = /<<EXTRA>>(.*?)<<\/EXTRA>>/g;
|
361 |
while ((match = extraRegex.exec(analysisOutput)) !== null) {
|
362 |
const phrase = match[1].trim();
|
363 |
if (phrase) {
|
364 |
const lineNum = getLineNumber(sourceText, phrase);
|
365 |
+
steps.push(`<li>${iconExtra} في السطر ${lineNum}، النص الزائد: <span class="highlight-extra">${phrase}</span> موجود بشكل غير متوقع في النص الهدف.</li>`);
|
366 |
}
|
367 |
}
|
|
|
368 |
const meaningRegex = /\[MEANING\](.*?)\[\/MEANING\]/g;
|
369 |
while ((match = meaningRegex.exec(analysisOutput)) !== null) {
|
370 |
const phrase = match[1].trim();
|
371 |
if (phrase) {
|
372 |
const lineNum = getLineNumber(sourceText, phrase);
|
373 |
+
steps.push(`<li>${iconMeaning} في السطر ${lineNum}، اختلاف في المعنى: <span class="highlight-meaning">${phrase}</span> بين المصدر والهدف.</li>`);
|
374 |
}
|
375 |
}
|
|
|
376 |
const doubtRegex = /\[DOUBT\](.*?)\[\/DOUBT\]/g;
|
377 |
while ((match = doubtRegex.exec(analysisOutput)) !== null) {
|
378 |
const phrase = match[1].trim();
|
379 |
if (phrase) {
|
380 |
const lineNum = getLineNumber(sourceText, phrase);
|
381 |
+
steps.push(`<li>${iconDoubt} في السطر ${lineNum}، علامة شك: <span class="highlight-doubt">${phrase}</span> قد تشير إلى غموض أو خطأ بسيط يحتاج مراجعة.</li>`);
|
382 |
}
|
383 |
}
|
|
|
384 |
if (steps.length === 0) {
|
385 |
+
return `<p class="text-green-700"><i class="fas fa-check-circle mr-2"></i> لا توجد اختلافات ملحوظة بين النصين.</p>`;
|
386 |
}
|
387 |
return `<ol class="list-decimal ml-6 space-y-2">${steps.join('')}</ol>`;
|
388 |
}
|
389 |
+
|
390 |
+
// دالة معالجة الملفات (PDF و DOCX)
|
|
|
|
|
391 |
async function processFile(file) {
|
392 |
let text = "";
|
393 |
if (file.type === 'application/pdf') {
|
|
|
409 |
}
|
410 |
return text;
|
411 |
}
|
412 |
+
|
413 |
+
// رفع الملفات وإدخال النصوص
|
|
|
|
|
|
|
414 |
document.getElementById('sourceFile')?.addEventListener('change', async (event) => {
|
415 |
const file = event.target.files[0];
|
416 |
if (!file) return;
|
|
|
420 |
document.getElementById('sourceText').value = text;
|
421 |
} catch (error) {
|
422 |
console.error('Error processing source file:', error);
|
423 |
+
addError('خطأ في معالجة ملف المصدر');
|
424 |
} finally {
|
425 |
document.getElementById('processStatus').classList.add('hidden');
|
426 |
}
|
427 |
});
|
|
|
428 |
document.getElementById('targetFile')?.addEventListener('change', async (event) => {
|
429 |
const file = event.target.files[0];
|
430 |
if (!file) return;
|
|
|
434 |
document.getElementById('targetText').value = text;
|
435 |
} catch (error) {
|
436 |
console.error('Error processing target file:', error);
|
437 |
+
addError('خطأ في معالجة ملف الهدف');
|
438 |
} finally {
|
439 |
document.getElementById('processStatus').classList.add('hidden');
|
440 |
}
|
441 |
});
|
|
|
442 |
document.getElementById('sourceExtraFile')?.addEventListener('change', async (event) => {
|
443 |
const file = event.target.files[0];
|
444 |
if (!file) return;
|
|
|
453 |
document.getElementById('processStatus').classList.add('hidden');
|
454 |
}
|
455 |
});
|
456 |
+
|
457 |
+
// دالة عرض الأخطاء
|
|
|
|
|
458 |
function addError(message, type = 'error') {
|
459 |
const errorsList = document.getElementById('errorsList');
|
460 |
if (!errorsList) return;
|
461 |
const errorDiv = document.createElement('div');
|
462 |
errorDiv.className = `p-4 rounded-xl ${type === 'error' ? 'bg-red-50 text-red-700' : 'bg-yellow-50 text-yellow-700'}`;
|
463 |
errorDiv.innerHTML = `<div class="flex items-center">
|
464 |
+
<i class="fas fa-${type === 'error' ? 'exclamation-circle' : 'info-circle'} mr-2"></i>
|
465 |
<span>${message}</span>
|
466 |
</div>`;
|
467 |
errorsList.appendChild(errorDiv);
|
468 |
}
|
469 |
+
|
470 |
+
// معالجة عملية التحليل عند الضغط على الزر
|
|
|
|
|
471 |
document.getElementById('submitBtn').addEventListener('click', async () => {
|
472 |
const sourceText = document.getElementById('sourceText').value;
|
473 |
const targetText = document.getElementById('targetText').value;
|
|
|
474 |
document.getElementById('errorsList').innerHTML = '';
|
475 |
document.getElementById('resultSection').classList.remove('hidden');
|
476 |
document.getElementById('explanationBox').classList.remove('hidden');
|
|
|
480 |
return;
|
481 |
}
|
482 |
|
|
|
483 |
const sourceWordCount = countWords(sourceText);
|
484 |
const targetWordCount = countWords(targetText);
|
485 |
if (sourceWordCount !== targetWordCount) {
|
|
|
487 |
}
|
488 |
|
489 |
try {
|
|
|
490 |
const progressDiv = document.createElement('div');
|
491 |
progressDiv.className = "bg-indigo-100 p-4 rounded-xl mb-4";
|
492 |
progressDiv.innerHTML = `<div class="flex items-center">
|
493 |
+
<div class="animate-spin h-6 w-6 border-4 border-indigo-600 rounded-full border-t-transparent mr-3"></div>
|
494 |
<span>جارٍ التحليل...</span>
|
495 |
</div>`;
|
496 |
document.getElementById('errorsList').appendChild(progressDiv);
|
497 |
+
|
|
|
498 |
const prompt = ANALYSIS_PROMPT
|
499 |
.replace("{source}", sourceText)
|
500 |
.replace("{target}", targetText);
|
501 |
|
|
|
502 |
const payload = {
|
503 |
model: "deepseek-chat",
|
504 |
messages: [
|
505 |
+
{ role: "system", content: "أنت خبير في تحليل ومراجعة النصوص بدقة عالية." },
|
506 |
{ role: "user", content: prompt }
|
507 |
],
|
508 |
temperature: 0.3,
|
|
|
517 |
},
|
518 |
body: JSON.stringify(payload)
|
519 |
});
|
520 |
+
if (!response.ok) { throw new Error('حدث خطأ بالشبكة: ' + response.statusText); }
|
|
|
|
|
521 |
const data = await response.json();
|
522 |
const analysisOutput = data.choices[0].message.content.trim();
|
523 |
progressDiv.remove();
|
524 |
|
|
|
525 |
if (analysisOutput.includes('[MATCH]')) {
|
526 |
const checkDiv = document.createElement('div');
|
527 |
checkDiv.className = "p-4 rounded-xl bg-green-50 text-green-700 flex items-center";
|
528 |
+
checkDiv.innerHTML = `<i class="fas fa-check-circle mr-2"></i> <span>النصوص متطابقة تماماً</span>`;
|
529 |
document.getElementById('errorsList').appendChild(checkDiv);
|
530 |
document.getElementById('sourceTextReview').innerHTML = splitIntoLines(sourceText);
|
531 |
document.getElementById('targetTextReview').innerHTML = splitIntoLines(targetText);
|
532 |
document.getElementById('explanationText').innerHTML = `<p>النصوص متطابقة ولا يوجد اختلاف يجب الإشارة إليه.</p>`;
|
533 |
} else {
|
|
|
534 |
const sourceHighlighted = applyHighlights(sourceText, analysisOutput);
|
535 |
const targetHighlighted = applyHighlights(targetText, analysisOutput);
|
536 |
document.getElementById('sourceTextReview').innerHTML = splitIntoLines(sourceHighlighted);
|
537 |
document.getElementById('targetTextReview').innerHTML = splitIntoLines(targetHighlighted);
|
|
|
538 |
const explanationHTML = generateExplanation(sourceText, analysisOutput);
|
539 |
document.getElementById('explanationText').innerHTML = explanationHTML;
|
540 |
|
|
|
541 |
const numDiffCount = (analysisOutput.match(/<([^<>]+)>/g) || []).length;
|
542 |
const missingDiffCount = (analysisOutput.match(/__(.*?)__/g) || []).length;
|
543 |
const extraDiffCount = (analysisOutput.match(/<<EXTRA>>(.*?)<<\/EXTRA>>/g) || []).length;
|
544 |
const meaningDiffCount = (analysisOutput.match(/\[MEANING\](.*?)\[\/MEANING\]/g) || []).length;
|
545 |
const doubtDiffCount = (analysisOutput.match(/\[DOUBT\](.*?)\[\/DOUBT\]/g) || []).length;
|
546 |
+
if (numDiffCount || missingDiffCount || extraDiffCount || meaningDiffCount || doubtDiffCount) {
|
547 |
const summaryDiv = document.createElement('div');
|
548 |
summaryDiv.className = "p-4 rounded-xl bg-yellow-50 text-gray-800";
|
549 |
+
let summaryText = '<div class="font-bold mb-2">ملخص الاختلافات:</div><ul class="list-disc ml-4 space-y-1">';
|
550 |
+
if (numDiffCount) summaryText += `<li>اختلاف في الأرقام/التواريخ: ${numDiffCount}</li>`;
|
551 |
+
if (missingDiffCount) summaryText += `<li>النصوص المفقودة: ${missingDiffCount}</li>`;
|
552 |
+
if (extraDiffCount) summaryText += `<li>النصوص الزائدة: ${extraDiffCount}</li>`;
|
553 |
+
if (meaningDiffCount) summaryText += `<li>اختلاف في المعنى: ${meaningDiffCount}</li>`;
|
554 |
+
if (doubtDiffCount) summaryText += `<li>علامات الشك: ${doubtDiffCount}</li>`;
|
555 |
summaryText += '</ul>';
|
556 |
summaryDiv.innerHTML = summaryText;
|
557 |
document.getElementById('errorsList').appendChild(summaryDiv);
|