221 lines
6.2 KiB
Python
221 lines
6.2 KiB
Python
from datetime import UTC, datetime
|
|
from enum import StrEnum
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class WorkflowStage(StrEnum):
|
|
UPLOADED = "uploaded"
|
|
REGION_SELECTION = "region_selection"
|
|
PLAN_REVIEW = "plan_review"
|
|
BLOCKOUT = "blockout"
|
|
STYLE_BRIEF = "style_brief"
|
|
DIRECTION_SELECTION = "direction_selection"
|
|
RENDER_REVIEW = "render_review"
|
|
EDITING = "editing"
|
|
COMPLETED = "completed"
|
|
FAILED = "failed"
|
|
|
|
|
|
class WorkflowCommand(StrEnum):
|
|
START_INGESTION = "start_ingestion"
|
|
SELECT_REGION = "select_region"
|
|
CONFIRM_PLAN = "confirm_plan"
|
|
BUILD_BLOCKOUT = "build_blockout"
|
|
SUBMIT_STYLE_BRIEF = "submit_style_brief"
|
|
SELECT_DIRECTION = "select_direction"
|
|
REQUEST_RENDER = "request_render"
|
|
APPLY_EDIT = "apply_edit"
|
|
COMPLETE_PROJECT = "complete_project"
|
|
RETRY = "retry"
|
|
|
|
|
|
class Point2D(BaseModel):
|
|
x: float
|
|
y: float
|
|
|
|
|
|
class PlanRegion(BaseModel):
|
|
id: str
|
|
name: str
|
|
bounds: list[float] = Field(min_length=4, max_length=4)
|
|
recommended: bool = False
|
|
confidence: float = Field(ge=0, le=1)
|
|
|
|
|
|
class PlanLayer(BaseModel):
|
|
id: str
|
|
label: str
|
|
category: str
|
|
visible: bool = True
|
|
source_names: list[str] = Field(default_factory=list)
|
|
element_count: int | None = None
|
|
|
|
|
|
class PlanIssue(BaseModel):
|
|
id: str
|
|
kind: str
|
|
message: str
|
|
confidence: float = Field(ge=0, le=1)
|
|
resolved: bool = False
|
|
|
|
|
|
class RoomProfile(BaseModel):
|
|
id: str
|
|
name: str
|
|
kind: str
|
|
area_sqm: float | None = None
|
|
confidence: float = Field(default=0.5, ge=0, le=1)
|
|
notes: str = ""
|
|
|
|
|
|
class StructureAnalysis(BaseModel):
|
|
status: str = "pending"
|
|
summary: str = ""
|
|
rooms: list[RoomProfile] = Field(default_factory=list)
|
|
circulation: str = ""
|
|
daylight: str = ""
|
|
layout_opportunities: list[str] = Field(default_factory=list)
|
|
risks: list[str] = Field(default_factory=list)
|
|
model_name: str = ""
|
|
degraded: bool = False
|
|
|
|
|
|
class PlanState(BaseModel):
|
|
source_name: str
|
|
source_kind: str
|
|
source_object_key: str | None = None
|
|
preview_object_key: str | None = None
|
|
preview_width: int | None = None
|
|
preview_height: int | None = None
|
|
page_count: int = 1
|
|
vector_based: bool = False
|
|
vector_element_count: int = 0
|
|
cad_layer_count: int = 0
|
|
ocr_used: bool = False
|
|
ocr_labels: list[str] = Field(default_factory=list)
|
|
ingestion_notes: list[str] = Field(default_factory=list)
|
|
regions: list[PlanRegion] = Field(default_factory=list)
|
|
selected_region_id: str | None = None
|
|
layers: list[PlanLayer] = Field(default_factory=list)
|
|
issues: list[PlanIssue] = Field(default_factory=list)
|
|
scale_mm_per_unit: float | None = None
|
|
ceiling_height_mm: int = 2800
|
|
gross_area_sqm: float | None = None
|
|
structure: StructureAnalysis = Field(default_factory=StructureAnalysis)
|
|
|
|
|
|
class CameraView(BaseModel):
|
|
id: str
|
|
label: str
|
|
room: str
|
|
status: str = "draft"
|
|
|
|
|
|
class SceneState(BaseModel):
|
|
blockout_asset_key: str | None = None
|
|
cameras: list[CameraView] = Field(default_factory=list)
|
|
locked_object_ids: list[str] = Field(default_factory=list)
|
|
furniture_mode: str = "preserve_reference"
|
|
|
|
|
|
class ColorToken(BaseModel):
|
|
name: str
|
|
hex: str
|
|
role: str
|
|
|
|
|
|
class StyleState(BaseModel):
|
|
concept: str = "克制、自然、明亮的现代住宅"
|
|
keywords: list[str] = Field(default_factory=lambda: ["轻盈", "自然材质", "留白"])
|
|
palette: list[ColorToken] = Field(default_factory=list)
|
|
materials: list[str] = Field(default_factory=list)
|
|
lighting: str = "低对比度的自然光与柔和间接照明"
|
|
forms: str = "低矮、水平延展、少量圆角"
|
|
density: str = "适度留白"
|
|
avoid: list[str] = Field(default_factory=list)
|
|
locked_decisions: list[str] = Field(default_factory=list)
|
|
selected_direction_id: str | None = None
|
|
|
|
|
|
class DesignBrief(BaseModel):
|
|
residents: str = ""
|
|
lifestyle: list[str] = Field(default_factory=list)
|
|
focus_rooms: list[str] = Field(default_factory=list)
|
|
preferred_styles: list[str] = Field(default_factory=list)
|
|
preferred_colors: list[str] = Field(default_factory=list)
|
|
disliked_elements: list[str] = Field(default_factory=list)
|
|
must_keep: list[str] = Field(default_factory=list)
|
|
budget_level: str = "适中"
|
|
additional_notes: str = ""
|
|
completed: bool = False
|
|
|
|
|
|
class StyleDirection(BaseModel):
|
|
id: str
|
|
name: str
|
|
thesis: str
|
|
keywords: list[str] = Field(default_factory=list)
|
|
palette: list[ColorToken] = Field(default_factory=list)
|
|
materials: list[str] = Field(default_factory=list)
|
|
lighting: str = ""
|
|
prompt: str = ""
|
|
model_name: str = ""
|
|
|
|
|
|
class RenderAsset(BaseModel):
|
|
id: str
|
|
direction_id: str
|
|
room: str
|
|
view: str
|
|
object_key: str
|
|
prompt: str
|
|
model_name: str
|
|
parent_id: str | None = None
|
|
edit_instruction: str = ""
|
|
created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
|
|
|
|
|
|
class ProjectEvent(BaseModel):
|
|
id: str
|
|
kind: str
|
|
message: str
|
|
created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
|
|
|
|
|
|
class ProjectSnapshot(BaseModel):
|
|
project_id: str
|
|
name: str
|
|
stage: WorkflowStage
|
|
revision: int = 1
|
|
plan: PlanState
|
|
scene: SceneState = Field(default_factory=SceneState)
|
|
style: StyleState = Field(default_factory=StyleState)
|
|
brief: DesignBrief = Field(default_factory=DesignBrief)
|
|
directions: list[StyleDirection] = Field(default_factory=list)
|
|
renders: list[RenderAsset] = Field(default_factory=list)
|
|
events: list[ProjectEvent] = Field(default_factory=list)
|
|
available_commands: list[WorkflowCommand] = Field(default_factory=list)
|
|
last_stable_stage: WorkflowStage | None = None
|
|
failure_reason: str | None = None
|
|
updated_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
|
|
|
|
|
|
class CommandRequest(BaseModel):
|
|
command: WorkflowCommand
|
|
expected_revision: int = Field(ge=1)
|
|
payload: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class WorkflowStageDefinition(BaseModel):
|
|
id: WorkflowStage
|
|
label: str
|
|
purpose: str
|
|
human_confirmation: bool
|
|
|
|
|
|
class WorkflowDefinition(BaseModel):
|
|
stages: list[WorkflowStageDefinition]
|
|
transitions: dict[str, list[str]]
|