diff --git a/development/cloud/api-reference.mdx b/development/cloud/api-reference.mdx index 251d9710c..203af1861 100644 --- a/development/cloud/api-reference.mdx +++ b/development/cloud/api-reference.mdx @@ -446,6 +446,196 @@ workflow = set_workflow_input(workflow, "6", "text", "a beautiful landscape") --- +## Jobs API + +The Jobs API provides efficient endpoints for listing and retrieving job details. Use these endpoints instead of the legacy `/history` and `/queue` endpoints for better performance and richer filtering options. + +### List Jobs + +Retrieve a paginated list of jobs with optional filtering by status, workflow ID, or output type. + + +```bash curl +# List all jobs (most recent first) +curl -X GET "$BASE_URL/api/jobs" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" + +# Filter by status +curl -X GET "$BASE_URL/api/jobs?status=completed" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" + +# Filter by output type and sort by execution time +curl -X GET "$BASE_URL/api/jobs?output_type=image&sort_by=execution_time&sort_order=desc" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" +``` + +```typescript TypeScript +interface JobEntry { + id: string; + status: "pending" | "in_progress" | "completed" | "failed" | "cancelled"; + create_time: number; + preview_output?: Record; + outputs_count?: number; + workflow_id?: string; + execution_start_time?: number; + execution_end_time?: number; +} + +interface JobsListResponse { + jobs: JobEntry[]; + pagination: { + offset: number; + limit: number; + total: number; + has_more: boolean; + }; +} + +async function listJobs(options: { + status?: string; + output_type?: "image" | "video" | "audio"; + sort_by?: "create_time" | "execution_time"; + sort_order?: "asc" | "desc"; + offset?: number; + limit?: number; +} = {}): Promise { + const params = new URLSearchParams(); + if (options.status) params.set("status", options.status); + if (options.output_type) params.set("output_type", options.output_type); + if (options.sort_by) params.set("sort_by", options.sort_by); + if (options.sort_order) params.set("sort_order", options.sort_order); + if (options.offset !== undefined) params.set("offset", String(options.offset)); + if (options.limit !== undefined) params.set("limit", String(options.limit)); + + const response = await fetch(`${BASE_URL}/api/jobs?${params}`, { + headers: getHeaders(), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); +} + +// List recent completed jobs +const { jobs, pagination } = await listJobs({ status: "completed", limit: 10 }); +console.log(`Found ${pagination.total} completed jobs`); +``` + +```python Python +def list_jobs( + status: str = None, + output_type: str = None, + sort_by: str = "create_time", + sort_order: str = "desc", + offset: int = 0, + limit: int = 100 +) -> dict: + """List jobs with optional filtering. + + Args: + status: Filter by status (pending, in_progress, completed, failed, cancelled) + output_type: Filter by output type (image, video, audio) + sort_by: Sort field (create_time or execution_time) + sort_order: Sort direction (asc or desc) + offset: Pagination offset + limit: Max items per page (1-1000) + + Returns: + Dict with 'jobs' array and 'pagination' info + """ + params = { + "sort_by": sort_by, + "sort_order": sort_order, + "offset": offset, + "limit": limit + } + if status: + params["status"] = status + if output_type: + params["output_type"] = output_type + + response = requests.get( + f"{BASE_URL}/api/jobs", + headers=get_headers(), + params=params + ) + response.raise_for_status() + return response.json() + +# List recent completed jobs +result = list_jobs(status="completed", limit=10) +print(f"Found {result['pagination']['total']} completed jobs") +``` + + +### Get Job Details + +Retrieve complete details for a specific job including the workflow and full outputs. + + +```bash curl +curl -X GET "$BASE_URL/api/jobs/{job_id}" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" +``` + +```typescript TypeScript +interface JobDetailResponse { + id: string; + status: "pending" | "in_progress" | "completed" | "failed" | "cancelled"; + workflow?: Record; + outputs?: Record; + preview_output?: Record; + outputs_count?: number; + create_time: number; + update_time: number; + workflow_id?: string; + execution_status?: Record; + execution_meta?: Record; +} + +async function getJobDetails(jobId: string): Promise { + const response = await fetch(`${BASE_URL}/api/jobs/${jobId}`, { + headers: getHeaders(), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); +} + +// Get full job details including outputs +const job = await getJobDetails(promptId); +if (job.status === "completed" && job.outputs) { + console.log(`Job has ${job.outputs_count} outputs`); +} +``` + +```python Python +def get_job_details(job_id: str) -> dict: + """Get complete job details including workflow and outputs. + + Args: + job_id: The job/prompt ID + + Returns: + Full job details including workflow and outputs + """ + response = requests.get( + f"{BASE_URL}/api/jobs/{job_id}", + headers=get_headers() + ) + response.raise_for_status() + return response.json() + +# Get full job details including outputs +job = get_job_details(prompt_id) +if job["status"] == "completed" and job.get("outputs"): + print(f"Job has {job.get('outputs_count', 0)} outputs") +``` + + + + **Legacy Endpoints:** The `/api/history`, `/api/history_v2`, and `/api/queue` endpoints are maintained for compatibility with local ComfyUI but the Jobs API is recommended for new integrations. + + +--- + ## Checking Job Status Poll for job completion. diff --git a/development/comfyui-server/comms_routes.mdx b/development/comfyui-server/comms_routes.mdx index 92b8a1e41..200ffd99d 100644 --- a/development/comfyui-server/comms_routes.mdx +++ b/development/comfyui-server/comms_routes.mdx @@ -35,10 +35,12 @@ The prompt queue is defined in `execution.py`, which also defines the `PromptExe | `/prompt` | post | submit a prompt to the queue | | `/object_info` | get | retrieve details of all node types | | `/object_info/{node_class}` | get | retrieve details of one node type | -| `/history` | get | retrieve the queue history | -| `/history/{prompt_id}` | get | retrieve the queue history for a specific prompt | +| `/jobs` | get | list jobs with filtering, sorting, and pagination (recommended) | +| `/jobs/{job_id}` | get | get full details for a specific job (recommended) | +| `/history` | get | retrieve the queue history (legacy) | +| `/history/{prompt_id}` | get | retrieve the queue history for a specific prompt (legacy) | | `/history` | post | clear history or delete history item | -| `/queue` | get | retrieve the current state of the execution queue | +| `/queue` | get | retrieve the current state of the execution queue (legacy) | | `/queue` | post | manage queue operations (clear pending/running) | | `/interrupt` | post | stop the current workflow execution | | `/free` | post | free memory by unloading specified models | @@ -51,6 +53,71 @@ The prompt queue is defined in `execution.py`, which also defines the `PromptExe | `/users` | get | get user information | | `/users` | post | create a new user (multi-user mode only) | +### Jobs API + +The Jobs API (`/jobs`) provides a unified interface for listing and retrieving job information with filtering, sorting, and pagination. It is the recommended way to query job status and history. + +#### List Jobs + +`GET /jobs` returns a paginated list of jobs with optional filtering: + +| Parameter | Type | Description | +|-----------|------|-------------| +| `status` | string | Filter by status (comma-separated): `pending`, `in_progress`, `completed`, `failed`, `cancelled` | +| `workflow_id` | string | Filter by workflow ID | +| `sort_by` | string | Sort field: `created_at` (default), `execution_duration` | +| `sort_order` | string | Sort direction: `asc`, `desc` (default) | +| `limit` | integer | Maximum items to return | +| `offset` | integer | Items to skip (default: 0) | + +**Response:** +```json +{ + "jobs": [ + { + "id": "prompt-uuid", + "status": "completed", + "create_time": 1706540000, + "workflow_id": "workflow-uuid", + "outputs_count": 2, + "preview_output": {"filename": "output.png", "type": "output"}, + "execution_start_time": 1706540001000, + "execution_end_time": 1706540005000 + } + ], + "pagination": { + "offset": 0, + "limit": 100, + "total": 42, + "has_more": false + } +} +``` + +#### Get Job Details + +`GET /jobs/{job_id}` returns full details for a specific job including outputs and workflow: + +```json +{ + "id": "prompt-uuid", + "status": "completed", + "create_time": 1706540000, + "outputs": { + "9": {"images": [{"filename": "output.png", "type": "output"}]} + }, + "workflow": { + "prompt": {...}, + "extra_data": {...} + }, + "execution_status": {...} +} +``` + + +The Jobs API consolidates data from the queue and history into a single unified format. Use `/jobs` instead of separately querying `/queue` and `/history` endpoints. + + ### WebSocket Communication The `/ws` endpoint provides real-time bidirectional communication between the client and server. This is used for: diff --git a/snippets/cloud/complete-example.mdx b/snippets/cloud/complete-example.mdx index 3d9095d7f..4f740d559 100644 --- a/snippets/cloud/complete-example.mdx +++ b/snippets/cloud/complete-example.mdx @@ -34,12 +34,12 @@ async function main() { await new Promise((resolve) => setTimeout(resolve, 2000)); } - // 4. Get outputs via history endpoint - const historyRes = await fetch(`${BASE_URL}/api/history_v2/${prompt_id}`, { + // 4. Get outputs via Jobs API + const jobRes = await fetch(`${BASE_URL}/api/jobs/${prompt_id}`, { headers: { "X-API-Key": API_KEY }, }); - const history = await historyRes.json(); - const outputs = history.outputs; + const job = await jobRes.json(); + const outputs = job.outputs; // 5. Download output files for (const nodeOutputs of Object.values(outputs)) { @@ -104,13 +104,13 @@ def main(): raise RuntimeError(f"Job {status}") time.sleep(2) - # 4. Get outputs via history endpoint - history_res = requests.get( - f"{BASE_URL}/api/history_v2/{prompt_id}", + # 4. Get outputs via Jobs API + job_res = requests.get( + f"{BASE_URL}/api/jobs/{prompt_id}", headers={"X-API-Key": API_KEY} ) - history = history_res.json() - outputs = history["outputs"] + job = job_res.json() + outputs = job["outputs"] # 5. Download output files for node_outputs in outputs.values(): diff --git a/snippets/zh/cloud/complete-example.mdx b/snippets/zh/cloud/complete-example.mdx index 323f7dce4..c7d70a6f1 100644 --- a/snippets/zh/cloud/complete-example.mdx +++ b/snippets/zh/cloud/complete-example.mdx @@ -34,12 +34,12 @@ async function main() { await new Promise((resolve) => setTimeout(resolve, 2000)); } - // 4. 通过历史端点获取输出 - const historyRes = await fetch(`${BASE_URL}/api/history_v2/${prompt_id}`, { + // 4. 通过 Jobs API 获取输出 + const jobRes = await fetch(`${BASE_URL}/api/jobs/${prompt_id}`, { headers: { "X-API-Key": API_KEY }, }); - const history = await historyRes.json(); - const outputs = history.outputs; + const job = await jobRes.json(); + const outputs = job.outputs; // 5. 下载输出文件 for (const nodeOutputs of Object.values(outputs)) { @@ -104,13 +104,13 @@ def main(): raise RuntimeError(f"任务 {status}") time.sleep(2) - # 4. 通过历史端点获取输出 - history_res = requests.get( - f"{BASE_URL}/api/history_v2/{prompt_id}", + # 4. 通过 Jobs API 获取输出 + job_res = requests.get( + f"{BASE_URL}/api/jobs/{prompt_id}", headers={"X-API-Key": API_KEY} ) - history = history_res.json() - outputs = history["outputs"] + job = job_res.json() + outputs = job["outputs"] # 5. 下载输出文件 for node_outputs in outputs.values(): diff --git a/zh-CN/development/cloud/api-reference.mdx b/zh-CN/development/cloud/api-reference.mdx index f8e69347f..c1b9b5d18 100644 --- a/zh-CN/development/cloud/api-reference.mdx +++ b/zh-CN/development/cloud/api-reference.mdx @@ -446,6 +446,196 @@ workflow = set_workflow_input(workflow, "6", "text", "a beautiful landscape") --- +## Jobs API + +Jobs API 提供了高效的端点来列出和检索任务详情。推荐使用这些端点代替旧版的 `/history` 和 `/queue` 端点,以获得更好的性能和更丰富的过滤选项。 + +### 列出任务 + +获取分页的任务列表,支持按状态、工作流 ID 或输出类型进行可选过滤。 + + +```bash curl +# 列出所有任务(最新的在前) +curl -X GET "$BASE_URL/api/jobs" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" + +# 按状态过滤 +curl -X GET "$BASE_URL/api/jobs?status=completed" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" + +# 按输出类型过滤并按执行时间排序 +curl -X GET "$BASE_URL/api/jobs?output_type=image&sort_by=execution_time&sort_order=desc" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" +``` + +```typescript TypeScript +interface JobEntry { + id: string; + status: "pending" | "in_progress" | "completed" | "failed" | "cancelled"; + create_time: number; + preview_output?: Record; + outputs_count?: number; + workflow_id?: string; + execution_start_time?: number; + execution_end_time?: number; +} + +interface JobsListResponse { + jobs: JobEntry[]; + pagination: { + offset: number; + limit: number; + total: number; + has_more: boolean; + }; +} + +async function listJobs(options: { + status?: string; + output_type?: "image" | "video" | "audio"; + sort_by?: "create_time" | "execution_time"; + sort_order?: "asc" | "desc"; + offset?: number; + limit?: number; +} = {}): Promise { + const params = new URLSearchParams(); + if (options.status) params.set("status", options.status); + if (options.output_type) params.set("output_type", options.output_type); + if (options.sort_by) params.set("sort_by", options.sort_by); + if (options.sort_order) params.set("sort_order", options.sort_order); + if (options.offset !== undefined) params.set("offset", String(options.offset)); + if (options.limit !== undefined) params.set("limit", String(options.limit)); + + const response = await fetch(`${BASE_URL}/api/jobs?${params}`, { + headers: getHeaders(), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); +} + +// 列出最近完成的任务 +const { jobs, pagination } = await listJobs({ status: "completed", limit: 10 }); +console.log(`Found ${pagination.total} completed jobs`); +``` + +```python Python +def list_jobs( + status: str = None, + output_type: str = None, + sort_by: str = "create_time", + sort_order: str = "desc", + offset: int = 0, + limit: int = 100 +) -> dict: + """列出任务,支持可选过滤。 + + Args: + status: 按状态过滤(pending, in_progress, completed, failed, cancelled) + output_type: 按输出类型过滤(image, video, audio) + sort_by: 排序字段(create_time 或 execution_time) + sort_order: 排序方向(asc 或 desc) + offset: 分页偏移量 + limit: 每页最大条目数(1-1000) + + Returns: + 包含 'jobs' 数组和 'pagination' 信息的字典 + """ + params = { + "sort_by": sort_by, + "sort_order": sort_order, + "offset": offset, + "limit": limit + } + if status: + params["status"] = status + if output_type: + params["output_type"] = output_type + + response = requests.get( + f"{BASE_URL}/api/jobs", + headers=get_headers(), + params=params + ) + response.raise_for_status() + return response.json() + +# 列出最近完成的任务 +result = list_jobs(status="completed", limit=10) +print(f"Found {result['pagination']['total']} completed jobs") +``` + + +### 获取任务详情 + +获取特定任务的完整详情,包括工作流和完整输出。 + + +```bash curl +curl -X GET "$BASE_URL/api/jobs/{job_id}" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" +``` + +```typescript TypeScript +interface JobDetailResponse { + id: string; + status: "pending" | "in_progress" | "completed" | "failed" | "cancelled"; + workflow?: Record; + outputs?: Record; + preview_output?: Record; + outputs_count?: number; + create_time: number; + update_time: number; + workflow_id?: string; + execution_status?: Record; + execution_meta?: Record; +} + +async function getJobDetails(jobId: string): Promise { + const response = await fetch(`${BASE_URL}/api/jobs/${jobId}`, { + headers: getHeaders(), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); +} + +// 获取完整任务详情,包括输出 +const job = await getJobDetails(promptId); +if (job.status === "completed" && job.outputs) { + console.log(`Job has ${job.outputs_count} outputs`); +} +``` + +```python Python +def get_job_details(job_id: str) -> dict: + """获取完整任务详情,包括工作流和输出。 + + Args: + job_id: 任务/prompt ID + + Returns: + 完整任务详情,包括工作流和输出 + """ + response = requests.get( + f"{BASE_URL}/api/jobs/{job_id}", + headers=get_headers() + ) + response.raise_for_status() + return response.json() + +# 获取完整任务详情,包括输出 +job = get_job_details(prompt_id) +if job["status"] == "completed" and job.get("outputs"): + print(f"Job has {job.get('outputs_count', 0)} outputs") +``` + + + + **旧版端点:** `/api/history`、`/api/history_v2` 和 `/api/queue` 端点为兼容本地 ComfyUI 而保留,但推荐在新集成中使用 Jobs API。 + + +--- + ## 检查任务状态 轮询任务完成状态。 diff --git a/zh-CN/development/comfyui-server/comms_routes.mdx b/zh-CN/development/comfyui-server/comms_routes.mdx index eb84763bd..9d9ba3222 100644 --- a/zh-CN/development/comfyui-server/comms_routes.mdx +++ b/zh-CN/development/comfyui-server/comms_routes.mdx @@ -35,10 +35,12 @@ title: "路由" | `/prompt` | post | 提交提示到队列 | | `/object_info` | get | 获取所有节点类型的详细信息 | | `/object_info/{node_class}` | get | 获取特定节点类型的详细信息 | -| `/history` | get | 获取队列历史记录 | -| `/history/{prompt_id}` | get | 获取特定提示的队列历史记录 | +| `/jobs` | get | 列出任务,支持过滤、排序和分页(推荐) | +| `/jobs/{job_id}` | get | 获取特定任务的完整详情(推荐) | +| `/history` | get | 获取队列历史记录(旧版) | +| `/history/{prompt_id}` | get | 获取特定提示的队列历史记录(旧版) | | `/history` | post | 清除历史记录或删除历史记录项 | -| `/queue` | get | 获取执行队列的当前状态 | +| `/queue` | get | 获取执行队列的当前状态(旧版) | | `/queue` | post | 管理队列操作(清除待处理/运行中的任务) | | `/interrupt` | post | 停止当前工作流执行 | | `/free` | post | 通过卸载指定模型释放内存 | @@ -51,6 +53,71 @@ title: "路由" | `/users` | get | 获取用户信息 | | `/users` | post | 创建新用户(仅限多用户模式) | +### Jobs API + +Jobs API (`/jobs`) 提供了一个统一的接口来列出和获取任务信息,支持过滤、排序和分页。这是查询任务状态和历史记录的推荐方式。 + +#### 列出任务 + +`GET /jobs` 返回一个分页的任务列表,支持可选的过滤: + +| 参数 | 类型 | 描述 | +|------|------|------| +| `status` | string | 按状态过滤(逗号分隔):`pending`、`in_progress`、`completed`、`failed`、`cancelled` | +| `workflow_id` | string | 按工作流 ID 过滤 | +| `sort_by` | string | 排序字段:`created_at`(默认)、`execution_duration` | +| `sort_order` | string | 排序方向:`asc`、`desc`(默认) | +| `limit` | integer | 返回的最大条目数 | +| `offset` | integer | 跳过的条目数(默认:0) | + +**响应:** +```json +{ + "jobs": [ + { + "id": "prompt-uuid", + "status": "completed", + "create_time": 1706540000, + "workflow_id": "workflow-uuid", + "outputs_count": 2, + "preview_output": {"filename": "output.png", "type": "output"}, + "execution_start_time": 1706540001000, + "execution_end_time": 1706540005000 + } + ], + "pagination": { + "offset": 0, + "limit": 100, + "total": 42, + "has_more": false + } +} +``` + +#### 获取任务详情 + +`GET /jobs/{job_id}` 返回特定任务的完整详情,包括输出和工作流: + +```json +{ + "id": "prompt-uuid", + "status": "completed", + "create_time": 1706540000, + "outputs": { + "9": {"images": [{"filename": "output.png", "type": "output"}]} + }, + "workflow": { + "prompt": {...}, + "extra_data": {...} + }, + "execution_status": {...} +} +``` + + +Jobs API 将队列和历史记录的数据整合为单一的统一格式。建议使用 `/jobs` 而不是分别查询 `/queue` 和 `/history` 端点。 + + ### WebSocket 通信 `/ws` 端点提供客户端与服务器之间的实时双向通信。用于: