Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>SAM3 Video Object Extractor</title> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| :root { | |
| --primary: #6366f1; | |
| --primary-dark: #4f46e5; | |
| --secondary: #8b5cf6; | |
| --accent: #ec4899; | |
| --dark: #1e293b; | |
| --light: #f8fafc; | |
| --gray: #64748b; | |
| --success: #10b981; | |
| --warning: #f59e0b; | |
| --danger: #ef4444; | |
| --gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| --shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); | |
| --shadow-lg: 0 25px 50px -12px rgba(0, 0, 0, 0.25); | |
| } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| color: var(--dark); | |
| position: relative; | |
| overflow-x: hidden; | |
| } | |
| body::before { | |
| content: ''; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: url('data:image/svg+xml,%3Csvg width="60" height="60" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg"%3E%3Cg fill="none" fill-rule="evenodd"%3E%3Cg fill="%23ffffff" fill-opacity="0.05"%3E%3Cpath d="M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z"/%3E%3C/g%3E%3C/g%3E%3C/svg%3E') repeat; | |
| pointer-events: none; | |
| z-index: 1; | |
| } | |
| .container { | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| position: relative; | |
| z-index: 2; | |
| } | |
| header { | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(10px); | |
| border-radius: 20px; | |
| padding: 30px; | |
| margin-bottom: 30px; | |
| box-shadow: var(--shadow-lg); | |
| animation: slideDown 0.5s ease-out; | |
| } | |
| @keyframes slideDown { | |
| from { | |
| opacity: 0; | |
| transform: translateY(-30px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .header-content { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| flex-wrap: wrap; | |
| gap: 20px; | |
| } | |
| .logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 15px; | |
| } | |
| .logo-icon { | |
| width: 50px; | |
| height: 50px; | |
| background: var(--gradient); | |
| border-radius: 15px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 24px; | |
| color: white; | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { transform: scale(1); } | |
| 50% { transform: scale(1.05); } | |
| } | |
| h1 { | |
| font-size: 28px; | |
| background: var(--gradient); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| .credit { | |
| font-size: 12px; | |
| color: var(--gray); | |
| text-decoration: none; | |
| transition: color 0.3s; | |
| } | |
| .credit:hover { | |
| color: var(--primary); | |
| } | |
| .main-content { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 30px; | |
| margin-bottom: 30px; | |
| } | |
| @media (max-width: 968px) { | |
| .main-content { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| .card { | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(10px); | |
| border-radius: 20px; | |
| padding: 30px; | |
| box-shadow: var(--shadow); | |
| animation: fadeIn 0.6s ease-out; | |
| animation-fill-mode: both; | |
| } | |
| .card:nth-child(2) { | |
| animation-delay: 0.1s; | |
| } | |
| @keyframes fadeIn { | |
| from { | |
| opacity: 0; | |
| transform: translateY(20px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .card-header { | |
| display: flex; | |
| align-items: center; | |
| gap: 15px; | |
| margin-bottom: 25px; | |
| padding-bottom: 15px; | |
| border-bottom: 2px solid var(--light); | |
| } | |
| .card-icon { | |
| width: 40px; | |
| height: 40px; | |
| background: linear-gradient(135deg, var(--primary), var(--secondary)); | |
| border-radius: 12px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: white; | |
| font-size: 20px; | |
| } | |
| h2 { | |
| font-size: 20px; | |
| color: var(--dark); | |
| } | |
| .upload-area { | |
| border: 3px dashed var(--primary); | |
| border-radius: 15px; | |
| padding: 40px; | |
| text-align: center; | |
| background: linear-gradient(135deg, rgba(99, 102, 241, 0.05), rgba(139, 92, 246, 0.05)); | |
| transition: all 0.3s; | |
| cursor: pointer; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .upload-area:hover { | |
| border-color: var(--secondary); | |
| background: linear-gradient(135deg, rgba(99, 102, 241, 0.1), rgba(139, 92, 246, 0.1)); | |
| transform: translateY(-2px); | |
| } | |
| .upload-area.dragover { | |
| border-color: var(--accent); | |
| background: linear-gradient(135deg, rgba(236, 72, 153, 0.1), rgba(139, 92, 246, 0.1)); | |
| } | |
| .upload-icon { | |
| font-size: 48px; | |
| color: var(--primary); | |
| margin-bottom: 15px; | |
| } | |
| .upload-text { | |
| color: var(--gray); | |
| margin-bottom: 10px; | |
| } | |
| .upload-button { | |
| background: var(--gradient); | |
| color: white; | |
| border: none; | |
| padding: 12px 30px; | |
| border-radius: 10px; | |
| font-size: 16px; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| display: inline-block; | |
| margin-top: 10px; | |
| } | |
| .upload-button:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 10px 20px rgba(99, 102, 241, 0.3); | |
| } | |
| input[type="file"] { | |
| display: none; | |
| } | |
| .video-preview { | |
| margin-top: 20px; | |
| border-radius: 15px; | |
| overflow: hidden; | |
| box-shadow: var(--shadow); | |
| position: relative; | |
| background: var(--dark); | |
| } | |
| video { | |
| width: 100%; | |
| height: auto; | |
| display: block; | |
| } | |
| .video-info { | |
| position: absolute; | |
| bottom: 0; | |
| left: 0; | |
| right: 0; | |
| background: linear-gradient(to top, rgba(0,0,0,0.8), transparent); | |
| color: white; | |
| padding: 20px; | |
| transform: translateY(100%); | |
| transition: transform 0.3s; | |
| } | |
| .video-preview:hover .video-info { | |
| transform: translateY(0); | |
| } | |
| .class-selector { | |
| display: grid; | |
| gap: 15px; | |
| } | |
| .class-option { | |
| background: white; | |
| border: 2px solid var(--light); | |
| border-radius: 15px; | |
| padding: 20px; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .class-option::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: var(--gradient); | |
| opacity: 0; | |
| transition: opacity 0.3s; | |
| } | |
| .class-option:hover { | |
| transform: translateY(-3px); | |
| box-shadow: var(--shadow); | |
| } | |
| .class-option.selected { | |
| border-color: var(--primary); | |
| background: linear-gradient(135deg, rgba(99, 102, 241, 0.1), rgba(139, 92, 246, 0.1)); | |
| } | |
| .class-option.selected::before { | |
| opacity: 0.1; | |
| } | |
| .class-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .class-name { | |
| font-weight: 600; | |
| font-size: 18px; | |
| color: var(--dark); | |
| } | |
| .class-icon { | |
| font-size: 24px; | |
| } | |
| .class-description { | |
| color: var(--gray); | |
| margin-top: 8px; | |
| font-size: 14px; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .class-examples { | |
| display: flex; | |
| gap: 8px; | |
| margin-top: 10px; | |
| flex-wrap: wrap; | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .example-tag { | |
| background: var(--light); | |
| color: var(--gray); | |
| padding: 4px 12px; | |
| border-radius: 20px; | |
| font-size: 12px; | |
| } | |
| .process-button { | |
| width: 100%; | |
| background: var(--gradient); | |
| color: white; | |
| border: none; | |
| padding: 15px; | |
| border-radius: 15px; | |
| font-size: 18px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| margin-top: 20px; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .process-button::before { | |
| content: ''; | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| width: 0; | |
| height: 0; | |
| border-radius: 50%; | |
| background: rgba(255, 255, 255, 0.3); | |
| transform: translate(-50%, -50%); | |
| transition: width 0.6s, height 0.6s; | |
| } | |
| .process-button:hover::before { | |
| width: 300px; | |
| height: 300px; | |
| } | |
| .process-button:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 15px 30px rgba(99, 102, 241, 0.4); | |
| } | |
| .process-button:disabled { | |
| opacity: 0.5; | |
| cursor: not-allowed; | |
| } | |
| .progress-section { | |
| display: none; | |
| margin-top: 30px; | |
| padding: 25px; | |
| background: linear-gradient(135deg, rgba(99, 102, 241, 0.1), rgba(139, 92, 246, 0.1)); | |
| border-radius: 15px; | |
| animation: slideUp 0.3s ease-out; | |
| } | |
| @keyframes slideUp { | |
| from { | |
| opacity: 0; | |
| transform: translateY(20px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .progress-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 15px; | |
| } | |
| .progress-title { | |
| font-weight: 600; | |
| color: var(--dark); | |
| } | |
| .progress-percentage { | |
| font-weight: 600; | |
| color: var(--primary); | |
| } | |
| .progress-bar { | |
| width: 100%; | |
| height: 8px; | |
| background: var(--light); | |
| border-radius: 10px; | |
| overflow: hidden; | |
| position: relative; | |
| } | |
| .progress-fill { | |
| height: 100%; | |
| background: var(--gradient); | |
| border-radius: 10px; | |
| width: 0%; | |
| transition: width 0.3s; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .progress-fill::after { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); | |
| animation: shimmer 1.5s infinite; | |
| } | |
| @keyframes shimmer { | |
| 0% { transform: translateX(-100%); } | |
| 100% { transform: translateX(100%); } | |
| } | |
| .progress-steps { | |
| margin-top: 20px; | |
| display: grid; | |
| gap: 10px; | |
| } | |
| .step { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| color: var(--gray); | |
| font-size: 14px; | |
| transition: color 0.3s; | |
| } | |
| .step.active { | |
| color: var(--primary); | |
| } | |
| .step.completed { | |
| color: var(--success); | |
| } | |
| .step-icon { | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 50%; | |
| border: 2px solid currentColor; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 12px; | |
| transition: all 0.3s; | |
| } | |
| .step.active .step-icon { | |
| background: var(--primary); | |
| border-color: var(--primary); | |
| color: white; | |
| animation: spin 1s linear infinite; | |
| } | |
| @keyframes spin { | |
| from { transform: rotate(0deg); } | |
| to { transform: rotate(360deg); } | |
| } | |
| .step.completed .step-icon { | |
| background: var(--success); | |
| border-color: var(--success); | |
| color: white; | |
| } | |
| .results-section { | |
| display: none; | |
| margin-top: 30px; | |
| animation: fadeIn 0.5s ease-out; | |
| } | |
| .results-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 25px; | |
| padding-bottom: 15px; | |
| border-bottom: 2px solid var(--light); | |
| } | |
| .results-stats { | |
| display: flex; | |
| gap: 20px; | |
| } | |
| .stat { | |
| text-align: center; | |
| } | |
| .stat-value { | |
| font-size: 24px; | |
| font-weight: bold; | |
| color: var(--primary); | |
| } | |
| .stat-label { | |
| font-size: 12px; | |
| color: var(--gray); | |
| text-transform: uppercase; | |
| letter-spacing: 1px; | |
| } | |
| .export-button { | |
| background: var(--success); | |
| color: white; | |
| border: none; | |
| padding: 10px 20px; | |
| border-radius: 10px; | |
| font-size: 14px; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .export-button:hover { | |
| background: #059669; | |
| transform: translateY(-2px); | |
| box-shadow: 0 10px 20px rgba(16, 185, 129, 0.3); | |
| } | |
| .objects-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); | |
| gap: 20px; | |
| margin-top: 20px; | |
| } | |
| .object-card { | |
| background: white; | |
| border-radius: 15px; | |
| overflow: hidden; | |
| box-shadow: var(--shadow); | |
| transition: all 0.3s; | |
| cursor: pointer; | |
| animation: scaleIn 0.3s ease-out; | |
| animation-fill-mode: both; | |
| } | |
| .object-card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: var(--shadow-lg); | |
| } | |
| @keyframes scaleIn { | |
| from { | |
| opacity: 0; | |
| transform: scale(0.8); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: scale(1); | |
| } | |
| } | |
| .object-thumbnail { | |
| width: 100%; | |
| height: 150px; | |
| background: var(--light); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .object-thumbnail img { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| } | |
| .object-overlay { | |
| position: absolute; | |
| top: 10px; | |
| right: 10px; | |
| background: rgba(99, 102, 241, 0.9); | |
| color: white; | |
| padding: 5px 10px; | |
| border-radius: 20px; | |
| font-size: 12px; | |
| font-weight: 600; | |
| } | |
| .object-info { | |
| padding: 15px; | |
| } | |
| .object-name { | |
| font-weight: 600; | |
| color: var(--dark); | |
| margin-bottom: 5px; | |
| } | |
| .object-details { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-top: 10px; | |
| padding-top: 10px; | |
| border-top: 1px solid var(--light); | |
| } | |
| .object-confidence { | |
| font-size: 12px; | |
| color: var(--gray); | |
| } | |
| .object-time { | |
| font-size: 12px; | |
| color: var(--gray); | |
| } | |
| .confidence-bar { | |
| display: inline-block; | |
| width: 50px; | |
| height: 4px; | |
| background: var(--light); | |
| border-radius: 2px; | |
| margin-left: 5px; | |
| position: relative; | |
| vertical-align: middle; | |
| } | |
| .confidence-fill { | |
| position: absolute; | |
| left: 0; | |
| top: 0; | |
| height: 100%; | |
| background: var(--success); | |
| border-radius: 2px; | |
| } | |
| .modal { | |
| display: none; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: rgba(0, 0, 0, 0.8); | |
| z-index: 1000; | |
| animation: fadeIn 0.3s; | |
| } | |
| .modal.active { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .modal-content { | |
| background: white; | |
| border-radius: 20px; | |
| max-width: 90%; | |
| max-height: 90%; | |
| overflow: auto; | |
| animation: scaleIn 0.3s; | |
| } | |
| .modal-header { | |
| padding: 20px; | |
| border-bottom: 1px solid var(--light); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .modal-close { | |
| width: 30px; | |
| height: 30px; | |
| border-radius: 50%; | |
| background: var(--light); | |
| border: none; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| transition: all 0.3s; | |
| } | |
| .modal-close:hover { | |
| background: var(--danger); | |
| color: white; | |
| } | |
| .modal-body { | |
| padding: 20px; | |
| } | |
| .modal-image { | |
| width: 100%; | |
| max-width: 800px; | |
| border-radius: 10px; | |
| } | |
| .notification { | |
| position: fixed; | |
| top: 20px; | |
| right: 20px; | |
| background: white; | |
| padding: 15px 20px; | |
| border-radius: 10px; | |
| box-shadow: var(--shadow-lg); | |
| display: flex; | |
| align-items: center; | |
| gap: 15px; | |
| z-index: 2000; | |
| animation: slideInRight 0.3s; | |
| max-width: 350px; | |
| } | |
| @keyframes slideInRight { | |
| from { | |
| opacity: 0; | |
| transform: translateX(100%); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateX(0); | |
| } | |
| } | |
| .notification.success { | |
| border-left: 4px solid var(--success); | |
| } | |
| .notification.error { | |
| border-left: 4px solid var(--danger); | |
| } | |
| .notification-icon { | |
| font-size: 20px; | |
| } | |
| .notification.success .notification-icon { | |
| color: var(--success); | |
| } | |
| .notification.error .notification-icon { | |
| color: var(--danger); | |
| } | |
| .notification-content { | |
| flex: 1; | |
| } | |
| .notification-title { | |
| font-weight: 600; | |
| margin-bottom: 2px; | |
| } | |
| .notification-message { | |
| font-size: 14px; | |
| color: var(--gray); | |
| } | |
| @media (max-width: 640px) { | |
| .container { | |
| padding: 10px; | |
| } | |
| .card { | |
| padding: 20px; | |
| } | |
| h1 { | |
| font-size: 24px; | |
| } | |
| .objects-grid { | |
| grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); | |
| gap: 15px; | |
| } | |
| .notification { | |
| right: 10px; | |
| left: 10px; | |
| max-width: none; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header> | |
| <div class="header-content"> | |
| <div class="logo"> | |
| <div class="logo-icon">🎯</div> | |
| <div> | |
| <h1>SAM3 Video Object Extractor</h1> | |
| <p style="color: var(--gray); margin-top: 5px;">AI-powered object detection and extraction</p> | |
| </div> | |
| </div> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="credit">Built with anycoder</a> | |
| </div> | |
| </header> | |
| <div class="main-content"> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <div class="card-icon">📹</div> | |
| <h2>Upload Video</h2> | |
| </div> | |
| <div class="upload-area" id="uploadArea"> | |
| <div class="upload-icon">📁</div> | |
| <p class="upload-text">Drag & drop your video here</p> | |
| <p style="color: var(--gray); font-size: 14px;">or</p> | |
| <button class="upload-button">Browse Files</button> | |
| <input type="file" id="fileInput" accept="video/*"> | |
| <p style="color: var(--gray); font-size: 12px; margin-top: 15px;">Supported formats: MP4, AVI, MOV, MKV (Max 100MB)</p> | |
| </div> | |
| <div class="video-preview" id="videoPreview" style="display: none;"> | |
| <video id="uploadedVideo" controls></video> | |
| <div class="video-info"> | |
| <strong id="videoName">video.mp4</strong> | |
| <p id="videoSize">Size: 0 MB</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-header"> | |
| <div class="card-icon">🏷️</div> | |
| <h2>Select Object Class</h2> | |
| </div> | |
| <div class="class-selector"> | |
| <div class="class-option" data-class="home-objects"> | |
| <div class="class-header"> | |
| <span class="class-name">Home Objects</span> | |
| <span class="class-icon">🏠</span> | |
| </div> | |
| <p class="class-description">Everyday household items and decorative objects</p> | |
| <div class="class-examples"> | |
| <span class="example-tag">Mugs</span> | |
| <span class="example-tag">Bowls</span> | |
| <span class="example-tag">Plates</span> | |
| <span class="example-tag">Vases</span> | |
| <span class="example-tag">Lamps</span> | |
| </div> | |
| </div> | |
| <div class="class-option" data-class="furniture"> | |
| <div class="class-header"> | |
| <span class="class-name">Furniture</span> | |
| <span class="class-icon">🪑</span> | |
| </div> | |
| <p class="class-description">Large furniture pieces and fixtures</p> | |
| <div class="class-examples"> | |
| <span class="example-tag">Chairs</span> | |
| <span class="example-tag">Tables</span> | |
| <span class="example-tag">Sofas</span> | |
| <span class="example-tag">Beds</span> | |
| <span class="example-tag">Cabinets</span> | |
| </div> | |
| </div> | |
| <div class="class-option" data-class="building"> | |
| <div class="class-header"> | |
| <span class="class-name">Building Elements</span> | |
| <span class="class-icon">🏢</span> | |
| </div> | |
| <p class="class-description">Architectural and structural components</p> | |
| <div class="class-examples"> | |
| <span class="example-tag">Walls</span> | |
| <span class="example-tag">Windows</span> | |
| <span class="example-tag">Doors</span> | |
| <span class="example-tag">Stairs</span> | |
| <span class="example-tag">Columns</span> | |
| </div> | |
| </div> | |
| </div> | |
| <button class="process-button" id="processButton" disabled> | |
| Process Video | |
| </button> | |
| </div> | |
| </div> | |
| <div class="progress-section" id="progressSection"> | |
| <div class="progress-header"> | |
| <span class="progress-title">Processing Video with SAM3...</span> | |
| <span class="progress-percentage" id="progressPercentage">0%</span> | |
| </div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" id="progressFill"></div> | |
| </div> | |
| <div class="progress-steps"> | |
| <div class="step" id="step1"> | |
| <div class="step-icon">⚡</div> | |
| <span>Initializing SAM3 model...</span> | |
| </div> | |
| <div class="step" id="step2"> | |
| <div class="step-icon">🎬</div> | |
| <span>Extracting video frames...</span> | |
| </div> | |
| <div class="step" id="step3"> | |
| <div class="step-icon">🔍</div> | |
| <span>Detecting objects...</span> | |
| </div> | |
| <div class="step" id="step4"> | |
| <div class="step-icon">✂️</div> | |
| <span>Segmenting instances...</span> | |
| </div> | |
| <div class="step" id="step5"> | |
| <div class="step-icon">📊</div> | |
| <span>Generating results...</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="results-section" id="resultsSection"> | |
| <div class="card"> | |
| <div class="results-header"> | |
| <div> | |
| <h2 style="margin-bottom: 10px;">Extraction Results</h2> | |
| <div class="results-stats"> | |
| <div class="stat"> | |
| <div class="stat-value" id="totalObjects">0</div> | |
| <div class="stat-label">Objects Found</div> | |
| </div> | |
| <div class="stat"> | |
| <div class="stat-value" id="uniqueTypes">0</div> | |
| <div class="stat-label">Unique Types</div> | |
| </div> | |
| <div class="stat"> | |
| <div class="stat-value" id="avgConfidence">0%</div> | |
| <div class="stat-label">Avg Confidence</div> | |
| </div> | |
| </div> | |
| </div> | |
| <button class="export-button" onclick="exportResults()"> | |
| <span>📥</span> | |
| <span>Export Results</span> | |
| </button> | |
| </div> | |
| <div class="objects-grid" id="objectsGrid"> | |
| <!-- Objects will be dynamically added here --> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="modal" id="objectModal"> | |
| <div class="modal-content"> | |
| <div class="modal-header"> | |
| <h3 id="modalTitle">Object Details</h3> | |
| <button class="modal-close" onclick="closeModal()">✕</button> | |
| </div> | |
| <div class="modal-body"> | |
| <img id="modalImage" class="modal-image" src="" alt="Object"> | |
| <div style="margin-top: 20px;"> | |
| <p><strong>Type:</strong> <span id="modalType"></span></p> | |
| <p><strong>Confidence:</strong> <span id="modalConfidence"></span></p> | |
| <p><strong>Timestamp:</strong> <span id="modalTimestamp"></span></p> | |
| <p><strong>Position:</strong> <span id="modalPosition"></span></p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Global variables | |
| let selectedClass = null; | |
| let uploadedFile = null; | |
| let processing = false; | |
| let extractedObjects = []; | |
| // Mock object data generator | |
| const mockObjects = { | |
| 'home-objects': [ | |
| { name: 'Coffee Mug', confidence: 0.95, time: '00:12', position: 'Table' }, | |
| { name: 'Ceramic Bowl', confidence: 0.88, time: '00:25', position: 'Counter' }, | |
| { name: 'Glass Vase', confidence: 0.92, time: '00:38', position: 'Shelf' }, | |
| { name: 'Table Lamp', confidence: 0.87, time: '01:15', position: 'Side Table' }, | |
| { name: 'Decorative Plate', confidence: 0.91, time: '01:42', position: 'Wall' }, | |
| { name: 'Wine Glass', confidence: 0.89, time: '02:05', position: 'Bar' }, | |
| { name: 'Tea Cup', confidence: 0.93, time: '02:28', position: 'Saucer' }, | |
| { name: 'Fruit Bowl', confidence: 0.86, time: '02:51', position: 'Kitchen Island' } | |
| ], | |
| 'furniture': [ | |
| { name: 'Office Chair', confidence: 0.94, time: '00:08', position: 'Desk Area' }, | |
| { name: 'Dining Table', confidence: 0.91, time: '00:31', position: 'Dining Room' }, | |
| { name: 'Sofa', confidence: 0.89, time: '00:55', position: 'Living Room' }, | |
| { name: 'Bookshelf', confidence: 0.92, time: '01:18', position: 'Study' }, | |
| { name: 'Bed Frame', confidence: 0.90, time: '01:45', position: 'Bedroom' }, | |
| { name: 'Wardrobe', confidence: 0.87, time: '02:12', position: 'Closet' }, | |
| { name: 'Coffee Table', confidence: 0.88, time: '02:35', position: 'Living Room' }, | |
| { name: 'TV Stand', confidence: 0.85, time: '02:58', position: 'Entertainment Area' } | |
| ], | |
| 'building': [ | |
| { name: 'Main Door', confidence: 0.96, time: '00:05', position: 'Entrance' }, | |
| { name: 'Living Room Window', confidence: 0.93, time: '00:22', position: 'West Wall' }, | |
| { name: 'Kitchen Wall', confidence: 0.88, time: '00:48', position: 'Ground Floor' }, | |
| { name: 'Staircase', confidence: 0.91, time: '01:10', position: 'Main Hall' }, | |
| { name: 'Patio Door', confidence: 0.89, time: '01:35', position: 'Back Exit' }, | |
| { name: 'Bedroom Window', confidence: 0.92, time: '01:58', position: 'Second Floor' }, | |
| { name: 'Support Column', confidence: 0.86, time: '02:20', position: 'Basement' }, | |
| { name: 'Garage Door', confidence: 0.90, time: '02:45', position: 'Side Building' } | |
| ] | |
| }; | |
| // Initialize event listeners | |
| document.addEventListener('DOMContentLoaded', () => { | |
| setupUploadArea(); | |
| setupClassSelector(); | |
| setupProcessButton(); | |
| }); | |
| function setupUploadArea() { | |
| const uploadArea = document.getElementById('uploadArea'); | |
| const fileInput = document.getElementById('fileInput'); | |
| const uploadButton = uploadArea.querySelector('.upload-button'); | |
| uploadButton.addEventListener('click', () => fileInput.click()); | |
| uploadArea.addEventListener('dragover', (e) => { | |
| e.preventDefault(); | |
| uploadArea.classList.add('dragover'); | |
| }); | |
| uploadArea.addEventListener('dragleave', () => { | |
| uploadArea.classList.remove('dragover'); | |
| }); | |
| uploadArea.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| uploadArea.classList.remove('dragover'); | |
| const files = e.dataTransfer.files; | |
| if (files.length > 0) { | |
| handleFileUpload(files[0]); | |
| } | |
| }); | |
| fileInput.addEventListener('change', (e) => { | |
| if (e.target.files.length > 0) { | |
| handleFileUpload(e.target.files[0]); | |
| } | |
| }); | |
| } | |
| function handleFileUpload(file) { | |
| if (!file.type.startsWith('video/')) { | |
| showNotification('error', |