Compare commits

...
20 Commits
Author SHA1 Message Date
SMKRV 440c734214 Bump release version to v2.1.4 2025-05-19 23:20:27 +03:00
SMKRV 73788373cd Release v2.1.3 2025-05-19 23:12:55 +03:00
SMKRV 4bfc96019b fix: DEFAULT_GEMINI_ENDPOINT 2025-05-19 15:53:43 +03:00
SMKRV 2138fc7654 fix: DEFAULT_GEMINI_ENDPOINT 2025-05-19 15:36:58 +03:00
SMKRV 95bd2ebb41 Add support for Google Gemini (thanks to @Azzedde) #5 2025-05-19 15:10:19 +03:00
smkrvandGitHub cad0fd7031 Merge pull request #5 from Azzedde/main
Add Gemini API provider support to HA Text AI integration by @Azzedde
2025-05-19 14:44:06 +03:00
Azzedde c003b258f6 Add Gemini API provider support to HA Text AI integration 2025-05-18 13:23:55 +02:00
SMKRV 65a10c77f4 ~ 2025-01-30 01:15:13 +03:00
SMKRV e1463828c9 ~ 2025-01-30 01:14:24 +03:00
SMKRV 5ebb9c9c66 fix: max_tokens value 2025-01-29 18:04:13 +03:00
SMKRV f17c631a79 fix: max_tokens value 2025-01-29 18:02:42 +03:00
SMKRV 0e06794384 refactor(docs): shields & community links updated 2025-01-29 03:05:47 +03:00
SMKRV d8a924909b refactor(docs): shields & community links updated 2025-01-29 03:05:11 +03:00
SMKRV 29f1659a02 refactor(docs): shields & community links updated 2025-01-29 03:04:39 +03:00
SMKRV 5b7905de80 refactor(docs): shields & community links updated 2025-01-29 03:03:48 +03:00
SMKRV cf9ac6dcea refactor(docs): shields & community links updated 2025-01-29 01:08:45 +03:00
SMKRV 568eb3e16c refactor(docs): shields updated 2025-01-29 00:58:27 +03:00
SMKRV 53fb150389 refactor(docs): shields updated 2025-01-29 00:58:09 +03:00
SMKRV acbb53d2af refactor(docs): shields updated 2025-01-29 00:57:27 +03:00
SMKRV e19db29441 refactor(docs): DeepSeek Integration 2025-01-28 16:25:59 +03:00
17 changed files with 135 additions and 79 deletions
-41
View File
@@ -1,41 +0,0 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Home Assistant
.storage
.cloud
.google.token
# IDE
.idea/
.vscode/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
*.psd
*.zip
*.txt
*.pdf
+15 -11
View File
@@ -2,8 +2,8 @@
<div align="center">
![GitHub release](https://img.shields.io/github/release/smkrv/ha-text-ai.svg?style=flat-square) ![GitHub last commit](https://img.shields.io/github/last-commit/smkrv/ha-text-ai.svg?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)
![Deutsch](https://img.shields.io/badge/de-Deutsch-blue?style=flat-square) ![English](https://img.shields.io/badge/en-English-blue?style=flat-square) ![Español](https://img.shields.io/badge/es-Español-blue?style=flat-square) ![हिन्दी](https://img.shields.io/badge/hi-हिन्दी-blue?style=flat-square) ![Italiano](https://img.shields.io/badge/it-Italiano-blue?style=flat-square) ![Русский](https://img.shields.io/badge/ru-Русский-blue?style=flat-square) ![Српски](https://img.shields.io/badge/sr-Српски-blue?style=flat-square) ![中文](https://img.shields.io/badge/zh-中文-blue?style=flat-square)
![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)
![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;"/>
@@ -12,22 +12,23 @@
</div>
<p align="center">
Transform your smart home experience with powerful AI assistance powered by multiple AI providers including OpenAI GPT and Anthropic Claude models. Get intelligent responses, automate complex scenarios, and enhance your home automation with advanced natural language processing.
Transform your smart home experience with powerful AI assistance powered by multiple AI providers including OpenAI GPT, DeepSeek and Anthropic Claude models. Get intelligent responses, automate complex scenarios, and enhance your home automation with advanced natural language processing.
</p>
---
> [!IMPORTANT]
> 🤝 Community Driven
> 🤝 Community Driven: for more details on the integration,
> check out the discussion on the **[Home Assistant Community forum](https://community.home-assistant.io/t/ha-text-ai-transforming-home-automation-through-multi-llm-integration/799741)**
>
> <a href="https://community.home-assistant.io/t/ha-text-ai-transforming-home-automation-with-multi-provider-language-models/799741"><img src="https://img.shields.io/badge/Community-blue?style=for-the-badge&logo=homeassistant&logoColor=white&color=03a9f4"/></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="210" height="auto"></a>
>
> [Screenshots](assets/images/screenshots/screenshot.jpg)
## 🌟 Features
- 🧠 **Multi-Provider AI Integration**: Support for OpenAI GPT and Anthropic Claude models
- 🧠 **Multi-Provider AI Integration**: Support for OpenAI GPT, DeepSeek and Anthropic Claude models
- 💬 **Advanced Language Processing**: Context-aware, multi-turn conversations
- 📝 **Enhanced Memory Management**: Secure file-based history storage
-**Performance Optimization**: Efficient token usage and smart rate limiting
@@ -42,6 +43,7 @@ Transform your smart home experience with powerful AI assistance powered by mult
### 🧠 **Multi-Provider AI Integration**
- Support for OpenAI GPT models
- Anthropic Claude integration
- DeepSeek integration
- Custom API endpoints
- Flexible model selection
@@ -104,12 +106,13 @@ Transform your smart home experience with powerful AI assistance powered by mult
## 📋 Prerequisites
- Home Assistant 2024.11 or later
- Home Assistant 2024.2.2 or later
- Active API key from:
- OpenAI ([Get key](https://platform.openai.com/account/api-keys))
- Anthropic ([Get key](https://console.anthropic.com/))
- DeepSeek 🆕 ([Get key](https://platform.deepseek.com/api_keys))
- DeepSeek ([Get key](https://platform.deepseek.com/api_keys))
- OpenRouter ([Get key](https://openrouter.ai/keys))
- Google Gemini 🆕 ([Get key](https://ai.google.dev/gemini-api/docs/api-key)) thanks to ([@Azzedde](https://github.com/Azzedde))
- Any OpenAI-compatible API provider
- Python 3.9 or newer
- Stable internet connection
@@ -117,7 +120,7 @@ Transform your smart home experience with powerful AI assistance powered by mult
## Configuration Options
### 🔧 **Core Configuration Settings**
- 🌐 **API Provider**: OpenAI/Anthropic
- 🌐 **API Provider**: OpenAI/Anthropic/DeepSeek
- 🔑 **API Key**: Provider-specific authentication
- 🤖 **Model Selection**: Flexible, provider-specific models
- 🌡️ **Temperature**: Creativity control (0.0-2.0)
@@ -157,6 +160,9 @@ To be compatible, a provider should support:
## ⚡ Installation
### HACS Installation (Recommended)
>[!TIP]
>HA Text AI is available in the default HACS repository. You can install it directly through HACS or click the button below to open it there.
<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
2. Click on "Integrations"
@@ -167,8 +173,6 @@ To be compatible, a provider should support:
7. Click "Download"
8. Restart Home Assistant
Note: Also Integration has been submitted to HACS store and is currently pending review in [pull request #2896](https://github.com/hacs/default/pull/2896).
### Manual Installation
1. Download the latest release
2. Extract and copy `custom_components/ha_text_ai` to your `custom_components` directory
+3
View File
@@ -40,13 +40,16 @@ from .const import (
API_PROVIDER_OPENAI,
API_PROVIDER_ANTHROPIC,
API_PROVIDER_DEEPSEEK,
API_PROVIDER_GEMINI,
DEFAULT_MODEL,
DEFAULT_DEEPSEEK_MODEL,
DEFAULT_GEMINI_MODEL,
DEFAULT_TEMPERATURE,
DEFAULT_MAX_TOKENS,
DEFAULT_OPENAI_ENDPOINT,
DEFAULT_ANTHROPIC_ENDPOINT,
DEFAULT_DEEPSEEK_ENDPOINT,
DEFAULT_GEMINI_ENDPOINT,
DEFAULT_REQUEST_INTERVAL,
DEFAULT_CONTEXT_MESSAGES,
API_TIMEOUT,
@@ -20,6 +20,7 @@ from .const import (
API_PROVIDER_ANTHROPIC,
API_PROVIDER_DEEPSEEK,
API_PROVIDER_OPENAI,
API_PROVIDER_GEMINI,
MIN_TEMPERATURE,
MAX_TEMPERATURE,
MIN_MAX_TOKENS,
@@ -115,6 +116,10 @@ class APIClient:
return await self._create_deepseek_completion(
model, messages, temperature, max_tokens
)
elif self.api_provider == API_PROVIDER_GEMINI:
return await self._create_gemini_completion(
model, messages, temperature, max_tokens
)
else:
return await self._create_openai_completion(
model, messages, temperature, max_tokens
@@ -238,6 +243,57 @@ class APIClient:
_LOGGER.error(f"Connection check failed: {str(e)}")
return False
async def _create_gemini_completion(
self,
model: str,
messages: List[Dict[str, str]],
temperature: float,
max_tokens: int,
) -> Dict[str, Any]:
"""Create completion using Gemini API."""
# Extract API key from headers (Bearer token)
api_key = self.headers.get("Authorization", "").replace("Bearer ", "")
url = f"{self.endpoint}/models/{model}:generateContent?key={api_key}"
# Convert messages to Gemini format
contents = []
system_instruction = ""
for msg in messages:
if msg['role'] == 'system':
system_instruction += msg['content'] + "\n"
else:
contents.append({
"role": "user" if msg['role'] == 'user' else "model",
"parts": [{"text": msg['content']}]
})
payload = {
"contents": contents,
"generationConfig": {
"temperature": temperature,
"maxOutputTokens": max_tokens
}
}
if system_instruction:
payload["systemInstruction"] = {
"parts": [{"text": system_instruction}]
}
data = await self._make_request(url, payload)
return {
"choices": [{
"message": {
"content": data["candidates"][0]["content"]["parts"][0]["text"]
}
}],
"usage": {
"prompt_tokens": data["usageMetadata"]["promptTokenCount"],
"completion_tokens": data["usageMetadata"]["candidatesTokenCount"],
"total_tokens": data["usageMetadata"]["totalTokenCount"]
}
}
async def shutdown(self) -> None:
"""Shutdown API client."""
_LOGGER.debug("Shutting down API client")
+23 -4
View File
@@ -29,15 +29,18 @@ from .const import (
API_PROVIDER_OPENAI,
API_PROVIDER_ANTHROPIC,
API_PROVIDER_DEEPSEEK,
API_PROVIDER_GEMINI,
API_PROVIDERS,
DEFAULT_MODEL,
DEFAULT_DEEPSEEK_MODEL,
DEFAULT_GEMINI_MODEL,
DEFAULT_TEMPERATURE,
DEFAULT_MAX_TOKENS,
DEFAULT_REQUEST_INTERVAL,
DEFAULT_OPENAI_ENDPOINT,
DEFAULT_ANTHROPIC_ENDPOINT,
DEFAULT_DEEPSEEK_ENDPOINT,
DEFAULT_GEMINI_ENDPOINT,
DEFAULT_CONTEXT_MESSAGES,
MIN_TEMPERATURE,
MAX_TEMPERATURE,
@@ -93,15 +96,20 @@ class HATextAIConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
self._errors = {}
if user_input is None:
# Выбор endpoint по провайдеру
# Selecting an endpoint by provider
default_endpoint = {
API_PROVIDER_OPENAI: DEFAULT_OPENAI_ENDPOINT,
API_PROVIDER_ANTHROPIC: DEFAULT_ANTHROPIC_ENDPOINT,
API_PROVIDER_DEEPSEEK: DEFAULT_DEEPSEEK_ENDPOINT,
API_PROVIDER_GEMINI: DEFAULT_GEMINI_ENDPOINT,
}.get(self._provider, DEFAULT_OPENAI_ENDPOINT)
# Выбор модели по умолчанию по провайдеру
default_model = DEFAULT_DEEPSEEK_MODEL if self._provider == API_PROVIDER_DEEPSEEK else DEFAULT_MODEL
# Selecting the default model by provider
default_model = (
DEFAULT_DEEPSEEK_MODEL if self._provider == API_PROVIDER_DEEPSEEK else
DEFAULT_GEMINI_MODEL if self._provider == API_PROVIDER_GEMINI else
DEFAULT_MODEL
)
return self.async_show_form(
step_id="provider",
@@ -256,7 +264,11 @@ class HATextAIConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
unique_id = f"{DOMAIN}_{normalized_name}_{self._provider}".lower()
default_model = DEFAULT_DEEPSEEK_MODEL if self._provider == API_PROVIDER_DEEPSEEK else DEFAULT_MODEL
default_model = (
DEFAULT_DEEPSEEK_MODEL if self._provider == API_PROVIDER_DEEPSEEK else
DEFAULT_GEMINI_MODEL if self._provider == API_PROVIDER_GEMINI else
DEFAULT_MODEL
)
entry_data = {
CONF_API_PROVIDER: self._provider,
@@ -304,6 +316,13 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
return self.async_create_entry(title="", data=user_input)
current_data = {**self.config_entry.data, **self.config_entry.options}
provider = current_data.get(CONF_API_PROVIDER)
default_model = (
DEFAULT_DEEPSEEK_MODEL if provider == API_PROVIDER_DEEPSEEK else
DEFAULT_GEMINI_MODEL if provider == API_PROVIDER_GEMINI else
DEFAULT_MODEL
)
return self.async_show_form(
step_id="init",
+7 -1
View File
@@ -12,6 +12,8 @@ from typing import Final
import voluptuous as vol
from homeassistant.const import Platform, CONF_API_KEY, CONF_NAME
from homeassistant.helpers import config_validation as cv
import logging
_LOGGER = logging.getLogger(__name__)
# Domain and platforms
DOMAIN: Final = "ha_text_ai"
@@ -22,11 +24,13 @@ CONF_API_PROVIDER: Final = "api_provider"
API_PROVIDER_OPENAI: Final = "openai"
API_PROVIDER_ANTHROPIC: Final = "anthropic"
API_PROVIDER_DEEPSEEK: Final = "deepseek"
API_PROVIDER_GEMINI: Final = "gemini"
API_PROVIDERS: Final = [
API_PROVIDER_OPENAI,
API_PROVIDER_ANTHROPIC,
API_PROVIDER_DEEPSEEK
API_PROVIDER_DEEPSEEK,
API_PROVIDER_GEMINI
]
# Read version from manifest.json
@@ -49,6 +53,7 @@ except Exception as err:
DEFAULT_OPENAI_ENDPOINT: Final = "https://api.openai.com/v1"
DEFAULT_ANTHROPIC_ENDPOINT: Final = "https://api.anthropic.com"
DEFAULT_DEEPSEEK_ENDPOINT: Final = "https://api.deepseek.com"
DEFAULT_GEMINI_ENDPOINT: Final = "https://generativelanguage.googleapis.com/v1beta"
# Configuration constants
CONF_MODEL: Final = "model"
@@ -69,6 +74,7 @@ ICONS_SUBDOMAIN = "icons"
# Default values
DEFAULT_MODEL: Final = "gpt-4o-mini"
DEFAULT_DEEPSEEK_MODEL: Final = "deepseek-chat"
DEFAULT_GEMINI_MODEL: Final = "gemini-pro"
DEFAULT_TEMPERATURE: Final = 0.1
DEFAULT_MAX_TOKENS: Final = 1000
DEFAULT_REQUEST_INTERVAL: Final = 1.0
+2 -1
View File
@@ -16,6 +16,7 @@
"requirements": [
"openai>=1.12.0",
"anthropic>=0.8.0",
"google-generativeai>=0.3.0",
"aiohttp>=3.8.0",
"async-timeout>=4.0.0",
"certifi>=2024.2.2"
@@ -23,6 +24,6 @@
"single_config_entry": false,
"ssdp": [],
"usb": [],
"version": "2.1.1",
"version": "2.1.4",
"zeroconf": []
}
+2 -2
View File
@@ -63,13 +63,13 @@ ask_question:
max_tokens:
name: Max Tokens
description: Maximum length of the response (1-4096 tokens)
description: Maximum length of the response (tokens)
required: false
default: 1000
selector:
number:
min: 1
max: 4096
max: 100000
step: 1
mode: box
@@ -88,12 +88,13 @@
"selector": {
"api_provider": {
"options": {
"openai": "OpenAI (kompatibel)",
"anthropic": "Anthropic (kompatibel)",
"deepseek": "DeepSeek"
}
"openai": "OpenAI (compatible)",
"anthropic": "Anthropic (compatible)",
"deepseek": "DeepSeek",
"gemini": "Google Gemini"
}
},
}
},
"services": {
"ask_question": {
"name": "Frage stellen (HA Text AI)",
@@ -86,11 +86,12 @@
}
},
"selector": {
"api_provider": {
"options": {
"openai": "OpenAI (compatible)",
"anthropic": "Anthropic (compatible)",
"deepseek": "DeepSeek"
"api_provider": {
"options": {
"openai": "OpenAI (compatible)",
"anthropic": "Anthropic (compatible)",
"deepseek": "DeepSeek",
"gemini": "Google Gemini"
}
}
},
@@ -90,10 +90,11 @@
"options": {
"openai": "OpenAI (compatible)",
"anthropic": "Anthropic (compatible)",
"deepseek": "DeepSeek"
}
"deepseek": "DeepSeek",
"gemini": "Google Gemini"
}
},
}
},
"services": {
"ask_question": {
"name": "Hacer Pregunta (HA Text AI)",
@@ -90,7 +90,8 @@
"options": {
"openai": "OpenAI (अनुकूलित)",
"anthropic": "Anthropic (अनुकूलित)",
"deepseek": "DeepSeek"
"deepseek": "DeepSeek",
"gemini": "Google Gemini"
}
}
},
@@ -90,7 +90,8 @@
"options": {
"openai": "OpenAI (compatibile)",
"anthropic": "Anthropic (compatibile)",
"deepseek": "DeepSeek"
"deepseek": "DeepSeek",
"gemini": "Google Gemini"
}
}
},
@@ -90,7 +90,8 @@
"options": {
"openai": "OpenAI (совместимый)",
"anthropic": "Anthropic (совместимый)",
"deepseek": "DeepSeek"
"deepseek": "DeepSeek",
"gemini": "Google Gemini"
}
}
},
@@ -90,7 +90,8 @@
"options": {
"openai": "OpenAI (компатибилан)",
"anthropic": "Anthropic (компатибилан)",
"deepseek": "DeepSeek"
"deepseek": "DeepSeek",
"gemini": "Google Gemini"
}
}
},
@@ -90,7 +90,8 @@
"options": {
"openai": "OpenAI(兼容)",
"anthropic": "Anthropic(兼容)",
"deepseek": "DeepSeek "
"deepseek": "DeepSeek",
"gemini": "Google Gemini"
}
}
},
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "HA text AI",
"name": "HA Text AI",
"render_readme": true,
"homeassistant": "2024.11.0"
}