Skip to content

upload_util

Uploading stuff to ComfyUI.

upload_image(base_url, image_path, *, type='input', subfolder='') async

Posts an image/video to /upload/image endpoint.

Returns:

Type Description
MutableMapping | None

JSON object response if successful, otherwise None

Source code in client/ayon_comfyui/api/upload_util.py
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
async def upload_image(
    base_url: str,
    image_path: str | Path,
    *,
    type: str = "input",
    subfolder: str = "",
) -> MutableMapping | None:
    """Posts an image/video to /upload/image endpoint.

    Returns:
        JSON object response if successful, otherwise None
    """
    if isinstance(image_path, str):
        image_path = Path(image_path)

    MIME_map = {  # noqa : N806
        # Common formats
        ".png": "image/png",
        ".jpg": "image/jpeg",
        ".jpeg": "image/jpeg",
        ".jpe": "image/jpeg",
        ".jfif": "image/jpeg",
        ".webp": "image/webp",
        ".gif": "image/gif",
        ".bmp": "image/bmp",
        ".dib": "image/bmp",
        ".avif": "image/avif",
        ".heic": "image/heic",
        ".heif": "image/heif",
        ".jxl": "image/jxl",
        # Vector | Are we gonna use this?
        ".svg": "image/svg+xml",
        # TIFF
        ".tif": "image/tiff",
        ".tiff": "image/tiff",
        # Icons | Are we gonna use this?
        ".ico": "image/vnd.microsoft.icon",
        # Portable anymap formats | Are we gonna use this?
        ".pbm": "image/x-portable-bitmap",
        ".pgm": "image/x-portable-graymap",
        ".ppm": "image/x-portable-pixmap",
        # High dynamic range / VFX
        ".hdr": "image/vnd.radiance",  # Not sure about HDR
        ".exr": "image/x-exr",
        # Adobe / design  | Are we gonna use this?
        ".psd": "image/vnd.adobe.photoshop",
        # Less common / legacy
        ".pcx": "image/x-pcx",
        ".tga": "image/x-targa",
        # Video
        ".mp4": "video/mp4",
        ".mov": "video/quicktime",
        ".webm": "video/webm",
        # 3D Model
        ".gltf": "model/gltf+json",
        ".glb": "model/gltf-binary",
        ".obj": "text/plain",  # or "model/obj" (unofficial)
        ".fbx": "application/octet-stream",  # or "model/vnd.autodesk.fbx"
        ".stl": "model/stl",  # or "application/vnd.ms-pki.stl"
        ".ply": "application/octet-stream",  # or "model/ply" (unofficial)
        ".spz": "application/octet-stream",
        ".splat": "application/octet-stream",
        ".ksplat": "application/octet-stream",
    }

    MIME_type = MIME_map.get(image_path.suffix)  # noqa : N806

    if MIME_type is None:
        # Maybe raise
        return None

    url_parsed = urlparse(base_url)
    post_url = url_parsed._replace(path="/upload/image").geturl()

    # we allow a file object here to allow for streaming in a session.
    async with aiohttp.ClientSession() as session:
        with image_path.open("rb") as image_file:  # noqa: ASYNC230
            data = aiohttp.FormData()
            data.add_field(
                "image",
                image_file,
                filename=image_path.name,
                content_type=MIME_type,
            )

            data.add_field("type", type)  # input by default

            if Path("AYON") in Path(subfolder).parents:
                subfolder_path = Path(subfolder)
            else:
                subfolder_path = (
                    (Path("AYON") / subfolder) if subfolder else Path("AYON")
                )

            data.add_field("subfolder", str(subfolder_path))

            async with session.post(post_url, data=data) as resp:
                return await resp.json()

upload_input_image(base_url, image_path, *, subfolder='')

Posts an image to /upload/image endpoint as input.

Does so synchronously.

The response JSON object has the following scheme:

{
  'name': 'filename.png', # or other extension
  'subfolder': 'path/to/subfolder',
  'type': 'input'
}

Returns:

Type Description
dict

JSON object response if successful, otherwise None

Source code in client/ayon_comfyui/api/upload_util.py
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def upload_input_image(
    base_url: str, image_path: str | Path, *, subfolder: str = ""
) -> dict:
    """Posts an image to /upload/image endpoint as input.

    Does so synchronously.

    The response JSON object has the following scheme:

    ```
    {
      'name': 'filename.png', # or other extension
      'subfolder': 'path/to/subfolder',
      'type': 'input'
    }
    ```

    Returns:
        JSON object response if successful, otherwise None

    """
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

    image_upload_info: dict[str, str] = loop.run_until_complete(
        upload_image(base_url, image_path, subfolder=subfolder)
    )

    image_upload_info["subfolder"] = image_upload_info["subfolder"].replace(
        "\\", "/"
    )

    return image_upload_info

upload_input_images(image_paths, base_url, *, subfolder='')

Posts an images to /upload/image endpoint as input.

Waits synchronously, but images are all uploaded asynchronously.

The response JSON objects have the following scheme:

{
  'name': 'filename.png', # or other extension
  'subfolder': 'path/to/subfolder',
  'type': 'input'
}

Returns:

Type Description
list[MutableMapping] | None

JSON objects in list if response if successful, otherwise None

Source code in client/ayon_comfyui/api/upload_util.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
def upload_input_images(
    image_paths: list[str], base_url: str, *, subfolder: str = ""
) -> list[MutableMapping] | None:
    """Posts an images to /upload/image endpoint as input.

    Waits synchronously, but images are all uploaded asynchronously.

    The response JSON objects have the following scheme:

    ```
    {
      'name': 'filename.png', # or other extension
      'subfolder': 'path/to/subfolder',
      'type': 'input'
    }
    ```

    Returns:
        JSON objects in list if response if successful, otherwise None

    """
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

    upload_infos = loop.run_until_complete(
        asyncio.gather(
            *[
                upload_image(base_url, image_path, subfolder=subfolder)
                for image_path in image_paths
            ]
        )
    )

    image_upload_info = []

    for upload_info in upload_infos:
        upload_info["subfolder"] = upload_info["subfolder"].replace("\\", "/")
        image_upload_info.append(upload_info)

    if image_upload_info:
        return image_upload_info

    return None