fix: distinguish image connection and generation checks

This commit is contained in:
Codex
2026-08-01 23:55:56 +08:00
parent 52d877836c
commit 922f8f4f2a
5 changed files with 134 additions and 18 deletions
+15 -1
View File
@@ -86,7 +86,21 @@ async def test_model_generation(
store: EncryptedSettingsStore = Depends(get_runtime_store),
) -> RuntimeSettingsTestResult:
try:
return await test_image_generation(store.merged_values(), model_id)
values = store.merged_values()
result = await test_image_generation(values, model_id)
store.record_test(result, values)
definitive_result = RuntimeSettingsTestResult(
target=f"model:{model_id}",
ok=result.ok,
message=(
result.message
if not result.ok
else "已通过一次真实生图端到端验证;模型、鉴权、请求参数、任务轮询和结果读取均可用。"
),
details=result.details,
)
store.record_test(definitive_result, values)
return result
except (RuntimeError, ValueError) as exc:
return RuntimeSettingsTestResult(
target=f"generation:{model_id}",
+49 -13
View File
@@ -342,7 +342,9 @@ class EncryptedSettingsStore:
document["tests"] = {
target: result
for target, result in document["tests"].items()
if not target.startswith("model:") or target.removeprefix("model:") in current_ids
if not (
target.startswith("model:") or target.startswith("generation:")
) or target.split(":", 1)[1] in current_ids
}
self.save_document(document)
@@ -525,8 +527,8 @@ class EncryptedSettingsStore:
) -> dict[str, dict[str, Any]]:
current: dict[str, dict[str, Any]] = {}
for target, result in tests.items():
if target.startswith("model:"):
model_id = target.removeprefix("model:")
if target.startswith("model:") or target.startswith("generation:"):
model_id = target.split(":", 1)[1]
if not any(item.get("id") == model_id for item in values.get("model_pool", [])):
continue
item = dict(result)
@@ -542,8 +544,8 @@ class EncryptedSettingsStore:
"database_url": self.bootstrap.database_url,
"redis_url": self.bootstrap.redis_url,
}
elif target.startswith("model:"):
model_id = target.removeprefix("model:")
elif target.startswith("model:") or target.startswith("generation:"):
model_id = target.split(":", 1)[1]
relevant = next(
(item for item in values.get("model_pool", []) if item.get("id") == model_id),
{"id": model_id, "missing": True},
@@ -742,7 +744,34 @@ async def test_model_pool_item(values: dict[str, Any], model_id: str) -> Runtime
for candidate in rows
if isinstance(candidate, dict) and candidate.get("id")
}
protocol_error = _validate_image_protocol(item)
if protocol_error:
return RuntimeSettingsTestResult(
target=target,
ok=False,
message=f"模型“{name}”的生图协议配置不正确:{protocol_error}",
details={"model_id": item["model_id"], "model_count": len(listed_ids)},
)
is_aigc_media = (
"image_generation" in item.get("capabilities", [])
and item.get("image_protocol") == "aigc_media"
)
if not listed_ids:
if is_aigc_media:
return RuntimeSettingsTestResult(
target=target,
ok=True,
message=(
f"模型“{name}”的 API Key 与模型列表接口连接正常;平台未在 /v1/models 中公开媒体模型 ID"
f"{item['model_id']}”,这里只完成连接与鉴权验证。最终可用性以“试生成”为准。"
),
details={
"model_id": item["model_id"],
"model_count": 0,
"id_advertised": False,
"verification": "connectivity_only",
},
)
return RuntimeSettingsTestResult(
target=target,
ok=False,
@@ -750,20 +779,27 @@ async def test_model_pool_item(values: dict[str, Any], model_id: str) -> Runtime
details={"model_id": item["model_id"], "model_count": 0},
)
if item["model_id"] not in listed_ids:
if is_aigc_media:
return RuntimeSettingsTestResult(
target=target,
ok=True,
message=(
f"模型“{name}”的 API Key 与模型列表接口连接正常;平台返回了 {len(listed_ids)} 个模型,"
f"但未公开媒体模型 ID“{item['model_id']}”。这不是生图失败,最终可用性以“试生成”为准。"
),
details={
"model_id": item["model_id"],
"model_count": len(listed_ids),
"id_advertised": False,
"verification": "connectivity_only",
},
)
return RuntimeSettingsTestResult(
target=target,
ok=False,
message=f"模型“{name}”测试失败:账号模型列表中未找到 ID“{item['model_id']}”。",
details={"model_id": item["model_id"], "model_count": len(listed_ids)},
)
protocol_error = _validate_image_protocol(item)
if protocol_error:
return RuntimeSettingsTestResult(
target=target,
ok=False,
message=f"模型“{name}”的 ID 可用,但生图协议配置不正确:{protocol_error}",
details={"model_id": item["model_id"], "model_count": len(listed_ids)},
)
return RuntimeSettingsTestResult(
target=target,
ok=True,
+65
View File
@@ -1,6 +1,7 @@
import pytest
from app.integrations.openai_compatible import OpenAICompatibleGateway
from app.runtime_settings import RuntimeSettingsTestResult, test_model_pool_item as run_model_pool_test
def image_values(profile: str, model_id: str) -> dict:
@@ -110,3 +111,67 @@ async def test_aigc_media_polls_task_until_result_url(monkeypatch) -> None:
assert result["state"] == "success"
assert result["data"] == [{"url": "https://cdn.example.com/final.png"}]
@pytest.mark.asyncio
async def test_aigc_media_connection_accepts_model_list_omission(monkeypatch) -> None:
class FakeResponse:
def raise_for_status(self) -> None:
return None
def json(self) -> dict:
return {"data": [{"id": "language-model-only"}]}
class FakeClient:
async def __aenter__(self):
return self
async def __aexit__(self, *args) -> None:
return None
async def get(self, *args, **kwargs) -> FakeResponse:
return FakeResponse()
monkeypatch.setattr("app.runtime_settings.httpx.AsyncClient", lambda **kwargs: FakeClient())
result = await run_model_pool_test(
image_values("gpt_image_2", "gpt-image-2"),
"image",
)
assert result.ok is True
assert result.details["id_advertised"] is False
assert result.details["verification"] == "connectivity_only"
assert "最终可用性以“试生成”为准" in result.message
@pytest.mark.asyncio
async def test_generation_endpoint_records_definitive_model_result(monkeypatch) -> None:
from app.api.settings import test_model_generation
class FakeStore:
def __init__(self) -> None:
self.recorded: list[RuntimeSettingsTestResult] = []
def merged_values(self) -> dict:
return image_values("gpt_image_2", "gpt-image-2")
def record_test(self, result: RuntimeSettingsTestResult, values: dict) -> None:
self.recorded.append(result)
async def fake_generation(values: dict, model_id: str) -> RuntimeSettingsTestResult:
return RuntimeSettingsTestResult(
target=f"generation:{model_id}",
ok=True,
message="端到端可用",
)
monkeypatch.setattr("app.api.settings.test_image_generation", fake_generation)
store = FakeStore()
result = await test_model_generation("image", store=store)
assert result.ok is True
assert [item.target for item in store.recorded] == ["generation:image", "model:image"]
assert store.recorded[1].ok is True
assert "真实生图端到端验证" in store.recorded[1].message