auto-save 2026-05-18 01:02 (~2)

This commit is contained in:
2026-05-18 01:02:30 +08:00
parent 34ecab42ba
commit 4c43d89346
2 changed files with 27 additions and 40 deletions

View File

@@ -50,18 +50,14 @@ LOCAL_ASR_TIMEOUT_SECONDS = max(30, int(os.getenv("LOCAL_ASR_TIMEOUT_SECONDS", "
TRANSLATE_MODEL = os.getenv("TRANSLATE_MODEL", "gemini-2.5-flash")
REWRITE_MODEL = os.getenv("REWRITE_MODEL", "gemini-2.5-pro")
VISION_MODEL = os.getenv("VISION_MODEL", "gemini-2.5-flash")
GPT_IMAGE_MODEL = os.getenv("GPT_IMAGE_MODEL", "gpt-image-2").strip() or "gpt-image-2"
IMAGE_BASE_URL = os.getenv("IMAGE_BASE_URL", LLM_BASE_URL).strip()
IMAGE_API_KEY = os.getenv("IMAGE_API_KEY", LLM_API_KEY).strip()
IMAGE_MODEL = os.getenv("IMAGE_MODEL", GPT_IMAGE_MODEL).strip() or GPT_IMAGE_MODEL
SUBJECT_ASSET_IMAGE_MODEL = os.getenv("SUBJECT_ASSET_IMAGE_MODEL", GPT_IMAGE_MODEL).strip() or GPT_IMAGE_MODEL
SUBJECT_ASSET_IMAGE_MODELS = [
m.strip()
for m in os.getenv("SUBJECT_ASSET_IMAGE_MODELS", f"{SUBJECT_ASSET_IMAGE_MODEL},gpt-image-1.5").split(",")
if m.strip()
]
if SUBJECT_ASSET_IMAGE_MODEL not in SUBJECT_ASSET_IMAGE_MODELS:
SUBJECT_ASSET_IMAGE_MODELS.insert(0, SUBJECT_ASSET_IMAGE_MODEL)
# Product decision: every image-generation/editing path is locked to gpt-image-2.
# Environment variables may still choose the gateway URL/key, but not the model.
GPT_IMAGE_MODEL = "gpt-image-2"
IMAGE_MODEL = GPT_IMAGE_MODEL
SUBJECT_ASSET_IMAGE_MODEL = GPT_IMAGE_MODEL
SUBJECT_ASSET_IMAGE_MODELS = [GPT_IMAGE_MODEL]
PRODUCT_ASSET_MAX_SIDE = max(1024, int(os.getenv("PRODUCT_ASSET_MAX_SIDE", "1600")))
PRODUCT_ASSET_MIN_LONG_SIDE = max(512, int(os.getenv("PRODUCT_ASSET_MIN_LONG_SIDE", "900")))
PRODUCT_ASSET_MIN_SHORT_SIDE = max(320, int(os.getenv("PRODUCT_ASSET_MIN_SHORT_SIDE", "600")))
@@ -2545,9 +2541,8 @@ def _image_edit_call(
"""通用 image edit 调用 · 失败重试 + 可选 text fallback。
返回 (image_bytes, effective_mode) where effective_mode in {"edit","text"}。
失败 raise RuntimeError。
输入图自动 resize 到 max_side默认 1024边长后再 base64,避免大图把 Gemini
function call 输入挤超阈值导致 incomplete_generation。
models: 多模型轮换列表,重试时换 model不传则单一 model 重试。"""
输入图自动 resize 到 max_side默认 1024边长后再 base64
生图模型按产品规则强制使用 gpt-image-2model/models 参数只保留兼容旧调用。"""
import base64 as b64lib
import io as _io
import time as _time
@@ -2555,12 +2550,8 @@ def _image_edit_call(
from PIL import Image as _PILImage
if not IMAGE_API_KEY:
raise RuntimeError("IMAGE_API_KEY 或 LLM_API_KEY 未配置")
# model 优先级models 列表 > 单个 model 参数 > IMAGE_MODEL
if models and len(models) > 0:
models_cycle = list(models)
else:
models_cycle = [model or IMAGE_MODEL]
model = models_cycle[0]
models_cycle = [GPT_IMAGE_MODEL]
model = GPT_IMAGE_MODEL
# 缩到 max_side 内
try:
im = _PILImage.open(image_path)
@@ -2583,7 +2574,6 @@ def _image_edit_call(
resp_data: dict = {}
effective_mode = "edit"
for attempt, current_mode in enumerate(plan):
# 多模型轮换:第 N 次重试用第 N 个 model不够时用最后一个
current_model = models_cycle[min(attempt, len(models_cycle) - 1)]
try:
if current_mode == "edit":
@@ -2609,7 +2599,6 @@ def _image_edit_call(
last_err = f"empty data · {err_obj.get('code', '')} · {str(err_obj.get('message', ''))[:200]} · model={current_model}"
except httpx.HTTPStatusError as e:
body = e.response.text
# 多模型轮换场景除明确不可恢复4xx 鉴权类)外都重试换 model
sc = e.response.status_code
fatal = sc in (401, 403)
last_err = f"HTTP {sc}: {body[:200]} · model={current_model}"
@@ -2619,8 +2608,7 @@ def _image_edit_call(
last_err = f"{type(e).__name__}: {e} · model={current_model}"
if attempt < len(plan) - 1:
next_model = models_cycle[min(attempt + 1, len(models_cycle) - 1)]
tag = f"retry {attempt + 1}/{len(plan)}{next_model}"
tag = f"retry {attempt + 1}/{len(plan)}{GPT_IMAGE_MODEL}"
print(f"[image edit {tag}] {last_err}", flush=True)
_time.sleep(1.0)
@@ -2639,12 +2627,12 @@ def _image_text_call(
models: list[str] | None = None,
max_attempts: int = 3,
) -> tuple[bytes, str]:
"""Text-only image generation with light model rotation."""
"""Text-only image generation. 生图模型强制使用 gpt-image-2。"""
import base64 as b64lib
import time as _time
if not IMAGE_API_KEY:
raise RuntimeError("IMAGE_API_KEY 或 LLM_API_KEY 未配置")
models_cycle = list(models) if models else [model or IMAGE_MODEL]
models_cycle = [GPT_IMAGE_MODEL]
last_err = ""
resp_data: dict = {}
for attempt in range(max_attempts):
@@ -2661,8 +2649,7 @@ def _image_text_call(
except Exception as e:
last_err = f"{type(e).__name__}: {e} · model={current_model}"
if attempt < max_attempts - 1:
next_model = models_cycle[min(attempt + 1, len(models_cycle) - 1)]
print(f"[image text retry {attempt + 1}/{max_attempts}{next_model}] {last_err}", flush=True)
print(f"[image text retry {attempt + 1}/{max_attempts}{GPT_IMAGE_MODEL}] {last_err}", flush=True)
_time.sleep(1.0)
raise RuntimeError(f"image text failed after {max_attempts} attempts: {last_err}")