Venket / src /templates /annotation_schema.py
venki101's picture
Add files using upload-large-folder tool
97b64b9 verified
Raw History Blame Contribute Delete
2.04 kB
"""Pydantic schema for template annotation files (``annotations/<template_id>.json``)."""
from __future__ import annotations
from pydantic import BaseModel, ConfigDict, Field, model_validator
class SignatureBoxAnnotation(BaseModel):
"""A single signature field on a page, in pixel coordinates of the template image."""
model_config = ConfigDict(extra="forbid")
id: str
x1: float
y1: float
x2: float
y2: float
role: str = "Signer"
name: str = "Signer"
@model_validator(mode="after")
def _normalize_box(self) -> "SignatureBoxAnnotation":
x1, x2 = sorted((self.x1, self.x2))
y1, y2 = sorted((self.y1, self.y2))
self.x1, self.x2, self.y1, self.y2 = x1, x2, y1, y2
if x2 <= x1 or y2 <= y1:
raise ValueError(f"Signature box '{self.id}' has non-positive area: {self.as_tuple()}")
return self
def as_tuple(self) -> tuple[float, float, float, float]:
"""Return the box as ``(x1, y1, x2, y2)``."""
return (self.x1, self.y1, self.x2, self.y2)
@property
def width(self) -> float:
return self.x2 - self.x1
@property
def height(self) -> float:
return self.y2 - self.y1
class TemplatePageAnnotation(BaseModel):
"""A single page of a template document."""
model_config = ConfigDict(extra="forbid")
page: int = 1
page_size: tuple[int, int]
dpi: int = 300
signature_boxes: list[SignatureBoxAnnotation] = Field(default_factory=list)
class TemplateAnnotation(BaseModel):
"""Full annotation for one template document (possibly multi-page)."""
model_config = ConfigDict(extra="forbid")
id: str
source_image: "str | None" = None
document_type: "str | None" = None
pages: list[TemplatePageAnnotation]
auto_detected: bool = False
def page_by_number(self, page: int) -> TemplatePageAnnotation:
for p in self.pages:
if p.page == page:
return p
raise KeyError(f"Template '{self.id}' has no page {page}")