from flask import Flask, render_template, request, jsonify, session, redirect, url_for, send_file from flask_sqlalchemy import SQLAlchemy from flask_mail import Mail, Message from werkzeug.security import generate_password_hash, check_password_hash import sqlite3 import pandas as pd import os import cv2 import numpy as np from datetime import datetime, time, date import base64 import json import random app = Flask(__name__) app.config['SECRET_KEY'] = 'your_secret_key_here' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # Email configuration app.config['MAIL_SERVER'] = 'smtp.gmail.com' app.config['MAIL_PORT'] = 465 app.config['MAIL_USERNAME'] = 'your_email@gmail.com' app.config['MAIL_PASSWORD'] = 'your_password' app.config['MAIL_USE_TLS'] = False app.config['MAIL_USE_SSL'] = True db = SQLAlchemy(app) mail = Mail(app) # User Model class User(db.Model): id = db.Column(db.Integer, primary_key=True) full_name = db.Column(db.String(100), nullable=False) email = db.Column(db.String(100), unique=True, nullable=False) username = db.Column(db.String(50), unique=True, nullable=False) password = db.Column(db.String(100), nullable=False) role = db.Column(db.String(10), nullable=False) enrollment_number = db.Column(db.String(20), unique=True, nullable=True) phone_number = db.Column(db.String(20), nullable=True) student_number = db.Column(db.String(20), unique=True, nullable=True) parent_number = db.Column(db.String(20), nullable=True) parent_email = db.Column(db.String(100), nullable=True) selected_class = db.Column(db.String(10), nullable=True) selected_regular_subjects = db.Column(db.Text, nullable=True) # JSON list selected_specializations = db.Column(db.Text, nullable=True) # JSON list selected_batch = db.Column(db.String(20), nullable=True) selected_practicals = db.Column(db.Text, nullable=True) # JSON list # Daily PIN Model class DailyPin(db.Model): id = db.Column(db.Integer, primary_key=True) class_name = db.Column(db.String(10), nullable=False) pin = db.Column(db.String(4), nullable=False) date = db.Column(db.Date, nullable=False) # Timetable Database Setup def get_db_connection(): conn = sqlite3.connect('config.db') conn.row_factory = sqlite3.Row return conn def init_timetable_db(): conn = get_db_connection() conn.execute(''' CREATE TABLE IF NOT EXISTS teacher_config ( id INTEGER PRIMARY KEY AUTOINCREMENT, class_name TEXT NOT NULL, config_type TEXT NOT NULL, name TEXT NOT NULL ) ''') conn.commit() conn.close() # Create databases with app.app_context(): db.create_all() init_timetable_db() # Attendance System Setup face_cascade = cv2.CascadeClassifier("haarcascade_frontalface_alt.xml") dataset_path = "./face_dataset/" attendance_path = "./attendance_data/" os.makedirs(dataset_path, exist_ok=True) os.makedirs(attendance_path, exist_ok=True) # Function to get or generate daily PIN for a class def get_daily_pin(class_name): today = date.today() pin_entry = DailyPin.query.filter_by(class_name=class_name, date=today).first() if not pin_entry: pin = f"{random.randint(0, 9999):04d}" # Generate 4-digit PIN pin_entry = DailyPin(class_name=class_name, pin=pin, date=today) db.session.add(pin_entry) db.session.commit() return pin_entry.pin # Combined Routes @app.route('/') def index(): return render_template('index.html') @app.route('/signup', methods=['POST']) def signup(): data = request.json full_name = data.get('full_name') email = data.get('email') username = data.get('username') password = data.get('password') role = data.get('role') enrollment = data.get('enrollment_number') if role == 'student' else None phone_number = data.get('phone_number') if role == 'teacher' else None student_number = data.get('student_number') if role == 'student' else None parent_number = data.get('parent_number') if role == 'student' else None parent_email = data.get('parent_email') if role == 'student' else None if not all([full_name, email, username, password, role]): return jsonify({'success': False, 'message': 'All fields are required!'}) if role == 'student' and not enrollment: return jsonify({'success': False, 'message': 'Enrollment number is required for students!'}) if role == 'teacher' and not phone_number: return jsonify({'success': False, 'message': 'Phone number is required for teachers!'}) if User.query.filter((User.username == username) | (User.email == email) | (User.enrollment_number == enrollment) | (User.student_number == student_number)).first(): return jsonify({'success': False, 'message': 'Username, email, enrollment, or student number already exists!'}) hashed = generate_password_hash(password) u = User( full_name=full_name, email=email, username=username, password=hashed, role=role, enrollment_number=enrollment, phone_number=phone_number, student_number=student_number, parent_number=parent_number, parent_email=parent_email ) db.session.add(u) db.session.commit() return jsonify({'success': True, 'message': 'Account created successfully! Please log in.'}) @app.route('/login', methods=['POST']) def login(): data = request.json username = data.get('username') password = data.get('password') role = data.get('role') user = User.query.filter_by(username=username, role=role).first() if user and check_password_hash(user.password, password): session['user_id'] = user.id session['role'] = user.role redirect_url = '/teacher_dashboard' if role == 'teacher' else '/student_dashboard' return jsonify({'success': True, 'redirect': redirect_url}) return jsonify({'success': False, 'message': 'Invalid username or password'}) @app.route('/logout') def logout(): session.clear() return redirect(url_for('index')) @app.route('/teacher_dashboard') def teacher_dashboard(): if 'user_id' not in session or session['role'] != 'teacher': return redirect(url_for('index')) user = db.session.get(User, session['user_id']) pin = get_daily_pin(user.selected_class) if user.selected_class else None return render_template('teacher_dashboard.html', user=user, selected_class=user.selected_class, daily_pin=pin) @app.route('/api/update_teacher_profile', methods=['POST']) def update_teacher_profile(): if 'user_id' not in session or session['role'] != 'teacher': return jsonify({'success': False, 'message': 'Unauthorized'}), 401 data = request.json user = db.session.get(User, session['user_id']) user.full_name = data['full_name'] user.email = data['email'] user.phone_number = data['phone_number'] db.session.commit() return jsonify({'success': True, 'message': 'Profile updated'}) @app.route('/get_students', methods=['GET']) def get_students(): class_name = request.args.get('class') students = User.query.filter_by(role='student', selected_class=class_name).all() students_data = [{'id': s.id, 'full_name': s.full_name, 'enrollment_number': s.enrollment_number} for s in students] return jsonify({'students': students_data}) @app.route('/api/select_teacher_class', methods=['POST']) def select_teacher_class(): if 'user_id' not in session or session['role'] != 'teacher': return jsonify({'success': False}), 401 data = request.json cls = data.get('class') user = db.session.get(User, session['user_id']) user.selected_class = cls db.session.commit() return jsonify({'success': True}) @app.route('/get_student_details', methods=['GET']) def get_student_details(): student_id = request.args.get('id') student = db.session.get(User, student_id) if not student or student.role != 'student': return jsonify({'error': 'Student not found'}), 404 subject_attendance = get_subject_attendance(student) regular_subjects = [{'name': subj, 'attendance_count': subject_attendance['regular'].get(subj, {'attendance': 0})['attendance'], 'total_count': subject_attendance['regular'].get(subj, {'total': 0})['total']} for subj in json.loads(student.selected_regular_subjects or '[]')] specialization_subjects = [{'name': subj, 'attendance_count': subject_attendance['specialization'].get(subj, {'attendance': 0})['attendance'], 'total_count': subject_attendance['specialization'].get(subj, {'total': 0})['total']} for subj in json.loads(student.selected_specializations or '[]')] practical_subjects = [{'name': subj, 'batch': student.selected_batch or 'N/A', 'attendance_count': subject_attendance['practical'].get(subj, {'attendance': 0})['attendance'], 'total_count': subject_attendance['practical'].get(subj, {'total': 0})['total']} for subj in json.loads(student.selected_practicals or '[]')] face_folder = os.path.join(dataset_path, student.selected_class or '') face_file = f"{student.enrollment_number}_{student.full_name}.npy" face_registered = os.path.exists(os.path.join(face_folder, face_file)) student_data = { 'enrollment_number': student.enrollment_number, 'email': student.email, 'student_number': student.student_number, 'parent_number': student.parent_number, 'parent_email': student.parent_email, 'regular_subjects': regular_subjects, 'specialization_subjects': specialization_subjects, 'practical_subjects': practical_subjects, 'face_registered': face_registered } return jsonify(student_data) @app.route('/student_dashboard') def student_dashboard(): if 'user_id' not in session or session['role'] != 'student': return redirect(url_for('index')) user = db.session.get(User, session['user_id']) face_folder = os.path.join(dataset_path, (user.selected_class or '')) face_file = f"{user.enrollment_number}_{user.full_name}.npy" face_exists = os.path.exists(os.path.join(face_folder, face_file)) subject_attendance = get_subject_attendance(user) teachers = User.query.filter_by(role='teacher', selected_class=user.selected_class).all() return render_template('student_dashboard.html', user=user, selected_regular_subjects=json.loads(user.selected_regular_subjects or '[]'), selected_specializations=json.loads(user.selected_specializations or '[]'), selected_practicals=json.loads(user.selected_practicals or '[]'), subject_attendance=subject_attendance, face_exists=face_exists, teachers=teachers) @app.route('/api/update_profile', methods=['POST']) def update_profile(): if 'user_id' not in session or session['role'] != 'student': return jsonify({'success': False, 'message': 'Unauthorized'}), 401 data = request.json user = db.session.get(User, session['user_id']) user.full_name = data['full_name'] user.enrollment_number = data['enrollment_number'] user.email = data['email'] user.student_number = data['student_number'] user.parent_number = data['parent_number'] user.parent_email = data['parent_email'] db.session.commit() return jsonify({'success': True, 'message': 'Profile updated'}) @app.route('/api/select_class', methods=['POST']) def api_select_class(): if 'user_id' not in session or session['role'] != 'student': return jsonify({'success': False}), 401 data = request.json cls = data.get('class') user = db.session.get(User, session['user_id']) user.selected_class = cls db.session.commit() return jsonify({'success': True}) @app.route('/api/update_regular_subjects', methods=['POST']) def update_regular_subjects(): if 'user_id' not in session: return jsonify(success=False), 401 subjects = request.json.get('subjects') u = db.session.get(User, session['user_id']) u.selected_regular_subjects = json.dumps(subjects) db.session.commit() return jsonify(success=True) @app.route('/api/update_specializations', methods=['POST']) def update_specializations(): if 'user_id' not in session: return jsonify(success=False), 401 subjects = request.json.get('subjects') u = db.session.get(User, session['user_id']) u.selected_specializations = json.dumps(subjects) db.session.commit() return jsonify(success=True) @app.route('/api/update_batch', methods=['POST']) def update_batch(): if 'user_id' not in session: return jsonify(success=False), 401 batch = request.json.get('batch') u = db.session.get(User, session['user_id']) u.selected_batch = batch db.session.commit() return jsonify(success=True) @app.route('/api/update_practicals', methods=['POST']) def update_practicals(): if 'user_id' not in session: return jsonify(success=False), 401 practs = request.json.get('practicals') u = db.session.get(User, session['user_id']) u.selected_practicals = json.dumps(practs) db.session.commit() return jsonify(success=True) def get_excel_filename(class_name): if class_name: return f"{class_name}_timetable.xlsx" return "timetable.xlsx" @app.route('/timetable') def timetable_page(): if 'user_id' not in session or session['role'] != 'teacher': return redirect(url_for('index')) return render_template('timetable.html') @app.route('/add_config', methods=['POST']) def add_config(): data = request.get_json() class_name = data.get("class") config_type = data.get("type") name = data.get("name") if not (class_name and config_type and name): return jsonify({"error": "Missing parameters"}), 400 conn = get_db_connection() conn.execute('INSERT INTO teacher_config (class_name, config_type, name) VALUES (?, ?, ?)', (class_name, config_type, name)) conn.commit() conn.close() return jsonify({"message": "Added successfully"}) @app.route('/delete_config', methods=['POST']) def delete_config(): data = request.get_json() class_name = data.get("class") config_type = data.get("type") name = data.get("name") if not (class_name and config_type and name): return jsonify({"error": "Missing parameters"}), 400 conn = get_db_connection() conn.execute('DELETE FROM teacher_config WHERE class_name=? AND config_type=? AND name=?', (class_name, config_type, name)) conn.commit() conn.close() return jsonify({"message": "Deleted successfully"}) @app.route('/get_config', methods=['GET']) def get_config(): class_name = request.args.get("class") config_type = request.args.get("type") if not (class_name and config_type): return jsonify([]) conn = get_db_connection() configs = conn.execute('SELECT name FROM teacher_config WHERE class_name=? AND config_type=?', (class_name, config_type)).fetchall() conn.close() return jsonify([row["name"] for row in configs]) @app.route('/load', methods=['GET']) def load_timetable(): class_name = request.args.get('class') filename = get_excel_filename(class_name) if not os.path.exists(filename): return jsonify({}) df = pd.read_excel(filename, index_col=0) return df.to_json() @app.route('/save', methods=['POST']) def save_timetable(): payload = request.get_json() teacher_class = payload.get("class", "") data = payload.get("timetable", {}) filename = get_excel_filename(teacher_class) df = pd.DataFrame(data) df.to_excel(filename) return jsonify({'message': f'Saved successfully to {filename}!'}) @app.route('/download_excel', methods=['GET']) def download_excel(): class_name = request.args.get('class') filename = get_excel_filename(class_name) if not os.path.exists(filename): return "File not found", 404 return send_file(filename, as_attachment=True) def distance(v1, v2): return np.sqrt(((v1 - v2) ** 2).sum()) def knn(train, test, k=5): dist = [] for i in range(train.shape[0]): ix = train[i, :-1] iy = train[i, -1] d = distance(test, ix) dist.append([d, iy]) dk = sorted(dist, key=lambda x: x[0])[:k] labels = np.array(dk)[:, -1] return np.unique(labels, return_counts=True)[0][0] class AttendanceSystem: def __init__(self, class_name): self.class_name = class_name self.main_file = os.path.join(attendance_path, f"{class_name}.xlsx") self.pending_file = os.path.join(attendance_path, f"{class_name}_pending.xlsx") self.columns = ["Enrollment", "Name", "Date", "Day", "CheckIn", "CheckOut"] for f in [self.main_file, self.pending_file]: if not os.path.exists(f): pd.DataFrame(columns=self.columns).to_excel(f, index=False) def checkin(self, enrollment, name, pin): today = datetime.now().strftime("%Y-%m-%d") correct_pin = get_daily_pin(self.class_name) if pin != correct_pin: return False, "Invalid PIN." now = datetime.now() checkin_time = now.strftime("%H.%M") df_main = pd.read_excel(self.main_file) if ((df_main["Enrollment"] == enrollment) & (df_main["Date"] == today)).any(): return False, "You have already checked in and checked out today." df_pending = pd.read_excel(self.pending_file) if ((df_pending["Enrollment"] == enrollment) & (df_pending["Date"] == today)).any(): return False, "You have already checked in today. Please check out first." if now.time() < datetime.strptime("08:00", "%H:%M").time(): return False, "Check-in starts at 8 AM." day_name = now.strftime("%A") new_entry = pd.DataFrame([[enrollment, name, today, day_name, checkin_time, ""]], columns=self.columns) df_pending = pd.concat([df_pending, new_entry], ignore_index=True) df_pending.to_excel(self.pending_file, index=False) return True, "Check-in successful. Please remember to check out later." def checkout(self, enrollment): now = datetime.now() today = now.strftime("%Y-%m-%d") checkout_time = now.strftime("%H.%M") df_pending = pd.read_excel(self.pending_file) df_main = pd.read_excel(self.main_file) has_main = ((df_main["Enrollment"] == enrollment) & (df_main["Date"] == today)).any() has_pending = ((df_pending["Enrollment"] == enrollment) & (df_pending["Date"] == today)).any() if not has_pending and has_main: return False, "You have already checked out today." if not has_pending: return False, "No pending check-in found. Please check in first." if now.time() > datetime.strptime("18:00", "%H:%M").time(): return False, "You missed check-out time. Contact your class teacher." idx = df_pending[(df_pending["Enrollment"] == enrollment) & (df_pending["Date"] == today)].index[0] pending_entry = df_pending.loc[idx] new_row = { "Enrollment": pending_entry["Enrollment"], "Name": pending_entry["Name"], "Date": today, "Day": pending_entry["Day"], "CheckIn": pending_entry["CheckIn"], "CheckOut": checkout_time } df_main = pd.concat([df_main, pd.DataFrame([new_row])], ignore_index=True) df_main.to_excel(self.main_file, index=False) df_pending = df_pending.drop(idx) df_pending.to_excel(self.pending_file, index=False) return True, "Check-out successful. Attendance recorded." import pandas as pd from datetime import datetime, time def parse_time(val): if pd.isna(val): return None s = str(val).replace('.', ':') if ':' not in s and len(s) >= 3 and s.isdigit(): s = s[:-2] + ':' + s[-2:] try: return datetime.strptime(s, '%H:%M').time() except ValueError: return datetime.strptime(s, '%I:%M').time() def parse_timetable_time(time_str): time_str = time_str.replace('.', ':') hour, minute = map(int, time_str.split(':')) if 1 <= hour <= 5: hour += 12 return time(hour, minute) def get_slot_type(content): content = "" if pd.isna(content) else str(content) if "Batch" in content: return "practical" elif "
" in content: return "specialization" elif content in ["Short Break", "Lunch Break"]: return "break" elif content.strip() == "": return "break" else: return "regular" def parse_practical(content): lines = content.split('
') batch_subjects = {} for line in lines: if ':' in line: batch, subject = line.split(':') batch = batch.strip().replace('Batch ', '') subject = subject.strip() batch_subjects[batch] = subject return batch_subjects def parse_specialization(content): return [subj.strip() for subj in content.split('
')] def get_slots(df, day): row = df.loc[day] slots = [] for col in df.columns: start_str, end_str = col.split(" - ") start_time = parse_timetable_time(start_str) end_time = parse_timetable_time(end_str) content = row[col] if pd.isna(content) or str(content).strip() == "": continue slots.append({ "start": start_time, "end": end_time, "content": str(content) }) return slots def get_subject_attendance(user): class_name = user.selected_class attendance_file = os.path.join(attendance_path, f"{class_name}.xlsx") if not os.path.exists(attendance_file): return {'regular': {}, 'specialization': {}, 'practical': {}} df_att = pd.read_excel(attendance_file) all_dates = df_att['Date'].unique() timetable_file = f"{class_name}_timetable.xlsx" if not os.path.exists(timetable_file): return {'regular': {}, 'specialization': {}, 'practical': {}} df_timetable = pd.read_excel(timetable_file, index_col=0) regular_counts = {subj: {'attendance': 0, 'total': 0} for subj in json.loads(user.selected_regular_subjects or '[]')} spec_counts = {subj: {'attendance': 0, 'total': 0} for subj in json.loads(user.selected_specializations or '[]')} prac_counts = {subj: {'attendance': 0, 'total': 0} for subj in json.loads(user.selected_practicals or '[]')} for date in all_dates: day = datetime.strptime(date, '%Y-%m-%d').strftime('%A') if day not in df_timetable.index: continue slots = get_slots(df_timetable, day) student_att = df_att[(df_att['Enrollment'] == user.enrollment_number) & (df_att['Date'] == date)] if not student_att.empty: check_in_str = student_att['CheckIn'].values[0] check_out_str = student_att['CheckOut'].values[0] check_in_time = parse_time(check_in_str) check_out_time = parse_time(check_out_str) else: check_in_time = None check_out_time = None for slot in slots: slot_start = slot['start'] slot_end = slot['end'] content = slot['content'] slot_type = get_slot_type(content) if slot_type == 'regular': subject = content if subject in regular_counts: regular_counts[subject]['total'] += 1 if check_in_time and check_in_time <= slot_start and check_out_time >= slot_end: regular_counts[subject]['attendance'] += 1 elif slot_type == 'specialization': subjects = parse_specialization(content) selected_specs = json.loads(user.selected_specializations or '[]') for selected_spec in selected_specs: if selected_spec in subjects: spec_counts[selected_spec]['total'] += 1 if check_in_time and check_in_time <= slot_start and check_out_time >= slot_end: spec_counts[selected_spec]['attendance'] += 1 elif slot_type == 'practical': batch_subjects = parse_practical(content) if user.selected_batch in batch_subjects: subject = batch_subjects[user.selected_batch] if subject in prac_counts: prac_counts[subject]['total'] += 1 if check_in_time and check_in_time <= slot_start and check_out_time >= slot_end: prac_counts[subject]['attendance'] += 1 return { 'regular': regular_counts, 'specialization': spec_counts, 'practical': prac_counts } @app.route('/check_attendance', methods=['GET']) def check_attendance(): students = User.query.filter_by(role='student').all() for student in students: subject_attendance = get_subject_attendance(student) total_attendance = 0 total_possible = 0 for subj_type in ['regular', 'specialization', 'practical']: for subj, counts in subject_attendance[subj_type].items(): total_attendance += counts['attendance'] total_possible += counts['total'] if total_possible > 0: overall_percentage = (total_attendance / total_possible) * 100 if overall_percentage < 75: details = { 'regular': [], 'specialization': [], 'practical': [] } for subj_type in ['regular', 'specialization', 'practical']: for subj, counts in subject_attendance[subj_type].items(): percentage = (counts['attendance'] / counts['total'] * 100) if counts['total'] > 0 else 0 details[subj_type].append({ 'subject': subj, 'attendance_count': counts['attendance'], 'total_count': counts['total'], 'percentage': round(percentage, 2) }) send_attendance_email(student, overall_percentage, details) return 'Attendance check completed' def send_attendance_email(student, overall_percentage, details): subject = "Low Attendance Alert" recipients = [student.email] if student.parent_email: recipients.append(student.parent_email) body = f""" Dear {student.full_name}, Your overall attendance average is {overall_percentage:.2f}%, which is below the required 75%. Here are your attendance details: Regular Subjects: """ for subj in details['regular']: body += f"- {subj['subject']}: {subj['attendance_count']}/{subj['total_count']} ({subj['percentage']}%\n" body += "\nSpecialization Subjects:\n" for subj in details['specialization']: body += f"- {subj['subject']}: {subj['attendance_count']}/{subj['total_count']} ({subj['percentage']}%\n" body += "\nPractical Subjects:\n" for subj in details['practical']: body += f"- {subj['subject']}: {subj['attendance_count']}/{subj['total_count']} ({subj['percentage']}%\n" body += "\nPlease take necessary actions to improve your attendance.\n\nBest regards,\nAttendance System" msg = Message(subject, recipients=recipients, body=body) mail.send(msg) @app.route('/mark_attendance') def mark_attendance_page(): return render_template('mark.html') @app.route('/register_face') def register_face_page(): if 'user_id' not in session or session['role'] != 'student': return redirect(url_for('index')) return render_template('register.html') @app.route('/api/register_face', methods=['POST']) def register_face(): data = request.json class_name = data['class_name'] name = data['name'] enrollment = data['enrollment'] images = data['images'] class_folder = os.path.join(dataset_path, class_name) os.makedirs(class_folder, exist_ok=True) face_data = [] for img_data in images: img_bytes = base64.b64decode(img_data.split(",")[1]) np_arr = np.frombuffer(img_bytes, np.uint8) img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray = cv2.equalizeHist(gray) faces = face_cascade.detectMultiScale(gray, 1.3, 5) for (x, y, w, h) in faces[:1]: face = img[y:y+h, x:x+w] face = cv2.resize(face, (100, 100)) face_data.append(face.flatten()) flipped = cv2.flip(face, 1) face_data.append(flipped.flatten()) if face_data: face_data = np.array(face_data) filename = f"{enrollment}_{name}.npy" np.save(os.path.join(class_folder, filename), face_data) return jsonify({"status": "success", "message": f"{len(face_data)} faces saved"}) return jsonify({"status": "fail", "message": "No faces detected"}) @app.route('/api/identify_face', methods=['POST']) def identify_face(): data = request.json class_name = data['class_name'] img_data = data['image'] img_bytes = base64.b64decode(img_data.split(",")[1]) np_arr = np.frombuffer(img_bytes, np.uint8) img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3, 5) class_folder = os.path.join(dataset_path, class_name) if not os.path.exists(class_folder): return jsonify({"status": "fail", "message": "No data for this class"}) face_data = [] labels = [] names = {} class_id = 0 for file in os.listdir(class_folder): if file.endswith('.npy'): data_arr = np.load(os.path.join(class_folder, file)) face_data.append(data_arr) parts = file[:-4].split('_', 1) labels.extend([class_id] * data_arr.shape[0]) names[class_id] = {'enrollment': parts[0], 'name': parts[1]} class_id += 1 if not face_data: return jsonify({"status": "fail", "message": "No trained data found"}) X_train = np.concatenate(face_data, axis=0) y_train = np.array(labels).reshape(-1, 1) trainset = np.hstack((X_train, y_train)) for (x, y, w, h) in faces[:1]: face = img[y:y+h, x:x+w] face = cv2.resize(face, (100, 100)).flatten() pred_id = knn(trainset, face) info = names.get(pred_id) if info: return jsonify({ "status": "success", "name": info['name'], "enrollment": info['enrollment'] }) return jsonify({"status": "fail", "message": "Face not recognized"}) @app.route('/api/checkin', methods=['POST']) def api_checkin(): data = request.json class_name = data['class_name'] enrollment = data['enrollment'] name = data['name'] pin = data.get('pin') # Get PIN from request attendance = AttendanceSystem(class_name) ok, msg = attendance.checkin(enrollment, name, pin) status = "success" if ok else "fail" return jsonify({"status": status, "message": msg}) @app.route('/api/checkout', methods=['POST']) def api_checkout(): data = request.json class_name = data['class_name'] enrollment = data['enrollment'] attendance = AttendanceSystem(class_name) ok, msg = attendance.checkout(enrollment) status = "success" if ok else "fail" return jsonify({"status": status, "message": msg}) # New endpoint to get the overall attendance average @app.route('/api/get_attendance_average', methods=['POST']) def get_attendance_average(): data = request.json class_name = data['class_name'] enrollment = data['enrollment'] user = User.query.filter_by(enrollment_number=enrollment, selected_class=class_name, role='student').first() if not user: return jsonify({'error': 'Student not found'}), 404 subject_attendance = get_subject_attendance(user) total_attendance = 0 total_possible = 0 for subj_type in ['regular', 'specialization', 'practical']: for subj, counts in subject_attendance[subj_type].items(): total_attendance += counts['attendance'] total_possible += counts['total'] if total_possible > 0: overall_percentage = (total_attendance / total_possible) * 100 else: overall_percentage = 0 return jsonify({'overall_percentage': round(overall_percentage, 2)}) if __name__ == '__main__': app.run(host='0.0.0.0', port=7860, debug=True)