diff --git a/backend/Dockerfile b/backend/Dockerfile index 2302c88..c93d0fb 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -4,24 +4,18 @@ FROM python:3.9 # Set the working directory inside the container WORKDIR /app -# Install system dependencies for PyAudio and other build tools +# Install system dependencies for OpenCV and other tools (pyaudio dependencies removed) RUN apt-get update && apt-get install -y \ - portaudio19-dev \ - libasound2-dev \ - libjack-dev \ curl \ + libsm6 \ + libxext6 \ + libgl1-mesa-glx \ build-essential \ - libssl-dev \ - libffi-dev \ - python3-dev \ && rm -rf /var/lib/apt/lists/* # Clean up apt cache to reduce image size # Upgrade pip RUN python -m pip install --upgrade pip -# Install PyAudio -RUN pip install --no-cache-dir PyAudio - # Copy application code into the container COPY . . diff --git a/backend/server.py b/backend/server.py index 42187ae..2d0832b 100644 --- a/backend/server.py +++ b/backend/server.py @@ -1,33 +1,28 @@ from flask import Flask, render_template, Response, jsonify, request import cv2 from mtcnn.mtcnn import MTCNN -import pyaudio +import sounddevice as sd +import numpy as np 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)) # Railway uses dynamic ports -app.run(host='0.0.0.0', port=port) +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 @@ -39,7 +34,7 @@ ) def initialize_devices(): - global cap, audio, camera_ready, audio_ready + global cap, camera_ready try: # Initialize camera @@ -52,32 +47,47 @@ def initialize_devices(): print("Failed to initialize camera") return False - # 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 + return camera_ready except Exception as e: print(f"Error initializing devices: {e}") return False +def record_audio(name, papercode, duration=5): + try: + file_basename = f"{name}_{papercode}" + filename = f"{file_basename}_audio.wav" + + # Capture audio data + sample_rate = 16000 + recording = sd.rec(int(duration * sample_rate), samplerate=sample_rate, channels=1, dtype='int16') + sd.wait() # Wait until recording is finished + + # Save the recording to a WAV file + with wave.open(filename, 'wb') as wf: + wf.setnchannels(1) + wf.setsampwidth(2) # 2 bytes per sample (16-bit audio) + wf.setframerate(sample_rate) + wf.writeframes(recording.tobytes()) + + # 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 @@ -132,52 +142,6 @@ 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: @@ -191,7 +155,6 @@ 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: @@ -217,19 +180,16 @@ 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, - 'audio_ready': audio_ready + 'camera_ready': camera_ready }) def generate_frames(): @@ -250,4 +210,4 @@ def video_feed(): mimetype='multipart/x-mixed-replace; boundary=frame') if __name__ == '__main__': - app.run(debug=True) + app.run(host='0.0.0.0', port=port, debug=True)