From 520a9618d7ef4ef1ca1f3a2f6aaebfed8faad343 Mon Sep 17 00:00:00 2001 From: eshelDror Date: Fri, 27 Oct 2023 09:26:49 -0700 Subject: [PATCH] add api qol changes (#12) --- backend/classsync/db.py | 1 + backend/classsync/main.py | 112 +++++++++++++++++++++++++----------- backend/classsync/models.py | 5 +- 3 files changed, 83 insertions(+), 35 deletions(-) diff --git a/backend/classsync/db.py b/backend/classsync/db.py index 1cd5bfc..31968ec 100644 --- a/backend/classsync/db.py +++ b/backend/classsync/db.py @@ -74,6 +74,7 @@ class AttendanceEvent(Base): student: Mapped["Student"] = relationship() time: Mapped[str] = mapped_column() # TODO: Make datetime inputType: Mapped[str] = mapped_column() + tardy: Mapped[bool] = mapped_column() class Timer(Base): diff --git a/backend/classsync/main.py b/backend/classsync/main.py index 2983352..96ee550 100644 --- a/backend/classsync/main.py +++ b/backend/classsync/main.py @@ -1,6 +1,4 @@ -from fastapi import FastAPI, HTTPException, File -from pydantic import BaseModel -from sqlalchemy import delete, select +from fastapi import FastAPI, File from classsync.db import ( Student, Timer, @@ -18,9 +16,7 @@ from PIL import Image from io import BytesIO -print("Initiating API") app = FastAPI() -print("Initiating Models") model = Models() @@ -66,25 +62,25 @@ async def add_timer(timing: int, teacher_id: int): # Post for image transfer from camera @app.post("/add_image") -async def add_image(image_file: Annotated[bytes, File()], time: str): +async def add_image(image_file: Annotated[bytes, File()], time: str, tardy: bool): image = Image.open(BytesIO(image_file)) faces = model.find_faces(image) with Session(engine) as session: for face in faces: student = session.query(Student).order_by(Student.face_embedding.cosine_distance(face)).first() - entry = AttendanceEvent(student=student, time=time, inputType="image") + entry = AttendanceEvent(student=student, time=time, inputType="image", tardy=tardy) session.add(entry) session.commit() return {"error": None, "face count": len(faces)} @app.post("/add_attendance") -async def add_attendance(student_id, time): +async def add_attendance(student_id: int, time: str, tardy: bool): with Session(engine) as session: student_query = session.query(Student).filter(Student.id == student_id) if len(student_query.all()) != 1: return {"error": f"student not found for {student_id=}"} student = student_query[0] - entry = AttendanceEvent(student=student, time=time, inputType = "manual") + entry = AttendanceEvent(student=student, time=time, inputType = "manual", tardy=tardy) session.add(entry) session.commit() return {"error": None} @@ -125,18 +121,32 @@ async def add_student_to_class(face_img: Annotated[bytes, File()], student_id: i session.refresh(student) return {"error": None} -# Get section for students, plagiarism, timers +# Delete +@app.delete("/clear_db") +async def clear_db(): + with Session(engine) as session: + session.expunge_all() + session.commit() + +# Get @app.get("/get_plagiarized") async def get_plagiarized(writing1: str, writing2: str): return float(cosine_similarity(model.encode(writing1), model.encode(writing2))) -@app.get("/get_attendance") -async def get_attendance(): +@app.get("/get_timers") +async def get_timer(): with Session(engine) as session: - attendance_query = session.query(AttendanceEvent) - return attendance_query.all() + timer_query = session.query(Timer) + return timer_query.all() + + +@app.get("/get_teachers") +async def get_teachers(): + with Session(engine) as session: + teacher_query = session.query(Teacher) + return teacher_query.all() @app.get("/get_classes") async def get_periodclasses(): @@ -144,27 +154,21 @@ async def get_periodclasses(): periodclass_query = session.query(PeriodClass) return periodclass_query.all() - @app.get("/get_students") async def get_student(): with Session(engine) as session: student_query = session.query(Student) - return student_query.all() - + students = student_query.all() + for s in students: + if s.face_embedding: + s.face_embedding = True + return students -@app.get("/get_timers") -async def get_timer(): - with Session(engine) as session: - timer_query = session.query(Timer) - return timer_query.all() - - -@app.get("/get_teachers") -async def get_teachers(): +@app.get("/get_attendance") +async def get_attendance(): with Session(engine) as session: - teacher_query = session.query(Teacher) - return teacher_query.all() - + attendance_query = session.query(AttendanceEvent) + return attendance_query.all() @app.get("/get_students_in_class") async def get_students_in_class(class_id: int): @@ -176,12 +180,9 @@ async def get_students_in_class(class_id: int): return {"error": f"periodclass not found for {class_id=}"} print("debug: returning students") students = periodclass_query.all()[0].students - student_ids = [s.id for s in students] + student_ids = [s.name for s in students] return student_ids - - - @app.get("/get_student_attendance") async def get_student_attendance(student_id: int): with Session(engine) as session: @@ -189,7 +190,52 @@ async def get_student_attendance(student_id: int): attendance_events = attendance_query.filter(AttendanceEvent.student_id==student_id).order_by(AttendanceEvent.time).all() return attendance_events +@app.get("/get_class_attendance") +async def get_class_attendance(class_id: int, start_time: str): + with Session(engine) as session: + class_query = session.query(PeriodClass) + periodclass = class_query.filter(PeriodClass.id==class_id).all() + if len(periodclass) != 1: + return {"error": f"couldn't find {class_id=}"} + students=periodclass[0].students + student_attendance: dict[int, str] = dict() + attendance_query = session.query(AttendanceEvent).filter(AttendanceEvent.time>=start_time).order_by(AttendanceEvent.time) + for student in students: + attendance = attendance_query.filter(AttendanceEvent.student_id==student.id).first() + if attendance == None: + student_attendance[student.name] = "absent" + elif attendance.tardy: + student_attendance[student.name] = "tardy" + else: + student_attendance[student.name] = "present" + return student_attendance + +@app.get("/get_student_id_by_name") +async def get_student_id_by_name(student_name: str): + with Session(engine) as session: + student_query = session.query(Student) + student = student_query.filter(Student.name==student_name).all() + if len(student) != 1: + return {"error": f"didn't find one {student_name=}"} + return {"error": None, "id": student[0].id} +@app.get("/get_student_name_by_id") +async def get_student_name_by_id(student_id: int): + with Session(engine) as session: + student_query = session.query(Student) + student = student_query.filter(Student.id==student_id).all() + if len(student) != 1: + return {"error": f"didn't find one {student_id=}"} + return {"error": None, "id": student[0].name} + +@app.get("/get_class_name_by_id") +async def get_class_name_by_id(class_id: str): + with Session(engine) as session: + class_query = session.query(PeriodClass) + periodclasses = class_query.filter(PeriodClass.id==class_id).all() + if len(periodclasses) != 1: + return {"error": f"didn't find one {class_id=}"} + return {"error": None, "id": periodclasses[0].name} if __name__ == "__main__": uvicorn.run("main:app", port=8000) diff --git a/backend/classsync/models.py b/backend/classsync/models.py index 02b6025..c2a3a5b 100644 --- a/backend/classsync/models.py +++ b/backend/classsync/models.py @@ -5,8 +5,9 @@ class Models: def __init__(self): - self.detector = scrfd.SCRFD(model_file="./scrfd-10g-kps.onnx") - self.pfc = partial_fc.PartialFC("pfc.onnx") + print("Initiating facial recognition models") + self.detector = scrfd.SCRFD(model_file="./backend/scrfd-10g-kps.onnx") + self.pfc = partial_fc.PartialFC("./backend/pfc.onnx") def find_faces(self, image: Image.Image): faces = self.detector.detect(image, 0.6, (640, 640))