From 3df902963d365003d5981c1a06f8fac92c90cfac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=AC=E5=8F=B8git?= <240241002@qq.com> Date: Sun, 26 Apr 2026 09:49:31 +0800 Subject: [PATCH] =?UTF-8?q?```=20feat(api):=20=E7=A7=BB=E9=99=A4gpt-image-?= =?UTF-8?q?2=E5=8F=82=E8=80=83=E5=9B=BE=E5=BC=BA=E5=88=B6=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E5=B9=B6=E4=BC=98=E5=8C=96=E5=9B=BE=E5=83=8F=E5=A4=84?= =?UTF-8?q?=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除对gpt-image-2模型的参考图上传强制验证,支持无参考图时调用生成接口, 同时优化图像URL提取和处理逻辑以支持不同响应格式 BREAKING CHANGE: gpt-image-2不再强制要求上传参考图 ``` --- blueprints/api.py | 6 ++---- config.py | 1 + services/generation_service.py | 16 +++++++++++++--- services/task_service.py | 31 ++++++++++++++++++++++++++++++- static/js/main.js | 12 ------------ templates/mobile.html | 5 ----- 6 files changed, 46 insertions(+), 25 deletions(-) diff --git a/blueprints/api.py b/blueprints/api.py index f810614..f9785cf 100644 --- a/blueprints/api.py +++ b/blueprints/api.py @@ -91,17 +91,15 @@ def generate(): image_data = data.get("image_data", []) if model_value == "gpt-image-2": - if not image_data: - return jsonify({"error": "gpt-image-2 编辑模式至少需要上传 1 张参考图"}), 400 - payload = { "prompt": prompt, "model": model_value, - "images": [{"image_url": img} for img in image_data], "size": data.get("size") or "2048x2048", "quality": "high", "output_format": "png", } + if image_data: + payload["images"] = [{"image_url": img} for img in image_data] else: payload = { "prompt": prompt, diff --git a/config.py b/config.py index adb8504..7a30b66 100644 --- a/config.py +++ b/config.py @@ -37,6 +37,7 @@ class Config: CHAT_API = f"{AI_BASE_URL}/v1/chat/completions" VIDEO_GEN_API = f"{AI_BASE_URL}/v2/videos/generations" VIDEO_POLL_API = f"{AI_BASE_URL}/v2/videos/generations/{{task_id}}" + GPT_IMAGE_GENERATION_API = "https://nas.4x4g.com:8317/v1/images/generations" GPT_IMAGE_EDIT_API = "https://nas.4x4g.com:8317/v1/images/edits" GPT_IMAGE_EDIT_KEY = "sk-vDmmYNzoe7UjWskKx" diff --git a/services/generation_service.py b/services/generation_service.py index 09ad31b..77317f5 100644 --- a/services/generation_service.py +++ b/services/generation_service.py @@ -34,12 +34,18 @@ def validate_generation_request(user, data): model_value = data.get("model") is_gemini_flash_image_preview = model_value == "gemini-3.1-flash-image-preview" is_gpt_image_edit = model_value == "gpt-image-2" + image_data = data.get("image_data", []) + has_reference_images = bool(image_data) if isinstance(is_premium, str): is_premium = is_premium.lower() in ("1", "true", "yes", "on") - # gpt-image-2 走独立的 edits 接口,其余模型沿用现有 generations 接口 - target_api = Config.GPT_IMAGE_EDIT_API if is_gpt_image_edit else Config.AI_API + # gpt-image-2 有参考图走 edits,无参考图走 generations;其它模型沿用现有 generations 接口 + target_api = ( + (Config.GPT_IMAGE_EDIT_API if has_reference_images else Config.GPT_IMAGE_GENERATION_API) + if is_gpt_image_edit + else Config.AI_API + ) api_key = None use_trial = False @@ -70,7 +76,11 @@ def validate_generation_request(user, data): else: api_key = Config.TRIAL_KEY - target_api = Config.GPT_IMAGE_EDIT_API if is_gpt_image_edit else Config.TRIAL_API + target_api = ( + (Config.GPT_IMAGE_EDIT_API if has_reference_images else Config.GPT_IMAGE_GENERATION_API) + if is_gpt_image_edit + else Config.TRIAL_API + ) use_trial = True # 计算本次任务消耗 diff --git a/services/task_service.py b/services/task_service.py index bf554b8..98cea5c 100644 --- a/services/task_service.py +++ b/services/task_service.py @@ -150,6 +150,14 @@ def _extract_b64_images(result): return images +def _extract_image_urls(result): + urls = [] + for item in result.get("data", []) or []: + if isinstance(item, dict) and item.get("url"): + urls.append(item["url"]) + return urls + + def _process_gpt_image_edit(app, user_id, task_id, payload, api_key, target_api, cost, use_trial): headers = { "Authorization": f"Bearer {api_key}", @@ -173,7 +181,28 @@ def _process_gpt_image_edit(app, user_id, task_id, payload, api_key, target_api, result = response.json() b64_images = _extract_b64_images(result) if not b64_images: - raise Exception("gpt-image-2 未返回可用图片数据") + url_images = _extract_image_urls(result) + if not url_images: + raise Exception("gpt-image-2 未返回可用图片数据") + + processed_data = [{"url": image_url, "thumb": image_url} for image_url in url_images] + new_record = GenerationRecord( + user_id=user_id, + prompt=payload.get("prompt"), + model=payload.get("model"), + cost=cost, + image_urls=json.dumps(processed_data), + ) + db.session.add(new_record) + db.session.commit() + + system_logger.info("gpt-image-2 生图任务完成", user_id=user_id, task_id=task_id, model=payload.get("model")) + redis_client.setex( + f"task:{task_id}", + 3600, + json.dumps({"status": "complete", "urls": url_images, "record_id": new_record.id}), + ) + return processed_data = [] final_urls = [] diff --git a/static/js/main.js b/static/js/main.js index 5b577d2..bd7641b 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -552,18 +552,6 @@ document.getElementById('submitBtn').onclick = async () => { } // UI 锁定 - if (document.getElementById('modelSelect').value === GPT_IMAGE_EDIT_MODEL && uploadedFiles.length === 0) { - return showToast('gpt-image-2 requires a reference image', 'warning'); - } - - if (document.getElementById('modelSelect').value === GPT_IMAGE_EDIT_MODEL && uploadedFiles.length === 0) { - return showToast('gpt-image-2 妯″瀷蹇呴』涓婁紶鍙傝€冨浘', 'warning'); - } - - if (document.getElementById('modelSelect').value === GPT_IMAGE_EDIT_MODEL && uploadedFiles.length === 0) { - return showToast('gpt-image-2 requires a reference image', 'warning'); - } - btn.disabled = true; const btnText = btn.querySelector('span'); btnText.innerText = uploadedFiles.length > 0 ? "正在同步参考图..." : "正在开启 AI 引擎..."; diff --git a/templates/mobile.html b/templates/mobile.html index 88b2870..55ec853 100644 --- a/templates/mobile.html +++ b/templates/mobile.html @@ -664,11 +664,6 @@ const num = parseInt(document.getElementById('numSelect').value); const isPremium = document.getElementById('isPremium').checked; - if (model === GPT_IMAGE_EDIT_MODEL && uploadedFiles.length === 0) { - showToast('gpt-image-2 模型必须上传参考图', 'warning'); - return; - } - // 显示加载状态 document.getElementById('placeholder').classList.add('hidden'); document.getElementById('placeholder').classList.add('hidden');