Improved API support

- Run comfyui workflows directly inside other python applications using
   EmbeddedComfyClient.
 - Optional telemetry in prompts and models using anonymity preserving
   Plausible self-hosted or hosted.
 - Better OpenAPI schema
 - Basic support for distributed ComfyUI backends. Limitations: no
   progress reporting, no easy way to start your own distributed
   backend, requires RabbitMQ as a message broker.
This commit is contained in:
doctorpangloss
2024-02-07 14:20:21 -08:00
parent 32d83e52ff
commit 1b2ea61345
271 changed files with 16925 additions and 413 deletions
+5
View File
@@ -0,0 +1,5 @@
# do not import all endpoints into this module because that uses a lot of memory and stack frames
# if you need the ability to import all endpoints from this module, import them with
# from comfy.api.apis.paths.view import View
path = "/view"
+179
View File
@@ -0,0 +1,179 @@
# coding: utf-8
"""
Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""
from comfy.api import api_client, exceptions
from comfy.api.shared_imports.operation_imports import * # pyright: ignore [reportWildcardImportFromLibrary]
from .. import path
from .responses import (
response_200,
response_400,
response_403,
response_404,
)
from .parameters import (
parameter_0,
parameter_1,
parameter_2,
)
from .query_parameters import QueryParameters, QueryParametersDictInput, QueryParametersDict
query_parameter_classes = (
parameter_0.Parameter0,
parameter_1.Parameter1,
parameter_2.Parameter2,
)
__StatusCodeToResponse = typing.TypedDict(
'__StatusCodeToResponse',
{
'200': typing.Type[response_200.ResponseFor200],
'400': typing.Type[response_400.ResponseFor400],
'403': typing.Type[response_403.ResponseFor403],
'404': typing.Type[response_404.ResponseFor404],
}
)
_status_code_to_response: __StatusCodeToResponse = {
'200': response_200.ResponseFor200,
'400': response_400.ResponseFor400,
'403': response_403.ResponseFor403,
'404': response_404.ResponseFor404,
}
_non_error_status_codes = frozenset({
'200',
})
_error_status_codes = frozenset({
'400',
'403',
'404',
})
_all_accept_content_types = (
"image/png",
)
class BaseApi(api_client.Api):
@typing.overload
def _view_image(
self,
query_params: typing.Union[
QueryParametersDictInput,
QueryParametersDict
],
*,
skip_deserialization: typing.Literal[False] = False,
accept_content_types: typing.Tuple[str, ...] = _all_accept_content_types,
server_index: typing.Optional[int] = None,
stream: bool = False,
timeout: typing.Optional[typing.Union[int, float, typing.Tuple]] = None,
) -> response_200.ApiResponse: ...
@typing.overload
def _view_image(
self,
query_params: typing.Union[
QueryParametersDictInput,
QueryParametersDict
],
*,
skip_deserialization: typing.Literal[True],
accept_content_types: typing.Tuple[str, ...] = _all_accept_content_types,
server_index: typing.Optional[int] = None,
stream: bool = False,
timeout: typing.Optional[typing.Union[int, float, typing.Tuple]] = None,
) -> api_response.ApiResponseWithoutDeserialization: ...
def _view_image(
self,
query_params: typing.Union[
QueryParametersDictInput,
QueryParametersDict
],
*,
skip_deserialization: bool = False,
accept_content_types: typing.Tuple[str, ...] = _all_accept_content_types,
server_index: typing.Optional[int] = None,
stream: bool = False,
timeout: typing.Optional[typing.Union[int, float, typing.Tuple]] = None,
):
"""
(UI) View image
:param skip_deserialization: If true then api_response.response will be set but
api_response.body and api_response.headers will not be deserialized into schema
class instances
"""
query_params = QueryParameters.validate(
query_params,
configuration=self.api_client.schema_configuration
)
used_path, query_params_suffix = self._get_used_path(
path,
query_parameters=query_parameter_classes,
query_params=query_params,
skip_validation=True
)
headers = self._get_headers(accept_content_types=accept_content_types)
# TODO add cookie handling
host = self.api_client.configuration.get_server_url(
"servers", server_index
)
raw_response = self.api_client.call_api(
resource_path=used_path,
query_params_suffix=query_params_suffix,
method='get',
host=host,
headers=headers,
stream=stream,
timeout=timeout,
)
if skip_deserialization:
skip_deser_response = api_response.ApiResponseWithoutDeserialization(response=raw_response)
self._verify_response_status(skip_deser_response)
return skip_deser_response
status = str(raw_response.status)
if status in _non_error_status_codes:
status_code = typing.cast(
typing.Literal[
'200',
],
status
)
return _status_code_to_response[status_code].deserialize(
raw_response, self.api_client.schema_configuration)
elif status in _error_status_codes:
error_status_code = typing.cast(
typing.Literal[
'400',
'403',
'404',
],
status
)
error_response = _status_code_to_response[error_status_code].deserialize(
raw_response, self.api_client.schema_configuration)
raise exceptions.ApiException(
status=error_response.response.status,
reason=error_response.response.reason,
api_response=error_response
)
response = api_response.ApiResponseWithoutDeserialization(response=raw_response)
self._verify_response_status(response)
return response
class ViewImage(BaseApi):
# this class is used by api classes that refer to endpoints with operationId.snakeCase fn names
view_image = BaseApi._view_image
class ApiForGet(BaseApi):
# this class is used by api classes that refer to endpoints by path and http method names
get = BaseApi._view_image
@@ -0,0 +1,17 @@
# coding: utf-8
"""
Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""
from comfy.api.shared_imports.header_imports import * # pyright: ignore [reportWildcardImportFromLibrary]
from . import schema
class Parameter0(api_client.QueryParameter):
name = "filename"
style = api_client.ParameterStyle.FORM
schema: typing_extensions.TypeAlias = schema.Schema
required = True
explode = True
@@ -0,0 +1,13 @@
# coding: utf-8
"""
comfyui
No description provided (generated by Openapi JSON Schema Generator https://github.com/openapi-json-schema-tools/openapi-json-schema-generator) # noqa: E501
The version of the OpenAPI document: 0.0.1
Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""
from __future__ import annotations
from comfy.api.shared_imports.schema_imports import * # pyright: ignore [reportWildcardImportFromLibrary]
Schema: typing_extensions.TypeAlias = schemas.StrSchema
@@ -0,0 +1,16 @@
# coding: utf-8
"""
Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""
from comfy.api.shared_imports.header_imports import * # pyright: ignore [reportWildcardImportFromLibrary]
from . import schema
class Parameter1(api_client.QueryParameter):
name = "type"
style = api_client.ParameterStyle.FORM
schema: typing_extensions.TypeAlias = schema.Schema
explode = True
@@ -0,0 +1,94 @@
# coding: utf-8
"""
comfyui
No description provided (generated by Openapi JSON Schema Generator https://github.com/openapi-json-schema-tools/openapi-json-schema-generator) # noqa: E501
The version of the OpenAPI document: 0.0.1
Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""
from __future__ import annotations
from comfy.api.shared_imports.schema_imports import * # pyright: ignore [reportWildcardImportFromLibrary]
class SchemaEnums:
@schemas.classproperty
def OUTPUT(cls) -> typing.Literal["output"]:
return Schema.validate("output")
@schemas.classproperty
def INPUT(cls) -> typing.Literal["input"]:
return Schema.validate("input")
@schemas.classproperty
def TEMP(cls) -> typing.Literal["temp"]:
return Schema.validate("temp")
@dataclasses.dataclass(frozen=True)
class Schema(
schemas.Schema
):
types: typing.FrozenSet[typing.Type] = frozenset({
str,
})
enum_value_to_name: typing.Mapping[typing.Union[int, float, str, schemas.Bool, None], str] = dataclasses.field(
default_factory=lambda: {
"output": "OUTPUT",
"input": "INPUT",
"temp": "TEMP",
}
)
enums = SchemaEnums
@typing.overload
@classmethod
def validate(
cls,
arg: typing.Literal["output"],
configuration: typing.Optional[schema_configuration.SchemaConfiguration] = None
) -> typing.Literal["output"]: ...
@typing.overload
@classmethod
def validate(
cls,
arg: typing.Literal["input"],
configuration: typing.Optional[schema_configuration.SchemaConfiguration] = None
) -> typing.Literal["input"]: ...
@typing.overload
@classmethod
def validate(
cls,
arg: typing.Literal["temp"],
configuration: typing.Optional[schema_configuration.SchemaConfiguration] = None
) -> typing.Literal["temp"]: ...
@typing.overload
@classmethod
def validate(
cls,
arg: str,
configuration: typing.Optional[schema_configuration.SchemaConfiguration] = None
) -> typing.Literal["output","input","temp",]: ...
@classmethod
def validate(
cls,
arg: typing.Union[str, datetime.date, datetime.datetime, uuid.UUID],
configuration: typing.Optional[schema_configuration.SchemaConfiguration] = None
) -> typing.Literal[
"output",
"input",
"temp",
]:
validated_arg = super().validate_base(
arg,
configuration=configuration,
)
return typing.cast(typing.Literal[
"output",
"input",
"temp",
],
validated_arg
)
@@ -0,0 +1,16 @@
# coding: utf-8
"""
Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""
from comfy.api.shared_imports.header_imports import * # pyright: ignore [reportWildcardImportFromLibrary]
from . import schema
class Parameter2(api_client.QueryParameter):
name = "subfolder"
style = api_client.ParameterStyle.FORM
schema: typing_extensions.TypeAlias = schema.Schema
explode = True
@@ -0,0 +1,13 @@
# coding: utf-8
"""
comfyui
No description provided (generated by Openapi JSON Schema Generator https://github.com/openapi-json-schema-tools/openapi-json-schema-generator) # noqa: E501
The version of the OpenAPI document: 0.0.1
Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""
from __future__ import annotations
from comfy.api.shared_imports.schema_imports import * # pyright: ignore [reportWildcardImportFromLibrary]
Schema: typing_extensions.TypeAlias = schemas.StrSchema
@@ -0,0 +1,161 @@
# coding: utf-8
"""
comfyui
No description provided (generated by Openapi JSON Schema Generator https://github.com/openapi-json-schema-tools/openapi-json-schema-generator) # noqa: E501
The version of the OpenAPI document: 0.0.1
Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""
from __future__ import annotations
from comfy.api.shared_imports.schema_imports import * # pyright: ignore [reportWildcardImportFromLibrary]
AdditionalProperties: typing_extensions.TypeAlias = schemas.NotAnyTypeSchema
from comfy.api.paths.view.get.parameters.parameter_0 import schema
from comfy.api.paths.view.get.parameters.parameter_1 import schema as schema_3
from comfy.api.paths.view.get.parameters.parameter_2 import schema as schema_2
Properties = typing.TypedDict(
'Properties',
{
"filename": typing.Type[schema.Schema],
"subfolder": typing.Type[schema_2.Schema],
"type": typing.Type[schema_3.Schema],
}
)
QueryParametersRequiredDictInput = typing.TypedDict(
'QueryParametersRequiredDictInput',
{
"filename": str,
}
)
QueryParametersOptionalDictInput = typing.TypedDict(
'QueryParametersOptionalDictInput',
{
"subfolder": str,
"type": typing.Literal[
"output",
"input",
"temp"
],
},
total=False
)
class QueryParametersDict(schemas.immutabledict[str, schemas.OUTPUT_BASE_TYPES]):
__required_keys__: typing.FrozenSet[str] = frozenset({
"filename",
})
__optional_keys__: typing.FrozenSet[str] = frozenset({
"subfolder",
"type",
})
def __new__(
cls,
*,
filename: str,
subfolder: typing.Union[
str,
schemas.Unset
] = schemas.unset,
type: typing.Union[
typing.Literal[
"output",
"input",
"temp"
],
schemas.Unset
] = schemas.unset,
configuration_: typing.Optional[schema_configuration.SchemaConfiguration] = None,
):
arg_: typing.Dict[str, typing.Any] = {
"filename": filename,
}
for key_, val in (
("subfolder", subfolder),
("type", type),
):
if isinstance(val, schemas.Unset):
continue
arg_[key_] = val
used_arg_ = typing.cast(QueryParametersDictInput, arg_)
return QueryParameters.validate(used_arg_, configuration=configuration_)
@staticmethod
def from_dict_(
arg: typing.Union[
QueryParametersDictInput,
QueryParametersDict
],
configuration: typing.Optional[schema_configuration.SchemaConfiguration] = None
) -> QueryParametersDict:
return QueryParameters.validate(arg, configuration=configuration)
@property
def filename(self) -> str:
return typing.cast(
str,
self.__getitem__("filename")
)
@property
def subfolder(self) -> typing.Union[str, schemas.Unset]:
val = self.get("subfolder", schemas.unset)
if isinstance(val, schemas.Unset):
return val
return typing.cast(
str,
val
)
@property
def type(self) -> typing.Union[typing.Literal["output", "input", "temp"], schemas.Unset]:
val = self.get("type", schemas.unset)
if isinstance(val, schemas.Unset):
return val
return typing.cast(
typing.Literal["output", "input", "temp"],
val
)
class QueryParametersDictInput(QueryParametersRequiredDictInput, QueryParametersOptionalDictInput):
pass
@dataclasses.dataclass(frozen=True)
class QueryParameters(
schemas.Schema[QueryParametersDict, tuple]
):
types: typing.FrozenSet[typing.Type] = frozenset({schemas.immutabledict})
required: typing.FrozenSet[str] = frozenset({
"filename",
})
properties: Properties = dataclasses.field(default_factory=lambda: schemas.typed_dict_to_instance(Properties)) # type: ignore
additional_properties: typing.Type[AdditionalProperties] = dataclasses.field(default_factory=lambda: AdditionalProperties) # type: ignore
type_to_output_cls: typing.Mapping[
typing.Type,
typing.Type
] = dataclasses.field(
default_factory=lambda: {
schemas.immutabledict: QueryParametersDict
}
)
@classmethod
def validate(
cls,
arg: typing.Union[
QueryParametersDictInput,
QueryParametersDict,
],
configuration: typing.Optional[schema_configuration.SchemaConfiguration] = None
) -> QueryParametersDict:
return super().validate_base(
arg,
configuration=configuration,
)
@@ -0,0 +1,28 @@
# coding: utf-8
"""
Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""
from comfy.api.shared_imports.response_imports import * # pyright: ignore [reportWildcardImportFromLibrary]
from .content.image_png import schema as image_png_schema
@dataclasses.dataclass(frozen=True)
class ApiResponse(api_response.ApiResponse):
body: typing.Union[bytes, schemas.FileIO]
headers: schemas.Unset
class ResponseFor200(api_client.OpenApiResponse[ApiResponse]):
@classmethod
def get_response(cls, response, headers, body) -> ApiResponse:
return ApiResponse(response=response, body=body, headers=headers)
class ImagePngMediaType(api_client.MediaType):
schema: typing_extensions.TypeAlias = image_png_schema.Schema
content = {
'image/png': ImagePngMediaType,
}
@@ -0,0 +1,13 @@
# coding: utf-8
"""
comfyui
No description provided (generated by Openapi JSON Schema Generator https://github.com/openapi-json-schema-tools/openapi-json-schema-generator) # noqa: E501
The version of the OpenAPI document: 0.0.1
Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""
from __future__ import annotations
from comfy.api.shared_imports.schema_imports import * # pyright: ignore [reportWildcardImportFromLibrary]
Schema: typing_extensions.TypeAlias = schemas.BinarySchema
@@ -0,0 +1,19 @@
# coding: utf-8
"""
Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""
from comfy.api.shared_imports.response_imports import * # pyright: ignore [reportWildcardImportFromLibrary]
@dataclasses.dataclass(frozen=True)
class ApiResponse(api_response.ApiResponse):
body: schemas.Unset
headers: schemas.Unset
class ResponseFor400(api_client.OpenApiResponse[ApiResponse]):
@classmethod
def get_response(cls, response, headers, body) -> ApiResponse:
return ApiResponse(response=response, body=body, headers=headers)
@@ -0,0 +1,19 @@
# coding: utf-8
"""
Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""
from comfy.api.shared_imports.response_imports import * # pyright: ignore [reportWildcardImportFromLibrary]
@dataclasses.dataclass(frozen=True)
class ApiResponse(api_response.ApiResponse):
body: schemas.Unset
headers: schemas.Unset
class ResponseFor403(api_client.OpenApiResponse[ApiResponse]):
@classmethod
def get_response(cls, response, headers, body) -> ApiResponse:
return ApiResponse(response=response, body=body, headers=headers)
@@ -0,0 +1,19 @@
# coding: utf-8
"""
Generated by: https://github.com/openapi-json-schema-tools/openapi-json-schema-generator
"""
from comfy.api.shared_imports.response_imports import * # pyright: ignore [reportWildcardImportFromLibrary]
@dataclasses.dataclass(frozen=True)
class ApiResponse(api_response.ApiResponse):
body: schemas.Unset
headers: schemas.Unset
class ResponseFor404(api_client.OpenApiResponse[ApiResponse]):
@classmethod
def get_response(cls, response, headers, body) -> ApiResponse:
return ApiResponse(response=response, body=body, headers=headers)