diff --git a/backend/server.py b/backend/server.py index ef5eda8..dc596a7 100644 --- a/backend/server.py +++ b/backend/server.py @@ -1,27 +1,31 @@ from flask import Flask, render_template, Response, jsonify, request import cv2 from mtcnn.mtcnn import MTCNN -from pydub import AudioSegment -import subprocess # For calling ffmpeg directly +import pyaudio import wave import threading +import speech_recognition as sr import cloudinary import cloudinary.uploader +import random import os import time from flask_cors import CORS +import os app = Flask(__name__) CORS(app, resources={r"/*": {"origins": "*"}}) -port = int(os.environ.get("PORT", 8000)) # Render uses dynamic ports # Initialize global variables cap = None +audio = None detector = MTCNN() +recognizer = sr.Recognizer() lock = threading.Lock() # Status flags camera_ready = False +audio_ready = False recording_in_progress = False test_ready = False @@ -33,11 +37,10 @@ ) def initialize_devices(): - global cap, camera_ready + global cap, audio, camera_ready, audio_ready try: # Initialize camera - print("Camera initialized successfully") if cap is None: cap = cv2.VideoCapture(0) if cap.isOpened(): @@ -47,41 +50,32 @@ def initialize_devices(): print("Failed to initialize camera") return False - return camera_ready + # Initialize audio + if audio is None: + audio = pyaudio.PyAudio() + try: + # Test audio input + stream = audio.open( + format=pyaudio.paInt16, + channels=1, + rate=16000, + input=True, + frames_per_buffer=1024, + start=False + ) + stream.close() + audio_ready = True + print("Audio initialized successfully") + except Exception as e: + print(f"Failed to initialize audio: {e}") + return False + + return camera_ready and audio_ready except Exception as e: print(f"Error initializing devices: {e}") return False -def record_audio_with_ffmpeg(name, papercode, duration=5): - try: - file_basename = f"{name}_{papercode}" - filename = f"{file_basename}_audio.wav" - - # Use ffmpeg to record audio from the default system microphone - subprocess.run([ - "ffmpeg", "-y", "-f", "alsa", "-i", "default", - "-t", str(duration), filename - ]) - - # Upload to Cloudinary - response = cloudinary.uploader.upload( - filename, - resource_type="raw", - public_id=f"{file_basename}_audio", - folder="media" - ) - - # Clean up temporary file - if os.path.exists(filename): - os.remove(filename) - - return response['secure_url'] - - except Exception as e: - print(f"Error recording audio: {e}") - return None - def record_video(name, papercode, duration=5): global recording_in_progress @@ -136,12 +130,58 @@ def record_video(name, papercode, duration=5): recording_in_progress = False return None + +def record_audio(name, papercode, duration=5): + try: + file_basename = f"{name}_{papercode}" + filename = f"{file_basename}_audio.wav" + + stream = audio.open( + format=pyaudio.paInt16, + channels=1, + rate=16000, + input=True, + frames_per_buffer=1024 + ) + + frames = [] + for _ in range(0, int(16000 / 1024 * duration)): + data = stream.read(1024) + frames.append(data) + + stream.stop_stream() + stream.close() + + with wave.open(filename, 'wb') as wf: + wf.setnchannels(1) + wf.setsampwidth(audio.get_sample_size(pyaudio.paInt16)) + wf.setframerate(16000) + wf.writeframes(b''.join(frames)) + + # Upload to Cloudinary + response = cloudinary.uploader.upload( + filename, + resource_type="raw", + public_id=f"{file_basename}_audio", + folder="media" + ) + + # Clean up temporary file + if os.path.exists(filename): + os.remove(filename) + + return response['secure_url'] + + except Exception as e: + print(f"Error recording audio: {e}") + return None + def run_test_recording(name, papercode, login_status): global test_ready try: while login_status: # Keep recording until the login status is false video_url = record_video(name, papercode) - audio_url = record_audio_with_ffmpeg(name, papercode) + audio_url = record_audio(name, papercode) if video_url and audio_url: test_ready = True @@ -149,6 +189,7 @@ def run_test_recording(name, papercode, login_status): else: return {'status': 'error', 'message': 'Failed to record video or audio'} + # If login_status becomes false, stop recording and cleanup return {'status': 'error', 'message': 'Recording stopped due to logout'} except Exception as e: @@ -174,16 +215,19 @@ def start_test(): def check_test_status(): return jsonify({ 'camera_ready': camera_ready, + 'audio_ready': audio_ready, 'recording_in_progress': recording_in_progress, 'test_ready': test_ready }) + @app.route('/initialize_devices') def check_devices(): success = initialize_devices() return jsonify({ 'success': success, - 'camera_ready': camera_ready + 'camera_ready': camera_ready, + 'audio_ready': audio_ready }) def generate_frames(): @@ -204,4 +248,4 @@ def video_feed(): mimetype='multipart/x-mixed-replace; boundary=frame') if __name__ == '__main__': - app.run(host='0.0.0.0', port=port, debug=True) + app.run(debug=True) \ No newline at end of file diff --git a/src/verification/verification.jsx b/src/verification/verification.jsx index 79a24ab..96df4cd 100644 --- a/src/verification/verification.jsx +++ b/src/verification/verification.jsx @@ -30,7 +30,7 @@ const Verification = () => { }, []) const checkDevices = () => { - fetch('https://iips-exam-student-portal.onrender.com/initialize_devices') + fetch('http://127.0.0.1:5000/initialize_devices') .then((response) => response.json()) .then((data) => { setDeviceStatus({ @@ -61,7 +61,7 @@ const Verification = () => { setIsRecording(true); setTestStatus('Please wait...'); - fetch('https://iips-exam-student-portal.onrender.com/start_test', { + fetch('http://127.0.0.1:5000/start_test', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ @@ -72,7 +72,7 @@ const Verification = () => { }) .then(() => { const intervalId = setInterval(() => { - fetch('https://iips-exam-student-portal.onrender.com/check_test_status') + fetch('http://127.0.0.1:5000/check_test_status') .then((response) => response.json()) .then((statusData) => { if (statusData.recording_in_progress) { @@ -98,7 +98,7 @@ const Verification = () => { setIsRecording(false); setTestStatus('Recording stopped due to logout.'); // Send a request to stop the recording on the server - fetch('https://iips-exam-student-portal.onrender.com/start_test', { + fetch('http://127.0.0.1:5000/start_test', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ @@ -128,7 +128,7 @@ const Verification = () => { Webcam feed