Download index.html from NRbones/docsync: direct link, hf CLI and curl.
- Browser
- Download file 66.1 kB
-
https://huggingface.co/spaces/NRbones/docsync/resolve/main/index.html
- Command line
-
hf download hf://spaces/NRbones/docsync/index.html
-
curl -L -o index.html https://huggingface.co/spaces/NRbones/docsync/resolve/main/index.html
66.1 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>DocSync - Intelligent Document Automation</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/pdf-lib@1.17.1/dist/pdf-lib.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| .dropzone { | |
| border: 2px dashed #3b82f6; | |
| transition: all 0.3s ease; | |
| } | |
| .dropzone.active { | |
| border-color: #10b981; | |
| background-color: #f0fdf4; | |
| } | |
| .document-preview { | |
| box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); | |
| } | |
| .confidence-meter { | |
| height: 6px; | |
| border-radius: 3px; | |
| } | |
| .sidebar-item { | |
| transition: all 0.2s ease; | |
| } | |
| .sidebar-item:hover { | |
| background-color: #f3f4f6; | |
| } | |
| .page-turner { | |
| animation: pageTurn 0.5s ease-in-out; | |
| } | |
| @keyframes pageTurn { | |
| 0% { transform: rotateY(0deg); } | |
| 50% { transform: rotateY(90deg); } | |
| 100% { transform: rotateY(0deg); } | |
| } | |
| .highlight-field { | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0% { background-color: rgba(255, 255, 0, 0.3); } | |
| 50% { background-color: rgba(255, 255, 0, 0.7); } | |
| 100% { background-color: rgba(255, 255, 0, 0.3); } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 font-sans"> | |
| <div class="flex h-screen overflow-hidden"> | |
| <!-- Sidebar --> | |
| <div class="hidden md:flex md:flex-shrink-0"> | |
| <div class="flex flex-col w-64 bg-white border-r border-gray-200"> | |
| <div class="flex items-center justify-center h-16 px-4 bg-blue-600"> | |
| <h1 class="text-white font-bold text-xl">DocSync</h1> | |
| </div> | |
| <div class="flex flex-col flex-grow p-4 overflow-y-auto"> | |
| <nav class="flex-1 space-y-2"> | |
| <a href="#" class="flex items-center px-4 py-2 text-sm font-medium text-blue-700 bg-blue-100 rounded-md sidebar-item"> | |
| <i class="fas fa-home mr-3"></i> | |
| Dashboard | |
| </a> | |
| <a href="#" class="flex items-center px-4 py-2 text-sm font-medium text-gray-600 rounded-md sidebar-item"> | |
| <i class="fas fa-file-import mr-3"></i> | |
| Document Processing | |
| </a> | |
| <a href="#" class="flex items-center px-4 py-2 text-sm font-medium text-gray-600 rounded-md sidebar-item"> | |
| <i class="fas fa-history mr-3"></i> | |
| Processing History | |
| </a> | |
| <a href="#" class="flex items-center px-4 py-2 text-sm font-medium text-gray-600 rounded-md sidebar-item"> | |
| <i class="fas fa-cog mr-3"></i> | |
| Settings | |
| </a> | |
| </nav> | |
| <div class="mt-auto p-4"> | |
| <div class="flex items-center"> | |
| <img class="w-10 h-10 rounded-full" src="https://randomuser.me/api/portraits/women/44.jpg" alt="User profile"> | |
| <div class="ml-3"> | |
| <p class="text-sm font-medium text-gray-700">Sarah Johnson</p> | |
| <p class="text-xs font-medium text-gray-500">Admin</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Main content --> | |
| <div class="flex flex-col flex-1 overflow-hidden"> | |
| <!-- Top navigation --> | |
| <div class="flex items-center justify-between h-16 px-6 bg-white border-b border-gray-200"> | |
| <div class="flex items-center"> | |
| <button class="md:hidden text-gray-500 focus:outline-none"> | |
| <i class="fas fa-bars"></i> | |
| </button> | |
| <h2 class="ml-4 text-lg font-medium text-gray-900">Document Automation</h2> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <button class="p-1 text-gray-400 rounded-full hover:text-gray-500 focus:outline-none"> | |
| <i class="fas fa-bell"></i> | |
| </button> | |
| <button class="p-1 text-gray-400 rounded-full hover:text-gray-500 focus:outline-none"> | |
| <i class="fas fa-question-circle"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Main content area --> | |
| <div class="flex-1 overflow-auto p-6"> | |
| <div class="max-w-7xl mx-auto"> | |
| <!-- Process steps --> | |
| <div class="mb-8"> | |
| <div class="flex items-center"> | |
| <div class="flex items-center relative"> | |
| <div class="flex items-center justify-center w-10 h-10 rounded-full bg-blue-600 text-white font-semibold"> | |
| 1 | |
| </div> | |
| <div class="ml-3 text-sm font-medium text-blue-600">Upload Source</div> | |
| </div> | |
| <div class="flex-auto border-t-2 border-gray-200 mx-4"></div> | |
| <div class="flex items-center"> | |
| <div class="flex items-center justify-center w-10 h-10 rounded-full bg-gray-200 text-gray-600 font-semibold"> | |
| 2 | |
| </div> | |
| <div class="ml-3 text-sm font-medium text-gray-500">Upload Template</div> | |
| </div> | |
| <div class="flex-auto border-t-2 border-gray-200 mx-4"></div> | |
| <div class="flex items-center"> | |
| <div class="flex items-center justify-center w-10 h-10 rounded-full bg-gray-200 text-gray-600 font-semibold"> | |
| 3 | |
| </div> | |
| <div class="ml-3 text-sm font-medium text-gray-500">Review & Export</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Upload source document --> | |
| <div id="sourceUploadSection" class="bg-white rounded-lg shadow p-6 mb-8"> | |
| <h3 class="text-lg font-medium text-gray-900 mb-4">Upload Source Document</h3> | |
| <p class="text-sm text-gray-500 mb-6">Upload a completed invoice, form, or PDF document that contains the data you want to extract.</p> | |
| <div id="sourceDropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer mb-4"> | |
| <div class="flex flex-col items-center justify-center"> | |
| <i class="fas fa-cloud-upload-alt text-4xl text-blue-500 mb-3"></i> | |
| <p class="text-sm text-gray-600 mb-1">Drag and drop your file here</p> | |
| <p class="text-xs text-gray-400">or click to browse</p> | |
| <input type="file" id="sourceFileInput" class="hidden" accept=".pdf,.jpg,.jpeg,.png,.tiff"> | |
| </div> | |
| </div> | |
| <div class="text-xs text-gray-500 text-center">Supported formats: PDF, JPG, PNG, TIFF (Max 20MB)</div> | |
| </div> | |
| <!-- Processing status (hidden initially) --> | |
| <div id="processingStatus" class="hidden bg-white rounded-lg shadow p-6 mb-8"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h3 class="text-lg font-medium text-gray-900">Processing Document</h3> | |
| <div class="text-sm text-blue-600">Step 1 of 3</div> | |
| </div> | |
| <div class="space-y-4"> | |
| <div> | |
| <div class="flex items-center justify-between mb-1"> | |
| <span class="text-sm font-medium text-gray-700">OCR Processing</span> | |
| <span class="text-xs font-medium text-green-600">Completed</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-1.5"> | |
| <div class="bg-green-600 h-1.5 rounded-full" style="width: 100%"></div> | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex items-center justify-between mb-1"> | |
| <span class="text-sm font-medium text-gray-700">Layout Analysis</span> | |
| <span class="text-xs font-medium text-green-600">Completed</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-1.5"> | |
| <div class="bg-green-600 h-1.5 rounded-full" style="width: 100%"></div> | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex items-center justify-between mb-1"> | |
| <span class="text-sm font-medium text-gray-700">Field Extraction</span> | |
| <span class="text-xs font-medium text-blue-600">In Progress</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-1.5"> | |
| <div class="bg-blue-600 h-1.5 rounded-full" style="width: 65%"></div> | |
| </div> | |
| </div> | |
| <div> | |
| <div class="flex items-center justify-between mb-1"> | |
| <span class="text-sm font-medium text-gray-700">Semantic Matching</span> | |
| <span class="text-xs font-medium text-gray-600">Pending</span> | |
| </div> | |
| <div class="w-full bg-gray-200 rounded-full h-1.5"> | |
| <div class="bg-gray-300 h-1.5 rounded-full" style="width: 0%"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Extracted data preview (hidden initially) --> | |
| <div id="extractedDataPreview" class="hidden bg-white rounded-lg shadow overflow-hidden mb-8"> | |
| <div class="border-b border-gray-200 px-6 py-4"> | |
| <h3 class="text-lg font-medium text-gray-900">Extracted Data Preview</h3> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-0"> | |
| <!-- Document preview --> | |
| <div class="md:col-span-1 border-r border-gray-200"> | |
| <div class="p-4"> | |
| <div class="document-preview bg-gray-100 rounded-lg overflow-hidden relative"> | |
| <div class="absolute top-0 left-0 right-0 bg-gray-800 text-white py-1 px-3 text-sm flex justify-between items-center"> | |
| <span id="sourceFileName">source_document.pdf</span> | |
| <div class="flex space-x-2"> | |
| <button class="text-gray-300 hover:text-white"> | |
| <i class="fas fa-search-plus"></i> | |
| </button> | |
| <button class="text-gray-300 hover:text-white"> | |
| <i class="fas fa-search-minus"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="p-4 h-96 overflow-auto"> | |
| <img id="documentPreviewImage" src="https://via.placeholder.com/600x800?text=Document+Preview" alt="Document preview" class="mx-auto shadow-lg"> | |
| </div> | |
| <div class="absolute bottom-0 left-0 right-0 bg-gray-100 py-2 px-4 flex justify-between items-center border-t border-gray-200"> | |
| <button id="prevPage" class="text-gray-600 hover:text-blue-600 disabled:text-gray-300"> | |
| <i class="fas fa-chevron-left mr-1"></i> Previous | |
| </button> | |
| <span class="text-sm text-gray-600">Page <span id="currentPage">1</span> of <span id="totalPages">3</span></span> | |
| <button id="nextPage" class="text-gray-600 hover:text-blue-600 disabled:text-gray-300"> | |
| Next <i class="fas fa-chevron-right ml-1"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Extracted fields --> | |
| <div class="md:col-span-2"> | |
| <div class="p-4"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <div> | |
| <h4 class="font-medium text-gray-900">Extracted Fields</h4> | |
| <p class="text-sm text-gray-500">Review and edit the extracted data before proceeding</p> | |
| </div> | |
| <div class="flex space-x-2"> | |
| <button class="px-3 py-1 bg-gray-100 text-gray-700 rounded text-sm hover:bg-gray-200"> | |
| <i class="fas fa-filter mr-1"></i> Filter | |
| </button> | |
| <button class="px-3 py-1 bg-gray-100 text-gray-700 rounded text-sm hover:bg-gray-200"> | |
| <i class="fas fa-search mr-1"></i> Search | |
| </button> | |
| </div> | |
| </div> | |
| <div class="overflow-auto" style="max-height: 500px;"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead class="bg-gray-50"> | |
| <tr> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Field Name</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Extracted Value</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Confidence</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody id="extractedFieldsTable" class="bg-white divide-y divide-gray-200"> | |
| <!-- Sample rows will be inserted here by JavaScript --> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div class="mt-4 flex justify-between items-center"> | |
| <div class="text-sm text-gray-500"> | |
| Showing <span id="showingStart">1</span> to <span id="showingEnd">10</span> of <span id="totalFields">24</span> fields | |
| </div> | |
| <div class="flex space-x-2"> | |
| <button class="px-3 py-1 bg-gray-100 text-gray-700 rounded text-sm hover:bg-gray-200 disabled:opacity-50"> | |
| <i class="fas fa-chevron-left"></i> | |
| </button> | |
| <button class="px-3 py-1 bg-gray-100 text-gray-700 rounded text-sm hover:bg-gray-200 disabled:opacity-50"> | |
| <i class="fas fa-chevron-right"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Upload template document (hidden initially) --> | |
| <div id="templateUploadSection" class="hidden bg-white rounded-lg shadow p-6 mb-8"> | |
| <h3 class="text-lg font-medium text-gray-900 mb-4">Upload Template Document</h3> | |
| <p class="text-sm text-gray-500 mb-6">Upload a blank or partially completed template form that you want to fill with the extracted data.</p> | |
| <div id="templateDropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer mb-4"> | |
| <div class="flex flex-col items-center justify-center"> | |
| <i class="fas fa-file-alt text-4xl text-blue-500 mb-3"></i> | |
| <p class="text-sm text-gray-600 mb-1">Drag and drop your template file here</p> | |
| <p class="text-xs text-gray-400">or click to browse</p> | |
| <input type="file" id="templateFileInput" class="hidden" accept=".pdf"> | |
| </div> | |
| </div> | |
| <div class="text-xs text-gray-500 text-center">Supported formats: PDF (Max 20MB)</div> | |
| </div> | |
| <!-- Field mapping (hidden initially) --> | |
| <div id="fieldMappingSection" class="hidden bg-white rounded-lg shadow overflow-hidden mb-8"> | |
| <div class="border-b border-gray-200 px-6 py-4"> | |
| <h3 class="text-lg font-medium text-gray-900">Field Mapping</h3> | |
| <p class="text-sm text-gray-500">Review and adjust how fields from your source document map to the template fields</p> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-0"> | |
| <!-- Source fields --> | |
| <div class="md:col-span-1 border-r border-gray-200 p-4"> | |
| <h4 class="font-medium text-gray-900 mb-3">Source Fields</h4> | |
| <div class="relative mb-3"> | |
| <input type="text" placeholder="Search source fields..." class="w-full pl-8 pr-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> | |
| <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i> | |
| </div> | |
| <div class="overflow-auto" style="max-height: 500px;"> | |
| <div id="sourceFieldsList" class="space-y-2"> | |
| <!-- Source fields will be inserted here by JavaScript --> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Mapping visualization --> | |
| <div class="md:col-span-1 border-r border-gray-200 p-4"> | |
| <h4 class="font-medium text-gray-900 mb-3 text-center">Field Mapping</h4> | |
| <div class="flex flex-col items-center justify-center h-full"> | |
| <div class="w-full max-w-xs"> | |
| <div class="bg-blue-50 rounded-lg p-6 text-center"> | |
| <i class="fas fa-random text-3xl text-blue-500 mb-3"></i> | |
| <p class="text-sm text-gray-700 mb-3">Drag fields between columns to create custom mappings</p> | |
| <p class="text-xs text-gray-500">Auto-mapped fields are shown in green</p> | |
| </div> | |
| <div class="mt-6"> | |
| <h5 class="text-sm font-medium text-gray-700 mb-2">Mapping Confidence</h5> | |
| <div class="bg-white rounded-lg shadow p-4"> | |
| <canvas id="mappingConfidenceChart" height="150"></canvas> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Template fields --> | |
| <div class="md:col-span-1 p-4"> | |
| <h4 class="font-medium text-gray-900 mb-3">Template Fields</h4> | |
| <div class="relative mb-3"> | |
| <input type="text" placeholder="Search template fields..." class="w-full pl-8 pr-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> | |
| <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i> | |
| </div> | |
| <div class="overflow-auto" style="max-height: 500px;"> | |
| <div id="templateFieldsList" class="space-y-2"> | |
| <!-- Template fields will be inserted here by JavaScript --> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Final output (hidden initially) --> | |
| <div id="finalOutputSection" class="hidden bg-white rounded-lg shadow overflow-hidden mb-8"> | |
| <div class="border-b border-gray-200 px-6 py-4"> | |
| <h3 class="text-lg font-medium text-gray-900">Final Output</h3> | |
| <p class="text-sm text-gray-500">Review and download your completed document</p> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-0"> | |
| <!-- Document preview --> | |
| <div class="md:col-span-1 border-r border-gray-200 p-4"> | |
| <h4 class="font-medium text-gray-900 mb-3">Completed Document Preview</h4> | |
| <div class="document-preview bg-gray-100 rounded-lg overflow-hidden relative"> | |
| <div class="absolute top-0 left-0 right-0 bg-gray-800 text-white py-1 px-3 text-sm flex justify-between items-center"> | |
| <span id="completedDocumentName">completed_document.pdf</span> | |
| <div class="flex space-x-2"> | |
| <button class="text-gray-300 hover:text-white"> | |
| <i class="fas fa-search-plus"></i> | |
| </button> | |
| <button class="text-gray-300 hover:text-white"> | |
| <i class="fas fa-search-minus"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="p-4 h-96 overflow-auto"> | |
| <img id="completedDocumentPreview" src="https://via.placeholder.com/600x800?text=Completed+Document+Preview" alt="Completed document preview" class="mx-auto shadow-lg"> | |
| </div> | |
| <div class="absolute bottom-0 left-0 right-0 bg-gray-100 py-2 px-4 flex justify-between items-center border-t border-gray-200"> | |
| <button id="prevCompletedPage" class="text-gray-600 hover:text-blue-600 disabled:text-gray-300"> | |
| <i class="fas fa-chevron-left mr-1"></i> Previous | |
| </button> | |
| <span class="text-sm text-gray-600">Page <span id="currentCompletedPage">1</span> of <span id="totalCompletedPages">3</span></span> | |
| <button id="nextCompletedPage" class="text-gray-600 hover:text-blue-600 disabled:text-gray-300"> | |
| Next <i class="fas fa-chevron-right ml-1"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Export options --> | |
| <div class="md:col-span-1 p-4"> | |
| <h4 class="font-medium text-gray-900 mb-3">Export Options</h4> | |
| <div class="space-y-4"> | |
| <div class="bg-gray-50 rounded-lg p-4 border border-gray-200"> | |
| <div class="flex items-start"> | |
| <div class="flex-shrink-0 h-10 w-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600"> | |
| <i class="fas fa-file-pdf"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <h5 class="text-sm font-medium text-gray-900">PDF Document</h5> | |
| <p class="text-sm text-gray-500">Download the filled-in PDF document</p> | |
| <div class="mt-2"> | |
| <button id="downloadPdf" class="inline-flex items-center px-3 py-1.5 border border-transparent text-xs font-medium rounded shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> | |
| <i class="fas fa-download mr-1"></i> Download PDF | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-gray-50 rounded-lg p-4 border border-gray-200"> | |
| <div class="flex items-start"> | |
| <div class="flex-shrink-0 h-10 w-10 rounded-full bg-green-100 flex items-center justify-center text-green-600"> | |
| <i class="fas fa-file-code"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <h5 class="text-sm font-medium text-gray-900">JSON Data</h5> | |
| <p class="text-sm text-gray-500">Export the structured data in JSON format</p> | |
| <div class="mt-2"> | |
| <button id="downloadJson" class="inline-flex items-center px-3 py-1.5 border border-transparent text-xs font-medium rounded shadow-sm text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500"> | |
| <i class="fas fa-download mr-1"></i> Download JSON | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-gray-50 rounded-lg p-4 border border-gray-200"> | |
| <div class="flex items-start"> | |
| <div class="flex-shrink-0 h-10 w-10 rounded-full bg-purple-100 flex items-center justify-center text-purple-600"> | |
| <i class="fas fa-file-csv"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <h5 class="text-sm font-medium text-gray-900">CSV Data</h5> | |
| <p class="text-sm text-gray-500">Export the data in tabular CSV format</p> | |
| <div class="mt-2"> | |
| <button id="downloadCsv" class="inline-flex items-center px-3 py-1.5 border border-transparent text-xs font-medium rounded shadow-sm text-white bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500"> | |
| <i class="fas fa-download mr-1"></i> Download CSV | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mt-6 pt-4 border-t border-gray-200"> | |
| <h5 class="text-sm font-medium text-gray-900 mb-2">Processing Summary</h5> | |
| <div class="bg-white rounded-lg shadow p-4"> | |
| <div class="grid grid-cols-2 gap-4"> | |
| <div> | |
| <p class="text-xs text-gray-500">Source Fields</p> | |
| <p class="font-medium">24</p> | |
| </div> | |
| <div> | |
| <p class="text-xs text-gray-500">Template Fields</p> | |
| <p class="font-medium">18</p> | |
| </div> | |
| <div> | |
| <p class="text-xs text-gray-500">Auto-mapped</p> | |
| <p class="font-medium text-green-600">16 (89%)</p> | |
| </div> | |
| <div> | |
| <p class="text-xs text-gray-500">Manual Mappings</p> | |
| <p class="font-medium">2</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Navigation buttons --> | |
| <div class="flex justify-between"> | |
| <button id="backButton" class="hidden px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> | |
| <i class="fas fa-arrow-left mr-2"></i> Back | |
| </button> | |
| <button id="nextButton" class="px-4 py-2 border border-transparent rounded-md text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> | |
| Continue <i class="fas fa-arrow-right ml-2"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Sample data for demonstration | |
| const extractedFields = [ | |
| { id: 1, name: "Invoice Number", value: "INV-2023-0042", confidence: 98, page: 1, boundingBox: "100,200,300,220" }, | |
| { id: 2, name: "Invoice Date", value: "2023-05-15", confidence: 95, page: 1, boundingBox: "100,250,300,270" }, | |
| { id: 3, name: "Due Date", value: "2023-06-14", confidence: 92, page: 1, boundingBox: "100,300,300,320" }, | |
| { id: 4, name: "Customer Name", value: "Acme Corporation", confidence: 97, page: 1, boundingBox: "100,350,300,370" }, | |
| { id: 5, name: "Customer Address", value: "123 Business Ave, Suite 450", confidence: 90, page: 1, boundingBox: "100,400,300,450" }, | |
| { id: 6, name: "Customer ID", value: "ACME-0042", confidence: 88, page: 1, boundingBox: "100,500,300,520" }, | |
| { id: 7, name: "Subtotal", value: "$1,250.00", confidence: 96, page: 2, boundingBox: "400,200,500,220" }, | |
| { id: 8, name: "Tax (8.25%)", value: "$103.13", confidence: 94, page: 2, boundingBox: "400,250,500,270" }, | |
| { id: 9, name: "Total Amount", value: "$1,353.13", confidence: 99, page: 2, boundingBox: "400,300,500,320" }, | |
| { id: 10, name: "Payment Terms", value: "Net 30", confidence: 85, page: 2, boundingBox: "400,350,500,370" }, | |
| ]; | |
| const templateFields = [ | |
| { id: 't1', name: "Invoice No.", mappedTo: 1, confidence: 95 }, | |
| { id: 't2', name: "Date Issued", mappedTo: 2, confidence: 90 }, | |
| { id: 't3', name: "Payment Due Date", mappedTo: 3, confidence: 88 }, | |
| { id: 't4', name: "Client Name", mappedTo: 4, confidence: 93 }, | |
| { id: 't5', name: "Client Address", mappedTo: 5, confidence: 85 }, | |
| { id: 't6', name: "Client Reference", mappedTo: 6, confidence: 80 }, | |
| { id: 't7', name: "Subtotal Amount", mappedTo: 7, confidence: 96 }, | |
| { id: 't8', name: "Tax Amount", mappedTo: 8, confidence: 94 }, | |
| { id: 't9', name: "Total Due", mappedTo: 9, confidence: 97 }, | |
| { id: 't10', name: "Payment Terms", mappedTo: 10, confidence: 82 }, | |
| { id: 't11', name: "Bank Account", mappedTo: null, confidence: null }, | |
| { id: 't12', name: "Payment Instructions", mappedTo: null, confidence: null }, | |
| ]; | |
| // Current state | |
| let currentStep = 1; | |
| let currentPage = 1; | |
| let totalPages = 3; | |
| let currentCompletedPage = 1; | |
| let totalCompletedPages = 3; | |
| let sourceFileName = ''; | |
| let templateFileName = ''; | |
| // DOM elements | |
| const sourceDropzone = document.getElementById('sourceDropzone'); | |
| const sourceFileInput = document.getElementById('sourceFileInput'); | |
| const templateDropzone = document.getElementById('templateDropzone'); | |
| const templateFileInput = document.getElementById('templateFileInput'); | |
| const processingStatus = document.getElementById('processingStatus'); | |
| const extractedDataPreview = document.getElementById('extractedDataPreview'); | |
| const templateUploadSection = document.getElementById('templateUploadSection'); | |
| const fieldMappingSection = document.getElementById('fieldMappingSection'); | |
| const finalOutputSection = document.getElementById('finalOutputSection'); | |
| const nextButton = document.getElementById('nextButton'); | |
| const backButton = document.getElementById('backButton'); | |
| const extractedFieldsTable = document.getElementById('extractedFieldsTable'); | |
| const sourceFieldsList = document.getElementById('sourceFieldsList'); | |
| const templateFieldsList = document.getElementById('templateFieldsList'); | |
| const documentPreviewImage = document.getElementById('documentPreviewImage'); | |
| const currentPageSpan = document.getElementById('currentPage'); | |
| const totalPagesSpan = document.getElementById('totalPages'); | |
| const prevPageButton = document.getElementById('prevPage'); | |
| const nextPageButton = document.getElementById('nextPage'); | |
| const currentCompletedPageSpan = document.getElementById('currentCompletedPage'); | |
| const totalCompletedPagesSpan = document.getElementById('totalCompletedPages'); | |
| const prevCompletedPageButton = document.getElementById('prevCompletedPage'); | |
| const nextCompletedPageButton = document.getElementById('nextCompletedPage'); | |
| const showingStartSpan = document.getElementById('showingStart'); | |
| const showingEndSpan = document.getElementById('showingEnd'); | |
| const totalFieldsSpan = document.getElementById('totalFields'); | |
| const sourceFileNameSpan = document.getElementById('sourceFileName'); | |
| const completedDocumentNameSpan = document.getElementById('completedDocumentName'); | |
| const sourceUploadSection = document.getElementById('sourceUploadSection'); | |
| const downloadPdfButton = document.getElementById('downloadPdf'); | |
| const downloadJsonButton = document.getElementById('downloadJson'); | |
| const downloadCsvButton = document.getElementById('downloadCsv'); | |
| // Initialize the app | |
| function init() { | |
| // Set up event listeners | |
| sourceDropzone.addEventListener('click', () => sourceFileInput.click()); | |
| sourceFileInput.addEventListener('change', handleSourceFileUpload); | |
| templateDropzone.addEventListener('click', () => templateFileInput.click()); | |
| templateFileInput.addEventListener('change', handleTemplateFileUpload); | |
| nextButton.addEventListener('click', handleNextStep); | |
| backButton.addEventListener('click', handlePreviousStep); | |
| prevPageButton.addEventListener('click', () => changePage(-1)); | |
| nextPageButton.addEventListener('click', () => changePage(1)); | |
| prevCompletedPageButton.addEventListener('click', () => changeCompletedPage(-1)); | |
| nextCompletedPageButton.addEventListener('click', () => changeCompletedPage(1)); | |
| // Set up drag and drop | |
| setupDragAndDrop(sourceDropzone, sourceFileInput); | |
| setupDragAndDrop(templateDropzone, templateFileInput); | |
| // Initialize showing fields | |
| showingStartSpan.textContent = '1'; | |
| showingEndSpan.textContent = '10'; | |
| totalFieldsSpan.textContent = extractedFields.length; | |
| // Initialize page numbers | |
| currentPageSpan.textContent = currentPage; | |
| totalPagesSpan.textContent = totalPages; | |
| currentCompletedPageSpan.textContent = currentCompletedPage; | |
| totalCompletedPagesSpan.textContent = totalCompletedPages; | |
| // Disable previous page buttons initially | |
| prevPageButton.disabled = true; | |
| prevCompletedPageButton.disabled = true; | |
| // Set up export buttons | |
| downloadPdfButton.addEventListener('click', exportPdf); | |
| downloadJsonButton.addEventListener('click', exportJson); | |
| downloadCsvButton.addEventListener('click', exportCsv); | |
| } | |
| // Set up drag and drop functionality | |
| function setupDragAndDrop(dropzone, fileInput) { | |
| dropzone.addEventListener('dragover', (e) => { | |
| e.preventDefault(); | |
| dropzone.classList.add('active'); | |
| }); | |
| dropzone.addEventListener('dragleave', () => { | |
| dropzone.classList.remove('active'); | |
| }); | |
| dropzone.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| dropzone.classList.remove('active'); | |
| if (e.dataTransfer.files.length) { | |
| fileInput.files = e.dataTransfer.files; | |
| if (fileInput === sourceFileInput) { | |
| handleSourceFileUpload(); | |
| } else { | |
| handleTemplateFileUpload(); | |
| } | |
| } | |
| }); | |
| } | |
| // Handle source file upload | |
| function handleSourceFileUpload() { | |
| if (sourceFileInput.files.length) { | |
| const file = sourceFileInput.files[0]; | |
| sourceFileName = file.name; | |
| sourceFileNameSpan.textContent = sourceFileName; | |
| console.log('Source file uploaded:', file.name); | |
| // Show processing status | |
| processingStatus.classList.remove('hidden'); | |
| sourceUploadSection.classList.add('hidden'); | |
| // Simulate processing | |
| setTimeout(() => { | |
| processingStatus.classList.add('hidden'); | |
| extractedDataPreview.classList.remove('hidden'); | |
| populateExtractedFieldsTable(); | |
| updateProcessSteps(2); | |
| // Enable template upload section | |
| templateUploadSection.classList.remove('hidden'); | |
| }, 3000); | |
| } | |
| } | |
| // Handle template file upload | |
| function handleTemplateFileUpload() { | |
| if (templateFileInput.files.length) { | |
| const file = templateFileInput.files[0]; | |
| templateFileName = file.name; | |
| completedDocumentNameSpan.textContent = `filled_${templateFileName}`; | |
| console.log('Template file uploaded:', file.name); | |
| // Show field mapping section | |
| templateUploadSection.classList.add('hidden'); | |
| fieldMappingSection.classList.remove('hidden'); | |
| populateFieldMappingLists(); | |
| renderMappingConfidenceChart(); | |
| updateProcessSteps(3); | |
| } | |
| } | |
| // Populate extracted fields table | |
| function populateExtractedFieldsTable() { | |
| extractedFieldsTable.innerHTML = ''; | |
| extractedFields.forEach(field => { | |
| const row = document.createElement('tr'); | |
| row.className = field.page === currentPage ? 'bg-blue-50' : ''; | |
| row.dataset.id = field.id; | |
| row.dataset.page = field.page; | |
| row.innerHTML = ` | |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${field.name}</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${field.value}</td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="flex items-center"> | |
| <div class="w-full bg-gray-200 rounded-full h-2.5"> | |
| <div class="bg-blue-600 h-2.5 rounded-full" style="width: ${field.confidence}%"></div> | |
| </div> | |
| <span class="ml-2 text-xs font-medium text-gray-700">${field.confidence}%</span> | |
| </div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | |
| <button class="text-blue-600 hover:text-blue-900 mr-3 edit-field"> | |
| <i class="fas fa-edit"></i> | |
| </button> | |
| <button class="text-red-600 hover:text-red-900 delete-field"> | |
| <i class="fas fa-trash"></i> | |
| </button> | |
| </td> | |
| `; | |
| extractedFieldsTable.appendChild(row); | |
| }); | |
| // Add event listeners to edit and delete buttons | |
| document.querySelectorAll('.edit-field').forEach(button => { | |
| button.addEventListener('click', (e) => { | |
| const row = e.target.closest('tr'); | |
| const fieldId = parseInt(row.dataset.id); | |
| editField(fieldId); | |
| }); | |
| }); | |
| document.querySelectorAll('.delete-field').forEach(button => { | |
| button.addEventListener('click', (e) => { | |
| const row = e.target.closest('tr'); | |
| const fieldId = parseInt(row.dataset.id); | |
| deleteField(fieldId); | |
| }); | |
| }); | |
| } | |
| // Populate field mapping lists | |
| function populateFieldMappingLists() { | |
| sourceFieldsList.innerHTML = ''; | |
| templateFieldsList.innerHTML = ''; | |
| // Source fields | |
| extractedFields.forEach(field => { | |
| const fieldElement = document.createElement('div'); | |
| fieldElement.className = 'flex items-center justify-between p-2 border border-gray-200 rounded-md cursor-move'; | |
| fieldElement.dataset.id = field.id; | |
| fieldElement.draggable = true; | |
| fieldElement.innerHTML = ` | |
| <div> | |
| <div class="text-sm font-medium text-gray-700">${field.name}</div> | |
| <div class="text-xs text-gray-500">${field.value}</div> | |
| </div> | |
| <div class="text-xs text-gray-400"> | |
| <i class="fas fa-grip-vertical"></i> | |
| </div> | |
| `; | |
| sourceFieldsList.appendChild(fieldElement); | |
| // Add drag start event | |
| fieldElement.addEventListener('dragstart', (e) => { | |
| e.dataTransfer.setData('text/plain', `source:${field.id}`); | |
| }); | |
| }); | |
| // Template fields | |
| templateFields.forEach(field => { | |
| const fieldElement = document.createElement('div'); | |
| fieldElement.className = `flex items-center justify-between p-2 border rounded-md cursor-move ${field.mappedTo ? 'border-green-200 bg-green-50' : 'border-gray-200'}`; | |
| fieldElement.dataset.id = field.id; | |
| fieldElement.draggable = true; | |
| fieldElement.innerHTML = ` | |
| <div> | |
| <div class="text-sm font-medium text-gray-700">${field.name}</div> | |
| ${field.mappedTo ? | |
| `<div class="text-xs text-green-600">Mapped to: ${extractedFields.find(f => f.id === field.mappedTo).name}</div>` : | |
| `<div class="text-xs text-gray-500">Not mapped</div>`} | |
| </div> | |
| <div class="text-xs ${field.mappedTo ? 'text-green-500' : 'text-gray-400'}"> | |
| <i class="fas fa-grip-vertical"></i> | |
| </div> | |
| `; | |
| templateFieldsList.appendChild(fieldElement); | |
| // Add drag start event | |
| fieldElement.addEventListener('dragstart', (e) => { | |
| e.dataTransfer.setData('text/plain', `template:${field.id}`); | |
| }); | |
| // Add drop event | |
| fieldElement.addEventListener('dragover', (e) => { | |
| e.preventDefault(); | |
| }); | |
| fieldElement.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| const data = e.dataTransfer.getData('text/plain'); | |
| const [type, id] = data.split(':'); | |
| if (type === 'source') { | |
| // Map source field to template field | |
| const sourceFieldId = parseInt(id); | |
| const templateFieldId = field.id; | |
| mapFields(sourceFieldId, templateFieldId); | |
| } | |
| }); | |
| }); | |
| } | |
| // Render mapping confidence chart | |
| function renderMappingConfidenceChart() { | |
| const ctx = document.getElementById('mappingConfidenceChart').getContext('2d'); | |
| const mappedFields = templateFields.filter(f => f.mappedTo !== null); | |
| const unmappedFields = templateFields.filter(f => f.mappedTo === null); | |
| new Chart(ctx, { | |
| type: 'doughnut', | |
| data: { | |
| labels: ['High Confidence', 'Medium Confidence', 'Low Confidence', 'Unmapped'], | |
| datasets: [{ | |
| data: [ | |
| mappedFields.filter(f => f.confidence >= 90).length, | |
| mappedFields.filter(f => f.confidence >= 70 && f.confidence < 90).length, | |
| mappedFields.filter(f => f.confidence < 70).length, | |
| unmappedFields.length | |
| ], | |
| backgroundColor: [ | |
| '#10B981', | |
| '#3B82F6', | |
| '#F59E0B', | |
| '#EF4444' | |
| ], | |
| borderWidth: 0 | |
| }] | |
| }, | |
| options: { | |
| cutout: '70%', | |
| plugins: { | |
| legend: { | |
| position: 'bottom', | |
| labels: { | |
| boxWidth: 12, | |
| padding: 20 | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| } | |
| // Map source field to template field | |
| function mapFields(sourceFieldId, templateFieldId) { | |
| const templateField = templateFields.find(f => f.id === templateFieldId); | |
| templateField.mappedTo = sourceFieldId; | |
| // Calculate confidence based on field name similarity (simplified for demo) | |
| const sourceField = extractedFields.find(f => f.id === sourceFieldId); | |
| const sourceName = sourceField.name.toLowerCase(); | |
| const templateName = templateField.name.toLowerCase(); | |
| // Simple similarity calculation for demo | |
| let similarity = 0; | |
| if (sourceName.includes('invoice') && templateName.includes('invoice')) similarity += 30; | |
| if (sourceName.includes('date') && templateName.includes('date')) similarity += 30; | |
| if (sourceName.includes('customer') && templateName.includes('client')) similarity += 20; | |
| if (sourceName.includes('total') && templateName.includes('total')) similarity += 20; | |
| templateField.confidence = Math.min(100, similarity + 50); // Ensure we don't go over 100% | |
| // Update the UI | |
| populateFieldMappingLists(); | |
| // Re-render the chart | |
| const chartCanvas = document.getElementById('mappingConfidenceChart'); | |
| chartCanvas.innerHTML = ''; // Clear old chart | |
| chartCanvas.width = chartCanvas.offsetWidth; | |
| chartCanvas.height = chartCanvas.offsetHeight; | |
| renderMappingConfidenceChart(); | |
| } | |
| // Edit field | |
| function editField(fieldId) { | |
| const field = extractedFields.find(f => f.id === fieldId); | |
| const newValue = prompt(`Edit field: ${field.name}\nCurrent value: ${field.value}`, field.value); | |
| if (newValue !== null) { | |
| field.value = newValue; | |
| populateExtractedFieldsTable(); | |
| } | |
| } | |
| // Delete field | |
| function deleteField(fieldId) { | |
| if (confirm('Are you sure you want to delete this field?')) { | |
| const index = extractedFields.findIndex(f => f.id === fieldId); | |
| if (index !== -1) { | |
| extractedFields.splice(index, 1); | |
| populateExtractedFieldsTable(); | |
| } | |
| } | |
| } | |
| // Change page in document preview | |
| function changePage(delta) { | |
| const newPage = currentPage + delta; | |
| if (newPage >= 1 && newPage <= totalPages) { | |
| currentPage = newPage; | |
| currentPageSpan.textContent = currentPage; | |
| // Update document preview image (simulated) | |
| documentPreviewImage.src = `https://via.placeholder.com/600x800?text=Document+Page+${currentPage}`; | |
| // Update extracted fields table highlighting | |
| document.querySelectorAll('#extractedFieldsTable tr').forEach(row => { | |
| if (parseInt(row.dataset.page) === currentPage) { | |
| row.classList.add('bg-blue-50'); | |
| } else { | |
| row.classList.remove('bg-blue-50'); | |
| } | |
| }); | |
| // Update pagination buttons | |
| prevPageButton.disabled = currentPage === 1; | |
| nextPageButton.disabled = currentPage === totalPages; | |
| // Add page turn animation | |
| documentPreviewImage.classList.add('page-turner'); | |
| setTimeout(() => { | |
| documentPreviewImage.classList.remove('page-turner'); | |
| }, 500); | |
| } | |
| } | |
| // Change page in completed document preview | |
| function changeCompletedPage(delta) { | |
| const newPage = currentCompletedPage + delta; | |
| if (newPage >= 1 && newPage <= totalCompletedPages) { | |
| currentCompletedPage = newPage; | |
| currentCompletedPageSpan.textContent = currentCompletedPage; | |
| // Update completed document preview image (simulated) | |
| document.getElementById('completedDocumentPreview').src = `https://via.placeholder.com/600x800?text=Completed+Page+${currentCompletedPage}`; | |
| // Update pagination buttons | |
| prevCompletedPageButton.disabled = currentCompletedPage === 1; | |
| nextCompletedPageButton.disabled = currentCompletedPage === totalCompletedPages; | |
| // Add page turn animation | |
| document.getElementById('completedDocumentPreview').classList.add('page-turner'); | |
| setTimeout(() => { | |
| document.getElementById('completedDocumentPreview').classList.remove('page-turner'); | |
| }, 500); | |
| } | |
| } | |
| // Handle next step | |
| function handleNextStep() { | |
| if (currentStep === 1) { | |
| // From upload source to upload template | |
| // This is now handled automatically after source file processing | |
| } else if (currentStep === 2) { | |
| // From upload template to field mapping (handled in upload handler) | |
| } else if (currentStep === 3) { | |
| // From field mapping to final output | |
| fieldMappingSection.classList.add('hidden'); | |
| finalOutputSection.classList.remove('hidden'); | |
| nextButton.textContent = 'Finish'; | |
| updateProcessSteps(4); | |
| } else if (currentStep === 4) { | |
| // Finish the process | |
| alert('Document processing completed!'); | |
| // In a real app, you would reset the form or redirect | |
| } | |
| } | |
| // Handle previous step | |
| function handlePreviousStep() { | |
| if (currentStep === 2) { | |
| // From upload template back to upload source | |
| templateUploadSection.classList.add('hidden'); | |
| extractedDataPreview.classList.add('hidden'); | |
| sourceUploadSection.classList.remove('hidden'); | |
| backButton.classList.add('hidden'); | |
| nextButton.textContent = 'Continue'; | |
| updateProcessSteps(1); | |
| } else if (currentStep === 3) { | |
| // From field mapping back to upload template | |
| fieldMappingSection.classList.add('hidden'); | |
| templateUploadSection.classList.remove('hidden'); | |
| updateProcessSteps(2); | |
| } else if (currentStep === 4) { | |
| // From final output back to field mapping | |
| finalOutputSection.classList.add('hidden'); | |
| fieldMappingSection.classList.remove('hidden'); | |
| nextButton.textContent = 'Continue'; | |
| updateProcessSteps(3); | |
| } | |
| } | |
| // Update process steps UI | |
| function updateProcessSteps(step) { | |
| currentStep = step; | |
| // Update step indicators | |
| const steps = document.querySelectorAll('.flex.items-center.relative'); | |
| steps.forEach((stepElement, index) => { | |
| const stepNumber = index + 1; | |
| const circle = stepElement.querySelector('div'); | |
| const text = stepElement.querySelector('div + div'); | |
| if (stepNumber < step) { | |
| // Completed step | |
| circle.classList.remove('bg-gray-200', 'text-gray-600'); | |
| circle.classList.add('bg-green-500', 'text-white'); | |
| text.classList.remove('text-gray-500'); | |
| text.classList.add('text-green-600'); | |
| } else if (stepNumber === step) { | |
| // Current step | |
| circle.classList.remove('bg-gray-200', 'text-gray-600'); | |
| circle.classList.add('bg-blue-600', 'text-white'); | |
| text.classList.remove('text-gray-500'); | |
| text.classList.add('text-blue-600'); | |
| } else { | |
| // Future step | |
| circle.classList.remove('bg-blue-600', 'bg-green-500', 'text-white'); | |
| circle.classList.add('bg-gray-200', 'text-gray-600'); | |
| text.classList.remove('text-blue-600', 'text-green-600'); | |
| text.classList.add('text-gray-500'); | |
| } | |
| }); | |
| // Update next button text | |
| if (step === 3) { | |
| nextButton.textContent = 'Complete Processing'; | |
| } else if (step === 4) { | |
| nextButton.textContent = 'Finish'; | |
| } else { | |
| nextButton.textContent = 'Continue'; | |
| } | |
| // Update back button visibility | |
| if (step > 1) { | |
| backButton.classList.remove('hidden'); | |
| } else { | |
| backButton.classList.add('hidden'); | |
| } | |
| } | |
| // Export PDF | |
| function exportPdf() { | |
| // In a real app, this would use PDF-lib to create a filled PDF | |
| // For demo purposes, we'll create a simple PDF with the data | |
| // Create a JSON representation of the mapped data | |
| const mappedData = {}; | |
| templateFields.forEach(templateField => { | |
| if (templateField.mappedTo) { | |
| const sourceField = extractedFields.find(f => f.id === templateField.mappedTo); | |
| mappedData[templateField.name] = sourceField.value; | |
| } | |
| }); | |
| // Create a simple PDF (simulated) | |
| const { jsPDF } = window.jspdf; | |
| const doc = new jsPDF(); | |
| // Add title | |
| doc.setFontSize(20); | |
| doc.text('Completed Document', 105, 20, { align: 'center' }); | |
| // Add fields | |
| doc.setFontSize(12); | |
| let y = 40; | |
| templateFields.forEach(templateField => { | |
| if (templateField.mappedTo) { | |
| const sourceField = extractedFields.find(f => f.id === templateField.mappedTo); | |
| doc.text(`${templateField.name}: ${sourceField.value}`, 20, y); | |
| y += 10; | |
| } | |
| }); | |
| // Save the PDF | |
| doc.save(`filled_${templateFileName || 'document'}.pdf`); | |
| alert('PDF document generated successfully!'); | |
| } | |
| // Export JSON | |
| function exportJson() { | |
| // Create a JSON representation of the mapped data | |
| const mappedData = {}; | |
| templateFields.forEach(templateField => { | |
| if (templateField.mappedTo) { | |
| const sourceField = extractedFields.find(f => f.id === templateField.mappedTo); | |
| mappedData[templateField.name] = { | |
| value: sourceField.value, | |
| confidence: templateField.confidence, | |
| sourceField: sourceField.name | |
| }; | |
| } | |
| }); | |
| // Create JSON string | |
| const jsonStr = JSON.stringify(mappedData, null, 2); | |
| // Create blob and download | |
| const blob = new Blob([jsonStr], { type: 'application/json' }); | |
| saveAs(blob, `document_data_${new Date().toISOString().slice(0, 10)}.json`); | |
| alert('JSON data exported successfully!'); | |
| } | |
| // Export CSV | |
| function exportCsv() { | |
| // Create CSV header | |
| let csv = 'Field Name,Value,Confidence,Source Field\n'; | |
| // Add rows for each mapped field | |
| templateFields.forEach(templateField => { | |
| if (templateField.mappedTo) { | |
| const sourceField = extractedFields.find(f => f.id === templateField.mappedTo); | |
| csv += `"${templateField.name}","${sourceField.value}",${templateField.confidence},"${sourceField.name}"\n`; | |
| } | |
| }); | |
| // Create blob and download | |
| const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); | |
| saveAs(blob, `document_data_${new Date().toISOString().slice(0, 10)}.csv`); | |
| alert('CSV data exported successfully!'); | |
| } | |
| // Initialize the app when DOM is loaded | |
| document.addEventListener('DOMContentLoaded', init); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=NRbones/docsync" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |