Compare commits

..
12 Commits
Author SHA1 Message Date
SMKRV 3097106e93 feat: Add configurable API timeout setting
- Add CONF_API_TIMEOUT configuration option (5-600 seconds, default 30)
- Update config_flow.py with api_timeout field in provider form and options flow
- Update api_client.py to use configurable timeout instead of hardcoded value
- Update coordinator.py to use api_timeout for async_process_message
- Update __init__.py to read and pass api_timeout from config
- Merge entry.data with entry.options for proper options flow support
- Add translations for api_timeout in all 8 language files (en, ru, de, es, it, hi, sr, zh)
- Bump version to 2.2.0

Closes #8
2025-12-22 00:07:17 +03:00
smkrvandGitHub 35073960b8 Delete ha-text-ai.code-workspace 2025-09-03 00:56:56 +03:00
SMKRV 8d0e0b5e44 docs: update README with context_messages parameter
- Added context_messages parameter to Platform Configuration table
- Fixed duplicate parameter entry in configuration docs
- Parameter allows 1-20 previous messages in context (default: 5)
2025-09-02 23:50:20 +03:00
SMKRV e91c3701c5 Fix: Resolve get_history service parameter handling issue
- Fixed async_get_history method to accept limit parameter and other filtering options
- Updated service schema to support all parameters from services.yaml
- Added support for start_date, include_metadata, and sort_order parameters
- Version bump to 2.1.9
2025-09-02 23:27:34 +03:00
smkrv 7f62101b3e Update HACS minimum HA version to align with README requirement (2024.12.0) 2025-09-02 23:15:01 +03:00
smkrvandGitHub 3729c3736f Update hassfest.yaml 2025-09-02 09:36:46 +03:00
smkrvandGitHub f5ce5e459a Update hassfest.yaml
fix: https://github.com/smkrv/ha-text-ai/security/code-scanning/2
2025-09-02 09:24:35 +03:00
smkrvGitHubCopilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
4064486b1e Potential fix for code scanning alert no. 1: Workflow does not contain permissions
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-09-02 09:18:15 +03:00
SMKRV 185778dbd0 docs: Update AI models to latest versions
- Update OpenAI models to GPT-5 and GPT-5 mini
- Update Anthropic Claude models to 4.1, 4.0 series
- Update DeepSeek models to V3.1 and R1
- Update Google Gemini models to 2.5 and 2.0 series
- Modernize model descriptions and capabilities
2025-09-02 02:19:37 +03:00
SMKRV 83a255dee0 docs: Update README.md - actualize documentation
- Simplify HACS installation instructions
- Update recommended models section (remove year from title)
- Update Claude model names to current format (claude-3.5-sonnet, claude-3.5-haiku)
- Add missing parameters to get_history service documentation
- Remove non-configurable history_file_size parameter from table
- Add missing context_messages parameter to configuration table
- Update all model references in examples to use current naming
2025-09-02 02:11:34 +03:00
SMKRV 6b66dd6a4d docs: Update README with latest configuration defaults and Gemini models
- Update default model from gpt-4o to gpt-4o-mini
- Update default temperature from 0.7 to 0.1
- Update default max_history_size from 100 to 50
- Add gemini-2.0-flash as latest recommended Gemini model
- Fix logo image link to use main branch instead of specific commit
- Update configuration parameters table with current defaults
2025-09-02 02:06:58 +03:00
SMKRV bd82f23120 docs: Update HACS badge from Custom to Default 2025-09-02 01:56:24 +03:00
18 changed files with 217 additions and 57 deletions
+2 -1
View File
@@ -1,5 +1,6 @@
name: Validate with hassfest name: Validate with hassfest
permissions:
contents: read
on: on:
push: push:
branches: branches:
+2
View File
@@ -1,4 +1,6 @@
name: Validate name: Validate
permissions:
contents: read
on: on:
push: push:
+61 -31
View File
@@ -2,11 +2,11 @@
<div align="center"> <div align="center">
![GitHub release](https://img.shields.io/github/v/release/smkrv/ha-text-ai?style=flat-square) ![GitHub last commit](https://img.shields.io/github/last-commit/smkrv/ha-text-ai?style=flat-square) [![License: CC BY-NC-SA 4.0](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg?style=flat-square)](https://creativecommons.org/licenses/by-nc-sa/4.0/) [![hacs_badge](https://img.shields.io/badge/HACS-Custom-41BDF5.svg?style=flat-square)](https://github.com/hacs/integration) ![GitHub release](https://img.shields.io/github/v/release/smkrv/ha-text-ai?style=flat-square) ![GitHub last commit](https://img.shields.io/github/last-commit/smkrv/ha-text-ai?style=flat-square) [![License: CC BY-NC-SA 4.0](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg?style=flat-square)](https://creativecommons.org/licenses/by-nc-sa/4.0/) [![hacs_badge](https://img.shields.io/badge/HACS-Default-41BDF5.svg?style=flat-square)](https://github.com/hacs/integration)
![Deutsch](https://img.shields.io/badge/lang-DE-blue?style=flat-square) ![English](https://img.shields.io/badge/lang-EN-blue?style=flat-square) ![Español](https://img.shields.io/badge/lang-ES-blue?style=flat-square) ![हिन्दी](https://img.shields.io/badge/lang-HI-blue?style=flat-square) ![Italiano](https://img.shields.io/badge/lang-IT-blue?style=flat-square) ![Русский](https://img.shields.io/badge/lang-RU-blue?style=flat-square) ![Српски](https://img.shields.io/badge/lang-SR-blue?style=flat-square) ![中文](https://img.shields.io/badge/lang-ZH-blue?style=flat-square) ![Deutsch](https://img.shields.io/badge/lang-DE-blue?style=flat-square) ![English](https://img.shields.io/badge/lang-EN-blue?style=flat-square) ![Español](https://img.shields.io/badge/lang-ES-blue?style=flat-square) ![हिन्दी](https://img.shields.io/badge/lang-HI-blue?style=flat-square) ![Italiano](https://img.shields.io/badge/lang-IT-blue?style=flat-square) ![Русский](https://img.shields.io/badge/lang-RU-blue?style=flat-square) ![Српски](https://img.shields.io/badge/lang-SR-blue?style=flat-square) ![中文](https://img.shields.io/badge/lang-ZH-blue?style=flat-square)
<img src="https://github.com/smkrv/ha-text-ai/blob/15c717fcb0204bf4a0d4b4b4c6f0bb93e9f6c9a9/custom_components/ha_text_ai/icons/logo%402x.png" alt="HA Text AI" style="width: 50%; max-width: 256px; max-height: 128px; aspect-ratio: 2/1; object-fit: contain;"/> <img src="https://github.com/smkrv/ha-text-ai/blob/main/custom_components/ha_text_ai/icons/logo%402x.png" alt="HA Text AI" style="width: 50%; max-width: 256px; max-height: 128px; aspect-ratio: 2/1; object-fit: contain;"/>
### Advanced AI Integration for [Home Assistant](https://www.home-assistant.io/) with LLM multi-provider support ### Advanced AI Integration for [Home Assistant](https://www.home-assistant.io/) with LLM multi-provider support
</div> </div>
@@ -106,7 +106,7 @@ Transform your smart home experience with powerful AI assistance powered by mult
## 📋 Prerequisites ## 📋 Prerequisites
- Home Assistant 2024.2.2 or later - Home Assistant 2024.12.0 or later (recommended for best compatibility)
- Active API key from: - Active API key from:
- OpenAI ([Get key](https://platform.openai.com/account/api-keys)) - OpenAI ([Get key](https://platform.openai.com/account/api-keys))
- Anthropic ([Get key](https://console.anthropic.com/)) - Anthropic ([Get key](https://console.anthropic.com/))
@@ -120,7 +120,7 @@ Transform your smart home experience with powerful AI assistance powered by mult
## Configuration Options ## Configuration Options
### 🔧 **Core Configuration Settings** ### 🔧 **Core Configuration Settings**
- 🌐 **API Provider**: OpenAI/Anthropic/DeepSeek - 🌐 **API Provider**: OpenAI/Anthropic/DeepSeek/Gemini
- 🔑 **API Key**: Provider-specific authentication - 🔑 **API Key**: Provider-specific authentication
- 🤖 **Model Selection**: Flexible, provider-specific models - 🤖 **Model Selection**: Flexible, provider-specific models
- 🌡️ **Temperature**: Creativity control (0.0-2.0) - 🌡️ **Temperature**: Creativity control (0.0-2.0)
@@ -129,6 +129,25 @@ Transform your smart home experience with powerful AI assistance powered by mult
- 💾 **History Size**: Number of messages to retain - 💾 **History Size**: Number of messages to retain
- 🌍 **Custom API Endpoint**: Optional advanced configuration - 🌍 **Custom API Endpoint**: Optional advanced configuration
### 🤖 **Recommended Models**
#### OpenAI Models
- **GPT-5** - The latest flagship model, best for complex reasoning
- **GPT-5 mini** - A cost-effective and fast model, suitable for most tasks
#### Anthropic Claude Models
- **Claude Opus 4.1** - The most capable model for handling complex tasks
- **Claude Sonnet 4** - Offers a balance between performance and cost
- **Claude Haiku 4** - The fastest and most economical option in the series
#### DeepSeek Models
- **DeepSeek-V3.1** - A general-purpose model for a wide range of tasks
- **DeepSeek-R1** - A specialized model focused on reasoning and coding
#### Google Gemini Models
- **Gemini 2.5 Pro & 2.5 Flash** - The newest and most advanced models available
- **Gemini 2.0 Pro & 2.0 Flash** - Previous generation models that are still powerful and efficient
<details> <details>
<summary>🌐 Potentially Compatible Providers</summary> <summary>🌐 Potentially Compatible Providers</summary>
@@ -166,12 +185,17 @@ To be compatible, a provider should support:
<a href="https://my.home-assistant.io/redirect/hacs_repository/?owner=smkrv&repository=ha-text-ai&category=Integration"><img src="https://my.home-assistant.io/badges/hacs_repository.svg" width="170" height="auto"></a> <a href="https://my.home-assistant.io/redirect/hacs_repository/?owner=smkrv&repository=ha-text-ai&category=Integration"><img src="https://my.home-assistant.io/badges/hacs_repository.svg" width="170" height="auto"></a>
1. Open HACS in Home Assistant 1. Open HACS in Home Assistant
2. Click on "Integrations" 2. Click on "Integrations"
3. Click "..." in top right corner 3. Search for "HA Text AI"
4. Select "Custom repositories" 4. Click "Download"
5. Add repository URL: `https://github.com/smkrv/ha-text-ai` 5. Restart Home Assistant
6. Choose "Integration" as category
7. Click "Download" **Alternative Method (Custom Repository):**
8. Restart Home Assistant If the integration is not found in the default repository:
1. Click "..." in top right corner of HACS
2. Select "Custom repositories"
3. Add repository URL: `https://github.com/smkrv/ha-text-ai`
4. Choose "Integration" as category
5. Click "Download"
### Manual Installation ### Manual Installation
1. Download the latest release 1. Download the latest release
@@ -196,7 +220,7 @@ To be compatible, a provider should support:
ha_text_ai: ha_text_ai:
api_provider: openai # Required api_provider: openai # Required
api_key: !secret ai_api_key # Required api_key: !secret ai_api_key # Required
model: gpt-4o-mini # Strongly recommended model: gpt-4o # Strongly recommended
temperature: 0.7 # Optional temperature: 0.7 # Optional
max_tokens: 1000 # Optional max_tokens: 1000 # Optional
request_interval: 1.0 # Optional request_interval: 1.0 # Optional
@@ -213,7 +237,7 @@ sensor:
- platform: ha_text_ai - platform: ha_text_ai
name: "My AI Assistant" # Required, unique identifier name: "My AI Assistant" # Required, unique identifier
api_provider: openai # Optional (inherits from platform) api_provider: openai # Optional (inherits from platform)
model: "gpt-4o-mini" # Optional model: "gpt-4o" # Optional
temperature: 0.7 # Optional temperature: 0.7 # Optional
max_tokens: 1000 # Optional max_tokens: 1000 # Optional
``` ```
@@ -224,16 +248,16 @@ sensor:
| Parameter | Type | Required | Default | Description | | Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------| |-----------|------|----------|---------|-------------|
| `api_provider` | String | ✅ | - | AI service provider (openai, anthropic) | | `api_provider` | String | ✅ | - | AI service provider (openai, anthropic, deepseek, gemini) |
| `api_key` | String | ✅ | - | Authentication key for AI service | | `api_key` | String | ✅ | - | Authentication key for AI service |
| `model` | String | ⚠️ | Provider default | Strongly recommended: Specific AI model to use. If not specified, the provider's default model will be used | | `model` | String | ⚠️ | gpt-4o-mini | Strongly recommended: Specific AI model to use. Default varies by provider |
| `temperature` | Float | ❌ | 0.7 | Response creativity level (0.0-2.0) | | `temperature` | Float | ❌ | 0.1 | Response creativity level (0.0-2.0) |
| `max_tokens` | Integer | ❌ | 1000 | Maximum response length | | `max_tokens` | Integer | ❌ | 1000 | Maximum response length |
| `request_interval` | Float | ❌ | 1.0 | Delay between API requests | | `request_interval` | Float | ❌ | 1.0 | Delay between API requests |
| `api_endpoint` | URL | ⚠️ | Provider default | Custom API endpoint | | `api_endpoint` | URL | ⚠️ | Provider default | Custom API endpoint |
| `system_prompt` | String | ❌ | - | Default context for AI interactions | | `system_prompt` | String | ❌ | - | Default context for AI interactions |
| `max_history_size` | Integer | ❌ | 100 | Maximum number of conversation entries to store | | `max_history_size` | Integer | ❌ | 50 | Maximum number of conversation entries to store |
| `history_file_size` | Integer | ⚠️ | 1 | Maximum history file size in MB | | `context_messages` | Integer | | 5 | Number of previous messages to include in context (1-20) |
#### Sensor Configuration #### Sensor Configuration
@@ -242,9 +266,9 @@ sensor:
| `platform` | String | ✅ | - | Must be `ha_text_ai` | | `platform` | String | ✅ | - | Must be `ha_text_ai` |
| `name` | String | ✅ | - | Unique sensor identifier | | `name` | String | ✅ | - | Unique sensor identifier |
| `api_provider` | String | ❌ | Platform setting | Override global provider | | `api_provider` | String | ❌ | Platform setting | Override global provider |
| `model` | String | ⚠️ | Platform setting | Recommended: Override global model. If not specified, uses platform or provider default | | `model` | String | ⚠️ | Provider default | Recommended: Override global model (gpt-4o-mini, deepseek-chat, gemini-2.0-flash) |
| `temperature` | Float | ❌ | Platform setting | Override global temperature | | `temperature` | Float | ❌ | 0.1 | Override global temperature |
| `max_tokens` | Integer | ❌ | Platform setting | Override global max tokens | | `max_tokens` | Integer | ❌ | 1000 | Override global max tokens |
</details> </details>
@@ -265,7 +289,7 @@ sensor:
service: ha_text_ai.ask_question service: ha_text_ai.ask_question
data: data:
question: "What's the optimal temperature for sleeping?" question: "What's the optimal temperature for sleeping?"
model: "claude-3-sonnet" # optional model: "claude-3.5-sonnet" # optional
temperature: 0.5 # optional temperature: 0.5 # optional
max_tokens: 500 # optional max_tokens: 500 # optional
context_messages: 10 #optional, number of previous messages to include in context, default: 5 context_messages: 10 #optional, number of previous messages to include in context, default: 5
@@ -281,10 +305,10 @@ response_text: "The optimal sleeping temperature is 65-68°F (18-20°C)..."
tokens_used: 150 tokens_used: 150
prompt_tokens: 50 prompt_tokens: 50
completion_tokens: 100 completion_tokens: 100
model_used: "claude-3-sonnet" model_used: "claude-3.5-sonnet"
instance: "sensor.ha_text_ai_gpt" instance: "sensor.ha_text_ai_gpt"
question: "What's the optimal temperature for sleeping?" question: "What's the optimal temperature for sleeping?"
timestamp: "2025-01-09T16:57:00.000Z" timestamp: "2025-02-09T16:57:00.000Z"
success: true success: true
# error: "Error message" (only present if success: false) # error: "Error message" (only present if success: false)
``` ```
@@ -313,8 +337,11 @@ data:
```yaml ```yaml
service: ha_text_ai.get_history service: ha_text_ai.get_history
data: data:
limit: 5 # optional limit: 5 # optional, number of conversations to return (1-100)
filter_model: "gpt-4o" # optional filter_model: "gpt-4o" # optional, filter by specific AI model
start_date: "2025-02-01" # optional, filter conversations from this date
include_metadata: false # optional, include tokens, response time, etc.
sort_order: "newest" # optional, sort order: "newest" or "oldest"
instance: sensor.ha_text_ai_gpt instance: sensor.ha_text_ai_gpt
``` ```
@@ -626,10 +653,10 @@ Conversation history stored in `.storage/ha_text_ai_history/` directory:
## 📘 FAQ ## 📘 FAQ
**Q: Which AI providers are supported?** **Q: Which AI providers are supported?**
A: Currently OpenAI (GPT models) and Anthropic (Claude models) are supported, with more providers planned. A: OpenAI (GPT models), Anthropic (Claude models), DeepSeek, Google Gemini, and OpenRouter are officially supported, with many other OpenAI-compatible providers working as well.
**Q: How can I reduce API costs?** **Q: How can I reduce API costs?**
A: Use GPT-3.5-Turbo or Claude-3-Sonnet for most queries, implement caching, and optimize token usage. A: Use gpt-4o-mini or claude-3.5-haiku for most queries, implement caching, and optimize token usage.
**Q: Are there limitations on the number of requests?** **Q: Are there limitations on the number of requests?**
A: Depends on your API provider's plan. We recommend monitoring usage and implementing request throttling via `request_interval` configuration. A: Depends on your API provider's plan. We recommend monitoring usage and implementing request throttling via `request_interval` configuration.
@@ -640,8 +667,11 @@ A: Yes, you can configure custom endpoints and use any compatible model by speci
**Q: How do I switch between different AI providers?** **Q: How do I switch between different AI providers?**
A: Simply change the model parameter in your configuration or service calls to use the desired provider's model. A: Simply change the model parameter in your configuration or service calls to use the desired provider's model.
**Q: How can I reduce API costs?** **Q: What are the token limits for different models?**
A: Use GPT-3.5-Turbo for most queries, implement caching, and optimize token usage. A: Token limits vary by provider and model. OpenAI's gpt-4o supports up to 128K tokens, Claude 3.5 Sonnet supports up to 200K tokens, while smaller models typically have 8K-32K limits. Check your provider's documentation for specific limits.
**Q: How do I monitor token usage?**
A: Use the sensor attributes like `Total tokens`, `Prompt tokens`, and `Completion tokens` to track usage. You can also create automations to alert you when usage exceeds certain thresholds.
**Q: Is my data secure?** **Q: Is my data secure?**
A: Yes, your data is secure. The system operates entirely on your local machine, keeping your data under your control. API keys are stored securely and all external communications use encrypted connections. A: Yes, your data is secure. The system operates entirely on your local machine, keeping your data under your control. API keys are stored securely and all external communications use encrypted connections.
@@ -707,9 +737,9 @@ If you want to say thanks financially, you can send a small token of appreciatio
<div align="center"><img src="https://github.com/smkrv/ha-text-ai/blob/2aaf3405759eb2d97624834594e24ace896131df/assets/images/icons/footer_icon.png" alt="HA Text AI" style="width: 128px; height: auto;"/></div> <div align="center"><img src="https://github.com/smkrv/ha-text-ai/blob/2aaf3405759eb2d97624834594e24ace896131df/assets/images/icons/footer_icon.png" alt="HA Text AI" style="width: 128px; height: auto;"/></div>
<div align="center"> <div align="center">
Made with ❤️ for the Home Assistant Community, Made with ❤️ for the Home Assistant Community
utilizing Claude 3.5 Sonnet, Gemini Pro 1.5, and Qwen 2.5 Coder 32B Instruct.
[Report Bug](https://github.com/smkrv/ha-text-ai/issues) · [Request Feature](https://github.com/smkrv/ha-text-ai/issues) [Report Bug](https://github.com/smkrv/ha-text-ai/issues) · [Request Feature](https://github.com/smkrv/ha-text-ai/issues)
</div> </div>
+26 -15
View File
@@ -35,6 +35,7 @@ from .const import (
CONF_MAX_TOKENS, CONF_MAX_TOKENS,
CONF_API_ENDPOINT, CONF_API_ENDPOINT,
CONF_REQUEST_INTERVAL, CONF_REQUEST_INTERVAL,
CONF_API_TIMEOUT,
CONF_API_PROVIDER, CONF_API_PROVIDER,
CONF_CONTEXT_MESSAGES, CONF_CONTEXT_MESSAGES,
API_PROVIDER_OPENAI, API_PROVIDER_OPENAI,
@@ -51,8 +52,8 @@ from .const import (
DEFAULT_DEEPSEEK_ENDPOINT, DEFAULT_DEEPSEEK_ENDPOINT,
DEFAULT_GEMINI_ENDPOINT, DEFAULT_GEMINI_ENDPOINT,
DEFAULT_REQUEST_INTERVAL, DEFAULT_REQUEST_INTERVAL,
DEFAULT_API_TIMEOUT,
DEFAULT_CONTEXT_MESSAGES, DEFAULT_CONTEXT_MESSAGES,
API_TIMEOUT,
SERVICE_ASK_QUESTION, SERVICE_ASK_QUESTION,
SERVICE_CLEAR_HISTORY, SERVICE_CLEAR_HISTORY,
SERVICE_GET_HISTORY, SERVICE_GET_HISTORY,
@@ -86,6 +87,9 @@ SERVICE_SCHEMA_GET_HISTORY = vol.Schema({
vol.Required("instance"): cv.string, vol.Required("instance"): cv.string,
vol.Optional("limit"): cv.positive_int, vol.Optional("limit"): cv.positive_int,
vol.Optional("filter_model"): cv.string, vol.Optional("filter_model"): cv.string,
vol.Optional("start_date"): cv.string,
vol.Optional("include_metadata"): cv.boolean,
vol.Optional("sort_order"): vol.In(["newest", "oldest"]),
}) })
def get_coordinator_by_instance(hass: HomeAssistant, instance: str) -> HATextAICoordinator: def get_coordinator_by_instance(hass: HomeAssistant, instance: str) -> HATextAICoordinator:
@@ -168,7 +172,10 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
coordinator = get_coordinator_by_instance(hass, call.data["instance"]) coordinator = get_coordinator_by_instance(hass, call.data["instance"])
return await coordinator.async_get_history( return await coordinator.async_get_history(
limit=call.data.get("limit"), limit=call.data.get("limit"),
filter_model=call.data.get("filter_model") filter_model=call.data.get("filter_model"),
start_date=call.data.get("start_date"),
include_metadata=call.data.get("include_metadata", False),
sort_order=call.data.get("sort_order", "newest")
) )
except Exception as err: except Exception as err:
_LOGGER.error("Error getting history: %s", str(err)) _LOGGER.error("Error getting history: %s", str(err))
@@ -262,7 +269,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
return True return True
async def async_check_api(session, endpoint: str, headers: dict, provider: str) -> bool: async def async_check_api(session, endpoint: str, headers: dict, provider: str, api_timeout: int = DEFAULT_API_TIMEOUT) -> bool:
"""Check API availability for different providers.""" """Check API availability for different providers."""
try: try:
if provider == API_PROVIDER_GEMINI: if provider == API_PROVIDER_GEMINI:
@@ -279,7 +286,7 @@ async def async_check_api(session, endpoint: str, headers: dict, provider: str)
else: # OpenAI else: # OpenAI
check_url = f"{endpoint}/models" check_url = f"{endpoint}/models"
async with timeout(API_TIMEOUT): async with timeout(api_timeout):
async with session.get(check_url, headers=headers) as response: async with session.get(check_url, headers=headers) as response:
if response.status in [200, 404]: if response.status in [200, 404]:
return True return True
@@ -305,22 +312,24 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
_LOGGER.error("API provider not specified") _LOGGER.error("API provider not specified")
raise ConfigEntryNotReady("API provider is required") raise ConfigEntryNotReady("API provider is required")
# Get configuration # Get configuration (merge data with options to apply any runtime changes)
config = {**entry.data, **entry.options}
session = aiohttp_client.async_get_clientsession(hass) session = aiohttp_client.async_get_clientsession(hass)
api_provider = entry.data.get(CONF_API_PROVIDER) api_provider = config.get(CONF_API_PROVIDER)
model = entry.data.get(CONF_MODEL, DEFAULT_MODEL) model = config.get(CONF_MODEL, DEFAULT_MODEL)
endpoint = entry.data.get( endpoint = config.get(
CONF_API_ENDPOINT, CONF_API_ENDPOINT,
DEFAULT_OPENAI_ENDPOINT if api_provider == API_PROVIDER_OPENAI DEFAULT_OPENAI_ENDPOINT if api_provider == API_PROVIDER_OPENAI
else DEFAULT_ANTHROPIC_ENDPOINT else DEFAULT_ANTHROPIC_ENDPOINT
).rstrip('/') ).rstrip('/')
api_key = entry.data[CONF_API_KEY] api_key = entry.data[CONF_API_KEY] # API key stays in data, not in options
instance_name = entry.data.get(CONF_NAME, entry.entry_id) instance_name = entry.data.get(CONF_NAME, entry.entry_id)
request_interval = entry.data.get(CONF_REQUEST_INTERVAL, DEFAULT_REQUEST_INTERVAL) request_interval = config.get(CONF_REQUEST_INTERVAL, DEFAULT_REQUEST_INTERVAL)
max_tokens = entry.data.get(CONF_MAX_TOKENS, DEFAULT_MAX_TOKENS) api_timeout = config.get(CONF_API_TIMEOUT, DEFAULT_API_TIMEOUT)
temperature = entry.data.get(CONF_TEMPERATURE, DEFAULT_TEMPERATURE) max_tokens = config.get(CONF_MAX_TOKENS, DEFAULT_MAX_TOKENS)
max_history_size = entry.data.get(CONF_MAX_HISTORY_SIZE, DEFAULT_MAX_HISTORY) temperature = config.get(CONF_TEMPERATURE, DEFAULT_TEMPERATURE)
context_messages = entry.data.get(CONF_CONTEXT_MESSAGES, DEFAULT_CONTEXT_MESSAGES) max_history_size = config.get(CONF_MAX_HISTORY_SIZE, DEFAULT_MAX_HISTORY)
context_messages = config.get(CONF_CONTEXT_MESSAGES, DEFAULT_CONTEXT_MESSAGES)
is_anthropic = api_provider == API_PROVIDER_ANTHROPIC is_anthropic = api_provider == API_PROVIDER_ANTHROPIC
headers = { headers = {
@@ -334,7 +343,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
else: else:
headers["Authorization"] = f"Bearer {api_key}" headers["Authorization"] = f"Bearer {api_key}"
if not await async_check_api(session, endpoint, headers, api_provider): if not await async_check_api(session, endpoint, headers, api_provider, api_timeout):
raise ConfigEntryNotReady("API connection failed") raise ConfigEntryNotReady("API connection failed")
_LOGGER.debug("Creating API client for %s with endpoint %s", api_provider, endpoint) _LOGGER.debug("Creating API client for %s with endpoint %s", api_provider, endpoint)
@@ -345,6 +354,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
headers=headers, headers=headers,
api_provider=api_provider, api_provider=api_provider,
model=model, model=model,
api_timeout=api_timeout,
) )
coordinator = HATextAICoordinator( coordinator = HATextAICoordinator(
@@ -358,6 +368,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
max_history_size=max_history_size, max_history_size=max_history_size,
context_messages=context_messages, context_messages=context_messages,
is_anthropic=is_anthropic, is_anthropic=is_anthropic,
api_timeout=api_timeout,
) )
_LOGGER.debug(f"Created coordinator for {instance_name}") _LOGGER.debug(f"Created coordinator for {instance_name}")
+5 -3
View File
@@ -16,7 +16,7 @@ from datetime import datetime, timedelta
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from .const import ( from .const import (
API_TIMEOUT, DEFAULT_API_TIMEOUT,
API_RETRY_COUNT, API_RETRY_COUNT,
API_PROVIDER_ANTHROPIC, API_PROVIDER_ANTHROPIC,
API_PROVIDER_DEEPSEEK, API_PROVIDER_DEEPSEEK,
@@ -41,6 +41,7 @@ class APIClient:
headers: Dict[str, str], headers: Dict[str, str],
api_provider: str, api_provider: str,
model: str, model: str,
api_timeout: int = DEFAULT_API_TIMEOUT,
) -> None: ) -> None:
"""Initialize API client.""" """Initialize API client."""
self.session = session self.session = session
@@ -48,7 +49,8 @@ class APIClient:
self.headers = headers self.headers = headers
self.api_provider = api_provider self.api_provider = api_provider
self.model = model self.model = model
self.timeout = ClientTimeout(total=API_TIMEOUT) self.api_timeout = api_timeout
self.timeout = ClientTimeout(total=api_timeout)
self._closed = False self._closed = False
async def __aenter__(self): async def __aenter__(self):
@@ -93,7 +95,7 @@ class APIClient:
for attempt in range(API_RETRY_COUNT): for attempt in range(API_RETRY_COUNT):
try: try:
async with timeout(API_TIMEOUT): async with timeout(self.api_timeout):
async with self.session.post( async with self.session.post(
url, url,
json=payload, json=payload,
@@ -25,6 +25,7 @@ from .const import (
CONF_MAX_TOKENS, CONF_MAX_TOKENS,
CONF_API_ENDPOINT, CONF_API_ENDPOINT,
CONF_REQUEST_INTERVAL, CONF_REQUEST_INTERVAL,
CONF_API_TIMEOUT,
CONF_API_PROVIDER, CONF_API_PROVIDER,
CONF_CONTEXT_MESSAGES, CONF_CONTEXT_MESSAGES,
API_PROVIDER_OPENAI, API_PROVIDER_OPENAI,
@@ -38,6 +39,7 @@ from .const import (
DEFAULT_TEMPERATURE, DEFAULT_TEMPERATURE,
DEFAULT_MAX_TOKENS, DEFAULT_MAX_TOKENS,
DEFAULT_REQUEST_INTERVAL, DEFAULT_REQUEST_INTERVAL,
DEFAULT_API_TIMEOUT,
DEFAULT_OPENAI_ENDPOINT, DEFAULT_OPENAI_ENDPOINT,
DEFAULT_ANTHROPIC_ENDPOINT, DEFAULT_ANTHROPIC_ENDPOINT,
DEFAULT_DEEPSEEK_ENDPOINT, DEFAULT_DEEPSEEK_ENDPOINT,
@@ -48,6 +50,8 @@ from .const import (
MIN_MAX_TOKENS, MIN_MAX_TOKENS,
MAX_MAX_TOKENS, MAX_MAX_TOKENS,
MIN_REQUEST_INTERVAL, MIN_REQUEST_INTERVAL,
MIN_API_TIMEOUT,
MAX_API_TIMEOUT,
DEFAULT_NAME_PREFIX, DEFAULT_NAME_PREFIX,
DEFAULT_MAX_HISTORY, DEFAULT_MAX_HISTORY,
CONF_MAX_HISTORY_SIZE, CONF_MAX_HISTORY_SIZE,
@@ -131,6 +135,10 @@ class HATextAIConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
vol.Coerce(float), vol.Coerce(float),
vol.Range(min=MIN_REQUEST_INTERVAL) vol.Range(min=MIN_REQUEST_INTERVAL)
), ),
vol.Optional(CONF_API_TIMEOUT, default=DEFAULT_API_TIMEOUT): vol.All(
vol.Coerce(int),
vol.Range(min=MIN_API_TIMEOUT, max=MAX_API_TIMEOUT)
),
vol.Optional( vol.Optional(
CONF_CONTEXT_MESSAGES, CONF_CONTEXT_MESSAGES,
default=DEFAULT_CONTEXT_MESSAGES default=DEFAULT_CONTEXT_MESSAGES
@@ -182,6 +190,10 @@ class HATextAIConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
vol.Coerce(float), vol.Coerce(float),
vol.Range(min=MIN_REQUEST_INTERVAL) vol.Range(min=MIN_REQUEST_INTERVAL)
), ),
vol.Optional(CONF_API_TIMEOUT, default=input_copy.get(CONF_API_TIMEOUT, DEFAULT_API_TIMEOUT)): vol.All(
vol.Coerce(int),
vol.Range(min=MIN_API_TIMEOUT, max=MAX_API_TIMEOUT)
),
vol.Optional( vol.Optional(
CONF_CONTEXT_MESSAGES, CONF_CONTEXT_MESSAGES,
default=input_copy.get(CONF_CONTEXT_MESSAGES, DEFAULT_CONTEXT_MESSAGES) default=input_copy.get(CONF_CONTEXT_MESSAGES, DEFAULT_CONTEXT_MESSAGES)
@@ -224,6 +236,10 @@ class HATextAIConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
vol.Coerce(float), vol.Coerce(float),
vol.Range(min=MIN_REQUEST_INTERVAL) vol.Range(min=MIN_REQUEST_INTERVAL)
), ),
vol.Optional(CONF_API_TIMEOUT, default=input_copy.get(CONF_API_TIMEOUT, DEFAULT_API_TIMEOUT)): vol.All(
vol.Coerce(int),
vol.Range(min=MIN_API_TIMEOUT, max=MAX_API_TIMEOUT)
),
vol.Optional( vol.Optional(
CONF_CONTEXT_MESSAGES, CONF_CONTEXT_MESSAGES,
default=input_copy.get(CONF_CONTEXT_MESSAGES, DEFAULT_CONTEXT_MESSAGES) default=input_copy.get(CONF_CONTEXT_MESSAGES, DEFAULT_CONTEXT_MESSAGES)
@@ -282,6 +298,10 @@ class HATextAIConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
vol.Coerce(float), vol.Coerce(float),
vol.Range(min=MIN_REQUEST_INTERVAL) vol.Range(min=MIN_REQUEST_INTERVAL)
), ),
vol.Optional(CONF_API_TIMEOUT, default=input_copy.get(CONF_API_TIMEOUT, DEFAULT_API_TIMEOUT)): vol.All(
vol.Coerce(int),
vol.Range(min=MIN_API_TIMEOUT, max=MAX_API_TIMEOUT)
),
vol.Optional( vol.Optional(
CONF_CONTEXT_MESSAGES, CONF_CONTEXT_MESSAGES,
default=input_copy.get(CONF_CONTEXT_MESSAGES, DEFAULT_CONTEXT_MESSAGES) default=input_copy.get(CONF_CONTEXT_MESSAGES, DEFAULT_CONTEXT_MESSAGES)
@@ -433,6 +453,7 @@ class HATextAIConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
CONF_TEMPERATURE: user_input.get(CONF_TEMPERATURE, DEFAULT_TEMPERATURE), CONF_TEMPERATURE: user_input.get(CONF_TEMPERATURE, DEFAULT_TEMPERATURE),
CONF_MAX_TOKENS: user_input.get(CONF_MAX_TOKENS, DEFAULT_MAX_TOKENS), CONF_MAX_TOKENS: user_input.get(CONF_MAX_TOKENS, DEFAULT_MAX_TOKENS),
CONF_REQUEST_INTERVAL: user_input.get(CONF_REQUEST_INTERVAL, DEFAULT_REQUEST_INTERVAL), CONF_REQUEST_INTERVAL: user_input.get(CONF_REQUEST_INTERVAL, DEFAULT_REQUEST_INTERVAL),
CONF_API_TIMEOUT: user_input.get(CONF_API_TIMEOUT, DEFAULT_API_TIMEOUT),
CONF_CONTEXT_MESSAGES: user_input.get(CONF_CONTEXT_MESSAGES, DEFAULT_CONTEXT_MESSAGES), CONF_CONTEXT_MESSAGES: user_input.get(CONF_CONTEXT_MESSAGES, DEFAULT_CONTEXT_MESSAGES),
CONF_MAX_HISTORY_SIZE: user_input.get(CONF_MAX_HISTORY_SIZE, DEFAULT_MAX_HISTORY), CONF_MAX_HISTORY_SIZE: user_input.get(CONF_MAX_HISTORY_SIZE, DEFAULT_MAX_HISTORY),
} }
@@ -504,6 +525,13 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
vol.Coerce(float), vol.Coerce(float),
vol.Range(min=MIN_REQUEST_INTERVAL) vol.Range(min=MIN_REQUEST_INTERVAL)
), ),
vol.Optional(
CONF_API_TIMEOUT,
default=current_data.get(CONF_API_TIMEOUT, DEFAULT_API_TIMEOUT)
): vol.All(
vol.Coerce(int),
vol.Range(min=MIN_API_TIMEOUT, max=MAX_API_TIMEOUT)
),
vol.Optional( vol.Optional(
CONF_CONTEXT_MESSAGES, CONF_CONTEXT_MESSAGES,
default=current_data.get( default=current_data.get(
+9 -1
View File
@@ -61,6 +61,7 @@ CONF_TEMPERATURE: Final = "temperature"
CONF_MAX_TOKENS: Final = "max_tokens" CONF_MAX_TOKENS: Final = "max_tokens"
CONF_API_ENDPOINT: Final = "api_endpoint" CONF_API_ENDPOINT: Final = "api_endpoint"
CONF_REQUEST_INTERVAL: Final = "request_interval" CONF_REQUEST_INTERVAL: Final = "request_interval"
CONF_API_TIMEOUT: Final = "api_timeout"
CONF_INSTANCE: Final = "instance" CONF_INSTANCE: Final = "instance"
CONF_MAX_HISTORY_SIZE: Final = "max_history_size" # Correct constant name CONF_MAX_HISTORY_SIZE: Final = "max_history_size" # Correct constant name
CONF_IS_ANTHROPIC: Final = "is_anthropic" CONF_IS_ANTHROPIC: Final = "is_anthropic"
@@ -79,6 +80,7 @@ DEFAULT_TEMPERATURE: Final = 0.1
DEFAULT_MAX_TOKENS: Final = 1000 DEFAULT_MAX_TOKENS: Final = 1000
DEFAULT_REQUEST_INTERVAL: Final = 1.0 DEFAULT_REQUEST_INTERVAL: Final = 1.0
DEFAULT_TIMEOUT: Final = 30 DEFAULT_TIMEOUT: Final = 30
DEFAULT_API_TIMEOUT: Final = 30
DEFAULT_MAX_HISTORY: Final = 50 DEFAULT_MAX_HISTORY: Final = 50
DEFAULT_NAME: Final = "HA Text AI" DEFAULT_NAME: Final = "HA Text AI"
DEFAULT_NAME_PREFIX = "ha_text_ai" DEFAULT_NAME_PREFIX = "ha_text_ai"
@@ -93,9 +95,11 @@ MIN_MAX_TOKENS: Final = 1
MAX_MAX_TOKENS: Final = 100000 MAX_MAX_TOKENS: Final = 100000
MIN_REQUEST_INTERVAL: Final = 0.1 MIN_REQUEST_INTERVAL: Final = 0.1
MAX_REQUEST_INTERVAL: Final = 60.0 MAX_REQUEST_INTERVAL: Final = 60.0
MIN_API_TIMEOUT: Final = 5
MAX_API_TIMEOUT: Final = 600
# API constants # API constants
API_TIMEOUT: Final = 30 API_TIMEOUT: Final = 30 # Legacy constant, use CONF_API_TIMEOUT from config
API_RETRY_COUNT: Final = 3 API_RETRY_COUNT: Final = 3
# Service names # Service names
@@ -232,6 +236,10 @@ CONFIG_SCHEMA = vol.Schema({
vol.Coerce(float), vol.Coerce(float),
vol.Range(min=MIN_REQUEST_INTERVAL, max=MAX_REQUEST_INTERVAL) vol.Range(min=MIN_REQUEST_INTERVAL, max=MAX_REQUEST_INTERVAL)
), ),
vol.Optional(CONF_API_TIMEOUT, default=DEFAULT_API_TIMEOUT): vol.All(
vol.Coerce(int),
vol.Range(min=MIN_API_TIMEOUT, max=MAX_API_TIMEOUT)
),
vol.Optional(CONF_MAX_HISTORY_SIZE, default=DEFAULT_MAX_HISTORY): vol.All( # Correct usage vol.Optional(CONF_MAX_HISTORY_SIZE, default=DEFAULT_MAX_HISTORY): vol.All( # Correct usage
vol.Coerce(int), vol.Coerce(int),
vol.Range(min=1, max=100), vol.Range(min=1, max=100),
+58 -4
View File
@@ -37,6 +37,7 @@ from .const import (
DEFAULT_MAX_TOKENS, DEFAULT_MAX_TOKENS,
DEFAULT_TEMPERATURE, DEFAULT_TEMPERATURE,
DEFAULT_MAX_HISTORY, DEFAULT_MAX_HISTORY,
DEFAULT_API_TIMEOUT,
DEFAULT_CONTEXT_MESSAGES, DEFAULT_CONTEXT_MESSAGES,
ABSOLUTE_MAX_HISTORY_SIZE, ABSOLUTE_MAX_HISTORY_SIZE,
MAX_ATTRIBUTE_SIZE, MAX_ATTRIBUTE_SIZE,
@@ -76,6 +77,7 @@ class HATextAICoordinator(DataUpdateCoordinator):
max_history_size: int = DEFAULT_MAX_HISTORY, max_history_size: int = DEFAULT_MAX_HISTORY,
context_messages: int = DEFAULT_CONTEXT_MESSAGES, context_messages: int = DEFAULT_CONTEXT_MESSAGES,
is_anthropic: bool = False, is_anthropic: bool = False,
api_timeout: int = DEFAULT_API_TIMEOUT,
) -> None: ) -> None:
"""Initialize coordinator.""" """Initialize coordinator."""
self.instance_name = instance_name self.instance_name = instance_name
@@ -115,6 +117,7 @@ class HATextAICoordinator(DataUpdateCoordinator):
ABSOLUTE_MAX_HISTORY_SIZE ABSOLUTE_MAX_HISTORY_SIZE
) )
self.is_anthropic = is_anthropic self.is_anthropic = is_anthropic
self.api_timeout = api_timeout
# Initialize essential attributes # Initialize essential attributes
self._is_processing = False self._is_processing = False
@@ -916,7 +919,7 @@ class HATextAICoordinator(DataUpdateCoordinator):
async def async_process_message(self, question: str, **kwargs) -> dict: async def async_process_message(self, question: str, **kwargs) -> dict:
"""Process message using the AI client.""" """Process message using the AI client."""
try: try:
async with asyncio.timeout(60): # 60 second timeout async with asyncio.timeout(self.api_timeout):
if self.is_anthropic: if self.is_anthropic:
response = await self._process_anthropic_message(question, **kwargs) response = await self._process_anthropic_message(question, **kwargs)
else: else:
@@ -1085,9 +1088,60 @@ class HATextAICoordinator(DataUpdateCoordinator):
_LOGGER.error(f"Error clearing history: {e}") _LOGGER.error(f"Error clearing history: {e}")
_LOGGER.debug(traceback.format_exc()) _LOGGER.debug(traceback.format_exc())
async def async_get_history(self) -> List[Dict[str, str]]: async def async_get_history(
"""Get conversation history.""" self,
return self._conversation_history limit: Optional[int] = None,
filter_model: Optional[str] = None,
start_date: Optional[str] = None,
include_metadata: bool = False,
sort_order: str = "newest"
) -> List[Dict[str, Any]]:
"""Get conversation history with optional filtering and sorting."""
try:
history = self._conversation_history.copy()
# Filter by model if specified
if filter_model:
history = [entry for entry in history if entry.get("model") == filter_model]
# Filter by start date if specified
if start_date:
try:
from datetime import datetime
start_dt = datetime.fromisoformat(start_date.replace('Z', '+00:00'))
history = [
entry for entry in history
if datetime.fromisoformat(entry["timestamp"].replace('Z', '+00:00')) >= start_dt
]
except (ValueError, KeyError) as e:
_LOGGER.warning(f"Invalid start_date format: {start_date}. Error: {e}")
# Sort history
if sort_order == "oldest":
history.sort(key=lambda x: x.get("timestamp", ""))
else: # newest (default)
history.sort(key=lambda x: x.get("timestamp", ""), reverse=True)
# Apply limit
if limit and limit > 0:
history = history[:limit]
# Add metadata if requested
if include_metadata:
for entry in history:
entry["metadata"] = {
"entry_size": len(str(entry)),
"question_length": len(entry.get("question", "")),
"response_length": len(entry.get("response", "")),
"model_used": entry.get("model", self.model),
"instance": self.instance_name
}
return history
except Exception as e:
_LOGGER.error(f"Error getting history: {e}")
return []
async def async_set_system_prompt(self, prompt: str) -> None: async def async_set_system_prompt(self, prompt: str) -> None:
"""Set system prompt.""" """Set system prompt."""
+1 -1
View File
@@ -24,6 +24,6 @@
"single_config_entry": false, "single_config_entry": false,
"ssdp": [], "ssdp": [],
"usb": [], "usb": [],
"version": "2.1.8", "version": "2.2.0",
"zeroconf": [] "zeroconf": []
} }
@@ -21,6 +21,7 @@
"temperature": "Kreativität der Antwort (0-2, niedriger = fokussierter)", "temperature": "Kreativität der Antwort (0-2, niedriger = fokussierter)",
"max_tokens": "Maximale Länge der Antwort (1-100000 Token)", "max_tokens": "Maximale Länge der Antwort (1-100000 Token)",
"request_interval": "Minimale Zeit zwischen Anfragen (0,1-60 Sekunden)", "request_interval": "Minimale Zeit zwischen Anfragen (0,1-60 Sekunden)",
"api_timeout": "API-Anfrage Timeout in Sekunden (5-600)",
"context_messages": "Anzahl der zu behaltenden Kontextnachrichten (1-20)", "context_messages": "Anzahl der zu behaltenden Kontextnachrichten (1-20)",
"max_history_size": "Maximale Größe des Gesprächsverlaufs (1-100)" "max_history_size": "Maximale Größe des Gesprächsverlaufs (1-100)"
} }
@@ -37,6 +38,7 @@
"api_endpoint": "Benutzerdefinierte API-Endpunkt-URL (optional)", "api_endpoint": "Benutzerdefinierte API-Endpunkt-URL (optional)",
"api_provider": "API-Anbieter", "api_provider": "API-Anbieter",
"request_interval": "Minimale Zeit zwischen Anfragen (0,1-60 Sekunden)", "request_interval": "Minimale Zeit zwischen Anfragen (0,1-60 Sekunden)",
"api_timeout": "API-Anfrage Timeout in Sekunden (5-600)",
"context_messages": "Anzahl der zu behaltenden Kontextnachrichten (1-20)", "context_messages": "Anzahl der zu behaltenden Kontextnachrichten (1-20)",
"max_history_size": "Maximale Größe des Gesprächsverlaufs (1-100)" "max_history_size": "Maximale Größe des Gesprächsverlaufs (1-100)"
} }
@@ -79,6 +81,7 @@
"temperature": "Kreativität der Antwort (0-2)", "temperature": "Kreativität der Antwort (0-2)",
"max_tokens": "Maximale Länge der Antwort (1-100000)", "max_tokens": "Maximale Länge der Antwort (1-100000)",
"request_interval": "Minimale Anfrageintervall (0,1-60 Sekunden)", "request_interval": "Minimale Anfrageintervall (0,1-60 Sekunden)",
"api_timeout": "API-Anfrage Timeout in Sekunden (5-600)",
"context_messages": "Anzahl der vorherigen Nachrichten, die im Kontext enthalten sein sollen (1-20)", "context_messages": "Anzahl der vorherigen Nachrichten, die im Kontext enthalten sein sollen (1-20)",
"max_history_size": "Maximale Größe des Gesprächsverlaufs (1-100)" "max_history_size": "Maximale Größe des Gesprächsverlaufs (1-100)"
} }
@@ -21,6 +21,7 @@
"temperature": "Response creativity (0-2, lower = more focused)", "temperature": "Response creativity (0-2, lower = more focused)",
"max_tokens": "Maximum response length (1-100000 tokens)", "max_tokens": "Maximum response length (1-100000 tokens)",
"request_interval": "Minimum time between requests (0.1-60 seconds)", "request_interval": "Minimum time between requests (0.1-60 seconds)",
"api_timeout": "API request timeout in seconds (5-600)",
"context_messages": "Number of context messages to retain (1-20)", "context_messages": "Number of context messages to retain (1-20)",
"max_history_size": "Maximum conversation history size (1-100)" "max_history_size": "Maximum conversation history size (1-100)"
} }
@@ -37,6 +38,7 @@
"api_endpoint": "Custom API endpoint URL (optional)", "api_endpoint": "Custom API endpoint URL (optional)",
"api_provider": "API Provider", "api_provider": "API Provider",
"request_interval": "Minimum time between requests (0.1-60 seconds)", "request_interval": "Minimum time between requests (0.1-60 seconds)",
"api_timeout": "API request timeout in seconds (5-600)",
"context_messages": "Number of context messages to retain (1-20)", "context_messages": "Number of context messages to retain (1-20)",
"max_history_size": "Maximum conversation history size (1-100)" "max_history_size": "Maximum conversation history size (1-100)"
} }
@@ -79,6 +81,7 @@
"temperature": "Response creativity (0-2)", "temperature": "Response creativity (0-2)",
"max_tokens": "Maximum response length (1-100000)", "max_tokens": "Maximum response length (1-100000)",
"request_interval": "Minimum request interval (0.1-60 seconds)", "request_interval": "Minimum request interval (0.1-60 seconds)",
"api_timeout": "API request timeout in seconds (5-600)",
"context_messages": "Number of previous messages to include in context (1-20)", "context_messages": "Number of previous messages to include in context (1-20)",
"max_history_size": "Maximum conversation history size (1-100)" "max_history_size": "Maximum conversation history size (1-100)"
} }
@@ -21,6 +21,7 @@
"temperature": "Creatividad de la respuesta (0-2, menor = más enfocado)", "temperature": "Creatividad de la respuesta (0-2, menor = más enfocado)",
"max_tokens": "Longitud máxima de la respuesta (1-100000 tokens)", "max_tokens": "Longitud máxima de la respuesta (1-100000 tokens)",
"request_interval": "Tiempo mínimo entre solicitudes (0.1-60 segundos)", "request_interval": "Tiempo mínimo entre solicitudes (0.1-60 segundos)",
"api_timeout": "Tiempo de espera de solicitud API en segundos (5-600)",
"context_messages": "Número de mensajes de contexto a retener (1-20)", "context_messages": "Número de mensajes de contexto a retener (1-20)",
"max_history_size": "Tamaño máximo del historial de conversación (1-100)" "max_history_size": "Tamaño máximo del historial de conversación (1-100)"
} }
@@ -37,6 +38,7 @@
"api_endpoint": "URL del endpoint de API personalizado (opcional)", "api_endpoint": "URL del endpoint de API personalizado (opcional)",
"api_provider": "Proveedor de API", "api_provider": "Proveedor de API",
"request_interval": "Tiempo mínimo entre solicitudes (0.1-60 segundos)", "request_interval": "Tiempo mínimo entre solicitudes (0.1-60 segundos)",
"api_timeout": "Tiempo de espera de solicitud API en segundos (5-600)",
"context_messages": "Número de mensajes de contexto a retener (1-20)", "context_messages": "Número de mensajes de contexto a retener (1-20)",
"max_history_size": "Tamaño máximo del historial de conversación (1-100)" "max_history_size": "Tamaño máximo del historial de conversación (1-100)"
} }
@@ -79,6 +81,7 @@
"temperature": "Creatividad de la respuesta (0-2)", "temperature": "Creatividad de la respuesta (0-2)",
"max_tokens": "Longitud máxima de la respuesta (1-100000)", "max_tokens": "Longitud máxima de la respuesta (1-100000)",
"request_interval": "Intervalo mínimo de solicitud (0.1-60 segundos)", "request_interval": "Intervalo mínimo de solicitud (0.1-60 segundos)",
"api_timeout": "Tiempo de espera de solicitud API en segundos (5-600)",
"context_messages": "Número de mensajes anteriores a incluir en el contexto (1-20)", "context_messages": "Número de mensajes anteriores a incluir en el contexto (1-20)",
"max_history_size": "Tamaño máximo del historial de conversación (1-100)" "max_history_size": "Tamaño máximo del historial de conversación (1-100)"
} }
@@ -12,6 +12,7 @@
"temperature": "प्रतिक्रिया की रचनात्मकता (0-2, कम = अधिक केंद्रित)", "temperature": "प्रतिक्रिया की रचनात्मकता (0-2, कम = अधिक केंद्रित)",
"max_tokens": "प्रतिक्रिया की अधिकतम लंबाई (1-100000 टोकन)", "max_tokens": "प्रतिक्रिया की अधिकतम लंबाई (1-100000 टोकन)",
"request_interval": "अनुरोधों के बीच न्यूनतम समय (0.1-60 सेकंड)", "request_interval": "अनुरोधों के बीच न्यूनतम समय (0.1-60 सेकंड)",
"api_timeout": "एपीआई अनुरोध टाइमआउट सेकंड में (5-600)",
"context_messages": "रखने के लिए संदर्भ संदेशों की संख्या (1-20)", "context_messages": "रखने के लिए संदर्भ संदेशों की संख्या (1-20)",
"max_history_size": "अधिकतम बातचीत इतिहास आकार (1-100)" "max_history_size": "अधिकतम बातचीत इतिहास आकार (1-100)"
} }
@@ -28,6 +29,7 @@
"api_endpoint": "कस्टम एपीआई एंडपॉइंट यूआरएल (वैकल्पिक)", "api_endpoint": "कस्टम एपीआई एंडपॉइंट यूआरएल (वैकल्पिक)",
"api_provider": "एपीआई प्रदाता", "api_provider": "एपीआई प्रदाता",
"request_interval": "अनुरोधों के बीच न्यूनतम समय (0.1-60 सेकंड)", "request_interval": "अनुरोधों के बीच न्यूनतम समय (0.1-60 सेकंड)",
"api_timeout": "एपीआई अनुरोध टाइमआउट सेकंड में (5-600)",
"context_messages": "रखने के लिए संदर्भ संदेशों की संख्या (1-20)", "context_messages": "रखने के लिए संदर्भ संदेशों की संख्या (1-20)",
"max_history_size": "अधिकतम बातचीत इतिहास आकार (1-100)" "max_history_size": "अधिकतम बातचीत इतिहास आकार (1-100)"
} }
@@ -70,6 +72,7 @@
"temperature": "प्रतिक्रिया की रचनात्मकता (0-2)", "temperature": "प्रतिक्रिया की रचनात्मकता (0-2)",
"max_tokens": "प्रतिक्रिया की अधिकतम लंबाई (1-100000)", "max_tokens": "प्रतिक्रिया की अधिकतम लंबाई (1-100000)",
"request_interval": "न्यूनतम अनुरोध अंतराल (0.1-60 सेकंड)", "request_interval": "न्यूनतम अनुरोध अंतराल (0.1-60 सेकंड)",
"api_timeout": "एपीआई अनुरोध टाइमआउट सेकंड में (5-600)",
"context_messages": "संदर्भ में शामिल करने के लिए पिछले संदेशों की संख्या (1-20)", "context_messages": "संदर्भ में शामिल करने के लिए पिछले संदेशों की संख्या (1-20)",
"max_history_size": "अधिकतम बातचीत इतिहास आकार (1-100)" "max_history_size": "अधिकतम बातचीत इतिहास आकार (1-100)"
} }
@@ -21,6 +21,7 @@
"temperature": "Creatività della risposta (0-2, più basso = più focalizzato)", "temperature": "Creatività della risposta (0-2, più basso = più focalizzato)",
"max_tokens": "Lunghezza massima della risposta (1-100000 token)", "max_tokens": "Lunghezza massima della risposta (1-100000 token)",
"request_interval": "Tempo minimo tra le richieste (0.1-60 secondi)", "request_interval": "Tempo minimo tra le richieste (0.1-60 secondi)",
"api_timeout": "Timeout della richiesta API in secondi (5-600)",
"context_messages": "Numero di messaggi di contesto da mantenere (1-20)", "context_messages": "Numero di messaggi di contesto da mantenere (1-20)",
"max_history_size": "Dimensione massima della cronologia delle conversazioni (1-100)" "max_history_size": "Dimensione massima della cronologia delle conversazioni (1-100)"
} }
@@ -37,6 +38,7 @@
"api_endpoint": "URL dell'endpoint API personalizzato (opzionale)", "api_endpoint": "URL dell'endpoint API personalizzato (opzionale)",
"api_provider": "Fornitore API", "api_provider": "Fornitore API",
"request_interval": "Tempo minimo tra le richieste (0.1-60 secondi)", "request_interval": "Tempo minimo tra le richieste (0.1-60 secondi)",
"api_timeout": "Timeout della richiesta API in secondi (5-600)",
"context_messages": "Numero di messaggi di contesto da mantenere (1-20)", "context_messages": "Numero di messaggi di contesto da mantenere (1-20)",
"max_history_size": "Dimensione massima della cronologia delle conversazioni (1-100)" "max_history_size": "Dimensione massima della cronologia delle conversazioni (1-100)"
} }
@@ -79,6 +81,7 @@
"temperature": "Creatività della risposta (0-2)", "temperature": "Creatività della risposta (0-2)",
"max_tokens": "Lunghezza massima della risposta (1-100000)", "max_tokens": "Lunghezza massima della risposta (1-100000)",
"request_interval": "Intervallo minimo di richiesta (0.1-60 secondi)", "request_interval": "Intervallo minimo di richiesta (0.1-60 secondi)",
"api_timeout": "Timeout della richiesta API in secondi (5-600)",
"context_messages": "Numero di messaggi precedenti da includere nel contesto (1-20)", "context_messages": "Numero di messaggi precedenti da includere nel contesto (1-20)",
"max_history_size": "Dimensione massima della cronologia delle conversazioni (1-100)" "max_history_size": "Dimensione massima della cronologia delle conversazioni (1-100)"
} }
@@ -21,6 +21,7 @@
"temperature": "Креативность ответа (0-2, меньше = более сфокусированно)", "temperature": "Креативность ответа (0-2, меньше = более сфокусированно)",
"max_tokens": "Максимальная длина ответа (1-100000 токенов)", "max_tokens": "Максимальная длина ответа (1-100000 токенов)",
"request_interval": "Минимальный интервал между запросами (0.1-60 секунд)", "request_interval": "Минимальный интервал между запросами (0.1-60 секунд)",
"api_timeout": "Таймаут API-запроса в секундах (5-600)",
"context_messages": "Количество сохраняемых контекстных сообщений (1-20)", "context_messages": "Количество сохраняемых контекстных сообщений (1-20)",
"max_history_size": "Максимальный размер истории разговора (1-100)" "max_history_size": "Максимальный размер истории разговора (1-100)"
} }
@@ -37,6 +38,7 @@
"api_endpoint": "Пользовательский URL-адрес конечной точки API (необязательно)", "api_endpoint": "Пользовательский URL-адрес конечной точки API (необязательно)",
"api_provider": "Провайдер API", "api_provider": "Провайдер API",
"request_interval": "Минимальный интервал между запросами (0.1-60 секунд)", "request_interval": "Минимальный интервал между запросами (0.1-60 секунд)",
"api_timeout": "Таймаут API-запроса в секундах (5-600)",
"context_messages": "Количество сохраняемых контекстных сообщений (1-20)", "context_messages": "Количество сохраняемых контекстных сообщений (1-20)",
"max_history_size": "Максимальный размер истории разговора (1-100)" "max_history_size": "Максимальный размер истории разговора (1-100)"
} }
@@ -79,6 +81,7 @@
"temperature": "Креативность ответа (0-2)", "temperature": "Креативность ответа (0-2)",
"max_tokens": "Максимальная длина ответа (1-100000)", "max_tokens": "Максимальная длина ответа (1-100000)",
"request_interval": "Минимальный интервал между запросами (0.1-60 секунд)", "request_interval": "Минимальный интервал между запросами (0.1-60 секунд)",
"api_timeout": "Таймаут API-запроса в секундах (5-600)",
"context_messages": "Количество предыдущих сообщений для включения в контекст (1-20)", "context_messages": "Количество предыдущих сообщений для включения в контекст (1-20)",
"max_history_size": "Максимальный размер истории разговора (1-100)" "max_history_size": "Максимальный размер истории разговора (1-100)"
} }
@@ -12,6 +12,7 @@
"temperature": "Креативност одговора (0-2, нижа = фокусираније)", "temperature": "Креативност одговора (0-2, нижа = фокусираније)",
"max_tokens": "Максимална дужина одговора (1-100000 токена)", "max_tokens": "Максимална дужина одговора (1-100000 токена)",
"request_interval": "Минимално време између захтева (0.1-60 секунди)", "request_interval": "Минимално време између захтева (0.1-60 секунди)",
"api_timeout": "Временско ограничење API захтева у секундама (5-600)",
"context_messages": "Број контекстуалних порука које треба задржати (1-20)", "context_messages": "Број контекстуалних порука које треба задржати (1-20)",
"max_history_size": "Максимална величина историје разговора (1-100)" "max_history_size": "Максимална величина историје разговора (1-100)"
} }
@@ -28,6 +29,7 @@
"api_endpoint": "Прилагођени URL API крајње тачке (опционо)", "api_endpoint": "Прилагођени URL API крајње тачке (опционо)",
"api_provider": "API провајдер", "api_provider": "API провајдер",
"request_interval": "Минимално време између захтева (0.1-60 секунди)", "request_interval": "Минимално време између захтева (0.1-60 секунди)",
"api_timeout": "Временско ограничење API захтева у секундама (5-600)",
"context_messages": "Број контекстуалних порука које треба задржати (1-20)", "context_messages": "Број контекстуалних порука које треба задржати (1-20)",
"max_history_size": "Максимална величина историје разговора (1-100)" "max_history_size": "Максимална величина историје разговора (1-100)"
} }
@@ -70,6 +72,7 @@
"temperature": "Креативност одговора (0-2)", "temperature": "Креативност одговора (0-2)",
"max_tokens": "Максимална дужина одговора (1-100000)", "max_tokens": "Максимална дужина одговора (1-100000)",
"request_interval": "Минимално време између захтева (0.1-60 секунди)", "request_interval": "Минимално време између захтева (0.1-60 секунди)",
"api_timeout": "Временско ограничење API захтева у секундама (5-600)",
"context_messages": "Број претходних порука које треба укључити у контекст (1-20)", "context_messages": "Број претходних порука које треба укључити у контекст (1-20)",
"max_history_size": "Максимална величина историје разговора (1-100)" "max_history_size": "Максимална величина историје разговора (1-100)"
} }
@@ -12,6 +12,7 @@
"temperature": "响应创造力(0-2,越低越专注)", "temperature": "响应创造力(0-2,越低越专注)",
"max_tokens": "最大响应长度(1-100000个标记)", "max_tokens": "最大响应长度(1-100000个标记)",
"request_interval": "请求之间的最小时间(0.1-60秒)", "request_interval": "请求之间的最小时间(0.1-60秒)",
"api_timeout": "API请求超时时间(5-600秒)",
"context_messages": "保留的上下文消息数量(1-20", "context_messages": "保留的上下文消息数量(1-20",
"max_history_size": "最大对话历史大小(1-100" "max_history_size": "最大对话历史大小(1-100"
} }
@@ -28,6 +29,7 @@
"api_endpoint": "自定义API端点URL(可选)", "api_endpoint": "自定义API端点URL(可选)",
"api_provider": "API提供者", "api_provider": "API提供者",
"request_interval": "请求之间的最小时间(0.1-60秒)", "request_interval": "请求之间的最小时间(0.1-60秒)",
"api_timeout": "API请求超时时间(5-600秒)",
"context_messages": "保留的上下文消息数量(1-20", "context_messages": "保留的上下文消息数量(1-20",
"max_history_size": "最大对话历史大小(1-100" "max_history_size": "最大对话历史大小(1-100"
} }
@@ -70,6 +72,7 @@
"temperature": "响应创造力(0-2", "temperature": "响应创造力(0-2",
"max_tokens": "最大响应长度(1-100000", "max_tokens": "最大响应长度(1-100000",
"request_interval": "最小请求间隔(0.1-60秒)", "request_interval": "最小请求间隔(0.1-60秒)",
"api_timeout": "API请求超时时间(5-600秒)",
"context_messages": "要包含在上下文中的先前消息数量(1-20)", "context_messages": "要包含在上下文中的先前消息数量(1-20)",
"max_history_size": "最大对话历史大小(1-100" "max_history_size": "最大对话历史大小(1-100"
} }
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"name": "HA Text AI", "name": "HA Text AI",
"render_readme": true, "render_readme": true,
"homeassistant": "2024.11.0" "homeassistant": "2024.12.0"
} }