diff --git a/custom_components/ha_text_ai/__init__.py b/custom_components/ha_text_ai/__init__.py index 995aabb..29a0f06 100644 --- a/custom_components/ha_text_ai/__init__.py +++ b/custom_components/ha_text_ai/__init__.py @@ -4,6 +4,8 @@ from __future__ import annotations import logging import os import shutil +import asyncio +from homeassistant.helpers.import_platform import async_import_platform from datetime import datetime from datetime import datetime, timedelta from typing import Any, Dict, Optional @@ -235,7 +237,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass=hass, client=None, # Будет установлен позже model=model, - update_interval=int(entry.data.get(CONF_REQUEST_INTERVAL, DEFAULT_REQUEST_INTERVAL)), + update_interval=timedelta(seconds=int(entry.data.get(CONF_REQUEST_INTERVAL, DEFAULT_REQUEST_INTERVAL))), instance_name=instance_name, max_tokens=entry.data.get(CONF_MAX_TOKENS, DEFAULT_MAX_TOKENS), temperature=entry.data.get(CONF_TEMPERATURE, DEFAULT_TEMPERATURE), @@ -248,7 +250,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: "config_entry": entry, } - await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + for platform in PLATFORMS: + hass.async_create_task( + async_import_platform(hass, f"{DOMAIN}.{platform}", DOMAIN) + ) + await asyncio.sleep(0) return True except Exception as ex: diff --git a/custom_components/ha_text_ai/const.py b/custom_components/ha_text_ai/const.py index 99ed36b..7b1be7c 100644 --- a/custom_components/ha_text_ai/const.py +++ b/custom_components/ha_text_ai/const.py @@ -31,7 +31,7 @@ CONF_REQUEST_INTERVAL: Final = "request_interval" CONF_INSTANCE: Final = "instance" # Default values -DEFAULT_MODEL: Final = "gpt-3.5-turbo" # Обновлено на актуальную модель +DEFAULT_MODEL: Final = "gpt-4o" DEFAULT_TEMPERATURE: Final = 0.7 DEFAULT_MAX_TOKENS: Final = 1000 DEFAULT_REQUEST_INTERVAL: Final = 1.0 @@ -64,6 +64,32 @@ ATTR_TEMPERATURE: Final = "temperature" ATTR_MAX_TOKENS: Final = "max_tokens" ATTR_SYSTEM_PROMPT: Final = "system_prompt" +# Sensor attributes +ATTR_TOTAL_RESPONSES: Final = "total_responses" +ATTR_TOTAL_ERRORS: Final = "total_errors" +ATTR_AVG_RESPONSE_TIME: Final = "average_response_time" +ATTR_LAST_REQUEST_TIME: Final = "last_request_time" +ATTR_LAST_ERROR: Final = "last_error" +ATTR_IS_PROCESSING: Final = "is_processing" +ATTR_IS_RATE_LIMITED: Final = "is_rate_limited" +ATTR_IS_MAINTENANCE: Final = "is_maintenance" +ATTR_API_VERSION: Final = "api_version" +ATTR_ENDPOINT_STATUS: Final = "endpoint_status" +ATTR_PERFORMANCE_METRICS: Final = "performance_metrics" +ATTR_HISTORY_SIZE: Final = "history_size" +ATTR_UPTIME: Final = "uptime" +ATTR_API_PROVIDER: Final = "api_provider" + +# Sensor metrics +METRIC_TOTAL_TOKENS: Final = "total_tokens" +METRIC_PROMPT_TOKENS: Final = "prompt_tokens" +METRIC_COMPLETION_TOKENS: Final = "completion_tokens" +METRIC_SUCCESSFUL_REQUESTS: Final = "successful_requests" +METRIC_FAILED_REQUESTS: Final = "failed_requests" +METRIC_AVERAGE_LATENCY: Final = "average_latency" +METRIC_MAX_LATENCY: Final = "max_latency" +METRIC_MIN_LATENCY: Final = "min_latency" + # Error messages ERROR_INVALID_API_KEY: Final = "invalid_api_key" ERROR_CANNOT_CONNECT: Final = "cannot_connect" @@ -76,6 +102,25 @@ ERROR_TIMEOUT: Final = "timeout_error" ERROR_INVALID_INSTANCE: Final = "invalid_instance" ERROR_NAME_EXISTS: Final = "name_exists" +# Entity attributes +ENTITY_ICON: Final = "mdi:robot" +ENTITY_ICON_ERROR: Final = "mdi:robot-dead" +ENTITY_ICON_PROCESSING: Final = "mdi:robot-excited" + +# State attributes +STATE_READY: Final = "ready" +STATE_PROCESSING: Final = "processing" +STATE_ERROR: Final = "error" +STATE_INITIALIZING: Final = "initializing" +STATE_MAINTENANCE: Final = "maintenance" +STATE_RATE_LIMITED: Final = "rate_limited" +STATE_DISCONNECTED: Final = "disconnected" + +# Event names +EVENT_RESPONSE_RECEIVED: Final = f"{DOMAIN}_response_received" +EVENT_ERROR_OCCURRED: Final = f"{DOMAIN}_error_occurred" +EVENT_STATE_CHANGED: Final = f"{DOMAIN}_state_changed" + # Service schema constants SERVICE_SCHEMA_ASK_QUESTION = vol.Schema({ vol.Required(CONF_INSTANCE): cv.string, @@ -128,18 +173,3 @@ CONFIG_SCHEMA = vol.Schema({ ) }) }, extra=vol.ALLOW_EXTRA) - -# Entity attributes -ENTITY_ICON: Final = "mdi:robot" -ENTITY_ICON_ERROR: Final = "mdi:robot-dead" -ENTITY_ICON_PROCESSING: Final = "mdi:robot-excited" - -# State attributes -STATE_READY: Final = "ready" -STATE_PROCESSING: Final = "processing" -STATE_ERROR: Final = "error" - -# Event names -EVENT_RESPONSE_RECEIVED: Final = f"{DOMAIN}_response_received" -EVENT_ERROR_OCCURRED: Final = f"{DOMAIN}_error_occurred" -EVENT_STATE_CHANGED: Final = f"{DOMAIN}_state_changed" diff --git a/custom_components/ha_text_ai/translations/en.json b/custom_components/ha_text_ai/translations/en.json index 4212cbf..6d1b889 100644 --- a/custom_components/ha_text_ai/translations/en.json +++ b/custom_components/ha_text_ai/translations/en.json @@ -30,6 +30,10 @@ "cannot_connect": "Failed to connect to API service", "invalid_model": "Selected model is not available", "rate_limit": "Rate limit exceeded", + "context_length": "Context length exceeded", + "rate_limit_exceeded": "API rate limit exceeded", + "maintenance": "Service is under maintenance", + "invalid_response": "Invalid API response received", "api_error": "API service error occurred", "timeout": "Request timed out", "invalid_instance": "Invalid instance specified", @@ -53,85 +57,105 @@ "services": { "ask_question": { "name": "Ask Question", - "description": "Send a question to the specified AI instance", + "description": "Send a question to the AI model and receive a detailed response. The response will be stored in the conversation history and can be retrieved later.", "fields": { "instance": { "name": "Instance", - "description": "The HA Text AI instance to use" + "description": "Name of the HA Text AI instance to use", + "required": true }, "question": { "name": "Question", - "description": "Your question or prompt" + "description": "Your question or prompt for the AI assistant", + "required": true }, "system_prompt": { "name": "System Prompt", - "description": "Optional context for this question" + "description": "Optional system prompt to set context for this specific question", + "required": false }, "model": { "name": "Model", - "description": "Override default model for this request" + "description": "Select AI model to use (optional, overrides default setting)", + "required": false }, "temperature": { "name": "Temperature", - "description": "Override default creativity setting" + "description": "Controls response creativity (0.0-2.0)", + "required": false, + "default": 0.7 }, "max_tokens": { "name": "Max Tokens", - "description": "Override default response length limit" + "description": "Maximum length of the response (1-4096 tokens)", + "required": false, + "default": 1000 } } }, "clear_history": { "name": "Clear History", - "description": "Delete conversation history for specified instance", + "description": "Delete all stored questions and responses from the conversation history", "fields": { "instance": { "name": "Instance", - "description": "The HA Text AI instance to clear history for" + "description": "Name of the HA Text AI instance to clear history for", + "required": true } } }, "get_history": { "name": "Get History", - "description": "Retrieve conversation history for specified instance", + "description": "Retrieve conversation history with optional filtering and sorting", "fields": { "instance": { "name": "Instance", - "description": "The HA Text AI instance to get history from" + "description": "Name of the HA Text AI instance to get history from", + "required": true }, "limit": { "name": "Limit", - "description": "Maximum number of entries (1-100)" + "description": "Number of conversations to return (1-100)", + "required": false, + "default": 10 }, "filter_model": { "name": "Filter Model", - "description": "Filter by specific AI model" + "description": "Filter conversations by specific AI model", + "required": false }, "start_date": { "name": "Start Date", - "description": "Filter from specific date/time" + "description": "Filter conversations starting from this date/time", + "required": false }, "include_metadata": { "name": "Include Metadata", - "description": "Include additional response information" + "description": "Include additional information like tokens used, response time, etc.", + "required": false, + "default": false }, "sort_order": { "name": "Sort Order", - "description": "Sort order (newest/oldest first)" + "description": "Sort order for results (newest or oldest first)", + "required": false, + "default": "desc" } } }, "set_system_prompt": { "name": "Set System Prompt", - "description": "Set default behavior for specified instance", + "description": "Set default system behavior instructions for all future conversations", "fields": { "instance": { "name": "Instance", - "description": "The HA Text AI instance to configure" + "description": "Name of the HA Text AI instance to set system prompt for", + "required": true }, "prompt": { "name": "System Prompt", - "description": "Default behavior instructions" + "description": "Instructions that define how the AI should behave and respond", + "required": true } } } @@ -146,6 +170,8 @@ "error": "Error", "disconnected": "Disconnected", "rate_limited": "Rate Limited", + "maintenance": "Maintenance", + "initializing": "Initializing", "retrying": "Retrying", "queued": "Queued" }, @@ -185,6 +211,60 @@ }, "tokens_used": { "name": "Total Tokens Used" + }, + "average_response_time": { + "name": "Average Response Time" + }, + "last_request_time": { + "name": "Last Request Time" + }, + "is_processing": { + "name": "Processing Status" + }, + "is_rate_limited": { + "name": "Rate Limited Status" + }, + "is_maintenance": { + "name": "Maintenance Status" + }, + "api_version": { + "name": "API Version" + }, + "endpoint_status": { + "name": "Endpoint Status" + }, + "performance_metrics": { + "name": "Performance Metrics" + }, + "history_size": { + "name": "History Size" + }, + "uptime": { + "name": "Uptime" + }, + "total_tokens": { + "name": "Total Tokens" + }, + "prompt_tokens": { + "name": "Prompt Tokens" + }, + "completion_tokens": { + "name": "Completion Tokens" + }, + "successful_requests": { + "name": "Successful Requests" + }, + "failed_requests": { + "name": "Failed Requests" + }, + "average_latency": { + "name": "Average Latency" + }, + "max_latency": { + "name": "Maximum Latency" + }, + "min_latency": { + "name": "Minimum Latency" } } } diff --git a/custom_components/ha_text_ai/translations/ru.json b/custom_components/ha_text_ai/translations/ru.json new file mode 100644 index 0000000..46874a7 --- /dev/null +++ b/custom_components/ha_text_ai/translations/ru.json @@ -0,0 +1,273 @@ +{ + "config": { + "step": { + "provider": { + "title": "Выбор AI провайдера", + "description": "Выберите провайдера AI сервиса для этого экземпляра", + "data": { + "api_provider": "API провайдер" + } + }, + "user": { + "title": "Настройка экземпляра HA Text AI", + "description": "Настройте новый экземпляр AI ассистента с выбранным провайдером", + "data": { + "name": "Название экземпляра (например, 'GPT Ассистент', 'Claude Помощник')", + "api_key": "API ключ для аутентификации", + "model": "Используемая AI модель", + "temperature": "Креативность ответов (0-2, чем ниже, тем точнее)", + "max_tokens": "Максимальная длина ответа (1-4096 токенов)", + "api_endpoint": "Пользовательский URL API (необязательно)", + "request_interval": "Минимальный интервал между запросами (0.1-60 секунд)" + } + } + }, + "error": { + "name_exists": "Экземпляр с таким именем уже существует", + "invalid_name": "Недопустимое имя экземпляра", + "invalid_auth": "Ошибка аутентификации - проверьте API ключ", + "invalid_api_key": "Недействительный API ключ - проверьте учетные данные", + "cannot_connect": "Не удалось подключиться к API сервису", + "invalid_model": "Выбранная модель недоступна", + "rate_limit": "Превышен лимит запросов", + "context_length": "Превышена длина контекста", + "rate_limit_exceeded": "Превышен лимит API запросов", + "maintenance": "Сервис находится на техническом обслуживании", + "invalid_response": "Получен некорректный ответ API", + "api_error": "Произошла ошибка API сервиса", + "timeout": "Превышено время ожидания запроса", + "invalid_instance": "Указан недействительный экземпляр", + "unknown": "Произошла непредвиденная ошибка" + } + }, + "options": { + "step": { + "init": { + "title": "Обновление настроек экземпляра", + "description": "Измените настройки для этого экземпляра AI ассистента", + "data": { + "model": "AI модель", + "temperature": "Креативность ответов (0-2)", + "max_tokens": "Максимальная длина ответа (1-4096)", + "request_interval": "Минимальный интервал запросов (0.1-60 секунд)" + } + } + } + }, + "services": { + "ask_question": { + "name": "Задать вопрос", + "description": "Отправьте вопрос AI модели и получите подробный ответ. Ответ будет сохранен в истории разговора и может быть получен позже.", + "fields": { + "instance": { + "name": "Экземпляр", + "description": "Название экземпляра HA Text AI для использования", + "required": true + }, + "question": { + "name": "Вопрос", + "description": "Ваш вопрос или запрос для AI ассистента", + "required": true + }, + "system_prompt": { + "name": "Системный промпт", + "description": "Необязательный системный промпт для установки контекста этого вопроса", + "required": false + }, + "model": { + "name": "Модель", + "description": "Выберите AI модель (необязательно, переопределяет настройки по умолчанию)", + "required": false + }, + "temperature": { + "name": "Temperature", + "description": "Управляет креативностью ответов (0.0-2.0)", + "required": false, + "default": 0.7 + }, + "max_tokens": { + "name": "Max Tokens", + "description": "Максимальная длина ответа (1-4096 токенов)", + "required": false, + "default": 1000 + } + } + }, + "clear_history": { + "name": "Очистить историю", + "description": "Удалить все сохраненные вопросы и ответы из истории разговора", + "fields": { + "instance": { + "name": "Экземпляр", + "description": "Название экземпляра HA Text AI для очистки истории", + "required": true + } + } + }, + "get_history": { + "name": "Получить историю", + "description": "Получить историю разговора с дополнительной фильтрацией и сортировкой", + "fields": { + "instance": { + "name": "Экземпляр", + "description": "Название экземпляра HA Text AI для получения истории", + "required": true + }, + "limit": { + "name": "Лимит", + "description": "Количество разговоров для возврата (1-100)", + "required": false, + "default": 10 + }, + "filter_model": { + "name": "Фильтр модели", + "description": "Фильтровать разговоры по конкретной AI модели", + "required": false + }, + "start_date": { + "name": "Начальная дата", + "description": "Фильтровать разговоры начиная с этой даты/времени", + "required": false + }, + "include_metadata": { + "name": "Включить метаданные", + "description": "Включить дополнительную информацию, такую как использованные токены, время ответа и т.д.", + "required": false, + "default": false + }, + "sort_order": { + "name": "Порядок сортировки", + "description": "Порядок сортировки результатов (сначала новые или старые)", + "required": false, + "default": "desc" + } + } + }, + "set_system_prompt": { + "name": "Установить системный промпт", + "description": "Установить инструкции поведения по умолчанию для всех будущих разговоров", + "fields": { + "instance": { + "name": "Экземпляр", + "description": "Название экземпляра HA Text AI для настройки", + "required": true + }, + "prompt": { + "name": "Системный промпт", + "description": "Инструкции, определяющие поведение и ответы AI", + "required": true + } + } + } + }, + "entity": { + "sensor": { + "ha_text_ai": { + "name": "{name}", + "state": { + "ready": "Готов", + "processing": "Обработка", + "error": "Ошибка", + "disconnected": "Отключен", + "rate_limited": "Превышен лимит", + "maintenance": "Обслуживание", + "initializing": "Инициализация", + "retrying": "Повторная попытка", + "queued": "В очереди" + }, + "state_attributes": { + "question": { + "name": "Последний вопрос" + }, + "response": { + "name": "Последний ответ" + }, + "model": { + "name": "Текущая модель" + }, + "temperature": { + "name": "Temperature" + }, + "max_tokens": { + "name": "Max Tokens" + }, + "system_prompt": { + "name": "Системный промпт" + }, + "response_time": { + "name": "Время последнего ответа" + }, + "total_responses": { + "name": "Всего ответов" + }, + "error_count": { + "name": "Количество ошибок" + }, + "last_error": { + "name": "Последняя ошибка" + }, + "api_status": { + "name": "Статус API" + }, + "tokens_used": { + "name": "Всего использовано токенов" + }, + "average_response_time": { + "name": "Среднее время ответа" + }, + "last_request_time": { + "name": "Время последнего запроса" + }, + "is_processing": { + "name": "Статус обработки" + }, + "is_rate_limited": { + "name": "Статус ограничения запросов" + }, + "is_maintenance": { + "name": "Статус обслуживания" + }, + "api_version": { + "name": "Версия API" + }, + "endpoint_status": { + "name": "Статус конечной точки" + }, + "performance_metrics": { + "name": "Метрики производительности" + }, + "history_size": { + "name": "Размер истории" + }, + "uptime": { + "name": "Время работы" + }, + "total_tokens": { + "name": "Всего токенов" + }, + "prompt_tokens": { + "name": "Токены промпта" + }, + "completion_tokens": { + "name": "Токены завершения" + }, + "successful_requests": { + "name": "Успешные запросы" + }, + "failed_requests": { + "name": "Неудачные запросы" + }, + "average_latency": { + "name": "Средняя задержка" + }, + "max_latency": { + "name": "Максимальная задержка" + }, + "min_latency": { + "name": "Минимальная задержка" + } + } + } + } + } +}