fix: OpenAI节点URL被截断报错及无图像时不调用API的问题
1. 修复ComfyUI前端吞掉URL中'//'导致 Invalid URL 'https:' 报错 - 新增 _fix_url() 函数,在请求前自动补回被吞的'//' 2. 修复无图像输入时节点直接返回user_prompt而不调用API的问题 - 有图像时:多模态格式(image_url+text)发送请求 - 无图像+有prompt时:纯文本模式正常调用API对话 - 无图像+无prompt时:返回明确的中文错误提示 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
a62c731252
commit
4b61f92262
+60
-30
@@ -4,6 +4,7 @@ import json
|
||||
import base64
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
from PIL import Image
|
||||
|
||||
# 快速解决方案:清除可能导致连接错误的代理环境变量
|
||||
@@ -17,6 +18,20 @@ os.environ['HTTPS_PROXY'] = ''
|
||||
os.environ['http_proxy'] = ''
|
||||
os.environ['https_proxy'] = ''
|
||||
|
||||
|
||||
def _fix_url(url: str) -> str:
|
||||
"""
|
||||
修复 ComfyUI 前端吞掉 URL 中 '//' 的问题。
|
||||
例如:
|
||||
'https:api.openai.com/v1/...' -> 'https://api.openai.com/v1/...'
|
||||
'https:' -> 原样返回(后续会报更清晰的错误)
|
||||
'https://api.openai.com/v1/...' -> 不变
|
||||
"""
|
||||
url = url.strip()
|
||||
# 匹配 http: 或 https: 后面紧跟的不是 // 的情况
|
||||
fixed = re.sub(r'^(https?:)(?!//)', r'\1//', url)
|
||||
return fixed
|
||||
|
||||
class OpenAINode:
|
||||
"""
|
||||
OpenAI API 节点:
|
||||
@@ -130,9 +145,14 @@ class OpenAINode:
|
||||
proxy_url=""
|
||||
):
|
||||
"""
|
||||
调用 OpenAI API 生成内容
|
||||
调用 OpenAI API 生成内容。
|
||||
- 有图像时:使用多模态格式(image_url + text)发送请求
|
||||
- 无图像时:使用纯文本格式发送请求,实现普通对话
|
||||
"""
|
||||
|
||||
# ---- 修复 URL:ComfyUI 前端可能吞掉 '//' ----
|
||||
api_url = _fix_url(api_url)
|
||||
|
||||
all_images = [
|
||||
img for img in [
|
||||
image_1,
|
||||
@@ -144,43 +164,53 @@ class OpenAINode:
|
||||
] if img is not None
|
||||
]
|
||||
|
||||
if not all_images:
|
||||
return (user_prompt if user_prompt.strip() else "(未提供图片和描述)",)
|
||||
|
||||
# ---- 构造 messages ----
|
||||
messages = [
|
||||
{"role": "system", "content": system_prompt}
|
||||
]
|
||||
|
||||
user_content = []
|
||||
if all_images:
|
||||
# 多模态模式:图像 + 文本
|
||||
user_content = []
|
||||
|
||||
if user_prompt:
|
||||
user_content.append({
|
||||
"type": "text",
|
||||
"text": user_prompt
|
||||
if user_prompt:
|
||||
user_content.append({
|
||||
"type": "text",
|
||||
"text": user_prompt
|
||||
})
|
||||
|
||||
for image in all_images:
|
||||
img_tensor = image[0]
|
||||
img_base64 = self._encode_image_tensor(img_tensor, image_max_size)
|
||||
user_content.append({
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": f"data:image/jpeg;base64,{img_base64}",
|
||||
"detail": detail
|
||||
}
|
||||
})
|
||||
|
||||
if not user_content:
|
||||
user_content.append({
|
||||
"type": "text",
|
||||
"text": " "
|
||||
})
|
||||
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": user_content
|
||||
})
|
||||
else:
|
||||
# 纯文本模式:无图像,直接发送文本对话
|
||||
prompt_text = user_prompt.strip() if user_prompt else ""
|
||||
if not prompt_text:
|
||||
return ("(错误:未提供图片也未提供提示词,请至少输入 user_prompt)",)
|
||||
|
||||
for image in all_images:
|
||||
img_tensor = image[0]
|
||||
img_base64 = self._encode_image_tensor(img_tensor, image_max_size)
|
||||
user_content.append({
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": f"data:image/jpeg;base64,{img_base64}",
|
||||
"detail": detail
|
||||
}
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": prompt_text
|
||||
})
|
||||
|
||||
if not user_content:
|
||||
user_content.append({
|
||||
"type": "text",
|
||||
"text": " "
|
||||
})
|
||||
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": user_content
|
||||
})
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {api_key}"
|
||||
@@ -211,7 +241,7 @@ class OpenAINode:
|
||||
return (content,)
|
||||
else:
|
||||
return (f"Error: API response format unexpected. Response: {json.dumps(result)}",)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
return (f"Error calling OpenAI API: {str(e)}",)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user