```
feat(api): 移除gpt-image-2参考图强制验证并优化图像处理逻辑 移除对gpt-image-2模型的参考图上传强制验证,支持无参考图时调用生成接口, 同时优化图像URL提取和处理逻辑以支持不同响应格式 BREAKING CHANGE: gpt-image-2不再强制要求上传参考图 ```
This commit is contained in:
parent
3610bedb39
commit
3df902963d
@ -91,17 +91,15 @@ def generate():
|
|||||||
|
|
||||||
image_data = data.get("image_data", [])
|
image_data = data.get("image_data", [])
|
||||||
if model_value == "gpt-image-2":
|
if model_value == "gpt-image-2":
|
||||||
if not image_data:
|
|
||||||
return jsonify({"error": "gpt-image-2 编辑模式至少需要上传 1 张参考图"}), 400
|
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
"prompt": prompt,
|
"prompt": prompt,
|
||||||
"model": model_value,
|
"model": model_value,
|
||||||
"images": [{"image_url": img} for img in image_data],
|
|
||||||
"size": data.get("size") or "2048x2048",
|
"size": data.get("size") or "2048x2048",
|
||||||
"quality": "high",
|
"quality": "high",
|
||||||
"output_format": "png",
|
"output_format": "png",
|
||||||
}
|
}
|
||||||
|
if image_data:
|
||||||
|
payload["images"] = [{"image_url": img} for img in image_data]
|
||||||
else:
|
else:
|
||||||
payload = {
|
payload = {
|
||||||
"prompt": prompt,
|
"prompt": prompt,
|
||||||
|
|||||||
@ -37,6 +37,7 @@ class Config:
|
|||||||
CHAT_API = f"{AI_BASE_URL}/v1/chat/completions"
|
CHAT_API = f"{AI_BASE_URL}/v1/chat/completions"
|
||||||
VIDEO_GEN_API = f"{AI_BASE_URL}/v2/videos/generations"
|
VIDEO_GEN_API = f"{AI_BASE_URL}/v2/videos/generations"
|
||||||
VIDEO_POLL_API = f"{AI_BASE_URL}/v2/videos/generations/{{task_id}}"
|
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_API = "https://nas.4x4g.com:8317/v1/images/edits"
|
||||||
GPT_IMAGE_EDIT_KEY = "sk-vDmmYNzoe7UjWskKx"
|
GPT_IMAGE_EDIT_KEY = "sk-vDmmYNzoe7UjWskKx"
|
||||||
|
|
||||||
|
|||||||
@ -34,12 +34,18 @@ def validate_generation_request(user, data):
|
|||||||
model_value = data.get("model")
|
model_value = data.get("model")
|
||||||
is_gemini_flash_image_preview = model_value == "gemini-3.1-flash-image-preview"
|
is_gemini_flash_image_preview = model_value == "gemini-3.1-flash-image-preview"
|
||||||
is_gpt_image_edit = model_value == "gpt-image-2"
|
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):
|
if isinstance(is_premium, str):
|
||||||
is_premium = is_premium.lower() in ("1", "true", "yes", "on")
|
is_premium = is_premium.lower() in ("1", "true", "yes", "on")
|
||||||
|
|
||||||
# gpt-image-2 走独立的 edits 接口,其余模型沿用现有 generations 接口
|
# gpt-image-2 有参考图走 edits,无参考图走 generations;其它模型沿用现有 generations 接口
|
||||||
target_api = Config.GPT_IMAGE_EDIT_API if is_gpt_image_edit else Config.AI_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.AI_API
|
||||||
|
)
|
||||||
api_key = None
|
api_key = None
|
||||||
use_trial = False
|
use_trial = False
|
||||||
|
|
||||||
@ -70,7 +76,11 @@ def validate_generation_request(user, data):
|
|||||||
else:
|
else:
|
||||||
api_key = Config.TRIAL_KEY
|
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
|
use_trial = True
|
||||||
|
|
||||||
# 计算本次任务消耗
|
# 计算本次任务消耗
|
||||||
|
|||||||
@ -150,6 +150,14 @@ def _extract_b64_images(result):
|
|||||||
return images
|
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):
|
def _process_gpt_image_edit(app, user_id, task_id, payload, api_key, target_api, cost, use_trial):
|
||||||
headers = {
|
headers = {
|
||||||
"Authorization": f"Bearer {api_key}",
|
"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()
|
result = response.json()
|
||||||
b64_images = _extract_b64_images(result)
|
b64_images = _extract_b64_images(result)
|
||||||
if not b64_images:
|
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 = []
|
processed_data = []
|
||||||
final_urls = []
|
final_urls = []
|
||||||
|
|||||||
@ -552,18 +552,6 @@ document.getElementById('submitBtn').onclick = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UI 锁定
|
// 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;
|
btn.disabled = true;
|
||||||
const btnText = btn.querySelector('span');
|
const btnText = btn.querySelector('span');
|
||||||
btnText.innerText = uploadedFiles.length > 0 ? "正在同步参考图..." : "正在开启 AI 引擎...";
|
btnText.innerText = uploadedFiles.length > 0 ? "正在同步参考图..." : "正在开启 AI 引擎...";
|
||||||
|
|||||||
@ -664,11 +664,6 @@
|
|||||||
const num = parseInt(document.getElementById('numSelect').value);
|
const num = parseInt(document.getElementById('numSelect').value);
|
||||||
const isPremium = document.getElementById('isPremium').checked;
|
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');
|
||||||
document.getElementById('placeholder').classList.add('hidden');
|
document.getElementById('placeholder').classList.add('hidden');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user