from app.domain.models import ( CameraView, ColorToken, PlanIssue, PlanLayer, PlanRegion, PlanState, ProjectSnapshot, SceneState, StyleState, WorkflowStage, ) from app.domain.workflow import available_commands def create_demo_project() -> ProjectSnapshot: stage = WorkflowStage.PLAN_REVIEW project = ProjectSnapshot( project_id="demo-apartment", name="11-2-104 住宅概念方案", stage=stage, revision=3, plan=PlanState( source_name="11-2-104-模型.pdf", source_kind="vector_pdf", vector_based=True, cad_layer_count=43, regions=[ PlanRegion( id="residence-upper", name="上方住宅户型", bounds=[0.08, 0.05, 0.92, 0.58], recommended=True, confidence=0.97, ), PlanRegion( id="common-lower", name="下方公共区域", bounds=[0.12, 0.61, 0.88, 0.94], confidence=0.91, ), ], selected_region_id="residence-upper", layers=[ PlanLayer( id="architecture", label="建筑结构", category="structure", source_names=["A-墙线", "WALL", "S-COLUMN"], ), PlanLayer( id="openings", label="门窗", category="openings", source_names=["WINDOW", "A-普通门窗", "A-防火门窗"], ), PlanLayer( id="furniture", label="原家具", category="furniture", source_names=["FF-FURN", "C-Chen_活动家具"], ), PlanLayer( id="dimensions", label="尺寸标注", category="annotation", visible=False, source_names=["B-标注", "DIM_SYMB"], ), PlanLayer( id="labels", label="房间文字", category="annotation", visible=False, source_names=["A-房间名称文字", "W-文字"], ), ], issues=[ PlanIssue( id="scale-check", kind="scale", message="多个尺寸标注需要交叉确认比例", confidence=0.82, ), PlanIssue( id="furniture-intent", kind="intent", message="请确认原家具是保留布局、参考方案还是噪声", confidence=1, ), ], ceiling_height_mm=2800, ), scene=SceneState( cameras=[ CameraView(id="living-entry", label="客厅入口", room="客厅"), CameraView(id="living-diagonal", label="客厅对角", room="客厅"), CameraView(id="dining-focus", label="餐厨主景", room="餐厅"), ] ), style=StyleState( concept="温暖、克制、带自然材质感的现代住宅", keywords=["清透", "低饱和", "自然纹理", "松弛"], palette=[ ColorToken(name="雾白", hex="#E8E9E4", role="base"), ColorToken(name="浅橡木", hex="#B9A68A", role="secondary"), ColorToken(name="松针绿", hex="#50665C", role="accent"), ], materials=["哑光涂料", "浅橡木", "亚麻", "浅色洞石"], avoid=["大面积冷灰", "高亮岩板", "过量灯带"], locked_decisions=["保留主要窗洞", "不改变客餐厅关系"], ), ) project.available_commands = available_commands(stage) return project class InMemoryProjectRepository: def __init__(self) -> None: demo = create_demo_project() self._items = {demo.project_id: demo} def get(self, project_id: str) -> ProjectSnapshot | None: return self._items.get(project_id) def save(self, project: ProjectSnapshot) -> ProjectSnapshot: self._items[project.project_id] = project return project repository = InMemoryProjectRepository()