feat(vision): il grafo vive sul task, la quota nomina la sua uscita

This commit is contained in:
2026-08-16 17:10:20 +02:00
parent cb0fab8c92
commit b578ac9e1b
4 changed files with 143 additions and 1 deletions
+6
View File
@@ -21,6 +21,7 @@ class SubtaskCreate(BaseModel):
ltl: Optional[float] = None
unit: str = Field("mm", max_length=20)
image_path: Optional[str] = Field(None, max_length=500)
vision_output: Optional[str] = None
class SubtaskUpdate(BaseModel):
@@ -35,6 +36,7 @@ class SubtaskUpdate(BaseModel):
ltl: Optional[float] = None
unit: Optional[str] = Field(None, max_length=20)
image_path: Optional[str] = Field(None, max_length=500)
vision_output: Optional[str] = None
class SubtaskResponse(BaseModel):
@@ -53,6 +55,7 @@ class SubtaskResponse(BaseModel):
ltl: Optional[float] = None
unit: str
image_path: Optional[str] = None
vision_output: Optional[str] = None
class TaskCreate(BaseModel):
@@ -64,6 +67,7 @@ class TaskCreate(BaseModel):
file_path: Optional[str] = Field(None, max_length=500)
file_type: Optional[str] = Field(None, pattern="^(image|pdf)$")
annotations_json: Optional[dict[str, Any]] = None
vision_json: Optional[dict] = None
subtasks: list[SubtaskCreate] = []
@@ -76,6 +80,7 @@ class TaskUpdate(BaseModel):
file_path: Optional[str] = Field(None, max_length=500)
file_type: Optional[str] = Field(None, pattern="^(image|pdf)$")
annotations_json: Optional[dict[str, Any]] = None
vision_json: Optional[dict] = None
class TaskResponse(BaseModel):
@@ -93,6 +98,7 @@ class TaskResponse(BaseModel):
file_path: Optional[str] = None
file_type: Optional[str] = None
annotations_json: Optional[dict[str, Any]] = None
vision_json: Optional[dict] = None
subtasks: list[SubtaskResponse] = []
+11 -1
View File
@@ -15,7 +15,7 @@ if TYPE_CHECKING:
# What a task is, declared by whoever writes the recipe instead of guessed from its
# contents. The last two are not built yet; they are in the enum from the start
# because widening a MySQL enum later is an ALTER on a live table.
TASK_TYPES = ("note", "measure", "drawing", "xf_compare", "camera_measure")
TASK_TYPES = ("note", "measure", "drawing", "dxf_compare", "camera_measure")
# Types the operator screen treats as "there are quotes to take here".
MEASURING_TASK_TYPES = ("measure", "camera_measure")
@@ -47,6 +47,10 @@ class RecipeTask(Base):
Enum("image", "pdf", name="file_type_enum"), nullable=True
)
annotations_json: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
# The vision graph, serialised by vs-task. Opaque here on purpose: the
# server routes it and never interprets it, which is what keeps VisionSuite
# out of this container.
vision_json: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
# Relationships
version: Mapped["RecipeVersion"] = relationship(back_populates="tasks")
@@ -89,6 +93,12 @@ class RecipeSubtask(Base):
unit: Mapped[str] = mapped_column(String(20), nullable=False, default="mm")
image_path: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)
# Which output of the vision graph fills this quote: "<tool_id>.<output>".
# A link is an id, not a pointer - the same rule vs-task follows, and for
# the same reason: a pointer does not survive being written to disk.
vision_output: Mapped[Optional[str]] = mapped_column(
String(120), nullable=True
)
# Relationships
task: Mapped["RecipeTask"] = relationship(back_populates="subtasks")