# app/models/schemas/node.py — Node Pydantic models from __future__ import annotations from typing import Literal from pydantic import BaseModel NodeStatus = Literal["pending", "generating", "ready", "error"] class NodeRow(BaseModel): id: str chain_id: str parent_id: str | None audio_path: str | None duration_s: float | None status: NodeStatus is_committed: bool prompt: str energy: float | None tempo_feel: float | None density: float | None cfg_coef: float prompt_duration_s: float error_msg: str | None created_at: float children: list["NodeRow"] = [] class BranchRequest(BaseModel): prompt: str = "" energy: float | None = None tempo_feel: float | None = None density: float | None = None cfg_coef: float = 3.0 prompt_duration_s: float = 10.0 duration_s: float = 15.0 class StemResult(BaseModel): node_id: str vocals: str drums: str bass: str other: str class ExportRequest(BaseModel): format: Literal["wav", "mp3"] = "wav" node_ids: list[str] | None = None # if None, use committed spine