Spaces:
Running on Zero
Running on Zero
| """ | |
| MCP Tool: run | |
| Unified image generation task submission and execution interface. | |
| """ | |
| import time | |
| import uuid | |
| from core.task_scheduler import QueueFullError, submit_background | |
| from core.runtime_config import CONFIG | |
| from .common import ( | |
| _load_yaml, | |
| _MODEL_LIST_PATH, | |
| _TASK_DEFINITIONS, | |
| _TASKS_DB, | |
| _TASKS_LOCK, | |
| _get_task_snapshot, | |
| _execute_imagegen_pipeline, | |
| ) | |
| from .error_schema import make_error, make_validation_error, make_not_found_error | |
| def handle_run(params: dict) -> dict: | |
| """Unified image generation task execution interface.""" | |
| if not isinstance(params, dict): | |
| return make_validation_error("Request params must be an object.") | |
| missing = [] | |
| for req_field in ["task_type", "model", "prompt"]: | |
| if req_field not in params or not params[req_field]: | |
| missing.append(req_field) | |
| if missing: | |
| return make_validation_error( | |
| f"Missing required parameter(s): {', '.join(missing)}", | |
| missing_fields=missing, | |
| ) | |
| task_type = params["task_type"] | |
| valid_tasks = [t["task_type"] for t in _TASK_DEFINITIONS] | |
| if task_type not in valid_tasks: | |
| return make_validation_error( | |
| f"Invalid task_type '{task_type}'. Must be one of {valid_tasks}.", | |
| invalid_fields={"task_type": f"Must be in {valid_tasks}"}, | |
| ) | |
| model_list = _load_yaml(_MODEL_LIST_PATH) | |
| checkpoints = model_list.get("Checkpoint", {}) | |
| all_models = set() | |
| for arch_name, arch_data in checkpoints.items(): | |
| if isinstance(arch_data, dict): | |
| for m in arch_data.get("models", []): | |
| all_models.add(m.get("display_name")) | |
| if params["model"] not in all_models: | |
| return make_not_found_error("model", params["model"]) | |
| task_requirements = { | |
| "txt2img": ("width", "height"), | |
| "img2img": ("image",), | |
| "inpaint": ("image",), | |
| "outpaint": ("image", "pad_left", "pad_right", "pad_top", "pad_bottom"), | |
| "hires_fix": ("image", "upscale_by"), | |
| } | |
| missing_task_fields = [ | |
| field | |
| for field in task_requirements.get(task_type, ()) | |
| if field not in params or params[field] is None or params[field] == "" | |
| ] | |
| if missing_task_fields: | |
| return make_validation_error( | |
| f"Missing required parameter(s) for {task_type}: {', '.join(missing_task_fields)}", | |
| missing_fields=missing_task_fields, | |
| ) | |
| try: | |
| batch_size = int(params.get("batch_size", 1)) | |
| except (TypeError, ValueError): | |
| batch_size = 0 | |
| if not 1 <= batch_size <= CONFIG.max_batch_size: | |
| return make_validation_error( | |
| f"batch_size must be between 1 and {CONFIG.max_batch_size}.", | |
| invalid_fields={"batch_size": f"Expected 1..{CONFIG.max_batch_size}"}, | |
| ) | |
| with _TASKS_LOCK: | |
| if len(_TASKS_DB) >= CONFIG.mcp_task_retention: | |
| finished = sorted( | |
| ( | |
| (old_task_id, task) | |
| for old_task_id, task in _TASKS_DB.items() | |
| if task.get("status") in {"completed", "failed"} | |
| ), | |
| key=lambda pair: pair[1].get("completed_at", pair[1].get("failed_at", 0)), | |
| ) | |
| remove_count = max(1, len(_TASKS_DB) - CONFIG.mcp_task_retention + 1) | |
| for old_task_id, _ in finished[:remove_count]: | |
| _TASKS_DB.pop(old_task_id, None) | |
| if len(_TASKS_DB) >= CONFIG.mcp_task_retention: | |
| return make_error( | |
| "QUEUE_FULL", | |
| "任务记录已满且当前任务均未结束,请稍后再试。", | |
| ) | |
| task_id = f"img_task_{uuid.uuid4().hex[:10]}" | |
| created_at = int(time.time()) | |
| _TASKS_DB[task_id] = { | |
| "task_id": task_id, | |
| "status": "queued", | |
| "progress": 0, | |
| "created_at": created_at, | |
| } | |
| async_exec = params.get("async_execution", False) | |
| if async_exec: | |
| try: | |
| submit_background(_execute_imagegen_pipeline, task_id, params) | |
| except QueueFullError as exc: | |
| with _TASKS_LOCK: | |
| _TASKS_DB.pop(task_id, None) | |
| return make_error("QUEUE_FULL", str(exc)) | |
| return { | |
| "status": "queued", | |
| "task_id": task_id, | |
| "poll_interval_ms": 2000, | |
| "message": "Task queued successfully. Poll get_task_status for results.", | |
| } | |
| else: | |
| _execute_imagegen_pipeline(task_id, params) | |
| return _get_task_snapshot(task_id) | |