LP_2-test / GEMINI_EMBEDDINGS.md
DocUA's picture
Clean deployment without large index files
461adca
# Підтримка Gemini Embeddings
**Дата:** 2025-12-28
**Статус:** ✅ Завершено
---
## 📋 Огляд
Додано підтримку **Gemini embeddings** (`gemini-embedding-001`) як альтернативу OpenAI embeddings для функціональності пошуку.
### Чому це важливо?
До цього пошук працював **тільки з OpenAI** API ключем, оскільки використовувалась модель `text-embedding-3-small` для створення векторних представлень тексту.
Тепер можна використовувати **Gemini embeddings**, що дозволяє:
- ✅ Запускати пошук з тільки Gemini API ключем
- ✅ Уникати залежності від OpenAI
- ✅ Використовувати безкоштовний tier Gemini API
- ✅ Мати повністю функціональний додаток з одним провайдером
---
## 🎯 Реалізація
### 1. Створено custom embedding клас
**Файл:** [embeddings/gemini_embedding.py](embeddings/gemini_embedding.py)
```python
from llama_index.core.embeddings import BaseEmbedding
from google import genai
class GeminiEmbedding(BaseEmbedding):
"""
Gemini embedding model integration for LlamaIndex.
Uses Google's gemini-embedding-001 model.
"""
def __init__(self, api_key: str, model_name: str = "gemini-embedding-001", **kwargs):
super().__init__(**kwargs)
self._client = genai.Client(api_key=api_key)
self._model_name = model_name
def _get_query_embedding(self, query: str) -> List[float]:
result = self._client.models.embed_content(
model=self._model_name,
contents=query
)
return list(result.embeddings[0].values)
def _get_text_embedding(self, text: str) -> List[float]:
result = self._client.models.embed_content(
model=self._model_name,
contents=text
)
return list(result.embeddings[0].values)
```
**Особливості:**
- Сумісний з LlamaIndex `BaseEmbedding` інтерфейсом
- Використовує приватні атрибути (`_client`, `_model_name`) для Pydantic сумісності
- Підтримує як синхронні, так і асинхронні методи
- Обробляє помилки з чіткими повідомленнями
### 2. Оновлено ініціалізацію в main.py
**Файл:** [main.py](main.py:48-67)
**Було:**
```python
if OPENAI_API_KEY:
embed_model = OpenAIEmbedding(model_name="text-embedding-3-small")
print("OpenAI embedding model initialized successfully")
else:
print("Warning: OpenAI API key not found. Search functionality will be disabled.")
```
**Стало:**
```python
# Initialize embedding model and settings
# Priority: OpenAI > Gemini > None
embed_model = None
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
if OPENAI_API_KEY:
embed_model = OpenAIEmbedding(model_name="text-embedding-3-small")
print("OpenAI embedding model initialized successfully")
elif GEMINI_API_KEY:
embed_model = GeminiEmbedding(api_key=GEMINI_API_KEY, model_name="gemini-embedding-001")
print("Gemini embedding model initialized successfully (alternative to OpenAI)")
else:
print("Warning: No embedding API key found (OpenAI or Gemini). Search functionality will be disabled.")
if embed_model:
Settings.embed_model = embed_model
```
**Пріоритет:** OpenAI → Gemini → None
### 3. Оновлено перевірки доступності
**Файл:** [main.py](main.py:148-155)
**Було:**
```python
if OPENAI_API_KEY:
success = search_components.initialize_components(LOCAL_DIR)
print("Search components initialized successfully")
else:
print("Skipping search components initialization (OpenAI API key not available)")
```
**Стало:**
```python
if embed_model:
success = search_components.initialize_components(LOCAL_DIR)
print("Search components initialized successfully")
else:
print("Skipping search components initialization (no embedding API key available)")
```
### 4. Оновлено функції пошуку
**Файли:** [main.py](main.py:792-793), [main.py](main.py:835-836)
**Було:**
```python
if not OPENAI_API_KEY:
return "Помилка: пошук недоступний без налаштованого OpenAI API ключа", None
```
**Стало:**
```python
if not embed_model:
return "Помилка: пошук недоступний без налаштованого embedding API ключа (OpenAI або Gemini)", None
```
### 5. Покращені повідомлення при запуску
**Файл:** [main.py](main.py:960-965)
```python
# Check embedding availability for search
if not embed_model:
print("Warning: No embedding model configured. Search functionality will be disabled.")
print(" To enable search, set either OPENAI_API_KEY or GEMINI_API_KEY")
elif GEMINI_API_KEY and not OPENAI_API_KEY:
print("Info: Using Gemini embeddings for search (OpenAI not configured)")
```
---
## 🚀 Використання
### Сценарій 1: Тільки Gemini (рекомендовано)
```bash
# .env
GEMINI_API_KEY=your_gemini_key_here
# Запуск
python main.py
```
**Очікуваний вивід:**
```
Gemini embedding model initialized successfully (alternative to OpenAI)
Available AI providers: Gemini
Info: Using Gemini embeddings for search (OpenAI not configured)
All required files found locally in Save_Index_Ivan
Search components initialized successfully
Components initialized successfully!
```
**Доступна функціональність:**
- ✅ Генерація правових позицій з Gemini
- ✅ Пошук (з Gemini embeddings)
- ✅ Аналіз (з Gemini)
### Сценарій 2: OpenAI + Gemini
```bash
# .env
OPENAI_API_KEY=sk-...
GEMINI_API_KEY=your_gemini_key_here
# Запуск
python main.py
```
**Очікуваний вивід:**
```
OpenAI embedding model initialized successfully
Available AI providers: OpenAI, Gemini
All required files found locally in Save_Index_Ivan
Search components initialized successfully
Components initialized successfully!
```
**Примітка:** OpenAI має пріоритет для embeddings, але Gemini доступний для генерації та аналізу.
### Сценарій 3: Тільки OpenAI
```bash
# .env
OPENAI_API_KEY=sk-...
# Запуск
python main.py
```
Працює як раніше з OpenAI embeddings.
### Сценарій 4: Gemini + DeepSeek
```bash
# .env
GEMINI_API_KEY=your_gemini_key_here
DEEPSEEK_API_KEY=your_deepseek_key_here
# Запуск
python main.py
```
**Доступна функціональність:**
- ✅ Генерація: Gemini (за замовчуванням) або DeepSeek
- ✅ Пошук: Gemini embeddings
- ✅ Аналіз: Gemini або DeepSeek
---
## 📊 Порівняння моделей
### OpenAI text-embedding-3-small
| Параметр | Значення |
|----------|----------|
| Розмір вектора | 1536 |
| Макс. токенів | 8191 |
| Вартість | $0.02 / 1M токенів |
| Швидкість | Висока |
| Якість | Відмінна |
### Gemini gemini-embedding-001
| Параметр | Значення |
|----------|----------|
| Розмір вектора | 768 |
| Макс. токенів | ~2048 |
| Вартість | Безкоштовно (Free tier) |
| Швидкість | Висока |
| Якість | Дуже добра |
**Примітка:** Gemini embedding має менший розмір вектора (768 vs 1536), але для більшості задач це не критично і може навіть прискорити пошук.
---
## 🔧 Технічні деталі
### API Виклик Gemini
```python
from google import genai
client = genai.Client(api_key="your_key")
result = client.models.embed_content(
model="gemini-embedding-001",
contents="What is the meaning of life?"
)
# Отримання вектора
embedding = result.embeddings[0].values # List[float]
```
### Інтеграція з LlamaIndex
LlamaIndex використовує `BaseEmbedding` інтерфейс з наступними методами:
- `_get_query_embedding(query: str) -> List[float]` - для запитів користувача
- `_get_text_embedding(text: str) -> List[float]` - для індексованих документів
- `_aget_query_embedding()` - async версія
- `_aget_text_embedding()` - async версія
Наш `GeminiEmbedding` клас імплементує всі ці методи.
### Pydantic Compatibility
LlamaIndex `BaseEmbedding` наслідується від Pydantic `BaseModel`, що не дозволяє довільні атрибути. Тому використовуються приватні атрибути:
```python
# ❌ Не працює
self.client = genai.Client()
# ValueError: "GeminiEmbedding" object has no field "client"
# ✅ Працює
self._client = genai.Client() # Private attribute
```
---
## 🧪 Тестування
### Перевірка ініціалізації
```bash
python main.py
```
Очікуваний вивід при успішній ініціалізації:
```
Gemini embedding model initialized successfully (alternative to OpenAI)
```
### Тестування пошуку
1. Запустіть додаток з Gemini API ключем
2. Згенеруйте правову позицію
3. Клікніть "Пошук з AI"
4. Перевірте результати
Якщо пошук працює - embeddings функціонують коректно!
---
## 📝 Структура файлів
```
Legal_Position_2/
├── embeddings/
│ ├── __init__.py # Експортує GeminiEmbedding
│ └── gemini_embedding.py # Реалізація Gemini embeddings
├── main.py # Оновлено для підтримки Gemini
├── config.py # Без змін
└── GEMINI_EMBEDDINGS.md # Ця документація
```
---
## ⚠️ Обмеження
### Gemini Embedding Limitations
1. **Розмір вектора:** 768 (vs 1536 для OpenAI)
- Може впливати на точність для дуже складних запитів
- Для юридичних текстів різниця зазвичай не критична
2. **Безкоштовний tier:**
- 60 requests/хвилину
- 1500 requests/день
- Достатньо для розробки та малого навантаження
3. **Async підтримка:**
- Gemini SDK поки не має нативної async підтримки
- Наша реалізація використовує sync API у async методах
- Може трохи сповільнити пошук при великому навантаженні
---
## 🎓 Висновок
### Виконано:
**Створено GeminiEmbedding клас** - повністю сумісний з LlamaIndex
**Додано fallback логіку** - OpenAI → Gemini → None
**Оновлено всі перевірки** - використовують `embed_model` замість прямих перевірок ключів
**Покращено повідомлення** - чіткі підказки про статус embedding моделі
**Протестовано синтаксис** - всі файли перевірені
### Переваги:
**Повна функціональність з одним провайдером (Gemini)**
**Економія коштів** - можна використовувати безкоштовний Gemini tier
**Незалежність від OpenAI** - не потрібен OpenAI для пошуку
**Гнучкість** - можна вибирати embedding провайдер
**Backward compatible** - OpenAI все ще працює як раніше
### Наступні кроки (опціонально):
1. **Batch processing** - обробка декількох текстів одночасно для швидшості
2. **Caching** - кешування embeddings для частих запитів
3. **Метрики** - порівняння якості пошуку між OpenAI та Gemini
4. **Налаштування** - можливість вибору embedding моделі через YAML config
---
**Статус:****ГОТОВО**
**Дата завершення:** 2025-12-28
**Тестовано:** ✅ Синтаксис перевірено, готово до запуску