更新生成接口,支持上传参考图并使用 URL 代替 Base64 格式

This commit is contained in:
公司git 2026-07-16 11:38:43 +08:00
parent efaa26314c
commit bc05afbcb0
2 changed files with 51 additions and 50 deletions

View File

@ -1,5 +1,5 @@
from flask import Blueprint, request, jsonify, session, current_app
from urllib.parse import unquote, urlparse
from urllib.parse import unquote, urljoin, urlparse
from config import Config
from extensions import db, redis_client, s3_client
from models import User, SavedPrompt
@ -72,6 +72,34 @@ def generate():
user = db.session.get(User, user_id)
data = request.json if request.is_json else request.form
image_urls = data.get(
"image",
data.get("image_urls", data.get("image_data", [])),
) or []
if isinstance(image_urls, str):
image_urls = [image_urls]
elif not isinstance(image_urls, (list, tuple)):
return jsonify({"error": "参考图地址格式无效"}), 400
normalized_image_urls = []
for image_url in image_urls:
if not isinstance(image_url, str) or not image_url.strip():
return jsonify({"error": "参考图地址无效"}), 400
image_url = image_url.strip()
parsed_input = urlparse(image_url)
if image_url.startswith("/"):
absolute_url = urljoin(request.url_root, image_url)
elif parsed_input.scheme in ("http", "https") and parsed_input.netloc:
absolute_url = image_url
else:
return jsonify({"error": "参考图必须使用 HTTP(S) URL不能使用 Base64"}), 400
parsed_url = urlparse(absolute_url)
if parsed_url.scheme not in ("http", "https") or not parsed_url.netloc:
return jsonify({"error": "参考图必须使用 HTTP(S) URL不能使用 Base64"}), 400
normalized_image_urls.append(absolute_url)
api_key, target_api, cost, use_trial, error = validate_generation_request(user, data)
if error:
return jsonify({"error": error}), 400
@ -92,7 +120,6 @@ def generate():
)
return jsonify(result), status_code
image_data = data.get("image_data", [])
if model_value == "gpt-image-2":
payload = {
"prompt": prompt,
@ -101,8 +128,8 @@ def generate():
"size": data.get("size") or "2048x2048",
"quality": "high",
}
if image_data:
payload["image"] = [img.split(",", 1)[1] if "," in img else img for img in image_data]
if normalized_image_urls:
payload["image"] = normalized_image_urls
else:
payload = {
"prompt": prompt,
@ -110,8 +137,8 @@ def generate():
"response_format": "url",
"aspect_ratio": data.get("ratio"),
}
if image_data:
payload["image"] = [img.split(",", 1)[1] if "," in img else img for img in image_data]
if normalized_image_urls:
payload["image"] = normalized_image_urls
if model_value in ("nano-banana-2", "gemini-3.1-flash-image-preview") and data.get("size"):
payload["image_size"] = data.get("size")

View File

@ -713,53 +713,27 @@ document.getElementById('submitBtn').onclick = async () => {
currentGeneratedUrls = []; // 重置当前生成列表
try {
let image_data = [];
let image = [];
// 1. 将图片转换为 Base64 (并压缩过大图片)
// 1. 上传参考图,生图接口统一使用 URL
if (uploadedFiles.length > 0) {
btnText.innerText = "正在准备图片数据...";
const processImageFile = (file) => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
const img = new Image();
img.onload = () => {
const maxDim = 2048;
let w = img.width;
let h = img.height;
btnText.innerText = "正在上传参考图...";
const formData = new FormData();
uploadedFiles.forEach(file => formData.append('images', file));
if (w <= maxDim && h <= maxDim) {
resolve(e.target.result);
return;
}
if (w > h) {
if (w > maxDim) {
h = Math.round(h * (maxDim / w));
w = maxDim;
}
} else {
if (h > maxDim) {
w = Math.round(w * (maxDim / h));
h = maxDim;
}
}
const canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, w, h);
// 保持原格式,如果不是 png 则默认 jpeg (0.9 质量)
const outType = file.type === 'image/png' ? 'image/png' : 'image/jpeg';
resolve(canvas.toDataURL(outType, 0.9));
};
img.onerror = reject;
img.src = e.target.result;
};
reader.onerror = reject;
reader.readAsDataURL(file);
const uploadResponse = await fetch('/api/upload', {
method: 'POST',
body: formData
});
image_data = await Promise.all(uploadedFiles.map(f => processImageFile(f)));
const uploadResult = await uploadResponse.json();
if (!uploadResponse.ok || uploadResult.error) {
throw new Error(uploadResult.error || '参考图上传失败');
}
image = (uploadResult.urls || []).map(url => new URL(url, window.location.origin).href);
if (image.length !== uploadedFiles.length) {
throw new Error('部分参考图上传失败');
}
}
// 2. 并行启动多个生成任务
@ -785,7 +759,7 @@ document.getElementById('submitBtn').onclick = async () => {
model: document.getElementById('modelSelect').value,
ratio: document.getElementById('modelSelect').value === GPT_IMAGE_EDIT_MODEL ? undefined : document.getElementById('ratioSelect').value,
size: document.getElementById('sizeSelect').value,
image_data // 发送 Base64 数组
image
})
});
const res = await r.json();