File size: 7,777 Bytes
4ad5efa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
"""
Утиліти для роботи з Google Embeddings API.
Цей файл повинен бути розміщений у modules/ai_analysis/google_embeddings_utils.py
"""

import os
import logging
from typing import List, Dict, Any, Optional
import time

logger = logging.getLogger(__name__)

# Перевірка наявності необхідних бібліотек
try:
    from google import genai
    GOOGLE_GENAI_AVAILABLE = True
    logger.info("Google GenAI SDK успішно імпортовано")
except ImportError as e:
    logger.warning(f"Google GenAI SDK не встановлено: {e}. Використання Google Embeddings буде вимкнено.")
    GOOGLE_GENAI_AVAILABLE = False

class GoogleEmbeddingsManager:
    """
    Менеджер для роботи з Google Embeddings API.
    """
    
    def __init__(self, api_key=None, model_name="text-embedding-004", task_type="retrieval_query"):
        """
        Ініціалізація менеджера Google Embeddings.
        
        Args:
            api_key (str, optional): API ключ для Google API. Якщо не вказано, спробує використати GEMINI_API_KEY з середовища.
            model_name (str): Назва моделі ембедингів.
            task_type (str): Тип задачі для ембедингів. Може бути "retrieval_query" або "retrieval_document".
        """
        self.api_key = api_key or os.getenv("GEMINI_API_KEY")
        self.model_name = model_name
        self.task_type = task_type
        self.client = None
        self.initialized = False
        
        # Спроба ініціалізації клієнта
        self._initialize_client()
    
    def _initialize_client(self):
        """
        Ініціалізує клієнт Google GenAI API.
        
        Returns:
            bool: True, якщо ініціалізація успішна, False в іншому випадку.
        """
        if not GOOGLE_GENAI_AVAILABLE:
            logger.error("Google GenAI SDK не встановлено. Встановіть пакет: pip install google-genai")
            return False
        
        if not self.api_key:
            logger.error("API ключ для Google API не вказано. Встановіть змінну GEMINI_API_KEY.")
            return False
        
        try:
            # Ініціалізація клієнта
            genai.configure(api_key=self.api_key)
            self.client = genai.Client()
            self.initialized = True
            logger.info(f"Клієнт Google GenAI успішно ініціалізовано для моделі {self.model_name}")
            return True
        except Exception as e:
            logger.error(f"Помилка при ініціалізації клієнта Google GenAI: {e}")
            return False
    
    def get_embeddings(self, texts, batch_size=8, retry_attempts=3, retry_delay=1):
        """
        Отримує ембединги для списку текстів.
        
        Args:
            texts (list): Список текстів для ембедингу.
            batch_size (int): Розмір батча для обробки.
            retry_attempts (int): Кількість спроб у випадку помилки.
            retry_delay (int): Затримка між спробами в секундах.
            
        Returns:
            list: Список ембедингів для кожного тексту або None у випадку помилки.
        """
        if not self.initialized:
            if not self._initialize_client():
                return None
        
        if not texts:
            logger.warning("Порожній список текстів для ембедингу")
            return []
        
        # Переконуємося, що input завжди список
        if not isinstance(texts, list):
            texts = [texts]
        
        try:
            all_embeddings = []
            
            # Обробка по батчам для ефективності
            for i in range(0, len(texts), batch_size):
                batch = texts[i:i + batch_size]
                
                # Спроби з повторами у випадку помилки
                for attempt in range(retry_attempts):
                    try:
                        result = self.client.models.embed_content(
                            model=self.model_name,
                            contents=batch,
                            config={"task_type": self.task_type}
                        )
                        
                        # Вилучення ембедингів
                        batch_embeddings = [embedding.values for embedding in result.embeddings]
                        all_embeddings.extend(batch_embeddings)
                        break
                    except Exception as e:
                        if attempt == retry_attempts - 1:
                            logger.error(f"Не вдалося отримати ембединги після {retry_attempts} спроб: {e}")
                            return None
                        logger.warning(f"Спроба {attempt+1} невдала: {e}. Повторна спроба через {retry_delay} сек.")
                        time.sleep(retry_delay)
            
            logger.info(f"Успішно отримано {len(all_embeddings)} ембедингів від Google API")
            return all_embeddings
            
        except Exception as e:
            logger.error(f"Помилка при отриманні ембедингів від Google API: {e}")
            return None
    
    def get_embedding_dimension(self):
        """
        Отримує розмірність ембедингів.
        
        Returns:
            int: Розмірність ембедингів або 0 у випадку помилки.
        """
        if not self.initialized:
            if not self._initialize_client():
                return 0
        
        try:
            # Отримуємо ембединг для тестового тексту
            result = self.client.models.embed_content(
                model=self.model_name,
                contents=["Test"],
                config={"task_type": self.task_type}
            )
            
            # Отримуємо розмірність
            [embedding] = result.embeddings
            return len(embedding.values)
            
        except Exception as e:
            logger.error(f"Помилка при отриманні розмірності ембедингів: {e}")
            return 0

# Приклад використання
if __name__ == "__main__":
    # Налаштування логування
    logging.basicConfig(level=logging.INFO)
    
    # Ініціалізація менеджера
    manager = GoogleEmbeddingsManager()
    
    # Отримання розмірності ембедингів
    dimension = manager.get_embedding_dimension()
    print(f"Розмірність ембедингів: {dimension}")
    
    # Отримання ембедингів для текстів
    texts = ["Це тестовий текст", "Це ще один тестовий текст"]
    embeddings = manager.get_embeddings(texts)
    
    if embeddings:
        print(f"Отримано {len(embeddings)} ембедингів")
        print(f"Розмірність першого ембедингу: {len(embeddings[0])}")