Compare commits

...
7 Commits
Author SHA1 Message Date
SMKRV 93558b2444 Version update 2024-11-19 17:34:27 +03:00
SMKRV 9f93f1ee18 Main changes:
Removed the validate_endpoint function
Optimized the validate_api_connection function
Simplified API connection verification
Preserved all error handling and retry logic
Improved exception handling
The integration should now correctly verify the
OpenAI API connection without false endpoint_not_available errors.
2024-11-19 17:33:27 +03:00
SMKRV 30a9b53ba1 Markdown changes 2024-11-19 17:18:23 +03:00
SMKRV 5175970d55 structure.md added 2024-11-19 17:16:30 +03:00
SMKRV f6bfbd4a07 Release v1.0.8 2024-11-19 17:02:38 +03:00
SMKRV 4ddb0dc977 Translation fixes 2024-11-19 16:59:42 +03:00
SMKRV 24dc4ac4d4 Hotfix 2024-11-19 16:53:27 +03:00
8 changed files with 152 additions and 191 deletions
+44 -70
View File
@@ -62,24 +62,6 @@ STEP_USER_DATA_SCHEMA = vol.Schema({
),
})
async def validate_endpoint(endpoint: str) -> Tuple[bool, str]:
"""Validate API endpoint accessibility."""
try:
parsed_url = urlparse(endpoint)
if parsed_url.scheme not in ('http', 'https'):
return False, "invalid_endpoint_scheme"
connector = aiohttp.TCPConnector(ssl=SSL_CONTEXT)
async with timeout(5):
async with aiohttp.ClientSession(connector=connector) as session:
async with session.get(endpoint) as response:
if response.status != 200:
return False, "endpoint_not_available"
return True, ""
except Exception as e:
_LOGGER.error("Error validating endpoint: %s", str(e))
return False, "endpoint_error"
async def validate_api_connection(
api_key: str,
endpoint: str,
@@ -87,64 +69,56 @@ async def validate_api_connection(
retry_count: int = 3,
retry_delay: float = 1.0
) -> Tuple[bool, str, list]:
"""Validate API connection with improved retry logic."""
# Validate endpoint first
endpoint_valid, endpoint_error = await validate_endpoint(endpoint)
if not endpoint_valid:
return False, endpoint_error, []
connector = aiohttp.TCPConnector(ssl=SSL_CONTEXT)
async with aiohttp.ClientSession(connector=connector) as session:
for attempt in range(retry_count):
try:
async with timeout(10):
client = AsyncOpenAI(
api_key=api_key,
base_url=endpoint,
http_client=session
)
models = await client.models.list()
model_ids = [model.id for model in models.data]
if model not in model_ids:
_LOGGER.warning(
"Model %s not found in available models: %s",
model,
", ".join(model_ids)
)
return False, "invalid_model", model_ids
return True, "", model_ids
except asyncio.TimeoutError:
_LOGGER.warning(
"Timeout during API validation (attempt %d/%d)",
attempt + 1,
retry_count
"""Validate API connection with retry logic."""
for attempt in range(retry_count):
try:
async with timeout(10):
client = AsyncOpenAI(
api_key=api_key,
base_url=endpoint,
)
if attempt == retry_count - 1:
return False, "timeout", []
await asyncio.sleep(retry_delay)
except AuthenticationError as err:
_LOGGER.error("Authentication error: %s", str(err))
return False, "invalid_auth", []
models = await client.models.list()
model_ids = [model.id for model in models.data]
except RateLimitError as err:
_LOGGER.error("Rate limit exceeded: %s", str(err))
return False, "rate_limit", []
if model not in model_ids:
_LOGGER.warning(
"Model %s not found in available models: %s",
model,
", ".join(model_ids)
)
return False, "invalid_model", model_ids
return True, "", model_ids
except APIConnectionError as err:
_LOGGER.error("API connection error: %s", str(err))
return False, "cannot_connect", []
except asyncio.TimeoutError:
_LOGGER.warning(
"Timeout during API validation (attempt %d/%d)",
attempt + 1,
retry_count
)
if attempt == retry_count - 1:
return False, "timeout", []
await asyncio.sleep(retry_delay)
except APIError as err:
_LOGGER.error("API error: %s", str(err))
return False, "api_error", []
except AuthenticationError as err:
_LOGGER.error("Authentication error: %s", str(err))
return False, "invalid_auth", []
except Exception as err:
_LOGGER.exception("Unexpected error during validation: %s", str(err))
return False, "unknown", []
except RateLimitError as err:
_LOGGER.error("Rate limit exceeded: %s", str(err))
return False, "rate_limit", []
except APIConnectionError as err:
_LOGGER.error("API connection error: %s", str(err))
return False, "cannot_connect", []
except APIError as err:
_LOGGER.error("API error: %s", str(err))
return False, "api_error", []
except Exception as err:
_LOGGER.exception("Unexpected error during validation: %s", str(err))
return False, "unknown", []
class HATextAIConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for HA text AI."""
+1 -1
View File
@@ -9,6 +9,6 @@
"issue_tracker": "https://github.com/smkrv/ha-text-ai/issues",
"requirements": ["openai>=1.0.0"],
"ssdp": [],
"version": "1.0.7",
"version": "1.0.9",
"zeroconf": []
}
+1 -17
View File
@@ -131,12 +131,7 @@ get_history:
mode: dropdown
set_system_prompt:
name: Set System Prompt
description: >-
Configure the AI's behavior by setting a system prompt.
This affects how the AI interprets and responds to all future questions.
The prompt will persist until changed or cleared.
fields:
fields:
prompt:
name: System Prompt
description: >-
@@ -157,14 +152,3 @@ set_system_prompt:
text:
multiline: true
type: text
max_length: 1000
clear_prompt:
name: Clear Existing Prompt
description: >-
Set to true to remove the current system prompt before applying the new one.
This ensures no conflicting instructions remain.
required: false
default: false
selector:
boolean: {}
@@ -1,61 +1,54 @@
{
"config": {
"option": {
"api_key": {
"name": "API Key",
"description": "Your OpenAI API key"
},
"model": {
"name": "Model",
"description": "AI model to use for responses"
},
"temperature": {
"name": "Temperature",
"description": "Temperature for response generation (0-2)"
},
"max_tokens": {
"name": "Max Tokens",
"description": "Maximum tokens in response (1-4096)"
},
"api_endpoint": {
"name": "API Endpoint",
"description": "API endpoint URL"
},
"request_interval": {
"name": "Request Interval",
"description": "Minimum time between API requests (seconds)"
"step": {
"user": {
"title": "Set up HA Text AI",
"description": "Configure your OpenAI integration",
"data": {
"api_key": "Your OpenAI API key",
"model": "AI model to use for responses",
"temperature": "Temperature for response generation (0-2)",
"max_tokens": "Maximum tokens in response (1-4096)",
"api_endpoint": "API endpoint URL",
"request_interval": "Minimum time between API requests (seconds)"
}
}
}
},
"options": {
"temperature": "Temperature",
"max_tokens": "Max Tokens",
"request_interval": "Request Interval"
},
"error": {
"invalid_api_key": "Invalid API key",
"cannot_connect": "Cannot connect to the API",
"unknown_error": "Unknown error",
"invalid_model": "Invalid model",
"rate_limit_exceeded": "Rate limit exceeded",
"context_length_exceeded": "Context length exceeded",
"api_error": "API error",
"timeout_error": "Timeout error",
"queue_full": "Queue full",
"invalid_prompt": "Invalid prompt"
},
"state": {
"ready": "Ready",
"processing": "Processing",
"error": "Error",
"disconnected": "Disconnected",
"rate_limited": "Rate limited",
"initializing": "Initializing"
"step": {
"init": {
"title": "HA Text AI Options",
"data": {
"temperature": "Response temperature (0-2)",
"max_tokens": "Maximum response length",
"request_interval": "Time between requests"
}
}
}
},
"services": {
"ask_question": "Ask Question",
"clear_history": "Clear History",
"get_history": "Get History",
"set_system_prompt": "Set System Prompt"
"ask_question": {
"name": "Ask Question",
"description": "Send a question to the AI model",
"fields": {
"question": {
"name": "Question",
"description": "Your question for the AI"
}
}
},
"clear_history": {
"name": "Clear History",
"description": "Clear conversation history"
},
"get_history": {
"name": "Get History",
"description": "Retrieve conversation history"
},
"set_system_prompt": {
"name": "Set System Prompt",
"description": "Set system behavior instructions"
}
}
}
@@ -1,61 +1,54 @@
{
"config": {
"option": {
"api_key": {
"name": "API ключ",
"description": "Ваш API ключ OpenAI"
},
"model": {
"name": "Модель",
"description": "Модель AI для генерации ответов"
},
"temperature": {
"name": "Температура",
"description": "Температура для генерации ответов (0-2)"
},
"max_tokens": {
"name": "Максимальное количество токенов",
"description": "Максимальное количество токенов в ответе (1-4096)"
},
"api_endpoint": {
"name": "Конечная точка API",
"description": "URL конечной точки API"
},
"request_interval": {
"name": "Интервал запросов",
"description": "Минимальное время между запросами к API в секундах"
"step": {
"user": {
"title": "Настройка HA Text AI",
"description": "Настройка интеграции с OpenAI",
"data": {
"api_key": "Ваш ключ API OpenAI",
"model": "Модель ИИ для генерации ответов",
"temperature": "Температура генерации ответов (0-2)",
"max_tokens": "Максимальное количество токенов в ответе (1-4096)",
"api_endpoint": "URL конечной точки API",
"request_interval": "Минимальное время между запросами к API (секунды)"
}
}
}
},
"options": {
"temperature": "Температура",
"max_tokens": "Максимальное количество токенов",
"request_interval": "Интервал запросов"
},
"error": {
"invalid_api_key": "Неверный API ключ",
"cannot_connect": "Не удается подключиться к API",
"unknown_error": "Неизвестная ошибка",
"invalid_model": "Неверная модель",
"rate_limit_exceeded": "Превышен лимит запросов",
"context_length_exceeded": "Превышена длина контекста",
"api_error": "Ошибка API",
"timeout_error": "Время ожидания истекло",
"queue_full": "Очередь полна",
"invalid_prompt": "Неверный запрос"
},
"state": {
"ready": "Готово",
"processing": "Обработка",
"error": "Ошибка",
"disconnected": "Отключено",
"rate_limited": "Ограниченный по скорости",
"initializing": "Инициализация"
"step": {
"init": {
"title": "Настройки HA Text AI",
"data": {
"temperature": "Температура ответов (0-2)",
"max_tokens": "Максимальная длина ответа",
"request_interval": "Время между запросами"
}
}
}
},
"services": {
"ask_question": "Задать вопрос",
"clear_history": "Очистить историю",
"get_history": "Получить историю",
"set_system_prompt": "Установить системный запрос"
"ask_question": {
"name": "Задать вопрос",
"description": "Отправить вопрос модели ИИ",
"fields": {
"question": {
"name": "Вопрос",
"description": "Ваш вопрос для ИИ"
}
}
},
"clear_history": {
"name": "Очистить историю",
"description": "Очистить историю разговора"
},
"get_history": {
"name": "Получить историю",
"description": "Получить историю разговора"
},
"set_system_prompt": {
"name": "Установить системный промпт",
"description": "Установить инструкции поведения системы"
}
}
}
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -4,6 +4,6 @@
"domains": ["sensor"],
"homeassistant": "2024.11.0",
"icon": "mdi:brain",
"version": "1.0.7",
"version": "1.0.9",
"documentation": "https://github.com/smkrv/ha-text-ai"
}
+17
View File
@@ -0,0 +1,17 @@
```
ha-text-ai/
├── custom_components/
│ └── ha_text_ai/
│ ├── __init__.py
│ ├── config_flow.py
│ ├── coordinator.py
│ ├── manifest.json
│ ├── sensor.py
│ ├── services.yaml
│ └── const.py
└── strings/
├── en.json
└── ru.json
```