Files
wehub-resource-sync cddb07a176
docs / deploy (push) Has been cancelled
docs / changes (push) Has been cancelled
docs / check-and-build (push) Has been cancelled
build container image / cpu (push) Has been cancelled
build container image / cuda (push) Has been cancelled
build container image / rocm (push) Has been cancelled
frontend checks / frontend-checks (push) Has been cancelled
frontend tests / frontend-tests (push) Has been cancelled
lfs checks / lfs-check (push) Has been cancelled
python checks / python-checks (push) Has been cancelled
python tests / py3.12: macos-default (push) Has been cancelled
python tests / py3.11: windows-cpu (push) Has been cancelled
python tests / py3.12: windows-cpu (push) Has been cancelled
python tests / py3.11: linux-cpu (push) Has been cancelled
typegen checks / typegen-checks (push) Has been cancelled
uv lock checks / uv-lock-checks (push) Has been cancelled
openapi checks / openapi-checks (push) Has been cancelled
python tests / py3.11: macos-default (push) Has been cancelled
python tests / py3.12: linux-cpu (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:22:06 +08:00

186 lines
6.5 KiB
Python

import os
from pathlib import Path
from typing import Any
import pytest
from fastapi.testclient import TestClient
from invokeai.app.api.dependencies import ApiDependencies
from invokeai.app.api_app import app
from invokeai.backend.model_manager.configs.external_api import (
ExternalApiModelConfig,
ExternalModelCapabilities,
ExternalModelPanelSchema,
)
from invokeai.backend.model_manager.taxonomy import ModelType
@pytest.fixture(autouse=True, scope="module")
def client(invokeai_root_dir: Path) -> TestClient:
os.environ["INVOKEAI_ROOT"] = invokeai_root_dir.as_posix()
return TestClient(app)
class DummyModelImages:
def get_url(self, key: str) -> str:
return f"https://example.com/models/{key}.png"
class DummyInvoker:
def __init__(self, services: Any) -> None:
self.services = services
class MockApiDependencies(ApiDependencies):
invoker: DummyInvoker
def __init__(self, invoker: DummyInvoker) -> None:
self.invoker = invoker
def test_model_manager_external_config_round_trip(
monkeypatch: Any, client: TestClient, mm2_model_manager: Any, mm2_app_config: Any
) -> None:
config = ExternalApiModelConfig(
key="external_test",
name="External Test",
provider_id="openai",
provider_model_id="gpt-image-1",
capabilities=ExternalModelCapabilities(modes=["txt2img"]),
)
mm2_model_manager.store.add_model(config)
services = type("Services", (), {})()
services.model_manager = mm2_model_manager
services.model_images = DummyModelImages()
services.configuration = mm2_app_config
invoker = DummyInvoker(services)
monkeypatch.setattr("invokeai.app.api.routers.model_manager.ApiDependencies", MockApiDependencies(invoker))
response = client.get("/api/v2/models/", params={"model_type": ModelType.ExternalImageGenerator.value})
assert response.status_code == 200
payload = response.json()
assert len(payload["models"]) == 1
assert payload["models"][0]["key"] == "external_test"
assert payload["models"][0]["provider_id"] == "openai"
assert payload["models"][0]["cover_image"] == "https://example.com/models/external_test.png"
get_response = client.get("/api/v2/models/i/external_test")
assert get_response.status_code == 200
model_payload = get_response.json()
assert model_payload["provider_model_id"] == "gpt-image-1"
assert model_payload["cover_image"] == "https://example.com/models/external_test.png"
def test_model_manager_external_config_preserves_custom_panel_schema(
monkeypatch: Any, client: TestClient, mm2_model_manager: Any, mm2_app_config: Any
) -> None:
config = ExternalApiModelConfig(
key="external_custom_schema",
name="External Custom Schema",
provider_id="custom",
provider_model_id="custom-model",
capabilities=ExternalModelCapabilities(modes=["txt2img"]),
panel_schema=ExternalModelPanelSchema(
prompts=[{"name": "reference_images"}],
image=[{"name": "dimensions"}],
),
source="external://custom/custom-model",
)
mm2_model_manager.store.add_model(config)
services = type("Services", (), {})()
services.model_manager = mm2_model_manager
services.model_images = DummyModelImages()
services.configuration = mm2_app_config
invoker = DummyInvoker(services)
monkeypatch.setattr("invokeai.app.api.routers.model_manager.ApiDependencies", MockApiDependencies(invoker))
response = client.get("/api/v2/models/i/external_custom_schema")
assert response.status_code == 200
payload = response.json()
assert [control["name"] for control in payload["panel_schema"]["prompts"]] == ["reference_images"]
assert [control["name"] for control in payload["panel_schema"]["image"]] == ["dimensions"]
def test_model_manager_external_starter_model_applies_panel_schema_overrides(
monkeypatch: Any, client: TestClient, mm2_model_manager: Any, mm2_app_config: Any
) -> None:
config = ExternalApiModelConfig(
key="external_starter_schema",
name="Starter Schema Test",
provider_id="openai",
provider_model_id="gpt-image-1",
capabilities=ExternalModelCapabilities(
modes=["txt2img"],
supports_reference_images=False,
),
)
mm2_model_manager.store.add_model(config)
services = type("Services", (), {})()
services.model_manager = mm2_model_manager
services.model_images = DummyModelImages()
services.configuration = mm2_app_config
invoker = DummyInvoker(services)
monkeypatch.setattr("invokeai.app.api.routers.model_manager.ApiDependencies", MockApiDependencies(invoker))
response = client.get("/api/v2/models/i/external_starter_schema")
assert response.status_code == 200
payload = response.json()
assert [control["name"] for control in payload["panel_schema"]["prompts"]] == ["reference_images"]
assert [control["name"] for control in payload["panel_schema"]["image"]] == ["dimensions"]
assert payload["panel_schema"]["generation"] == []
def test_model_manager_gemini_starter_model_applies_reference_and_resolution_overrides(
monkeypatch: Any, client: TestClient, mm2_model_manager: Any, mm2_app_config: Any
) -> None:
config = ExternalApiModelConfig(
key="external_gemini_schema",
name="Gemini Starter Schema Test",
provider_id="gemini",
provider_model_id="gemini-3.1-flash-image-preview",
capabilities=ExternalModelCapabilities(modes=["txt2img"]),
source="external://gemini/gemini-3.1-flash-image-preview",
)
mm2_model_manager.store.add_model(config)
services = type("Services", (), {})()
services.model_manager = mm2_model_manager
services.model_images = DummyModelImages()
services.configuration = mm2_app_config
invoker = DummyInvoker(services)
monkeypatch.setattr("invokeai.app.api.routers.model_manager.ApiDependencies", MockApiDependencies(invoker))
response = client.get("/api/v2/models/i/external_gemini_schema")
assert response.status_code == 200
payload = response.json()
assert payload["capabilities"]["max_reference_images"] == 14
assert payload["capabilities"]["max_image_size"] == {"width": 4096, "height": 4096}
assert payload["capabilities"]["allowed_aspect_ratios"] == [
"1:1",
"1:4",
"1:8",
"2:3",
"3:2",
"3:4",
"4:1",
"4:3",
"4:5",
"5:4",
"8:1",
"9:16",
"16:9",
"21:9",
]