Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>AI Data Extractor - Visiting Card</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600&display=swap" rel="stylesheet"> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" /> | |
| <style> | |
| :root { | |
| --primary: #ee4410; | |
| --secondary: #ff9f0a; | |
| --bg-dark: #0a0a0c; | |
| --card-bg: rgba(30, 30, 35, 0.7); | |
| --text-glow: 0 0 10px rgba(238, 68, 16, 0.5); | |
| } | |
| body { | |
| background-color: var(--bg-dark); | |
| font-family: 'Outfit', sans-serif; | |
| color: #f5f5f7; | |
| overflow-x: hidden; | |
| background: radial-gradient(circle at 50% 50%, #1a1a1f 0%, #0a0a0c 100%); | |
| min-height: 100vh; | |
| } | |
| .glass-card { | |
| background: var(--card-bg); | |
| backdrop-filter: blur(12px); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 20px; | |
| box-shadow: 0 15px 35px rgba(0, 0, 0, 0.4); | |
| padding: 2.5rem; | |
| margin-top: 2rem; | |
| } | |
| .premium-title { | |
| background: linear-gradient(135deg, #fff 0%, #aaa 100%); | |
| -webkit-background-clip: text; | |
| background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| font-weight: 600; | |
| letter-spacing: -1px; | |
| text-shadow: var(--text-glow); | |
| margin-bottom: 2rem; | |
| text-align: center; | |
| } | |
| .top-bar { | |
| background: rgba(20, 20, 25, 0.8); | |
| backdrop-filter: blur(10px); | |
| padding: 1rem 2rem; | |
| border-bottom: 1px solid rgba(255, 255, 255, 0.05); | |
| position: sticky; | |
| top: 0; | |
| z-index: 1000; | |
| } | |
| .tab-btn { | |
| background: transparent; | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| color: #8e8e93; | |
| padding: 0.6rem 1.2rem; | |
| border-radius: 30px; | |
| margin-right: 10px; | |
| transition: all 0.3s ease; | |
| text-decoration: none; | |
| font-size: 0.9rem; | |
| } | |
| .tab-btn:hover, .tab-btn.active { | |
| border-color: var(--primary); | |
| color: #fff; | |
| background: rgba(238, 68, 16, 0.1); | |
| } | |
| .tab-btn.active { | |
| box-shadow: 0 0 15px rgba(238, 68, 16, 0.2); | |
| } | |
| .upload-area { | |
| border: 2px dashed rgba(255, 255, 255, 0.1); | |
| border-radius: 15px; | |
| padding: 3rem; | |
| text-align: center; | |
| transition: all 0.3s ease; | |
| cursor: pointer; | |
| margin-bottom: 2rem; | |
| } | |
| .upload-area:hover { | |
| border-color: var(--primary); | |
| background: rgba(238, 68, 16, 0.05); | |
| } | |
| .btn-premium { | |
| background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%); | |
| border: none; | |
| color: white; | |
| padding: 0.8rem 2rem; | |
| border-radius: 30px; | |
| font-weight: 600; | |
| box-shadow: 0 5px 15px rgba(238, 68, 16, 0.3); | |
| transition: all 0.3s ease; | |
| width: 100%; | |
| } | |
| .btn-premium:hover:not(:disabled) { | |
| transform: scale(1.02); | |
| box-shadow: 0 8px 25px rgba(238, 68, 16, 0.5); | |
| } | |
| .btn-premium:disabled { | |
| opacity: 0.6; | |
| cursor: not-allowed; | |
| } | |
| .loader { | |
| display: none; | |
| width: 40px; | |
| height: 40px; | |
| border: 3px solid rgba(255,255,255,0.1); | |
| border-top: 3px solid var(--primary); | |
| border-radius: 50%; | |
| animation: spin 1s linear infinite; | |
| margin: 2rem auto; | |
| } | |
| @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } | |
| .alert-premium { | |
| background: rgba(40, 40, 45, 0.9); | |
| border: 1px solid var(--primary); | |
| color: #fff; | |
| border-radius: 12px; | |
| padding: 1rem; | |
| margin-top: 1.5rem; | |
| text-align: center; | |
| } | |
| .file-list { | |
| margin-top: 1.5rem; | |
| padding: 1rem; | |
| background: rgba(0, 0, 0, 0.2); | |
| border-radius: 10px; | |
| font-size: 0.9rem; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="top-bar d-flex justify-content-between align-items-center"> | |
| <h4 class="mb-0 text-white" style="font-weight: 600; letter-spacing: -0.5px;">AI EXtractor</h4> | |
| <div class="d-none d-md-flex"> | |
| <a href="#" class="tab-btn active">Visiting Card</a> | |
| <a href="https://webashalarforml-resumeextractor2.hf.space/" class="tab-btn">Resume Detail</a> | |
| </div> | |
| </div> | |
| <div class="container py-5"> | |
| <div class="row justify-content-center"> | |
| <div class="col-lg-6"> | |
| <div class="glass-card"> | |
| <h1 class="premium-title">Card Scanner <small style="display: block; font-size: 0.4em; letter-spacing: 2px; color: var(--primary); margin-top: 5px;">POWERED BY GROQ VLM</small></h1> | |
| <form id="uploadForm" action="{{ url_for('upload_file') }}" method="POST" enctype="multipart/form-data"> | |
| <div class="upload-area" onclick="document.getElementById('fileInput').click()"> | |
| <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="currentColor" class="bi bi-cloud-upload text-muted mb-3" viewBox="0 0 16 16"> | |
| <path fill-rule="evenodd" d="M4.406 3.342A5.53 5.53 0 0 1 8 2c2.69 0 4.923 2 5.166 4.579C14.758 6.804 16 8.137 16 9.773 16 11.569 14.502 13 12.687 13H3.781C1.708 13 0 11.366 0 9.318c0-1.763 1.266-3.223 2.942-3.593.143-.863.698-1.723 1.464-2.383zm.653.757c-.757.653-1.153 1.44-1.153 2.056v.448l-.445.049C2.064 6.805 1 7.952 1 9.318 1 10.785 2.23 12 3.781 12h8.906C13.98 12 15 10.988 15 9.773c0-1.216-1.02-2.228-2.313-2.228h-.5v-.5C12.188 4.825 10.328 3 8 3a4.53 4.53 0 0 0-2.941 1.1z"/> | |
| <path fill-rule="evenodd" d="M7.646 5.146a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1-.708.708L8.5 6.707V10.5a.5.5 0 0 1-1 0V6.707L6.354 7.854a.5.5 0 1 1-.708-.708l2-2z"/> | |
| </svg> | |
| <p class="mb-0 text-muted">Click or Drag & Drop Business Cards</p> | |
| <input type="file" name="files" id="fileInput" multiple style="display: none;" required onchange="updateFileList(this)" /> | |
| </div> | |
| <div id="fileList" class="file-list" style="display: none;"></div> | |
| <button type="submit" id="submitBtn" class="btn-premium mt-3">Start Extraction</button> | |
| </form> | |
| <div class="loader" id="loader"></div> | |
| <p id="loadingMsg" class="text-center text-muted small mt-2" style="display: none;">Analyzing images with AI engine...</p> | |
| {% if session.get('uploaded_files') %} | |
| <div class="mt-4 pt-3 border-top border-secondary"> | |
| <div class="d-flex justify-content-between align-items-center"> | |
| <span class="small text-muted">Ready to process: {{ session.get('uploaded_files')|length }} files</span> | |
| <a href="{{ url_for('reset_upload') }}" class="text-danger small text-decoration-none">Clear All</a> | |
| </div> | |
| </div> | |
| {% endif %} | |
| {% with messages = get_flashed_messages() %} | |
| {% if messages %} | |
| <div class="alert-premium" id="flashMessage"> | |
| {{ messages[0] }} | |
| </div> | |
| {% endif %} | |
| {% endwith %} | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| function updateFileList(input) { | |
| const list = document.getElementById('fileList'); | |
| if (input.files.length > 0) { | |
| list.style.display = 'block'; | |
| list.innerHTML = '<strong>Selected:</strong><br>' + | |
| Array.from(input.files).map(f => f.name).join('<br>'); | |
| } else { | |
| list.style.display = 'none'; | |
| } | |
| } | |
| document.getElementById('uploadForm').onsubmit = function() { | |
| document.getElementById('loader').style.display = 'block'; | |
| document.getElementById('loadingMsg').style.display = 'block'; | |
| document.getElementById('submitBtn').disabled = true; | |
| document.getElementById('submitBtn').innerText = 'Processing...'; | |
| }; | |
| // Flash message auto-hide | |
| setTimeout(() => { | |
| const flash = document.getElementById('flashMessage'); | |
| if (flash) { | |
| flash.style.transition = 'opacity 1s ease'; | |
| flash.style.opacity = '0'; | |
| setTimeout(() => flash.remove(), 1000); | |
| } | |
| }, 4000); | |
| </script> | |
| </body> | |
| </html> | |