punimtag/.cursorrules
2025-08-15 00:57:39 -08:00

495 lines
13 KiB
Plaintext

# PunimTag - Intelligent Photo Management System
## Project Overview
PunimTag is an intelligent photo management system that uses face recognition to automatically organize, tag, and manage personal photo collections. It's built with Flask (Python) and vanilla JavaScript, focusing on privacy-first local processing.
## Core Value Proposition
- **Automatic Face Recognition**: Identify and tag people in photos without manual effort
- **Smart Organization**: Group photos by people, events, and locations
- **Duplicate Detection**: Find and manage duplicate photos automatically
- **Intuitive Interface**: Web-based GUI that's easy to use for non-technical users
- **Privacy-First**: Local processing, no cloud dependencies
## Technology Stack
### Backend
- **Framework**: Flask (Python web framework)
- **Database**: SQLite (lightweight, file-based)
- **Face Recognition**: dlib (C++ library with Python bindings)
- **Image Processing**: Pillow (PIL fork)
- **Data Processing**: NumPy (numerical operations)
### Frontend
- **Language**: Vanilla JavaScript (ES6+)
- **Styling**: CSS3 with Grid/Flexbox
- **HTTP Client**: Fetch API
- **Progressive Loading**: Intersection Observer API
- **No Frameworks**: Pure JavaScript for simplicity
## Project Structure
```
PunimTag/
├── src/ # Main application source code
│ ├── backend/ # Flask backend and API
│ │ ├── app.py # Main Flask application
│ │ ├── db_manager.py # Database operations
│ │ └── visual_identifier.py # Face recognition
│ ├── frontend/ # JavaScript and UI components
│ └── utils/ # Utility functions
│ └── tag_manager.py # Tag management
├── docs/ # Documentation and steering documents
├── tests/ # Test files
├── data/ # Database files and user data
├── config/ # Configuration files
├── scripts/ # Utility scripts
├── assets/ # Static assets
├── photos/ # User photo storage
└── main.py # Application entry point
```
## Key Features
### 1. Photo Management
- Upload and organize photos by date, location, and content
- Automatic metadata extraction (EXIF data, GPS coordinates)
- Batch operations for efficiency
### 2. Face Recognition & Tagging
- Automatic face detection in photos
- Face identification and naming
- Group photos by people
- Handle multiple faces per photo
### 3. Duplicate Management
- Find duplicate photos automatically
- Visual comparison tools
- Bulk removal options
- Keep best quality versions
### 4. Search & Discovery
- Search by person name
- Filter by date ranges
- Tag-based filtering
- Similar face suggestions
### 5. User Experience
- Progressive loading for large collections
- Responsive web interface
- Custom dialogs (no browser alerts)
- Real-time notifications
## Database Schema
```sql
-- Core tables
images (id, filename, path, date_taken, metadata)
faces (id, image_id, person_id, encoding, coordinates, confidence)
people (id, name, created_date)
tags (id, name)
image_tags (image_id, tag_id)
-- Supporting tables
face_encodings (id, face_id, encoding_data)
photo_metadata (image_id, exif_data, gps_data)
```
## API Standards
### Response Format
**Success Response:**
```json
{
"success": true,
"data": {
// Response data here
},
"message": "Optional success message"
}
```
**Error Response:**
```json
{
"success": false,
"error": "Descriptive error message",
"code": "ERROR_CODE_OPTIONAL"
}
```
**Paginated Response:**
```json
{
"success": true,
"data": {
"items": [...],
"pagination": {
"page": 1,
"per_page": 20,
"total": 150,
"pages": 8
}
}
}
```
### HTTP Status Codes
- **200 OK**: Request successful
- **201 Created**: Resource created successfully
- **400 Bad Request**: Invalid request data
- **404 Not Found**: Resource not found
- **500 Internal Server Error**: Server error
### Endpoint Naming Conventions
- **GET /photos**: List photos
- **GET /photos/{id}**: Get specific photo
- **POST /photos**: Create new photo
- **PUT /photos/{id}**: Update photo
- **DELETE /photos/{id}**: Delete photo
- **POST /photos/{id}/identify**: Identify faces in photo
## Python Code Conventions
### Code Style (PEP 8)
```python
# Imports
import os
import sys
from typing import List, Dict, Optional
from flask import Flask, request, jsonify
# Constants
MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
ALLOWED_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.gif'}
# Functions
def process_image(image_path: str, max_size: int = MAX_FILE_SIZE) -> Dict[str, any]:
"""
Process an image file and extract metadata.
Args:
image_path: Path to the image file
max_size: Maximum file size in bytes
Returns:
Dictionary containing image metadata
Raises:
FileNotFoundError: If image file doesn't exist
ValueError: If file size exceeds limit
"""
if not os.path.exists(image_path):
raise FileNotFoundError(f"Image file not found: {image_path}")
file_size = os.path.getsize(image_path)
if file_size > max_size:
raise ValueError(f"File size {file_size} exceeds limit {max_size}")
# Process the image
metadata = extract_metadata(image_path)
return metadata
```
### Naming Conventions
- **Variables and Functions**: Use snake_case
- **Classes**: Use PascalCase
- **Constants**: Use UPPER_CASE
### Type Hints
```python
from typing import List, Dict, Optional, Union, Tuple
def get_photos(
user_id: int,
page: int = 1,
per_page: int = DEFAULT_PAGE_SIZE,
filters: Optional[Dict[str, any]] = None
) -> Dict[str, Union[List[Dict], int]]:
"""Get photos with pagination and filtering."""
pass
```
### Error Handling
```python
import logging
from typing import Optional
logger = logging.getLogger(__name__)
def safe_operation(func):
"""Decorator for safe operation execution."""
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
logger.error(f"Error in {func.__name__}: {e}")
return None
return wrapper
```
## Database Operations
### Connection Management
```python
def get_db_connection():
conn = sqlite3.connect('punimtag_simple.db')
conn.row_factory = sqlite3.Row # Enable dict-like access
return conn
# Usage in endpoint
try:
conn = get_db_connection()
cursor = conn.cursor()
# Database operations
conn.commit()
except Exception as e:
conn.rollback()
return jsonify({'success': False, 'error': str(e)}), 500
finally:
conn.close()
```
### Parameterized Queries
```python
# Always use parameterized queries to prevent SQL injection
cursor.execute('SELECT * FROM images WHERE id = ?', (image_id,))
cursor.execute('INSERT INTO photos (name, path) VALUES (?, ?)', (name, path))
```
## Testing Standards
### Test Organization
```
tests/
├── unit/ # Unit tests for individual functions
├── integration/ # Integration tests for API endpoints
├── e2e/ # End-to-end tests for complete workflows
├── fixtures/ # Test data and fixtures
├── utils/ # Test utilities and helpers
└── conftest.py # pytest configuration and shared fixtures
```
### Unit Test Example
```python
# tests/unit/test_face_recognition.py
import pytest
from src.utils.face_recognition import detect_faces, encode_face
def test_detect_faces_with_valid_image():
"""Test face detection with a valid image."""
image_path = "tests/fixtures/valid_face.jpg"
faces = detect_faces(image_path)
assert len(faces) > 0
assert all(hasattr(face, 'left') for face in faces)
assert all(hasattr(face, 'top') for face in faces)
```
### Integration Test Example
```python
# tests/integration/test_photo_api.py
import pytest
from src.app import app
@pytest.fixture
def client():
"""Create a test client."""
app.config['TESTING'] = True
app.config['DATABASE'] = 'test.db'
with app.test_client() as client:
yield client
def test_get_photos_endpoint(client):
"""Test the GET /photos endpoint."""
response = client.get('/photos')
assert response.status_code == 200
data = response.get_json()
assert data['success'] == True
assert 'photos' in data
```
## JavaScript Conventions
### Code Style
```javascript
// Use ES6+ features
const API_BASE_URL = '/api';
const DEFAULT_PAGE_SIZE = 20;
// Async/await for API calls
async function fetchPhotos(page = 1, perPage = DEFAULT_PAGE_SIZE) {
try {
const response = await fetch(`${API_BASE_URL}/photos?page=${page}&per_page=${perPage}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Error fetching photos:', error);
throw error;
}
}
// Event handlers
function handlePhotoClick(photoId) {
showPhotoDetails(photoId);
}
// DOM manipulation
function updatePhotoGrid(photos) {
const grid = document.getElementById('photo-grid');
grid.innerHTML = '';
photos.forEach(photo => {
const photoElement = createPhotoElement(photo);
grid.appendChild(photoElement);
});
}
```
### Error Handling
```javascript
// Global error handler
window.addEventListener('error', (event) => {
console.error('Global error:', event.error);
showErrorMessage('An unexpected error occurred');
});
// API error handling
async function safeApiCall(apiFunction, ...args) {
try {
return await apiFunction(...args);
} catch (error) {
console.error('API call failed:', error);
showErrorMessage('Failed to load data. Please try again.');
return null;
}
}
```
## Performance Considerations
### Image Processing
- **Thumbnail Generation**: On-demand with caching
- **Face Detection**: Optimized for speed vs accuracy
- **Batch Processing**: Efficient handling of large photo sets
- **Memory Management**: Streaming for large images
### Database Optimization
- **Indexing**: Strategic indexes on frequently queried columns
- **Connection Pooling**: Efficient database connections
- **Query Optimization**: Minimize N+1 query problems
- **Data Archiving**: Move old data to separate tables
### Frontend Performance
- **Progressive Loading**: Load data in chunks
- **Image Lazy Loading**: Load images as they become visible
- **Caching**: Browser caching for static assets
- **Debouncing**: Prevent excessive API calls
## Security Considerations
### Data Protection
- **Local Storage**: No cloud dependencies
- **Input Validation**: Sanitize all user inputs
- **SQL Injection Prevention**: Parameterized queries
- **File Upload Security**: Validate file types and sizes
### Privacy
- **Face Data**: Stored locally, not shared
- **Metadata**: User controls what's stored
- **Access Control**: Local access only
- **Data Export**: User can export/delete their data
## Development Workflow
### Code Organization
- **Modular Design**: Separate concerns into modules
- **Configuration Management**: Environment-based settings
- **Error Handling**: Comprehensive error catching and logging
- **Documentation**: Inline code documentation
### Testing Strategy
- **Unit Tests**: Test individual functions and classes
- **Integration Tests**: Test API endpoints and database operations
- **End-to-End Tests**: Test complete user workflows
- **Performance Tests**: Test with large datasets
## Quick Start Commands
```bash
# Install dependencies
pip install -r requirements.txt
# Run the application
python main.py
# Access the web interface
# http://localhost:5000
# Run tests
python tests/test_main.py
# Run with pytest (if installed)
pytest tests/
```
## Common Development Tasks
### Adding New API Endpoints
1. Follow the API standards for response format
2. Use proper HTTP status codes
3. Implement error handling
4. Add parameterized queries for database operations
5. Write integration tests
### Adding New Features
1. Follow the project structure
2. Use type hints in Python
3. Follow naming conventions
4. Add comprehensive error handling
5. Write tests for new functionality
### Database Changes
1. Use parameterized queries
2. Add proper indexes
3. Handle connection management
4. Implement rollback on errors
5. Update schema documentation
## Troubleshooting
### Common Issues
- **Face Recognition Not Working**: Check dlib installation and CUDA setup
- **Database Errors**: Verify SQLite file permissions and schema
- **Performance Issues**: Check image sizes and database indexes
- **UI Not Loading**: Check browser console for JavaScript errors
### Debug Mode
```python
# Enable debug mode in Flask
app.run(host='0.0.0.0', port=5000, debug=True)
```
## Future Roadmap
- Cloud sync capabilities
- Mobile app companion
- Advanced AI features (emotion detection, age progression)
- Social sharing features
- Integration with existing photo services
## Support and Resources
- Check the steering documents in `docs/`
- Review existing tests in `tests/`
- Check the API standards for endpoint usage
- Follow code conventions for maintainability