.
This commit is contained in:
@@ -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(
|
||||||
|
"Данные для анализа",
|
||||||
|
"Напиши краткий отчет"
|
||||||
|
);
|
||||||
|
```
|
||||||
@@ -37,6 +37,16 @@ public class OpenAIAnalyticsService {
|
|||||||
private String apiKey;
|
private String apiKey;
|
||||||
|
|
||||||
public OpenAIAnalyticsService(@Value("${openai.api.url:https://api.openai.com/v1/chat/completions}") String openaiUrl) {
|
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()
|
HttpClient httpClient = HttpClient.create()
|
||||||
.compress(true)
|
.compress(true)
|
||||||
.responseTimeout(Duration.ofMillis(timeoutMs));
|
.responseTimeout(Duration.ofMillis(timeoutMs));
|
||||||
@@ -46,6 +56,8 @@ public class OpenAIAnalyticsService {
|
|||||||
.clientConnector(new ReactorClientHttpConnector(httpClient))
|
.clientConnector(new ReactorClientHttpConnector(httpClient))
|
||||||
.defaultHeader("Authorization", "Bearer " + apiKey)
|
.defaultHeader("Authorization", "Bearer " + apiKey)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
logger.info("OpenAIAnalyticsService initialized with model: {}", modelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MarketItem.Analytics analyzeText(String text) {
|
public MarketItem.Analytics analyzeText(String text) {
|
||||||
@@ -135,7 +147,14 @@ public class OpenAIAnalyticsService {
|
|||||||
.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
|
.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
|
||||||
})
|
})
|
||||||
.onErrorResume(err -> {
|
.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();
|
return Mono.empty();
|
||||||
})
|
})
|
||||||
.block(Duration.ofMillis(timeoutMs));
|
.block(Duration.ofMillis(timeoutMs));
|
||||||
@@ -187,7 +206,14 @@ public class OpenAIAnalyticsService {
|
|||||||
.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
|
.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
|
||||||
})
|
})
|
||||||
.onErrorResume(err -> {
|
.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();
|
return Mono.empty();
|
||||||
})
|
})
|
||||||
.block(Duration.ofMillis(timeoutMs));
|
.block(Duration.ofMillis(timeoutMs));
|
||||||
|
|||||||
@@ -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
|
||||||
Reference in New Issue
Block a user