136 lines
2.9 KiB
Python
136 lines
2.9 KiB
Python
from datetime import datetime
|
|
from typing import Any, Literal
|
|
from uuid import UUID
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class Rect(BaseModel):
|
|
x: float
|
|
y: float
|
|
width: float
|
|
height: float
|
|
|
|
|
|
class AnnotationBase(BaseModel):
|
|
id: UUID
|
|
page: int = Field(ge=0)
|
|
type: str
|
|
rect: Rect
|
|
rotation: float = 0.0
|
|
z: int = 0
|
|
createdAt: datetime
|
|
updatedAt: datetime
|
|
|
|
|
|
class TextProps(BaseModel):
|
|
text: str
|
|
fontFamily: str = "Liberation Sans"
|
|
fontSize: float = 14
|
|
color: str = "#000000"
|
|
align: Literal["left", "center", "right"] = "left"
|
|
bold: bool = False
|
|
italic: bool = False
|
|
lineHeight: float = 1.2
|
|
highlightColor: str | None = None
|
|
styles: dict[str, Any] | None = None
|
|
|
|
|
|
class TextAnnotation(AnnotationBase):
|
|
type: Literal["text"]
|
|
props: TextProps
|
|
|
|
|
|
class DrawProps(BaseModel):
|
|
paths: list[tuple[float, float]] = Field(default_factory=list)
|
|
svgPath: str | None = None
|
|
strokeColor: str = "#000000"
|
|
strokeWidth: float = 2
|
|
opacity: float = 1.0
|
|
|
|
|
|
class DrawAnnotation(AnnotationBase):
|
|
type: Literal["draw"]
|
|
props: DrawProps
|
|
|
|
|
|
class SignatureDrawProps(BaseModel):
|
|
mode: Literal["draw"]
|
|
ref: str
|
|
strokeColor: str = "#000000"
|
|
|
|
|
|
class SignatureTypeProps(BaseModel):
|
|
mode: Literal["type"]
|
|
text: str
|
|
fontFamily: str
|
|
color: str = "#000000"
|
|
|
|
|
|
class SignatureAnnotation(AnnotationBase):
|
|
type: Literal["signature"]
|
|
props: SignatureDrawProps | SignatureTypeProps = Field(discriminator="mode")
|
|
|
|
|
|
class ImageProps(BaseModel):
|
|
ref: str
|
|
naturalWidth: float
|
|
naturalHeight: float
|
|
|
|
|
|
class ImageAnnotation(AnnotationBase):
|
|
type: Literal["image"]
|
|
props: ImageProps
|
|
|
|
|
|
class HighlightProps(BaseModel):
|
|
color: str = "#FFEB3B"
|
|
opacity: float = 0.3
|
|
|
|
|
|
class HighlightAnnotation(AnnotationBase):
|
|
type: Literal["highlight"]
|
|
props: HighlightProps
|
|
|
|
|
|
class ShapeProps(BaseModel):
|
|
kind: Literal["rect", "ellipse", "line", "arrow"]
|
|
strokeColor: str = "#000000"
|
|
fillColor: str = "transparent"
|
|
strokeWidth: float = 2
|
|
start: tuple[float, float] | None = None
|
|
end: tuple[float, float] | None = None
|
|
|
|
|
|
class ShapeAnnotation(AnnotationBase):
|
|
type: Literal["shape"]
|
|
props: ShapeProps
|
|
|
|
|
|
KnownAnnotation = (
|
|
TextAnnotation
|
|
| DrawAnnotation
|
|
| SignatureAnnotation
|
|
| ImageAnnotation
|
|
| HighlightAnnotation
|
|
| ShapeAnnotation
|
|
)
|
|
|
|
# Working state is intentionally opaque. Keeping this payload as dictionaries
|
|
# lets newer clients round-trip annotation types that this server cannot export
|
|
# yet; the export registry skips those types with a warning.
|
|
AnnotationPayload = dict[str, Any]
|
|
|
|
|
|
class AnnotationStateResponse(BaseModel):
|
|
data: list[AnnotationPayload]
|
|
updatedAt: datetime
|
|
|
|
|
|
class AnnotationStateUpdateRequest(BaseModel):
|
|
data: list[AnnotationPayload]
|
|
baseUpdatedAt: datetime | None = None
|
|
|
|
|
|
class AnnotationStateUpdateResponse(BaseModel):
|
|
updatedAt: datetime
|