import uuid from datetime import datetime from pydantic import BaseModel, Field class OutputTypeCreate(BaseModel): name: str description: str | None = None renderer: str = "blender" render_settings: dict = {} output_format: str = "png" sort_order: int = 0 is_active: bool = True compatible_categories: list[str] = [] render_backend: str = "celery" is_animation: bool = False transparent_bg: bool = False pricing_tier_id: int | None = None cycles_device: str | None = None workflow_family: str = "order_line" artifact_kind: str | None = None invocation_overrides: dict = {} workflow_definition_id: uuid.UUID | None = None workflow_rollout_mode: str = "legacy_only" material_override: str | None = None class OutputTypePatch(BaseModel): name: str | None = None description: str | None = None renderer: str | None = None render_settings: dict | None = None output_format: str | None = None sort_order: int | None = None is_active: bool | None = None compatible_categories: list[str] | None = None render_backend: str | None = None is_animation: bool | None = None transparent_bg: bool | None = None workflow_family: str | None = None artifact_kind: str | None = None invocation_overrides: dict | None = None pricing_tier_id: int | None = None cycles_device: str | None = None workflow_definition_id: uuid.UUID | None = None workflow_rollout_mode: str | None = None material_override: str | None = None class OutputTypeInvocationProfileOut(BaseModel): renderer: str render_backend: str workflow_family: str artifact_kind: str output_format: str is_animation: bool workflow_definition_id: uuid.UUID | None = None workflow_rollout_mode: str = "legacy_only" transparent_bg: bool cycles_device: str | None = None material_override: str | None = None allowed_override_keys: list[str] = Field(default_factory=list) invocation_overrides: dict = Field(default_factory=dict) class OutputTypeContractCatalogOut(BaseModel): workflow_families: list[str] = Field(default_factory=list) workflow_rollout_modes: list[str] = Field(default_factory=list) artifact_kinds: list[str] = Field(default_factory=list) allowed_artifact_kinds_by_family: dict[str, list[str]] = Field(default_factory=dict) allowed_output_formats_by_family: dict[str, list[str]] = Field(default_factory=dict) allowed_invocation_override_keys_by_artifact_kind: dict[str, list[str]] = Field(default_factory=dict) default_output_format_by_artifact_kind: dict[str, str] = Field(default_factory=dict) parameter_ownership: dict[str, dict | list[str]] = Field(default_factory=dict) class OutputTypeOut(BaseModel): id: uuid.UUID name: str description: str | None renderer: str render_settings: dict output_format: str sort_order: int compatible_categories: list[str] render_backend: str is_animation: bool transparent_bg: bool workflow_family: str artifact_kind: str invocation_overrides: dict cycles_device: str | None = None pricing_tier_id: int | None = None pricing_tier_name: str | None = None price_per_item: float | None = None workflow_definition_id: uuid.UUID | None = None workflow_rollout_mode: str workflow_name: str | None = None material_override: str | None = None invocation_profile: OutputTypeInvocationProfileOut | None = None is_active: bool created_at: datetime updated_at: datetime model_config = {"from_attributes": True} class RenderPositionCreate(BaseModel): name: str rotation_x: float = 0.0 rotation_y: float = 0.0 rotation_z: float = 0.0 is_default: bool = False sort_order: int = 0 focal_length_mm: float | None = None sensor_width_mm: float | None = None class RenderPositionPatch(BaseModel): name: str | None = None rotation_x: float | None = None rotation_y: float | None = None rotation_z: float | None = None is_default: bool | None = None sort_order: int | None = None focal_length_mm: float | None = None sensor_width_mm: float | None = None class RenderPositionOut(BaseModel): id: uuid.UUID product_id: uuid.UUID name: str rotation_x: float rotation_y: float rotation_z: float is_default: bool sort_order: int focal_length_mm: float | None = None sensor_width_mm: float | None = None created_at: datetime updated_at: datetime model_config = {"from_attributes": True} class GlobalRenderPositionCreate(BaseModel): name: str rotation_x: float = 0.0 rotation_y: float = 0.0 rotation_z: float = 0.0 is_default: bool = False sort_order: int = 0 focal_length_mm: float | None = None sensor_width_mm: float | None = None class GlobalRenderPositionPatch(BaseModel): name: str | None = None rotation_x: float | None = None rotation_y: float | None = None rotation_z: float | None = None is_default: bool | None = None sort_order: int | None = None focal_length_mm: float | None = None sensor_width_mm: float | None = None class GlobalRenderPositionOut(BaseModel): id: uuid.UUID name: str rotation_x: float rotation_y: float rotation_z: float is_default: bool sort_order: int focal_length_mm: float | None = None sensor_width_mm: float | None = None created_at: datetime updated_at: datetime model_config = {"from_attributes": True} class WorkflowDefinitionCreate(BaseModel): name: str output_type_id: uuid.UUID | None = None config: dict is_active: bool = True class WorkflowDefinitionUpdate(BaseModel): name: str | None = None config: dict | None = None is_active: bool | None = None class WorkflowDefinitionOut(BaseModel): id: uuid.UUID name: str output_type_id: uuid.UUID | None config: dict family: str | None = None supported_artifact_kinds: list[str] = Field(default_factory=list) rollout_summary: "WorkflowRolloutSummaryOut" = Field( default_factory=lambda: WorkflowRolloutSummaryOut() ) is_active: bool created_at: datetime model_config = {"from_attributes": True} class WorkflowDraftPreflightRequest(BaseModel): context_id: str config: dict workflow_id: uuid.UUID | None = None class WorkflowDraftDispatchRequest(BaseModel): context_id: str config: dict workflow_id: uuid.UUID | None = None class WorkflowNodeResultOut(BaseModel): id: uuid.UUID node_name: str status: str output: dict | None log: str | None duration_s: float | None created_at: datetime model_config = {"from_attributes": True} class WorkflowRunOut(BaseModel): id: uuid.UUID workflow_def_id: uuid.UUID | None order_line_id: uuid.UUID | None celery_task_id: str | None execution_mode: str status: str started_at: datetime | None completed_at: datetime | None error_message: str | None created_at: datetime node_results: list[WorkflowNodeResultOut] = [] model_config = {"from_attributes": True} class WorkflowRolloutLatestRunOut(BaseModel): workflow_run_id: uuid.UUID execution_mode: str status: str created_at: datetime completed_at: datetime | None = None class WorkflowRolloutLinkedOutputTypeOut(BaseModel): id: uuid.UUID name: str is_active: bool artifact_kind: str workflow_rollout_mode: str class WorkflowRolloutSummaryOut(BaseModel): linked_output_type_count: int = 0 active_output_type_count: int = 0 linked_output_type_names: list[str] = Field(default_factory=list) linked_output_types: list[WorkflowRolloutLinkedOutputTypeOut] = Field(default_factory=list) rollout_modes: list[str] = Field(default_factory=list) has_blocking_contracts: bool = False blocking_reasons: list[str] = Field(default_factory=list) latest_run: WorkflowRolloutLatestRunOut | None = None latest_shadow_run: WorkflowRolloutLatestRunOut | None = None latest_rollout_gate_verdict: str | None = None latest_rollout_ready: bool | None = None latest_rollout_status: str | None = None latest_rollout_reasons: list[str] = Field(default_factory=list) class WorkflowComparisonArtifactOut(BaseModel): path: str | None storage_key: str | None exists: bool file_size_bytes: int | None sha256: str | None mime_type: str | None image_width: int | None image_height: int | None class WorkflowRunComparisonOut(BaseModel): workflow_run_id: uuid.UUID workflow_def_id: uuid.UUID | None order_line_id: uuid.UUID | None execution_mode: str status: str summary: str rollout_gate_verdict: str workflow_rollout_ready: bool workflow_rollout_status: str rollout_reasons: list[str] = [] rollout_thresholds: dict[str, float] = Field(default_factory=dict) authoritative_output: WorkflowComparisonArtifactOut observer_output: WorkflowComparisonArtifactOut exact_match: bool | None dimensions_match: bool | None mean_pixel_delta: float | None class WorkflowPreflightIssueOut(BaseModel): severity: str code: str message: str node_id: str | None = None step: str | None = None class WorkflowPreflightNodeOut(BaseModel): node_id: str step: str label: str | None = None execution_kind: str supported: bool status: str issues: list[WorkflowPreflightIssueOut] = [] class WorkflowPreflightOut(BaseModel): workflow_id: uuid.UUID | None = None context_id: str context_kind: str | None = None expected_context_kind: str execution_mode: str graph_dispatch_allowed: bool summary: str resolved_order_line_id: uuid.UUID | None = None resolved_cad_file_id: uuid.UUID | None = None unsupported_node_ids: list[str] = [] issues: list[WorkflowPreflightIssueOut] = [] nodes: list[WorkflowPreflightNodeOut] = [] class WorkflowOrderLineContextOptionOut(BaseModel): value: uuid.UUID label: str meta: str class WorkflowOrderLineContextGroupOut(BaseModel): order_id: uuid.UUID order_label: str options: list[WorkflowOrderLineContextOptionOut] = []