diff --git a/development/cloud/api-reference.mdx b/development/cloud/api-reference.mdx index 251d9710c..7861cda1f 100644 --- a/development/cloud/api-reference.mdx +++ b/development/cloud/api-reference.mdx @@ -111,7 +111,362 @@ print(f"KSampler inputs: {inputs}") --- -## Uploading Inputs +## Assets API + +The Assets API provides a unified, tag-based system for managing files (images, models, outputs) with content-addressed storage and rich metadata support. + +### Key Features + +- **Content-addressed storage**: Files are deduplicated using Blake3 hashes +- **Tag-based organization**: Flexible tagging instead of folder hierarchies +- **Metadata support**: Attach custom JSON metadata to assets +- **Filtering and search**: Query assets by tags, name, or metadata + +### List Assets + +Retrieve a paginated list of your assets with optional filtering. + + +```bash curl +# List all assets +curl -X GET "$BASE_URL/api/assets" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" + +# Filter by tags +curl -X GET "$BASE_URL/api/assets?include_tags=output,image" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" + +# Search by name +curl -X GET "$BASE_URL/api/assets?name_contains=portrait" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" +``` + +```typescript TypeScript +interface Asset { + id: string; + name: string; + hash: string; + size_bytes: number; + mime_type: string; + tags: string[]; + created_at: string; + preview_url?: string; +} + +interface ListAssetsResponse { + assets: Asset[]; + total: number; + offset: number; + limit: number; +} + +async function listAssets(options: { + include_tags?: string[]; + exclude_tags?: string[]; + name_contains?: string; + sort?: "name" | "created_at" | "size"; + order?: "asc" | "desc"; + offset?: number; + limit?: number; +} = {}): Promise { + const params = new URLSearchParams(); + if (options.include_tags?.length) { + params.set("include_tags", options.include_tags.join(",")); + } + if (options.exclude_tags?.length) { + params.set("exclude_tags", options.exclude_tags.join(",")); + } + if (options.name_contains) params.set("name_contains", options.name_contains); + if (options.sort) params.set("sort", options.sort); + if (options.order) params.set("order", options.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/assets?${params}`, { + headers: getHeaders(), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); +} + +// List output images +const { assets } = await listAssets({ include_tags: ["output", "image"] }); +console.log(`Found ${assets.length} output images`); +``` + +```python Python +def list_assets( + include_tags: list = None, + exclude_tags: list = None, + name_contains: str = None, + sort: str = "created_at", + order: str = "desc", + offset: int = 0, + limit: int = 20 +) -> dict: + """List assets with optional filtering. + + Args: + include_tags: Only include assets with ALL these tags + exclude_tags: Exclude assets with ANY of these tags + name_contains: Filter by name substring (case-insensitive) + sort: Sort field (name, created_at, size, updated_at) + order: Sort direction (asc or desc) + offset: Pagination offset + limit: Max items per page (1-500) + + Returns: + Dict with 'assets' array and pagination info + """ + params = { + "sort": sort, + "order": order, + "offset": offset, + "limit": limit + } + if include_tags: + params["include_tags"] = ",".join(include_tags) + if exclude_tags: + params["exclude_tags"] = ",".join(exclude_tags) + if name_contains: + params["name_contains"] = name_contains + + response = requests.get( + f"{BASE_URL}/api/assets", + headers=get_headers(), + params=params + ) + response.raise_for_status() + return response.json() + +# List all output images +result = list_assets(include_tags=["output"]) +print(f"Found {len(result['assets'])} output assets") +``` + + +### Upload Asset + +Upload a file with tags and metadata. + + +```bash curl +curl -X POST "$BASE_URL/api/assets" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" \ + -F "file=@image.png" \ + -F "tags=input,reference" \ + -F "name=My Reference Image" +``` + +```typescript TypeScript +async function uploadAsset( + file: File | Blob, + options: { + name?: string; + tags?: string[]; + mime_type?: string; + user_metadata?: Record; + } = {} +): Promise { + const formData = new FormData(); + formData.append("file", file); + if (options.name) formData.append("name", options.name); + if (options.tags?.length) formData.append("tags", options.tags.join(",")); + if (options.mime_type) formData.append("mime_type", options.mime_type); + if (options.user_metadata) { + formData.append("user_metadata", JSON.stringify(options.user_metadata)); + } + + const response = await fetch(`${BASE_URL}/api/assets`, { + method: "POST", + headers: { "X-API-Key": API_KEY }, + body: formData, + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); +} + +// Upload with tags +const asset = await uploadAsset(imageBlob, { + name: "reference.png", + tags: ["input", "reference"], +}); +console.log(`Uploaded: ${asset.id}`); +``` + +```python Python +def upload_asset( + file_path: str, + name: str = None, + tags: list = None, + user_metadata: dict = None +) -> dict: + """Upload an asset with optional metadata. + + Args: + file_path: Path to the file to upload + name: Display name for the asset + tags: List of tags to apply + user_metadata: Custom JSON metadata + + Returns: + Created asset details + """ + with open(file_path, "rb") as f: + files = {"file": f} + data = {} + if name: + data["name"] = name + if tags: + data["tags"] = ",".join(tags) + if user_metadata: + data["user_metadata"] = json.dumps(user_metadata) + + response = requests.post( + f"{BASE_URL}/api/assets", + headers={"X-API-Key": API_KEY}, + files=files, + data=data + ) + response.raise_for_status() + return response.json() + +# Upload with tags +asset = upload_asset("image.png", name="reference", tags=["input", "reference"]) +print(f"Uploaded: {asset['id']}") +``` + + +### Get Asset Details + +Retrieve full details for a specific asset. + + +```bash curl +curl -X GET "$BASE_URL/api/assets/{asset_id}" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" +``` + +```typescript TypeScript +async function getAsset(assetId: string): Promise { + const response = await fetch(`${BASE_URL}/api/assets/${assetId}`, { + headers: getHeaders(), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); +} +``` + +```python Python +def get_asset(asset_id: str) -> dict: + """Get asset details by ID.""" + response = requests.get( + f"{BASE_URL}/api/assets/{asset_id}", + headers=get_headers() + ) + response.raise_for_status() + return response.json() +``` + + +### Manage Tags + +Add or remove tags from assets. + + +```bash curl +# Add tags +curl -X POST "$BASE_URL/api/assets/{asset_id}/tags" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{"tags": ["favorite", "portrait"]}' + +# Remove tags +curl -X DELETE "$BASE_URL/api/assets/{asset_id}/tags" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{"tags": ["temporary"]}' +``` + +```typescript TypeScript +async function addAssetTags(assetId: string, tags: string[]): Promise { + const response = await fetch(`${BASE_URL}/api/assets/${assetId}/tags`, { + method: "POST", + headers: getHeaders(), + body: JSON.stringify({ tags }), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); +} + +async function removeAssetTags(assetId: string, tags: string[]): Promise { + const response = await fetch(`${BASE_URL}/api/assets/${assetId}/tags`, { + method: "DELETE", + headers: getHeaders(), + body: JSON.stringify({ tags }), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); +} +``` + +```python Python +def add_asset_tags(asset_id: str, tags: list) -> dict: + """Add tags to an asset.""" + response = requests.post( + f"{BASE_URL}/api/assets/{asset_id}/tags", + headers=get_headers(), + json={"tags": tags} + ) + response.raise_for_status() + return response.json() + +def remove_asset_tags(asset_id: str, tags: list) -> dict: + """Remove tags from an asset.""" + response = requests.delete( + f"{BASE_URL}/api/assets/{asset_id}/tags", + headers=get_headers(), + json={"tags": tags} + ) + response.raise_for_status() + return response.json() +``` + + +### Delete Asset + + +```bash curl +curl -X DELETE "$BASE_URL/api/assets/{asset_id}" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" +``` + +```typescript TypeScript +async function deleteAsset(assetId: string): Promise { + const response = await fetch(`${BASE_URL}/api/assets/${assetId}`, { + method: "DELETE", + headers: getHeaders(), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); +} +``` + +```python Python +def delete_asset(asset_id: str) -> None: + """Delete an asset.""" + response = requests.delete( + f"{BASE_URL}/api/assets/{asset_id}", + headers=get_headers() + ) + response.raise_for_status() +``` + + +--- + +## Uploading Inputs (Legacy) + + + **Legacy Endpoints:** These endpoints (`/api/upload/*`) are maintained for compatibility with local ComfyUI. For new integrations, consider using the [Assets API](#assets-api) when available. + Upload images, masks, or other files for use in workflows. diff --git a/development/comfyui-server/comms_routes.mdx b/development/comfyui-server/comms_routes.mdx index 92b8a1e41..206e0ed81 100644 --- a/development/comfyui-server/comms_routes.mdx +++ b/development/comfyui-server/comms_routes.mdx @@ -26,9 +26,14 @@ The prompt queue is defined in `execution.py`, which also defines the `PromptExe | `/models` | get | retrieve a list of available model types | | `/models/{folder}` | get | retrieve models in a specific folder | | `/workflow_templates` | get | retrieve a map of custom node modules and associated template workflows | -| `/upload/image` | post | upload an image | -| `/upload/mask` | post | upload a mask | -| `/view` | get | view an image. Lots of options, see `@routes.get("/view")` in `server.py` | +| `/api/assets` | get | list assets with filtering and pagination (recommended) | +| `/api/assets` | post | upload a new asset with tags and metadata (recommended) | +| `/api/assets/{id}` | get | get asset details by ID (recommended) | +| `/api/assets/{id}/content` | get | download asset content | +| `/api/tags` | get | list all tags | +| `/upload/image` | post | upload an image (legacy) | +| `/upload/mask` | post | upload a mask (legacy) | +| `/view` | get | view an image (legacy). See `@routes.get("/view")` in `server.py` | | `/view_metadata`/{folder_name} | get | retrieve metadata for a model | | `/system_stats` | get | retrieve information about the system (python version, devices, vram etc) | | `/prompt` | get | retrieve current queue status and execution information | @@ -51,6 +56,68 @@ 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) | +### Assets API + +The Assets API (`/api/assets`) provides a unified, tag-based system for managing files (images, models, outputs) with content-addressed storage and metadata support. It is the recommended way to upload, organize, and retrieve files. + +#### List Assets + +`GET /api/assets` returns a paginated list of assets with optional filtering: + +| Parameter | Type | Description | +|-----------|------|-------------| +| `include_tags` | string | Filter assets that have ALL of these tags (comma-separated) | +| `exclude_tags` | string | Exclude assets that have ANY of these tags (comma-separated) | +| `name_contains` | string | Filter by name substring (case-insensitive) | +| `sort` | string | Sort field: `name`, `created_at` (default), `updated_at`, `size` | +| `order` | string | Sort direction: `asc`, `desc` (default) | +| `limit` | integer | Maximum items to return (1-500, default: 20) | +| `offset` | integer | Items to skip (default: 0) | + +**Response:** +```json +{ + "assets": [ + { + "id": "asset-uuid", + "name": "my-image.png", + "hash": "blake3:abc123...", + "size_bytes": 102400, + "mime_type": "image/png", + "tags": ["output", "image"], + "created_at": "2024-01-29T12:00:00Z", + "preview_url": "/api/assets/asset-uuid/content" + } + ], + "total": 42, + "offset": 0, + "limit": 20 +} +``` + +#### Upload Asset + +`POST /api/assets` uploads a new asset (multipart/form-data): + +| Field | Type | Description | +|-------|------|-------------| +| `file` | file | The file to upload (required) | +| `name` | string | Display name for the asset | +| `tags` | string | Comma-separated tags (e.g., `input,reference`) | +| `user_metadata` | string | Custom JSON metadata | + +#### Get Asset Details + +`GET /api/assets/{id}` returns full details for a specific asset. + +#### Download Asset Content + +`GET /api/assets/{id}/content` downloads the asset file with appropriate Content-Type and Content-Disposition headers. + + +The Assets API uses content-addressed storage with Blake3 hashes, meaning identical files are automatically deduplicated. Tags provide flexible organization without rigid folder hierarchies. + + ### WebSocket Communication The `/ws` endpoint provides real-time bidirectional communication between the client and server. This is used for: diff --git a/zh-CN/development/cloud/api-reference.mdx b/zh-CN/development/cloud/api-reference.mdx index f8e69347f..cfd599475 100644 --- a/zh-CN/development/cloud/api-reference.mdx +++ b/zh-CN/development/cloud/api-reference.mdx @@ -111,7 +111,362 @@ print(f"KSampler inputs: {inputs}") --- -## 上传输入 +## Assets API + +Assets API 提供了一个统一的、基于标签的文件管理系统(图片、模型、输出),支持内容寻址存储和丰富的元数据。 + +### 主要特性 + +- **内容寻址存储**:使用 Blake3 哈希进行文件去重 +- **基于标签的组织**:灵活的标签系统取代文件夹层级 +- **元数据支持**:可为资产附加自定义 JSON 元数据 +- **过滤和搜索**:按标签、名称或元数据查询资产 + +### 列出资产 + +获取分页的资产列表,支持可选过滤。 + + +```bash curl +# 列出所有资产 +curl -X GET "$BASE_URL/api/assets" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" + +# 按标签过滤 +curl -X GET "$BASE_URL/api/assets?include_tags=output,image" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" + +# 按名称搜索 +curl -X GET "$BASE_URL/api/assets?name_contains=portrait" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" +``` + +```typescript TypeScript +interface Asset { + id: string; + name: string; + hash: string; + size_bytes: number; + mime_type: string; + tags: string[]; + created_at: string; + preview_url?: string; +} + +interface ListAssetsResponse { + assets: Asset[]; + total: number; + offset: number; + limit: number; +} + +async function listAssets(options: { + include_tags?: string[]; + exclude_tags?: string[]; + name_contains?: string; + sort?: "name" | "created_at" | "size"; + order?: "asc" | "desc"; + offset?: number; + limit?: number; +} = {}): Promise { + const params = new URLSearchParams(); + if (options.include_tags?.length) { + params.set("include_tags", options.include_tags.join(",")); + } + if (options.exclude_tags?.length) { + params.set("exclude_tags", options.exclude_tags.join(",")); + } + if (options.name_contains) params.set("name_contains", options.name_contains); + if (options.sort) params.set("sort", options.sort); + if (options.order) params.set("order", options.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/assets?${params}`, { + headers: getHeaders(), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); +} + +// 列出输出图片 +const { assets } = await listAssets({ include_tags: ["output", "image"] }); +console.log(`Found ${assets.length} output images`); +``` + +```python Python +def list_assets( + include_tags: list = None, + exclude_tags: list = None, + name_contains: str = None, + sort: str = "created_at", + order: str = "desc", + offset: int = 0, + limit: int = 20 +) -> dict: + """列出资产,支持可选过滤。 + + Args: + include_tags: 仅包含具有所有这些标签的资产 + exclude_tags: 排除具有任何这些标签的资产 + name_contains: 按名称子字符串过滤(不区分大小写) + sort: 排序字段(name, created_at, size, updated_at) + order: 排序方向(asc 或 desc) + offset: 分页偏移量 + limit: 每页最大条目数(1-500) + + Returns: + 包含 'assets' 数组和分页信息的字典 + """ + params = { + "sort": sort, + "order": order, + "offset": offset, + "limit": limit + } + if include_tags: + params["include_tags"] = ",".join(include_tags) + if exclude_tags: + params["exclude_tags"] = ",".join(exclude_tags) + if name_contains: + params["name_contains"] = name_contains + + response = requests.get( + f"{BASE_URL}/api/assets", + headers=get_headers(), + params=params + ) + response.raise_for_status() + return response.json() + +# 列出所有输出图片 +result = list_assets(include_tags=["output"]) +print(f"Found {len(result['assets'])} output assets") +``` + + +### 上传资产 + +上传带有标签和元数据的文件。 + + +```bash curl +curl -X POST "$BASE_URL/api/assets" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" \ + -F "file=@image.png" \ + -F "tags=input,reference" \ + -F "name=My Reference Image" +``` + +```typescript TypeScript +async function uploadAsset( + file: File | Blob, + options: { + name?: string; + tags?: string[]; + mime_type?: string; + user_metadata?: Record; + } = {} +): Promise { + const formData = new FormData(); + formData.append("file", file); + if (options.name) formData.append("name", options.name); + if (options.tags?.length) formData.append("tags", options.tags.join(",")); + if (options.mime_type) formData.append("mime_type", options.mime_type); + if (options.user_metadata) { + formData.append("user_metadata", JSON.stringify(options.user_metadata)); + } + + const response = await fetch(`${BASE_URL}/api/assets`, { + method: "POST", + headers: { "X-API-Key": API_KEY }, + body: formData, + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); +} + +// 上传带标签的文件 +const asset = await uploadAsset(imageBlob, { + name: "reference.png", + tags: ["input", "reference"], +}); +console.log(`Uploaded: ${asset.id}`); +``` + +```python Python +def upload_asset( + file_path: str, + name: str = None, + tags: list = None, + user_metadata: dict = None +) -> dict: + """上传资产,支持可选元数据。 + + Args: + file_path: 要上传的文件路径 + name: 资产的显示名称 + tags: 要应用的标签列表 + user_metadata: 自定义 JSON 元数据 + + Returns: + 创建的资产详情 + """ + with open(file_path, "rb") as f: + files = {"file": f} + data = {} + if name: + data["name"] = name + if tags: + data["tags"] = ",".join(tags) + if user_metadata: + data["user_metadata"] = json.dumps(user_metadata) + + response = requests.post( + f"{BASE_URL}/api/assets", + headers={"X-API-Key": API_KEY}, + files=files, + data=data + ) + response.raise_for_status() + return response.json() + +# 上传带标签的文件 +asset = upload_asset("image.png", name="reference", tags=["input", "reference"]) +print(f"Uploaded: {asset['id']}") +``` + + +### 获取资产详情 + +获取特定资产的完整详情。 + + +```bash curl +curl -X GET "$BASE_URL/api/assets/{asset_id}" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" +``` + +```typescript TypeScript +async function getAsset(assetId: string): Promise { + const response = await fetch(`${BASE_URL}/api/assets/${assetId}`, { + headers: getHeaders(), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); +} +``` + +```python Python +def get_asset(asset_id: str) -> dict: + """按 ID 获取资产详情。""" + response = requests.get( + f"{BASE_URL}/api/assets/{asset_id}", + headers=get_headers() + ) + response.raise_for_status() + return response.json() +``` + + +### 管理标签 + +为资产添加或移除标签。 + + +```bash curl +# 添加标签 +curl -X POST "$BASE_URL/api/assets/{asset_id}/tags" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{"tags": ["favorite", "portrait"]}' + +# 移除标签 +curl -X DELETE "$BASE_URL/api/assets/{asset_id}/tags" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{"tags": ["temporary"]}' +``` + +```typescript TypeScript +async function addAssetTags(assetId: string, tags: string[]): Promise { + const response = await fetch(`${BASE_URL}/api/assets/${assetId}/tags`, { + method: "POST", + headers: getHeaders(), + body: JSON.stringify({ tags }), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); +} + +async function removeAssetTags(assetId: string, tags: string[]): Promise { + const response = await fetch(`${BASE_URL}/api/assets/${assetId}/tags`, { + method: "DELETE", + headers: getHeaders(), + body: JSON.stringify({ tags }), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); +} +``` + +```python Python +def add_asset_tags(asset_id: str, tags: list) -> dict: + """为资产添加标签。""" + response = requests.post( + f"{BASE_URL}/api/assets/{asset_id}/tags", + headers=get_headers(), + json={"tags": tags} + ) + response.raise_for_status() + return response.json() + +def remove_asset_tags(asset_id: str, tags: list) -> dict: + """从资产移除标签。""" + response = requests.delete( + f"{BASE_URL}/api/assets/{asset_id}/tags", + headers=get_headers(), + json={"tags": tags} + ) + response.raise_for_status() + return response.json() +``` + + +### 删除资产 + + +```bash curl +curl -X DELETE "$BASE_URL/api/assets/{asset_id}" \ + -H "X-API-Key: $COMFY_CLOUD_API_KEY" +``` + +```typescript TypeScript +async function deleteAsset(assetId: string): Promise { + const response = await fetch(`${BASE_URL}/api/assets/${assetId}`, { + method: "DELETE", + headers: getHeaders(), + }); + if (!response.ok) throw new Error(`HTTP ${response.status}`); +} +``` + +```python Python +def delete_asset(asset_id: str) -> None: + """删除资产。""" + response = requests.delete( + f"{BASE_URL}/api/assets/{asset_id}", + headers=get_headers() + ) + response.raise_for_status() +``` + + +--- + +## 上传输入(旧版) + + + **旧版端点:** 这些端点(`/api/upload/*`)为兼容本地 ComfyUI 而保留。对于新集成,推荐使用 [Assets API](#assets-api)。 + 上传图像、遮罩或其他文件以在工作流中使用。 diff --git a/zh-CN/development/comfyui-server/comms_routes.mdx b/zh-CN/development/comfyui-server/comms_routes.mdx index eb84763bd..61fc5d688 100644 --- a/zh-CN/development/comfyui-server/comms_routes.mdx +++ b/zh-CN/development/comfyui-server/comms_routes.mdx @@ -26,9 +26,14 @@ title: "路由" | `/models` | get | 获取可用模型类型列表 | | `/models/{folder}` | get | 获取特定文件夹中的模型 | | `/workflow_templates` | get | 获取自定义节点模块及其关联模板工作流的映射 | -| `/upload/image` | post | 上传图片 | -| `/upload/mask` | post | 上传蒙版 | -| `/view` | get | 查看图片。更多选项请参见 `server.py` 中的 `@routes.get("/view")` | +| `/api/assets` | get | 列出资产,支持过滤和分页(推荐) | +| `/api/assets` | post | 上传新资产,支持标签和元数据(推荐) | +| `/api/assets/{id}` | get | 按 ID 获取资产详情(推荐) | +| `/api/assets/{id}/content` | get | 下载资产内容 | +| `/api/tags` | get | 列出所有标签 | +| `/upload/image` | post | 上传图片(旧版) | +| `/upload/mask` | post | 上传蒙版(旧版) | +| `/view` | get | 查看图片(旧版)。参见 `server.py` 中的 `@routes.get("/view")` | | `/view_metadata`/{folder_name} | get | 获取模型的元数据 | | `/system_stats` | get | 获取系统信息(Python 版本、设备、显存等) | | `/prompt` | get | 获取当前队列状态和执行信息 | @@ -51,6 +56,68 @@ title: "路由" | `/users` | get | 获取用户信息 | | `/users` | post | 创建新用户(仅限多用户模式) | +### Assets API + +Assets API (`/api/assets`) 提供了一个统一的、基于标签的文件管理系统(图片、模型、输出),支持内容寻址存储和元数据。这是上传、组织和检索文件的推荐方式。 + +#### 列出资产 + +`GET /api/assets` 返回一个分页的资产列表,支持可选的过滤: + +| 参数 | 类型 | 描述 | +|------|------|------| +| `include_tags` | string | 过滤包含所有这些标签的资产(逗号分隔) | +| `exclude_tags` | string | 排除包含任何这些标签的资产(逗号分隔) | +| `name_contains` | string | 按名称子字符串过滤(不区分大小写) | +| `sort` | string | 排序字段:`name`、`created_at`(默认)、`updated_at`、`size` | +| `order` | string | 排序方向:`asc`、`desc`(默认) | +| `limit` | integer | 返回的最大条目数(1-500,默认:20) | +| `offset` | integer | 跳过的条目数(默认:0) | + +**响应:** +```json +{ + "assets": [ + { + "id": "asset-uuid", + "name": "my-image.png", + "hash": "blake3:abc123...", + "size_bytes": 102400, + "mime_type": "image/png", + "tags": ["output", "image"], + "created_at": "2024-01-29T12:00:00Z", + "preview_url": "/api/assets/asset-uuid/content" + } + ], + "total": 42, + "offset": 0, + "limit": 20 +} +``` + +#### 上传资产 + +`POST /api/assets` 上传新资产(multipart/form-data): + +| 字段 | 类型 | 描述 | +|------|------|------| +| `file` | file | 要上传的文件(必需) | +| `name` | string | 资产的显示名称 | +| `tags` | string | 逗号分隔的标签(例如 `input,reference`) | +| `user_metadata` | string | 自定义 JSON 元数据 | + +#### 获取资产详情 + +`GET /api/assets/{id}` 返回特定资产的完整详情。 + +#### 下载资产内容 + +`GET /api/assets/{id}/content` 下载资产文件,带有适当的 Content-Type 和 Content-Disposition 头。 + + +Assets API 使用 Blake3 哈希的内容寻址存储,这意味着相同的文件会自动去重。标签提供了灵活的组织方式,无需严格的文件夹层次结构。 + + ### WebSocket 通信 `/ws` 端点提供客户端与服务器之间的实时双向通信。用于: