mirror of
https://github.com/smkrv/ha-text-ai.git
synced 2026-07-22 23:24:03 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
976f4f16a3 | ||
|
|
2bdef2b494 | ||
|
|
42324a793b | ||
|
|
30aa894634 | ||
|
|
398b2550a9 |
@@ -7,12 +7,27 @@ from homeassistant.const import CONF_API_KEY
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
from homeassistant.helpers import aiohttp_client
|
from homeassistant.helpers import aiohttp_client
|
||||||
|
from homeassistant.helpers import config_validation as cv
|
||||||
|
|
||||||
from .const import DOMAIN, PLATFORMS
|
from .const import (
|
||||||
from .coordinator import HATextAICoordinator
|
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__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool:
|
async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool:
|
||||||
"""Set up the HA Text AI component."""
|
"""Set up the HA Text AI component."""
|
||||||
hass.data.setdefault(DOMAIN, {})
|
hass.data.setdefault(DOMAIN, {})
|
||||||
@@ -26,11 +41,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
coordinator = HATextAICoordinator(
|
coordinator = HATextAICoordinator(
|
||||||
hass,
|
hass,
|
||||||
api_key=entry.data[CONF_API_KEY],
|
api_key=entry.data[CONF_API_KEY],
|
||||||
endpoint=entry.data.get("api_endpoint", "https://api.openai.com/v1"),
|
endpoint=entry.data.get(CONF_API_ENDPOINT, DEFAULT_API_ENDPOINT),
|
||||||
model=entry.data.get("model", "gpt-3.5-turbo"),
|
model=entry.data.get(CONF_MODEL, DEFAULT_MODEL),
|
||||||
temperature=entry.data.get("temperature", 0.7),
|
temperature=entry.data.get(CONF_TEMPERATURE, DEFAULT_TEMPERATURE),
|
||||||
max_tokens=entry.data.get("max_tokens", 1000),
|
max_tokens=entry.data.get(CONF_MAX_TOKENS, DEFAULT_MAX_TOKENS),
|
||||||
request_interval=entry.data.get("request_interval", 1.0),
|
request_interval=entry.data.get(CONF_REQUEST_INTERVAL, DEFAULT_REQUEST_INTERVAL),
|
||||||
session=session,
|
session=session,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -54,7 +69,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
|
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
"Successfully set up HA Text AI with model: %s",
|
"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
|
return True
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ from .const import (
|
|||||||
import logging
|
import logging
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_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({
|
STEP_USER_DATA_SCHEMA = vol.Schema({
|
||||||
vol.Required(CONF_API_KEY): str,
|
vol.Required(CONF_API_KEY): str,
|
||||||
vol.Optional(CONF_MODEL, default=DEFAULT_MODEL): str,
|
vol.Optional(CONF_MODEL, default=DEFAULT_MODEL): str,
|
||||||
@@ -40,29 +43,22 @@ STEP_USER_DATA_SCHEMA = vol.Schema({
|
|||||||
default=DEFAULT_TEMPERATURE
|
default=DEFAULT_TEMPERATURE
|
||||||
): vol.All(
|
): vol.All(
|
||||||
vol.Coerce(float),
|
vol.Coerce(float),
|
||||||
vol.Range(min=0, max=2),
|
vol.Range(min=0, max=2)
|
||||||
msg="Temperature must be between 0 and 2"
|
|
||||||
),
|
),
|
||||||
vol.Optional(
|
vol.Optional(
|
||||||
CONF_MAX_TOKENS,
|
CONF_MAX_TOKENS,
|
||||||
default=DEFAULT_MAX_TOKENS
|
default=DEFAULT_MAX_TOKENS
|
||||||
): vol.All(
|
): vol.All(
|
||||||
vol.Coerce(int),
|
vol.Coerce(int),
|
||||||
vol.Range(min=1, max=4096),
|
vol.Range(min=1, max=4096)
|
||||||
msg="Max tokens must be between 1 and 4096"
|
|
||||||
),
|
|
||||||
vol.Optional(CONF_API_ENDPOINT, default=DEFAULT_API_ENDPOINT): vol.All(
|
|
||||||
str,
|
|
||||||
vol.URL(),
|
|
||||||
msg="Must be a valid URL"
|
|
||||||
),
|
),
|
||||||
|
vol.Optional(CONF_API_ENDPOINT, default=DEFAULT_API_ENDPOINT): str,
|
||||||
vol.Optional(
|
vol.Optional(
|
||||||
CONF_REQUEST_INTERVAL,
|
CONF_REQUEST_INTERVAL,
|
||||||
default=DEFAULT_REQUEST_INTERVAL
|
default=DEFAULT_REQUEST_INTERVAL
|
||||||
): vol.All(
|
): vol.All(
|
||||||
vol.Coerce(float),
|
vol.Coerce(float),
|
||||||
vol.Range(min=0.1),
|
vol.Range(min=0.1)
|
||||||
msg="Request interval must be at least 0.1 seconds"
|
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -73,10 +69,10 @@ async def validate_endpoint(endpoint: str) -> Tuple[bool, str]:
|
|||||||
if parsed_url.scheme not in ('http', 'https'):
|
if parsed_url.scheme not in ('http', 'https'):
|
||||||
return False, "invalid_endpoint_scheme"
|
return False, "invalid_endpoint_scheme"
|
||||||
|
|
||||||
ssl_context = ssl.create_default_context(cafile=certifi.where())
|
connector = aiohttp.TCPConnector(ssl=SSL_CONTEXT)
|
||||||
async with timeout(5):
|
async with timeout(5):
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession(connector=connector) as session:
|
||||||
async with session.get(endpoint, ssl=ssl_context) as response:
|
async with session.get(endpoint) as response:
|
||||||
if response.status != 200:
|
if response.status != 200:
|
||||||
return False, "endpoint_not_available"
|
return False, "endpoint_not_available"
|
||||||
return True, ""
|
return True, ""
|
||||||
@@ -92,71 +88,63 @@ async def validate_api_connection(
|
|||||||
retry_delay: float = 1.0
|
retry_delay: float = 1.0
|
||||||
) -> Tuple[bool, str, list]:
|
) -> Tuple[bool, str, list]:
|
||||||
"""Validate API connection with improved retry logic."""
|
"""Validate API connection with improved retry logic."""
|
||||||
ssl_context = ssl.create_default_context(cafile=certifi.where())
|
|
||||||
|
|
||||||
# Validate endpoint first
|
# Validate endpoint first
|
||||||
endpoint_valid, endpoint_error = await validate_endpoint(endpoint)
|
endpoint_valid, endpoint_error = await validate_endpoint(endpoint)
|
||||||
if not endpoint_valid:
|
if not endpoint_valid:
|
||||||
return False, endpoint_error, []
|
return False, endpoint_error, []
|
||||||
|
|
||||||
for attempt in range(retry_count):
|
connector = aiohttp.TCPConnector(ssl=SSL_CONTEXT)
|
||||||
try:
|
async with aiohttp.ClientSession(connector=connector) as session:
|
||||||
async with timeout(10):
|
for attempt in range(retry_count):
|
||||||
client = AsyncOpenAI(
|
try:
|
||||||
api_key=api_key,
|
async with timeout(10):
|
||||||
base_url=endpoint,
|
client = AsyncOpenAI(
|
||||||
http_client=aiohttp.ClientSession(
|
api_key=api_key,
|
||||||
connector=aiohttp.TCPConnector(
|
base_url=endpoint,
|
||||||
ssl=ssl_context,
|
http_client=session
|
||||||
enable_cleanup_closed=True
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
models = await client.models.list()
|
models = await client.models.list()
|
||||||
model_ids = [model.id for model in models.data]
|
model_ids = [model.id for model in models.data]
|
||||||
finally:
|
|
||||||
await client.http_client.close()
|
|
||||||
|
|
||||||
if model not in model_ids:
|
if model not in model_ids:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Model %s not found in available models: %s",
|
"Model %s not found in available models: %s",
|
||||||
model,
|
model,
|
||||||
", ".join(model_ids)
|
", ".join(model_ids)
|
||||||
)
|
)
|
||||||
return False, "invalid_model", model_ids
|
return False, "invalid_model", model_ids
|
||||||
return True, "", model_ids
|
return True, "", model_ids
|
||||||
|
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Timeout during API validation (attempt %d/%d)",
|
"Timeout during API validation (attempt %d/%d)",
|
||||||
attempt + 1,
|
attempt + 1,
|
||||||
retry_count
|
retry_count
|
||||||
)
|
)
|
||||||
if attempt == retry_count - 1:
|
if attempt == retry_count - 1:
|
||||||
return False, "timeout", []
|
return False, "timeout", []
|
||||||
await asyncio.sleep(retry_delay)
|
await asyncio.sleep(retry_delay)
|
||||||
|
|
||||||
except AuthenticationError as err:
|
except AuthenticationError as err:
|
||||||
_LOGGER.error("Authentication error: %s", str(err))
|
_LOGGER.error("Authentication error: %s", str(err))
|
||||||
return False, "invalid_auth", []
|
return False, "invalid_auth", []
|
||||||
|
|
||||||
except RateLimitError as err:
|
except RateLimitError as err:
|
||||||
_LOGGER.error("Rate limit exceeded: %s", str(err))
|
_LOGGER.error("Rate limit exceeded: %s", str(err))
|
||||||
return False, "rate_limit", []
|
return False, "rate_limit", []
|
||||||
|
|
||||||
except APIConnectionError as err:
|
except APIConnectionError as err:
|
||||||
_LOGGER.error("API connection error: %s", str(err))
|
_LOGGER.error("API connection error: %s", str(err))
|
||||||
return False, "cannot_connect", []
|
return False, "cannot_connect", []
|
||||||
|
|
||||||
except APIError as err:
|
except APIError as err:
|
||||||
_LOGGER.error("API error: %s", str(err))
|
_LOGGER.error("API error: %s", str(err))
|
||||||
return False, "api_error", []
|
return False, "api_error", []
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
_LOGGER.exception("Unexpected error during validation: %s", str(err))
|
_LOGGER.exception("Unexpected error during validation: %s", str(err))
|
||||||
return False, "unknown", []
|
return False, "unknown", []
|
||||||
|
|
||||||
class HATextAIConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
class HATextAIConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
"""Handle a config flow for HA text AI."""
|
"""Handle a config flow for HA text AI."""
|
||||||
@@ -172,12 +160,32 @@ class HATextAIConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
|
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
try:
|
try:
|
||||||
|
# Validate URL format
|
||||||
|
endpoint = user_input.get(CONF_API_ENDPOINT, DEFAULT_API_ENDPOINT)
|
||||||
|
try:
|
||||||
|
result = urlparse(endpoint)
|
||||||
|
if not all([result.scheme, result.netloc]):
|
||||||
|
errors["base"] = "invalid_url_format"
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="user",
|
||||||
|
data_schema=STEP_USER_DATA_SCHEMA,
|
||||||
|
errors=errors
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
_LOGGER.error("URL parsing error: %s", str(e))
|
||||||
|
errors["base"] = "invalid_url_format"
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="user",
|
||||||
|
data_schema=STEP_USER_DATA_SCHEMA,
|
||||||
|
errors=errors
|
||||||
|
)
|
||||||
|
|
||||||
# Validate input data
|
# Validate input data
|
||||||
user_input = STEP_USER_DATA_SCHEMA(user_input)
|
user_input = STEP_USER_DATA_SCHEMA(user_input)
|
||||||
|
|
||||||
is_valid, error_code, available_models = await validate_api_connection(
|
is_valid, error_code, available_models = await validate_api_connection(
|
||||||
user_input[CONF_API_KEY],
|
user_input[CONF_API_KEY],
|
||||||
user_input.get(CONF_API_ENDPOINT, DEFAULT_API_ENDPOINT),
|
endpoint,
|
||||||
user_input[CONF_MODEL]
|
user_input[CONF_MODEL]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -244,8 +252,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
|||||||
description={"suggested_value": DEFAULT_TEMPERATURE},
|
description={"suggested_value": DEFAULT_TEMPERATURE},
|
||||||
): vol.All(
|
): vol.All(
|
||||||
vol.Coerce(float),
|
vol.Coerce(float),
|
||||||
vol.Range(min=0, max=2),
|
vol.Range(min=0, max=2)
|
||||||
msg="Temperature must be between 0 and 2"
|
|
||||||
),
|
),
|
||||||
vol.Optional(
|
vol.Optional(
|
||||||
CONF_MAX_TOKENS,
|
CONF_MAX_TOKENS,
|
||||||
@@ -255,8 +262,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
|||||||
description={"suggested_value": DEFAULT_MAX_TOKENS},
|
description={"suggested_value": DEFAULT_MAX_TOKENS},
|
||||||
): vol.All(
|
): vol.All(
|
||||||
vol.Coerce(int),
|
vol.Coerce(int),
|
||||||
vol.Range(min=1, max=4096),
|
vol.Range(min=1, max=4096)
|
||||||
msg="Max tokens must be between 1 and 4096"
|
|
||||||
),
|
),
|
||||||
vol.Optional(
|
vol.Optional(
|
||||||
CONF_REQUEST_INTERVAL,
|
CONF_REQUEST_INTERVAL,
|
||||||
@@ -266,8 +272,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
|||||||
description={"suggested_value": DEFAULT_REQUEST_INTERVAL},
|
description={"suggested_value": DEFAULT_REQUEST_INTERVAL},
|
||||||
): vol.All(
|
): vol.All(
|
||||||
vol.Coerce(float),
|
vol.Coerce(float),
|
||||||
vol.Range(min=0.1),
|
vol.Range(min=0.1)
|
||||||
msg="Request interval must be at least 0.1 seconds"
|
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,6 @@
|
|||||||
"issue_tracker": "https://github.com/smkrv/ha-text-ai/issues",
|
"issue_tracker": "https://github.com/smkrv/ha-text-ai/issues",
|
||||||
"requirements": ["openai>=1.0.0"],
|
"requirements": ["openai>=1.0.0"],
|
||||||
"ssdp": [],
|
"ssdp": [],
|
||||||
"version": "1.0.4",
|
"version": "1.0.7",
|
||||||
"zeroconf": []
|
"zeroconf": []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,192 +1,61 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"step": {
|
"option": {
|
||||||
"user": {
|
"api_key": {
|
||||||
"title": "Set up HA Text AI",
|
"name": "API Key",
|
||||||
"description": "Configure your OpenAI integration for smart home interactions. You'll need an OpenAI API key from platform.openai.com to proceed.",
|
"description": "Your OpenAI API key"
|
||||||
"data": {
|
},
|
||||||
"api_key": {
|
"model": {
|
||||||
"name": "OpenAI API Key",
|
"name": "Model",
|
||||||
"description": "Your OpenAI API key from platform.openai.com. Keep this secure and never share it."
|
"description": "AI model to use for responses"
|
||||||
},
|
},
|
||||||
"model": {
|
"temperature": {
|
||||||
"name": "AI Model",
|
"name": "Temperature",
|
||||||
"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."
|
"description": "Temperature for response generation (0-2)"
|
||||||
},
|
},
|
||||||
"temperature": {
|
"max_tokens": {
|
||||||
"name": "Temperature",
|
"name": "Max Tokens",
|
||||||
"description": "Controls response creativity (0-2). Low values (0.1-0.3) for focused responses, high values (0.8-2.0) for creative ones."
|
"description": "Maximum tokens in response (1-4096)"
|
||||||
},
|
},
|
||||||
"max_tokens": {
|
"api_endpoint": {
|
||||||
"name": "Max Tokens",
|
"name": "API Endpoint",
|
||||||
"description": "Maximum length of responses. Higher values allow longer responses but consume more API tokens. Recommended: 512-1024."
|
"description": "API endpoint URL"
|
||||||
},
|
},
|
||||||
"api_endpoint": {
|
"request_interval": {
|
||||||
"name": "API Endpoint",
|
"name": "Request Interval",
|
||||||
"description": "OpenAI API endpoint URL. Leave default unless using a custom endpoint or proxy."
|
"description": "Minimum time between API requests (seconds)"
|
||||||
},
|
}
|
||||||
"request_interval": {
|
|
||||||
"name": "Request Interval",
|
|
||||||
"description": "Minimum time between API requests in seconds. Increase if experiencing rate limits."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"options": {
|
||||||
|
"temperature": "Temperature",
|
||||||
|
"max_tokens": "Max Tokens",
|
||||||
|
"request_interval": "Request Interval"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"invalid_auth": "Invalid API key. Please check your OpenAI API key and try again.",
|
"invalid_api_key": "Invalid API key",
|
||||||
"cannot_connect": "Failed to connect to API. Please check your internet connection and API endpoint.",
|
"cannot_connect": "Cannot connect to the API",
|
||||||
"unknown": "Unexpected error occurred. Please check the logs for more details.",
|
"unknown_error": "Unknown error",
|
||||||
"already_exists": "This API key is already configured in another integration.",
|
"invalid_model": "Invalid model",
|
||||||
"invalid_model": "Selected model is not available. Please choose a different model.",
|
"rate_limit_exceeded": "Rate limit exceeded",
|
||||||
"rate_limit": "API rate limit exceeded. Please try again later or increase the request interval.",
|
"context_length_exceeded": "Context length exceeded",
|
||||||
"context_length": "Input too long for selected model. Try reducing max tokens or using a model with larger context.",
|
"api_error": "API error",
|
||||||
"api_error": "OpenAI API error. Please check the logs for details.",
|
"timeout_error": "Timeout error",
|
||||||
"timeout": "API response timeout. Request took too long to complete.",
|
"queue_full": "Queue full",
|
||||||
"queue_full": "Request queue is full. Please try again later."
|
"invalid_prompt": "Invalid prompt"
|
||||||
},
|
},
|
||||||
"abort": {
|
"state": {
|
||||||
"already_configured": "This OpenAI integration is already configured",
|
"ready": "Ready",
|
||||||
"auth_failed": "Authentication failed. Please verify your API key.",
|
"processing": "Processing",
|
||||||
"invalid_endpoint": "Invalid API endpoint URL provided"
|
"error": "Error",
|
||||||
}
|
"disconnected": "Disconnected",
|
||||||
},
|
"rate_limited": "Rate limited",
|
||||||
"options": {
|
"initializing": "Initializing"
|
||||||
"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": {
|
"services": {
|
||||||
"name": "Clear History",
|
"ask_question": "Ask Question",
|
||||||
"description": "Delete all stored conversation history. This action cannot be undone."
|
"clear_history": "Clear History",
|
||||||
},
|
"get_history": "Get History",
|
||||||
"get_history": {
|
"set_system_prompt": "Set System Prompt"
|
||||||
"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."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,192 +1,61 @@
|
|||||||
{
|
{
|
||||||
"config": {
|
"config": {
|
||||||
"step": {
|
"option": {
|
||||||
"user": {
|
"api_key": {
|
||||||
"title": "Настройка HA Text AI",
|
"name": "API ключ",
|
||||||
"description": "Настройте интеграцию OpenAI для умного дома. Требуется API ключ OpenAI. Подробнее о получении ключа на platform.openai.com",
|
"description": "Ваш API ключ OpenAI"
|
||||||
"data": {
|
},
|
||||||
"api_key": {
|
"model": {
|
||||||
"name": "API ключ OpenAI",
|
"name": "Модель",
|
||||||
"description": "Ваш API ключ с platform.openai.com. Храните его в безопасности."
|
"description": "Модель AI для генерации ответов"
|
||||||
},
|
},
|
||||||
"model": {
|
"temperature": {
|
||||||
"name": "AI Модель",
|
"name": "Температура",
|
||||||
"description": "Выберите модель AI. GPT-3.5-Turbo рекомендуется для большинства задач как оптимальное сочетание возможностей и стоимости."
|
"description": "Температура для генерации ответов (0-2)"
|
||||||
},
|
},
|
||||||
"temperature": {
|
"max_tokens": {
|
||||||
"name": "Температура",
|
"name": "Максимальное количество токенов",
|
||||||
"description": "Контролирует креативность ответов (0-2). Низкие значения (0.1-0.3) для точных ответов, высокие (0.8-2.0) для творческих."
|
"description": "Максимальное количество токенов в ответе (1-4096)"
|
||||||
},
|
},
|
||||||
"max_tokens": {
|
"api_endpoint": {
|
||||||
"name": "Максимум токенов",
|
"name": "Конечная точка API",
|
||||||
"description": "Максимальная длина ответов. Больше токенов = длиннее ответы, но выше расход API токенов. Рекомендуется: 512-1024."
|
"description": "URL конечной точки API"
|
||||||
},
|
},
|
||||||
"api_endpoint": {
|
"request_interval": {
|
||||||
"name": "API Endpoint",
|
"name": "Интервал запросов",
|
||||||
"description": "URL API OpenAI. Оставьте значение по умолчанию, если не используете собственный endpoint."
|
"description": "Минимальное время между запросами к API в секундах"
|
||||||
},
|
}
|
||||||
"request_interval": {
|
|
||||||
"name": "Интервал запросов",
|
|
||||||
"description": "Минимальное время между API запросами в секундах. Увеличьте при превышении лимитов запросов."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"options": {
|
||||||
|
"temperature": "Температура",
|
||||||
|
"max_tokens": "Максимальное количество токенов",
|
||||||
|
"request_interval": "Интервал запросов"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"invalid_auth": "Неверный API ключ. Проверьте ключ OpenAI и попробуйте снова.",
|
"invalid_api_key": "Неверный API ключ",
|
||||||
"cannot_connect": "Не удалось подключиться к API. Проверьте подключение к интернету и endpoint.",
|
"cannot_connect": "Не удается подключиться к API",
|
||||||
"unknown": "Неожиданная ошибка. Проверьте логи для подробностей.",
|
"unknown_error": "Неизвестная ошибка",
|
||||||
"already_exists": "Этот API ключ уже используется в другой интеграции.",
|
"invalid_model": "Неверная модель",
|
||||||
"invalid_model": "Выбранная модель недоступна. Выберите другую модель.",
|
"rate_limit_exceeded": "Превышен лимит запросов",
|
||||||
"rate_limit": "Превышен лимит API запросов. Попробуйте позже или увеличьте интервал запросов.",
|
"context_length_exceeded": "Превышена длина контекста",
|
||||||
"context_length": "Входные данные слишком длинные для выбранной модели. Уменьшите max_tokens или используйте модель с большим контекстом.",
|
"api_error": "Ошибка API",
|
||||||
"api_error": "Ошибка API OpenAI. Проверьте логи для подробностей.",
|
"timeout_error": "Время ожидания истекло",
|
||||||
"timeout": "Превышено время ожидания ответа от API.",
|
"queue_full": "Очередь полна",
|
||||||
"queue_full": "Очередь запросов переполнена. Попробуйте позже."
|
"invalid_prompt": "Неверный запрос"
|
||||||
},
|
},
|
||||||
"abort": {
|
"state": {
|
||||||
"already_configured": "Эта интеграция OpenAI уже настроена",
|
"ready": "Готово",
|
||||||
"auth_failed": "Ошибка аутентификации. Проверьте API ключ.",
|
"processing": "Обработка",
|
||||||
"invalid_endpoint": "Указан неверный URL API endpoint"
|
"error": "Ошибка",
|
||||||
}
|
"disconnected": "Отключено",
|
||||||
},
|
"rate_limited": "Ограниченный по скорости",
|
||||||
"options": {
|
"initializing": "Инициализация"
|
||||||
"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": {
|
"services": {
|
||||||
"name": "Очистить историю",
|
"ask_question": "Задать вопрос",
|
||||||
"description": "Удалить всю историю разговоров. Это действие нельзя отменить."
|
"clear_history": "Очистить историю",
|
||||||
},
|
"get_history": "Получить историю",
|
||||||
"get_history": {
|
"set_system_prompt": "Установить системный запрос"
|
||||||
"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": "Удалить текущий системный промпт перед установкой нового."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -4,6 +4,6 @@
|
|||||||
"domains": ["sensor"],
|
"domains": ["sensor"],
|
||||||
"homeassistant": "2024.11.0",
|
"homeassistant": "2024.11.0",
|
||||||
"icon": "mdi:brain",
|
"icon": "mdi:brain",
|
||||||
"version": "1.0.4",
|
"version": "1.0.7",
|
||||||
"documentation": "https://github.com/smkrv/ha-text-ai"
|
"documentation": "https://github.com/smkrv/ha-text-ai"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user