| | <!DOCTYPE html> |
| | <html lang="en"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>플로렌스 비디오 AI</title> |
| | <script src="https://cdn.tailwindcss.com"></script> |
| | <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| | <style> |
| | @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); |
| | |
| | body { |
| | font-family: 'Inter', sans-serif; |
| | background-color: #1a1a1a; |
| | color: #ffffff; |
| | } |
| | |
| | .video-container { |
| | aspect-ratio: 16/9; |
| | position: relative; |
| | overflow: hidden; |
| | border-radius: 12px; |
| | } |
| | |
| | .video-wrapper { |
| | position: relative; |
| | background-color: #000000; |
| | } |
| | |
| | .progress-bar { |
| | height: 2px; |
| | background-color: rgba(255, 255, 255, 0.2); |
| | } |
| | |
| | .progress { |
| | height: 100%; |
| | background: linear-gradient(90deg, #2563eb, #3b82f6); |
| | } |
| | |
| | .hover-card { |
| | transition: all 0.3s ease; |
| | border: 1px solid rgba(255, 255, 255, 0.1); |
| | } |
| | |
| | .hover-card:hover { |
| | transform: translateY(-4px); |
| | box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3); |
| | border-color: rgba(59, 130, 246, 0.5); |
| | } |
| | |
| | .ai-tag { |
| | position: absolute; |
| | top: 12px; |
| | right: 12px; |
| | background: linear-gradient(90deg, #2563eb, #3b82f6); |
| | } |
| | |
| | .processing-pulse { |
| | animation: pulse 2s infinite; |
| | } |
| | |
| | @keyframes pulse { |
| | 0% { |
| | opacity: 0.6; |
| | } |
| | 50% { |
| | opacity: 1; |
| | } |
| | 100% { |
| | opacity: 0.6; |
| | } |
| | } |
| | |
| | .context-menu { |
| | opacity: 0; |
| | transform: scale(0.95); |
| | transform-origin: top left; |
| | transition: all 0.2s ease; |
| | pointer-events: none; |
| | } |
| | |
| | .context-menu.active { |
| | opacity: 1; |
| | transform: scale(1); |
| | pointer-events: all; |
| | } |
| | |
| | .loading-dots { |
| | display: flex; |
| | justify-content: center; |
| | align-items: center; |
| | } |
| | |
| | .loading-dots span { |
| | width: 8px; |
| | height: 8px; |
| | margin: 0 2px; |
| | background-color: #3b82f6; |
| | border-radius: 50%; |
| | display: inline-block; |
| | animation: bounce 1.4s infinite ease-in-out both; |
| | } |
| | |
| | .loading-dots span:nth-child(1) { |
| | animation-delay: -0.32s; |
| | } |
| | |
| | .loading-dots span:nth-child(2) { |
| | animation-delay: -0.16s; |
| | } |
| | |
| | @keyframes bounce { |
| | 0%, 80%, 100% { |
| | transform: translateY(0); |
| | } |
| | 40% { |
| | transform: translateY(-8px); |
| | } |
| | } |
| | |
| | .video-thumbnail { |
| | transition: all 0.3s ease; |
| | cursor: pointer; |
| | } |
| | |
| | .video-thumbnail:hover .play-icon { |
| | transform: scale(1.1); |
| | opacity: 1; |
| | } |
| | |
| | .play-icon { |
| | transition: all 0.3s ease; |
| | opacity: 0.6; |
| | } |
| | </style> |
| | </head> |
| | <body class="min-h-screen bg-gray-900"> |
| | <div class="container mx-auto px-4 py-8"> |
| | |
| | <header class="flex justify-between items-center mb-8"> |
| | <div class="flex items-center"> |
| | <div class="w-10 h-10 rounded-md bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center mr-3"> |
| | <i class="fas fa-eye text-white text-lg"></i> |
| | </div> |
| | <h1 class="text-2xl font-bold text-white">플로렌스 비디오</h1> |
| | </div> |
| | <div class="flex space-x-3"> |
| | <button class="px-4 py-2 bg-gray-800 hover:bg-gray-700 text-gray-300 rounded-lg text-sm font-medium flex items-center"> |
| | <i class="fas fa-history mr-2"></i> 기록 |
| | </button> |
| | <button id="accountBtn" class="px-4 py-2 bg-gray-800 hover:bg-gray-700 text-gray-300 rounded-lg text-sm font-medium flex items-center relative"> |
| | <i class="fas fa-user mr-2"></i> 계정 |
| | <div id="accountDropdown" class="hidden absolute top-full right-0 mt-1 w-48 bg-gray-800 rounded-lg shadow-lg z-50 py-1 border border-gray-700"> |
| | <a href="#" class="block px-4 py-2 text-sm text-gray-300 hover:bg-gray-700">프로필</a> |
| | <a href="#" class="block px-4 py-2 text-sm text-gray-300 hover:bg-gray-700">설정</a> |
| | <a href="#" class="block px-4 py-2 text-sm text-gray-300 hover:bg-gray-700 border-t border-gray-700 mt-1">로그아웃</a> |
| | </div> |
| | </button> |
| | </div> |
| | </header> |
| |
|
| | |
| | <div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8"> |
| | <div class="lg:col-span-2"> |
| | <div class="bg-gray-800 rounded-xl p-4"> |
| | <h2 class="text-lg font-semibold text-white mb-4">비디오 처리</h2> |
| | |
| | |
| | <div id="uploadContainer" class="mb-4 p-8 border-2 border-dashed border-gray-600 rounded-lg text-center cursor-pointer hover:border-blue-500 transition-colors"> |
| | <input type="file" id="videoUpload" accept=".mp4,.mov,.avi,.mkv,.mp3,.wav" class="hidden"> |
| | <i class="fas fa-cloud-upload-alt text-4xl text-gray-400 mb-3"></i> |
| | <p class="text-gray-300 mb-2">여기에 비디오 파일을 드래그 앤 드롭하세요</p> |
| | <p class="text-sm text-gray-500">또는 클릭하여 파일 찾아보기 (MP4, MOV, AVI, MP3)</p> |
| | </div> |
| | |
| | |
| | <div id="videoPlayerContainer" class="hidden"> |
| | |
| | <div class="video-wrapper video-container rounded-lg mb-4"> |
| | <video id="videoPlayer" class="w-full h-full object-contain" controls> |
| | 브라우저가 비디오 태그를 지원하지 않습니다. |
| | </video> |
| | <div class="absolute bottom-0 left-0 w-full"> |
| | <div class="progress-bar"> |
| | <div id="progressIndicator" class="progress" style="width: 0%"></div> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div class="flex items-center justify-between"> |
| | <div class="flex space-x-3"> |
| | <button id="playPauseBtn" class="w-10 h-10 bg-blue-600 hover:bg-blue-700 rounded-full flex items-center justify-center text-white"> |
| | <i class="fas fa-play"></i> |
| | </button> |
| | <button class="w-10 h-10 bg-gray-700 hover:bg-gray-600 rounded-full flex items-center justify-center text-white"> |
| | <i class="fas fa-volume-up"></i> |
| | </button> |
| | <button class="w-10 h-10 bg-gray-700 hover:bg-gray-600 rounded-full flex items-center justify-center text-white"> |
| | <i class="fas fa-cog"></i> |
| | </button> |
| | </div> |
| | <div class="flex items-center text-sm text-gray-400"> |
| | <span id="currentTime">00:00</span> |
| | <span class="mx-2">/</span> |
| | <span id="duration">00:00</span> |
| | </div> |
| | <div class="flex space-x-2"> |
| | <button class="px-3 py-1.5 bg-gray-700 hover:bg-gray-600 rounded-lg text-xs font-medium text-white flex items-center"> |
| | <i class="fas fa-expand mr-2"></i> 전체 화면 |
| | </button> |
| | <button id="processBtn" class="px-3 py-1.5 bg-blue-600 hover:blue-gray-700 rounded-lg text-xs font-medium text-white flex items-center"> |
| | <i class="fas fa-bolt mr-2"></i> 비디오 처리 |
| | </button> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div class="bg-gray-800 rounded-xl p-4 h-fit"> |
| | <h2 class="text-lg font-semibold text-white mb-4">AI 비전 옵션</h2> |
| | |
| | <div class="space-y-4"> |
| | <div class="p-3 bg-gray-900 rounded-lg border border-gray-700 hover-card"> |
| | <div class="flex items-start"> |
| | <div class="w-10 h-10 rounded-lg bg-blue-500/10 flex items-center justify-center mr-3 border border-blue-500/50"> |
| | <i class="fas fa-search text-blue-400"></i> |
| | </div> |
| | <div> |
| | <h3 class="font-medium text-white">객체 감지</h3> |
| | <p class="text-sm text-gray-400 mt-1">비디오에서 객체를 식별하고 라벨링합니다</p> |
| | <label class="relative inline-flex items-center mt-2"> |
| | <input type="checkbox" class="sr-only peer" checked> |
| | <div class="w-9 h-5 bg-gray-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-blue-600"></div> |
| | </label> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | <div class="p-3 bg-gray-900 rounded-lg border border-gray-700 hover-card"> |
| | <div class="flex items-start"> |
| | <div class="w-10 h-10 rounded-lg bg-purple-500/10 flex items-center justify-center mr-3 border border-purple-500/50"> |
| | <i class="fas fa-person text-purple-400"></i> |
| | </div> |
| | <div> |
| | <h3 class="font-medium text-white">사람 추적</h3> |
| | <p class="text-sm text-gray-400 mt-1">장면 전체에서 개인을 추적합니다</p> |
| | <label class="relative inline-flex items-center mt-2"> |
| | <input type="checkbox" class="sr-only peer" checked> |
| | <div class="w-9 h-5 bg-gray-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-purple-600"></div> |
| | </label> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | <div class="p-3 bg-gray-900 rounded-lg border border-gray-700 hover-card"> |
| | <div class="flex items-start"> |
| | <div class="w-10 h-10 rounded-lg bg-yellow-500/10 flex items-center justify-center mr-3 border border-yellow-500/50"> |
| | <i class="fas fa-chart-line text-yellow-400"></i> |
| | </div> |
| | <div> |
| | <h3 class="font-medium text-white">활동 분석</h3> |
| | <p class="text-sm text-gray-400 mt-1">행동과 움직임을 감지합니다</p> |
| | <label class="relative inline-flex items-center mt-2"> |
| | <input type="checkbox" class="sr-only peer"> |
| | <div class="w-9 h-5 bg-gray-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-yellow-600"></div> |
| | </label> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | <div class="p-3 bg-gray-900 rounded-lg border border-gray-700 hover-card"> |
| | <div class="flex items-start"> |
| | <div class="w-10 h-10 rounded-lg bg-green-500/10 flex items-center justify-center mr-3 border border-green-500/50"> |
| | <i class="fas fa-image text-green-400"></i> |
| | </div> |
| | <div> |
| | <h3 class="font-medium text-white">장면 태그</h3> |
| | <p class="text-sm text-gray-400 mt-1">비디오 세그먼트를 자동으로 분류합니다</p> |
| | <label class="relative inline-flex items-center mt-2"> |
| | <input type="checkbox" class="sr-only peer" checked> |
| | <div class="w-9 h-5 bg-gray-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-green-600"></div> |
| | </label> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | <div class="mt-4 p-4 bg-gray-900/50 rounded-lg border border-dashed border-gray-700"> |
| | <div class="text-center"> |
| | <button class="w-full py-2 px-4 border border-gray-600 hover:border-blue-500 rounded-lg text-sm text-gray-400 hover:text-blue-400 font-medium flex items-center justify-center"> |
| | <i class="fas fa-plus mr-2"></i> 사용자 정의 분석 추가 |
| | </button> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div class="bg-gray-800 rounded-xl p-4 mb-8"> |
| | <div class="flex justify-between items-center mb-4"> |
| | <h2 class="text-lg font-semibold text-white">AI 분석 결과</h2> |
| | <div class="flex space-x-2"> |
| | <button class="px-3 py-1 bg-gray-700 hover:bg-gray-600 rounded-lg text-sm font-medium text-gray-300"> |
| | <i class="fas fa-filter mr-2"></i> 필터 |
| | </button> |
| | <button class="px-3 py-1 bg-gray-700 hover:bg-gray-600 rounded-lg text-sm font-medium text-gray-300"> |
| | <i class="fas fa-download mr-2"></i> 내보내기 |
| | </button> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div id="processingState" class="hidden"> |
| | <div class="p-8 text-center rounded-lg bg-gray-900/50"> |
| | <div class="loading-dots mb-4"> |
| | <span></span> |
| | <span></span> |
| | <span></span> |
| | </div> |
| | <h3 class="text-lg font-medium text-white mb-2">비디오 콘텐츠 분석 중</h3> |
| | <p class="text-gray-400">비디오 길이에 따라 일반적으로 2-3분이 걸립니다</p> |
| | <div class="mt-4 text-xs text-gray-500"> |
| | <i class="fas fa-info-circle mr-1"></i> 플로렌스 AI가 비디오에서 객체, 사람 및 활동을 감지하고 있습니다. |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div id="resultsDisplay"> |
| | <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> |
| | |
| | <div class="p-4 bg-gray-900 rounded-lg border border-gray-700"> |
| | <h3 class="font-medium text-white mb-3 flex items-center"> |
| | <i class="fas fa-box-open text-blue-400 mr-2"></i> 감지된 객체 |
| | </h3> |
| | <div class="flex flex-wrap gap-2"> |
| | <span class="px-2 py-1 bg-blue-900/50 text-blue-300 rounded text-xs">사람 (92%)</span> |
| | <span class="px-2 py-1 bg-blue-900/50 text-blue-300 rounded text-xs">자동차 (87%)</span> |
| | <span class="px-2 py-1 bg-blue-900/50 text-blue-300 rounded text-xs">나무 (82%)</span> |
| | <span class="px-2 py-1 bg-blue-900/50 text-blue-300 rounded text-xs">개 (76%)</span> |
| | <span class="px-2 py-1 bg-blue-900/50 text-blue-300 rounded text-xs">건물 (94%)</span> |
| | <span class="px-2 py-1 bg-blue-900/50 text-blue-300 rounded text-xs">자전거 (62%)</span> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div class="p-4 bg-gray-900 rounded-lg border border-gray-700"> |
| | <h3 class="font-medium text-white mb-3 flex items-center"> |
| | <i class="fas fa-running text-purple-400 mr-2"></i> 활동 |
| | </h3> |
| | <div class="space-y-2"> |
| | <div> |
| | <div class="flex justify-between text-xs text-gray-400 mb-1"> |
| | <span>걷기</span> |
| | <span>00:12 - 01:35</span> |
| | </div> |
| | <div class="w-full bg-gray-700 rounded-full h-1.5"> |
| | <div class="bg-purple-600 h-1.5 rounded-full" style="width: 78%"></div> |
| | </div> |
| | </div> |
| | <div> |
| | <div class="flex justify-between text-xs text-gray-400 mb-1"> |
| | <span>달리기</span> |
| | <span>01:42 - 02:15</span> |
| | </div> |
| | <div class="w-full bg-gray-700 rounded-full h-1.5"> |
| | <div class="bg-purple-600 h-1.5 rounded-full" style="width: 42%"></div> |
| | </div> |
| | </div> |
| | <div> |
| | <div class="flex justify-between text-xs text-gray-400 mb-1"> |
| | <span>서 있기</span> |
| | <span>00:00 - 04:30</span> |
| | </div> |
| | <div class="w-full bg-gray-700 rounded-full h-1.5"> |
| | <div class="bg-purple-600 h-1.5 rounded-full" style="width: 91%"></div> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div class="p-4 bg-gray-900 rounded-lg border border-gray-700"> |
| | <h3 class="font-medium text-white mb-3 flex items-center"> |
| | <i class="fas fa-photo-video text-yellow-400 mr-2"></i> 장면 세그먼트 |
| | </h3> |
| | <div class="space-y-3"> |
| | <div class="flex items-start"> |
| | <div class="w-8 h-8 rounded bg-yellow-500/10 flex items-center justify-center mr-2 flex-shrink-0 border border-yellow-500/30 text-yellow-400 text-xs">1</div> |
| | <div> |
| | <div class="text-sm text-white">야외 거리 전경</div> |
| | <div class="text-xs text-gray-400 mt-1">00:00 - 01:22</div> |
| | </div> |
| | </div> |
| | <div class="flex items-start"> |
| | <div class="w-8 h-8 rounded bg-yellow-500/10 flex items-center justify-center mr-2 flex-shrink-0 border border-yellow-500/30 text-yellow-400 text-xs">2</div> |
| | <div> |
| | <div class="text-sm text-white">실내 대화</div> |
| | <div class="text-xs text-gray-400 mt-1">01:23 - 03:15</div> |
| | </div> |
| | </div> |
| | <div class="flex items-start"> |
| | <div class="w-8 h-8 rounded bg-yellow-500/10 flex items-center justify-center mr-2 flex-shrink-0 border border-yellow-500/30 text-yellow-400 text-xs">3</div> |
| | <div> |
| | <div class="text-sm text-white">공원 활동</div> |
| | <div class="text-xs text-gray-400 mt-1">03:16 - 04:30</div> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div class="mt-6 p-4 bg-gray-900 rounded-lg border border-gray-700"> |
| | <h3 class="font-medium text-white mb-4">Timeline Analysis</h3> |
| | <div class="relative h-40 overflow-hidden rounded-md"> |
| | <canvas id="timelineCanvas" class="absolute top-0 left-0 w-full h-full"></canvas> |
| | </div> |
| | <div class="mt-2 flex justify-between text-xs text-gray-400"> |
| | <span>00:00</span> |
| | <span>01:30</span> |
| | <span>03:00</span> |
| | <span>04:30</span> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div class="mt-4"> |
| | <h3 class="font-medium text-white mb-3">Key Frames</h3> |
| | <div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-3"> |
| | <div class="relative rounded-md overflow-hidden aspect-video bg-gray-700"> |
| | <div class="absolute inset-0 flex items-center justify-center text-gray-500"> |
| | <i class="fas fa-image text-2xl"></i> |
| | </div> |
| | <div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-2"> |
| | <div class="text-xs text-white truncate">Person walking (82%)</div> |
| | <div class="text-[10px] text-gray-300">00:12</div> |
| | </div> |
| | </div> |
| | <div class="relative rounded-md overflow-hidden aspect-video bg-gray-700"> |
| | <div class="absolute inset-0 flex items-center justify-center text-gray-500"> |
| | <i class="fas fa-image text-2xl"></i> |
| | </div> |
| | <div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-2"> |
| | <div class="text-xs text-white truncate">Car moving (76%)</div> |
| | <div class="text-[10px] text-gray-300">00:42</div> |
| | </div> |
| | </div> |
| | <div class="relative rounded-md overflow-hidden aspect-video bg-gray-7 00"> |
| | <div class="absolute inset-0 flex items-center justify-center text-gray-500"> |
| | <i class="fas fa-image text-2xl"></i> |
| | </div> |
| | <div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-2"> |
| | <div class="text-xs text-white truncate">Person running (68%)</div> |
| | <div class="text-[10px] text-gray-300">01:55</div> |
| | </div> |
| | </div> |
| | <div class="relative rounded-md overflow-hidden aspect-video bg-gray-700"> |
| | <div class="absolute inset-0 flex items-center justify-center text-gray-500"> |
| | <i class="fas fa-image text-2xl"></i> |
| | </div> |
| | <div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-2"> |
| | <div class="text-xs text-white truncate">Building (93%)</div> |
| | <div class="text-[10px] text-gray-300">02:30</div> |
| | </div> |
| | </div> |
| | <div class="relative rounded-md overflow-hidden aspect-video bg-gray-700"> |
| | <div class="absolute inset-0 flex items-center justify-center text-gray-500"> |
| | <i class="fas fa-image text-2xl"></i> |
| | </div> |
| | <div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-2"> |
| | <div class="text-xs text-white truncate">Dog sitting (71%)</div> |
| | <div class="text-[10px] text-gray-300">03:15</div> |
| | </div> |
| | </div> |
| | <div class="relative rounded-md overflow-hidden aspect-video bg-gray-700"> |
| | <div class="absolute inset-0 flex items-center justify-center text-gray-500"> |
| | <i class="fas fa-image text-2xl"></i> |
| | </div> |
| | <div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-2"> |
| | <div class="text-xs text-white truncate">Bicycle (59%)</div> |
| | <div class="text-[10px] text-gray-300">04:08</div> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div class="bg-gray-800 rounded-xl p-4"> |
| | <div class="flex justify-between items-center mb-4"> |
| | <h2 class="text-lg font-semibold text-white">Recent Projects</h2> |
| | <button class="px-3 py-1 bg-gray-700 hover:bg-gray-600 rounded-lg text-sm font-medium text-gray-300"> |
| | View All |
| | </button> |
| | </div> |
| | <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4"> |
| | <div class="group video-thumbnail relative rounded-lg overflow-hidden bg-gray-900 aspect-video"> |
| | <div class="absolute inset-0 bg-gradient-to-br from-blue-900/20 to-purple-900/30 flex items-center justify-center"> |
| | <i class="fas fa-play play-icon text-white/60 group-hover:text-white/90 text-4xl transition-all"></i> |
| | </div> |
| | <div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-3"> |
| | <div class="text-sm font-medium text-white">Street Interview.mp4</div> |
| | <div class="text-xs text-gray-400">Analyzed 2 days ago</div> |
| | </div> |
| | <div class="ai-tag text-xs px-2 py-1 rounded-full text-white">AI Processed</div> |
| | </div> |
| | <div class="group video-thumbnail relative rounded-lg overflow-hidden bg-gray-900 aspect-video"> |
| | <div class="absolute inset-0 bg-gradient-to-br from-purple-900/20 to-pink-900/30 flex items-center justify-center"> |
| | <i class="fas fa-play play-icon text-white/60 group-hover:text-white/90 text-4xl transition-all"></i> |
| | </div> |
| | <div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-3"> |
| | <div class="text-sm font-medium text-white">Park Activities.mp4</div> |
| | <div class="text-xs text-gray-400">Analyzed 1 week ago</div> |
| | </div> |
| | </div> |
| | <div class="group video-thumbnail relative rounded-lg overflow-hidden bg-gray-900 aspect-video"> |
| | <div class="absolute inset-0 bg-gradient-to-br from-pink-900/20 to-red-900/30 flex items-center justify-center"> |
| | <i class="fas fa-play play-icon text-white/60 group-hover:text-white/90 text-4xl transition-all"></i> |
| | </div> |
| | <div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-3"> |
| | <div class="text-sm font-medium text-white">Product Demo.mov</div> |
| | <div class="text-xs text-gray-400">Analyzed 2 weeks ago</div> |
| | </div> |
| | <div class="ai-tag text-xs px-2 py-1 rounded-full text-white">AI Processed</div> |
| | </div> |
| | <div class="group video-thumbnail relative rounded-lg overflow-hidden bg-gray-900 aspect-video"> |
| | <div class="absolute inset-0 bg-gradient-to-br from-green-900/20 to-blue-900/30 flex items-center justify-center"> |
| | <i class="fas fa-plus text-white/60 group-hover:text-white/90 text-3xl transition-all"></i> |
| | </div> |
| | <div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 to-transparent p-3 flex items-center justify-center"> |
| | <div class="text-sm font-medium text-white">Upload New Video</div> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div id="contextMenu" class="context-menu absolute w-48 bg-gray-800 rounded-md shadow-lg z-50 py-1 border border-gray-700"> |
| | <div class="text-gray-400 text-xs px-4 py-2 border-b border-gray-700">Video Actions</div> |
| | <a href="#" class="block px-4 py-2 text-sm text-gray-300 hover:bg-gray-700">Analyze Scene</a> |
| | <a href="#" class="block px-4 py-2 text-sm text-gray-300 hover:bg-gray-700">Extract Frame</a> |
| | <a href="#" class="block px-4 py-2 text-sm text-gray-300 hover:bg-gray-700">Audio Analysis</a> |
| | <div class="border-t border-gray-700 my-1"></div> |
| | <a href="#" class="block px-4 py-2 text-sm text-gray-300 hover:bg-gray-700">Export Clip</a> |
| | </div> |
| |
|
| | <script> |
| | document.addEventListener('DOMContentLoaded', function() { |
| | |
| | const video = document.getElementById('videoPlayer'); |
| | const playPauseBtn = document.getElementById('playPauseBtn'); |
| | const progressIndicator = document.getElementById('progressIndicator'); |
| | const currentTimeDisplay = document.getElementById('currentTime'); |
| | const durationDisplay = document.getElementById('duration'); |
| | const processBtn = document.getElementById('processBtn'); |
| | const processingState = document.getElementById('processingState'); |
| | const resultsDisplay = document.getElementById('resultsDisplay'); |
| | const videoPlayerContainer = document.getElementById('videoPlayerContainer'); |
| | const uploadContainer = document.getElementById('uploadContainer'); |
| | const videoUpload = document.getElementById('videoUpload'); |
| | const accountBtn = document.getElementById('accountBtn'); |
| | const accountDropdown = document.getElementById('accountDropdown'); |
| | |
| | |
| | const sampleVideoUrl = 'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4'; |
| | |
| | |
| | function formatTime(seconds) { |
| | const mins = Math.floor(seconds / 60); |
| | const secs = Math.floor(seconds % 60); |
| | return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; |
| | } |
| | |
| | |
| | function updateTimeDisplays() { |
| | currentTimeDisplay.textContent = formatTime(video.currentTime); |
| | durationDisplay.textContent = formatTime(video.duration); |
| | progressIndicator.style.width = `${(video.currentTime / video.duration) * 100}%`; |
| | } |
| | |
| | |
| | function togglePlayPause() { |
| | if (video.paused) { |
| | video.play(); |
| | playPauseBtn.innerHTML = '<i class="fas fa-pause"></i>'; |
| | } else { |
| | video.pause(); |
| | playPauseBtn.innerHTML = '<i class="fas fa-play"></i>'; |
| | } |
| | } |
| | |
| | |
| | function handleFileUpload(event) { |
| | const file = event.target.files[0]; |
| | if (!file) return; |
| | |
| | const fileType = file.type.split('/')[0]; |
| | const isAudio = fileType === 'audio'; |
| | |
| | |
| | const fileURL = URL.createObjectURL(file); |
| | |
| | |
| | uploadContainer.classList.add('hidden'); |
| | videoPlayerContainer.classList.remove('hidden'); |
| | |
| | if (isAudio) { |
| | |
| | video.poster = 'https://images.unsplash.com/photo-1511671782779-c97d3d27a1d4?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80'; |
| | video.innerHTML = `<source src="${fileURL}" type="${file.type}">`; |
| | } else { |
| | |
| | video.poster = ''; |
| | video.innerHTML = `<source src="${fileURL}" type="${file.type}">`; |
| | } |
| | |
| | |
| | video.load(); |
| | } |
| | |
| | |
| | document.querySelectorAll('.video-thumbnail').forEach(thumbnail => { |
| | thumbnail.addEventListener('click', function() { |
| | const isNewUpload = this.querySelector('.fa-plus'); |
| | |
| | if (isNewUpload) { |
| | |
| | videoUpload.click(); |
| | } else { |
| | |
| | uploadContainer.classList.add('hidden'); |
| | videoPlayerContainer.classList.remove('hidden'); |
| | video.innerHTML = `<source src="${sampleVideoUrl}" type="video/mp4">`; |
| | video.load(); |
| | video.play().then(() => { |
| | playPauseBtn.innerHTML = '<i class="fas fa-pause"></i>'; |
| | }); |
| | } |
| | }); |
| | }); |
| | |
| | |
| | video.addEventListener('timeupdate', updateTimeDisplays); |
| | video.addEventListener('click', togglePlayPause); |
| | video.addEventListener('play', () => { |
| | playPauseBtn.innerHTML = '<i class="fas fa-pause"></i>'; |
| | }); |
| | video.addEventListener('pause', () => { |
| | playPauseBtn.innerHTML = '<i class="fas fa-play"></i>'; |
| | }); |
| | video.addEventListener('loadedmetadata', updateTimeDisplays); |
| | |
| | playPauseBtn.addEventListener('click', togglePlayPause); |
| | |
| | |
| | processBtn.addEventListener('click', function() { |
| | processingState.classList.remove('hidden'); |
| | resultsDisplay.classList.add('hidden'); |
| | |
| | |
| | setTimeout(() => { |
| | processingState.classList.add('hidden'); |
| | resultsDisplay.classList.remove('hidden'); |
| | drawTimeline(); |
| | |
| | |
| | processBtn.innerHTML = '<i class="fas fa-sync-alt mr-2"></i> Re-process'; |
| | processBtn.classList.add('bg-blue-700'); |
| | }, 2500); |
| | }); |
| | |
| | |
| | uploadContainer.addEventListener('click', function() { |
| | videoUpload.click(); |
| | }); |
| | |
| | |
| | videoUpload.addEventListener('change', handleFileUpload); |
| | |
| | |
| | accountBtn.addEventListener('click', function(e) { |
| | e.stopPropagation(); |
| | accountDropdown.classList.toggle('hidden'); |
| | }); |
| | |
| | |
| | document.addEventListener('click', function() { |
| | accountDropdown.classList.add('hidden'); |
| | }); |
| | |
| | |
| | document.addEventListener('contextmenu', function(e) { |
| | e.preventDefault(); |
| | const contextMenu = document.getElementById('contextMenu'); |
| | |
| | |
| | let x = e.pageX; |
| | let y = e.pageY; |
| | |
| | |
| | const menuWidth = contextMenu.offsetWidth; |
| | const menuHeight = contextMenu.offsetHeight; |
| | |
| | if (x + menuWidth > window.innerWidth) { |
| | x = window.innerWidth - menuWidth; |
| | } |
| | |
| | if (y + menuHeight > window.innerHeight) { |
| | y = window.innerHeight - menuHeight; |
| | } |
| | |
| | contextMenu.style.left = `${x}px`; |
| | contextMenu.style.top = `${y}px`; |
| | contextMenu.classList.add('active'); |
| | |
| | |
| | const closeMenu = function() { |
| | contextMenu.classList.remove('active'); |
| | document.removeEventListener('click', closeMenu); |
| | }; |
| | |
| | document.addEventListener('click', closeMenu); |
| | }); |
| | |
| | |
| | function drawTimeline() { |
| | const canvas = document.getElementById('timelineCanvas'); |
| | const ctx = canvas.getContext('2d'); |
| | |
| | |
| | canvas.width = canvas.offsetWidth; |
| | canvas.height = canvas.offsetHeight; |
| | |
| | |
| | const activities = [ |
| | { type: 'people', start: 0, end: 270, color: '#3b82f6' }, |
| | { type: 'objects', start: 30, end: 180, color: '#10b981' }, |
| | { type: 'movement', start: 60, end: 240, color: '#8b5cf6' }, |
| | { type: 'people', start: 180, end: 270, color: '#3b82f6' } |
| | ]; |
| | |
| | |
| | ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)'; |
| | ctx.lineWidth = 2; |
| | ctx.beginPath(); |
| | ctx.moveTo(0, canvas.height / 2); |
| | ctx.lineTo(canvas.width, canvas.height / 2); |
| | ctx.stroke(); |
| | |
| | |
| | activities.forEach(activity => { |
| | const x1 = (activity.start / 270) * canvas.width; |
| | const x2 = (activity.end / 270) * canvas.width; |
| | const width = x2 - x1; |
| | |
| | ctx.fillStyle = activity.color + '20'; |
| | ctx.strokeStyle = activity.color; |
| | ctx.lineWidth = 1; |
| | |
| | |
| | ctx.beginPath(); |
| | ctx.roundRect(x1, canvas.height / 4, width, canvas.height / 2, 6); |
| | ctx.fill(); |
| | ctx.stroke(); |
| | |
| | |
| | ctx.fillStyle = activity.color; |
| | ctx.beginPath(); |
| | ctx.arc(x1, canvas.height / 2, 3, 0, Math.PI * 2); |
| | ctx.fill(); |
| | ctx.beginPath(); |
| | ctx.arc(x2, canvas.height / 2, 3, 0, Math.PI * 2); |
| | ctx.fill(); |
| | }); |
| | |
| | |
| | const times = [0, 90, 180, 270]; |
| | times.forEach(time => { |
| | const x = (time / 270) * canvas.width; |
| | |
| | ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)'; |
| | ctx.lineWidth = 1; |
| | ctx.beginPath(); |
| | ctx.moveTo(x, canvas.height / 2 - 10); |
| | ctx.lineTo(x, canvas.height / 2 + 10); |
| | ctx.stroke(); |
| | }); |
| | } |
| | |
| | |
| | window.addEventListener('resize', drawTimeline); |
| | }); |
| | </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=nkjoy/drums" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| | </html> |