diff --git a/core/db/models.py b/core/db/models.py index 5cda061..983a6b6 100644 --- a/core/db/models.py +++ b/core/db/models.py @@ -164,7 +164,7 @@ class Brand(SQLModel, table=True): aliases: List[str] = Field(default_factory=list, sa_column=Column(JSON, nullable=False, server_default='[]')) source: BrandSource = "ocr" confirmed: bool = False - airings: List[str] = Field(default_factory=list, sa_column=Column(JSON, nullable=False, server_default='[]')) + airings: List[Dict[str, Any]] = Field(default_factory=list, sa_column=Column(JSON, nullable=False, server_default='[]')) total_airings: int = 0 created_at: Optional[datetime] = Field(default_factory=datetime.utcnow) updated_at: Optional[datetime] = Field(default_factory=datetime.utcnow) diff --git a/core/gpu/models/models.py b/core/gpu/models/models.py index ca820df..f2a90f5 100644 --- a/core/gpu/models/models.py +++ b/core/gpu/models/models.py @@ -115,13 +115,13 @@ class SegmentFieldRequest(BaseModel): class SegmentFieldResponse(BaseModel): """Response from field segmentation.""" - boundary: List[str] = Field(default_factory=list) + boundary: List[List[int]] = Field(default_factory=list) coverage: float = 0.0 mask_b64: str = "" class SegmentFieldDebugResponse(BaseModel): """Response from field segmentation with debug overlay.""" - boundary: List[str] = Field(default_factory=list) + boundary: List[List[int]] = Field(default_factory=list) coverage: float = 0.0 mask_overlay_b64: str = "" diff --git a/modelgen/types.py b/modelgen/types.py index 274d14a..a9f6883 100644 --- a/modelgen/types.py +++ b/modelgen/types.py @@ -8,6 +8,8 @@ Used by generators to convert Python types to target framework types. import dataclasses as dc from typing import Any, Callable, get_args +from .helpers import get_origin_name + # ============================================================================= # Django Type Mappings # ============================================================================= @@ -38,7 +40,7 @@ DJANGO_SPECIAL: dict[str, str] = { def _get_list_inner(type_hint: Any) -> str: - """Get inner type of List[T] for Pydantic.""" + """Get inner type of List[T] for Pydantic. Recurses for nested generics.""" args = get_args(type_hint) if args: inner = args[0] @@ -46,6 +48,11 @@ def _get_list_inner(type_hint: Any) -> str: return {str: "str", int: "int", float: "float", bool: "bool"}[inner] if isinstance(inner, type) and dc.is_dataclass(inner): return inner.__name__ + origin = get_origin_name(inner) + if origin == "list": + return f"List[{_get_list_inner(inner)}]" + if origin == "dict": + return "Dict[str, Any]" return "str" @@ -69,7 +76,7 @@ PYDANTIC_RESOLVERS: dict[Any, Callable[[Any], str]] = { def _resolve_ts_list(base: Any) -> str: - """Resolve TypeScript list type.""" + """Resolve TypeScript list type. Recurses for nested generics.""" args = get_args(base) if args: inner = args[0] @@ -81,6 +88,11 @@ def _resolve_ts_list(base: Any) -> str: return "boolean[]" elif isinstance(inner, type) and dc.is_dataclass(inner): return f"{inner.__name__}[]" + origin = get_origin_name(inner) + if origin == "list": + return f"{_resolve_ts_list(inner)}[]" + if origin == "dict": + return "Record[]" return "string[]" diff --git a/ui/common/types/generated.ts b/ui/common/types/generated.ts index 89cd48c..87bdbd4 100644 --- a/ui/common/types/generated.ts +++ b/ui/common/types/generated.ts @@ -117,7 +117,7 @@ export interface Brand { aliases: string[]; source: BrandSource; confirmed: boolean; - airings: string[]; + airings: Record[]; total_airings: number; created_at: string | null; updated_at: string | null;