File size: 1,130 Bytes
2e818da
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from __future__ import annotations
import time
import uuid
from typing import List, Optional

from pydantic import BaseModel, ConfigDict, Field


class _StrictModel(BaseModel):
    model_config = ConfigDict(strict=True, extra="forbid")


class BoundingBox(_StrictModel):
    """Page-normalised bounding box (all coords 0..1, relative to page element)."""
    page: int
    x: float
    y: float
    w: float
    h: float


class SelectionSnippet(_StrictModel):
    page_number: int
    text: str
    boxes: List[BoundingBox]
    char_start: Optional[int] = None
    char_end: Optional[int] = None


class StudentAnnotation(_StrictModel):
    annotation_id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    document_id: str = Field(pattern=r"^[0-9a-f]{64}$")
    project_id: str = Field(pattern=r"^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$")
    target_snippets: List[SelectionSnippet]
    note_text: Optional[str] = None
    image_base64: Optional[str] = None  # cropped region PNG (pinned figures/tables/formulas)
    created_at: float = Field(default_factory=time.time)
    updated_at: float = Field(default_factory=time.time)