mirror of
https://github.com/home-assistant/core.git
synced 2026-09-25 07:51:46 -05:00
Add support for GPT-Image-2.5 (#181735)
This commit is contained in:
@@ -553,6 +553,8 @@ class OpenAISubentryFlowHandler(ConfigSubentryFlow):
|
||||
] = SelectSelector(
|
||||
SelectSelectorConfig(
|
||||
options=[
|
||||
"gpt-image-2.5-sunburst",
|
||||
"gpt-image-2.5-flare",
|
||||
"gpt-image-2",
|
||||
"gpt-image-1.5",
|
||||
"gpt-image-1",
|
||||
|
||||
@@ -40,7 +40,7 @@ CONF_WEB_SEARCH_TIMEZONE = "timezone"
|
||||
CONF_WEB_SEARCH_INLINE_CITATIONS = "inline_citations"
|
||||
RECOMMENDED_CODE_INTERPRETER = False
|
||||
RECOMMENDED_CHAT_MODEL = "gpt-4o-mini"
|
||||
RECOMMENDED_IMAGE_MODEL = "gpt-image-2"
|
||||
RECOMMENDED_IMAGE_MODEL = "gpt-image-2.5-flare"
|
||||
RECOMMENDED_MAX_TOKENS = 3000
|
||||
RECOMMENDED_PRO_MODE = False
|
||||
RECOMMENDED_REASONING_EFFORT = "low"
|
||||
|
||||
@@ -630,7 +630,7 @@ class OpenAIBaseLLMEntity(Entity):
|
||||
model=image_model,
|
||||
output_format="png",
|
||||
)
|
||||
if image_model not in ("gpt-image-1-mini", "gpt-image-2"):
|
||||
if image_model in ("gpt-image-1", "gpt-image-1.5"):
|
||||
image_tool["input_fidelity"] = "high"
|
||||
tools.append(image_tool)
|
||||
# Keep image state on OpenAI so follow-up prompts can continue by
|
||||
|
||||
@@ -10,7 +10,10 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant.components import ai_task, media_source
|
||||
from homeassistant.components.openai_conversation import DOMAIN
|
||||
from homeassistant.components.openai_conversation.const import CONF_STORE_RESPONSES
|
||||
from homeassistant.components.openai_conversation.const import (
|
||||
CONF_IMAGE_MODEL,
|
||||
CONF_STORE_RESPONSES,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er, issue_registry as ir, selector
|
||||
@@ -229,12 +232,31 @@ async def test_generate_data_with_attachments(
|
||||
@pytest.mark.freeze_time("2025-06-14 22:59:00")
|
||||
@pytest.mark.parametrize("configured_store", [False, True])
|
||||
@pytest.mark.parametrize(
|
||||
("image_model", "input_fidelity_present"),
|
||||
("image_options", "image_model", "input_fidelity_options"),
|
||||
[
|
||||
("gpt-image-2", False),
|
||||
("gpt-image-1.5", True),
|
||||
("gpt-image-1", True),
|
||||
("gpt-image-1-mini", False),
|
||||
({}, "gpt-image-2.5-flare", {}),
|
||||
(
|
||||
{CONF_IMAGE_MODEL: "gpt-image-2.5-sunburst"},
|
||||
"gpt-image-2.5-sunburst",
|
||||
{},
|
||||
),
|
||||
(
|
||||
{CONF_IMAGE_MODEL: "gpt-image-2.5-flare"},
|
||||
"gpt-image-2.5-flare",
|
||||
{},
|
||||
),
|
||||
({CONF_IMAGE_MODEL: "gpt-image-2"}, "gpt-image-2", {}),
|
||||
(
|
||||
{CONF_IMAGE_MODEL: "gpt-image-1.5"},
|
||||
"gpt-image-1.5",
|
||||
{"input_fidelity": "high"},
|
||||
),
|
||||
(
|
||||
{CONF_IMAGE_MODEL: "gpt-image-1"},
|
||||
"gpt-image-1",
|
||||
{"input_fidelity": "high"},
|
||||
),
|
||||
({CONF_IMAGE_MODEL: "gpt-image-1-mini"}, "gpt-image-1-mini", {}),
|
||||
],
|
||||
)
|
||||
async def test_generate_image(
|
||||
@@ -243,8 +265,9 @@ async def test_generate_image(
|
||||
mock_create_stream: AsyncMock,
|
||||
entity_registry: er.EntityRegistry,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
image_options: dict[str, str],
|
||||
image_model: str,
|
||||
input_fidelity_present: bool,
|
||||
input_fidelity_options: dict[str, str],
|
||||
configured_store: bool,
|
||||
) -> None:
|
||||
"""Test AI Task image generation."""
|
||||
@@ -264,7 +287,7 @@ async def test_generate_image(
|
||||
ai_task_entry,
|
||||
data={
|
||||
**ai_task_entry.data,
|
||||
"image_model": image_model,
|
||||
**image_options,
|
||||
CONF_STORE_RESPONSES: configured_store,
|
||||
},
|
||||
)
|
||||
@@ -314,7 +337,12 @@ async def test_generate_image(
|
||||
if tool["type"] == "image_generation"
|
||||
),
|
||||
)
|
||||
assert ("input_fidelity" in image_tool) == input_fidelity_present
|
||||
assert image_tool == {
|
||||
"type": "image_generation",
|
||||
"model": image_model,
|
||||
"output_format": "png",
|
||||
**input_fidelity_options,
|
||||
}
|
||||
image_data = mock_upload_media.call_args[0][1]
|
||||
assert image_data.file.getvalue() == b"A"
|
||||
assert image_data.content_type == "image/png"
|
||||
|
||||
@@ -1352,10 +1352,27 @@ async def test_ai_task_subentry_not_loaded(
|
||||
assert result.get("reason") == "entry_not_loaded"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_init_component")
|
||||
@pytest.mark.parametrize(
|
||||
("image_options", "image_model"),
|
||||
[
|
||||
({}, "gpt-image-2.5-flare"),
|
||||
(
|
||||
{CONF_IMAGE_MODEL: "gpt-image-2.5-sunburst"},
|
||||
"gpt-image-2.5-sunburst",
|
||||
),
|
||||
(
|
||||
{CONF_IMAGE_MODEL: "gpt-image-2.5-flare"},
|
||||
"gpt-image-2.5-flare",
|
||||
),
|
||||
({CONF_IMAGE_MODEL: "gpt-image-2"}, "gpt-image-2"),
|
||||
],
|
||||
)
|
||||
async def test_creating_ai_task_subentry_additional(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_init_component,
|
||||
image_options: dict[str, str],
|
||||
image_model: str,
|
||||
) -> None:
|
||||
"""Test creating an AI task subentry with additional settings."""
|
||||
result = await hass.config_entries.subentries.async_init(
|
||||
@@ -1398,6 +1415,7 @@ async def test_creating_ai_task_subentry_additional(
|
||||
result["flow_id"],
|
||||
{
|
||||
CONF_CODE_INTERPRETER: False,
|
||||
**image_options,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1406,7 +1424,7 @@ async def test_creating_ai_task_subentry_additional(
|
||||
assert result4.get("data") == {
|
||||
CONF_RECOMMENDED: False,
|
||||
CONF_CHAT_MODEL: "gpt-4o",
|
||||
CONF_IMAGE_MODEL: "gpt-image-2",
|
||||
CONF_IMAGE_MODEL: image_model,
|
||||
CONF_MAX_TOKENS: 200,
|
||||
CONF_STORE_RESPONSES: True,
|
||||
CONF_TEMPERATURE: 0.5,
|
||||
|
||||
Reference in New Issue
Block a user