mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-17 11:19:15 +00:00
bug6095: minor refactoring in the com.sap.sailing.news bundle;
it may come in handy as a basis for placing AI-generated "news" in the event feed
This commit is contained in:
@@ -337,4 +337,8 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al
|
||||
id="com.sap.sailing.domain.queclinkadapter"
|
||||
version="0.0.0"/>
|
||||
|
||||
<plugin
|
||||
id="com.sap.sailing.aiagent"
|
||||
version="0.0.0"/>
|
||||
|
||||
</feature>
|
||||
|
||||
+5
-6
@@ -84,16 +84,15 @@ public class GetEventOverviewNewsAction implements SailingAction<ResultWithTTL<L
|
||||
@GwtIncompatible
|
||||
private List<NewsEntryDTO> getNews(SailingDispatchContext dispatchContext, Event event) {
|
||||
List<EventNewsItem> newsItems = dispatchContext.getEventNewsService().getNews(event);
|
||||
|
||||
if(this.limit > 0 && newsItems.size() > limit) {
|
||||
if (this.limit > 0 && newsItems.size() > limit) {
|
||||
newsItems = newsItems.subList(0, limit);
|
||||
}
|
||||
List<NewsEntryDTO> news = new ArrayList<>(newsItems.size());
|
||||
for(EventNewsItem newsItem: newsItems) {
|
||||
if(newsItem instanceof InfoEventNewsItem) {
|
||||
final List<NewsEntryDTO> news = new ArrayList<>(newsItems.size());
|
||||
for (EventNewsItem newsItem : newsItems) {
|
||||
if (newsItem instanceof InfoEventNewsItem) {
|
||||
news.add(new InfoNewsEntryDTO((InfoEventNewsItem) newsItem, dispatchContext.getClientLocale()));
|
||||
}
|
||||
if(newsItem instanceof LeaderboardUpdateNewsItem) {
|
||||
if (newsItem instanceof LeaderboardUpdateNewsItem) {
|
||||
news.add(new LeaderboardNewsEntryDTO((LeaderboardUpdateNewsItem) newsItem));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ public class Activator implements BundleActivator {
|
||||
EventNewsService newsService = new EventNewsServiceImpl(providerRegistry);
|
||||
context.registerService(EventNewsService.class, newsService, null);
|
||||
context.registerService(EventNewsProviderRegistry.class, providerRegistry, null);
|
||||
|
||||
// The json event news provider is only a fallback and should not be activated per default
|
||||
// providerRegistry.registerNewsProvider(new JsonEventNewsProvider());
|
||||
providerRegistry.registerNewsProvider(new LeaderboardUpdateEventNewsProvider());
|
||||
|
||||
@@ -9,8 +9,4 @@ public interface EventNewsProvider {
|
||||
Collection<? extends EventNewsItem> getNews(Event event);
|
||||
|
||||
Collection<? extends EventNewsItem> getNews(Event event, Date startingFrom);
|
||||
|
||||
boolean hasNews(Event event, Date startingFrom);
|
||||
|
||||
boolean hasNews(Event event);
|
||||
}
|
||||
|
||||
@@ -4,16 +4,18 @@ import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
/**
|
||||
* An interface for a generic news item
|
||||
* @author Frank
|
||||
* An interface for a generic news item. The natural ordering, implementing the {@link Comparable} interface,
|
||||
* is defined by the {@link #getCreatedAtDate() creation time point}.
|
||||
*
|
||||
* @author Frank Mittag
|
||||
*
|
||||
*/
|
||||
public interface NewsItem extends Comparable<NewsItem> {
|
||||
UUID getId();
|
||||
|
||||
String getCategory();
|
||||
|
||||
String getTitle();
|
||||
|
||||
String getMessage();
|
||||
@@ -21,4 +23,10 @@ public interface NewsItem extends Comparable<NewsItem> {
|
||||
URL getRelatedItemLink();
|
||||
|
||||
Date getCreatedAtDate();
|
||||
|
||||
@Override
|
||||
default int compareTo(NewsItem o) {
|
||||
final Date otherCreatedAtDate = o.getCreatedAtDate();
|
||||
return -Util.compareToWithNull(getCreatedAtDate(), otherCreatedAtDate, /* nullIsLess */ true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,16 +9,11 @@ import com.sap.sailing.news.EventNewsItem;
|
||||
public abstract class AbstractEventNewsItem extends AbstractNewsItem implements EventNewsItem {
|
||||
private UUID eventId;
|
||||
|
||||
public AbstractEventNewsItem(UUID eventId, String title, String message, Date createdAtDate, String category, URL relatedItemLink) {
|
||||
super(title, message, createdAtDate, category, relatedItemLink);
|
||||
protected AbstractEventNewsItem(UUID eventId, String title, String message, Date createdAtDate, URL relatedItemLink) {
|
||||
super(title, message, createdAtDate, relatedItemLink);
|
||||
this.eventId = eventId;
|
||||
}
|
||||
|
||||
public AbstractEventNewsItem(UUID eventId, String title, String message, Date createdAtDate, String category) {
|
||||
super(title, message, createdAtDate, category);
|
||||
this.eventId = eventId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getEventUUID() {
|
||||
return eventId;
|
||||
|
||||
@@ -6,11 +6,9 @@ import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.news.NewsItem;
|
||||
|
||||
public class AbstractNewsItem implements NewsItem {
|
||||
public abstract class AbstractNewsItem implements NewsItem {
|
||||
private final UUID id;
|
||||
|
||||
private String category;
|
||||
|
||||
private String title;
|
||||
|
||||
private String message;
|
||||
@@ -19,55 +17,36 @@ public class AbstractNewsItem implements NewsItem {
|
||||
|
||||
private Date createdAtDate;
|
||||
|
||||
public AbstractNewsItem(String title, String message, Date createdAtDate, String category) {
|
||||
this(title, message, createdAtDate, category, null);
|
||||
}
|
||||
|
||||
public AbstractNewsItem(String title, String message, Date createdAtDate, String category, URL relatedItemLink) {
|
||||
protected AbstractNewsItem(String title, String message, Date createdAtDate, URL relatedItemLink) {
|
||||
this.title = title;
|
||||
this.message = message;
|
||||
this.category = category;
|
||||
this.createdAtDate = createdAtDate;
|
||||
this.relatedItemLink = relatedItemLink;
|
||||
this.id = UUID.randomUUID();
|
||||
}
|
||||
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getRelatedItemLink() {
|
||||
return relatedItemLink;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreatedAtDate() {
|
||||
return createdAtDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(NewsItem o) {
|
||||
Date otherCreatedAtDate = o.getCreatedAtDate();
|
||||
if(createdAtDate == otherCreatedAtDate) {
|
||||
return 0;
|
||||
}
|
||||
if(createdAtDate == null) {
|
||||
return 1;
|
||||
}
|
||||
if(otherCreatedAtDate == null) {
|
||||
return -1;
|
||||
}
|
||||
return -createdAtDate.compareTo(otherCreatedAtDate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.sap.sailing.news.EventNewsProviderRegistry;
|
||||
import com.sap.sailing.news.EventNewsService;
|
||||
|
||||
public class EventNewsServiceImpl implements EventNewsService {
|
||||
private final static int LIMIT = 25;
|
||||
private final EventNewsProviderRegistry providerRegistry;
|
||||
|
||||
public EventNewsServiceImpl(EventNewsProviderRegistry providerRegistry) {
|
||||
@@ -21,13 +22,13 @@ public class EventNewsServiceImpl implements EventNewsService {
|
||||
|
||||
@Override
|
||||
public List<EventNewsItem> getNews(Event event) {
|
||||
List<EventNewsItem> result = new ArrayList<>();
|
||||
for(EventNewsProvider provider: providerRegistry.getEventNewsProvider()) {
|
||||
final List<EventNewsItem> result = new ArrayList<>();
|
||||
for (EventNewsProvider provider : providerRegistry.getEventNewsProvider()) {
|
||||
Collection<? extends EventNewsItem> news = provider.getNews(event);
|
||||
result.addAll(news);
|
||||
}
|
||||
Collections.sort(result);
|
||||
if(result.size() <= 25) {
|
||||
if (result.size() <= 25) {
|
||||
return result;
|
||||
}
|
||||
return result.subList(0, 25);
|
||||
@@ -40,11 +41,8 @@ public class EventNewsServiceImpl implements EventNewsService {
|
||||
Collection<? extends EventNewsItem> news = provider.getNews(event, startingFrom);
|
||||
result.addAll(news);
|
||||
}
|
||||
Collections.sort(result);
|
||||
if(result.size() <= 25) {
|
||||
return result;
|
||||
}
|
||||
return result.subList(0, 25);
|
||||
Collections.sort(result); // sorts by the NewsItem natural order, based on creation date
|
||||
return result.subList(0, Math.min(result.size(), LIMIT));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,9 +10,9 @@ public class InfoEventNewsItem extends AbstractEventNewsItem {
|
||||
private Map<Locale, String> titles;
|
||||
private Map<Locale, String> messages;
|
||||
|
||||
public InfoEventNewsItem(UUID eventId, String title, String message, Date createdAtDate, String category,
|
||||
URL relatedItemLink, Map<Locale, String> titles, Map<Locale, String> messages) {
|
||||
super(eventId, title, message, createdAtDate, category, relatedItemLink);
|
||||
public InfoEventNewsItem(UUID eventId, String title, String message, Date createdAtDate, URL relatedItemLink,
|
||||
Map<Locale, String> titles, Map<Locale, String> messages) {
|
||||
super(eventId, title, message, createdAtDate, relatedItemLink);
|
||||
this.titles = titles;
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public class JsonEventNewsProvider implements EventNewsProvider {
|
||||
Map<Locale, String> messages = readI18nText(eventAsJson, "messages");
|
||||
String newsURL = (String) eventAsJson.get("url");
|
||||
UUID eventId = UUID.fromString(eventIdAsString);
|
||||
InfoEventNewsItem newsItem = new InfoEventNewsItem(eventId, title, message, new Date(timestamp.longValue()), null, newsURL == null ? null : new URL(newsURL), titles, messages);
|
||||
InfoEventNewsItem newsItem = new InfoEventNewsItem(eventId, title, message, new Date(timestamp.longValue()), newsURL == null ? null : new URL(newsURL), titles, messages);
|
||||
newNews.add(newsItem);
|
||||
}
|
||||
news = newNews;
|
||||
@@ -128,15 +128,4 @@ public class JsonEventNewsProvider implements EventNewsProvider {
|
||||
public Collection<? extends EventNewsItem> getNews(Event event, Date startingFrom) {
|
||||
return getNews(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNews(Event event, Date startingFrom) {
|
||||
return news.size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNews(Event event) {
|
||||
return news.size() > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+23
-45
@@ -8,78 +8,56 @@ import java.util.List;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.EventBase;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.SettableScoreCorrection;
|
||||
import com.sap.sailing.domain.leaderboard.ScoreCorrection;
|
||||
import com.sap.sailing.news.EventNewsItem;
|
||||
import com.sap.sailing.news.EventNewsProvider;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
/**
|
||||
* An event news provider looking at leaderboard updates triggered by changes of timePointOfLatestModification
|
||||
* @author Frank
|
||||
* An event news provider looking at leaderboard updates triggered by changes of timePointOfLatestModification
|
||||
*
|
||||
* @author Frank Mittag
|
||||
*
|
||||
*/
|
||||
public class LeaderboardUpdateEventNewsProvider implements EventNewsProvider {
|
||||
|
||||
private final static int LIMIT = 10;
|
||||
|
||||
@Override
|
||||
public Collection<? extends EventNewsItem> getNews(Event event) {
|
||||
List<LeaderboardUpdateNewsItem> result = new LinkedList<>();
|
||||
Iterable<LeaderboardGroup> leaderboardGroups = event.getLeaderboardGroups();
|
||||
final List<LeaderboardUpdateNewsItem> result = new LinkedList<>();
|
||||
final Iterable<LeaderboardGroup> leaderboardGroups = event.getLeaderboardGroups();
|
||||
for (LeaderboardGroup leaderboardGroup : leaderboardGroups) {
|
||||
for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
|
||||
if (!isPartOfEvent(event, leaderboard)) {
|
||||
continue;
|
||||
}
|
||||
SettableScoreCorrection scoreCorrection = leaderboard.getScoreCorrection();
|
||||
if (scoreCorrection != null) {
|
||||
TimePoint timePointOfLatestModification = scoreCorrection.getTimePointOfLastCorrectionsValidity();
|
||||
if (timePointOfLatestModification != null) {
|
||||
String displayName = leaderboard.getDisplayName() != null ? leaderboard.getDisplayName()
|
||||
: leaderboard.getName();
|
||||
String boatClassName = null;
|
||||
if (leaderboard instanceof RegattaLeaderboard) {
|
||||
BoatClass boatClass = ((RegattaLeaderboard) leaderboard).getRegatta().getBoatClass();
|
||||
if (boatClass != null) {
|
||||
boatClassName = boatClass.getName();
|
||||
if (leaderboard.isPartOfEvent(event)) {
|
||||
final ScoreCorrection scoreCorrection = leaderboard.getScoreCorrection();
|
||||
if (scoreCorrection != null) {
|
||||
final TimePoint timePointOfLatestModification = scoreCorrection.getTimePointOfLastCorrectionsValidity();
|
||||
if (timePointOfLatestModification != null) {
|
||||
String displayName = leaderboard.getDisplayName() != null ? leaderboard.getDisplayName()
|
||||
: leaderboard.getName();
|
||||
String boatClassName = null;
|
||||
if (leaderboard instanceof RegattaLeaderboard) {
|
||||
final BoatClass boatClass = ((RegattaLeaderboard) leaderboard).getRegatta().getBoatClass();
|
||||
if (boatClass != null) {
|
||||
boatClassName = boatClass.getName();
|
||||
}
|
||||
}
|
||||
result.add(new LeaderboardUpdateNewsItem(event.getId(), timePointOfLatestModification.asDate(), leaderboard.getName(), displayName, boatClassName));
|
||||
}
|
||||
result.add(new LeaderboardUpdateNewsItem(event.getId(), timePointOfLatestModification.asDate(), leaderboard.getName(), displayName, boatClassName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(result);
|
||||
if (result.size() <= 10) {
|
||||
return result;
|
||||
}
|
||||
return result.subList(0, 11);
|
||||
return result.subList(0, Math.min(LIMIT, result.size()));
|
||||
}
|
||||
|
||||
// TODO duplicate code taken from HomeServiceUtil
|
||||
private boolean isPartOfEvent(EventBase event, Leaderboard regattaEntity) {
|
||||
return Util.isEmpty(regattaEntity.getCourseAreas())
|
||||
|| Util.containsAny(event.getVenue().getCourseAreas(), regattaEntity.getCourseAreas());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends EventNewsItem> getNews(Event event, Date startingFrom) {
|
||||
// TODO correct implementation
|
||||
return getNews(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNews(Event event, Date startingFrom) {
|
||||
// TODO correct implementation
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNews(Event event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ public class LeaderboardUpdateNewsItem extends AbstractEventNewsItem {
|
||||
private String boatClass;
|
||||
|
||||
public LeaderboardUpdateNewsItem(UUID eventId, Date updateDate, String leaderboardName, String leaderboardDisplayName, String boatClass) {
|
||||
super(eventId, leaderboardDisplayName, null, updateDate, null, null);
|
||||
super(eventId, leaderboardDisplayName, /* message */ null, updateDate, /* relatedItemLink */ null);
|
||||
this.leaderboardName = leaderboardName;
|
||||
this.boatClass = boatClass;
|
||||
}
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ public class TestWithSecretCredentials {
|
||||
|
||||
@Before
|
||||
public void setUp() throws MalformedURLException, ParseException {
|
||||
final String credentialsJsonString = System.getProperty("sap.aicore.credentials");
|
||||
final String credentialsJsonString = System.getProperty(AICore.CREDENTIALS_SYSTEM_PROPERTY_NAME);
|
||||
credentials = CredentialsParser.create().parse(credentialsJsonString);
|
||||
aiCore = AICore.create(credentials);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.sap.sse.aicore;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -27,7 +28,7 @@ import com.sap.sse.common.Util;
|
||||
*
|
||||
* Example:
|
||||
* <pre>
|
||||
* final AICore aiCore = AICore.create(CredentialsParser.create().parse(System.getProperty("sap.ai.core.credentials")));
|
||||
* final AICore aiCore = AICore.create(CredentialsParser.create().parse(System.getProperty(CREDENTIALS_SYSTEM_PROPERTY_NAME)));
|
||||
* final ChatSession chatSession = aiCore.createChatSession("gpt-4o-mini").get();
|
||||
* final String response = chatSession
|
||||
* .addSystemPrompt("You are a teacher.")
|
||||
@@ -39,6 +40,22 @@ import com.sap.sse.common.Util;
|
||||
*
|
||||
*/
|
||||
public interface AICore {
|
||||
/**
|
||||
* Name of the system property in which we look for default credentials that will be used by the
|
||||
* {@link #getDefault} method to obtain valid credentials.
|
||||
*/
|
||||
String CREDENTIALS_SYSTEM_PROPERTY_NAME = "sap.aicore.credentials";
|
||||
|
||||
/**
|
||||
* Produces a default {@link AICore} instance using credentials from the system property whose name
|
||||
* is specified by {@link #CREDENTIALS_SYSTEM_PROPERTY_NAME}. If that property is not set, {@code null}
|
||||
* is returned.
|
||||
*/
|
||||
static AICore getDefault() throws MalformedURLException, ParseException {
|
||||
final String systemProperty = System.getProperty(CREDENTIALS_SYSTEM_PROPERTY_NAME);
|
||||
return systemProperty == null ? null : AICore.create(CredentialsParser.create().parse(systemProperty));
|
||||
}
|
||||
|
||||
static AICore create(final Credentials credentials) {
|
||||
return new AICoreImpl(credentials);
|
||||
}
|
||||
|
||||
@@ -163,6 +163,7 @@
|
||||
<module>com.sap.sailing.domain.swisstimingadapter</module>
|
||||
<module>com.sap.sailing.domain.swisstimingadapter.persistence</module>
|
||||
<module>com.sap.sailing.domain.swisstimingreplayadapter</module>
|
||||
<module>com.sap.sailing.aiagent</module>
|
||||
<module>com.sap.sailing.news</module>
|
||||
<module>com.sap.sailing.declination</module>
|
||||
<module>com.sap.sailing.udpconnector</module>
|
||||
|
||||
Reference in New Issue
Block a user