Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The OpenAI Conversation integration."""
2 
3 from __future__ import annotations
4 
5 import openai
6 import voluptuous as vol
7 
8 from homeassistant.config_entries import ConfigEntry
9 from homeassistant.const import CONF_API_KEY, Platform
10 from homeassistant.core import (
11  HomeAssistant,
12  ServiceCall,
13  ServiceResponse,
14  SupportsResponse,
15 )
16 from homeassistant.exceptions import (
17  ConfigEntryNotReady,
18  HomeAssistantError,
19  ServiceValidationError,
20 )
21 from homeassistant.helpers import config_validation as cv, selector
22 from homeassistant.helpers.httpx_client import get_async_client
23 from homeassistant.helpers.typing import ConfigType
24 
25 from .const import DOMAIN, LOGGER
26 
27 SERVICE_GENERATE_IMAGE = "generate_image"
28 PLATFORMS = (Platform.CONVERSATION,)
29 CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
30 
31 type OpenAIConfigEntry = ConfigEntry[openai.AsyncClient]
32 
33 
34 async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
35  """Set up OpenAI Conversation."""
36 
37  async def render_image(call: ServiceCall) -> ServiceResponse:
38  """Render an image with dall-e."""
39  entry_id = call.data["config_entry"]
40  entry = hass.config_entries.async_get_entry(entry_id)
41 
42  if entry is None or entry.domain != DOMAIN:
44  translation_domain=DOMAIN,
45  translation_key="invalid_config_entry",
46  translation_placeholders={"config_entry": entry_id},
47  )
48 
49  client: openai.AsyncClient = entry.runtime_data
50 
51  try:
52  response = await client.images.generate(
53  model="dall-e-3",
54  prompt=call.data["prompt"],
55  size=call.data["size"],
56  quality=call.data["quality"],
57  style=call.data["style"],
58  response_format="url",
59  n=1,
60  )
61  except openai.OpenAIError as err:
62  raise HomeAssistantError(f"Error generating image: {err}") from err
63 
64  return response.data[0].model_dump(exclude={"b64_json"})
65 
66  hass.services.async_register(
67  DOMAIN,
68  SERVICE_GENERATE_IMAGE,
69  render_image,
70  schema=vol.Schema(
71  {
72  vol.Required("config_entry"): selector.ConfigEntrySelector(
73  {
74  "integration": DOMAIN,
75  }
76  ),
77  vol.Required("prompt"): cv.string,
78  vol.Optional("size", default="1024x1024"): vol.In(
79  ("1024x1024", "1024x1792", "1792x1024")
80  ),
81  vol.Optional("quality", default="standard"): vol.In(("standard", "hd")),
82  vol.Optional("style", default="vivid"): vol.In(("vivid", "natural")),
83  }
84  ),
85  supports_response=SupportsResponse.ONLY,
86  )
87  return True
88 
89 
90 async def async_setup_entry(hass: HomeAssistant, entry: OpenAIConfigEntry) -> bool:
91  """Set up OpenAI Conversation from a config entry."""
92  client = openai.AsyncOpenAI(
93  api_key=entry.data[CONF_API_KEY],
94  http_client=get_async_client(hass),
95  )
96 
97  # Cache current platform data which gets added to each request (caching done by library)
98  _ = await hass.async_add_executor_job(client.platform_headers)
99 
100  try:
101  await hass.async_add_executor_job(client.with_options(timeout=10.0).models.list)
102  except openai.AuthenticationError as err:
103  LOGGER.error("Invalid API key: %s", err)
104  return False
105  except openai.OpenAIError as err:
106  raise ConfigEntryNotReady(err) from err
107 
108  entry.runtime_data = client
109 
110  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
111 
112  return True
113 
114 
115 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
116  """Unload OpenAI."""
117  return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
bool async_setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:34
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
Definition: __init__.py:115
bool async_setup_entry(HomeAssistant hass, OpenAIConfigEntry entry)
Definition: __init__.py:90
httpx.AsyncClient get_async_client(HomeAssistant hass, bool verify_ssl=True)
Definition: httpx_client.py:41