From c6b9fb8d44dd02406aecaa36bfa3f5e13bc32f72 Mon Sep 17 00:00:00 2001 From: Hekmon <3418467+hekmon@users.noreply.github.com> Date: Fri, 7 Nov 2025 23:04:45 +0100 Subject: [PATCH] migrate client to manifest v3 --- __init__.py | 79 ++++++++++++++++++++++++++-------------- client.py | 101 ++++++++++++++++++++++++++++++---------------------- iotypes.py | 23 +++++++----- 3 files changed, 125 insertions(+), 78 deletions(-) diff --git a/__init__.py b/__init__.py index 0a3e839..eaaf3c7 100644 --- a/__init__.py +++ b/__init__.py @@ -1,34 +1,59 @@ +from typing_extensions import override +from comfy_api.latest import ComfyExtension, io + from .client import Client from .completions import ChatCompletion from .debug import Debug from .options import OptionSeed, OptionTemperature, OptionMaxTokens, OptionTopP, OptionFrequencyPenalty, OptionPresencePenalty, OptionExtraBody, OptionDeveloperRole -NODE_CLASS_MAPPINGS = { - "OAIAPIClient": Client, - "OAIAPIChatCompletion": ChatCompletion, - "OAIAPIDebug": Debug, - "OAIAPISeed": OptionSeed, - "OAIAPITemperature": OptionTemperature, - "OAIAPIMaxTokens": OptionMaxTokens, - "OAIAPITopP": OptionTopP, - "OAIAPIFrequencyPenalty": OptionFrequencyPenalty, - "OAIAPIPresencePenalty": OptionPresencePenalty, - "OAIAPIExtraBody": OptionExtraBody, - "OAIAPIDeveloperRole": OptionDeveloperRole, -} +# NODE_CLASS_MAPPINGS = { +# "OAIAPIClient": Client, +# "OAIAPIChatCompletion": ChatCompletion, +# "OAIAPIDebug": Debug, +# "OAIAPISeed": OptionSeed, +# "OAIAPITemperature": OptionTemperature, +# "OAIAPIMaxTokens": OptionMaxTokens, +# "OAIAPITopP": OptionTopP, +# "OAIAPIFrequencyPenalty": OptionFrequencyPenalty, +# "OAIAPIPresencePenalty": OptionPresencePenalty, +# "OAIAPIExtraBody": OptionExtraBody, +# "OAIAPIDeveloperRole": OptionDeveloperRole, +# } -NODE_DISPLAY_NAME_MAPPINGS = { - "OAIAPIClient": "OpenAI API - Client", - "OAIAPIChatCompletion": "OpenAI API - Chat Completion", - "OAIAPIDebug": "OpenAI API - Debug", - "OAIAPISeed": "OpenAI API - Seed", - "OAIAPITemperature": "OpenAI API - Temperature", - "OAIAPIMaxTokens": "OpenAI API - Max Tokens", - "OAIAPITopP": "OpenAI API - Top P", - "OAIAPIFrequencyPenalty": "OpenAI API - Frequency Penalty", - "OAIAPIPresencePenalty": "OpenAI API - Presence Penalty", - "OAIAPIExtraBody": "OpenAI API - Extra Body", - "OAIAPIDeveloperRole": "OpenAI API - Developer Role", -} +# NODE_DISPLAY_NAME_MAPPINGS = { +# "OAIAPIClient": "OpenAI API - Client", +# "OAIAPIChatCompletion": "OpenAI API - Chat Completion", +# "OAIAPIDebug": "OpenAI API - Debug", +# "OAIAPISeed": "OpenAI API - Seed", +# "OAIAPITemperature": "OpenAI API - Temperature", +# "OAIAPIMaxTokens": "OpenAI API - Max Tokens", +# "OAIAPITopP": "OpenAI API - Top P", +# "OAIAPIFrequencyPenalty": "OpenAI API - Frequency Penalty", +# "OAIAPIPresencePenalty": "OpenAI API - Presence Penalty", +# "OAIAPIExtraBody": "OpenAI API - Extra Body", +# "OAIAPIDeveloperRole": "OpenAI API - Developer Role", +# } -__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS'] +# __all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS'] + + +class OpenAIAPIExtension(ComfyExtension): + @override + async def get_node_list(self) -> list[type[io.ComfyNode]]: + return [ + Client, + # ChatCompletion, + # Debug, + # OptionSeed, + # OptionTemperature, + # OptionMaxTokens, + # OptionTopP, + # OptionFrequencyPenalty, + # OptionPresencePenalty, + # OptionExtraBody, + # OptionDeveloperRole + ] + + +async def comfy_entrypoint() -> OpenAIAPIExtension: + return OpenAIAPIExtension() diff --git a/client.py b/client.py index b1046f6..fb5f0e2 100644 --- a/client.py +++ b/client.py @@ -1,45 +1,59 @@ from urllib.parse import urlparse -from comfy.comfy_types import IO from openai import OpenAI -from .iotypes import OAIAPIIO +from comfy_api.latest import io -class Client: - CATEGORY = "OpenAI API" - RETURN_TYPES = (OAIAPIIO.CLIENT,) - # RETURN_NAMES = ("Target",) - FUNCTION = "create_client" +from .iotypes import ClientParam + + +class Client(io.ComfyNode): + @classmethod + def define_schema(cls) -> io.Schema: + return io.Schema( + node_id="OAIAPIClient", + display_name="OpenAI API - Client", + category="OpenAI API", + inputs=[ + io.String.Input( + id="base_url", + display_name="Base URL", + tooltip="The base URL to use for the OpenAI API requests", + placeholder="http(s)://host[:port][/URI]", + default="https://api.openai.com/v1" + ), + io.Int.Input( + id="max_retries", + display_name="Max Retries", + tooltip="The base URL to use for the OpenAI API requests", + default=2, + min=0, + ), + io.Int.Input( + id="timeout", + display_name="Timeout", + tooltip="Request timeout in seconds", + default=600, + min=1, + ), + io.String.Input( + id="api_key", + display_name="API Key", + optional=True, + tooltip="The API key to use, if any", + ), + ], + outputs=[ + ClientParam.Output( + id="client", + display_name="CLIENT", + tooltip="The initialized and ready to query OpenAI API client" + ) + ], + ) @classmethod - def INPUT_TYPES(s): - return { - "required": { - "base_url": (IO.STRING, { - "default": "https://api.openai.com/v1", - "placeholder": "http(s)://host[:port][/URI]", - "tooltip": "The base URL to use for the OpenAI API requests", - }), - "max_retries": (IO.INT, { - "min": 0, - "default": 2, - "tooltip": "Maximum number of retries on failure" - }), - "timeout": (IO.INT, { - "min": 1, - "default": 600, - "tooltip": "Request timeout in seconds" - }), - }, - "optional": { - "api_key": (IO.STRING, { - "tooltip": "The API key to use, if any" - }) - } - } - - @classmethod - def VALIDATE_INPUTS(cls, base_url): + def validate_inputs(cls, base_url) -> bool | str: try: result = urlparse(base_url) if result.scheme not in ["http", "https"]: @@ -48,10 +62,13 @@ class Client: return f"invalid URL: {e}" return True - def create_client(self, base_url, api_key=None, max_retries=2, timeout=600): - return (OpenAI( - api_key=api_key, - base_url=base_url, - max_retries=max_retries, - timeout=timeout - ),) + @classmethod + def execute(cls, base_url: str, max_retries: int, timeout: int, api_key: str | None = None) -> io.NodeOutput: + return io.NodeOutput( + OpenAI( + api_key=api_key, + base_url=base_url, + max_retries=max_retries, + timeout=timeout + ) + ) diff --git a/iotypes.py b/iotypes.py index 443dd73..efb6e4f 100644 --- a/iotypes.py +++ b/iotypes.py @@ -1,10 +1,15 @@ -from comfy.comfy_types.node_typing import StrEnum +from comfy_api.latest import io +# from comfy.comfy_types.node_typing import StrEnum -class OAIAPIIO(StrEnum): - """ - Node input/output data types. - """ - CLIENT = "CLIENT" - OPTIONS = "OPTIONS" - HISTORY = "HISTORY" - DEBUG = f"{OPTIONS},{HISTORY}" + +# class OAIAPIIO(StrEnum): +# """ +# Node input/output data types. +# """ +# CLIENT = "CLIENT" +# OPTIONS = "OPTIONS" +# HISTORY = "HISTORY" +# DEBUG = f"{OPTIONS},{HISTORY}" + + +ClientParam = io.Custom("OAIAPI_CLIENT")