Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Document Similarity Checker</title> | |
| <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=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style> | |
| body { | |
| font-family: 'Inter', sans-serif; | |
| background: linear-gradient(to bottom right, #141e30, #243b55); | |
| } | |
| .card { | |
| backdrop-filter: blur(10px); | |
| background-color: rgba(40, 50, 60, 0.7); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| transition: transform 0.3s ease-in-out, box-shadow 0.3s ease-in-out; | |
| } | |
| .card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2); | |
| } | |
| .file-input-wrapper { | |
| transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out; | |
| } | |
| </style> | |
| </head> | |
| <body class="flex items-center justify-center min-h-screen p-4"> | |
| <!-- Main application container with a modern card design --> | |
| <div class="card p-8 rounded-3xl shadow-2xl max-w-lg w-full text-center"> | |
| <h1 class="text-4xl font-bold text-white mb-2 tracking-wide">DocChecker</h1> | |
| <p class="text-base text-gray-400 mb-8">Upload two .docx files to check their content similarity.</p> | |
| <!-- Form for file uploads --> | |
| <form id="uploadForm" class="space-y-6"> | |
| <div> | |
| <label for="file1" class="block text-left text-sm font-medium text-gray-300 mb-1">Base Document</label> | |
| <label for="file1" class="file-input-wrapper flex items-center justify-center space-x-2 cursor-pointer bg-gray-700 hover:bg-gray-600 rounded-lg p-4 transition duration-300 ease-in-out border-2 border-solid border-gray-600 focus-within:border-cyan-500"> | |
| <input type="file" id="file1" name="file1" accept=".docx" required class="hidden"> | |
| <!-- SVG icon for a document --> | |
| <svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 13h6m-3-3v6m5 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path> | |
| </svg> | |
| <span id="file1-name" class="text-sm font-medium text-gray-400">Choose a .docx file...</span> | |
| </label> | |
| </div> | |
| <div> | |
| <label for="file2" class="block text-left text-sm font-medium text-gray-300 mb-1">Candidate Document</label> | |
| <label for="file2" class="file-input-wrapper flex items-center justify-center space-x-2 cursor-pointer bg-gray-700 hover:bg-gray-600 rounded-lg p-4 transition duration-300 ease-in-out border-2 border-solid border-gray-600 focus-within:border-cyan-500"> | |
| <input type="file" id="file2" name="file2" accept=".docx" required class="hidden"> | |
| <!-- SVG icon for a document --> | |
| <svg class="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 13h6m-3-3v6m5 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path> | |
| </svg> | |
| <span id="file2-name" class="text-sm font-medium text-gray-400">Choose a .docx file...</span> | |
| </label> | |
| </div> | |
| <!-- Submit button with a hover and active effect --> | |
| <button type="submit" id="submitBtn" class="w-full py-3 px-4 bg-cyan-500 text-white font-semibold rounded-full | |
| shadow-lg hover:bg-cyan-600 focus:outline-none focus:ring-2 focus:ring-cyan-500 | |
| focus:ring-offset-2 focus:ring-offset-gray-800 transition duration-300 ease-in-out | |
| transform hover:scale-105 active:scale-95"> | |
| Check Similarity | |
| </button> | |
| </form> | |
| <!-- Area for displaying results or messages --> | |
| <div id="resultContainer" class="mt-8 relative min-h-[100px] flex items-center justify-center"> | |
| <!-- Loading spinner with animation --> | |
| <div id="loading" class="hidden text-center absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 opacity-0 transition-opacity duration-500 ease-in-out"> | |
| <div class="inline-block h-10 w-10 animate-spin rounded-full border-4 border-solid border-current border-r-transparent text-cyan-400" role="status"> | |
| <span class="!absolute !-m-px !h-px !w-px !overflow-hidden !whitespace-nowrap !border-0 !p-0 ![clip:rect(0,0,0,0)]">Loading...</span> | |
| </div> | |
| <p class="mt-3 text-sm text-gray-400">Checking files...</p> | |
| </div> | |
| <!-- Result display area with fade-in effect --> | |
| <div id="result" class="hidden absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 opacity-0 transition-opacity duration-500 ease-in-out"> | |
| <p class="text-xl text-gray-300">Similarity Score:</p> | |
| <p id="score" class="text-6xl font-extrabold text-cyan-400 mt-2"></p> | |
| </div> | |
| <!-- Error message display area with fade-in effect --> | |
| <div id="error" class="hidden absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 opacity-0 transition-opacity duration-500 ease-in-out"> | |
| <p id="errorMessage" class="text-red-400 text-sm font-medium mt-2"></p> | |
| </div> | |
| </div> | |
| <!-- Developer Information Section --> | |
| <div class="mt-12 pt-6 border-t border-gray-700 text-gray-400 text-sm"> | |
| <p class="mb-2">Developed by Muhammad Hamza</p> | |
| <div class="flex justify-center space-x-6"> | |
| <a href="https://github.com/MuhammadHamza123c" target="_blank" class="hover:text-white transition duration-200" title="GitHub"> | |
| <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true"> | |
| <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.956 0-1.091.39-1.984 1.029-2.682-.103-.253-.446-1.272.098-2.651 0 0 .84-.268 2.75 1.022A9.615 9.615 0 0112 6.865c.85.006 1.704.114 2.504.337 1.909-1.29 2.747-1.022 2.747-1.022.546 1.379.202 2.398.099 2.651.64.698 1.028 1.591 1.028 2.682 0 3.854-2.339 4.691-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd" /> | |
| </svg> | |
| </a> | |
| <a href="https://www.linkedin.com/in/muhammad-hamzads/" target="_blank" class="hover:text-white transition duration-200" title="LinkedIn"> | |
| <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"> | |
| <path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/> | |
| </svg> | |
| </a> | |
| <a href="mailto:muhammadhamzao241@gmaul.com" target="_blank" class="hover:text-white transition duration-200" title="Email"> | |
| <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"> | |
| <path d="M12 12.713l-11.985-9.713h23.97l-11.985 9.713zm0 2.574l-12-9.722v16.435h24v-16.435l-12 9.722z"/> | |
| </svg> | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const form = document.getElementById('uploadForm'); | |
| const file1Input = document.getElementById('file1'); | |
| const file2Input = document.getElementById('file2'); | |
| const submitBtn = document.getElementById('submitBtn'); | |
| const loading = document.getElementById('loading'); | |
| const resultDiv = document.getElementById('result'); | |
| const scoreSpan = document.getElementById('score'); | |
| const errorDiv = document.getElementById('error'); | |
| const errorMessageSpan = document.getElementById('errorMessage'); | |
| // The base URL for the FastAPI service | |
| const baseUrl = 'https://humza7656-my-doc-checker.hf.space'; | |
| // Function to show a message box by fading in the content | |
| function showMessage(element, message, isError = false) { | |
| // Hide all result containers first | |
| loading.classList.add('hidden', 'opacity-0'); | |
| resultDiv.classList.add('hidden', 'opacity-0'); | |
| errorDiv.classList.add('hidden', 'opacity-0'); | |
| if (isError) { | |
| errorMessageSpan.textContent = message; | |
| } else { | |
| scoreSpan.textContent = message; | |
| } | |
| // Show the specific element and fade it in | |
| element.classList.remove('hidden'); | |
| setTimeout(() => element.classList.remove('opacity-0'), 10); | |
| } | |
| // Update the display text for file inputs | |
| file1Input.addEventListener('change', (event) => { | |
| const fileName = event.target.files[0] ? event.target.files[0].name : 'Choose a .docx file...'; | |
| document.getElementById('file1-name').textContent = fileName; | |
| }); | |
| file2Input.addEventListener('change', (event) => { | |
| const fileName = event.target.files[0] ? event.target.files[0].name : 'Choose a .docx file...'; | |
| document.getElementById('file2-name').textContent = fileName; | |
| }); | |
| form.addEventListener('submit', async (e) => { | |
| e.preventDefault(); | |
| // Get the files from the input fields | |
| const file1 = file1Input.files[0]; | |
| const file2 = file2Input.files[0]; | |
| // Simple client-side validation for file types | |
| if (!file1 || !file2) { | |
| showMessage(errorDiv, 'Please select both files.', true); | |
| return; | |
| } | |
| if (!file1.name.endsWith('.docx') || !file2.name.endsWith('.docx')) { | |
| showMessage(errorDiv, 'Both files must be of type .docx', true); | |
| return; | |
| } | |
| // Show loading state | |
| showMessage(loading, '', false); | |
| submitBtn.disabled = true; | |
| // Create a FormData object to send the files | |
| const formData = new FormData(); | |
| formData.append('f1', file1); | |
| formData.append('f2', file2); | |
| try { | |
| const response = await fetch(`${baseUrl}/similar_doc`, { | |
| method: 'POST', | |
| body: formData | |
| }); | |
| const data = await response.json(); | |
| if (response.ok) { | |
| // API call was successful | |
| const similarity = data.Similarity; | |
| showMessage(resultDiv, similarity.toFixed(2)); | |
| } else { | |
| // API returned an error | |
| const errorMsg = data.error || 'An unknown error occurred.'; | |
| showMessage(errorDiv, errorMsg, true); | |
| } | |
| } catch (error) { | |
| // Network or other fetch-related error | |
| console.error('Error:', error); | |
| showMessage(errorDiv, 'Could not connect to the API. Please try again later.', true); | |
| } finally { | |
| // Re-enable button | |
| submitBtn.disabled = false; | |
| } | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |