mirror of
https://github.com/smkrv/ha-text-ai.git
synced 2026-07-21 22:54:00 +08:00
Security: - Add SSRF protection via HTTPS-only endpoint validation with private IP blocking - Mask API keys in all log output via safe_log_data() - Sanitize error responses to prevent internal detail leakage - Remove API key pre-population in config flow forms - Harden service schemas with input length limits and type coercion Bug fixes: - Fix temperature=0 rejected due to Python falsy value bug (0 or default) - Fix fire-and-forget race condition in coordinator init (5 async_create_task → awaited async_initialize) - Fix rate limit state not resetting after successful API calls - Fix ConnectionError incorrectly setting is_rate_limited=True - Fix _rotate_history calling async method via sync executor - Fix shutil.move blocking event loop in history migration - Fix async_shutdown removing wrong key from hass.data - Replace os.rename with shutil.move for cross-device safety Improvements: - Add asyncio.Lock for request serialization - Replace async_timeout with stdlib asyncio.timeout (Python 3.12+) - Use SupportsResponse.OPTIONAL for ask_question and get_history services - Use Platform.SENSOR enum instead of string literal - Add strings.json for HA translation framework - Update DEFAULT_ANTHROPIC_MODEL to claude-sonnet-4-6 - Retry only transient errors (429, timeout) in API client Cleanup: - Remove dead code: unused schemas, imports, sync_write_history, check_memory, check_connection - Remove icon copying code from async_setup - Remove unused dependencies from manifest (anthropic, openai, certifi, async-timeout) - Remove empty manifest arrays (bluetooth, mqtt, ssdp, usb, zeroconf) - Fix duplicate JSON keys in 5 translation files - Fix Serbian translation: "Прекључено" → "Искључено" for disconnected state Bump version to 2.4.0
310 lines
16 KiB
JSON
310 lines
16 KiB
JSON
{
|
||
"config": {
|
||
"step": {
|
||
"provider": {
|
||
"title": "Настройки провайдера",
|
||
"description": "Укажите параметры подключения для выбранного провайдера ИИ.",
|
||
"data": {
|
||
"name": "Название экземпляра (например, 'GPT Помощник', 'Клод Ассистент')",
|
||
"api_key": "API-ключ для аутентификации",
|
||
"model": "Модель ИИ для использования",
|
||
"api_endpoint": "Пользовательский URL-адрес конечной точки API (необязательно)",
|
||
"temperature": "Креативность ответа (0-2, меньше = более сфокусированно)",
|
||
"max_tokens": "Максимальная длина ответа (1-100000 токенов)",
|
||
"request_interval": "Минимальный интервал между запросами (0.1-60 секунд)",
|
||
"api_timeout": "Таймаут API-запроса в секундах (5-600)",
|
||
"context_messages": "Количество сохраняемых контекстных сообщений (1-20)",
|
||
"max_history_size": "Максимальный размер истории разговора (1-100)"
|
||
}
|
||
},
|
||
"user": {
|
||
"title": "Настройка экземпляра текстового ИИ для Home Assistant",
|
||
"description": "Настройте новый экземпляр ИИ-помощника с выбранным провайдером.",
|
||
"data": {
|
||
"name": "Название экземпляра (например, 'GPT Помощник', 'Клод Ассистент')",
|
||
"api_key": "API-ключ для аутентификации",
|
||
"model": "Модель ИИ для использования",
|
||
"temperature": "Креативность ответа (0-2, меньше = более сфокусированно)",
|
||
"max_tokens": "Максимальная длина ответа (1-100000 токенов)",
|
||
"api_endpoint": "Пользовательский URL-адрес конечной точки API (необязательно)",
|
||
"api_provider": "Провайдер API",
|
||
"request_interval": "Минимальный интервал между запросами (0.1-60 секунд)",
|
||
"api_timeout": "Таймаут API-запроса в секундах (5-600)",
|
||
"context_messages": "Количество сохраняемых контекстных сообщений (1-20)",
|
||
"max_history_size": "Максимальный размер истории разговора (1-100)"
|
||
}
|
||
}
|
||
},
|
||
"error": {
|
||
"history_storage_error": "Не удалось инициализировать хранилище истории. Проверьте разрешения.",
|
||
"history_rotation_error": "Ошибка при ротации файла истории.",
|
||
"history_file_access_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": "Произошла непредвиденная ошибка",
|
||
"empty": "Имя не может быть пустым",
|
||
"invalid_characters": "Имя может содержать только буквы, цифры, пробелы, подчеркивания и дефисы",
|
||
"name_too_long": "Имя должно быть не длиннее 50 символов"
|
||
},
|
||
"abort": {
|
||
"already_configured": "Экземпляр уже настроен"
|
||
}
|
||
},
|
||
"options": {
|
||
"step": {
|
||
"init": {
|
||
"title": "Выбор провайдера",
|
||
"description": "Выберите провайдера ИИ для этого экземпляра. Интеграция перезагрузится после сохранения изменений.",
|
||
"data": {
|
||
"api_provider": "Провайдер API"
|
||
}
|
||
},
|
||
"settings": {
|
||
"title": "Настройки подключения и модели",
|
||
"description": "Настройте учётные данные API и параметры модели. Изменения вступят в силу после перезагрузки интеграции.",
|
||
"data": {
|
||
"api_key": "API-ключ",
|
||
"api_endpoint": "URL конечной точки API",
|
||
"model": "Модель ИИ",
|
||
"temperature": "Креативность ответа (0-2)",
|
||
"max_tokens": "Максимальная длина ответа (1-100000)",
|
||
"request_interval": "Минимальный интервал между запросами (0.1-60 секунд)",
|
||
"api_timeout": "Таймаут API-запроса в секундах (5-600)",
|
||
"context_messages": "Количество предыдущих сообщений для включения в контекст (1-20)",
|
||
"max_history_size": "Максимальный размер истории разговора (1-100)"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"selector": {
|
||
"api_provider": {
|
||
"options": {
|
||
"openai": "OpenAI (совместимый)",
|
||
"anthropic": "Anthropic (совместимый)",
|
||
"deepseek": "DeepSeek",
|
||
"gemini": "Google Gemini"
|
||
}
|
||
}
|
||
},
|
||
"services": {
|
||
"ask_question": {
|
||
"name": "Задать вопрос (HA Text AI)",
|
||
"description": "Отправить вопрос модели ИИ и получить подробный ответ. Сервис теперь возвращает данные ответа напрямую, устраняя необходимость в отдельных текстовых сенсорах и ограничение в 255 символов. Ответ также будет сохранен в истории разговора.",
|
||
"fields": {
|
||
"instance": {
|
||
"name": "Экземпляр",
|
||
"description": "Название экземпляра текстового ИИ для использования"
|
||
},
|
||
"question": {
|
||
"name": "Вопрос",
|
||
"description": "Ваш вопрос или запрос к ИИ-помощнику"
|
||
},
|
||
"context_messages": {
|
||
"name": "Контекстные сообщения",
|
||
"description": "Количество предыдущих сообщений для включения в контекст (1-20)"
|
||
},
|
||
"system_prompt": {
|
||
"name": "Системный промпт",
|
||
"description": "Необязательный системный промпт для установки контекста для этого конкретного вопроса"
|
||
},
|
||
"model": {
|
||
"name": "Модель",
|
||
"description": "Выберите модель ИИ для использования (необязательно, переопределяет настройки по умолчанию)"
|
||
},
|
||
"temperature": {
|
||
"name": "Температура",
|
||
"description": "Управление креативностью ответа (0.0-2.0)"
|
||
},
|
||
"max_tokens": {
|
||
"name": "Максимум токенов",
|
||
"description": "Максимальная длина ответа (1-100000 токенов)"
|
||
},
|
||
"structured_output": {
|
||
"name": "Структурированный вывод",
|
||
"description": "Включить режим структурированного JSON-вывода. При включении ИИ будет отвечать валидным JSON, соответствующим указанной схеме."
|
||
},
|
||
"json_schema": {
|
||
"name": "JSON Schema",
|
||
"description": "JSON-схема, определяющая структуру ожидаемого ответа. Обязательна при включении structured_output."
|
||
}
|
||
}
|
||
},
|
||
"clear_history": {
|
||
"name": "Очистить историю",
|
||
"description": "Удалить все сохраненные вопросы и ответы из истории разговора",
|
||
"fields": {
|
||
"instance": {
|
||
"name": "Экземпляр",
|
||
"description": "Название экземпляра текстового ИИ для очистки истории"
|
||
}
|
||
}
|
||
},
|
||
"get_history": {
|
||
"name": "Получить историю",
|
||
"description": "Получить историю разговора с дополнительной фильтрацией и сортировкой",
|
||
"fields": {
|
||
"instance": {
|
||
"name": "Экземпляр",
|
||
"description": "Название экземпляра текстового ИИ для получения истории"
|
||
},
|
||
"limit": {
|
||
"name": "Лимит",
|
||
"description": "Количество разговоров для возврата (1-100)"
|
||
},
|
||
"filter_model": {
|
||
"name": "Фильтр модели",
|
||
"description": "Фильтрация разговоров по конкретной модели ИИ"
|
||
},
|
||
"start_date": {
|
||
"name": "Начальная дата",
|
||
"description": "Фильтрация разговоров, начиная с указанной даты/времени"
|
||
},
|
||
"include_metadata": {
|
||
"name": "Включить метаданные",
|
||
"description": "Включить дополнительную информацию, например, использованные токены, время ответа и т.д."
|
||
},
|
||
"sort_order": {
|
||
"name": "Порядок сортировки",
|
||
"description": "Порядок сортировки результатов (сначала новые или старые)"
|
||
}
|
||
}
|
||
},
|
||
"set_system_prompt": {
|
||
"name": "Установить системный промпт",
|
||
"description": "Установить инструкции по умолчанию для поведения ИИ во всех будущих разговорах",
|
||
"fields": {
|
||
"instance": {
|
||
"name": "Экземпляр",
|
||
"description": "Название экземпляра текстового ИИ для установки системного промпта"
|
||
},
|
||
"prompt": {
|
||
"name": "Системный промпт",
|
||
"description": "Инструкции, определяющие, как ИИ должен вести себя и отвечать"
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"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": "Температура"
|
||
},
|
||
"max_tokens": {
|
||
"name": "Максимум токенов"
|
||
},
|
||
"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": "Минимальная задержка"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|