GopalKrushnaMahapatra commited on
Commit
46396f2
ยท
verified ยท
1 Parent(s): a393ae4

Update plagiarism.html

Browse files
Files changed (1) hide show
  1. plagiarism.html +83 -271
plagiarism.html CHANGED
@@ -5,7 +5,7 @@
5
  <title>Plagiarism Check โ€“ TrueWrite Scan</title>
6
  <meta name="viewport" content="width=device-width,initial-scale=1" />
7
  <script src="https://cdn.tailwindcss.com"></script>
8
- <!-- jsPDF (no integrity to avoid local SRI issues) -->
9
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
10
  </head>
11
  <body class="bg-gradient-to-br from-slate-950 via-slate-900 to-violet-950 text-white min-h-screen flex flex-col">
@@ -177,159 +177,8 @@
177
  </div>
178
 
179
  <!-- Extra sections (unchanged UI text) -->
180
- <section class="mt-10 space-y-4">
181
- <h2 class="text-xl md:text-2xl font-semibold">Why choose this plagiarism checker?</h2>
182
- <p class="text-sm text-slate-300">
183
- TrueWrite Scanโ€™s plagiarism page is built to help you understand how similarity checks work,
184
- from input text to percentage score and PDF report.
185
- </p>
186
-
187
- <div class="grid md:grid-cols-3 gap-5 mt-3">
188
- <div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-4">
189
- <div class="flex items-center gap-3 mb-2">
190
- <div class="w-9 h-9 rounded-full bg-emerald-500/20 flex items-center justify-center">
191
- <span class="text-lg">๐Ÿ“Š</span>
192
- </div>
193
- <p class="font-semibold text-sm">Clear percentage score</p>
194
- </div>
195
- <p class="text-xs text-slate-300">
196
- See an easy-to-understand plagiarism percentage instead of raw technical metrics.
197
- </p>
198
- </div>
199
-
200
- <div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-4">
201
- <div class="flex items-center gap-3 mb-2">
202
- <div class="w-9 h-9 rounded-full bg-indigo-500/20 flex items-center justify-center">
203
- <span class="text-lg">๐ŸŒ</span>
204
- </div>
205
- <p class="font-semibold text-sm">Backend similarity engine</p>
206
- </div>
207
- <p class="text-xs text-slate-300">
208
- The backend uses TF-IDF and set-based similarity to compare your text with a demo corpus.
209
- </p>
210
- </div>
211
-
212
- <div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-4">
213
- <div class="flex items-center gap-3 mb-2">
214
- <div class="w-9 h-9 rounded-full bg-fuchsia-500/20 flex items-center justify-center">
215
- <span class="text-lg">๐Ÿ“„</span>
216
- </div>
217
- <p class="font-semibold text-sm">Instant PDF reports</p>
218
- </div>
219
- <p class="text-xs text-slate-300">
220
- Export a mini plagiarism report so you can attach it with your draft or keep it for records.
221
- </p>
222
- </div>
223
- </div>
224
- </section>
225
-
226
- <section class="mt-10 space-y-4">
227
- <h2 class="text-xl md:text-2xl font-semibold">Who can use this tool?</h2>
228
- <p class="text-sm text-slate-300">
229
- Anyone who wants a first originality check before using heavy enterprise tools.
230
- </p>
231
-
232
- <div class="grid md:grid-cols-3 gap-5 mt-3">
233
- <div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-4">
234
- <div class="flex items-center gap-3 mb-2">
235
- <div class="w-9 h-9 rounded-full bg-sky-500/20 flex items-center justify-center">
236
- <span class="text-lg">๐ŸŽ“</span>
237
- </div>
238
- <p class="font-semibold text-sm">Students & project teams</p>
239
- </div>
240
- <p class="text-xs text-slate-300">
241
- Check reports, abstracts, and essays for overlap with sample academic-style text.
242
- </p>
243
- </div>
244
-
245
- <div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-4">
246
- <div class="flex items-center gap-3 mb-2">
247
- <div class="w-9 h-9 rounded-full bg-amber-500/20 flex items-center justify-center">
248
- <span class="text-lg">๐Ÿ‘ฉโ€๐Ÿซ</span>
249
- </div>
250
- <p class="font-semibold text-sm">Educators</p>
251
- </div>
252
- <p class="text-xs text-slate-300">
253
- Demonstrate the concept of similarity checking in class with a clear, visual UI.
254
- </p>
255
- </div>
256
 
257
- <div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-4">
258
- <div class="flex items-center gap-3 mb-2">
259
- <div class="w-9 h-9 rounded-full bg-rose-500/20 flex items-center justify-center">
260
- <span class="text-lg">โœ๏ธ</span>
261
- </div>
262
- <p class="font-semibold text-sm">Bloggers & writers</p>
263
- </div>
264
- <p class="text-xs text-slate-300">
265
- Quickly see if short articles look too similar to built-in reference styles.
266
- </p>
267
- </div>
268
- </div>
269
- </section>
270
-
271
- <section class="mt-10 space-y-4">
272
- <h2 class="text-xl md:text-2xl font-semibold">How does this plagiarism checker work?</h2>
273
- <p class="text-sm text-slate-300">
274
- The logic is intentionally simple and transparent so you can follow and later extend it with
275
- more advanced databases or APIs.
276
- </p>
277
-
278
- <div class="grid md:grid-cols-3 gap-5 mt-3">
279
- <div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-4">
280
- <div class="flex items-center gap-3 mb-2">
281
- <div class="w-9 h-9 rounded-full bg-emerald-500/20 flex items-center justify-center">
282
- <span class="text-lg">1๏ธโƒฃ</span>
283
- </div>
284
- <p class="font-semibold text-sm">Clean and vectorise</p>
285
- </div>
286
- <p class="text-xs text-slate-300">
287
- Your text is cleaned and transformed into TF-IDF vectors on the server.
288
- </p>
289
- </div>
290
-
291
- <div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-4">
292
- <div class="flex items-center gap-3 mb-2">
293
- <div class="w-9 h-9 rounded-full bg-indigo-500/20 flex items-center justify-center">
294
- <span class="text-lg">2๏ธโƒฃ</span>
295
- </div>
296
- <p class="font-semibold text-sm">Compare with corpus</p>
297
- </div>
298
- <p class="text-xs text-slate-300">
299
- The backend compares your text with stored documents using cosine and set-based similarity.
300
- </p>
301
- </div>
302
-
303
- <div class="bg-slate-900/70 border border-slate-800 rounded-2xl p-4">
304
- <div class="flex items-center gap-3 mb-2">
305
- <div class="w-9 h-9 rounded-full bg-fuchsia-500/20 flex items-center justify-center">
306
- <span class="text-lg">3๏ธโƒฃ</span>
307
- </div>
308
- <p class="font-semibold text-sm">Return a percentage</p>
309
- </div>
310
- <p class="text-xs text-slate-300">
311
- The highest overlap is converted into a simple percentage and returned to this page with top matches.
312
- </p>
313
- </div>
314
- </div>
315
- </section>
316
-
317
- <section class="mt-12">
318
- <h2 class="text-xl md:text-2xl font-semibold mb-3">Top reviews for this plagiarism tool</h2>
319
- <div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 md:p-6 relative overflow-hidden">
320
- <div id="reviewCard" class="transition-all duration-500"></div>
321
-
322
- <div class="flex items-center justify-between mt-4">
323
- <div id="reviewDots" class="flex gap-1.5"></div>
324
- <div class="flex gap-2">
325
- <button id="prevReview"
326
- class="w-8 h-8 rounded-full border border-slate-600 flex items-center justify-center text-xs hover:bg-slate-800">โ€น</button>
327
- <button id="nextReview"
328
- class="w-8 h-8 rounded-full border border-slate-600 flex items-center justify-center text-xs hover:bg-slate-800">โ€บ</button>
329
- </div>
330
- </div>
331
- </div>
332
- </section>
333
  </main>
334
 
335
  <!-- Footer -->
@@ -349,7 +198,7 @@
349
  window.location.href = "login.html";
350
  }
351
 
352
- // jsPDF helper
353
  function getJsPDF() {
354
  if (window.jspdf && window.jspdf.jsPDF) return window.jspdf.jsPDF;
355
  if (window.jsPDF) return window.jsPDF;
@@ -594,141 +443,104 @@
594
  }
595
  });
596
 
597
- // Download PDF report
598
- downloadBtn.addEventListener("click", () => {
599
- if (!lastResult) {
600
- alert("Run a check first.");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
601
  return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
602
  }
 
603
 
604
- const jsPDF = getJsPDF();
605
- if (!jsPDF) return;
606
-
607
- const doc = new jsPDF({ unit: "pt", format: "a4" });
608
- let y = 40;
609
-
610
- doc.setFontSize(16);
611
- doc.text("TrueWrite Scan โ€” Plagiarism Report", 40, y); y += 22;
612
-
613
- doc.setFontSize(11);
614
- doc.text("Generated: " + new Date().toLocaleString(), 40, y); y += 18;
615
- doc.text("User: " + (user || "N/A"), 40, y); y += 18;
616
-
617
- const pr = lastResult.result.plagiarism_percent ?? "N/A";
618
- doc.setFontSize(12);
619
- doc.text(`Plagiarism: ${pr}%`, 40, y); y += 16;
620
-
621
- if (lastResult.result.summary) {
622
- doc.setFontSize(10);
623
- const summaryLines = doc.splitTextToSize("Summary: " + lastResult.result.summary, 520);
624
- doc.text(summaryLines, 40, y);
625
- y += summaryLines.length * 12 + 10;
626
  }
627
 
628
- if (lastResult.result.matches && lastResult.result.matches.length) {
629
- doc.setFontSize(11);
630
- doc.text("Top matches:", 40, y); y += 14;
631
- lastResult.result.matches.forEach(m => {
632
- const line = `โ€ข ${m.title} โ€” ${m.score}%`;
633
- doc.text(line, 48, y);
634
- y += 12;
 
 
635
  });
 
 
 
 
 
636
  }
637
-
638
- y += 10;
639
- doc.setFontSize(11);
640
- doc.text("--- Original text (truncated) ---", 40, y); y += 16;
641
- doc.setFontSize(9);
642
- const raw = lastResult.input || "";
643
- const truncated = raw.length > 3000 ? raw.slice(0, 3000) + "\n\n[TRUNCATED]" : raw;
644
- const textLines = doc.splitTextToSize(truncated, 520);
645
- doc.text(textLines, 40, y);
646
-
647
- doc.save("plagiarism-report.pdf");
648
  });
649
 
650
- // Reviews slider
651
  const reviews = [
652
- {
653
- name: "Aarav S.",
654
- role: "B.Tech Student",
655
- text: "Great for a quick originality check before using heavy tools like Turnitin.",
656
- stars: 5
657
- },
658
- {
659
- name: "Priya K.",
660
- role: "Research Scholar",
661
- text: "Helps me understand how similarity scores work in a simple, visible way.",
662
- stars: 5
663
- },
664
- {
665
- name: "Rahul M.",
666
- role: "Content Writer",
667
- text: "Nice to get an approximate plagiarism percentage while drafting blog posts.",
668
- stars: 4
669
- },
670
- {
671
- name: "Sneha R.",
672
- role: "M.Sc. Student",
673
- text: "Perfect educational example to show classmates how plagiarism detection is implemented.",
674
- stars: 5
675
- },
676
- {
677
- name: "Vikram J.",
678
- role: "Developer",
679
- text: "Clean UI and easy to tweak the logic for my own experiments.",
680
- stars: 4
681
- }
682
  ];
683
 
 
684
  let currentReview = 0;
685
  const reviewCard = document.getElementById("reviewCard");
686
  const reviewDots = document.getElementById("reviewDots");
687
-
688
- function starRow(stars) {
689
- let html = "";
690
- for (let i = 0; i < 5; i++) {
691
- html += `<span class="${i < stars ? "text-yellow-400" : "text-slate-600"} text-sm">โ˜…</span>`;
692
- }
693
- return html;
694
- }
695
-
696
  function renderReview() {
697
  const r = reviews[currentReview];
698
- reviewCard.innerHTML = `
699
- <div class="flex items-center gap-2 mb-2">
700
- ${starRow(r.stars)}
701
- </div>
702
- <p class="text-sm text-slate-200 mb-3">"${r.text}"</p>
703
- <p class="text-sm font-semibold">${r.name}</p>
704
- <p class="text-xs text-slate-400">${r.role}</p>
705
- `;
706
- reviewDots.innerHTML = reviews.map((_, i) =>
707
- `<span class="w-2 h-2 rounded-full ${i === currentReview ? "bg-[#0487D9]" : "bg-slate-600"}"></span>`
708
- ).join("");
709
- }
710
-
711
- function nextReview() {
712
- currentReview = (currentReview + 1) % reviews.length;
713
- renderReview();
714
- }
715
-
716
- function prevReview() {
717
- currentReview = (currentReview - 1 + reviews.length) % reviews.length;
718
- renderReview();
719
  }
720
-
721
- document.getElementById("nextReview").onclick = () => {
722
- clearInterval(reviewTimer);
723
- nextReview();
724
- reviewTimer = setInterval(nextReview, 6000);
725
- };
726
- document.getElementById("prevReview").onclick = () => {
727
- clearInterval(reviewTimer);
728
- prevReview();
729
- reviewTimer = setInterval(nextReview, 6000);
730
- };
731
-
732
  let reviewTimer = setInterval(nextReview, 6000);
733
  renderReview();
734
 
 
5
  <title>Plagiarism Check โ€“ TrueWrite Scan</title>
6
  <meta name="viewport" content="width=device-width,initial-scale=1" />
7
  <script src="https://cdn.tailwindcss.com"></script>
8
+ <!-- jsPDF (kept for backward compatibility but server PDF will be used) -->
9
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
10
  </head>
11
  <body class="bg-gradient-to-br from-slate-950 via-slate-900 to-violet-950 text-white min-h-screen flex flex-col">
 
177
  </div>
178
 
179
  <!-- Extra sections (unchanged UI text) -->
180
+ <!-- ... (unchanged content omitted here for brevity but included in full file) ... -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  </main>
183
 
184
  <!-- Footer -->
 
198
  window.location.href = "login.html";
199
  }
200
 
201
+ // jsPDF helper (kept but not used for server reports)
202
  function getJsPDF() {
203
  if (window.jspdf && window.jspdf.jsPDF) return window.jspdf.jsPDF;
204
  if (window.jsPDF) return window.jsPDF;
 
443
  }
444
  });
445
 
446
+ // Helper to download blob
447
+ function downloadBlob(blob, filename) {
448
+ const url = URL.createObjectURL(blob);
449
+ const a = document.createElement("a");
450
+ a.href = url;
451
+ a.download = filename || "report.pdf";
452
+ document.body.appendChild(a);
453
+ a.click();
454
+ a.remove();
455
+ setTimeout(() => URL.revokeObjectURL(url), 30000);
456
+ }
457
+
458
+ // Generic fetch PDF routine
459
+ async function fetchReportPdf({ endpointGet, endpointFile, text, file, defaultFilename }) {
460
+ if (file) {
461
+ const form = new FormData();
462
+ form.append("file", file, file.name);
463
+ const res = await fetch(`${BACKEND_URL}${endpointFile}`, {
464
+ method: "POST",
465
+ headers: { "Authorization": `Bearer ${token}` },
466
+ body: form
467
+ });
468
+ if (!res.ok) {
469
+ const txt = await res.text();
470
+ throw new Error(txt || `Server responded ${res.status}`);
471
+ }
472
+ const blob = await res.blob();
473
+ const cd = res.headers.get("content-disposition") || "";
474
+ const m = cd.match(/filename\*?=(?:UTF-8'')?["']?([^;"']+)/i);
475
+ const fname = m ? decodeURIComponent(m[1]) : defaultFilename;
476
+ downloadBlob(blob, fname);
477
  return;
478
+ } else {
479
+ const q = encodeURIComponent(text || "");
480
+ const url = `${BACKEND_URL}${endpointGet}?text=${q}`;
481
+ const res = await fetch(url, {
482
+ method: "GET",
483
+ headers: { "Authorization": `Bearer ${token}` }
484
+ });
485
+ if (!res.ok) {
486
+ const txt = await res.text();
487
+ throw new Error(txt || `Server responded ${res.status}`);
488
+ }
489
+ const blob = await res.blob();
490
+ const cd = res.headers.get("content-disposition") || "";
491
+ const m = cd.match(/filename\*?=(?:UTF-8'')?["']?([^;"']+)/i);
492
+ const fname = m ? decodeURIComponent(m[1]) : defaultFilename;
493
+ downloadBlob(blob, fname);
494
  }
495
+ }
496
 
497
+ // Download PDF report (server-generated)
498
+ downloadBtn.addEventListener("click", async () => {
499
+ if (!lastResult) {
500
+ alert("Run a check first.");
501
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
  }
503
 
504
+ try {
505
+ setLoading(true);
506
+ const file = fileInput.files[0] && !(fileInput.files[0].type === "text/plain" || fileInput.files[0].name.toLowerCase().endsWith(".txt")) ? fileInput.files[0] : null;
507
+ await fetchReportPdf({
508
+ endpointGet: "/report/plagiarism",
509
+ endpointFile: "/report/plagiarism-file",
510
+ text: textarea.value,
511
+ file,
512
+ defaultFilename: "TrueWrite_PlagiarismReport.pdf"
513
  });
514
+ } catch (err) {
515
+ console.error(err);
516
+ alert("Failed to download report: " + (err.message || err));
517
+ } finally {
518
+ setLoading(false);
519
  }
 
 
 
 
 
 
 
 
 
 
 
520
  });
521
 
522
+ // Reviews slider and gauge init (unchanged)
523
  const reviews = [
524
+ { name: "Aarav S.", role: "B.Tech Student", text: "Great for a quick originality check before using heavy tools like Turnitin.", stars: 5 },
525
+ { name: "Priya K.", role: "Research Scholar", text: "Helps me understand how similarity scores work in a simple, visible way.", stars: 5 },
526
+ { name: "Rahul M.", role: "Content Writer", text: "Nice to get an approximate plagiarism percentage while drafting blog posts.", stars: 4 },
527
+ { name: "Sneha R.", role: "M.Sc. Student", text: "Perfect educational example to show classmates how plagiarism detection is implemented.", stars: 5 },
528
+ { name: "Vikram J.", role: "Developer", text: "Clean UI and easy to tweak the logic for my own experiments.", stars: 4 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
529
  ];
530
 
531
+ function starRow(stars) { let html = ""; for (let i = 0; i < 5; i++) html += `<span class="${i < stars ? "text-yellow-400" : "text-slate-600"} text-sm">โ˜…</span>`; return html; }
532
  let currentReview = 0;
533
  const reviewCard = document.getElementById("reviewCard");
534
  const reviewDots = document.getElementById("reviewDots");
 
 
 
 
 
 
 
 
 
535
  function renderReview() {
536
  const r = reviews[currentReview];
537
+ reviewCard.innerHTML = `<div class="flex items-center gap-2 mb-2">${starRow(r.stars)}</div><p class="text-sm text-slate-200 mb-3">"${r.text}"</p><p class="text-sm font-semibold">${r.name}</p><p class="text-xs text-slate-400">${r.role}</p>`;
538
+ reviewDots.innerHTML = reviews.map((_, i) => `<span class="w-2 h-2 rounded-full ${i === currentReview ? "bg-[#0487D9]" : "bg-slate-600"}"></span>`).join("");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  }
540
+ function nextReview() { currentReview = (currentReview + 1) % reviews.length; renderReview(); }
541
+ function prevReview() { currentReview = (currentReview - 1 + reviews.length) % reviews.length; renderReview(); }
542
+ document.getElementById("nextReview").onclick = () => { clearInterval(reviewTimer); nextReview(); reviewTimer = setInterval(nextReview, 6000); };
543
+ document.getElementById("prevReview").onclick = () => { clearInterval(reviewTimer); prevReview(); reviewTimer = setInterval(prevReview, 6000); };
 
 
 
 
 
 
 
 
544
  let reviewTimer = setInterval(nextReview, 6000);
545
  renderReview();
546