Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <!--Favicon--> | |
| <link rel="shortcut icon" href="/static/images/favicon.ico" title="Favicon" /> | |
| <!-- Main CSS Files --> | |
| <!-- <link rel="stylesheet" href="/static/css/style.css"> --> | |
| <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> | |
| <link rel="stylesheet" href="{{ url_for('static', filename='css/extractor.css') }}"> | |
| <!-- Color CSS --> | |
| <link rel="stylesheet" href="/static/css/color.css"> | |
| <!--Icon Fonts - Font Awesome Icons--> | |
| <link rel="stylesheet" href="/static/css/font-awesome.min.css"> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"> | |
| <!-- Animate CSS--> | |
| <link href="css/animate.css" rel="stylesheet" type="text/css"> | |
| <!--Google Webfonts--> | |
| <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,600,700,800' rel='stylesheet' type='text/css'> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;300;400;500;600&display=swap" | |
| rel="stylesheet"> | |
| <title>ExCeipt | Extractor</title> | |
| <script src="https://cdn.lordicon.com/lordicon.js"></script> | |
| </head> | |
| <body> | |
| <div id="flash-container" class="alert alert-danger" role="alert"> | |
| <!-- Flash message will be displayed here --> | |
| </div> | |
| <div class="containerz"> | |
| <div class="left-column"> | |
| <button class="backbutton" id="submitButton" onclick="window.location.href='{{ index_url }}'"> | |
| <i class="fa-solid fa-arrow-left"></i> | |
| <span>Back</span> | |
| </button> | |
| <div id="canvas-container"> | |
| {% if image_paths %} | |
| {% for image_path, prediction_results_copy in predictions.items() %} | |
| <div | |
| class="image-container {% if prediction_results_copy == 'non-receipt' %}red-border{% elif prediction_results_copy == 'receipt' %}green-border{% endif %}"> | |
| <div class="tooltiptext">Click to view fullscreen</div> | |
| <img src="{{ url_for('static', filename='temp/img_display/' + image_path) }}" id="my-image" | |
| alt="uploads" | |
| data-img-path="{{ url_for('static', filename='temp/img_display/' + image_path) }}" /> | |
| <div class="image-name"> | |
| <p class="images-name">{{image_path}}</p> | |
| </div> | |
| </div> | |
| {% endfor %} | |
| {% else %} | |
| <p>No files uploaded.</p> | |
| {% endif %} | |
| </div> | |
| </div> | |
| <div class="right-column"> | |
| <div id="logox"> | |
| <img src="/static/images/logo.png" id="banner-logo" alt="Landing Page" /> | |
| </div> | |
| <div style="display: flex; align-items: center;"> | |
| </div> | |
| <hr style="color: #ccc; width:95%; opacity:0.35;"> | |
| <div class="labels" style="margin: 0 0 0 20px;"> | |
| <p>Receipt Verification</p> | |
| <p class="desc">Verify receipt details attentively, acknowledging occasional misclassification, which | |
| may arise from variations in image quality or format.</p> | |
| </div> | |
| <div class="receipt"> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>File Name</th> | |
| <th>Prediction Result</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| {% for image_path, prediction_results_copy in predictions.items() %} | |
| <tr> | |
| <td>{{ image_path }}</td> | |
| <td> | |
| <div class="details"> | |
| <div style="display: flex; align-items: center; justify-content: center;"> | |
| {% if prediction_results_copy.lower() == 'receipt' %} | |
| <lord-icon src="https://cdn.lordicon.com/lomfljuq.json" trigger="in" | |
| delay="1500" colors="primary:#16c72e" state="morph-check-in-1" | |
| style="width:25px;height:25px"> | |
| </lord-icon> | |
| <p class="valid">Valid Receipt</p> | |
| {% else %} | |
| <lord-icon src="https://cdn.lordicon.com/zxvuvcnc.json" trigger="in" | |
| delay="1500" state="morph-cross-in" colors="primary:#e83a30" | |
| style="width:25px;height:25px"> | |
| </lord-icon> | |
| <p class="valid">Not a Receipt</p> | |
| {% endif %} | |
| </div> | |
| </div> | |
| </td> | |
| </tr> | |
| {% endfor %} | |
| </tbody> | |
| </table> | |
| </div> | |
| <hr style="color: #ccc; width:95%; opacity:0.35;"> | |
| <div class="labels" style="margin: 0 0 0 20px;"> | |
| <p>Text Extraction</p> | |
| <p class="desc">Ensure optimal text extraction accuracy from receipts by making sure that the receipt | |
| image is clear, well-lit, and after extraction review the extracted text and edit.</p> | |
| </div> | |
| <div style="text-align: center; margin-top: 25px;"> | |
| <button id="uploadbutton" class="uploadbutton" type="submit"> | |
| <i id="loadingIcon" class="fa fa-spinner fa-spin" style="display: none;"></i> | |
| <span id="extractingText">Extract</span> | |
| </button> | |
| </div> | |
| <div class="avatargif"> | |
| <img src="/static/images/avatar.gif" id="avatargif" /> | |
| </div> | |
| <div class="receipt1" id="receiptdiv"> | |
| <div class="details1"> | |
| <table id="dataTable" border="1"> | |
| <thead> | |
| <tr> | |
| <th>Receipt No.</th> | |
| <th>Merchant</th> | |
| <th>Address</th> | |
| <th>Date</th> | |
| <th>Time</th> | |
| <th>Items</th> | |
| <th>Price</th> | |
| <th>Total</th> | |
| <th>VAT</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <div style="text-align: center; display: none; justify-content: center;" id="downloadbutton"> | |
| <a href="{{ url_for('download_csv') }}"> | |
| <button id="downloadButton" class="exportbutton" type="submit"><i | |
| class="fa-solid fa-download"></i>Download CSV</button> | |
| </a> | |
| <button class="exportbutton" onclick="window.location.href='{{ index_url }}'"> | |
| <span id="uploadIcon"><i class="fas fa-upload"></i></span> | |
| <span>Upload again</span> | |
| </button> | |
| </div> | |
| </div> | |
| <a href="https://lordicon.com/" hidden>Icons by Lordicon.com</a> | |
| <script> | |
| const index_url = '{{ index_url }}'; // Replace with the actual value if it's not supposed to be a template variable | |
| document.addEventListener('DOMContentLoaded', function () { | |
| const dataTable = document.getElementById('receiptdiv'); | |
| const loadingSpinner = document.getElementById('loadingIcon'); | |
| const extractingText = document.getElementById('extractingText'); | |
| const runInferenceButton = document.getElementById('uploadbutton'); | |
| const exportCSVButton = document.getElementById('downloadbutton'); | |
| document.getElementById('uploadbutton').addEventListener('click', function () { | |
| loadingSpinner.style.display = 'inline-block'; // Show loading spinner | |
| extractingText.textContent = 'Extracting...'; // Change text to "Extracting..." | |
| runInferenceButton.disabled = true; | |
| // Hide the avatargif image | |
| document.getElementById('avatargif').style.display = 'none'; | |
| runInference(); | |
| }); | |
| async function getData() { | |
| const response = await fetch('/get_data'); | |
| const data = await response.text(); | |
| updateTable(data); | |
| // Show the table when data is updated | |
| dataTable.style.display = 'table'; | |
| } | |
| const imageElement = document.getElementById('my-image'); // replace 'my-image' with the id of your image element | |
| async function runInference() { | |
| await fetch('/run_inference'); | |
| setTimeout(function () { | |
| loadingSpinner.style.display = 'none'; | |
| runInferenceButton.style.display = 'none'; | |
| exportCSVButton.style.display = 'flex'; | |
| var imageElements = document.querySelectorAll('[data-img-path]'); | |
| // Iterate over each image | |
| imageElements.forEach(function (imageElement) { | |
| var imagePath = imageElement.dataset.imgPath; | |
| // Remove the 'temp/img_display/' part from the imagePath | |
| // var newImagePath = imagePath.replace('temp/img_display/', ''); | |
| // Update the image source | |
| imageElement.src = imagePath + "_inference.jpg"; | |
| // Add an error handler | |
| imageElement.onerror = function () { | |
| // Hide the image's container if the image fails to load | |
| this.parentElement.style.display = 'none'; | |
| }; | |
| }); | |
| getData(); | |
| }, 500); | |
| } | |
| function updateTable(data) { | |
| Papa.parse(data, { | |
| header: true, | |
| skipEmptyLines: true, | |
| complete: function (results) { | |
| const tbody = document.querySelector('#dataTable tbody'); | |
| tbody.innerHTML = ''; // Clear existing rows | |
| results.data.forEach(row => { | |
| const RECEIPTNUMBER = row['RECEIPTNUMBER'] || ''; | |
| const MERCHANTNAME = row['MERCHANTNAME'] || ''; | |
| const MERCHANTADDRESS = row['MERCHANTADDRESS'] || ''; | |
| const TRANSACTIONDATE = row['TRANSACTIONDATE'] || ''; | |
| const TRANSACTIONTIME = row['TRANSACTIONTIME'] || ''; | |
| const ITEMS = row['ITEMS'] || ''; | |
| const PRICE = row['PRICE'] || ''; | |
| const TOTAL = row['TOTAL'] || ''; | |
| const VATTAX = row['VATTAX'] || ''; | |
| const tr = document.createElement('tr'); | |
| tr.innerHTML = ` | |
| <td contenteditable="true">${RECEIPTNUMBER}</td> | |
| <td contenteditable="true">${MERCHANTNAME}</td> | |
| <td contenteditable="true">${MERCHANTADDRESS}</td> | |
| <td contenteditable="true">${TRANSACTIONDATE}</td> | |
| <td contenteditable="true">${TRANSACTIONTIME}</td> | |
| <td contenteditable="true">${ITEMS}</td> | |
| <td contenteditable="true">${PRICE}</td> | |
| <td contenteditable="true">${TOTAL}</td> | |
| <td contenteditable="true">${VATTAX}</td> | |
| `; | |
| tbody.appendChild(tr); | |
| }); | |
| } | |
| }); | |
| } | |
| }); | |
| document.querySelector('#downloadButton').addEventListener('click', function (event) { | |
| event.preventDefault(); // Prevent the default action | |
| const tbody = document.querySelector('#dataTable tbody'); | |
| const rows = Array.from(tbody.querySelectorAll('tr')); | |
| // Define your headers | |
| const headers = ['RECEIPTNUMBER', 'MERCHANTNAME', 'MERCHANTADDRESS', 'TRANSACTIONDATE', 'TRANSACTIONTIME', 'ITEMS', 'PRICE', 'TOTAL', 'VATTAX']; | |
| // Convert the content to CSV format | |
| const csvData = [headers.join(',')].concat(rows.map(row => { | |
| const cells = Array.from(row.querySelectorAll('td')); | |
| return cells.map(cell => cell.textContent.replace(/,/g, '.')).join(','); | |
| })).join('\n'); | |
| // Send a POST request to the server with the CSV data | |
| fetch(index_url + 'download_csv', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'text/csv' | |
| }, | |
| body: csvData | |
| }) | |
| .then(response => response.blob()) | |
| .then(blob => { | |
| // Create a Blob URL and initiate the download | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'data.csv'; | |
| a.click(); | |
| }); | |
| }); | |
| </script> | |
| <!-- Include JavaScript resources --> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script> | |
| <script src="/static/js/jquery.1.8.3.min.js"></script> | |
| <script src="/static/js/wow.min.js"></script> | |
| <script src="/static/js/featherlight.min.js"></script> | |
| <script src="/static/js/featherlight.gallery.min.js"></script> | |
| <script src="/static/js/jquery.enllax.min.js"></script> | |
| <script src="/static/js/jquery.scrollUp.min.js"></script> | |
| <script src="/static/js/jquery.easing.min.js"></script> | |
| <script src="/static/js/jquery.stickyNavbar.min.js"></script> | |
| <script src="/static/js/jquery.waypoints.min.js"></script> | |
| <script src="/static/js/images-loaded.min.js"></script> | |
| <script src="/static/js/lightbox.min.js"></script> | |
| <script src="/static/js/site.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.5.0/fabric.min.js"></script> | |
| </body> | |
| </html> |