analytics added

This commit is contained in:
root
2025-09-17 12:29:11 +05:00
parent 995094fe82
commit 63499c351a
9 changed files with 273 additions and 0 deletions
@@ -32,6 +32,9 @@ public class KapitalParserService implements ParserService {
@Autowired
private MarketItemRepository marketItemRepository;
@Autowired
private OllamaAnalyticsService analyticsService;
@Value("${rss.kapital.url}")
private String rssFeedUrl;
@@ -79,6 +82,13 @@ public class KapitalParserService implements ParserService {
try {
MarketItem marketItem = processRssEntry(entry);
if (marketItem != null) {
try {
MarketItem.Analytics analytics = analyticsService.analyzeText(marketItem.getRawText());
marketItem.setAnalytics(analytics);
} catch (Exception e) {
logger.warn("Analytics step failed for Kapital '{}': {}", marketItem.getTitle(),
e.getMessage());
}
MarketItem savedItem = saveOrUpdateMarketItem(marketItem);
if (savedItem != null) {
savedItems.add(savedItem);
@@ -32,6 +32,9 @@ public class KursivParserService implements ParserService {
@Autowired
private MarketItemRepository marketItemRepository;
@Autowired
private OllamaAnalyticsService analyticsService;
@Value("${rss.feed.url}")
private String rssFeedUrl;
@@ -79,6 +82,13 @@ public class KursivParserService implements ParserService {
try {
MarketItem marketItem = processRssEntry(entry);
if (marketItem != null) {
try {
MarketItem.Analytics analytics = analyticsService.analyzeText(marketItem.getRawText());
marketItem.setAnalytics(analytics);
} catch (Exception e) {
logger.warn("Analytics step failed for entry '{}': {}", marketItem.getTitle(),
e.getMessage());
}
MarketItem savedItem = saveOrUpdateMarketItem(marketItem);
if (savedItem != null) {
savedItems.add(savedItem);
@@ -32,6 +32,9 @@ public class LsmParserService implements ParserService {
@Autowired
private MarketItemRepository marketItemRepository;
@Autowired
private OllamaAnalyticsService analyticsService;
@Value("${rss.lsm.url}")
private String rssFeedUrl;
@@ -79,6 +82,13 @@ public class LsmParserService implements ParserService {
try {
MarketItem marketItem = processRssEntry(entry);
if (marketItem != null) {
try {
MarketItem.Analytics analytics = analyticsService.analyzeText(marketItem.getRawText());
marketItem.setAnalytics(analytics);
} catch (Exception e) {
logger.warn("Analytics step failed for LSM '{}': {}", marketItem.getTitle(),
e.getMessage());
}
MarketItem savedItem = saveOrUpdateMarketItem(marketItem);
if (savedItem != null) {
savedItems.add(savedItem);
@@ -0,0 +1,119 @@
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.util.HashMap;
import java.util.Map;
@Service
public class OllamaAnalyticsService {
private static final Logger logger = LoggerFactory.getLogger(OllamaAnalyticsService.class);
private final WebClient webClient;
@Value("${ollama.model:gemma3:1b}")
private String modelName;
public OllamaAnalyticsService(@Value("${ollama.host:http://185.35.223.45:11434}") String ollamaHost) {
this.webClient = WebClient.builder()
.baseUrl(ollamaHost)
.build();
}
public MarketItem.Analytics analyzeText(String text) {
MarketItem.Analytics analytics = new MarketItem.Analytics();
try {
String summary = generate(text,
"Напиши краткое саммари следующей новостной статьи на русском языке. Ответ должен содержать только саммари из 3-4 предложений, без лишних вступлений. Статья: ");
analytics.setSummary(summary);
} catch (Exception e) {
logger.warn("Failed to get summary from Ollama: {}", e.getMessage());
}
try {
String tagsCsv = generate(text,
"Извлеки 5-7 ключевых слов или тегов из текста новостной статьи. В ответе дай только список тегов через запятую, без нумерации и заголовков. Статья: ");
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 Ollama: {}", e.getMessage());
}
try {
String sentiment = generate(text,
"Определи тональность текста новостной статьи. В ответе дай только одно слово латиницей: positive, negative или neutral. Статья: ");
if (sentiment != null) {
sentiment = sentiment.trim().toLowerCase();
}
analytics.setSentiment(sentiment);
} catch (Exception e) {
logger.warn("Failed to get sentiment from Ollama: {}", e.getMessage());
}
try {
String entitiesJson = generate(text,
"Извлеки из текста имена людей, названия компаний и географические локации. В ответе дай только JSON объект следующей структуры: {\\\"persons\\\": [], \\\"companies\\\": [], \\\"locations\\\": []}. Статья: ");
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 Ollama: {}", e.getMessage());
}
return analytics;
}
private String generate(String text, String instructionPrefix) {
String prompt = instructionPrefix + text;
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model", modelName);
requestBody.put("prompt", prompt);
requestBody.put("stream", false);
try {
Map<String, Object> response = this.webClient.post()
.uri("/api/generate")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.bodyValue(requestBody)
.retrieve()
.bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
})
.onErrorResume(err -> {
logger.warn("Ollama request failed: {}", err.getMessage());
return Mono.empty();
})
.block();
if (response == null) {
return null;
}
Object res = response.get("response");
return res == null ? null : String.valueOf(res);
} catch (Exception e) {
logger.warn("Error calling Ollama generate: {}", e.getMessage());
return null;
}
}
}
@@ -32,6 +32,9 @@ public class RbcParserService implements ParserService {
@Autowired
private MarketItemRepository marketItemRepository;
@Autowired
private OllamaAnalyticsService analyticsService;
@Value("${rss.rbc.url}")
private String rssFeedUrl;
@@ -79,6 +82,13 @@ public class RbcParserService implements ParserService {
try {
MarketItem marketItem = processRssEntry(entry);
if (marketItem != null) {
try {
MarketItem.Analytics analytics = analyticsService.analyzeText(marketItem.getRawText());
marketItem.setAnalytics(analytics);
} catch (Exception e) {
logger.warn("Analytics step failed for RBC '{}': {}", marketItem.getTitle(),
e.getMessage());
}
MarketItem savedItem = saveOrUpdateMarketItem(marketItem);
if (savedItem != null) {
savedItems.add(savedItem);
@@ -32,6 +32,9 @@ public class VedomostiParserService implements ParserService {
@Autowired
private MarketItemRepository marketItemRepository;
@Autowired
private OllamaAnalyticsService analyticsService;
@Value("${rss.vedomosti.url}")
private String rssFeedUrl;
@@ -79,6 +82,13 @@ public class VedomostiParserService implements ParserService {
try {
MarketItem marketItem = processRssEntry(entry);
if (marketItem != null) {
try {
MarketItem.Analytics analytics = analyticsService.analyzeText(marketItem.getRawText());
marketItem.setAnalytics(analytics);
} catch (Exception e) {
logger.warn("Analytics step failed for Vedomosti '{}': {}", marketItem.getTitle(),
e.getMessage());
}
MarketItem savedItem = saveOrUpdateMarketItem(marketItem);
if (savedItem != null) {
savedItems.add(savedItem);
@@ -37,3 +37,8 @@ logging.level.kz.konturai.parser.service.VedomostiParserService=INFO
logging.level.org.springframework.scheduling=DEBUG
logging.level.org.springframework.data.mongodb=INFO
logging.level.com.mongodb=WARN
# Ollama AI analytics configuration
ollama.host=http://185.35.223.45:11434
ollama.model=gemma3:1b
logging.level.kz.konturai.parser.service.OllamaAnalyticsService=INFO