File size: 5,878 Bytes
cb28fad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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);