From 228c4c51416de1224fbbd9a1238b187645d70277 Mon Sep 17 00:00:00 2001 From: o1key <951565127@qq.com> Date: Mon, 25 May 2026 10:36:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20GPT=20Image=20=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E5=90=8D=E6=98=A0=E5=B0=84=E5=8F=8A=E5=85=A8=E5=B1=80=E6=8A=A5?= =?UTF-8?q?=E9=94=99=E6=96=87=E6=A1=88=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GPT Image 模型下拉选项映射为实际 API 参数(次卡→gpt-image-2-c,按量→gpt-image-2) - 全局:含 "high load" 关键词的错误统一展示为"模型过载,请稍后重试!" - GPT 独立:500 错误展示为"触发内容风控,或服务器繁忙!" Co-Authored-By: Claude Opus 4.7 --- clients/base_client.py | 6 +++--- clients/gpt_image_client.py | 15 ++++++++++++--- nodes/gpt_image.py | 10 +++++++--- utils/http_error.py | 17 +++++++++++++---- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/clients/base_client.py b/clients/base_client.py index be709c2..4d369f7 100644 --- a/clients/base_client.py +++ b/clients/base_client.py @@ -14,7 +14,7 @@ import time import aiohttp -from ..utils.http_error import HTTP_ERROR_MESSAGES, RETRYABLE_STATUS_CODES, _compute_delay, DEFAULT_MAX_RETRIES, DEFAULT_BASE_DELAY, DEFAULT_MAX_DELAY, DEFAULT_BACKOFF_FACTOR +from ..utils.http_error import HTTP_ERROR_MESSAGES, RETRYABLE_STATUS_CODES, _compute_delay, DEFAULT_MAX_RETRIES, DEFAULT_BASE_DELAY, DEFAULT_MAX_DELAY, DEFAULT_BACKOFF_FACTOR, get_friendly_message @@ -276,13 +276,13 @@ class BaseAPIClient(ABC): if status in HTTP_ERROR_MESSAGES: raise RuntimeError(HTTP_ERROR_MESSAGES[status]) - raise RuntimeError(error_text) + raise RuntimeError(get_friendly_message(status, error_text)) return result if last_error_status and last_error_status in HTTP_ERROR_MESSAGES: raise RuntimeError(HTTP_ERROR_MESSAGES[last_error_status]) - raise RuntimeError(last_error_text) + raise RuntimeError(get_friendly_message(last_error_status or 0, last_error_text)) except InterruptProcessingException: raise diff --git a/clients/gpt_image_client.py b/clients/gpt_image_client.py index e1852bb..585c71c 100644 --- a/clients/gpt_image_client.py +++ b/clients/gpt_image_client.py @@ -26,7 +26,12 @@ from PIL import Image from ..utils.config import get_api_key_or_raise, get_api_base_url from ..utils.image_utils import tensor_to_pil, encode_image_to_base64 -from ..utils.http_error import RETRYABLE_STATUS_CODES, HTTP_ERROR_MESSAGES, _compute_delay, DEFAULT_MAX_RETRIES, DEFAULT_BASE_DELAY, DEFAULT_MAX_DELAY, DEFAULT_BACKOFF_FACTOR +from ..utils.http_error import RETRYABLE_STATUS_CODES, HTTP_ERROR_MESSAGES, _compute_delay, DEFAULT_MAX_RETRIES, DEFAULT_BASE_DELAY, DEFAULT_MAX_DELAY, DEFAULT_BACKOFF_FACTOR, get_friendly_message + +# GPT Image 专属错误文案 +_GPT_ERROR_MESSAGES = { + 500: "触发内容风控,或服务器繁忙!", +} try: from comfy.model_management import processing_interrupted, InterruptProcessingException @@ -346,6 +351,8 @@ class GptImageClient: print(f"[o1key GPT Image] {friendly} {delay:.1f}s 后重试 ({attempt+1}/{DEFAULT_MAX_RETRIES})...") await asyncio.sleep(delay) continue + if resp.status in _GPT_ERROR_MESSAGES: + raise RuntimeError(_GPT_ERROR_MESSAGES[resp.status]) if resp.status in HTTP_ERROR_MESSAGES: raise RuntimeError(HTTP_ERROR_MESSAGES[resp.status]) try: @@ -358,7 +365,7 @@ class GptImageClient: ) except Exception: msg = text - raise RuntimeError(f"请求失败 HTTP {resp.status}: {msg}") + raise RuntimeError(get_friendly_message(resp.status, msg)) try: resp_json = json.loads(text) @@ -462,6 +469,8 @@ class GptImageClient: text = await resp.text() if resp.status != 200: + if resp.status in _GPT_ERROR_MESSAGES: + raise RuntimeError(_GPT_ERROR_MESSAGES[resp.status]) if resp.status in HTTP_ERROR_MESSAGES: raise RuntimeError(HTTP_ERROR_MESSAGES[resp.status]) try: @@ -474,7 +483,7 @@ class GptImageClient: ) except Exception: msg = text - raise RuntimeError(f"请求失败 HTTP {resp.status}: {msg}") + raise RuntimeError(get_friendly_message(resp.status, msg)) try: resp_json = json.loads(text) diff --git a/nodes/gpt_image.py b/nodes/gpt_image.py index 35f74e1..8c7393d 100644 --- a/nodes/gpt_image.py +++ b/nodes/gpt_image.py @@ -167,7 +167,11 @@ class O1keyGPTImage: # ── 2. 解析分辨率显示值 → API 参数值 ────────────────────────────────── size = "auto" if 分辨率 == "智能" else 分辨率.split("(")[0].strip() - # ── 2b. 解析质量显示值 → API 参数值 ─────────────────────────────────── + # ── 2b. 解析模型显示值 → API 参数值 ─────────────────────────────────── + _model_map = {"gpt-image-2-次卡": "gpt-image-2-c", "gpt-image-2-按量": "gpt-image-2"} + model = _model_map.get(模型, 模型) + + # ── 2c. 解析质量显示值 → API 参数值 ─────────────────────────────────── _quality_map = {"高": "high", "中": "medium", "低": "low", "自动": "auto"} quality = _quality_map.get(质量, "auto") @@ -199,7 +203,7 @@ class O1keyGPTImage: try: pil_images = client.run_sync( prompt=p, - model=模型, + model=model, quality=quality, size=size, n=生图数量, @@ -223,7 +227,7 @@ class O1keyGPTImage: try: pil_images = client.run_sync( prompt=prompt, - model=模型, + model=model, quality=quality, size=size, n=生图数量, diff --git a/utils/http_error.py b/utils/http_error.py index 23d7810..488f05c 100644 --- a/utils/http_error.py +++ b/utils/http_error.py @@ -26,6 +26,11 @@ HTTP_ERROR_MESSAGES = { 504: "网关超时。请稍后重试。", } +# 错误内容关键词 → 用户友好文案(优先于状态码匹配) +ERROR_CONTENT_MESSAGES = { + "The current model has a high load": "模型过载,请稍后重试!", +} + # 可退避重试的状态码 RETRYABLE_STATUS_CODES = {429, 502, 503, 504} @@ -37,7 +42,11 @@ DEFAULT_BACKOFF_FACTOR = 2.0 # 指数退避因子 def get_friendly_message(status_code: int, raw_message: str = "") -> str: - """根据状态码返回友好文案,未匹配则返回原始信息""" + """根据状态码/错误内容返回友好文案,未匹配则返回原始信息""" + if raw_message: + for keyword, friendly_msg in ERROR_CONTENT_MESSAGES.items(): + if keyword in raw_message: + return friendly_msg friendly = HTTP_ERROR_MESSAGES.get(status_code) if friendly: return friendly @@ -119,7 +128,7 @@ async def async_request_with_retry( break if last_status and last_status in HTTP_ERROR_MESSAGES: - raise_for_status(last_status, prefix=prefix) + raise_for_status(last_status, raw_message=last_message, prefix=prefix) - raw_msg = last_message[:200] if last_message else "" - raise RuntimeError(f"{prefix}请求失败 ({last_status}): {raw_msg}") + friendly = get_friendly_message(last_status or 0, last_message) + raise RuntimeError(f"{prefix}{friendly}")