diff --git a/frontend/src/api/faces.ts b/frontend/src/api/faces.ts index 766f5ab..e4150d3 100644 --- a/frontend/src/api/faces.ts +++ b/frontend/src/api/faces.ts @@ -152,6 +152,7 @@ export const facesApi = { date_to?: string date_taken_from?: string date_taken_to?: string + date_processed?: string date_processed_from?: string date_processed_to?: string sort_by?: 'quality' | 'date_taken' | 'date_added' diff --git a/frontend/src/pages/Identify.tsx b/frontend/src/pages/Identify.tsx index ab422b4..cc6144a 100644 --- a/frontend/src/pages/Identify.tsx +++ b/frontend/src/pages/Identify.tsx @@ -18,6 +18,7 @@ export default function Identify() { const [sortDir, setSortDir] = useState('desc') const [dateFrom, setDateFrom] = useState('') const [dateTo, setDateTo] = useState('') + const [dateProcessed, setDateProcessed] = useState('') const [currentIdx, setCurrentIdx] = useState(0) const currentFace = faces[currentIdx] @@ -74,8 +75,9 @@ export default function Identify() { page: 1, page_size: pageSize, min_quality: minQuality, - date_from: dateFrom || undefined, - date_to: dateTo || undefined, + date_taken_from: dateFrom || undefined, + date_taken_to: dateTo || undefined, + date_processed: dateProcessed || undefined, sort_by: sortBy, sort_dir: sortDir, tag_names: selectedTags.length > 0 ? selectedTags.join(', ') : undefined, @@ -248,6 +250,7 @@ export default function Identify() { if (settings.sortDir !== undefined) setSortDir(settings.sortDir) if (settings.dateFrom !== undefined) setDateFrom(settings.dateFrom) if (settings.dateTo !== undefined) setDateTo(settings.dateTo) + if (settings.dateProcessed !== undefined) setDateProcessed(settings.dateProcessed) if (settings.uniqueFacesOnly !== undefined) setUniqueFacesOnly(settings.uniqueFacesOnly) if (settings.compareEnabled !== undefined) setCompareEnabled(settings.compareEnabled) if (settings.selectedTags !== undefined) setSelectedTags(settings.selectedTags) @@ -271,6 +274,7 @@ export default function Identify() { sortDir, dateFrom, dateTo, + dateProcessed, uniqueFacesOnly, compareEnabled, selectedTags, @@ -279,7 +283,7 @@ export default function Identify() { } catch (error) { console.error('Error saving settings to localStorage:', error) } - }, [pageSize, minQuality, sortBy, sortDir, dateFrom, dateTo, uniqueFacesOnly, compareEnabled, selectedTags, settingsLoaded]) + }, [pageSize, minQuality, sortBy, sortDir, dateFrom, dateTo, dateProcessed, uniqueFacesOnly, compareEnabled, selectedTags, settingsLoaded]) // Initial load on mount (after settings are loaded) useEffect(() => { @@ -521,18 +525,12 @@ export default function Identify() {
- - setMinQuality(parseFloat(e.target.value))} className="w-full" /> -
{(minQuality * 100).toFixed(0)}%
-
-
- + setDateFrom(e.target.value)} className="mt-1 block w-full border rounded px-2 py-1" />
- + setDateTo(e.target.value)} className="mt-1 block w-full border rounded px-2 py-1" />
@@ -553,6 +551,17 @@ export default function Identify() {
+
+ + setDateProcessed(e.target.value)} + className="mt-1 block w-full border rounded px-2 py-1" /> +
+
+ + setMinQuality(parseFloat(e.target.value))} className="w-full" /> +
{(minQuality * 100).toFixed(0)}%
+
diff --git a/src/web/api/faces.py b/src/web/api/faces.py index aa585e2..5ae40d5 100644 --- a/src/web/api/faces.py +++ b/src/web/api/faces.py @@ -100,10 +100,11 @@ def process_faces(request: ProcessFacesRequest) -> ProcessFacesResponse: @router.get("/unidentified", response_model=UnidentifiedFacesResponse) def get_unidentified_faces( page: int = Query(1, ge=1), - page_size: int = Query(50, ge=1, le=200), + page_size: int = Query(50, ge=1, le=2000), min_quality: float = Query(0.0, ge=0.0, le=1.0), - date_from: str | None = Query(None), - date_to: str | None = Query(None), + date_taken_from: str | None = Query(None, description="Filter by date taken (from)"), + date_taken_to: str | None = Query(None, description="Filter by date taken (to)"), + date_processed: str | None = Query(None, description="Filter by date processed (exact date)"), sort_by: str = Query("quality"), sort_dir: str = Query("desc"), tag_names: str | None = Query(None, description="Comma-separated tag names for filtering"), @@ -113,8 +114,20 @@ def get_unidentified_faces( """Get unidentified faces with filters and pagination.""" from datetime import date as _date - df = _date.fromisoformat(date_from) if date_from else None - dt = _date.fromisoformat(date_to) if date_to else None + try: + dtf = _date.fromisoformat(date_taken_from) if date_taken_from and date_taken_from.strip() else None + except (ValueError, AttributeError, TypeError): + dtf = None + + try: + dtt = _date.fromisoformat(date_taken_to) if date_taken_to and date_taken_to.strip() else None + except (ValueError, AttributeError, TypeError): + dtt = None + + try: + dp = _date.fromisoformat(date_processed) if date_processed and date_processed.strip() else None + except (ValueError, AttributeError, TypeError): + dp = None # Parse tag names tag_names_list = None @@ -126,8 +139,9 @@ def get_unidentified_faces( page=page, page_size=page_size, min_quality=min_quality, - date_from=df, - date_to=dt, + date_taken_from=dtf, + date_taken_to=dtt, + date_processed=dp, sort_by=sort_by, sort_dir=sort_dir, tag_names=tag_names_list, diff --git a/src/web/services/face_service.py b/src/web/services/face_service.py index 6029ac2..5cbd409 100644 --- a/src/web/services/face_service.py +++ b/src/web/services/face_service.py @@ -1200,6 +1200,7 @@ def list_unidentified_faces( date_to: Optional[date] = None, date_taken_from: Optional[date] = None, date_taken_to: Optional[date] = None, + date_processed: Optional[date] = None, date_processed_from: Optional[date] = None, date_processed_to: Optional[date] = None, sort_by: str = "quality", @@ -1263,6 +1264,9 @@ def list_unidentified_faces( query = query.filter(Photo.date_taken <= date_taken_to) # Date processed filters (uses photo.date_added) + if date_processed is not None: + # Filter by exact date processed + query = query.filter(func.date(Photo.date_added) == date_processed) if date_processed_from is not None: query = query.filter(func.date(Photo.date_added) >= date_processed_from) if date_processed_to is not None: