Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ Online learning has taken the front seat in the post-pandemic age. With the adve

EduAid is one such project currently available in the form of a browser extension.

## System Requirements

- **ffmpeg** or **libav** installed and available on your system `PATH`. Required for transcoding audio formats such as `.mp3` to `.wav`. (Note: `.wav` files are supported directly by the backend and do not require conversion).
- The Python dependencies **pydub** and **SpeechRecognition** must be installed (these are automatically installed via `pip install -r requirements.txt`).

## Installation and Setup

### 1. Clone the Repository
Expand Down
80 changes: 71 additions & 9 deletions backend/Generator/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
import os
import fitz
import mammoth
import speech_recognition as sr
from pydub import AudioSegment
import uuid

class MCQGenerator:

Expand Down Expand Up @@ -367,20 +370,79 @@ def extract_text_from_docx(self, file_path):
result = mammoth.extract_raw_text(docx_file)
return result.value

def extract_text_from_audio(self, file_path):
wav_path = file_path
request_id = uuid.uuid4().hex
chunk_files = []
try:
if file_path.endswith('.mp3'):
audio = AudioSegment.from_file(file_path, format='mp3')
wav_path = os.path.join(self.upload_folder, f"{request_id}.wav")
audio.export(wav_path, format='wav')

r = sr.Recognizer()
audio = AudioSegment.from_wav(wav_path)

# Enforce max duration of 10 minutes (600,000 milliseconds)
max_duration_ms = 10 * 60 * 1000
if len(audio) > max_duration_ms:
raise ValueError("Audio file is too long. Maximum supported duration is 10 minutes.")

chunk_length_ms = 60 * 1000
audio_len = len(audio)

full_text = []
for i, start_ms in enumerate(range(0, audio_len, chunk_length_ms)):
chunk = audio[start_ms : start_ms + chunk_length_ms]
chunk_filename = os.path.join(self.upload_folder, f"{request_id}_chunk_{i}.wav")
chunk_files.append(chunk_filename)
chunk.export(chunk_filename, format='wav')

with sr.AudioFile(chunk_filename) as source:
audio_data = r.record(source)
try:
text = r.recognize_google(audio_data)
full_text.append(text)
except sr.UnknownValueError:
full_text.append("[Unintelligible]")
except sr.RequestError as e:
raise RuntimeError("Could not request results") from e
Comment thread
coderabbitai[bot] marked this conversation as resolved.
finally:
for chunk_file in chunk_files:
if os.path.exists(chunk_file):
os.remove(chunk_file)
if wav_path != file_path and os.path.exists(wav_path):
os.remove(wav_path)

return "\n".join(full_text)

def process_file(self, file):
file_path = os.path.join(self.upload_folder, file.filename)
# Extract and validate extension
_, ext = os.path.splitext(file.filename)
ext = ext.lower()
if ext not in ['.txt', '.pdf', '.docx', '.wav', '.mp3']:
raise ValueError('Unsupported file format')

# Generate safe storage name to prevent path traversal & collisions
temp_filename = f"{uuid.uuid4().hex}{ext}"
file_path = os.path.join(self.upload_folder, temp_filename)
file.save(file_path)
content = ""

if file.filename.endswith('.txt'):
with open(file_path, 'r') as f:
content = f.read()
elif file.filename.endswith('.pdf'):
content = self.extract_text_from_pdf(file_path)
elif file.filename.endswith('.docx'):
content = self.extract_text_from_docx(file_path)
try:
if ext == '.txt':
with open(file_path, 'r') as f:
content = f.read()
elif ext == '.pdf':
content = self.extract_text_from_pdf(file_path)
elif ext == '.docx':
content = self.extract_text_from_docx(file_path)
elif ext in ['.wav', '.mp3']:
content = self.extract_text_from_audio(file_path)
finally:
if os.path.exists(file_path):
os.remove(file_path)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

os.remove(file_path)
return content

class QuestionGenerator:
Expand Down
5 changes: 4 additions & 1 deletion backend/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,10 @@ def upload_file():
if file.filename == '':
return jsonify({"error": "No selected file"}), 400

content = file_processor.process_file(file)
try:
content = file_processor.process_file(file)
except (ValueError, RuntimeError) as e:
return jsonify({"error": str(e)}), 400

if content:
return jsonify({"content": content})
Expand Down
4 changes: 2 additions & 2 deletions eduaid_web/src/pages/Text_Input.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,9 @@ const Text_Input = () => {
{/* File Upload Section */}
<div className="w-full max-w-2xl mx-auto border-[3px] rounded-2xl text-center px-6 py-6 border-dotted border-[#3E5063] mt-6">
<img className="mx-auto mb-2" height={32} width={32} src={cloud} alt="cloud" />
<p className="text-white text-lg">Choose a file (PDF, MP3 supported)</p>
<p className="text-white text-lg">Choose a file (PDF, Audio supported)</p>

<input type="file" ref={fileInputRef} onChange={handleFileUpload} style={{ display: "none" }} />
<input type="file" accept=".txt,.pdf,.docx,.mp3,.wav" ref={fileInputRef} onChange={handleFileUpload} style={{ display: "none" }} />
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
<button
className="bg-[#3e506380] my-4 text-lg rounded-2xl text-white border border-[#cbd0dc80] px-6 py-2"
onClick={handleClick}
Expand Down
3 changes: 2 additions & 1 deletion extension/src/pages/text_input/TextInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,12 @@ function Second() {
<img className="mx-auto" height={24} width={24} src={cloud} alt="cloud" />
<div className="text-center text-white text-sm">Choose a file</div>
<div className="text-center text-white text-sm">
PDF, MP3 supported
PDF, Audio supported
</div>
<div>
<input
type="file"
accept=".txt,.pdf,.docx,.mp3,.wav"
ref={fileInputRef}
onChange={handleFileUpload}
style={{ display: 'none' }}
Expand Down
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,7 @@ tokenizers
mammoth
mediawikiapi
PyMuPDF
textblob
textblob==0.19.0
SpeechRecognition==3.14.5
pydub==0.25.1
llama-cpp-python