Compare commits

...
11 Commits
Author SHA1 Message Date
SMKRV 9a7635c2ae Release v1.1.0 2024-11-19 18:55:14 +03:00
SMKRV df3d79c20c feat: add multi-provider support,
config improvements
2024-11-19 18:53:51 +03:00
SMKRV d6144be7ed v.1.0.10 2024-11-19 17:49:48 +03:00
SMKRV 9afbb904b3 __init__.py:
added: from .coordinator import HATextAICoordinator
2024-11-19 17:48:00 +03:00
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
11 changed files with 468 additions and 219 deletions
+134 -12
View File
@@ -1,14 +1,16 @@
"""The HA Text AI integration."""
import logging
from typing import Any
from typing import Any, Dict, Optional
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import aiohttp_client
from homeassistant.helpers import config_validation as cv
from .coordinator import HATextAICoordinator
from .const import (
DOMAIN,
PLATFORMS,
@@ -53,19 +55,134 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await coordinator.async_config_entry_first_refresh()
except Exception as refresh_ex:
_LOGGER.error("Failed to refresh coordinator: %s", str(refresh_ex))
return False
raise ConfigEntryNotReady from refresh_ex
if not coordinator.last_update_success:
_LOGGER.error("Failed to communicate with OpenAI API")
return False
raise ConfigEntryNotReady("Failed to communicate with OpenAI API")
hass.data[DOMAIN][entry.entry_id] = coordinator
try:
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
except Exception as setup_ex:
_LOGGER.error("Failed to setup platforms: %s", str(setup_ex))
return False
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
async def async_ask_question(call: ServiceCall) -> None:
"""Handle the ask_question service call."""
question = call.data.get("question", "")
if not question:
_LOGGER.error("No question provided in service call")
return
# Собираем все опциональные параметры
request_params = {}
# Обработка system_prompt
system_prompt = call.data.get("system_prompt")
if system_prompt is not None:
request_params["system_prompt"] = system_prompt
# Обработка model
model = call.data.get("model")
if model is not None:
request_params["model"] = model
# Обработка temperature
temperature = call.data.get("temperature")
if temperature is not None:
try:
request_params["temperature"] = float(temperature)
except ValueError:
_LOGGER.error("Invalid temperature value: %s", temperature)
return
# Обработка max_tokens
max_tokens = call.data.get("max_tokens")
if max_tokens is not None:
try:
request_params["max_tokens"] = int(max_tokens)
except ValueError:
_LOGGER.error("Invalid max_tokens value: %s", max_tokens)
return
try:
await coordinator.async_ask_question(question, **request_params)
except Exception as err:
_LOGGER.error("Error asking question: %s", str(err))
async def async_clear_history(call: ServiceCall) -> None:
"""Handle the clear_history service call."""
try:
coordinator._responses.clear()
await coordinator.async_refresh()
_LOGGER.info("History cleared successfully")
except Exception as err:
_LOGGER.error("Error clearing history: %s", str(err))
async def async_get_history(call: ServiceCall) -> dict:
"""Handle the get_history service call."""
try:
limit = call.data.get("limit", 10)
filter_model = call.data.get("filter_model", "")
responses = coordinator._responses
# Применяем фильтрацию по модели
if filter_model:
filtered_responses = {
k: v for k, v in responses.items()
if v.get("model") == filter_model
}
else:
filtered_responses = responses.copy()
# Сортируем по времени и ограничиваем количество
sorted_responses = dict(
sorted(
filtered_responses.items(),
key=lambda x: x[1]["timestamp"],
reverse=True
)[:limit]
)
return sorted_responses
except Exception as err:
_LOGGER.error("Error getting history: %s", str(err))
return {}
async def async_set_system_prompt(call: ServiceCall) -> None:
"""Handle the set_system_prompt service call."""
prompt = call.data.get("prompt", "")
if prompt:
try:
coordinator.system_prompt = prompt
_LOGGER.info("System prompt updated successfully")
except Exception as err:
_LOGGER.error("Error setting system prompt: %s", str(err))
else:
_LOGGER.error("No prompt provided in service call")
# Регистрация сервисов
hass.services.async_register(
DOMAIN,
"ask_question",
async_ask_question
)
hass.services.async_register(
DOMAIN,
"clear_history",
async_clear_history
)
hass.services.async_register(
DOMAIN,
"get_history",
async_get_history
)
hass.services.async_register(
DOMAIN,
"set_system_prompt",
async_set_system_prompt
)
_LOGGER.info(
"Successfully set up HA Text AI with model: %s",
@@ -76,7 +193,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
except Exception as ex:
_LOGGER.exception("Unexpected error setting up entry: %s", str(ex))
return False
raise ConfigEntryNotReady from ex
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
@@ -84,6 +201,11 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if entry.entry_id not in hass.data.get(DOMAIN, {}):
return True
# Удаляем все сервисы при выгрузке интеграции
services = ["ask_question", "clear_history", "get_history", "set_system_prompt"]
for service in services:
hass.services.async_remove(DOMAIN, service)
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
coordinator = hass.data[DOMAIN].pop(entry.entry_id)
@@ -101,4 +223,4 @@ async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
await async_unload_entry(hass, entry)
await async_setup_entry(hass, entry)
except Exception as ex:
_LOGGER.exception("Error reloading entry: %s", str(ex))
_LOGGER.exception("Error reloading entry: %s", str(ex)) # убрано лишнее двоеточие
+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."""
+54 -13
View File
@@ -71,14 +71,27 @@ class HATextAICoordinator(DataUpdateCoordinator):
try:
async with async_timeout.timeout(30):
question = await self._question_queue.get()
question_data = await self._question_queue.get()
question = question_data["question"]
params = question_data["params"]
try:
response_content = await self._make_api_call(question)
response_content = await self._make_api_call(
question,
model=params.get("model"),
temperature=params.get("temperature"),
max_tokens=params.get("max_tokens"),
system_prompt=params.get("system_prompt")
)
self._responses[question] = {
"question": question,
"response": response_content,
"error": None,
"timestamp": self.hass.loop.time()
"timestamp": self.hass.loop.time(),
"model": params.get("model", self.model),
"temperature": params.get("temperature", self.temperature),
"max_tokens": params.get("max_tokens", self.max_tokens)
}
self._error_count = 0
self._is_ready = True
@@ -113,7 +126,10 @@ class HATextAICoordinator(DataUpdateCoordinator):
"question": question,
"response": None,
"error": error_msg,
"timestamp": self.hass.loop.time()
"timestamp": self.hass.loop.time(),
"model": self.model,
"temperature": self.temperature,
"max_tokens": self.max_tokens
}
_LOGGER.error("API error (%s): %s", type(error).__name__, error_msg)
@@ -136,19 +152,27 @@ class HATextAICoordinator(DataUpdateCoordinator):
except Exception as err:
_LOGGER.error("Error clearing question queue: %s", err)
async def _make_api_call(self, question: str) -> str:
async def _make_api_call(
self,
question: str,
model: Optional[str] = None,
temperature: Optional[float] = None,
max_tokens: Optional[int] = None,
system_prompt: Optional[str] = None
) -> str:
"""Make API call to OpenAI."""
try:
messages = []
if self.system_prompt:
messages.append({"role": "system", "content": self.system_prompt})
current_system_prompt = system_prompt if system_prompt is not None else self.system_prompt
if current_system_prompt:
messages.append({"role": "system", "content": current_system_prompt})
messages.append({"role": "user", "content": question})
completion = await self.client.chat.completions.create(
model=self.model,
model=model or self.model,
messages=messages,
temperature=self.temperature,
max_tokens=self.max_tokens,
temperature=temperature if temperature is not None else self.temperature,
max_tokens=max_tokens if max_tokens is not None else self.max_tokens,
)
return completion.choices[0].message.content
@@ -156,13 +180,30 @@ class HATextAICoordinator(DataUpdateCoordinator):
_LOGGER.error("Error in API call: %s", err)
raise
async def async_ask_question(self, question: str) -> None:
"""Add question to queue."""
async def async_ask_question(
self,
question: str,
system_prompt: Optional[str] = None,
model: Optional[str] = None,
temperature: Optional[float] = None,
max_tokens: Optional[int] = None
) -> None:
"""Add question to queue with optional parameters."""
if not self._is_ready and self._error_count >= self._MAX_ERRORS:
_LOGGER.warning("Coordinator is not ready due to previous errors")
return
await self._question_queue.put(question)
question_data = {
"question": question,
"params": {
"system_prompt": system_prompt,
"model": model,
"temperature": temperature,
"max_tokens": max_tokens
}
}
await self._question_queue.put(question_data)
await self.async_refresh()
async def async_shutdown(self) -> None:
+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.1.0",
"zeroconf": []
}
+25 -5
View File
@@ -117,21 +117,35 @@ class HATextAISensor(CoordinatorEntity, SensorEntity):
return attributes
try:
history = list(self.coordinator.data.items())
# Получаем историю ответов
history = list(self.coordinator._responses.items())
if history:
last_question, last_data = history[-1]
# Handle different response formats
# Обработка формата ответа
if isinstance(last_data, dict):
last_response = last_data.get("response", "")
last_updated = last_data.get("timestamp", self.coordinator.last_update_success_time)
response_time = last_data.get("response_time")
# Добавляем новые метаданные
model = last_data.get("model", self.coordinator.model)
temperature = last_data.get("temperature", self.coordinator.temperature)
max_tokens = last_data.get("max_tokens", self.coordinator.max_tokens)
error = last_data.get("error")
if error:
self._last_error = error
self._state = STATE_ERROR
else:
last_response = str(last_data)
last_updated = self.coordinator.last_update_success_time
response_time = None
model = self.coordinator.model
temperature = self.coordinator.temperature
max_tokens = self.coordinator.max_tokens
# Convert timestamp to local time if needed
# Конвертация времени в локальный формат
if isinstance(last_updated, datetime):
last_updated = dt_util.as_local(last_updated)
@@ -140,6 +154,9 @@ class HATextAISensor(CoordinatorEntity, SensorEntity):
ATTR_RESPONSE: last_response,
ATTR_LAST_UPDATED: last_updated,
ATTR_TOTAL_RESPONSES: len(history),
ATTR_MODEL: model,
ATTR_TEMPERATURE: temperature,
ATTR_MAX_TOKENS: max_tokens,
})
if response_time is not None:
@@ -169,7 +186,10 @@ class HATextAISensor(CoordinatorEntity, SensorEntity):
"""Handle updated data from the coordinator."""
try:
if self.coordinator.data:
self._state = STATE_READY
if self.coordinator._is_ready:
self._state = STATE_READY
else:
self._state = STATE_DISCONNECTED
else:
self._state = STATE_DISCONNECTED
except Exception as err:
@@ -178,4 +198,4 @@ class HATextAISensor(CoordinatorEntity, SensorEntity):
self._last_error = str(err)
self._state = STATE_ERROR
self.async_write_ha_state()
self.async_write_ha_state() # Исправлено лишнее двоеточие
+20 -15
View File
@@ -28,6 +28,7 @@ ask_question:
name: Model
description: >-
Select an AI model to use (optional, overrides default setting).
You can choose from predefined models or enter your own model identifier.
Different models have different capabilities and token limits.
Note: More capable models may have longer response times and higher API costs.
required: false
@@ -35,6 +36,7 @@ ask_question:
default: "gpt-3.5-turbo"
selector:
select:
custom_value: true
options:
- label: "GPT-3.5 Turbo (Fast & Efficient)"
value: "gpt-3.5-turbo"
@@ -46,6 +48,8 @@ ask_question:
value: "gpt-4-32k"
- label: "GPT-4 Turbo (Latest)"
value: "gpt-4-1106-preview"
- label: "Claude-3 Sonnet"
value: "claude-3-sonnet"
mode: dropdown
temperature:
@@ -84,6 +88,17 @@ ask_question:
step: 1
mode: box
system_prompt:
name: System Prompt
description: >-
Optional system prompt to set context for this specific question.
This will temporarily override the default system prompt.
required: false
example: "You are a home automation expert focused on energy efficiency"
selector:
text:
multiline: true
clear_history:
name: Clear History
description: >-
@@ -121,6 +136,7 @@ get_history:
required: false
selector:
select:
custom_value: true
options:
- label: "All Models"
value: ""
@@ -128,14 +144,15 @@ get_history:
value: "gpt-3.5-turbo"
- label: "GPT-4"
value: "gpt-4"
- label: "Claude-3 Sonnet"
value: "claude-3-sonnet"
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.
Set default system behavior instructions for all future conversations.
This defines how the AI should behave and respond to questions.
fields:
prompt:
name: System Prompt
@@ -156,15 +173,3 @@ set_system_prompt:
selector:
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,96 @@
{
"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 AI integration (OpenAI, Anthropic, etc.)",
"data": {
"api_key": "Your API key",
"model": "AI model to use for responses (e.g., gpt-3.5-turbo, claude-3-sonnet)",
"temperature": "Temperature for response generation (0-2)",
"max_tokens": "Maximum tokens in response (1-4096)",
"api_endpoint": "API endpoint URL (optional, for custom endpoints)",
"request_interval": "Minimum time between API requests (seconds)",
"system_prompt": "Default system prompt for all conversations"
}
}
},
"error": {
"invalid_api_key": "Invalid API key - please check your credentials",
"cannot_connect": "Failed to connect to API - check endpoint and network",
"invalid_model": "Selected model is not available or invalid",
"rate_limit": "API rate limit exceeded - please wait",
"unknown": "Unexpected error occurred - check logs for details"
}
},
"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": {
"model": "AI model selection",
"temperature": "Response temperature (0-2)",
"max_tokens": "Maximum response length",
"request_interval": "Time between requests (seconds)",
"system_prompt": "Default system instructions"
}
}
}
},
"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 and receive a response",
"fields": {
"question": {
"name": "Question",
"description": "Your question or prompt for the AI"
},
"system_prompt": {
"name": "System Prompt",
"description": "Optional system prompt to override default for this question"
},
"model": {
"name": "Model",
"description": "Optional AI model to use for this question"
},
"temperature": {
"name": "Temperature",
"description": "Optional temperature setting for this question (0-2)"
},
"max_tokens": {
"name": "Max Tokens",
"description": "Optional maximum token limit for this response"
}
}
},
"clear_history": {
"name": "Clear History",
"description": "Delete all stored conversation history"
},
"get_history": {
"name": "Get History",
"description": "Retrieve conversation history with metadata",
"fields": {
"limit": {
"name": "Limit",
"description": "Maximum number of conversations to return"
},
"filter_model": {
"name": "Filter Model",
"description": "Optional filter to show only specific model responses"
}
}
},
"set_system_prompt": {
"name": "Set System Prompt",
"description": "Set default system behavior instructions",
"fields": {
"prompt": {
"name": "System Prompt",
"description": "Instructions defining AI behavior and response style"
}
}
}
}
}
@@ -1,61 +1,96 @@
{
"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": "Настройка интеграции с AI-сервисами (OpenAI, Anthropic и др.)",
"data": {
"api_key": "Ваш API-ключ",
"model": "Модель AI для ответов (например, gpt-3.5-turbo, claude-3-sonnet)",
"temperature": "Температура генерации ответов (0-2)",
"max_tokens": "Максимальное количество токенов в ответе (1-4096)",
"api_endpoint": "URL конечной точки API (необязательно, для пользовательских endpoint)",
"request_interval": "Минимальный интервал между запросами к API (секунды)",
"system_prompt": "Системная инструкция по умолчанию для всех диалогов"
}
}
},
"error": {
"invalid_api_key": "Недействительный API-ключ - проверьте учетные данные",
"cannot_connect": "Не удалось подключиться к API - проверьте endpoint и сеть",
"invalid_model": "Выбранная модель недоступна или некорректна",
"rate_limit": "Превышен лимит запросов API - пожалуйста, подождите",
"unknown": "Произошла непредвиденная ошибка - проверьте логи"
}
},
"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": {
"model": "Выбор модели AI",
"temperature": "Температура ответов (0-2)",
"max_tokens": "Максимальная длина ответа",
"request_interval": "Интервал между запросами (секунды)",
"system_prompt": "Системные инструкции по умолчанию"
}
}
}
},
"services": {
"ask_question": "Задать вопрос",
"clear_history": "Очистить историю",
"get_history": олучить историю",
"set_system_prompt": "Установить системный запрос"
"ask_question": {
"name": "Задать вопрос",
"description": "Отправить вопрос модели AI и получить ответ",
"fields": {
"question": {
"name": "Вопрос",
"description": "Ваш вопрос или запрос для AI"
},
"system_prompt": {
"name": "Системная инструкция",
"description": "Необязательная системная инструкция, заменяющая инструкцию по умолчанию для этого вопроса"
},
"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": "Максимальное количество диалогов для возврата"
},
"filter_model": {
"name": "Фильтр по модели",
"description": "Необязательный фильтр для показа ответов только от определенной модели"
}
}
},
"set_system_prompt": {
"name": "Установить системную инструкцию",
"description": "Задать системные инструкции по умолчанию",
"fields": {
"prompt": {
"name": "Системная инструкция",
"description": "Инструкции, определяющие поведение AI и стиль ответов"
}
}
}
}
}
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.1.0",
"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
```