mirror of
https://github.com/smkrv/ha-text-ai.git
synced 2026-07-21 22:54:00 +08:00
feat: add multi-provider support,
config improvements
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
"""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 .coordinator import HATextAICoordinator
|
||||
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
@@ -55,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",
|
||||
@@ -78,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."""
|
||||
@@ -86,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)
|
||||
@@ -103,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)) # убрано лишнее двоеточие
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
"issue_tracker": "https://github.com/smkrv/ha-text-ai/issues",
|
||||
"requirements": ["openai>=1.0.0"],
|
||||
"ssdp": [],
|
||||
"version": "1.0.10",
|
||||
"version": "1.1.0",
|
||||
"zeroconf": []
|
||||
}
|
||||
|
||||
@@ -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() # Исправлено лишнее двоеточие
|
||||
|
||||
@@ -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,10 +144,16 @@ 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:
|
||||
fields:
|
||||
name: Set System Prompt
|
||||
description: >-
|
||||
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
|
||||
description: >-
|
||||
@@ -151,4 +173,3 @@ set_system_prompt:
|
||||
selector:
|
||||
text:
|
||||
multiline: true
|
||||
type: text
|
||||
|
||||
@@ -3,16 +3,24 @@
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Set up HA Text AI",
|
||||
"description": "Configure your OpenAI integration",
|
||||
"description": "Configure your AI integration (OpenAI, Anthropic, etc.)",
|
||||
"data": {
|
||||
"api_key": "Your OpenAI API key",
|
||||
"model": "AI model to use for responses",
|
||||
"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",
|
||||
"request_interval": "Minimum time between API requests (seconds)"
|
||||
"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": {
|
||||
@@ -20,9 +28,11 @@
|
||||
"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"
|
||||
"request_interval": "Time between requests (seconds)",
|
||||
"system_prompt": "Default system instructions"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,25 +40,57 @@
|
||||
"services": {
|
||||
"ask_question": {
|
||||
"name": "Ask Question",
|
||||
"description": "Send a question to the AI model",
|
||||
"fields": {
|
||||
"description": "Send a question to the AI model and receive a response",
|
||||
"fields": {
|
||||
"question": {
|
||||
"name": "Question",
|
||||
"description": "Your question for the AI"
|
||||
"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": "Clear conversation history"
|
||||
"description": "Delete all stored conversation history"
|
||||
},
|
||||
"get_history": {
|
||||
"name": "Get History",
|
||||
"description": "Retrieve conversation 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 system behavior instructions"
|
||||
"description": "Set default system behavior instructions",
|
||||
"fields": {
|
||||
"prompt": {
|
||||
"name": "System Prompt",
|
||||
"description": "Instructions defining AI behavior and response style"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,24 @@
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Настройка HA Text AI",
|
||||
"description": "Настройка интеграции с OpenAI",
|
||||
"description": "Настройка интеграции с AI-сервисами (OpenAI, Anthropic и др.)",
|
||||
"data": {
|
||||
"api_key": "Ваш ключ API OpenAI",
|
||||
"model": "Модель ИИ для генерации ответов",
|
||||
"api_key": "Ваш API-ключ",
|
||||
"model": "Модель AI для ответов (например, gpt-3.5-turbo, claude-3-sonnet)",
|
||||
"temperature": "Температура генерации ответов (0-2)",
|
||||
"max_tokens": "Максимальное количество токенов в ответе (1-4096)",
|
||||
"api_endpoint": "URL конечной точки API",
|
||||
"request_interval": "Минимальное время между запросами к API (секунды)"
|
||||
"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": {
|
||||
@@ -20,9 +28,11 @@
|
||||
"init": {
|
||||
"title": "Настройки HA Text AI",
|
||||
"data": {
|
||||
"model": "Выбор модели AI",
|
||||
"temperature": "Температура ответов (0-2)",
|
||||
"max_tokens": "Максимальная длина ответа",
|
||||
"request_interval": "Время между запросами"
|
||||
"request_interval": "Интервал между запросами (секунды)",
|
||||
"system_prompt": "Системные инструкции по умолчанию"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,25 +40,57 @@
|
||||
"services": {
|
||||
"ask_question": {
|
||||
"name": "Задать вопрос",
|
||||
"description": "Отправить вопрос модели ИИ",
|
||||
"description": "Отправить вопрос модели AI и получить ответ",
|
||||
"fields": {
|
||||
"question": {
|
||||
"name": "Вопрос",
|
||||
"description": "Ваш вопрос для ИИ"
|
||||
"description": "Ваш вопрос или запрос для AI"
|
||||
},
|
||||
"system_prompt": {
|
||||
"name": "Системная инструкция",
|
||||
"description": "Необязательная системная инструкция, заменяющая инструкцию по умолчанию для этого вопроса"
|
||||
},
|
||||
"model": {
|
||||
"name": "Модель",
|
||||
"description": "Необязательная модель AI для этого вопроса"
|
||||
},
|
||||
"temperature": {
|
||||
"name": "Температура",
|
||||
"description": "Необязательная настройка температуры для этого вопроса (0-2)"
|
||||
},
|
||||
"max_tokens": {
|
||||
"name": "Макс. токенов",
|
||||
"description": "Необязательное ограничение количества токенов для этого ответа"
|
||||
}
|
||||
}
|
||||
},
|
||||
"clear_history": {
|
||||
"name": "Очистить историю",
|
||||
"description": "Очистить историю разговора"
|
||||
"description": "Удалить всю сохраненную историю диалогов"
|
||||
},
|
||||
"get_history": {
|
||||
"name": "Получить историю",
|
||||
"description": "Получить историю разговора"
|
||||
"description": "Получить историю диалогов с метаданными",
|
||||
"fields": {
|
||||
"limit": {
|
||||
"name": "Лимит",
|
||||
"description": "Максимальное количество диалогов для возврата"
|
||||
},
|
||||
"filter_model": {
|
||||
"name": "Фильтр по модели",
|
||||
"description": "Необязательный фильтр для показа ответов только от определенной модели"
|
||||
}
|
||||
}
|
||||
},
|
||||
"set_system_prompt": {
|
||||
"name": "Установить системный промпт",
|
||||
"description": "Установить инструкции поведения системы"
|
||||
"name": "Установить системную инструкцию",
|
||||
"description": "Задать системные инструкции по умолчанию",
|
||||
"fields": {
|
||||
"prompt": {
|
||||
"name": "Системная инструкция",
|
||||
"description": "Инструкции, определяющие поведение AI и стиль ответов"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user