feat(ai): enforce direct image edit contract

This commit is contained in:
chengma
2026-07-20 17:52:59 +08:00
parent 61db0f4ed6
commit 2a2cbad7bd
11 changed files with 382 additions and 94 deletions
+52 -2
View File
@@ -142,10 +142,10 @@ DEFAULT_AI_MODELS_CONFIG = {
"name": "Nano Banana 2",
"category": "image",
"enabled": True,
"url": "https://api.vectorengine.ai/v1/chat/completions",
"url": "https://api.vectorengine.ai/v1",
"model": "gemini-3.1-flash-image-preview",
"api_key": "",
"api_type": "auto",
"api_type": "images_edits",
"connect_timeout_seconds": 30,
"timeout_seconds": 0,
"extra_body": {},
@@ -1018,6 +1018,56 @@ def get_model(name, path=AI_MODELS_PATH) -> dict:
return copy.deepcopy(models[_model_index(models, name)])
def is_image_edit_model(model) -> bool:
"""Return whether a model satisfies the direct image-edit contract."""
return (
isinstance(model, dict)
and model.get("category") == "image"
and model.get("api_type") == "images_edits"
)
def image_model_config_error(model) -> str:
"""Return a Chinese actionable error for a direct image model, if any."""
if not isinstance(model, dict) or model.get("category") != "image":
return "当前模型不是图片模型"
if model.get("api_type") != "images_edits":
return "图片模型仅支持 OpenAI 图片编辑接口,请在设置中选择该接口类型"
missing = [
field
for field in ("url", "model", "api_key")
if not str(model.get(field, "") or "").strip()
]
if missing:
return "图片模型缺少必要配置:" + "、".join(missing)
url = str(model.get("url") or "").strip()
parts = urllib.parse.urlsplit(url)
if parts.scheme not in {"http", "https"} or not parts.netloc:
return "图片模型网址必须使用 http 或 https"
try:
connect_timeout = int(model.get("connect_timeout_seconds", 0) or 0)
except (TypeError, ValueError):
connect_timeout = 0
if connect_timeout <= 0:
return "图片模型连接超时必须大于 0 秒"
return ""
def check_image_model_config(name, path=AI_MODELS_PATH) -> dict:
"""Validate one image model locally without making a billable request."""
try:
model = get_model(name, path=path)
error = image_model_config_error(model)
if error:
return {"ok": False, "check_only": True, "error": error}
return {"ok": True, "check_only": True}
except Exception as exc:
return {"ok": False, "check_only": True, "error": str(exc)}
def model_request_url(model) -> str:
"""Return the HTTP endpoint used for a configured AI model."""