// the_story
The Problem
Manual attendance is a solved problem that nobody has actually solved. The teacher reads names, students say "present," someone marks a spreadsheet, and ten minutes of class time evaporates. For a learning side project, I wanted to attack something real and technically interesting at the same time. SnapClass automates the whole flow: a teacher uploads a classroom photo, and the system figures out who showed up.
The Approach
Two recognition modes — because one is never enough when you're learning.
Face attendance: a teacher uploads a classroom photo, dlib's CNN detects every face, extracts a 128-dimensional embedding per face, and an SVM classifier maps that embedding to a student ID. Detections above 0.6 confidence get marked present. The SVM retrains automatically every time a new student registers — so the model always knows about every enrolled student without any manual intervention.
Voice attendance: librosa splits audio by silence into speaker segments, Resemblyzer converts each segment into a 256-D speaker embedding, and cosine similarity against every enrolled student's voice profile determines who's in the room. Threshold: 0.65.
Both pipelines write to the same attendance log. Same database, same report, different sensor.
The Build
The core is the face pipeline:
[CODE BLOCK — language: python — filename: src/pipelines/face_pipeline.py]
def identify_faces(image, embeddings, labels, threshold=0.6):
face_locations = face_recognition.face_locations(image, model="cnn")
face_encodings = face_recognition.face_encodings(image, face_locations)
results = []
for encoding in face_encodings:
probs = clf.predict_proba([encoding])[0]
confidence = max(probs)
if confidence >= threshold:
student_id = clf.classes_[probs.argmax()]
results.append((student_id, confidence))
return results
The 128-D embeddings live in Supabase alongside all other app data — teachers, students, subjects, enrollment records. The schema is straightforward: a junction table handles student-subject enrollment, and every attendance event writes a timestamped row to attendance_logs. Students register by scanning their face via webcam — no password, no username. Face ID is the login.
The teacher flow is three steps: create a subject, share a QR code for students to self-enroll, upload a photo and confirm the AI's output. The UI is Streamlit — fast to build, good enough for a demo, handles multi-user sessions without spinning up a separate backend.
Passwordless biometric login for students sounds futuristic. Building it in a weekend with dlib and a Postgres table is a good reality check on how approachable this stuff actually is.
What I Learned
- Embeddings are just vectors. The face recognition magic is a 128-number array per face stored in a database column. Once that clicked, the whole pipeline became obvious: distance in embedding space = similarity in appearance.
- Dynamic retraining is a real design decision. The SVM retrains on every new student registration. That's fine at 30 students; it becomes a conversation at 3,000. Thinking through the scalability limits of a design choice is part of engineering.
- Dual-modality is harder than it looks. Face and voice attendance share the same output (a presence record) but have completely different failure modes — bad lighting kills faces, background noise kills voice. Designing a system that degrades gracefully when one modality fails is its own problem.
- Biometric UX needs careful thought. Passwordless login via face is genuinely convenient until the camera is bad, the lighting is dim, or someone's wearing a mask. The 0.6 confidence threshold is a UX decision as much as a technical one.
- Free-tier infrastructure is a feature, not a compromise. Supabase pausing on inactivity is annoying for a live demo but costs nothing. For a side project where the point is learning, that tradeoff is correct.
SnapClass isn't production-ready — the SVM doesn't scale, Streamlit has session quirks, and a paused database is a rough first impression. But it's a complete system: two AI pipelines, a real database schema, biometric auth, QR enrollment, and a live deployment. For a side project, that's the whole point.
