.
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
# Интеграция OpenAI API
|
||||
|
||||
## Обзор
|
||||
|
||||
Создан новый сервис `OpenAIAnalyticsService` для замены `OllamaAnalyticsService`. Новый сервис использует OpenAI API для анализа текста и генерации контента.
|
||||
|
||||
## Основные изменения
|
||||
|
||||
### 1. Новый сервис OpenAIAnalyticsService
|
||||
|
||||
- **Файл**: `src/main/java/kz/konturai/parser/service/OpenAIAnalyticsService.java`
|
||||
- **Функциональность**: Аналогична `OllamaAnalyticsService`, но использует OpenAI API
|
||||
- **Методы**:
|
||||
- `analyzeText(String text)` - анализ текста с извлечением саммари, тегов, тональности и сущностей
|
||||
- `analyzeText(String text, String language)` - анализ с указанием языка
|
||||
- `generateWithInstruction(String text, String instruction)` - генерация текста по инструкции
|
||||
- `generateWithInstruction(String text, String instruction, String language)` - генерация с указанием языка
|
||||
|
||||
### 2. Обновленные сервисы
|
||||
|
||||
Все сервисы, которые использовали `OllamaAnalyticsService`, теперь используют `OpenAIAnalyticsService`:
|
||||
|
||||
- `ReportSynthesisService`
|
||||
- `ReportGenerationService`
|
||||
- `KursivParserService`
|
||||
- `KapitalParserService`
|
||||
- `LsmParserService`
|
||||
- `RbcParserService`
|
||||
- `VedomostiParserService`
|
||||
|
||||
### 3. Конфигурация
|
||||
|
||||
В `application.properties` уже настроены параметры для OpenAI:
|
||||
|
||||
```properties
|
||||
# OpenAI Configuration
|
||||
openai.api.key=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
|
||||
openai.api.url=https://api.openai.com/v1/chat/completions
|
||||
openai.model.name=gpt-4o-mini
|
||||
openai.timeoutMs=90000
|
||||
```
|
||||
|
||||
### 4. Тестовый контроллер
|
||||
|
||||
Создан `OpenAITestController` для тестирования функциональности:
|
||||
|
||||
- `POST /api/openai/analyze` - анализ текста
|
||||
- `POST /api/openai/generate` - генерация по инструкции
|
||||
- `GET /api/openai/test` - тест подключения
|
||||
|
||||
## Использование
|
||||
|
||||
### Анализ текста
|
||||
|
||||
```java
|
||||
@Autowired
|
||||
private OpenAIAnalyticsService openAIAnalyticsService;
|
||||
|
||||
// Анализ текста на русском языке
|
||||
MarketItem.Analytics analytics = openAIAnalyticsService.analyzeText(text, "ru");
|
||||
|
||||
// Получение саммари
|
||||
String summary = analytics.getSummary();
|
||||
|
||||
// Получение тегов
|
||||
String[] tags = analytics.getTags();
|
||||
|
||||
// Получение тональности
|
||||
String sentiment = analytics.getSentiment();
|
||||
|
||||
// Получение сущностей
|
||||
Map<String, Object> entities = analytics.getEntities();
|
||||
```
|
||||
|
||||
### Генерация текста
|
||||
|
||||
```java
|
||||
// Генерация отчета
|
||||
String instruction = "Напиши краткий отчет на основе следующих данных:";
|
||||
String generatedText = openAIAnalyticsService.generateWithInstruction(data, instruction, "ru");
|
||||
```
|
||||
|
||||
## Преимущества OpenAI API
|
||||
|
||||
1. **Высокое качество**: GPT-4o-mini обеспечивает более качественный анализ и генерацию текста
|
||||
2. **Надежность**: Стабильная работа API без необходимости локального сервера
|
||||
3. **Масштабируемость**: Легко масштабируется под нагрузку
|
||||
4. **Многоязычность**: Отличная поддержка русского и английского языков
|
||||
5. **Консистентность**: Более предсказуемые результаты
|
||||
|
||||
## Миграция
|
||||
|
||||
Все существующие вызовы `OllamaAnalyticsService` автоматически заменены на `OpenAIAnalyticsService`. API остается совместимым, поэтому дополнительных изменений в коде не требуется.
|
||||
|
||||
## Тестирование
|
||||
|
||||
Для тестирования нового сервиса:
|
||||
|
||||
1. Запустите приложение
|
||||
2. Откройте `GET /api/openai/test` для проверки подключения
|
||||
3. Используйте `POST /api/openai/analyze` для анализа текста
|
||||
4. Используйте `POST /api/openai/generate` для генерации контента
|
||||
|
||||
## Настройка
|
||||
|
||||
Убедитесь, что в `application.properties` указан корректный API ключ OpenAI:
|
||||
|
||||
```properties
|
||||
openai.api.key=your-openai-api-key-here
|
||||
```
|
||||
|
||||
Модель по умолчанию: `gpt-4o-mini` (можно изменить в настройках).
|
||||
@@ -0,0 +1,42 @@
|
||||
package kz.konturai.parser.controller;
|
||||
|
||||
import kz.konturai.parser.model.MarketItem;
|
||||
import kz.konturai.parser.service.OpenAIAnalyticsService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/openai")
|
||||
public class OpenAITestController {
|
||||
|
||||
@Autowired
|
||||
private OpenAIAnalyticsService openAIAnalyticsService;
|
||||
|
||||
@PostMapping("/analyze")
|
||||
public MarketItem.Analytics analyzeText(@RequestParam String text,
|
||||
@RequestParam(defaultValue = "ru") String language) {
|
||||
return openAIAnalyticsService.analyzeText(text, language);
|
||||
}
|
||||
|
||||
@PostMapping("/generate")
|
||||
public String generateWithInstruction(@RequestParam String text,
|
||||
@RequestParam String instruction,
|
||||
@RequestParam(defaultValue = "ru") String language) {
|
||||
return openAIAnalyticsService.generateWithInstruction(text, instruction, language);
|
||||
}
|
||||
|
||||
@GetMapping("/test")
|
||||
public String testConnection() {
|
||||
String testText = "Это тестовая новость о развитии технологий в Казахстане. Компания Kaspi Bank объявила о новых инвестициях в цифровые сервисы.";
|
||||
MarketItem.Analytics analytics = openAIAnalyticsService.analyzeText(testText);
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("OpenAI Analytics Service Test:\n");
|
||||
result.append("Summary: ").append(analytics.getSummary()).append("\n");
|
||||
result.append("Sentiment: ").append(analytics.getSentiment()).append("\n");
|
||||
result.append("Tags: ").append(String.join(", ", analytics.getTags())).append("\n");
|
||||
result.append("Entities: ").append(analytics.getEntities()).append("\n");
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public class KapitalParserService implements ParserService {
|
||||
private MarketItemRepository marketItemRepository;
|
||||
|
||||
@Autowired
|
||||
private OllamaAnalyticsService analyticsService;
|
||||
private OpenAIAnalyticsService analyticsService;
|
||||
|
||||
@Value("${rss.kapital.url}")
|
||||
private String rssFeedUrl;
|
||||
|
||||
@@ -33,7 +33,7 @@ public class KursivParserService implements ParserService {
|
||||
private MarketItemRepository marketItemRepository;
|
||||
|
||||
@Autowired
|
||||
private OllamaAnalyticsService analyticsService;
|
||||
private OpenAIAnalyticsService analyticsService;
|
||||
|
||||
@Value("${rss.feed.url}")
|
||||
private String rssFeedUrl;
|
||||
|
||||
@@ -33,7 +33,7 @@ public class LsmParserService implements ParserService {
|
||||
private MarketItemRepository marketItemRepository;
|
||||
|
||||
@Autowired
|
||||
private OllamaAnalyticsService analyticsService;
|
||||
private OpenAIAnalyticsService analyticsService;
|
||||
|
||||
@Value("${rss.lsm.url}")
|
||||
private String rssFeedUrl;
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
package kz.konturai.parser.service;
|
||||
|
||||
import kz.konturai.parser.model.MarketItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Mono;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
|
||||
@Service
|
||||
public class OpenAIAnalyticsService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OpenAIAnalyticsService.class);
|
||||
|
||||
private final WebClient webClient;
|
||||
|
||||
@Value("${openai.model.name:gpt-4o-mini}")
|
||||
private String modelName;
|
||||
|
||||
@Value("${openai.timeoutMs:90000}")
|
||||
private long timeoutMs;
|
||||
|
||||
@Value("${openai.api.key}")
|
||||
private String apiKey;
|
||||
|
||||
public OpenAIAnalyticsService(@Value("${openai.api.url:https://api.openai.com/v1/chat/completions}") String openaiUrl) {
|
||||
HttpClient httpClient = HttpClient.create()
|
||||
.compress(true)
|
||||
.responseTimeout(Duration.ofMillis(timeoutMs));
|
||||
|
||||
this.webClient = WebClient.builder()
|
||||
.baseUrl(openaiUrl)
|
||||
.clientConnector(new ReactorClientHttpConnector(httpClient))
|
||||
.defaultHeader("Authorization", "Bearer " + apiKey)
|
||||
.build();
|
||||
}
|
||||
|
||||
public MarketItem.Analytics analyzeText(String text) {
|
||||
return analyzeText(text, "ru");
|
||||
}
|
||||
|
||||
public MarketItem.Analytics analyzeText(String text, String language) {
|
||||
MarketItem.Analytics analytics = new MarketItem.Analytics();
|
||||
boolean isRussian = "ru".equalsIgnoreCase(language) || "russian".equalsIgnoreCase(language);
|
||||
|
||||
try {
|
||||
String summaryPrompt = isRussian
|
||||
? "Напиши краткое саммари следующей новостной статьи на русском языке. Ответ должен содержать только саммари из 3-4 предложений, без лишних вступлений. Статья: "
|
||||
: "Write a brief summary of the following news article in English. The response should contain only a summary of 3-4 sentences, without any unnecessary introductions. Article: ";
|
||||
String summary = generate(text, summaryPrompt);
|
||||
analytics.setSummary(summary);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to get summary from OpenAI: {}", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
String tagsPrompt = isRussian
|
||||
? "Извлеки 5-7 ключевых слов или тегов из текста новостной статьи. В ответе дай только список тегов через запятую, без нумерации и заголовков. Статья: "
|
||||
: "Extract 5-7 key words or tags from the news article text. In your response, provide only a list of tags separated by commas, without numbering or headers. Article: ";
|
||||
String tagsCsv = generate(text, tagsPrompt);
|
||||
String[] tags = tagsCsv == null ? new String[] {} : tagsCsv.replace("\n", " ").split("\\s*,\\s*");
|
||||
analytics.setTags(tags);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to get tags from OpenAI: {}", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
String sentimentPrompt = isRussian
|
||||
? "Определи тональность текста новостной статьи. В ответе дай только одно слово латиницей: positive, negative или neutral. Статья: "
|
||||
: "Determine the sentiment of the news article text. In your response, provide only one word in English: positive, negative, or neutral. Article: ";
|
||||
String sentiment = generate(text, sentimentPrompt);
|
||||
if (sentiment != null) {
|
||||
sentiment = sentiment.trim().toLowerCase();
|
||||
}
|
||||
analytics.setSentiment(sentiment);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to get sentiment from OpenAI: {}", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
String entitiesPrompt = isRussian
|
||||
? "Извлеки из текста имена людей, названия компаний и географические локации. В ответе дай только JSON объект следующей структуры: {\"persons\": [], \"companies\": [], \"locations\": []}. Статья: "
|
||||
: "Extract from the text names of people, company names, and geographic locations. In your response, provide only a JSON object with the following structure: {\"persons\": [], \"companies\": [], \"locations\": []}. Article: ";
|
||||
String entitiesJson = generate(text, entitiesPrompt);
|
||||
Map<String, Object> entities = new HashMap<>();
|
||||
if (entitiesJson != null && entitiesJson.trim().startsWith("{")) {
|
||||
try {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
entities = mapper.readValue(entitiesJson, new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
} catch (Exception parseEx) {
|
||||
entities.put("raw", entitiesJson);
|
||||
}
|
||||
}
|
||||
analytics.setEntities(entities);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to get entities from OpenAI: {}", e.getMessage());
|
||||
}
|
||||
|
||||
return analytics;
|
||||
}
|
||||
|
||||
private String generate(String text, String instructionPrefix) {
|
||||
String prompt = instructionPrefix + text;
|
||||
|
||||
Map<String, Object> message = new HashMap<>();
|
||||
message.put("role", "user");
|
||||
message.put("content", prompt);
|
||||
|
||||
Map<String, Object> requestBody = new HashMap<>();
|
||||
requestBody.put("model", modelName);
|
||||
requestBody.put("messages", List.of(message));
|
||||
requestBody.put("max_tokens", 1000);
|
||||
requestBody.put("temperature", 0.3);
|
||||
|
||||
try {
|
||||
Map<String, Object> response = this.webClient.post()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(requestBody)
|
||||
.retrieve()
|
||||
.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
|
||||
})
|
||||
.onErrorResume(err -> {
|
||||
logger.warn("OpenAI request failed: {}", err.getMessage());
|
||||
return Mono.empty();
|
||||
})
|
||||
.block(Duration.ofMillis(timeoutMs));
|
||||
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> choices = (List<Map<String, Object>>) response.get("choices");
|
||||
if (choices != null && !choices.isEmpty()) {
|
||||
Map<String, Object> firstChoice = choices.get(0);
|
||||
Map<String, Object> messageObj = (Map<String, Object>) firstChoice.get("message");
|
||||
if (messageObj != null) {
|
||||
Object content = messageObj.get("content");
|
||||
return content == null ? null : String.valueOf(content).trim();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error calling OpenAI generate: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String generateWithInstruction(String text, String instruction) {
|
||||
return generateWithInstruction(text, instruction, "ru");
|
||||
}
|
||||
|
||||
public String generateWithInstruction(String text, String instruction, String language) {
|
||||
String prompt = instruction + "\n\n" + text;
|
||||
|
||||
Map<String, Object> message = new HashMap<>();
|
||||
message.put("role", "user");
|
||||
message.put("content", prompt);
|
||||
|
||||
Map<String, Object> requestBody = new HashMap<>();
|
||||
requestBody.put("model", modelName);
|
||||
requestBody.put("messages", List.of(message));
|
||||
requestBody.put("max_tokens", 2000);
|
||||
requestBody.put("temperature", 0.3);
|
||||
|
||||
try {
|
||||
Map<String, Object> response = this.webClient.post()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(requestBody)
|
||||
.retrieve()
|
||||
.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
|
||||
})
|
||||
.onErrorResume(err -> {
|
||||
logger.warn("OpenAI request failed: {}", err.getMessage());
|
||||
return Mono.empty();
|
||||
})
|
||||
.block(Duration.ofMillis(timeoutMs));
|
||||
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> choices = (List<Map<String, Object>>) response.get("choices");
|
||||
if (choices != null && !choices.isEmpty()) {
|
||||
Map<String, Object> firstChoice = choices.get(0);
|
||||
Map<String, Object> messageObj = (Map<String, Object>) firstChoice.get("message");
|
||||
if (messageObj != null) {
|
||||
Object content = messageObj.get("content");
|
||||
String result = content == null ? null : String.valueOf(content).trim();
|
||||
System.out.println("OpenAI response: " + result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error calling OpenAI generate (generic): {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public class RbcParserService implements ParserService {
|
||||
private MarketItemRepository marketItemRepository;
|
||||
|
||||
@Autowired
|
||||
private OllamaAnalyticsService analyticsService;
|
||||
private OpenAIAnalyticsService analyticsService;
|
||||
|
||||
@Value("${rss.rbc.url}")
|
||||
private String rssFeedUrl;
|
||||
|
||||
@@ -82,18 +82,18 @@ public class ReportGenerationService {
|
||||
}
|
||||
|
||||
private final MarketItemRepository marketItemRepository;
|
||||
private final OllamaAnalyticsService ollamaAnalyticsService;
|
||||
private final OpenAIAnalyticsService openAIAnalyticsService;
|
||||
private final ReportHistoryRepository reportHistoryRepository;
|
||||
private final MinIOService minIOService;
|
||||
private final EmailService emailService;
|
||||
|
||||
public ReportGenerationService(MarketItemRepository marketItemRepository,
|
||||
OllamaAnalyticsService ollamaAnalyticsService,
|
||||
OpenAIAnalyticsService openAIAnalyticsService,
|
||||
ReportHistoryRepository reportHistoryRepository,
|
||||
MinIOService minIOService,
|
||||
EmailService emailService) {
|
||||
this.marketItemRepository = marketItemRepository;
|
||||
this.ollamaAnalyticsService = ollamaAnalyticsService;
|
||||
this.openAIAnalyticsService = openAIAnalyticsService;
|
||||
this.reportHistoryRepository = reportHistoryRepository;
|
||||
this.minIOService = minIOService;
|
||||
this.emailService = emailService;
|
||||
@@ -131,7 +131,7 @@ public class ReportGenerationService {
|
||||
+ "Не упоминай, что ты ИИ. Используй русский язык.\n\nКонтекст отчёта:\n" + contextBlock
|
||||
+ "\nСводки новостей:\n";
|
||||
|
||||
String generated = ollamaAnalyticsService.generateWithInstruction(combined, instruction);
|
||||
String generated = openAIAnalyticsService.generateWithInstruction(combined, instruction);
|
||||
if (generated == null) {
|
||||
generated = "(Не удалось сгенерировать текст отчёта по предоставленным данным.)";
|
||||
}
|
||||
@@ -248,7 +248,7 @@ public class ReportGenerationService {
|
||||
return "";
|
||||
}
|
||||
String instruction = "На основе этих кратких сводок новостей напиши общую аннотацию на 2-3 абзаца, выделяя ключевые тренды и события.";
|
||||
String res = ollamaAnalyticsService.generateWithInstruction(combined, instruction);
|
||||
String res = openAIAnalyticsService.generateWithInstruction(combined, instruction);
|
||||
return res == null ? "" : res;
|
||||
}
|
||||
|
||||
@@ -257,16 +257,16 @@ public class ReportGenerationService {
|
||||
if (combined.isBlank()) {
|
||||
return new Sections("", "", "", "");
|
||||
}
|
||||
String annotation = ollamaAnalyticsService.generateWithInstruction(combined,
|
||||
String annotation = openAIAnalyticsService.generateWithInstruction(combined,
|
||||
"На основе кратких сводок новостей напиши краткое содержание (2-3 абзаца), выделив ключевые тренды и события. Стиль: деловой, нейтральный.");
|
||||
|
||||
String intro = ollamaAnalyticsService.generateWithInstruction(combined,
|
||||
String intro = openAIAnalyticsService.generateWithInstruction(combined,
|
||||
"Напиши краткое введение к аналитическому отчёту за период. Укажи цель отчёта, источники данных и подход к анализу. Объём: 1 абзац.");
|
||||
|
||||
String mainPart = ollamaAnalyticsService.generateWithInstruction(combined,
|
||||
String mainPart = openAIAnalyticsService.generateWithInstruction(combined,
|
||||
"Сформируй основную часть отчёта: перечисли и кратко объясни 3-5 ключевых тенденций и событий периода, добавь замеченные риски и возможности. Используй маркированные пункты и короткие абзацы.");
|
||||
|
||||
String recs = ollamaAnalyticsService.generateWithInstruction(combined,
|
||||
String recs = openAIAnalyticsService.generateWithInstruction(combined,
|
||||
"На основе сводок сформулируй практические рекомендации (4-6 пунктов) для бизнеса/маркетинга. Формат: маркированный список, краткие и конкретные формулировки.");
|
||||
|
||||
return new Sections(annotation, intro, mainPart, recs);
|
||||
|
||||
@@ -18,13 +18,13 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class ReportSynthesisService {
|
||||
|
||||
private final OllamaAnalyticsService ollamaAnalyticsService;
|
||||
private final OpenAIAnalyticsService openAIAnalyticsService;
|
||||
private final OpenAiChartService openAiChartService;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public ReportSynthesisService(OllamaAnalyticsService ollamaAnalyticsService,
|
||||
public ReportSynthesisService(OpenAIAnalyticsService openAIAnalyticsService,
|
||||
OpenAiChartService openAiChartService) {
|
||||
this.ollamaAnalyticsService = ollamaAnalyticsService;
|
||||
this.openAIAnalyticsService = openAIAnalyticsService;
|
||||
this.openAiChartService = openAiChartService;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public class ReportSynthesisService {
|
||||
String aggregatedLearnings = formatLearnings(learnings);
|
||||
String prompt = buildTextPrompt(originalQuery, aggregatedLearnings, lang);
|
||||
return Mono
|
||||
.fromCallable(() -> ollamaAnalyticsService.generateWithInstruction(aggregatedLearnings, prompt, lang));
|
||||
.fromCallable(() -> openAIAnalyticsService.generateWithInstruction(aggregatedLearnings, prompt, lang));
|
||||
}
|
||||
|
||||
public Mono<FinalReportPayload> synthesizeReportAndCharts(String originalQuery, List<String> learnings,
|
||||
@@ -40,7 +40,7 @@ public class ReportSynthesisService {
|
||||
String aggregatedLearnings = formatLearnings(learnings);
|
||||
|
||||
Mono<String> textMono = Mono.fromCallable(
|
||||
() -> ollamaAnalyticsService.generateWithInstruction(aggregatedLearnings,
|
||||
() -> openAIAnalyticsService.generateWithInstruction(aggregatedLearnings,
|
||||
buildTextPrompt(originalQuery, aggregatedLearnings, lang), lang))
|
||||
.subscribeOn(Schedulers.boundedElastic());
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ public class VedomostiParserService implements ParserService {
|
||||
private MarketItemRepository marketItemRepository;
|
||||
|
||||
@Autowired
|
||||
private OllamaAnalyticsService analyticsService;
|
||||
private OpenAIAnalyticsService analyticsService;
|
||||
|
||||
@Value("${rss.vedomosti.url}")
|
||||
private String rssFeedUrl;
|
||||
|
||||
Reference in New Issue
Block a user