Skip to content

Commit 72e5b5c

Browse files
committed
Feature: Make API key optional for custom endpoints
- API key now only required when using default OpenAI endpoint - Custom endpoints (local TTS servers) can work without authentication - Updated config flow validation logic - Updated engine to conditionally add Authorization header - Updated all translations (en, cs, de, el)
1 parent b372870 commit 72e5b5c

File tree

7 files changed

+53
-38
lines changed

7 files changed

+53
-38
lines changed

custom_components/openai_tts/config_flow.py

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
CONF_VOICE,
3131
CONF_SPEED,
3232
CONF_URL,
33+
DEFAULT_URL,
3334
DOMAIN,
3435
MODELS,
3536
VOICES,
@@ -116,8 +117,12 @@ async def async_validate_api_key(api_key: str, url: str) -> bool:
116117

117118
async def validate_user_input(user_input: dict) -> None:
118119
"""Validate user input for config flow."""
119-
if user_input.get(CONF_API_KEY) is None:
120-
raise ValueError("API key is required")
120+
api_url = user_input.get(CONF_URL, DEFAULT_URL)
121+
api_key = user_input.get(CONF_API_KEY)
122+
123+
# API key is only required for the default OpenAI endpoint
124+
if api_url == DEFAULT_URL and not api_key:
125+
raise ValueError("API key is required for OpenAI API")
121126

122127
def get_chime_options() -> list[dict[str, str]]:
123128
"""Scan chime folder and return dropdown options."""
@@ -145,8 +150,8 @@ class OpenAITTSConfigFlow(ConfigFlow, domain=DOMAIN):
145150
MINOR_VERSION = 1 # Increment for subentry flow support
146151

147152
data_schema = vol.Schema({
148-
vol.Required(CONF_API_KEY): str,
149-
vol.Optional(CONF_URL, default="https://api.openai.com/v1/audio/speech"): str,
153+
vol.Optional(CONF_API_KEY, default=""): str,
154+
vol.Optional(CONF_URL, default=DEFAULT_URL): str,
150155
})
151156

152157
async def async_step_user(self, user_input: dict[str, Any] | None = None) -> ConfigFlowResult:
@@ -156,28 +161,37 @@ async def async_step_user(self, user_input: dict[str, Any] | None = None) -> Con
156161
try:
157162
await validate_user_input(user_input)
158163

159-
# Check for duplicate API key
160-
api_key = user_input.get(CONF_API_KEY)
161-
api_url = user_input.get(CONF_URL, "https://api.openai.com/v1/audio/speech")
162-
163-
for entry in self._async_current_entries():
164-
if entry.data.get(CONF_API_KEY) == api_key:
165-
_LOGGER.error("An entry with this API key already exists: %s", entry.title)
166-
errors["base"] = "duplicate_api_key"
167-
# Show the form again with the error
168-
return self.async_show_form(
169-
step_id="user",
170-
data_schema=self.data_schema,
171-
errors=errors,
172-
)
173-
174-
# Validate API key by making a test request
175-
await async_validate_api_key(api_key, api_url)
176-
177-
# Use API key as the unique identifier (hashed for privacy)
164+
api_key = user_input.get(CONF_API_KEY, "")
165+
api_url = user_input.get(CONF_URL, DEFAULT_URL)
166+
is_custom_endpoint = api_url != DEFAULT_URL
167+
168+
# Check for duplicate API key (only if API key is provided)
169+
if api_key:
170+
for entry in self._async_current_entries():
171+
if entry.data.get(CONF_API_KEY) == api_key:
172+
_LOGGER.error("An entry with this API key already exists: %s", entry.title)
173+
errors["base"] = "duplicate_api_key"
174+
return self.async_show_form(
175+
step_id="user",
176+
data_schema=self.data_schema,
177+
errors=errors,
178+
)
179+
180+
# Validate API key by making a test request (only for OpenAI or if key is provided)
181+
if api_key:
182+
await async_validate_api_key(api_key, api_url)
183+
184+
# Generate unique ID
178185
import hashlib
179-
api_key_hash = hashlib.sha256(api_key.encode()).hexdigest()[:16]
180-
unique_id = f"openai_tts_{api_key_hash}"
186+
if api_key:
187+
# Use API key hash for unique ID
188+
api_key_hash = hashlib.sha256(api_key.encode()).hexdigest()[:16]
189+
unique_id = f"openai_tts_{api_key_hash}"
190+
else:
191+
# Use URL hash for custom endpoints without API key
192+
url_hash = hashlib.sha256(api_url.encode()).hexdigest()[:16]
193+
unique_id = f"openai_tts_{url_hash}"
194+
181195
user_input[UNIQUE_ID] = unique_id
182196
await self.async_set_unique_id(unique_id)
183197
hostname = urlparse(user_input[CONF_URL]).hostname

custom_components/openai_tts/openaitts_engine.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,10 @@ async def async_get_tts_stream(
177177

178178
headers = {
179179
"Content-Type": "application/json",
180-
"Authorization": f"Bearer {self._api_key}",
181180
"User-Agent": "HomeAssistant-OpenAI-TTS"
182181
}
182+
if self._api_key:
183+
headers["Authorization"] = f"Bearer {self._api_key}"
183184

184185
payload = {
185186
"model": model,

custom_components/openai_tts/strings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
"step": {
44
"user": {
55
"title": "Add OpenAI TTS Service",
6-
"description": "Set up OpenAI TTS integration to create TTS agents.",
6+
"description": "Set up OpenAI TTS integration to create TTS agents. API key is required for OpenAI, optional for custom endpoints.",
77
"data": {
8-
"api_key": "API Key",
8+
"api_key": "API Key (required for OpenAI, optional for custom endpoints)",
99
"url": "API Endpoint (optional)"
1010
}
1111
},

custom_components/openai_tts/translations/cs.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
"step": {
44
"user": {
55
"title": "Přidat OpenAI TTS službu",
6-
"description": "Nastavte OpenAI TTS integraci pro vytvoření TTS agentů.",
6+
"description": "Nastavte OpenAI TTS integraci pro vytvoření TTS agentů. API key je vyžadován pro OpenAI, volitelný pro custom endpoints.",
77
"data": {
8-
"api_key": "API klíč",
8+
"api_key": "API Key (vyžadován pro OpenAI, volitelný pro custom endpoints)",
99
"url": "API Endpoint (volitelné)"
1010
}
1111
},

custom_components/openai_tts/translations/de.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
"step": {
44
"user": {
55
"title": "OpenAI TTS-Dienst hinzufügen",
6-
"description": "Richten Sie die OpenAI TTS-Integration ein, um TTS-Agenten zu erstellen.",
6+
"description": "Richten Sie die OpenAI TTS-Integration ein, um TTS-Agenten zu erstellen. API Key ist für OpenAI erforderlich, für custom endpoints optional.",
77
"data": {
8-
"api_key": "API-Schlüssel",
9-
"url": "API-Endpunkt (optional)"
8+
"api_key": "API Key (für OpenAI erforderlich, für custom endpoints optional)",
9+
"url": "API Endpoint (optional)"
1010
}
1111
},
1212
"reconfigure": {

custom_components/openai_tts/translations/el.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
"step": {
44
"user": {
55
"title": "Προσθήκη υπηρεσίας OpenAI TTS",
6-
"description": "Ρυθμίστε την ενσωμάτωση OpenAI TTS για να δημιουργήσετε πράκτορες TTS.",
6+
"description": "Ρυθμίστε την ενσωμάτωση OpenAI TTS για να δημιουργήσετε πράκτορες TTS. Το API key απαιτείται για OpenAI, προαιρετικό για custom endpoints.",
77
"data": {
8-
"api_key": "Κλειδί API",
9-
"url": "Διεύθυνση API (προαιρετικό)"
8+
"api_key": "API Key (απαιτείται για OpenAI, προαιρετικό για custom endpoints)",
9+
"url": "API Endpoint (προαιρετικό)"
1010
}
1111
},
1212
"reconfigure": {

custom_components/openai_tts/translations/en.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
"step": {
44
"user": {
55
"title": "Add OpenAI TTS Service",
6-
"description": "Set up OpenAI TTS integration to create TTS agents.",
6+
"description": "Set up OpenAI TTS integration to create TTS agents. API key is required for OpenAI, optional for custom endpoints.",
77
"data": {
8-
"api_key": "API Key",
8+
"api_key": "API Key (required for OpenAI, optional for custom endpoints)",
99
"url": "API Endpoint (optional)"
1010
}
1111
},

0 commit comments

Comments
 (0)