update nodes for hyprlab api

This commit is contained in:
AhBumm
2025-11-27 19:27:01 +08:00
parent 28f2ee5abe
commit 130b3e9647
4 changed files with 146 additions and 2 deletions
+3
View File
@@ -6,6 +6,7 @@ from .nodes4tuzi import (
LoadVideoFromUrlVHS,
LoadVideoFromUrlComfyIO,
)
from .nodes4hypr import HyprLab_Image_API_Node
# Exporting the node classes for ComfyUI to discover
NODE_CLASS_MAPPINGS = {
@@ -31,6 +32,7 @@ NODE_CLASS_MAPPINGS = {
"reg_tuzi_chat_response": RegTuziChatResponse,
"load_video_from_url": LoadVideoFromUrlVHS,
"load_video_from_url_comfy_core": LoadVideoFromUrlComfyIO,
"hyprlab_image_api_node": HyprLab_Image_API_Node,
}
NODE_DISPLAY_NAME_MAPPINGS = {
@@ -56,4 +58,5 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"BillBum_Modified_LLM_ForceStream_Mode": "LLM StreamResponse Node (Old)",
"BillBum_Modified_GPTImage1_API_Node": "Custom GPTImage1 API Node",
"BillBum_Modified_Flux_API_with_imgInput": "Custom Flux API Node",
"hyprlab_image_api_node": "HyprLab ImageGen API Node",
}
+1 -1
View File
@@ -161,7 +161,7 @@ class Input_Text:
def INPUT_TYPES(s):
return {
"required": {
"text": ("STRING", {"multiline": True},),
"text": ("STRING", {"dynamicPrompts": True, "multiline": True},),
},
}
+141
View File
@@ -0,0 +1,141 @@
import torch
import numpy as np
from PIL import Image
import io
import base64
import requests
import random
import tenacity
import math
from comfy.utils import common_upscale
## ====== Utility Functions ======
def tensor2pil(image):
return Image.fromarray(np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8))
def pil2tensor(image):
return torch.from_numpy(np.array(image).astype(np.float32) / 255.0).unsqueeze(0)
def downscale_input(image):
samples = image.movedim(-1,1)
total = int(1536 * 1024)
scale_by = math.sqrt(total / (samples.shape[3] * samples.shape[2]))
if scale_by >= 1:
return image
width = round(samples.shape[3] * scale_by)
height = round(samples.shape[2] * scale_by)
s = common_upscale(samples, width, height, "lanczos", "disabled")
s = s.movedim(1,-1)
return s
## ====== HyprLab API Nodes ======
class HyprLab_Image_API_Node:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"prompt": ("STRING", {"forceInput": True, "dynamicPrompts": True, "tooltip": "The main text prompt"}),
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
"model": ("STRING", {"default": "nano-banana-pro"}),
"api_url": ("STRING", {"multiline": False, "default": "https://api.hyprlab.io/v1/images/generations"}),
"api_key": ("STRING", {"multiline": False, "default": "YOUR_API_KEY_HERE"}),
"resolution": (["1K", "2K", "4K"], {"default": "1K"}),
"aspect_ratio": ([
"match_input_image", "1:1", "9:16", "16:9", "3:4",
"4:3", "3:2", "2:3", "5:4", "4:5", "21:9"
], {"default": "1:1"}),
},
"optional": {
"image_input": ("IMAGE", {"default": None, "tooltip": "Optional input images to guide generation"}),
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("IMAGE",)
FUNCTION = "generate_image"
CATEGORY = "BillBum_API/Image_API"
@staticmethod
def _encode_images_to_base64(images):
if images is None:
return []
if images.dim() == 3:
images = images.unsqueeze(0)
images = downscale_input(images)
encoded_images = []
for idx in range(images.shape[0]):
tensor_image = images[idx].clamp(0.0, 1.0)
pil_image = tensor2pil(tensor_image)
buffer = io.BytesIO()
pil_image.save(buffer, format="PNG")
encoded = base64.b64encode(buffer.getvalue()).decode("utf-8")
encoded_images.append(f"data:image/png;base64,{encoded}")
return encoded_images
@tenacity.retry(wait=tenacity.wait_exponential(multiplier=1.25, min=5, max=30), stop=tenacity.stop_after_attempt(3))
def generate_image(self, prompt, seed, model, api_url, api_key, resolution, aspect_ratio, image_input=None):
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
payload = {
"model": model,
"prompt": prompt,
"resolution": resolution,
"aspect_ratio": aspect_ratio,
"output_format": "png",
"response_format": "b64_json",
"seed": seed
}
if image_input is not None:
encoded_imgs = self._encode_images_to_base64(image_input)
if encoded_imgs:
payload["image_input"] = encoded_imgs
try:
response = requests.post(api_url, headers=headers, json=payload, timeout=60)
response.raise_for_status()
response_data = response.json()
images_output = []
data_list = response_data.get("data", [])
if not data_list and "b64_json" in response_data:
data_list = [response_data]
for item in data_list:
b64_str = item.get("b64_json")
if b64_str:
img_data = base64.b64decode(b64_str)
img = Image.open(io.BytesIO(img_data))
if img.mode != "RGBA":
img = img.convert("RGBA")
images_output.append(pil2tensor(img))
if not images_output:
print(f"API Response: {response_data}")
raise ValueError("API did not return any valid images.")
return (torch.cat(images_output, dim=0),)
except Exception as e:
if isinstance(e, requests.exceptions.RequestException) and e.response is not None:
print(f"API Error Response: {e.response.text}")
raise ValueError(f"HyprBanana API Error: {e}")
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui_billbum_api_nodes"
description = "API call node for Third-party platforms both official and local. Support VLMs LLMs Dalle3 Flux-Pro(Support kontext, banana etc... now!! and new Support gpt-image-1!!). And some little tools: img to b64 url, b64 url to img, b64 url to b64 data, reg text to word and ',' only, etc."
version = "1.1.6"
version = "1.1.7"
license = {file = "LICENSE"}
dependencies = ["tenacity", "openai", "pillow", "requests", "torch", "numpy", "tiktoken"]