Team Ai
Apppublic

Prathmesh0001/interview-system

sourceHugging Faceupdated 8mo agoView on Hugging Face
0likes
interview_backup.html457 linesDownload Raw Back to templates
1<!DOCTYPE html>
2<html lang="en">
3
4<head>
5    <meta charset="UTF-8">
6    <meta name="viewport" content="width=device-width, initial-scale=1.0">
7    <title>Interview in Progress - AI Mock Interview</title>
8    <link rel="stylesheet" href="/static/css/style.css">
9</head>
10
11<body class="interview-page">
12    <div class="interview-container">
13        <!-- Left Panel: Video and Question -->
14        <div class="left-panel">
15            <!-- Video Section -->
16            <div class="video-section">
17                <video id="videoElement" autoplay muted></video>
18                <div class="video-status" id="videoStatus">
19                    <div id="recordingIndicator" class="hidden">
20                        ๐Ÿ”ด Recording...
21                    </div>
22                </div>
23            </div>
24
25            <!-- Question Display -->
26            <div class="question-display">
27                <div class="question-header">
28                    <span class="question-number" id="questionNumber">Question 1 of 5</span>
29                    <span class="question-category" id="questionCategory">Resume-Based</span>
30                </div>
31                <div class="question-text" id="questionText">
32                    Loading question...
33                </div>
34                <div class="question-focus" id="questionFocus"></div>
35            </div>
36        </div>
37
38        <!-- Right Panel: Controls and Transcript -->
39        <div class="right-panel">
40            <div class="controls-section">
41                <h3>Interview Controls</h3>
42
43                <!-- Recording Controls -->
44                <div class="recording-controls">
45                    <button id="startRecording" class="btn-record" disabled>
46                        ๐ŸŽค Start Recording
47                    </button>
48                    <button id="stopRecording" class="btn-stop" disabled style="display: none;">
49                        โน๏ธ Stop Recording
50                    </button>
51                    <div class="recording-timer" id="recordingTimer">00:00</div>
52                </div>
53
54                <div class="status-message" id="statusMessage">
55                    Loading interview...
56                </div>
57
58                <!-- Transcript Display -->
59                <div class="transcript-section">
60                    <h4>Your Answer:</h4>
61                    <div id="transcript" class="transcript-box">
62                        <em>Your answer will appear here as you speak...</em>
63                    </div>
64                    <div id="wordCount" class="word-count">Words: 0</div>
65                </div>
66
67                <!-- Submit Button -->
68                <button id="submitAnswer" class="btn-submit" disabled style="display: none;">
69                    Submit Answer & Continue
70                </button>
71
72                <!-- Feedback Display -->
73                <div id="feedbackSection" class="feedback-section" style="display: none;">
74                    <h4>Quick Feedback:</h4>
75                    <div class="score-display">
76                        Score: <span id="answerScore">0</span>/100
77                    </div>
78                    <ul id="feedbackList"></ul>
79                </div>
80            </div>
81
82            <!-- Progress Bar -->
83            <div class="progress-section">
84                <div class="progress-bar">
85                    <div id="progressFill" class="progress-fill" style="width: 0%"></div>
86                </div>
87                <div class="progress-text" id="progressText">0 of 5 questions completed</div>
88            </div>
89        </div>
90    </div>
91
92    <script>
93        const sessionId = '{{ session_id }}';
94        let mediaRecorder;
95        let audioChunks = [];
96        let recordingStartTime;
97        let timerInterval;
98        let currentTranscript = '';
99        let recognition;
100        let isRecording = false;
101
102        // Safe DOM helper functions
103        function safeGetElement(id) {
104            const element = document.getElementById(id);
105            if (!element) {
106                console.error(`Element not found: ${id}`);
107            }
108            return element;
109        }
110
111        function safeSetText(id, text) {
112            const element = safeGetElement(id);
113            if (element) {
114                element.textContent = text;
115            }
116        }
117
118        function safeSetHTML(id, html) {
119            const element = safeGetElement(id);
120            if (element) {
121                element.innerHTML = html;
122            }
123        }
124
125        function safeSetStyle(id, styles) {
126            const element = safeGetElement(id);
127            if (element) {
128                Object.assign(element.style, styles);
129            }
130        }
131
132        function safeToggleClass(id, className, add) {
133            const element = safeGetElement(id);
134            if (element && element.classList) {
135                if (add) {
136                    element.classList.add(className);
137                } else {
138                    element.classList.remove(className);
139                }
140            }
141        }
142
143        function safeSetDisabled(id, disabled) {
144            const element = safeGetElement(id);
145            if (element) {
146                element.disabled = disabled;
147            }
148        }
149
150        // Initialize Speech Recognition
151        if ('webkitSpeechRecognition' in window || 'SpeechRecognition' in window) {
152            const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
153            recognition = new SpeechRecognition();
154            recognition.continuous = true;
155            recognition.interimResults = true;
156            recognition.lang = 'en-US';
157
158            recognition.onresult = (event) => {
159                let interimTranscript = '';
160                let finalTranscript = '';
161
162                for (let i = event.resultIndex; i < event.results.length; i++) {
163                    const transcript = event.results[i][0].transcript;
164                    if (event.results[i].isFinal) {
165                        finalTranscript += transcript + ' ';
166                    } else {
167                        interimTranscript += transcript;
168                    }
169                }
170
171                if (finalTranscript) {
172                    currentTranscript += finalTranscript;
173                }
174
175                const fullText = currentTranscript + interimTranscript;
176                safeSetText('transcript', fullText || 'Listening...');
177
178                // Update word count
179                const wordCount = fullText.trim().split(/\s+/).filter(w => w.length > 0).length;
180                safeSetText('wordCount', `Words: ${wordCount}`);
181            };
182
183            recognition.onerror = (event) => {
184                console.error('Speech recognition error:', event.error);
185                if (event.error === 'no-speech') {
186                    safeSetHTML('transcript', '<em>No speech detected. Please try again.</em>');
187                } else if (event.error === 'aborted') {
188                    console.log('Recognition stopped');
189                }
190            };
191
192            recognition.onend = () => {
193                console.log('Recognition ended');
194                if (isRecording) {
195                    try {
196                        recognition.start();
197                    } catch (e) {
198                        console.log('Recognition restart failed:', e);
199                    }
200                }
201            };
202        } else {
203            alert('Speech recognition is not supported in your browser. Please use Chrome or Edge.');
204        }
205
206        // Initialize video
207        async function initVideo() {
208            try {
209                const stream = await navigator.mediaDevices.getUserMedia({
210                    video: true,
211                    audio: true
212                });
213                const videoElement = safeGetElement('videoElement');
214                if (videoElement) {
215                    videoElement.srcObject = stream;
216                }
217                safeSetText('videoStatus', 'โœ… Camera Ready');
218
219                // Load first question
220                loadQuestion();
221            } catch (error) {
222                console.error('Error accessing camera:', error);
223                safeSetText('videoStatus', 'โŒ Camera Error');
224                alert('Please allow camera and microphone access to continue.');
225            }
226        }
227
228        // Load current question
229        async function loadQuestion() {
230            try {
231                safeSetText('statusMessage', 'Loading question...');
232
233                const response = await fetch(`/api/get-question/${sessionId}`);
234                const data = await response.json();
235
236                if (data.completed) {
237                    window.location.href = `/results/${sessionId}`;
238                    return;
239                }
240
241                // Update question display
242                safeSetText('questionNumber', `Question ${data.question_number} of ${data.total_questions}`);
243                safeSetText('questionCategory', data.category || 'Resume-Based');
244                safeSetText('questionText', data.question);
245                safeSetText('questionFocus', data.focus_area || '');
246
247                // Update progress
248                const progress = ((data.question_number - 1) / data.total_questions) * 100;
249                safeSetStyle('progressFill', { width: `${progress}%` });
250                safeSetText('progressText', `${data.question_number - 1} of ${data.total_questions} questions completed`);
251
252                // Enable recording
253                safeSetDisabled('startRecording', false);
254                safeSetText('statusMessage', 'Ready to record your answer');
255
256                // Speak the question
257                speakQuestion(data.question);
258
259            } catch (error) {
260                console.error('Error loading question:', error);
261                safeSetText('statusMessage', 'Error loading question: ' + error.message);
262            }
263        }
264
265        // Text-to-speech for question
266        function speakQuestion(text) {
267            if ('speechSynthesis' in window) {
268                speechSynthesis.cancel();
269                
270                const utterance = new SpeechSynthesisUtterance(text);
271                utterance.rate = 0.9;
272                utterance.pitch = 1;
273                utterance.volume = 1;
274                speechSynthesis.speak(utterance);
275            }
276        }
277
278        // Start recording
279        const startRecordingBtn = safeGetElement('startRecording');
280        if (startRecordingBtn) {
281            startRecordingBtn.addEventListener('click', async () => {
282                try {
283                    console.log('Start recording clicked');
284                    
285                    // Reset transcript
286                    currentTranscript = '';
287                    safeSetText('transcript', 'Listening...');
288                    safeSetText('wordCount', 'Words: 0');
289                    safeSetStyle('feedbackSection', { display: 'none' });
290
291                    // Start speech recognition
292                    if (recognition) {
293                        isRecording = true;
294                        recognition.start();
295                        console.log('Speech recognition started');
296                    }
297
298                    // Update UI
299                    safeSetStyle('startRecording', { display: 'none' });
300                    safeSetStyle('stopRecording', { display: 'block' });
301                    safeSetDisabled('stopRecording', false);
302                    safeToggleClass('recordingIndicator', 'hidden', false);
303                    safeSetText('statusMessage', '๐ŸŽค Recording... Speak your answer clearly');
304
305                    // Start timer
306                    recordingStartTime = Date.now();
307                    timerInterval = setInterval(updateTimer, 1000);
308
309                } catch (error) {
310                    console.error('Error starting recording:', error);
311                    alert('Error starting recording: ' + error.message);
312                    isRecording = false;
313                }
314            });
315        }
316
317        // Stop recording
318        const stopRecordingBtn = safeGetElement('stopRecording');
319        if (stopRecordingBtn) {
320            stopRecordingBtn.addEventListener('click', () => {
321                console.log('Stop recording clicked');
322                
323                // Stop speech recognition
324                isRecording = false;
325                if (recognition) {
326                    try {
327                        recognition.stop();
328                        console.log('Speech recognition stopped');
329                    } catch (e) {
330                        console.log('Error stopping recognition:', e);
331                    }
332                }
333
334                // Stop timer
335                clearInterval(timerInterval);
336
337                // Update UI
338                safeSetStyle('stopRecording', { display: 'none' });
339                safeToggleClass('recordingIndicator', 'hidden', true);
340                safeSetText('statusMessage', 'Processing your answer...');
341
342                // Show submit button
343                if (currentTranscript.trim().length > 0) {
344                    safeSetStyle('submitAnswer', { display: 'block' });
345                    safeSetDisabled('submitAnswer', false);
346                    safeSetText('statusMessage', 'Review your answer and click Submit');
347                } else {
348                    safeSetText('statusMessage', 'No speech detected. Please try again.');
349                    safeSetStyle('startRecording', { display: 'block' });
350                    safeSetDisabled('startRecording', false);
351                }
352            });
353        }
354
355        // Submit answer
356        const submitAnswerBtn = safeGetElement('submitAnswer');
357        if (submitAnswerBtn) {
358            submitAnswerBtn.addEventListener('click', async () => {
359                const answer = currentTranscript.trim();
360
361                if (!answer) {
362                    alert('Please record an answer first');
363                    return;
364                }
365
366                safeSetDisabled('submitAnswer', true);
367                safeSetText('statusMessage', 'Analyzing your answer...');
368
369                try {
370                    const duration = (Date.now() - recordingStartTime) / 1000;
371
372                    const response = await fetch(`/api/submit-answer/${sessionId}`, {
373                        method: 'POST',
374                        headers: {
375                            'Content-Type': 'application/json'
376                        },
377                        body: JSON.stringify({
378                            answer: answer,
379                            duration: duration
380                        })
381                    });
382
383                    const data = await response.json();
384
385                    if (data.success) {
386                        // Show feedback
387                        safeSetText('answerScore', data.score.toFixed(1));
388                        const feedbackList = safeGetElement('feedbackList');
389                        if (feedbackList) {
390                            feedbackList.innerHTML = '';
391                            data.feedback.forEach(fb => {
392                                const li = document.createElement('li');
393                                li.textContent = fb;
394                                feedbackList.appendChild(li);
395                            });
396                        }
397                        safeSetStyle('feedbackSection', { display: 'block' });
398
399                        // Wait 3 seconds then move to next question
400                        safeSetText('statusMessage',
401                            data.is_complete ? 'Interview complete! Redirecting...' : 'Loading next question...');
402                        
403                        setTimeout(() => {
404                            if (data.is_complete) {
405                                window.location.href = `/results/${sessionId}`;
406                            } else {
407                                // Reset for next question
408                                safeSetStyle('submitAnswer', { display: 'none' });
409                                safeSetStyle('startRecording', { display: 'block' });
410                                safeSetText('recordingTimer', '00:00');
411                                safeSetHTML('transcript', '<em>Your answer will appear here as you speak...</em>');
412                                safeSetText('wordCount', 'Words: 0');
413                                loadQuestion();
414                            }
415                        }, 3000);
416                    } else {
417                        alert('Error submitting answer: ' + (data.error || 'Unknown error'));
418                        safeSetDisabled('submitAnswer', false);
419                    }
420                } catch (error) {
421                    console.error('Error submitting answer:', error);
422                    alert('Error submitting answer: ' + error.message);
423                    safeSetDisabled('submitAnswer', false);
424                }
425            });
426        }
427
428        // Update recording timer
429        function updateTimer() {
430            const elapsed = Math.floor((Date.now() - recordingStartTime) / 1000);
431            const minutes = Math.floor(elapsed / 60);
432            const seconds = elapsed % 60;
433            safeSetText('recordingTimer',
434                `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`);
435        }
436
437        // Initialize on page load
438        window.addEventListener('load', () => {
439            console.log('Page loaded, initializing...');
440            initVideo();
441        });
442
443        // Cleanup on page unload
444        window.addEventListener('beforeunload', () => {
445            isRecording = false;
446            if (recognition) {
447                try {
448                    recognition.stop();
449                } catch (e) {
450                    console.log('Cleanup error:', e);
451                }
452            }
453        });
454    </script>
455</body>
456
457</html>