Files
punimtag/backend/schemas/people.py
T
ilia 3b9cd12e20
CI / skip-ci-check (pull_request) Successful in 32s
CI / python-lint (pull_request) Successful in 36s
CI / docker-ci (pull_request) Successful in 36s
CI / secret-scan (pull_request) Successful in 47s
CI / admin-unit (pull_request) Successful in 1m27s
CI / viewer-unit (pull_request) Successful in 3m53s
CI / e2e (pull_request) Successful in 3m5s
Add Immich-style person merge API and Modify UI.
POST /people/{keep_id}/merge reassigns faces, videos, and match
decisions, rebuilds encodings, then deletes sources so strict
Auto-Match thresholds stay recoverable.
2026-08-05 12:32:16 -04:00

110 lines
2.7 KiB
Python

"""People schemas for web API (Phase 3)."""
from __future__ import annotations
from datetime import date
from typing import Optional
from pydantic import BaseModel, ConfigDict, Field
class PersonResponse(BaseModel):
"""Person DTO returned from API."""
model_config = ConfigDict(from_attributes=True, protected_namespaces=())
id: int
first_name: str
last_name: str
middle_name: Optional[str] = None
maiden_name: Optional[str] = None
date_of_birth: Optional[date] = None
email: Optional[str] = None
phone: Optional[str] = None
class PersonCreateRequest(BaseModel):
"""Request payload to create a new person."""
model_config = ConfigDict(protected_namespaces=())
first_name: str = Field(..., min_length=1)
last_name: str = Field(..., min_length=1)
middle_name: Optional[str] = None
maiden_name: Optional[str] = None
date_of_birth: Optional[date] = None
email: Optional[str] = None
phone: Optional[str] = None
class PeopleListResponse(BaseModel):
"""List of people for selection dropdowns."""
model_config = ConfigDict(protected_namespaces=())
items: list[PersonResponse]
total: int
class PersonUpdateRequest(BaseModel):
"""Request payload to update a person."""
model_config = ConfigDict(protected_namespaces=())
first_name: str = Field(..., min_length=1)
last_name: str = Field(..., min_length=1)
middle_name: Optional[str] = None
maiden_name: Optional[str] = None
date_of_birth: Optional[date] = None
email: Optional[str] = None
phone: Optional[str] = None
class PersonWithFacesResponse(BaseModel):
"""Person with face count for modify identified workflow."""
model_config = ConfigDict(from_attributes=True, protected_namespaces=())
id: int
first_name: str
last_name: str
middle_name: Optional[str] = None
maiden_name: Optional[str] = None
date_of_birth: Optional[date] = None
email: Optional[str] = None
phone: Optional[str] = None
face_count: int
video_count: int
class PeopleWithFacesListResponse(BaseModel):
"""List of people with face counts."""
model_config = ConfigDict(protected_namespaces=())
items: list[PersonWithFacesResponse]
total: int
class PersonMergeRequest(BaseModel):
"""Merge other people into the keep person (Immich-style)."""
model_config = ConfigDict(protected_namespaces=())
merge_ids: list[int] = Field(..., min_length=1, description="Person IDs to merge into keep")
class PersonMergeResponse(BaseModel):
"""Result of merging people into keep."""
model_config = ConfigDict(protected_namespaces=())
person: PersonResponse
merged_ids: list[int]
faces_moved: int
videos_moved: int
encodings_rebuilt: int