Files

237 lines
9.6 KiB
Python

from .file_handler import FileHandler
import json
from pathlib import Path
from .logger import is_backend_logging_enabled, log, set_backend_logging_enabled
class WorkflowManager:
"""工作流管理器 - 单例模式"""
_instance = None
_initialized = False
def __new__(cls, base_path=None):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self, base_path=None):
# 防止重复初始化
if self._initialized:
return
if base_path is None:
raise ValueError("base_path required on first initialization")
self._load_config()
self.file_handler = FileHandler(
base_path,
auto_backup_enabled=self.auto_backup_enabled,
max_auto_backups=self.max_auto_backups,
latest_backup_enabled=self.latest_backup_enabled,
)
WorkflowManager._initialized = True
@staticmethod
def _read_config_file():
config_file = Path(__file__).parent / "config.json"
if not config_file.exists():
return {}
return json.loads(config_file.read_text(encoding="utf-8"))
@classmethod
def resolve_data_path(cls, comfyui_path):
config = cls._read_config_file()
data_dir = config.get("data_dir", "yeban-workflows") or "yeban-workflows"
data_path = Path(data_dir).expanduser()
if not data_path.is_absolute():
data_path = Path(comfyui_path) / data_path
return data_path
def _load_config(self):
"""从 config.json 加载配置"""
try:
config = self._read_config_file()
self.data_dir = config.get("data_dir", "yeban-workflows")
self.auto_save_interval = config.get("auto_save_interval", 60)
self.max_versions = config.get("max_versions", 20)
self.auto_backup_enabled = config.get("auto_backup_enabled", True)
self.max_auto_backups = config.get("max_auto_backups", 50)
self.latest_backup_enabled = config.get("latest_backup_enabled", True)
log(f"[yeban-WM] \u914d\u7f6e\u5df2\u52a0\u8f7d: \u81ea\u52a8\u4fdd\u5b58\u95f4\u9694={self.auto_save_interval}\u79d2, \u6700\u5927\u7248\u672c\u6570={self.max_versions}, \u81ea\u52a8\u5907\u4efd\u6570={self.max_auto_backups}, \u6700\u65b0\u5907\u4efd={self.latest_backup_enabled}")
except Exception as e:
log(f"[yeban-WM] \u52a0\u8f7d\u914d\u7f6e\u5931\u8d25: {e}")
self.data_dir = "yeban-workflows"
self.auto_save_interval = 60
self.max_versions = 20
self.auto_backup_enabled = True
self.max_auto_backups = 50
self.latest_backup_enabled = True
@classmethod
def reset(cls):
"""重置单例(用于测试或重载)"""
cls._instance = None
cls._initialized = False
# ── groups ────────────────────────────────────────────────────────────────
def create_group(self, name, parent_id=None):
"""创建分组"""
if not name or not isinstance(name, str):
raise ValueError("Group name must be non-empty string")
name = name.strip()
return self.file_handler.create_group(name, parent_id)
def delete_group(self, group_id):
"""删除分组"""
return self.file_handler.delete_group(group_id)
def rename_group(self, group_id, new_name):
"""重命名分组"""
if not new_name or not isinstance(new_name, str):
raise ValueError("Group name must be non-empty string")
new_name = new_name.strip()
return self.file_handler.rename_group(group_id, new_name)
# ── workflows ─────────────────────────────────────────────────────────────
def save_workflow(self, data, name, group_id=None):
"""保存工作流"""
if not name or not isinstance(name, str):
raise ValueError("Workflow name must be non-empty string")
name = name.strip()
if not isinstance(data, dict):
raise ValueError("Workflow data must be a dict")
return self.file_handler.save_workflow(data, name, group_id)
def load_workflow(self, wf_id):
"""加载工作流"""
if not wf_id:
raise ValueError("Workflow ID required")
return self.file_handler.load_workflow(wf_id)
def delete_workflow(self, wf_id):
"""删除工作流"""
if not wf_id:
raise ValueError("Workflow ID required")
return self.file_handler.delete_workflow(wf_id)
def rename_workflow(self, wf_id, new_name):
"""重命名工作流"""
if not wf_id:
raise ValueError("Workflow ID required")
if not new_name or not isinstance(new_name, str):
raise ValueError("New name must be non-empty string")
new_name = new_name.strip()
return self.file_handler.rename_workflow(wf_id, new_name)
def move_workflow(self, wf_id, target_group_id):
"""移动工作流到其他分组"""
if not wf_id:
raise ValueError("Workflow ID required")
return self.file_handler.move_workflow(wf_id, target_group_id)
def copy_workflow(self, wf_id, target_group_id, new_name=None):
"""复制工作流"""
if not wf_id:
raise ValueError("Workflow ID required")
if new_name:
new_name = new_name.strip()
return self.file_handler.copy_workflow(wf_id, target_group_id, new_name)
# ── thumbnail ─────────────────────────────────────────────────────────────
def save_thumbnail(self, wf_id, data_url):
"""保存缩略图"""
if not wf_id:
raise ValueError("Workflow ID required")
if not data_url:
raise ValueError("Data URL required")
return self.file_handler.save_thumbnail(wf_id, data_url)
def get_thumbnail_path(self, wf_id):
"""获取缩略图路径"""
if not wf_id:
raise ValueError("Workflow ID required")
return self.file_handler.get_thumbnail_path(wf_id)
# ── version history ───────────────────────────────────────────────────────
def save_version(self, wf_id):
"""创建版本快照"""
if not wf_id:
raise ValueError("Workflow ID required")
return self.file_handler.save_version(wf_id, self.max_versions)
def list_versions(self, wf_id):
"""列出所有版本"""
if not wf_id:
raise ValueError("Workflow ID required")
return self.file_handler.list_versions(wf_id)
def restore_version(self, wf_id, version_filename):
"""恢复到指定版本"""
if not wf_id:
raise ValueError("Workflow ID required")
if not version_filename:
raise ValueError("Version filename required")
return self.file_handler.restore_version(wf_id, version_filename)
# ── misc ──────────────────────────────────────────────────────────────────
def search_workflows(self, query):
"""搜索工作流"""
if not isinstance(query, str):
query = ""
return self.file_handler.search_workflows(query)
def get_all_workflows(self):
"""获取所有工作流元数据"""
return self.file_handler.get_all_workflows()
def get_all_groups(self):
"""获取所有分组"""
return self.file_handler.get_all_groups()
def backup_workflow(self, wf_id):
"""备份工作流"""
if not wf_id:
raise ValueError("Workflow ID required")
return self.file_handler.backup_workflow(wf_id)
def import_workflow(self, import_path, workflow_name, group_id=None):
"""导入工作流"""
if not import_path:
raise ValueError("Import path required")
if not workflow_name or not isinstance(workflow_name, str):
raise ValueError("Workflow name must be non-empty string")
workflow_name = workflow_name.strip()
return self.file_handler.import_workflow(import_path, workflow_name, group_id)
def toggle_star(self, wf_id):
"""收藏/取消收藏工作流"""
if not wf_id:
raise ValueError("Workflow ID required")
return self.file_handler.toggle_star(wf_id)
def update_tags(self, wf_id, tags):
"""更新工作流标签"""
if not wf_id:
raise ValueError("Workflow ID required")
if not isinstance(tags, list):
tags = []
tags = [str(t).strip() for t in tags if str(t).strip()]
return self.file_handler.update_tags(wf_id, tags)
def get_settings(self):
return {
"backend_logging_enabled": is_backend_logging_enabled(),
}
def update_settings(self, backend_logging_enabled=None):
if backend_logging_enabled is not None:
if isinstance(backend_logging_enabled, str):
backend_logging_enabled = backend_logging_enabled.strip().lower() not in {"0", "false", "no", "off"}
set_backend_logging_enabled(bool(backend_logging_enabled))
return self.get_settings()