LP_2-test / GEMINI_EMBEDDINGS.md
DocUA's picture
Clean deployment without large index files
461adca

A newer version of the Gradio SDK is available: 6.6.0

Upgrade

Підтримка 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

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

Було:

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.")

Стало:

# 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

Було:

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)")

Стало:

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

Було:

if not OPENAI_API_KEY:
    return "Помилка: пошук недоступний без налаштованого OpenAI API ключа", None

Стало:

if not embed_model:
    return "Помилка: пошук недоступний без налаштованого embedding API ключа (OpenAI або Gemini)", None

5. Покращені повідомлення при запуску

Файл: main.py

# 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 (рекомендовано)

# .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

# .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

# .env
OPENAI_API_KEY=sk-...

# Запуск
python main.py

Працює як раніше з OpenAI embeddings.

Сценарій 4: Gemini + DeepSeek

# .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

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, що не дозволяє довільні атрибути. Тому використовуються приватні атрибути:

# ❌ Не працює
self.client = genai.Client()
# ValueError: "GeminiEmbedding" object has no field "client"

# ✅ Працює
self._client = genai.Client()  # Private attribute

🧪 Тестування

Перевірка ініціалізації

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

Тестовано: ✅ Синтаксис перевірено, готово до запуску