Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
prodev717 authored Nov 15, 2024
1 parent 5731c94 commit f5cc84b
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 0 deletions.
Binary file added favicon.ico
Binary file not shown.
115 changes: 115 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import tkinter as tk
import proctor
import threading
import time

def show_error_popup(message):
error_popup = tk.Toplevel(app)
error_popup.title("Input Error")
error_popup.geometry("300x150")
error_popup.configure(bg="#2C3E50")
error_label = tk.Label(error_popup, text=message, bg="#2C3E50", fg="#ECF0F1", font=("Helvetica", 12))
error_label.pack(pady=20)
ok_button = tk.Button(error_popup, text="OK", command=error_popup.destroy, font=("Helvetica", 12, "bold"), bg="#1ABC9C", fg="white")
ok_button.pack(pady=10)

def show_terms_and_conditions():
terms_window = tk.Toplevel(app)
terms_window.title("Terms and Conditions")
terms_window.attributes('-fullscreen', True)
terms_window.configure(bg="#2C3E50")
terms_frame = tk.Frame(terms_window, bg="#2C3E50")
terms_frame.pack(expand=True, fill=tk.BOTH, padx=20, pady=20)
terms_text = """\
Terms and Conditions :-
1.Camera and microphone will be used to monitor exams.
Data is processed locally on your device.If suspicious activity is detected,
the exam may be ended.
Any failure to attend or complete the exam will not be the app’s responsibility.
2.Video, audio, and exam data are processed according to our Privacy Policy
and are not shared without consent, except for exam-related purposes.
3.Violations may result in account suspension or termination.
4.Examify is not responsible for failures to attend or complete
exams due to device issues.
5.Maintain a distance 40-70 Cms from the screen for better exam experience
without any interruption.
6.Make sure you sit in a silent room away from any noise disturbances.
7.You can cry after seeing the questions but make sure the keyboard doesn't
get wet as we won't be responsible for any hardware damage.
8.You can skip the test if you feel like you will fail but don't
blame the app after doing so.
9.It is crucial to stay within the boundary for a valid test.
Certainly! Here’s a more professional version of your message:
10.After selecting "Proceed," you will be directed to a sample camera view where you
can check and adjust your position in relation to your surroundings and the defined boundary limits.
You will have 15 seconds to make these adjustments. Please ensure that the boundary box remains
within the permissible area; if it turns red, it indicates a potential violation.
11.Terms may change; continued use means acceptance of updates.
12.Best of luck.
For questions, contact us at teamx0403@gmail.com
"""
terms_label = tk.Label(terms_frame, text=terms_text, bg="#2C3E50", fg="#ECF0F1", font=("Arial", 10), justify=tk.LEFT)
terms_label.pack(pady=20)
terms_accepted = tk.BooleanVar()
terms_checkbox = tk.Checkbutton(terms_frame, text="I have read and agree to the Terms and Conditions", variable=terms_accepted, bg="#2C3E50", fg="#ECF0F1", font=("Arial", 12), selectcolor="#34495E")
terms_checkbox.pack(pady=10)
proceed_button = tk.Button(terms_frame, text="Proceed", command=lambda: proceed(terms_window, terms_accepted.get()), font=("Arial", 12, "bold"), bg="#28A745", fg="white", state=tk.DISABLED)
proceed_button.pack(pady=20)
terms_accepted.trace("w", lambda *args: proceed_button.config(state=tk.NORMAL if terms_accepted.get() else tk.DISABLED))

def proceed(terms_window, accepted):
global full_name,reg_number,test_link
if accepted:
print("Proceeding to the application...")
terms_window.destroy()
app.destroy()
proctor.Tapp(test_link,(full_name,reg_number))
exit()
else:
print("You must accept the terms to proceed.")

def submit_form():
global full_name,reg_number,test_link
full_name = name_entry.get()
reg_number = reg_number_entry.get()
test_link = test_link_entry.get()
if not full_name or not reg_number or not test_link:
show_error_popup("⚠️ All fields are mandatory")
return
print(f"Full Name: {full_name}")
print(f"Registration Number: {reg_number}")
print(f"Test Link: {test_link}")
show_terms_and_conditions()

app = tk.Tk()
full_name = None
reg_number = None
test_link = None
app.title("Examify")
app.geometry("400x500")
app.configure(bg="#2C3E50")
app.iconbitmap("favicon.ico")
title_label = tk.Label(app, text="Welcome to Examify", bg="#2C3E50", fg="#ECF0F1", font=("Helvetica", 18, "bold"))
title_label.pack(pady=(20, 10))
border_frame = tk.Frame(app, bg ="#34495E", bd=5, relief="raised")
border_frame.pack(padx=20, pady=20, expand=True, fill=tk.BOTH)
form_frame = tk.Frame(border_frame, bg="#2C3E50")
form_frame.pack(expand=True, fill=tk.BOTH, padx=10, pady=10)
label_font = ("Helvetica", 12, "bold")
entry_font = ("Helvetica", 12)
tk.Label(form_frame, text="Full Name:", bg="#2C3E50", fg="#ECF0F1", font=label_font).pack(pady=(10, 5))
name_entry = tk.Entry(form_frame, font=entry_font, bg="#34495E", fg="#ECF0F1", insertbackground='white', bd=2, relief="flat", width=30)
name_entry.pack(pady=(0, 10))
tk.Label(form_frame, text="Registration Number:", bg="#2C3E50", fg="#ECF0F1", font=label_font).pack(pady=(10, 5))
reg_number_entry = tk.Entry(form_frame, font=entry_font, bg="#34495E", fg="#ECF0F1", insertbackground='white', bd=2, relief="flat", width=30)
reg_number_entry.pack(pady=(0, 10))
tk.Label(form_frame, text="Test Link:", bg="#2C3E50", fg="#ECF0F1", font=label_font).pack(pady=(10, 5))
test_link_entry = tk.Entry(form_frame, font=entry_font, bg="#34495E", fg="#ECF0F1", insertbackground='white', bd=2, relief="flat", width=30)
test_link_entry.pack(pady=(0, 10))
submit_button = tk.Button(form_frame, text="Take Test", command=submit_form, font=("Helvetica", 12, "bold"), bg="#1ABC9C", fg="white", relief="raised", bd=3)
submit_button.pack(pady=20)
app.eval('tk::PlaceWindow . center')
app.mainloop()

# https://docs.google.com/forms/d/e/1FAIpQLSfuZc4ZKX3ex20-LdhgsOyVwHFRdnWOdZgH2iS72_erJ9sf3A/viewform?usp=sf_link
85 changes: 85 additions & 0 deletions proctor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import cv2
import numpy as np
import mediapipe as mp
from math import dist
import winsound
from selenium import webdriver
import time
from threading import Thread
import requests
import keyboard

data = None
server = "http://localhost:8000"
duration = requests.get(server+"/duration").json()["duration"]
detector = mp.solutions.face_detection.FaceDetection(model_selection=1,min_detection_confidence=0.5)
camera = cv2.VideoCapture(0)
warning = 0
old = 0

def proctor(duration,st):
global warning,old,camera,detector
while time.time()-st<duration:
ret, frame = camera.read()
if not ret:
break
if int(warning)>old:
print("warning")
old=old+1
winsound.MessageBeep()
h,w,c = frame.shape
frame = cv2.flip(frame, 1)
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = detector.process(rgb_frame)
if results.detections:
for face in results.detections:
face_react = np.multiply(
[
face.location_data.relative_bounding_box.xmin,
face.location_data.relative_bounding_box.ymin,
face.location_data.relative_bounding_box.width,
face.location_data.relative_bounding_box.height,
],[w,h,w,h]).astype(int)
key_points = np.array([(p.x, p.y) for p in face.location_data.relative_keypoints])
key_points_coords = np.multiply(key_points,[w,h]).astype(int)
for p in key_points_coords:
cv2.circle(frame, p, 4, (255, 255, 0))
thresh = dist(key_points_coords[0],key_points_coords[1])
cv2.putText(frame,f"{thresh}",(30, 30),cv2.FONT_HERSHEY_DUPLEX,0.7,(0, 255, 255),2,)
cv2.putText(frame,f"{warning}",(30, 70),cv2.FONT_HERSHEY_DUPLEX,0.7,(0, 0, 255),2,)
if 65<thresh<120:
cv2.rectangle(frame, face_react, color=(255, 255, 255), thickness=2)
else:
cv2.rectangle(frame, face_react, color=(0, 0, 255), thickness=2)
warning=warning+0.01
if cv2.waitKey(1) == ord("q"):
break
# cv2.waitKey(1)
cv2.imshow("proctor", frame)
camera.release()
cv2.destroyAllWindows()

def upload():
global warning,data
requests.post(server+"/studentdata",json={"name":data[0],"regno":data[1],"warning":warning})
print(warning,data)

def test(link,duration):
keyboard.block_key("windows")
driver = webdriver.Chrome(executable_path="chromedriver.exe")
driver.get(link)
driver.fullscreen_window()
time.sleep(duration)
upload()

def Tapp(link,user_data):
global data,duration
data = user_data
t1 = Thread(target=test,args=(link,duration,))
t2 = Thread(target=proctor,args=(duration+15,time.time()))
t2.start()
time.sleep(15)
t1.start()

if __name__ == "__main__":
proctor(60,time.time())
24 changes: 24 additions & 0 deletions server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from fastapi import FastAPI
from pydantic import BaseModel
import json
import csv
import math

class StudentData(BaseModel):
name:"str"
regno:"str"
warning:float
app = FastAPI()
dur = 60

@app.get('/duration')
def duration():
global dur
return {"duration":dur}

@app.post("/studentdata")
def submit(data:StudentData):
print(data)
with open("credresult.csv","a") as file:
writer = csv.writer(file)
writer.writerow([data.name,data.regno,100-math.floor(data.warning)])
3 changes: 3 additions & 0 deletions start_server.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@echo off
uvicorn server:app
end

0 comments on commit f5cc84b

Please sign in to comment.