Files
2026-04-22 17:19:41 +08:00

186 lines
6.8 KiB
Python

"""
PD: OpenAI GPT Image 1 & 1.5 Node (ComfyUI Auth Token)
"""
import time
import requests
import torch
from ._image_gpt_common import (
calculate_token_price_1_or_1_5,
decode_response_images,
empty_image,
estimate_price_range_1_or_1_5,
format_rmb_range,
format_rmb_value,
mask_to_png_bytes,
tensor_to_bytes,
)
class PDOpenAIGPTImageAuthToken:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"auth_token": ("STRING", {
"default": "",
"multiline": False,
"placeholder": "Paste your Auth Token here"
}),
"prompt": ("STRING", {
"multiline": True,
"default": "",
"tooltip": "Describe what you want to generate or edit"
}),
"model": (["gpt-image-1", "gpt-image-1.5"], {
"default": "gpt-image-1.5",
"tooltip": "GPT Image model version"
}),
"quality": (["low", "medium", "high"], {
"default": "low",
"tooltip": "Image quality, affects cost and generation time"
}),
"background": (["auto", "opaque", "transparent"], {
"default": "auto",
"tooltip": "Background transparency"
}),
"size": (["auto", "1024x1024", "1024x1536", "1536x1024"], {
"default": "auto",
"tooltip": "Image size"
}),
"n": ("INT", {
"default": 1,
"min": 1,
"max": 8,
"step": 1,
"tooltip": "Number of images to generate"
}),
"seed": ("INT", {
"default": 0,
"min": 0,
"max": 0xFFFFFFFFFFFFFFFF
}),
},
"optional": {
"image": ("IMAGE", {"default": None, "tooltip": "Input image for editing"}),
"mask": ("MASK", {"default": None, "tooltip": "Mask for inpainting"}),
},
"hidden": {
"unique_id": "UNIQUE_ID",
}
}
RETURN_TYPES = ("IMAGE", "STRING")
RETURN_NAMES = ("image", "info")
FUNCTION = "generate_image"
CATEGORY = "PD_Tools/Image_Generation"
def generate_image(self, auth_token, prompt, model, quality, background, size, n, seed, unique_id, image=None, mask=None):
if not auth_token or not auth_token.strip():
error_msg = "Error: Auth Token is required"
print(f"[IMAGE_GPT_AUTHTOKEN] {error_msg}")
return (empty_image(), error_msg)
auth_token = auth_token.strip()
if auth_token.lower().startswith("bearer "):
auth_token = auth_token[7:].strip()
base_url = "https://api.comfy.org"
is_edit_mode = image is not None
start_time = time.time()
try:
if is_edit_mode:
url = f"{base_url}/proxy/openai/images/edits"
files = {
"image": ("image.png", tensor_to_bytes(image), "image/png")
}
if mask is not None:
files["mask"] = ("mask.png", mask_to_png_bytes(mask), "image/png")
data = {
"model": model,
"prompt": prompt,
"n": str(n),
"size": size,
"quality": quality,
"background": background,
"moderation": "low"
}
headers = {
"Authorization": f"Bearer {auth_token}",
"User-Agent": "ComfyUI-PD-Node/2.1"
}
response = requests.post(url, headers=headers, files=files, data=data, timeout=300)
else:
url = f"{base_url}/proxy/openai/images/generations"
payload = {
"model": model,
"prompt": prompt,
"n": n,
"size": size,
"quality": quality,
"background": background,
"moderation": "low"
}
headers = {
"Authorization": f"Bearer {auth_token}",
"Content-Type": "application/json",
"User-Agent": "ComfyUI-PD-Node/2.1"
}
response = requests.post(url, headers=headers, json=payload, timeout=300)
if response.status_code != 200:
error_msg = f"API Error {response.status_code}: {response.text[:200]}"
print(f"[IMAGE_GPT_AUTHTOKEN] {error_msg}")
return (empty_image(), error_msg)
result = response.json()
image_tensors = decode_response_images(result)
if not image_tensors:
error_msg = "Error: Failed to process output images"
print(f"[IMAGE_GPT_AUTHTOKEN] {error_msg}")
return (empty_image(), error_msg)
final_image = torch.cat(image_tensors, dim=0)
duration = time.time() - start_time
min_cost, max_cost = estimate_price_range_1_or_1_5(model, quality, n)
token_cost = calculate_token_price_1_or_1_5(model, n)
info_str = (
f"模型: {model}\n"
f"显示名称: OpenAI GPT Image 1 & 1.5\n"
f"模式: {'编辑' if is_edit_mode else '生成'}\n"
f"状态: 成功\n"
f"耗时: {duration:.2f} 秒\n"
f"图片数量: {len(image_tensors)}\n"
f"尺寸: {size}\n"
f"质量: {quality}\n"
f"背景: {background}\n"
f"预估价格区间(USD): ${min_cost:.3f}-${max_cost:.3f}\n"
f"预估价格区间(RMB): {format_rmb_range(min_cost, max_cost)}\n"
f"Token 公式估算(USD): ${token_cost:.4f}\n"
f"Token 公式估算(RMB): {format_rmb_value(token_cost)}"
)
return (final_image, info_str)
except requests.exceptions.Timeout:
return (empty_image(), "Error: Request timeout (300s)")
except requests.exceptions.ConnectionError as e:
return (empty_image(), f"Error: Connection failed - {str(e)}")
except Exception as e:
import traceback
traceback.print_exc()
return (empty_image(), f"Error: {str(e)}")
NODE_CLASS_MAPPINGS = {
"PDOpenAIGPTImageAuthToken": PDOpenAIGPTImageAuthToken
}
NODE_DISPLAY_NAME_MAPPINGS = {
"PDOpenAIGPTImageAuthToken": "PD: GPT Image 1 & 1.5 (comfyui_AuthToken)"
}