Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import json | |
| import re | |
| from datetime import datetime | |
| from enum import Enum | |
| from typing import Any, Literal | |
| from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator | |
| PROJECT_NAME_MAX_LENGTH = 200 | |
| PROJECT_DESCRIPTION_MAX_LENGTH = 4000 | |
| PROJECT_METADATA_MAX_BYTES = 16 * 1024 | |
| class ProjectStatus(str, Enum): | |
| ACTIVE = "active" | |
| ARCHIVED = "archived" | |
| def normalize_project_name(value: str) -> str: | |
| normalized = re.sub(r"\s+", " ", value).strip() | |
| if not normalized: | |
| raise ValueError("Project name cannot be blank") | |
| if len(normalized) > PROJECT_NAME_MAX_LENGTH: | |
| raise ValueError(f"Project name cannot exceed {PROJECT_NAME_MAX_LENGTH} characters") | |
| return normalized | |
| def validate_metadata_size(value: dict[str, Any]) -> dict[str, Any]: | |
| try: | |
| encoded = json.dumps( | |
| value, ensure_ascii=False, separators=(",", ":"), allow_nan=False | |
| ).encode("utf-8") | |
| except (TypeError, ValueError) as exc: | |
| raise ValueError("Project metadata must be valid JSON") from exc | |
| if len(encoded) > PROJECT_METADATA_MAX_BYTES: | |
| raise ValueError(f"Project metadata cannot exceed {PROJECT_METADATA_MAX_BYTES} bytes") | |
| return value | |
| class ProjectCreate(BaseModel): | |
| model_config = ConfigDict(extra="forbid") | |
| name: str | |
| description: str | None = Field(default=None, max_length=PROJECT_DESCRIPTION_MAX_LENGTH) | |
| thumbnail_asset_id: str | None = Field(default=None, min_length=1, max_length=36) | |
| metadata: dict[str, Any] = Field(default_factory=dict) | |
| _normalize_name = field_validator("name")(normalize_project_name) | |
| _validate_metadata = field_validator("metadata")(validate_metadata_size) | |
| class ProjectUpdate(BaseModel): | |
| model_config = ConfigDict(extra="forbid") | |
| name: str | None = None | |
| description: str | None = Field(default=None, max_length=PROJECT_DESCRIPTION_MAX_LENGTH) | |
| thumbnail_asset_id: str | None = Field(default=None, min_length=1, max_length=36) | |
| metadata: dict[str, Any] | None = None | |
| status: ProjectStatus | None = None | |
| def normalize_name(cls, value: str | None) -> str | None: | |
| if value is None: | |
| return value | |
| return normalize_project_name(value) | |
| def validate_metadata(cls, value: dict[str, Any] | None) -> dict[str, Any] | None: | |
| return None if value is None else validate_metadata_size(value) | |
| def validate_patch(self) -> ProjectUpdate: | |
| if not self.model_fields_set: | |
| raise ValueError("At least one project field must be supplied") | |
| if "name" in self.model_fields_set and self.name is None: | |
| raise ValueError("Project name cannot be null") | |
| if "metadata" in self.model_fields_set and self.metadata is None: | |
| raise ValueError("Project metadata cannot be null") | |
| if "status" in self.model_fields_set and self.status is None: | |
| raise ValueError("Project status cannot be null") | |
| return self | |
| class ProjectResponse(BaseModel): | |
| model_config = ConfigDict(from_attributes=True) | |
| id: str | |
| workspace_id: str | |
| name: str | |
| description: str | None | |
| status: ProjectStatus | |
| thumbnail_asset_id: str | None | |
| brand_kit_id: str | None = None | |
| brand_kit_version_id: str | None = None | |
| metadata: dict[str, Any] | |
| created_by: str | |
| created_at: datetime | |
| updated_at: datetime | |
| archived_at: datetime | None | |
| class ProjectListResponse(BaseModel): | |
| items: list[ProjectResponse] | |
| next_cursor: str | None = None | |
| limit: int = Field(ge=1, le=100) | |
| class ProjectAssetAttach(BaseModel): | |
| model_config = ConfigDict(extra="forbid") | |
| asset_id: str = Field(min_length=1, max_length=36) | |
| class ProjectAssetResponse(BaseModel): | |
| id: str | |
| project_id: str | |
| request_id: str | |
| filename: str | |
| mime_type: str | |
| file_size: int | |
| metadata: dict[str, Any] | |
| created_by_user_id: str | None | |
| created_at: datetime | |
| updated_at: datetime | |
| class ProjectAssetListResponse(BaseModel): | |
| items: list[ProjectAssetResponse] | |
| class ProjectGenerationJobAttach(BaseModel): | |
| model_config = ConfigDict(extra="forbid") | |
| generation_job_id: str = Field(min_length=1, max_length=36) | |
| class ProjectGenerationJobResponse(BaseModel): | |
| id: str | |
| project_id: str | |
| job_type: Literal["generation"] = "generation" | |
| generation_request_id: str | |
| provider: str | |
| status: str | |
| output_asset_id: str | None | |
| error_code: str | None | |
| created_at: datetime | |
| started_at: datetime | None | |
| completed_at: datetime | None | |
| updated_at: datetime | |
| attached_at: datetime | |
| class ProjectGenerationJobListResponse(BaseModel): | |
| items: list[ProjectGenerationJobResponse] | |