LP_2-test / API_KEYS_OPTIONAL.md
DocUA's picture
Clean deployment without large index files
461adca
# Звіт про зміни: Опціональні API ключі
**Дата:** 2025-12-28
**Статус:** ✅ Завершено
---
## 📋 Проблема
При запуску додатку виникала помилка:
```
ValueError: OpenAI API key not found in environment variables
```
Додаток вимагав наявності всіх API ключів (OpenAI, Anthropic, AWS), навіть якщо користувач планував використовувати тільки один провайдер (наприклад, Gemini).
**Вимога користувача:**
> "якщо деякі ключі відсутні або не релевантні це не повинно бути причиною зупинки розгортання додатку"
---
## ✅ Виконані зміни
### 1. Опціональна ініціалізація OpenAI embedding моделі
**Файл:** [main.py](main.py:45-57)
**Було:**
```python
if not OPENAI_API_KEY:
raise ValueError("OpenAI API key not found in environment variables")
embed_model = OpenAIEmbedding(model_name="text-embedding-3-small")
Settings.embed_model = embed_model
```
**Стало:**
```python
if OPENAI_API_KEY:
embed_model = OpenAIEmbedding(model_name="text-embedding-3-small")
Settings.embed_model = embed_model
print("OpenAI embedding model initialized successfully")
else:
print("Warning: OpenAI API key not found. Search functionality will be disabled.")
```
### 2. Покращені повідомлення про помилки в LLMAnalyzer
**Файл:** [main.py](main.py:181-199)
**Зміни:**
- Замість загальних помилок про відсутність ключів, тепер показуються специфічні повідомлення для кожного провайдера
- Приклад: `"Gemini API key not configured. Please set GEMINI_API_KEY environment variable to use gemini provider."`
### 3. Оновлена функція validate_environment()
**Файл:** [config.py](config.py:45-76)
**Було:**
```python
def validate_environment():
required_vars = [
"AWS_ACCESS_KEY_ID",
"AWS_SECRET_ACCESS_KEY",
"OPENAI_API_KEY",
"ANTHROPIC_API_KEY"
]
missing_vars = [var for var in required_vars if not os.getenv(var)]
if missing_vars:
raise ValueError(f"Missing required environment variables: {', '.join(missing_vars)}")
```
**Стало:**
```python
def validate_environment(require_ai_provider: bool = True, require_aws: bool = False):
"""
Validate environment variables.
Args:
require_ai_provider: If True, requires at least one AI provider API key
require_aws: If True, requires AWS credentials
Returns:
dict: Status of each provider (available/missing)
"""
status = {
"openai": bool(os.getenv("OPENAI_API_KEY")),
"anthropic": bool(os.getenv("ANTHROPIC_API_KEY")),
"gemini": bool(os.getenv("GEMINI_API_KEY")),
"deepseek": bool(os.getenv("DEEPSEEK_API_KEY")),
"aws": bool(os.getenv("AWS_ACCESS_KEY_ID") and os.getenv("AWS_SECRET_ACCESS_KEY"))
}
if require_ai_provider:
if not any([status["openai"], status["anthropic"], status["gemini"], status["deepseek"]]):
raise ValueError(
"At least one AI provider API key is required. Please set one of: "
"OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, DEEPSEEK_API_KEY"
)
if require_aws and not status["aws"]:
raise ValueError("AWS credentials are required")
return status
```
### 4. Додані хелпер функції
**Файл:** [main.py](main.py:171-200)
**Нові функції:**
```python
def get_available_providers() -> Dict[str, bool]:
"""Get status of all AI providers."""
return {
"openai": bool(OPENAI_API_KEY),
"anthropic": bool(ANTHROPIC_API_KEY),
"gemini": bool(os.getenv("GEMINI_API_KEY")),
"deepseek": bool(DEEPSEEK_API_KEY)
}
def check_provider_available(provider: str) -> Tuple[bool, str]:
"""
Check if a provider is available.
Returns:
Tuple of (is_available, error_message)
"""
providers = get_available_providers()
provider_key = provider.lower()
if provider_key not in providers:
return False, f"Unknown provider: {provider}"
if not providers[provider_key]:
available = [k.upper() for k, v in providers.items() if v]
if not available:
return False, "No AI provider API keys configured. Please set at least one API key."
return False, f"{provider.upper()} API key not configured. Available providers: {', '.join(available)}"
return True, ""
```
### 5. Runtime перевірки в generate_legal_position()
**Файл:** [main.py](main.py:502-510)
**Додано на початок функції:**
```python
# Check if provider is available
is_available, error_msg = check_provider_available(provider)
if not is_available:
return {
"title": "Помилка конфігурації",
"text": error_msg,
"proceeding": "N/A",
"category": "Error"
}
```
### 6. Перевірки в функціях пошуку
**Файли:** [main.py](main.py:780-781), [main.py](main.py:823-824)
**Додано:**
```python
if not OPENAI_API_KEY:
return "Помилка: пошук недоступний без налаштованого OpenAI API ключа", None
```
### 7. Опціональна ініціалізація search components
**Файл:** [main.py](main.py:140-147)
**Додано:**
```python
# Initialize search components only if OpenAI is available
if OPENAI_API_KEY:
success = search_components.initialize_components(LOCAL_DIR)
if not success:
raise RuntimeError("Failed to initialize search components")
print("Search components initialized successfully")
else:
print("Skipping search components initialization (OpenAI API key not available)")
```
Це дозволяє додатку запускатися навіть без OpenAI, оскільки search components залежать від OpenAI embedding моделі.
### 8. Оновлена валідація при запуску
**Файл:** [main.py](main.py:875-900)
**Було:**
```python
required_vars = ["OPENAI_API_KEY"]
missing_vars = [var for var in required_vars if not os.getenv(var)]
if missing_vars:
print(f"Missing required environment variables: {', '.join(missing_vars)}")
sys.exit(1)
```
**Стало:**
```python
# Check which providers are available
available_providers = []
if OPENAI_API_KEY:
available_providers.append("OpenAI")
if ANTHROPIC_API_KEY:
available_providers.append("Anthropic")
if os.getenv("GEMINI_API_KEY"):
available_providers.append("Gemini")
if DEEPSEEK_API_KEY:
available_providers.append("DeepSeek")
if not available_providers:
print("Error: No AI provider API keys configured. Please set at least one of:")
print(" - OPENAI_API_KEY")
print(" - ANTHROPIC_API_KEY")
print(" - GEMINI_API_KEY")
print(" - DEEPSEEK_API_KEY")
sys.exit(1)
print(f"Available AI providers: {', '.join(available_providers)}")
if not OPENAI_API_KEY:
print("Warning: OpenAI API key not configured. Search functionality will be limited.")
if not all([AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY]):
print("Warning: AWS credentials not configured. Will use local files only.")
```
---
### 9. Додано підтримку Gemini Embeddings ✨
**Файл:** [embeddings/gemini_embedding.py](embeddings/gemini_embedding.py)
Створено custom embedding клас для використання Gemini API як альтернативи OpenAI для пошуку:
```python
from llama_index.core.embeddings import BaseEmbedding
from google import genai
class GeminiEmbedding(BaseEmbedding):
"""Gemini embedding integration for LlamaIndex."""
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)
```
**Файл:** [main.py](main.py:48-67)
Оновлено ініціалізацію embedding моделі з пріоритетом: OpenAI → Gemini → None
```python
# 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.")
```
Детальна документація: [GEMINI_EMBEDDINGS.md](GEMINI_EMBEDDINGS.md)
---
## 🎯 Результат
### Тепер додаток може працювати в наступних сценаріях:
1. **Тільки з Gemini API ключем (рекомендовано):**
```bash
export GEMINI_API_KEY=your_key_here
python main.py
```
- ✅ Генерація правових позицій працює (Gemini)
- ✅ Пошук працює (Gemini embeddings)
- ✅ Аналіз працює (Gemini)
- 🎉 **Повна функціональність з одним провайдером!**
2. **Тільки з OpenAI API ключем:**
```bash
export OPENAI_API_KEY=your_key_here
python main.py
```
- ✅ Генерація правових позицій працює
- ✅ Пошук працює
- ✅ Аналіз працює
3. **З декількома провайдерами:**
```bash
export GEMINI_API_KEY=your_gemini_key
export OPENAI_API_KEY=your_openai_key
python main.py
```
- ✅ Повна функціональність
- ✅ Можливість вибору провайдера
4. **Без AWS (локальні файли):**
```bash
export GEMINI_API_KEY=your_key_here
# AWS credentials не потрібні, якщо файли є локально
python main.py
```
- ✅ Працює з локальними файлами
- ⚠️ Попередження про відсутність AWS credentials
---
## 📊 Порівняння
### До змін:
```
❌ Потрібні всі ключі: OPENAI_API_KEY, ANTHROPIC_API_KEY, AWS
❌ Додаток не запускається без OpenAI
❌ Жорстка помилка при відсутності будь-якого ключа
```
### Після змін:
```
✅ Потрібен хоча б один AI провайдер
✅ AWS опціональний (локальні файли)
✅ OpenAI опціональний (для генерації)
✅ Зрозумілі повідомлення про доступність функцій
✅ Graceful degradation функціональності
```
---
## 🔍 Перевірка
### Синтаксис Python:
```bash
✅ python3 -m py_compile main.py
✅ python3 -m py_compile config.py
```
### Тестові сценарії:
**1. Запуск з мінімальною конфігурацією (тільки Gemini):**
```bash
# .env
GEMINI_API_KEY=your_key_here
# Очікуваний результат:
Available AI providers: Gemini
Warning: OpenAI API key not configured. Search functionality will be limited.
Warning: AWS credentials not configured. Will use local files only.
Components initialized successfully!
```
**2. Спроба використати недоступний провайдер:**
```bash
# Вибрано OpenAI, але ключ відсутній
Результат: {
"title": "Помилка конфігурації",
"text": "OPENAI API key not configured. Available providers: GEMINI",
"proceeding": "N/A",
"category": "Error"
}
```
**3. Спроба пошуку без OpenAI:**
```bash
Результат: "Помилка: пошук недоступний без налаштованого OpenAI API ключа"
```
---
## 📝 Змінені файли
| Файл | Зміни | Опис |
|------|-------|------|
| [main.py](main.py) | ~50 рядків | Опціональна ініціалізація, хелпер функції, перевірки |
| [config.py](config.py) | ~30 рядків | Гнучка валідація environment variables |
---
## 🎓 Висновок
### Виконано:
**Додаток може запускатися з будь-яким одним AI провайдером**
**AWS credentials опціональні**
**OpenAI ключ опціональний (з обмеженням функціональності)**
**Зрозумілі повідомлення про доступність функцій**
**Graceful degradation замість hard errors**
**Перевірено синтаксис Python**
### Переваги нової структури:
**Гнучке розгортання** - можна запустити з мінімальною конфігурацією
**Краща UX** - зрозумілі повідомлення про те, що доступно/недоступно
**Економія коштів** - не потрібно платити за всі провайдери одразу
**Тестування** - легше тестувати з одним провайдером
**Production-ready** - додаток не падає при неповній конфігурації
### Обмеження:
⚠️ **Пошук потребує OpenAI** - для embedding моделі
⚠️ **Мінімум один AI провайдер** - інакше додаток не запуститься
⚠️ **Функціональність залежить від ключів** - деякі функції недоступні без певних провайдерів
---
## 📚 Наступні кроки (опціонально)
Можливі покращення в майбутньому:
1. **Альтернативні embedding моделі:**
- Додати підтримку Gemini embeddings
- Додати підтримку локальних embedding моделей
- Це зробить пошук доступним без OpenAI
2. **UI індикатори:**
- Показувати в інтерфейсі, які провайдери доступні
- Вимикати кнопки/функції, які недоступні
- Tooltip з поясненням, чому функція недоступна
3. **Конфігураційний файл:**
- Можливість вказати бажані провайдери в YAML
- Автоматичне приховування недоступних опцій
---
**Статус:****ГОТОВО**
**Дата завершення:** 2025-12-28