Spaces:
Sleeping
Sleeping
Upload index.html
Browse files- templates/index.html +84 -107
templates/index.html
CHANGED
|
@@ -176,24 +176,20 @@ body { padding-bottom: 240px; } /* add this */
|
|
| 176 |
|
| 177 |
<div class="container">
|
| 178 |
<!-- Upload card -->
|
| 179 |
-
<section class="card panel">
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
<
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
<
|
| 192 |
-
|
| 193 |
-
<a id="downloadOutput" href="#" style="display:none; margin-left:16px;">Download output file</a>
|
| 194 |
-
</form>
|
| 195 |
-
</section>
|
| 196 |
-
|
| 197 |
|
| 198 |
<!-- Tabs toolbar -->
|
| 199 |
<div class="tabs toolbar card">
|
|
@@ -380,85 +376,13 @@ async function autoGenerateTTSFromNY() {
|
|
| 380 |
document.getElementById("generateApiTTS").addEventListener("click", autoGenerateTTSFromNY);
|
| 381 |
|
| 382 |
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
document.getElementById("editBtn").addEventListener("click", () => {
|
| 386 |
-
// Choose which editor to focus; keep your existing logic if you like
|
| 387 |
-
const isFinal = document.getElementById("finalTextTab").style.display === "block";
|
| 388 |
-
const targetId = isFinal ? "finalText" : "fullText";
|
| 389 |
-
const div = document.getElementById(targetId);
|
| 390 |
-
if (div) div.focus();
|
| 391 |
-
});
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
const selectedFiles = []; // array of File objects
|
| 401 |
-
|
| 402 |
-
function renderSelectedList() {
|
| 403 |
-
const ul = document.getElementById("selectedList");
|
| 404 |
-
ul.innerHTML = "";
|
| 405 |
-
selectedFiles.forEach((f, i) => {
|
| 406 |
-
const li = document.createElement("li");
|
| 407 |
-
li.style.margin = "4px 0";
|
| 408 |
-
li.textContent = `${f.name} (${(f.size/1024).toFixed(1)} KB)`;
|
| 409 |
-
ul.appendChild(li);
|
| 410 |
-
});
|
| 411 |
-
|
| 412 |
-
// Legacy "single file" label support (optional)
|
| 413 |
-
const fileEl = document.querySelector("#dropZone .dz-file");
|
| 414 |
-
const labelEl = document.querySelector("#dropZone .dz-label");
|
| 415 |
-
if (selectedFiles.length) {
|
| 416 |
-
if (fileEl) { fileEl.style.display = "block"; fileEl.textContent = `${selectedFiles.length} file(s) ready`; }
|
| 417 |
-
if (labelEl) labelEl.textContent = "Ready:";
|
| 418 |
-
} else {
|
| 419 |
-
if (fileEl) { fileEl.style.display = "none"; fileEl.textContent = ""; }
|
| 420 |
-
if (labelEl) labelEl.textContent = "Drop PDFs here or click to choose";
|
| 421 |
-
}
|
| 422 |
-
}
|
| 423 |
-
|
| 424 |
-
function addFiles(list) {
|
| 425 |
-
const pdfs = Array.from(list).filter(f =>
|
| 426 |
-
f.type === "application/pdf" || f.name.toLowerCase().endsWith(".pdf")
|
| 427 |
-
);
|
| 428 |
-
// Prevent exact duplicates (same name+size)
|
| 429 |
-
const key = f => `${f.name}|${f.size}`;
|
| 430 |
-
const existing = new Set(selectedFiles.map(key));
|
| 431 |
-
pdfs.forEach(f => {
|
| 432 |
-
if (!existing.has(key(f))) selectedFiles.push(f);
|
| 433 |
-
});
|
| 434 |
-
renderSelectedList();
|
| 435 |
-
}
|
| 436 |
-
|
| 437 |
-
// --- Wire up form ---
|
| 438 |
-
document.getElementById("addAnother").addEventListener("click", () => {
|
| 439 |
-
document.getElementById("pdfUpload").click();
|
| 440 |
-
});
|
| 441 |
-
|
| 442 |
-
document.getElementById("pdfUpload").addEventListener("change", (e) => {
|
| 443 |
-
if (e.target.files?.length) addFiles(e.target.files);
|
| 444 |
-
// Allow picking the same file again later
|
| 445 |
-
e.target.value = "";
|
| 446 |
-
});
|
| 447 |
-
|
| 448 |
document.getElementById("uploadForm").addEventListener("submit", async (e) => {
|
| 449 |
e.preventDefault();
|
|
|
|
|
|
|
| 450 |
|
| 451 |
-
const input = document.getElementById("pdfUpload");
|
| 452 |
const fd = new FormData();
|
| 453 |
-
|
| 454 |
-
if (selectedFiles.length) {
|
| 455 |
-
selectedFiles.forEach(f => fd.append("pdfs", f));
|
| 456 |
-
} else if (input.files.length) {
|
| 457 |
-
// fallback if user didn't use the basket
|
| 458 |
-
Array.from(input.files).forEach(f => fd.append("pdfs", f));
|
| 459 |
-
} else {
|
| 460 |
-
return alert("Please choose at least one PDF.");
|
| 461 |
-
}
|
| 462 |
|
| 463 |
try {
|
| 464 |
const res = await fetch("/upload", { method: "POST", body: fd });
|
|
@@ -467,34 +391,53 @@ document.getElementById("uploadForm").addEventListener("submit", async (e) => {
|
|
| 467 |
const outputText = await fetch(result.download_url).then(r => r.text());
|
| 468 |
document.getElementById("outputText").textContent = outputText;
|
| 469 |
|
| 470 |
-
document.getElementById("fullText").innerText
|
| 471 |
-
document.getElementById("finalText").innerText
|
| 472 |
document.getElementById("nyFinalText").innerText = result.ny_final_pdf_text;
|
| 473 |
|
| 474 |
-
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
const editBtn = document.getElementById("editBtn");
|
| 480 |
-
if (editBtn) editBtn.style.display = "inline";
|
| 481 |
} catch (err) {
|
| 482 |
console.error(err);
|
| 483 |
-
alert("Failed to process
|
| 484 |
}
|
| 485 |
});
|
| 486 |
|
| 487 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 488 |
(() => {
|
| 489 |
const form = document.getElementById("uploadForm");
|
|
|
|
| 490 |
const dropZone = document.getElementById("dropZone");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 491 |
|
|
|
|
| 492 |
["dragenter","dragover","dragleave","drop"].forEach(evt =>
|
| 493 |
document.addEventListener(evt, e => { e.preventDefault(); e.stopPropagation(); })
|
| 494 |
);
|
| 495 |
|
| 496 |
-
|
| 497 |
-
|
| 498 |
["dragenter","dragover"].forEach(evt =>
|
| 499 |
dropZone.addEventListener(evt, () => dropZone.classList.add("is-dragover"))
|
| 500 |
);
|
|
@@ -502,10 +445,44 @@ document.getElementById("uploadForm").addEventListener("submit", async (e) => {
|
|
| 502 |
dropZone.addEventListener(evt, () => dropZone.classList.remove("is-dragover"))
|
| 503 |
);
|
| 504 |
|
|
|
|
| 505 |
dropZone.addEventListener("drop", (e) => {
|
| 506 |
const files = e.dataTransfer?.files;
|
| 507 |
if (!files || !files.length) return;
|
| 508 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 509 |
});
|
| 510 |
})();
|
| 511 |
</script>
|
|
|
|
| 176 |
|
| 177 |
<div class="container">
|
| 178 |
<!-- Upload card -->
|
| 179 |
+
<section class="card panel">
|
| 180 |
+
<h3 class="section-title">Upload a PDF</h3>
|
| 181 |
+
<form id="uploadForm" action="/upload" method="post" enctype="multipart/form-data">
|
| 182 |
+
<div id="dropZone" class="dropzone" title="Drop a PDF here or click to choose">
|
| 183 |
+
<div class="dz-label">Drop PDF here or click to choose</div>
|
| 184 |
+
<div class="dz-file" style="display:none;"></div>
|
| 185 |
+
</div>
|
| 186 |
+
|
| 187 |
+
<label for="pdfUpload" class="btn">Choose File</label>
|
| 188 |
+
<input id="pdfUpload" type="file" name="pdf" accept="application/pdf" required style="display:none;" />
|
| 189 |
+
<button type="submit" class="btn">Upload & Annotate</button>
|
| 190 |
+
<a id="downloadOutput" href="#" style="display:none; margin-left:16px;">Download output file</a>
|
| 191 |
+
</form>
|
| 192 |
+
</section>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
|
| 194 |
<!-- Tabs toolbar -->
|
| 195 |
<div class="tabs toolbar card">
|
|
|
|
| 376 |
document.getElementById("generateApiTTS").addEventListener("click", autoGenerateTTSFromNY);
|
| 377 |
|
| 378 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 379 |
document.getElementById("uploadForm").addEventListener("submit", async (e) => {
|
| 380 |
e.preventDefault();
|
| 381 |
+
const input = e.target.querySelector('input[name="pdf"]');
|
| 382 |
+
if (!input.files.length) return alert("Please choose a PDF first.");
|
| 383 |
|
|
|
|
| 384 |
const fd = new FormData();
|
| 385 |
+
fd.append("pdf", input.files[0]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 386 |
|
| 387 |
try {
|
| 388 |
const res = await fetch("/upload", { method: "POST", body: fd });
|
|
|
|
| 391 |
const outputText = await fetch(result.download_url).then(r => r.text());
|
| 392 |
document.getElementById("outputText").textContent = outputText;
|
| 393 |
|
| 394 |
+
document.getElementById("fullText").innerText = result.pdf_text;
|
| 395 |
+
document.getElementById("finalText").innerText = result.final_pdf_text;
|
| 396 |
document.getElementById("nyFinalText").innerText = result.ny_final_pdf_text;
|
| 397 |
|
| 398 |
+
document.getElementById("downloadOutput").href = result.download_url;
|
| 399 |
+
document.getElementById("downloadOutput").download = input.files[0].name.replace(/\.pdf$/i, ".txt");
|
| 400 |
+
document.getElementById("downloadOutput").style.display = "inline";
|
| 401 |
+
const editBtn = document.getElementById("editBtn");
|
| 402 |
+
if (editBtn) editBtn.style.display = "inline";
|
|
|
|
|
|
|
| 403 |
} catch (err) {
|
| 404 |
console.error(err);
|
| 405 |
+
alert("Failed to process PDF.");
|
| 406 |
}
|
| 407 |
});
|
| 408 |
|
| 409 |
+
|
| 410 |
+
document.getElementById("editBtn").addEventListener("click", () => {
|
| 411 |
+
// Choose which editor to focus; keep your existing logic if you like
|
| 412 |
+
const isFinal = document.getElementById("finalTextTab").style.display === "block";
|
| 413 |
+
const targetId = isFinal ? "finalText" : "fullText";
|
| 414 |
+
const div = document.getElementById(targetId);
|
| 415 |
+
if (div) div.focus();
|
| 416 |
+
});
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
|
| 420 |
+
|
| 421 |
+
|
| 422 |
+
|
| 423 |
+
|
| 424 |
+
// Drag & drop wiring
|
| 425 |
(() => {
|
| 426 |
const form = document.getElementById("uploadForm");
|
| 427 |
+
const fileInput = form.querySelector('input[name="pdf"]');
|
| 428 |
const dropZone = document.getElementById("dropZone");
|
| 429 |
+
const labelEl = dropZone.querySelector(".dz-label");
|
| 430 |
+
const fileEl = dropZone.querySelector(".dz-file");
|
| 431 |
+
|
| 432 |
+
// Let clicking the dropzone open the file picker
|
| 433 |
+
dropZone.addEventListener("click", () => fileInput.click());
|
| 434 |
|
| 435 |
+
// Prevent the browser from opening the file on drop
|
| 436 |
["dragenter","dragover","dragleave","drop"].forEach(evt =>
|
| 437 |
document.addEventListener(evt, e => { e.preventDefault(); e.stopPropagation(); })
|
| 438 |
);
|
| 439 |
|
| 440 |
+
// Visual highlight
|
|
|
|
| 441 |
["dragenter","dragover"].forEach(evt =>
|
| 442 |
dropZone.addEventListener(evt, () => dropZone.classList.add("is-dragover"))
|
| 443 |
);
|
|
|
|
| 445 |
dropZone.addEventListener(evt, () => dropZone.classList.remove("is-dragover"))
|
| 446 |
);
|
| 447 |
|
| 448 |
+
// Handle the actual drop
|
| 449 |
dropZone.addEventListener("drop", (e) => {
|
| 450 |
const files = e.dataTransfer?.files;
|
| 451 |
if (!files || !files.length) return;
|
| 452 |
+
|
| 453 |
+
const file = files[0];
|
| 454 |
+
const isPDF = file.type === "application/pdf" || file.name.toLowerCase().endsWith(".pdf");
|
| 455 |
+
if (!isPDF) {
|
| 456 |
+
alert("Please drop a PDF file.");
|
| 457 |
+
return;
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
// Assign to the real <input type="file">
|
| 461 |
+
const dt = new DataTransfer();
|
| 462 |
+
dt.items.add(file);
|
| 463 |
+
fileInput.files = dt.files;
|
| 464 |
+
|
| 465 |
+
// UI feedback
|
| 466 |
+
labelEl.textContent = "Ready:";
|
| 467 |
+
fileEl.style.display = "block";
|
| 468 |
+
fileEl.textContent = file.name;
|
| 469 |
+
|
| 470 |
+
// Optional: auto-submit after drop (uncomment to enable)
|
| 471 |
+
// form.requestSubmit();
|
| 472 |
+
});
|
| 473 |
+
|
| 474 |
+
// Also reflect selection when user picks via dialog
|
| 475 |
+
fileInput.addEventListener("change", () => {
|
| 476 |
+
const file = fileInput.files?.[0];
|
| 477 |
+
if (!file) {
|
| 478 |
+
labelEl.textContent = "Drop PDF here or click to choose";
|
| 479 |
+
fileEl.style.display = "none";
|
| 480 |
+
fileEl.textContent = "";
|
| 481 |
+
return;
|
| 482 |
+
}
|
| 483 |
+
labelEl.textContent = "Ready:";
|
| 484 |
+
fileEl.style.display = "block";
|
| 485 |
+
fileEl.textContent = file.name;
|
| 486 |
});
|
| 487 |
})();
|
| 488 |
</script>
|