Merge pull request #57 from HuangYuChuh/feat/comfyui-import-preview-api

feat(api): preview ComfyUI workflow imports before sync
This commit is contained in:
科林 KELIN
2026-03-22 21:01:58 +08:00
committed by GitHub
3 changed files with 104 additions and 0 deletions
+10
View File
@@ -302,6 +302,16 @@ def create_app() -> FastAPI:
except (RuntimeError, ValueError) as e:
raise HTTPException(status_code=400, detail=str(e)) from e
@app.get("/api/servers/{server_id}/workflows/import/comfyui/preview")
async def preview_workflows_from_comfyui(server_id: str) -> dict:
try:
preview = service.preview_workflows_from_comfyui(server_id)
return {"status": "success", "preview": preview}
except FileNotFoundError as e:
raise HTTPException(status_code=404, detail=str(e)) from e
except (RuntimeError, ValueError) as e:
raise HTTPException(status_code=400, detail=str(e)) from e
@app.post("/api/servers/{server_id}/workflows/import/local")
async def import_local_workflows(server_id: str, data: LocalWorkflowImportModel) -> dict:
try:
+4
View File
@@ -415,6 +415,10 @@ class UIStorageService:
importer = WorkflowBulkImporter(self, server_id)
return importer.import_from_comfyui().to_dict()
def preview_workflows_from_comfyui(self, server_id: str) -> dict[str, Any]:
importer = WorkflowBulkImporter(self, server_id)
return importer.preview_from_comfyui().to_dict()
def import_local_workflows(self, server_id: str, files: list[dict[str, str]]) -> dict[str, Any]:
importer = WorkflowBulkImporter(self, server_id)
return importer.import_local_files(files).to_dict()
+90
View File
@@ -73,6 +73,44 @@ class BulkImportReport:
}
@dataclass(slots=True)
class BulkImportPreviewItem:
workflow_id: str
final_workflow_id: str
source_label: str
description: str
status: str
reason: str = ""
def to_dict(self) -> dict[str, Any]:
return {
"workflow_id": self.workflow_id,
"final_workflow_id": self.final_workflow_id,
"source_label": self.source_label,
"description": self.description,
"status": self.status,
"reason": self.reason,
}
@dataclass(slots=True)
class BulkImportPreviewReport:
items: list[BulkImportPreviewItem] = field(default_factory=list)
def to_dict(self) -> dict[str, Any]:
summary = {
"ready": sum(1 for item in self.items if item.status == "ready"),
"renamed": sum(1 for item in self.items if item.status == "renamed"),
"failed": sum(1 for item in self.items if item.status == "failed"),
"importable": sum(1 for item in self.items if item.status in {"ready", "renamed"}),
"total": len(self.items),
}
return {
"summary": summary,
"items": [item.to_dict() for item in self.items],
}
class WorkflowBulkImporter:
def __init__(self, service: UIStorageService, server_id: str):
self.service = service
@@ -139,6 +177,30 @@ class WorkflowBulkImporter:
return report
def preview_from_comfyui(self) -> BulkImportPreviewReport:
api = self._build_server_api()
workflow_paths = api.list_workflow_paths()
report = BulkImportPreviewReport()
reserved_ids: set[str] = set()
for workflow_path in workflow_paths:
try:
workflow_data = api.read_workflow_json(workflow_path)
except ComfyUIClientError as exc:
report.items.append(BulkImportPreviewItem("", "", workflow_path, "", "failed", str(exc)))
continue
report.items.append(
self._preview_one(
workflow_data=workflow_data,
source_label=workflow_path,
reserved_ids=reserved_ids,
file_name=PurePosixPath(workflow_path).name,
),
)
return report
def _import_one(
self,
workflow_data: Any,
@@ -167,6 +229,32 @@ class WorkflowBulkImporter:
except (WorkflowImportError, FileExistsError, ValueError) as exc:
return BulkImportItem("", "", source_label, "failed", str(exc))
def _preview_one(
self,
workflow_data: Any,
source_label: str,
reserved_ids: set[str],
file_name: str = "",
) -> BulkImportPreviewItem:
if not isinstance(workflow_data, dict):
return BulkImportPreviewItem("", "", source_label, "", "failed", "Workflow JSON must be an object.")
try:
normalized_workflow = self._normalize_workflow_payload(workflow_data)
suggested_id = suggest_workflow_id(normalized_workflow, file_name)
final_workflow_id = self.service.next_available_workflow_id(self.server_id, suggested_id, reserved_ids)
reserved_ids.add(final_workflow_id)
status = "ready" if final_workflow_id == suggested_id else "renamed"
return BulkImportPreviewItem(
suggested_id,
final_workflow_id,
source_label,
self._suggest_description(workflow_data, normalized_workflow, source_label),
status,
)
except (WorkflowImportError, FileExistsError, ValueError) as exc:
return BulkImportPreviewItem("", "", source_label, "", "failed", str(exc))
def _save_imported_workflow(
self,
original_workflow: dict[str, Any],
@@ -254,6 +342,8 @@ class WorkflowBulkImporter:
__all__ = [
"BulkImportItem",
"BulkImportPreviewItem",
"BulkImportPreviewReport",
"BulkImportReport",
"ComfyUIClientError",
"ComfyUIServerAPI",