A production-ready facial recognition employee verification platform built with Django, DeepFace (ArcFace model), and ChromaDB for vector similarity search.
- Employee Registration: Add employees with personal details, photos, and reputation scores
- Facial Recognition: Extract and store facial embeddings using DeepFace with ArcFace model
- Identity Verification: Upload a photo to verify employee identity using cosine similarity
- Vector Search: ChromaDB for efficient facial embedding storage and retrieval
- Clean Architecture: Modular service layer separating business logic from views
- Production Ready: Secure settings, error handling, and deployment configurations
- Backend: Django 5.0.2
- Database: PostgreSQL (production) / SQLite (development)
- Face Recognition: DeepFace 0.0.92 with ArcFace model
- Face Detection: RetinaFace backend
- Vector Database: ChromaDB 0.4.24
- Frontend: Django Templates + Bootstrap 5
- Python: 3.11+
employee_verification_platform/
βββ config/ # Django project settings
β βββ __init__.py
β βββ settings.py # Main settings
β βββ urls.py # Root URL configuration
β βββ wsgi.py # WSGI application
βββ employees/ # Main Django app
β βββ migrations/ # Database migrations
β βββ services/ # Business logic layer
β β βββ __init__.py
β β βββ face_service.py # DeepFace operations
β β βββ chroma_service.py # ChromaDB operations
β βββ static/ # Static files
β β βββ css/
β β βββ style.css
β βββ templates/ # HTML templates
β β βββ base.html
β β βββ home.html
β β βββ add_employee.html
β β βββ verify_employee.html
β β βββ result.html
β β βββ employee_list.html
β βββ templatetags/ # Custom template filters
β β βββ __init__.py
β β βββ custom_filters.py
β βββ __init__.py
β βββ admin.py # Admin interface
β βββ apps.py # App configuration
β βββ forms.py # Django forms
β βββ models.py # Database models
β βββ urls.py # App URLs
β βββ views.py # View controllers
βββ .env.example # Environment variables template
βββ .gitignore
βββ manage.py # Django management script
βββ requirements.txt # Python dependencies
βββ README.md # This file
- Python 3.11 or higher
- pip
- Virtual environment tool (venv)
- PostgreSQL (optional, SQLite works for development)
- Clone or download the project
cd employee_verification_platform- Create and activate virtual environment
# Linux/Mac
python3.11 -m venv venv
source venv/bin/activate
# Windows
python -m venv venv
venv\Scripts\activate- Install dependencies
pip install --upgrade pip
pip install -r requirements.txtThis will install:
- Django and related packages
- DeepFace and TensorFlow dependencies
- ChromaDB
- OpenCV and image processing libraries
- Configure environment variables
cp .env.example .envEdit .env and configure as needed. For development with SQLite:
SECRET_KEY=your-secret-key-here-change-in-production
DEBUG=True
ALLOWED_HOSTS=localhost,127.0.0.1
# SQLite for development
DATABASE_ENGINE=django.db.backends.sqlite3
DATABASE_NAME=db.sqlite3
SIMILARITY_THRESHOLD=0.65
MAX_UPLOAD_SIZE=5242880
CHROMA_PERSIST_DIRECTORY=chroma_db- Run migrations
python manage.py makemigrations
python manage.py migrate- Create superuser
python manage.py createsuperuserFollow the prompts to create an admin account.
- Create required directories
mkdir -p media/employee_photos media/temp
mkdir -p chroma_db- Collect static files
python manage.py collectstatic --noinput- Run development server
python manage.py runserverVisit: http://localhost:8000
The similarity threshold determines how strict the facial matching is:
- 0.5-0.6: Very lenient (may have false positives)
- 0.65-0.7: Balanced (recommended)
- 0.75-0.85: Strict (may miss valid matches)
- 0.9+: Very strict (requires near-perfect match)
Configure in .env:
SIMILARITY_THRESHOLD=0.65- Embedding Extraction: DeepFace extracts a 512-dimensional vector from each face
- Normalization: Vectors are normalized for cosine similarity
- Cosine Similarity: Measures angle between vectors (0-1, where 1 is identical)
- Distance to Similarity: ChromaDB returns distance; we convert to similarity:
1 - (distance / 2) - Threshold Check: If similarity β₯ threshold, it's a match
Example:
- Distance: 0.5 β Similarity: 0.75 (75%)
- Distance: 0.7 β Similarity: 0.65 (65%)
- Distance: 1.0 β Similarity: 0.50 (50%)
In .env:
DATABASE_ENGINE=django.db.backends.postgresql
DATABASE_NAME=employee_verification
DATABASE_USER=your_db_user
DATABASE_PASSWORD=your_db_password
DATABASE_HOST=localhost
DATABASE_PORT=5432In .env:
DATABASE_ENGINE=django.db.backends.sqlite3
DATABASE_NAME=db.sqlite3- Navigate to Add Employee
- Fill in employee details:
- Full Name
- Phone
- Employer Name
- Position
- Reputation Score (0-10)
- Notes (optional)
- Photo (required - must contain exactly one face)
- Click Add Employee
- System will:
- Validate the image
- Extract facial embedding
- Store in both Django DB and ChromaDB
- Show success message
- Navigate to Verify Employee
- Upload a photo (doesn't need to be identical to registered photo)
- Click Verify Identity
- System will:
- Extract embedding from uploaded photo
- Search ChromaDB for closest match
- Calculate similarity score
- Return employee details if match found (β₯ threshold)
Match Found:
- Employee details displayed
- Similarity percentage shown
- Confidence level (High/Medium)
- Reputation score highlighted
No Match:
- Friendly message displayed
- Closest similarity shown (if any)
- Suggestions to try again or register
- CSRF Protection: Enabled on all forms
- File Upload Validation:
- Type checking (JPEG, PNG, WebP only)
- Size limits (5MB default)
- SQL Injection Protection: Django ORM prevents SQL injection
- XSS Protection: Django templates auto-escape content
- Secure Headers: Configured in production mode
- Environment Variables: Sensitive data in
.envfile
- Set
DEBUG=Falsein production - Use strong
SECRET_KEY - Configure HTTPS (SSL/TLS)
- Set proper
ALLOWED_HOSTS - Use PostgreSQL (not SQLite)
- Regular security updates
- Implement rate limiting
- Set up proper file permissions
- Use environment variables for secrets
- Enable Django security middleware
- Ubuntu 20.04+ VPS (DigitalOcean, Linode, etc.)
- Domain name (optional but recommended)
- SSH access to server
# Update system
sudo apt update && sudo apt upgrade -y
# Install Python and dependencies
sudo apt install -y python3.11 python3.11-venv python3-pip
sudo apt install -y postgresql postgresql-contrib
sudo apt install -y nginx
sudo apt install -y libpq-dev python3-dev
sudo apt install -y libgl1-mesa-glx libglib2.0-0 # OpenCV dependencies# Switch to postgres user
sudo -u postgres psql
# In PostgreSQL shell:
CREATE DATABASE employee_verification;
CREATE USER your_db_user WITH PASSWORD 'strong_password_here';
ALTER ROLE your_db_user SET client_encoding TO 'utf8';
ALTER ROLE your_db_user SET default_transaction_isolation TO 'read committed';
ALTER ROLE your_db_user SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE employee_verification TO your_db_user;
\q# Create project user
sudo adduser employeeverif
sudo usermod -aG sudo employeeverif
su - employeeverif
# Clone/upload project
cd /home/employeeverif
# Upload your project files here
cd employee_verification_platform
# Create virtual environment
python3.11 -m venv venv
source venv/bin/activate
# Install dependencies
pip install --upgrade pip
pip install -r requirements.txt
pip install gunicorn# Create production .env
nano .envAdd:
SECRET_KEY=generate-a-long-random-secret-key-here
DEBUG=False
ALLOWED_HOSTS=your-domain.com,your-server-ip
DATABASE_ENGINE=django.db.backends.postgresql
DATABASE_NAME=employee_verification
DATABASE_USER=your_db_user
DATABASE_PASSWORD=strong_password_here
DATABASE_HOST=localhost
DATABASE_PORT=5432
SIMILARITY_THRESHOLD=0.65
MAX_UPLOAD_SIZE=5242880
CHROMA_PERSIST_DIRECTORY=/home/employeeverif/employee_verification_platform/chroma_db# Run migrations
python manage.py makemigrations
python manage.py migrate
# Create superuser
python manage.py createsuperuser
# Collect static files
python manage.py collectstatic --noinput
# Create directories
mkdir -p media/employee_photos media/temp
mkdir -p chroma_db
# Set permissions
chmod 755 media chroma_dbCreate systemd service file:
sudo nano /etc/systemd/system/gunicorn.serviceAdd:
[Unit]
Description=Gunicorn daemon for Employee Verification Platform
After=network.target
[Service]
User=employeeverif
Group=www-data
WorkingDirectory=/home/employeeverif/employee_verification_platform
Environment="PATH=/home/employeeverif/employee_verification_platform/venv/bin"
ExecStart=/home/employeeverif/employee_verification_platform/venv/bin/gunicorn \
--workers 3 \
--bind unix:/home/employeeverif/employee_verification_platform/gunicorn.sock \
config.wsgi:application
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl start gunicorn
sudo systemctl enable gunicorn
sudo systemctl status gunicornsudo nano /etc/nginx/sites-available/employee_verificationAdd:
server {
listen 80;
server_name your-domain.com;
client_max_body_size 10M;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
alias /home/employeeverif/employee_verification_platform/staticfiles/;
}
location /media/ {
alias /home/employeeverif/employee_verification_platform/media/;
}
location / {
include proxy_params;
proxy_pass http://unix:/home/employeeverif/employee_verification_platform/gunicorn.sock;
}
}Enable site:
sudo ln -s /etc/nginx/sites-available/employee_verification /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginxsudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.comsudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw enable# Restart services
sudo systemctl restart gunicorn
sudo systemctl restart nginx
# View logs
sudo journalctl -u gunicorn
sudo tail -f /var/log/nginx/error.log
# Update code
cd /home/employeeverif/employee_verification_platform
git pull # or upload new files
source venv/bin/activate
pip install -r requirements.txt
python manage.py migrate
python manage.py collectstatic --noinput
sudo systemctl restart gunicornThe application uses a clean service layer architecture:
# Extract facial embedding
embedding = FaceService.extract_embedding(image_path)
# Validate image
validation = FaceService.validate_image(image_path)
# Convert formats
embedding_list = FaceService.embedding_to_list(embedding)# Add employee embedding
ChromaService.add_employee_embedding(uuid, embedding, metadata)
# Search for match
result = ChromaService.search_embedding(query_embedding)
# Delete embedding
ChromaService.delete_employee_embedding(uuid)
# Get statistics
stats = ChromaService.get_collection_stats()-
Add Employee Test:
- Upload photo with one face β Success
- Upload photo with no face β Error
- Upload photo with multiple faces β Error
- Upload non-image file β Error
-
Verify Employee Test:
- Upload photo of registered employee β Match found
- Upload photo of unregistered person β No match
- Upload different angle of same person β Match found (if similarity β₯ threshold)
# Check employee count
python manage.py shell
>>> from employees.models import Employee
>>> Employee.objects.count()
# Check ChromaDB
>>> from employees.services import ChromaService
>>> ChromaService.get_collection_stats()1. "No face detected" error
- Ensure photo has good lighting
- Face should be clearly visible
- Try front-facing angle
- Check image quality
2. ChromaDB errors
- Ensure
chroma_dbdirectory exists - Check write permissions
- Restart application
3. Import errors for DeepFace
- Install all requirements:
pip install -r requirements.txt - Some models download on first use (may take time)
4. Media files not displaying
- Check
MEDIA_ROOTandMEDIA_URLsettings - Ensure media directory exists
- In production, configure Nginx to serve media files
5. Database connection errors
- Verify PostgreSQL is running
- Check database credentials in
.env - Ensure database exists
| Variable | Description | Example |
|---|---|---|
SECRET_KEY |
Django secret key | Long random string |
DEBUG |
Debug mode | True/False |
ALLOWED_HOSTS |
Allowed hostnames | localhost,domain.com |
DATABASE_ENGINE |
Database backend | django.db.backends.postgresql |
DATABASE_NAME |
Database name | employee_verification |
DATABASE_USER |
Database user | dbuser |
DATABASE_PASSWORD |
Database password | secure_password |
DATABASE_HOST |
Database host | localhost |
DATABASE_PORT |
Database port | 5432 |
SIMILARITY_THRESHOLD |
Face match threshold | 0.65 |
MAX_UPLOAD_SIZE |
Max file size (bytes) | 5242880 |
CHROMA_PERSIST_DIRECTORY |
ChromaDB storage path | chroma_db |
This is a production prototype. For improvements:
- Add tests (pytest, pytest-django)
- Add API endpoints (Django REST Framework)
- Implement background tasks (Celery)
- Add monitoring (Sentry, New Relic)
- Implement caching (Redis)
This project is provided as-is for educational and commercial use.
For issues or questions, refer to the troubleshooting section or check the service layer code for implementation details.
Built with Django, DeepFace, and ChromaDB π