Spaces:
Runtime error
Runtime error
| const timeInput = document.getElementById('time-input'); | |
| const startBtn = document.getElementById('start-btn'); | |
| const videoElement = document.getElementById('video'); | |
| const statusElement = document.getElementById('status'); | |
| const stressLevelElement = document.getElementById('stress-level'); | |
| const countdownElement = document.getElementById('countdown'); | |
| const showResultBtn = document.getElementById('show-result-btn'); | |
| let stream; | |
| let interval; | |
| let countdownInterval; | |
| let totalTime; | |
| let frameCount = 0; | |
| let countdownTime; | |
| let sessionId = Date.now().toString(); | |
| async function startCamera() { | |
| try { | |
| stream = await navigator.mediaDevices.getUserMedia({ | |
| video: true, | |
| }); | |
| videoElement.srcObject = stream; | |
| } catch (err) { | |
| console.error("Error accessing the camera", err); | |
| statusElement.textContent = "Gagal mengakses kamera."; | |
| } | |
| } | |
| function stopCamera() { | |
| if (stream) { | |
| let tracks = stream.getTracks(); | |
| tracks.forEach(track => track.stop()); | |
| videoElement.srcObject = null; | |
| } | |
| } | |
| async function sendFrameToBackend(dataUrl) { | |
| try { | |
| console.log("Preparing to send frame to backend..."); | |
| const formData = new FormData(); | |
| formData.append('image', dataUrl); | |
| formData.append('sessionId', sessionId); | |
| console.log("Sending request to backend..."); | |
| const controller = new AbortController(); | |
| const timeoutId = setTimeout(() => controller.abort(), 10000); | |
| const apiResponse = await fetch('https://PatriciaWening-emoapi.hf.space/api/deteksi-emosi', { | |
| method: 'POST', | |
| body: formData, | |
| signal: controller.signal | |
| }); | |
| clearTimeout(timeoutId); | |
| if (!apiResponse.ok) { | |
| const errorText = await apiResponse.text(); | |
| console.error(`Server returned error ${apiResponse.status}: ${errorText}`); | |
| throw new Error(`HTTP error! Status: ${apiResponse.status}`); | |
| } | |
| const data = await apiResponse.json(); | |
| console.log("API response:", data); | |
| if (data.faceDetected) { | |
| drawFaceRectangle(data.faceRegion); | |
| updateStressLevel(data.stressLevel, data.emotion); | |
| statusElement.textContent = `Emosi terdeteksi: ${data.emotion}, Tingkat stres: ${data.stressLevel}%`; | |
| } else { | |
| statusElement.textContent = data.error || "Wajah tidak terdeteksi, mohon cek posisi kamera."; | |
| } | |
| } catch (error) { | |
| console.error('Error sending frame to backend:', error); | |
| statusElement.textContent = "Kesalahan saat memproses data: " + error.message; | |
| } | |
| } | |
| function drawFaceRectangle(region) { | |
| const canvas = document.createElement('canvas'); | |
| canvas.width = videoElement.videoWidth; | |
| canvas.height = videoElement.videoHeight; | |
| const context = canvas.getContext('2d'); | |
| context.drawImage(videoElement, 0, 0, canvas.width, canvas.height); | |
| context.strokeStyle = '#00FF00'; | |
| context.lineWidth = 3; | |
| context.strokeRect(region.x, region.y, region.width, region.height); | |
| const dataURL = canvas.toDataURL('image/png'); | |
| const tempImg = document.createElement('img'); | |
| tempImg.src = dataURL; | |
| tempImg.style.width = '100%'; | |
| tempImg.style.height = 'auto'; | |
| tempImg.style.border = '2px solid #ccc'; | |
| tempImg.style.borderRadius = '8px'; | |
| const videoParent = videoElement.parentNode; | |
| videoParent.insertBefore(tempImg, videoElement); | |
| videoElement.style.display = 'none'; | |
| setTimeout(() => { | |
| tempImg.remove(); | |
| videoElement.style.display = 'block'; | |
| }, 200); | |
| } | |
| function updateStressLevel(stressLevel, emotion) { | |
| stressLevelElement.textContent = `Tingkat Stres: ${stressLevel} (${emotion})`; | |
| if (stressLevel >= 80) { | |
| stressLevelElement.classList.remove('text-green-600', 'text-yellow-600'); | |
| stressLevelElement.classList.add('text-red-600'); | |
| } else if (stressLevel >= 50) { | |
| stressLevelElement.classList.remove('text-green-600', 'text-red-600'); | |
| stressLevelElement.classList.add('text-yellow-600'); | |
| } else { | |
| stressLevelElement.classList.remove('text-yellow-600', 'text-red-600'); | |
| stressLevelElement.classList.add('text-green-600'); | |
| } | |
| localStorage.setItem('currentSessionId', sessionId); | |
| } | |
| async function captureAndAnalyze() { | |
| const canvas = document.createElement('canvas'); | |
| const context = canvas.getContext('2d'); | |
| canvas.width = videoElement.videoWidth; | |
| canvas.height = videoElement.videoHeight; | |
| context.drawImage(videoElement, 0, 0, canvas.width, canvas.height); | |
| const frame = canvas.toDataURL('image/jpeg'); | |
| sendFrameToBackend(frame); | |
| frameCount++; | |
| } | |
| function updateCountdown() { | |
| const minutes = Math.floor(countdownTime / 60); | |
| const seconds = countdownTime % 60; | |
| countdownElement.textContent = `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; | |
| countdownTime--; | |
| if (countdownTime < 0) { | |
| clearInterval(countdownInterval); | |
| } | |
| } | |
| function startDetection() { | |
| totalTime = parseInt(timeInput.value) * 1000; | |
| if (isNaN(totalTime) || totalTime <= 0) { | |
| statusElement.textContent = "Waktu input tidak valid."; | |
| return; | |
| } | |
| countdownTime = totalTime / 1000; | |
| countdownInterval = setInterval(updateCountdown, 1000); | |
| statusElement.textContent = `Kamera aktif selama ${totalTime / 1000} detik.`; | |
| startCamera(); | |
| interval = setInterval(captureAndAnalyze, 1000); | |
| setTimeout(() => { | |
| clearInterval(interval); | |
| stopCamera(); | |
| statusElement.textContent = "Proses selesai!"; | |
| showResultBtn.classList.remove('hidden'); | |
| }, totalTime); | |
| } | |
| startBtn.addEventListener('click', startDetection); |