import asyncio import base64 from app.services.ai_engine.gemini_factory import AIClients class _Resp: def __init__(self, payload): self.payload = payload def raise_for_status(self): return None def json(self): return self.payload class _Client: def __init__(self, payload): self.payload = payload self.calls = [] async def post(self, url, **kwargs): self.calls.append({"url": url, **kwargs}) return _Resp(self.payload) def test_apiports_image_edit_uses_chat_completions(monkeypatch): img = base64.b64encode(b"image-bytes").decode() fake = _Client({ "choices": [{ "message": { "images": [{"b64_json": img}], }, }], }) client = AIClients(_gpt_token="apiports-token", _gpt_base="https://apiports.example") monkeypatch.setattr(client, "_gpt_target", lambda provider: ("https://apiports.example", "apiports-token", fake)) out = asyncio.run(client.gpt_edits("keep bottle", [b"ref"], "1024x1536", provider="apiports")) assert out == b"image-bytes" assert fake.calls[0]["url"] == "https://apiports.example/chat/completions" payload = fake.calls[0]["json"] assert payload["model"] == client._model_image content = payload["messages"][0]["content"] assert content[0]["type"] == "text" assert content[1]["type"] == "image_url" assert content[1]["image_url"]["url"].startswith("data:image/png;base64,") def test_codeproxy_image_edit_keeps_images_edits(monkeypatch): img = base64.b64encode(b"codeproxy-image").decode() fake = _Client({"data": [{"b64_json": img}]}) client = AIClients(_alt_token="codeproxy-token", _alt_base="https://codeproxy.example") monkeypatch.setattr(client, "_gpt_target", lambda provider: ("https://codeproxy.example", "codeproxy-token", fake)) out = asyncio.run(client.gpt_edits("keep bottle", [b"ref"], "1024x1536", provider="codeproxy")) assert out == b"codeproxy-image" assert fake.calls[0]["url"] == "https://codeproxy.example/images/edits" files = fake.calls[0]["files"] assert any(part[0] == "image[]" for part in files) assert any(part[0] == "prompt" for part in files)