Compare commits

...
10 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
SMKRV 976f4f16a3 translation fixes 2024-11-19 16:40:56 +03:00
SMKRV 2bdef2b494 Main changes:
Created global SSL_CONTEXT at module level
Removed blocking create_default_context calls from async functions
Optimized aiohttp.ClientSession handling:
Using single connector with SSL context
Session is created once for all requests in validate_api_connection
Improved resource management:
Automatic session closure using context managers
More efficient connection handling
These changes should eliminate the blocking call warning and improve
overall code performance.
2024-11-19 16:33:30 +03:00
SMKRV 42324a793b bufix 2024-11-19 16:25:44 +03:00
9 changed files with 144 additions and 442 deletions
+23 -8
View File
@@ -7,12 +7,27 @@ from homeassistant.const import CONF_API_KEY
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import aiohttp_client
from homeassistant.helpers import config_validation as cv
from .const import DOMAIN, PLATFORMS
from .coordinator import HATextAICoordinator
from .const import (
DOMAIN,
PLATFORMS,
CONF_MODEL,
CONF_TEMPERATURE,
CONF_MAX_TOKENS,
CONF_API_ENDPOINT,
CONF_REQUEST_INTERVAL,
DEFAULT_MODEL,
DEFAULT_TEMPERATURE,
DEFAULT_MAX_TOKENS,
DEFAULT_API_ENDPOINT,
DEFAULT_REQUEST_INTERVAL,
)
_LOGGER = logging.getLogger(__name__)
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool:
"""Set up the HA Text AI component."""
hass.data.setdefault(DOMAIN, {})
@@ -26,11 +41,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
coordinator = HATextAICoordinator(
hass,
api_key=entry.data[CONF_API_KEY],
endpoint=entry.data.get("api_endpoint", "https://api.openai.com/v1"),
model=entry.data.get("model", "gpt-3.5-turbo"),
temperature=entry.data.get("temperature", 0.7),
max_tokens=entry.data.get("max_tokens", 1000),
request_interval=entry.data.get("request_interval", 1.0),
endpoint=entry.data.get(CONF_API_ENDPOINT, DEFAULT_API_ENDPOINT),
model=entry.data.get(CONF_MODEL, DEFAULT_MODEL),
temperature=entry.data.get(CONF_TEMPERATURE, DEFAULT_TEMPERATURE),
max_tokens=entry.data.get(CONF_MAX_TOKENS, DEFAULT_MAX_TOKENS),
request_interval=entry.data.get(CONF_REQUEST_INTERVAL, DEFAULT_REQUEST_INTERVAL),
session=session,
)
@@ -54,7 +69,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
_LOGGER.info(
"Successfully set up HA Text AI with model: %s",
entry.data.get("model", "gpt-3.5-turbo")
entry.data.get(CONF_MODEL, DEFAULT_MODEL)
)
return True
+6 -37
View File
@@ -32,6 +32,9 @@ from .const import (
import logging
_LOGGER = logging.getLogger(__name__)
# Create SSL context at module level
SSL_CONTEXT = ssl.create_default_context(cafile=certifi.where())
STEP_USER_DATA_SCHEMA = vol.Schema({
vol.Required(CONF_API_KEY): str,
vol.Optional(CONF_MODEL, default=DEFAULT_MODEL): str,
@@ -59,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"
ssl_context = ssl.create_default_context(cafile=certifi.where())
async with timeout(5):
async with aiohttp.ClientSession() as session:
async with session.get(endpoint, ssl=ssl_context) 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,
@@ -84,33 +69,17 @@ 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."""
ssl_context = ssl.create_default_context(cafile=certifi.where())
# Validate endpoint first
endpoint_valid, endpoint_error = await validate_endpoint(endpoint)
if not endpoint_valid:
return False, endpoint_error, []
"""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,
http_client=aiohttp.ClientSession(
connector=aiohttp.TCPConnector(
ssl=ssl_context,
enable_cleanup_closed=True
)
)
)
try:
models = await client.models.list()
model_ids = [model.id for model in models.data]
finally:
await client.http_client.close()
models = await client.models.list()
model_ids = [model.id for model in models.data]
if model not in model_ids:
_LOGGER.warning(
+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.5",
"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: {}
+48 -186
View File
@@ -1,192 +1,54 @@
{
"config": {
"step": {
"user": {
"title": "Set up HA Text AI",
"description": "Configure your OpenAI integration for smart home interactions. You'll need an OpenAI API key from platform.openai.com to proceed.",
"data": {
"api_key": {
"name": "OpenAI API Key",
"description": "Your OpenAI API key from platform.openai.com. Keep this secure and never share it."
},
"model": {
"name": "AI Model",
"description": "Select the AI model to use. GPT-3.5-Turbo is recommended for most uses as it offers the best balance of capabilities and cost."
},
"temperature": {
"name": "Temperature",
"description": "Controls response creativity (0-2). Low values (0.1-0.3) for focused responses, high values (0.8-2.0) for creative ones."
},
"max_tokens": {
"name": "Max Tokens",
"description": "Maximum length of responses. Higher values allow longer responses but consume more API tokens. Recommended: 512-1024."
},
"api_endpoint": {
"name": "API Endpoint",
"description": "OpenAI API endpoint URL. Leave default unless using a custom endpoint or proxy."
},
"request_interval": {
"name": "Request Interval",
"description": "Minimum time between API requests in seconds. Increase if experiencing rate limits."
}
"config": {
"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)"
}
}
}
}
},
"error": {
"invalid_auth": "Invalid API key. Please check your OpenAI API key and try again.",
"cannot_connect": "Failed to connect to API. Please check your internet connection and API endpoint.",
"unknown": "Unexpected error occurred. Please check the logs for more details.",
"already_exists": "This API key is already configured in another integration.",
"invalid_model": "Selected model is not available. Please choose a different model.",
"rate_limit": "API rate limit exceeded. Please try again later or increase the request interval.",
"context_length": "Input too long for selected model. Try reducing max tokens or using a model with larger context.",
"api_error": "OpenAI API error. Please check the logs for details.",
"timeout": "API response timeout. Request took too long to complete.",
"queue_full": "Request queue is full. Please try again later."
"options": {
"step": {
"init": {
"title": "HA Text AI Options",
"data": {
"temperature": "Response temperature (0-2)",
"max_tokens": "Maximum response length",
"request_interval": "Time between requests"
}
}
}
},
"abort": {
"already_configured": "This OpenAI integration is already configured",
"auth_failed": "Authentication failed. Please verify your API key.",
"invalid_endpoint": "Invalid API endpoint URL provided"
"services": {
"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"
}
}
},
"options": {
"step": {
"init": {
"title": "HA Text AI Options",
"description": "Adjust your OpenAI integration settings. Changes will apply to future requests only.",
"data": {
"temperature": {
"name": "Temperature",
"description": "Controls response creativity (0-2). Low values for focused responses, high for creative ones."
},
"max_tokens": {
"name": "Max Tokens",
"description": "Maximum length of responses. Higher values allow longer responses but consume more API tokens."
},
"request_interval": {
"name": "Request Interval",
"description": "Minimum time between API requests in seconds. Increase if experiencing rate limits."
}
}
}
}
},
"entity": {
"sensor": {
"last_response": {
"name": "Last Response",
"state_attributes": {
"last_updated": {
"name": "Last Updated",
"description": "Timestamp of the last AI response"
},
"question": {
"name": "Last Question",
"description": "Most recent question asked"
},
"response": {
"name": "AI Response",
"description": "Latest response from the AI"
},
"model": {
"name": "Current Model",
"description": "AI model currently in use"
},
"temperature": {
"name": "Temperature Setting",
"description": "Current temperature parameter"
},
"max_tokens": {
"name": "Max Tokens Setting",
"description": "Current maximum tokens limit"
},
"total_responses": {
"name": "Total Responses",
"description": "Number of responses since last reset"
},
"system_prompt": {
"name": "System Prompt",
"description": "Current system instructions for the AI"
},
"response_time": {
"name": "Response Time",
"description": "Time taken to generate last response"
},
"queue_size": {
"name": "Queue Size",
"description": "Current size of request queue"
},
"api_status": {
"name": "API Status",
"description": "Current API connection status"
},
"error_count": {
"name": "Error Count",
"description": "Number of errors since last reset"
},
"last_error": {
"name": "Last Error",
"description": "Description of the last error encountered"
}
}
}
}
},
"services": {
"ask_question": {
"name": "Ask Question",
"description": "Send a question to the AI model and receive a detailed response. The response will be stored in conversation history.",
"fields": {
"question": {
"name": "Question",
"description": "Your question or prompt for the AI. Be specific for better results."
},
"model": {
"name": "Model",
"description": "AI model to use (optional, overrides default settings)."
},
"temperature": {
"name": "Temperature",
"description": "Response creativity level (0-2, optional)."
},
"max_tokens": {
"name": "Max Tokens",
"description": "Maximum response length (optional)."
}
}
},
"clear_history": {
"name": "Clear History",
"description": "Delete all stored conversation history. This action cannot be undone."
},
"get_history": {
"name": "Get History",
"description": "Retrieve conversation history, including questions, responses, and timestamps.",
"fields": {
"limit": {
"name": "Limit",
"description": "Number of recent conversations to return (default 10)."
},
"filter_model": {
"name": "Filter by Model",
"description": "Retrieve only conversations using a specific AI model."
}
}
},
"set_system_prompt": {
"name": "Set System Prompt",
"description": "Configure AI behavior by setting a system prompt.",
"fields": {
"prompt": {
"name": "Prompt",
"description": "Instructions defining AI behavior and response style."
},
"clear_prompt": {
"name": "Clear Prompt",
"description": "Remove current system prompt before setting new one."
}
}
}
}
}
+47 -192
View File
@@ -1,199 +1,54 @@
{
"config": {
"step": {
"user": {
"title": "Настройка HA Text AI",
"description": "Настройте интеграцию OpenAI для умного дома. Требуется API ключ OpenAI. Подробнее о получении ключа на platform.openai.com",
"data": {
"api_key": {
"name": "API ключ OpenAI",
"description": "Ваш API ключ с platform.openai.com. Храните его в безопасности."
},
"model": {
"name": "AI Модель",
"description": "Выберите модель AI. GPT-3.5-Turbo рекомендуется для большинства задач как оптимальное сочетание возможностей и стоимости."
},
"temperature": {
"name": "Температура",
"description": "Контролирует креативность ответов (0-2). Низкие значения (0.1-0.3) для точных ответов, высокие (0.8-2.0) для творческих."
},
"max_tokens": {
"name": "Максимум токенов",
"description": "Максимальная длина ответов. Больше токенов = длиннее ответы, но выше расход API токенов. Рекомендуется: 512-1024."
},
"api_endpoint": {
"name": "API Endpoint",
"description": "URL API OpenAI. Оставьте значение по умолчанию, если не используете собственный endpoint."
},
"request_interval": {
"name": "Интервал запросов",
"description": "Минимальное время между API запросами в секундах. Увеличьте при превышении лимитов запросов."
"config": {
"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 (секунды)"
}
}
}
}
}
},
"error": {
"invalid_auth": "Неверный API ключ. Проверьте ключ OpenAI и попробуйте снова.",
"cannot_connect": "Не удалось подключиться к API. Проверьте подключение к интернету и endpoint.",
"unknown": "Неожиданная ошибка. Проверьте логи для подробностей.",
"already_exists": "Этот API ключ уже используется в другой интеграции.",
"invalid_model": "Выбранная модель недоступна. Выберите другую модель.",
"rate_limit": "Превышен лимит API запросов. Попробуйте позже или увеличьте интервал запросов.",
"context_length": "Входные данные слишком длинные для выбранной модели. Уменьшите max_tokens или используйте модель с большим контекстом.",
"api_error": "Ошибка API OpenAI. Проверьте логи для подробностей.",
"timeout": "Превышено время ожидания ответа от API.",
"queue_full": "Очередь запросов переполнена. Попробуйте позже.",
"invalid_url_format": "Неверный формат URL",
"invalid_input": "Неверные входные данные",
"invalid_temperature": "Температура должна быть от 0 до 2",
"invalid_max_tokens": "Максимальное количество токенов должно быть от 1 до 4096",
"invalid_request_interval": "Интервал запросов должен быть не менее 0.1 секунды",
"unknown": "Неизвестная ошибка"
"options": {
"step": {
"init": {
"title": "Настройки HA Text AI",
"data": {
"temperature": "Температура ответов (0-2)",
"max_tokens": "Максимальная длина ответа",
"request_interval": "Время между запросами"
}
}
}
},
"abort": {
"already_configured": "Эта интеграция OpenAI уже настроена",
"auth_failed": "Ошибка аутентификации. Проверьте API ключ.",
"invalid_endpoint": "Указан неверный URL API endpoint"
"services": {
"ask_question": {
"name": "Задать вопрос",
"description": "Отправить вопрос модели ИИ",
"fields": {
"question": {
"name": "Вопрос",
"description": "Ваш вопрос для ИИ"
}
}
},
"clear_history": {
"name": "Очистить историю",
"description": "Очистить историю разговора"
},
"get_history": {
"name": "Получить историю",
"description": "Получить историю разговора"
},
"set_system_prompt": {
"name": "Установить системный промпт",
"description": "Установить инструкции поведения системы"
}
}
},
"options": {
"step": {
"init": {
"title": "Настройки HA Text AI",
"description": "Измените настройки интеграции OpenAI. Изменения применятся к будущим запросам.",
"data": {
"temperature": {
"name": "Температура",
"description": "Контролирует креативность ответов (0-2). Низкие значения для точных ответов, высокие для творческих."
},
"max_tokens": {
"name": "Максимум токенов",
"description": "Максимальная длина ответов. Больше токенов = длиннее ответы, но выше расход API токенов."
},
"request_interval": {
"name": "Интервал запросов",
"description": "Минимальное время между API запросами в секундах. Увеличьте при превышении лимитов."
}
}
}
}
},
"entity": {
"sensor": {
"last_response": {
"name": "Последний ответ",
"state_attributes": {
"last_updated": {
"name": "Последнее обновление",
"description": "Время последнего ответа AI"
},
"question": {
"name": "Последний вопрос",
"description": "Последний заданный вопрос"
},
"response": {
"name": "Ответ AI",
"description": "Последний ответ от AI"
},
"model": {
"name": "Текущая модель",
"description": "Используемая модель AI"
},
"temperature": {
"name": "Настройка температуры",
"description": "Текущий параметр температуры"
},
"max_tokens": {
"name": "Лимит токенов",
"description": "Текущий лимит максимальных токенов"
},
"total_responses": {
"name": "Всего ответов",
"description": "Количество ответов с последнего сброса"
},
"system_prompt": {
"name": "Системный промпт",
"description": "Текущие системные инструкции для AI"
},
"response_time": {
"name": "Время ответа",
"description": "Время генерации последнего ответа"
},
"queue_size": {
"name": "Размер очереди",
"description": "Текущий размер очереди запросов"
},
"api_status": {
"name": "Статус API",
"description": "Текущий статус подключения к API"
},
"error_count": {
"name": "Счётчик ошибок",
"description": "Количество ошибок с последнего сброса"
},
"last_error": {
"name": "Последняя ошибка",
"description": "Описание последней возникшей ошибки"
}
}
}
}
},
"services": {
"ask_question": {
"name": "Задать вопрос",
"description": "Отправить вопрос модели AI и получить подробный ответ. Ответ сохраняется в истории.",
"fields": {
"question": {
"name": "Вопрос",
"description": "Ваш вопрос или запрос для AI. Будьте конкретны для лучших результатов."
},
"model": {
"name": "Модель",
"description": "Модель AI для использования (необязательно, переопределяет настройки по умолчанию)."
},
"temperature": {
"name": "Температура",
"description": "Уровень креативности ответа (0-2, необязательно)."
},
"max_tokens": {
"name": "Максимум токенов",
"description": "Максимальная длина ответа (необязательно)."
}
}
},
"clear_history": {
"name": "Очистить историю",
"description": "Удалить всю историю разговоров. Это действие нельзя отменить."
},
"get_history": {
"name": "Получить историю",
"description": "Получить историю разговоров, включая вопросы, ответы и временные метки.",
"fields": {
"limit": {
"name": "Лимит",
"description": "Количество последних разговоров для получения (по умолчанию 10)."
},
"filter_model": {
"name": "Фильтр по модели",
"description": "Получить только разговоры с определённой моделью AI."
}
}
},
"set_system_prompt": {
"name": "Установить системный промпт",
"description": "Настроить поведение AI, установив системный промпт.",
"fields": {
"prompt": {
"name": "Промпт",
"description": "Инструкции, определяющие поведение и стиль ответов AI."
},
"clear_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.5",
"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
```