diff --git a/src/main/java/com/severalcircles/flames/StringUtil.java b/src/main/java/com/severalcircles/flames/StringUtil.java index 6251d54a..602d9c16 100644 --- a/src/main/java/com/severalcircles/flames/StringUtil.java +++ b/src/main/java/com/severalcircles/flames/StringUtil.java @@ -5,10 +5,22 @@ package com.severalcircles.flames; import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.Locale; public class StringUtil { public static String formatScore(double score) { DecimalFormat formatter = new DecimalFormat("#,###"); return String.format("%s fp", formatter.format(score)); } + public static String prettyDate(Instant instant, Locale locale) { + SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/YYYY", locale); + return formatter.format(new Date(instant.toEpochMilli())); + } } diff --git a/src/main/java/com/severalcircles/flames/conversations/Analysis.java b/src/main/java/com/severalcircles/flames/conversations/Analysis.java index 8d94342f..f721dec5 100644 --- a/src/main/java/com/severalcircles/flames/conversations/Analysis.java +++ b/src/main/java/com/severalcircles/flames/conversations/Analysis.java @@ -5,11 +5,14 @@ package com.severalcircles.flames.conversations; import com.google.cloud.language.v1.Document; +import com.google.cloud.language.v1.Entity; import com.google.cloud.language.v1.LanguageServiceClient; import com.google.cloud.language.v1.Sentiment; import com.severalcircles.flames.Flames; import java.io.IOException; +import java.util.LinkedList; +import java.util.List; public class Analysis { public static Sentiment analyze(String text) { @@ -23,4 +26,19 @@ public static Sentiment analyze(String text) { throw new RuntimeException(e); } } + public static List analyzeEntities(String text) { + try (LanguageServiceClient language = LanguageServiceClient.create()) { + Document doc = Document.newBuilder(). + setContent(text).setType(Document.Type.PLAIN_TEXT).build(); + List entities = language.analyzeEntities(doc).getEntitiesList(); + List finalEntities = new LinkedList<>(); + entities.forEach(entity -> { + Flames.getFlogger().finest("Entity: \n" + entity.getName()); + finalEntities.add(entity.getName()); + }); + return finalEntities; + } catch (IOException e) { + throw new RuntimeException(e); + } + } } diff --git a/src/main/java/com/severalcircles/flames/conversations/Conversation.java b/src/main/java/com/severalcircles/flames/conversations/Conversation.java index e5b2a9b8..5a9f137e 100644 --- a/src/main/java/com/severalcircles/flames/conversations/Conversation.java +++ b/src/main/java/com/severalcircles/flames/conversations/Conversation.java @@ -11,12 +11,13 @@ import java.time.Instant; import java.util.HashMap; +import java.util.List; import java.util.Map; public class Conversation { private double emotion; private double score; - private final Map topics; + private final Map topics; private final Map participationMap; private final Instant started; private Instant expires; @@ -51,17 +52,20 @@ public void addScore(double score) { this.score += score; } - public Map getTopics() { + public Map getTopics() { return topics; } - public void addTopic(ConversationEntity topic) { + public void addTopic(String topic) { if (topics.containsKey(topic)) { topics.put(topic, topics.get(topic) + 1); } else { topics.put(topic, 1); } } + public void addTopics(List topics) { + topics.forEach(this::addTopic); + } public Map getParticipationMap() { return participationMap; diff --git a/src/main/java/com/severalcircles/flames/conversations/ConversationEntity.java b/src/main/java/com/severalcircles/flames/conversations/ConversationEntity.java deleted file mode 100644 index 66b8d698..00000000 --- a/src/main/java/com/severalcircles/flames/conversations/ConversationEntity.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2023 Several Circles - */ - -package com.severalcircles.flames.conversations; - -public record ConversationEntity( - String name, - String description -) { -} diff --git a/src/main/java/com/severalcircles/flames/conversations/today/Today.java b/src/main/java/com/severalcircles/flames/conversations/today/Today.java new file mode 100644 index 00000000..0b038d18 --- /dev/null +++ b/src/main/java/com/severalcircles/flames/conversations/today/Today.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2023 Several Circles + */ + +package com.severalcircles.flames.conversations.today; + +import com.severalcircles.flames.data.user.FlamesQuote; +import com.severalcircles.flames.data.user.FlamesUser; +import com.severalcircles.flames.system.manager.secondary.UserDataManager; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Today is a class that stores data about the current day. Today, we're talking about Flames, and we're feeling a certain way. + * @author Several Circles + * @version 8 + * @since 4.4 + */ +public class Today { + static Map topics = new HashMap<>(); + static FlamesQuote quote = new FlamesQuote("No quote found", UserDataManager.flames()); + static double quoteScore = 0; + static double emotion = 0; + static FlamesUser highUser = UserDataManager.flames(); + static { + int msToMidnight = (int) (Instant.now().until(Instant.now().plusSeconds(60 * 60 * 24).truncatedTo(ChronoUnit.DAYS), ChronoUnit.SECONDS) * 1000); + Timer timer = new Timer(); + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + topics.clear(); + quote = new FlamesQuote("No quote found", UserDataManager.flames()); + quoteScore = 0; + emotion = 0; + highUser = UserDataManager.flames(); + } + }, msToMidnight, 1000 * 60 * 60 * 24); + } + public static void addTopic(String topic) { + if (topics.containsKey(topic)) { + topics.put(topic, topics.get(topic) + 1); + } else { + topics.put(topic, 1); + } + } + public static void checkQuote(FlamesQuote quote, double score) { + if (score > quoteScore) { + Today.quote = quote; + quoteScore = score; + } + } + public static void addEmotion(double emotion) { + Today.emotion += emotion; + } + public static void checkUser(FlamesUser user) { + if (user.getScore() > highUser.getScore()) { + highUser = user; + } + } + public static String getTopTopic() { + AtomicReference max = new AtomicReference<>(0); + AtomicReference toptopic = new AtomicReference<>(""); + topics.forEach((topic, count) -> { + if (count > max.get()) { + max.set(count); + toptopic.set(topic); + } + }); + return toptopic.get(); + } + + public static double getEmotion() { + return emotion; + } + + public static Map getTopics() { + return topics; + } + + public static FlamesQuote getQuote() { + return quote; + } + + public static double getQuoteScore() { + return quoteScore; + } + + public static FlamesUser getHighUser() { + return highUser; + } +} diff --git a/src/main/java/com/severalcircles/flames/frontend/FlamesEmbed.java b/src/main/java/com/severalcircles/flames/frontend/FlamesEmbed.java index 009e9900..7a95e25d 100644 --- a/src/main/java/com/severalcircles/flames/frontend/FlamesEmbed.java +++ b/src/main/java/com/severalcircles/flames/frontend/FlamesEmbed.java @@ -20,8 +20,10 @@ @ExceptionID("700") public abstract class FlamesEmbed { ResourceBundle local; + Locale locale; public FlamesEmbed(Locale locale) { local = ResourceBundle.getBundle("strings/" + this.getClass().getAnnotation(Embed.class).name(), locale); + this.locale = locale; } public abstract MessageEmbed get(); } diff --git a/src/main/java/com/severalcircles/flames/frontend/TodayEmbed.java b/src/main/java/com/severalcircles/flames/frontend/TodayEmbed.java new file mode 100644 index 00000000..9f5d76d1 --- /dev/null +++ b/src/main/java/com/severalcircles/flames/frontend/TodayEmbed.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Several Circles + */ + +package com.severalcircles.flames.frontend; + +import com.severalcircles.flames.Flames; +import com.severalcircles.flames.StringUtil; +import com.severalcircles.flames.conversations.today.Today; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageEmbed; + +import java.time.Instant; +import java.util.Locale; + +@Embed(name = "Today") +public class TodayEmbed extends FlamesEmbed{ + + public TodayEmbed(Locale locale) { + super(locale); + } + + @Override + public MessageEmbed get() { + MessageEmbed embed = new EmbedBuilder() + .setAuthor(String.format(local.getString("author"), StringUtil.prettyDate(Instant.now(), locale)), null, Flames.getApi().getSelfUser().getAvatarUrl()) + .setTitle(local.getString("title")) + .addField(local.getString("talkingAbout"), Today.getTopTopic(), true) + .addField(local.getString("feeling"), String.valueOf(Today.getEmotion()), true) + .addField(local.getString("highUser"), Today.getHighUser().getDiscordUser().getName() + " (" + Today.getHighUser().getScore() + ")", true) + .addBlankField(false) + .addField("\"" + Today.getQuote().message() + "\"", "-" + Today.getQuote().user().getDiscordUser().getName(), false) + .addBlankField(false) + .addField(local.getString("closer.title"), local.getString("closer.text"), false) + .setColor(0x00ff00) + .build(); + return embed; + } +} diff --git a/src/main/java/com/severalcircles/flames/interactions/slash/CaptionThisCommand.java b/src/main/java/com/severalcircles/flames/interactions/slash/CaptionThisCommand.java index accfa65d..faeb79d4 100644 --- a/src/main/java/com/severalcircles/flames/interactions/slash/CaptionThisCommand.java +++ b/src/main/java/com/severalcircles/flames/interactions/slash/CaptionThisCommand.java @@ -30,7 +30,7 @@ public void execute(SlashCommandInteraction interaction, FlamesUser user) { } // AtomicReference i = new AtomicReference<>(0); AtomicReference tp = new AtomicReference<>(""); - tp.set(conversation.getTopics().keySet().stream().toList().get(new Random().nextInt(conversation.getTopics().keySet().size())).name().substring(0, Math.min(conversation.getTopics().keySet().size(), 256))); + tp.set(conversation.getTopics().keySet().stream().toList().get(new Random().nextInt(conversation.getTopics().keySet().size())).substring(0, Math.min(conversation.getTopics().keySet().size(), 256))); List urls = Tenor.extractUrls(Objects.requireNonNull(Tenor.getSearchResults(tp.get().replace(" ", "%20"), 10)).toString()); String url = urls.get(new Random().nextInt(urls.size())); int attempts = 1; diff --git a/src/main/java/com/severalcircles/flames/interactions/slash/TodayCommand.java b/src/main/java/com/severalcircles/flames/interactions/slash/TodayCommand.java new file mode 100644 index 00000000..6f15c302 --- /dev/null +++ b/src/main/java/com/severalcircles/flames/interactions/slash/TodayCommand.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Several Circles + */ + +package com.severalcircles.flames.interactions.slash; + +import com.severalcircles.flames.data.user.FlamesUser; +import com.severalcircles.flames.frontend.TodayEmbed; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +@FlamesCommand(name = "today", description = "Find out what today is all about") +public class TodayCommand extends FlamesSlashCommand{ + @Override + public void execute(SlashCommandInteraction interaction, FlamesUser user) { + interaction.replyEmbeds(new TodayEmbed(user.getLocale()).get()).queue(); + } +} diff --git a/src/main/java/com/severalcircles/flames/system/manager/primary/FlamesInteractionManager.java b/src/main/java/com/severalcircles/flames/system/manager/primary/FlamesInteractionManager.java index eac033a6..554830b0 100644 --- a/src/main/java/com/severalcircles/flames/system/manager/primary/FlamesInteractionManager.java +++ b/src/main/java/com/severalcircles/flames/system/manager/primary/FlamesInteractionManager.java @@ -39,6 +39,7 @@ public void prepare() { commandInteractionList.add(new QuestionCommand()); commandInteractionList.add(new HiCommand()); commandInteractionList.add(new MyDataCommand()); + commandInteractionList.add(new TodayCommand()); commandInteractionList.forEach(command -> { SlashCommandData data = Commands.slash(command.getClass().getAnnotation(FlamesCommand.class).name(), command.getClass().getAnnotation(FlamesCommand.class).description()); for (FlamesCommandOption option : command.getClass().getAnnotation(FlamesCommand.class).options()) { diff --git a/src/main/java/com/severalcircles/flames/system/manager/secondary/ConversationManager.java b/src/main/java/com/severalcircles/flames/system/manager/secondary/ConversationManager.java index bc46bb8c..8d899bfb 100644 --- a/src/main/java/com/severalcircles/flames/system/manager/secondary/ConversationManager.java +++ b/src/main/java/com/severalcircles/flames/system/manager/secondary/ConversationManager.java @@ -9,7 +9,6 @@ import com.severalcircles.flames.conversations.Analysis; import com.severalcircles.flames.conversations.AnalysisScore; import com.severalcircles.flames.conversations.Conversation; -import com.severalcircles.flames.conversations.ConversationEntity; import com.severalcircles.flames.data.FlamesData; import com.severalcircles.flames.data.user.FlamesQuote; import com.severalcircles.flames.data.user.FlamesUser; @@ -64,7 +63,7 @@ public static void processMessage(MessageChannelUnion channel, Message message, conversation.addParticipation(user); conversation.addEmotion(score.get().emotion()); conversation.addScore(score.get().score()); - conversation.addTopic(new ConversationEntity(message.getContentRaw(), message.getAuthor().getId())); + conversation.addTopics(Analysis.analyzeEntities(message.getContentRaw())); Flames.getFlogger().finest("Conversation: " + conversation); Flames.getFlogger().finest("Conversation topics: \n" + conversation.getTopics()); Flames.getFlogger().finest("Conversation participation: \n" + conversation.getParticipationMap()); diff --git a/src/main/resources/strings/Today.properties b/src/main/resources/strings/Today.properties new file mode 100644 index 00000000..97546743 --- /dev/null +++ b/src/main/resources/strings/Today.properties @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023 Several Circles +# +author=Here's what %s is all about. +closer.text=What will tomorrow bring? +closer.title=...and that's what Today is all about. +feeling=We're feeling +highUser=The highest scoring user is +talkingAbout=We're talking about +title=Today... \ No newline at end of file diff --git a/src/main/resources/strings/Today_en.properties b/src/main/resources/strings/Today_en.properties new file mode 100644 index 00000000..4bd5a41e --- /dev/null +++ b/src/main/resources/strings/Today_en.properties @@ -0,0 +1,11 @@ +# +# Copyright (c) 2023 Several Circles +# + +author=Here's what %s is all about. +closer.text=What will tomorrow bring? +closer.title=...and that's what Today is all about. +feeling=We're feeling +highUser=The highest scoring user is +talkingAbout=We're talking about +title=Today... \ No newline at end of file diff --git a/src/main/resources/strings/Today_es.properties b/src/main/resources/strings/Today_es.properties new file mode 100644 index 00000000..fecc8a09 --- /dev/null +++ b/src/main/resources/strings/Today_es.properties @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023 Several Circles +# +author=Aqui esta que trata el %s. +closer.text=¿Qué traerá el mañana? +closer.title=...y de eso se trata hoy. +feeling=Estamos sentimiento +highUser=El usario con la puntuacion mas alta es +talkingAbout=Estamos hablando de +title=Hoy mismo...