diff --git a/OPENAI_SETUP.md b/OPENAI_SETUP.md new file mode 100644 index 0000000..34e7f44 --- /dev/null +++ b/OPENAI_SETUP.md @@ -0,0 +1,89 @@ +# Настройка OpenAI API + +## Проблема + +Получена ошибка `401 Unauthorized` при обращении к OpenAI API. Это означает, что API ключ недействителен или истек. + +## Решение + +### 1. Получите новый API ключ OpenAI + +1. Перейдите на [OpenAI Platform](https://platform.openai.com/) +2. Войдите в свой аккаунт или создайте новый +3. Перейдите в раздел "API Keys" +4. Создайте новый API ключ +5. Скопируйте ключ (он начинается с `sk-`) + +### 2. Настройте API ключ + +#### Вариант A: Переменная окружения (рекомендуется) + +```bash +export OPENAI_API_KEY=sk-your-actual-api-key-here +``` + +#### Вариант B: Прямо в application.properties + +Откройте файл `src/main/resources/application.properties` и замените: + +```properties +openai.api.key=your-openai-api-key-here +``` + +на: + +```properties +openai.api.key=sk-your-actual-api-key-here +``` + +### 3. Проверьте настройки + +Убедитесь, что в `application.properties` правильно настроены: + +```properties +# OpenAI Configuration +openai.api.key=${OPENAI_API_KEY:your-openai-api-key-here} +openai.api.url=https://api.openai.com/v1/chat/completions +openai.model.name=gpt-4o-mini +openai.timeoutMs=90000 +``` + +### 4. Тестирование + +После настройки API ключа: + +1. Перезапустите приложение +2. Откройте `GET /api/openai/test` для проверки подключения +3. Проверьте логи на наличие ошибок + +### 5. Возможные проблемы + +- **401 Unauthorized**: Неверный или истекший API ключ +- **429 Rate Limit**: Превышен лимит запросов +- **500 Server Error**: Временная проблема с сервером OpenAI + +### 6. Безопасность + +⚠️ **Важно**: Никогда не коммитьте реальные API ключи в репозиторий! + +- Используйте переменные окружения +- Добавьте `application.properties` в `.gitignore` если содержит секреты +- Используйте отдельные файлы конфигурации для продакшена + +## Пример использования + +После настройки API ключа сервис будет работать автоматически: + +```java +@Autowired +private OpenAIAnalyticsService openAIAnalyticsService; + +// Анализ текста +MarketItem.Analytics analytics = openAIAnalyticsService.analyzeText("Ваш текст здесь"); + +// Генерация контента +String result = openAIAnalyticsService.generateWithInstruction( + "Данные для анализа", + "Напиши краткий отчет" +); +``` diff --git a/src/main/java/kz/konturai/parser/service/OpenAIAnalyticsService.java b/src/main/java/kz/konturai/parser/service/OpenAIAnalyticsService.java index a650ceb..481fb1a 100644 --- a/src/main/java/kz/konturai/parser/service/OpenAIAnalyticsService.java +++ b/src/main/java/kz/konturai/parser/service/OpenAIAnalyticsService.java @@ -37,6 +37,16 @@ public class OpenAIAnalyticsService { private String apiKey; public OpenAIAnalyticsService(@Value("${openai.api.url:https://api.openai.com/v1/chat/completions}") String openaiUrl) { + // Проверяем API ключ при инициализации + if (apiKey == null || apiKey.trim().isEmpty() || apiKey.equals("your-openai-api-key-here")) { + logger.error("OpenAI API key is not configured properly. Please set OPENAI_API_KEY environment variable or update application.properties"); + throw new IllegalStateException("OpenAI API key is not configured"); + } + + if (!apiKey.startsWith("sk-")) { + logger.warn("OpenAI API key does not start with 'sk-'. Please verify your API key is correct."); + } + HttpClient httpClient = HttpClient.create() .compress(true) .responseTimeout(Duration.ofMillis(timeoutMs)); @@ -46,6 +56,8 @@ public class OpenAIAnalyticsService { .clientConnector(new ReactorClientHttpConnector(httpClient)) .defaultHeader("Authorization", "Bearer " + apiKey) .build(); + + logger.info("OpenAIAnalyticsService initialized with model: {}", modelName); } public MarketItem.Analytics analyzeText(String text) { @@ -135,7 +147,14 @@ public class OpenAIAnalyticsService { .bodyToMono(new ParameterizedTypeReference>() { }) .onErrorResume(err -> { - logger.warn("OpenAI request failed: {}", err.getMessage()); + logger.error("OpenAI request failed: {} - {}", err.getMessage(), err.getClass().getSimpleName()); + if (err.getMessage().contains("401")) { + logger.error("OpenAI API key is invalid or expired. Please check your openai.api.key configuration."); + } else if (err.getMessage().contains("429")) { + logger.error("OpenAI API rate limit exceeded. Please try again later."); + } else if (err.getMessage().contains("500")) { + logger.error("OpenAI API server error. Please try again later."); + } return Mono.empty(); }) .block(Duration.ofMillis(timeoutMs)); @@ -187,7 +206,14 @@ public class OpenAIAnalyticsService { .bodyToMono(new ParameterizedTypeReference>() { }) .onErrorResume(err -> { - logger.warn("OpenAI request failed: {}", err.getMessage()); + logger.error("OpenAI request failed: {} - {}", err.getMessage(), err.getClass().getSimpleName()); + if (err.getMessage().contains("401")) { + logger.error("OpenAI API key is invalid or expired. Please check your openai.api.key configuration."); + } else if (err.getMessage().contains("429")) { + logger.error("OpenAI API rate limit exceeded. Please try again later."); + } else if (err.getMessage().contains("500")) { + logger.error("OpenAI API server error. Please try again later."); + } return Mono.empty(); }) .block(Duration.ofMillis(timeoutMs)); diff --git a/test-openai-api.sh b/test-openai-api.sh new file mode 100644 index 0000000..4d4ea4e --- /dev/null +++ b/test-openai-api.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# Скрипт для тестирования OpenAI API ключа + +echo "🔍 Тестирование OpenAI API ключа..." + +# Проверяем, установлена ли переменная окружения +if [ -z "$OPENAI_API_KEY" ]; then + echo "❌ Переменная окружения OPENAI_API_KEY не установлена" + echo "Установите её командой: export OPENAI_API_KEY=sk-your-api-key-here" + exit 1 +fi + +# Проверяем формат ключа +if [[ ! $OPENAI_API_KEY =~ ^sk- ]]; then + echo "❌ API ключ должен начинаться с 'sk-'" + exit 1 +fi + +echo "✅ API ключ найден: ${OPENAI_API_KEY:0:10}..." + +# Тестируем API +echo "🚀 Отправка тестового запроса к OpenAI API..." + +response=$(curl -s -w "\n%{http_code}" -X POST "https://api.openai.com/v1/chat/completions" \ + -H "Authorization: Bearer $OPENAI_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "model": "gpt-4o-mini", + "messages": [ + { + "role": "user", + "content": "Привет! Это тест API ключа. Ответь коротко." + } + ], + "max_tokens": 50 + }') + +# Извлекаем HTTP код и тело ответа +http_code=$(echo "$response" | tail -n1) +response_body=$(echo "$response" | head -n -1) + +echo "📊 HTTP код: $http_code" + +if [ "$http_code" = "200" ]; then + echo "✅ API ключ работает корректно!" + echo "📝 Ответ от OpenAI:" + echo "$response_body" | jq -r '.choices[0].message.content' 2>/dev/null || echo "$response_body" +elif [ "$http_code" = "401" ]; then + echo "❌ Ошибка 401: API ключ недействителен или истек" + echo "📝 Ответ: $response_body" +elif [ "$http_code" = "429" ]; then + echo "⚠️ Ошибка 429: Превышен лимит запросов" + echo "📝 Ответ: $response_body" +else + echo "❌ Ошибка $http_code" + echo "📝 Ответ: $response_body" +fi