+ Added formattable benchmark for returns and adjusted to vaguely fuzzy-search
This commit is contained in:
@@ -2,6 +2,7 @@ package commands;
|
||||
|
||||
import core.Command;
|
||||
import core.LocStrings;
|
||||
import core.benchmark.BenchmarkFormattable;
|
||||
import core.benchmark.BenchmarkFramework;
|
||||
import dataStructures.KittyChannel;
|
||||
import dataStructures.KittyGuild;
|
||||
@@ -36,18 +37,18 @@ public class CommandBenchmark extends Command
|
||||
return;
|
||||
}
|
||||
|
||||
String result = null;
|
||||
BenchmarkFormattable commandOutput = null;
|
||||
synchronized(framework)
|
||||
{
|
||||
result = framework.Run(input.args.trim());
|
||||
commandOutput = framework.Run(input.args.trim());
|
||||
}
|
||||
|
||||
if(result == null)
|
||||
if(commandOutput == null)
|
||||
{
|
||||
res.Call(LocStrings.Stub("BenchmarkInvalid"));
|
||||
return;
|
||||
}
|
||||
|
||||
res.Call(result);
|
||||
commandOutput.Call(res);
|
||||
}
|
||||
}
|
||||
@@ -4,19 +4,20 @@ import java.util.List;
|
||||
|
||||
import core.benchmark.BenchmarkCommand;
|
||||
import core.benchmark.BenchmarkEntry;
|
||||
import core.benchmark.BenchmarkFormattable;
|
||||
import core.benchmark.BenchmarkInput;
|
||||
import core.benchmark.BenchmarkManager;
|
||||
|
||||
public class BenchmarkCommandCompare extends BenchmarkCommand
|
||||
{
|
||||
public String OnRun(BenchmarkManager manager, BenchmarkInput input)
|
||||
public BenchmarkFormattable OnRun(BenchmarkManager manager, BenchmarkInput input)
|
||||
{
|
||||
final String lineDelimiter = "\n";
|
||||
String output = "";
|
||||
String[] inputSplit = input.value.trim().split("\\s+");
|
||||
|
||||
if(inputSplit.length < 2)
|
||||
return "You must to specify 2 models to compare!";
|
||||
return new BenchmarkFormattable("You must to specify 2 models to compare!");
|
||||
|
||||
for(int i = 0; i < inputSplit.length; ++i)
|
||||
{
|
||||
@@ -38,6 +39,6 @@ public class BenchmarkCommandCompare extends BenchmarkCommand
|
||||
output += "----------";
|
||||
}
|
||||
|
||||
return output;
|
||||
return new BenchmarkFormattable(output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ import core.benchmark.*;
|
||||
|
||||
public class BenchmarkCommandFind extends BenchmarkCommand
|
||||
{
|
||||
private final char lineDelimiter = '\n';
|
||||
private final String lineDelimiter = "\n";
|
||||
private final int listMax = 30;
|
||||
|
||||
public String OnRun(BenchmarkManager manager, BenchmarkInput input)
|
||||
public BenchmarkFormattable OnRun(BenchmarkManager manager, BenchmarkInput input)
|
||||
{
|
||||
String output = "";
|
||||
String searchString = input.value.trim();
|
||||
@@ -42,6 +42,6 @@ public class BenchmarkCommandFind extends BenchmarkCommand
|
||||
output = "Couldn't find any models matching the search `" + searchString + "`!";
|
||||
}
|
||||
|
||||
return output;
|
||||
return new BenchmarkFormattable(output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,11 @@ import java.util.List;
|
||||
|
||||
import core.benchmark.BenchmarkCommand;
|
||||
import core.benchmark.BenchmarkEntry;
|
||||
import core.benchmark.BenchmarkFormattable;
|
||||
import core.benchmark.BenchmarkInput;
|
||||
import core.benchmark.BenchmarkManager;
|
||||
import dataStructures.KittyEmbed;
|
||||
import java.awt.Color;
|
||||
|
||||
public class BenchmarkCommandInfo extends BenchmarkCommand
|
||||
{
|
||||
@@ -21,26 +24,75 @@ public class BenchmarkCommandInfo extends BenchmarkCommand
|
||||
return output;
|
||||
}
|
||||
|
||||
public static KittyEmbed FormatInfoEmbed(BenchmarkEntry entry)
|
||||
{
|
||||
// Populate general embed info
|
||||
KittyEmbed embed = new KittyEmbed();
|
||||
|
||||
embed.title = "" + entry.brand + " " + entry.model + "" + lineDelimiter;
|
||||
embed.authorLink = entry.url;
|
||||
embed.authorImage = "https://kittybot.net/assets/generic/baseline_assessment_black_48dp.png";
|
||||
embed.authorText = "[view online]";
|
||||
embed.color = Color.LIGHT_GRAY;
|
||||
embed.descriptionText = "Average Bench: " + entry.benchmark + "%";
|
||||
|
||||
// Brand coloring
|
||||
String brandClean = entry.brand.toLowerCase().trim();
|
||||
|
||||
if(brandClean.contains("intel"))
|
||||
embed.color = Color.getHSBColor((float) (205.0/360), 1.00f, 0.75f);
|
||||
else if(brandClean.contains("amd"))
|
||||
embed.color = Color.getHSBColor((float) (357.0/360), 0.88f, 0.92f);
|
||||
else if (brandClean.contains("nvidia"))
|
||||
embed.color = Color.getHSBColor((float) (081.0/360), 1.00f, 0.72f);
|
||||
|
||||
// Add relative performance numbers
|
||||
switch(entry.type)
|
||||
{
|
||||
case CPU:
|
||||
embed.footerText = "(100% ~ Intel i7-7700k)";
|
||||
break;
|
||||
case GPU:
|
||||
embed.footerText = "(100% ~ Nvidia GTX 1070)";
|
||||
break;
|
||||
case SSD:
|
||||
embed.footerText = "(100% ~ Samsung 850 Pro)";
|
||||
break;
|
||||
case HDD:
|
||||
embed.footerText = "(100% ~ Seagate Baracuda 3TB (2016))";
|
||||
break;
|
||||
case RAM:
|
||||
embed.footerText = "(100% ~ Corsair Vengence LPX 2666 C15 4x8GB w/ Intel Skylake)";
|
||||
break;
|
||||
case USB:
|
||||
embed.footerText = "(100% ~ Sandisk Extreme 64GB)";
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
return embed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String OnRun(BenchmarkManager manager, BenchmarkInput input)
|
||||
public BenchmarkFormattable OnRun(BenchmarkManager manager, BenchmarkInput input)
|
||||
{
|
||||
String searchString = input.value.trim();
|
||||
|
||||
String output = "";
|
||||
output += lineDelimiter;
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
List<BenchmarkEntry> entries = manager.FindModel(searchString);
|
||||
|
||||
if(entries.size() < 1)
|
||||
output += "Couldn't find any models containing `" + searchString + "`!";
|
||||
return new BenchmarkFormattable("Couldn't find any models containing `" + searchString + "`!");
|
||||
|
||||
output += FormatInfo(entries.get(0));
|
||||
output += lineDelimiter;
|
||||
List<BenchmarkEntry> sortedEntries = manager.EvaluateLevenshteinDistance(entries, searchString);
|
||||
BenchmarkEntry entry = sortedEntries.get(0);
|
||||
KittyEmbed embed = FormatInfoEmbed(entry);
|
||||
|
||||
if(entries.size() > 1)
|
||||
output += "_chose " + entries.get(0).model + " from " + entries.size() + " potential components. To see others, try the command `benchmark find " + searchString +"`_)";
|
||||
embed.footerText += " (Chose the " + entry.model + " from " + entries.size() + " potential components. To see others, try the command 'benchmark find " + searchString +"')";
|
||||
|
||||
return output;
|
||||
embed.footerText += " (took " + (System.currentTimeMillis() - start) + "ms)";
|
||||
|
||||
return new BenchmarkFormattable(embed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package core.benchmark;
|
||||
|
||||
public abstract class BenchmarkCommand {
|
||||
public BenchmarkCommand() { }
|
||||
public abstract class BenchmarkCommand
|
||||
{
|
||||
public BenchmarkCommand()
|
||||
{ }
|
||||
|
||||
// OVERRIDE ME
|
||||
public abstract String OnRun(BenchmarkManager manager, BenchmarkInput input);
|
||||
public abstract BenchmarkFormattable OnRun(BenchmarkManager manager, BenchmarkInput input);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package core.benchmark;
|
||||
|
||||
import dataStructures.KittyEmbed;
|
||||
import dataStructures.Response;
|
||||
|
||||
// Only one isn't null!
|
||||
public class BenchmarkFormattable
|
||||
{
|
||||
public final KittyEmbed resEmbed;
|
||||
public final String resString;
|
||||
|
||||
// Default constructor is hidden and disabled.
|
||||
// If somehow it is called, defaults to an empty string and no embed.
|
||||
@SuppressWarnings("unused")
|
||||
private BenchmarkFormattable()
|
||||
{
|
||||
this.resEmbed = null;
|
||||
this.resString = "";
|
||||
}
|
||||
|
||||
public BenchmarkFormattable(String res)
|
||||
{
|
||||
this.resEmbed = null;
|
||||
this.resString = res;
|
||||
}
|
||||
|
||||
public BenchmarkFormattable(KittyEmbed embed)
|
||||
{
|
||||
this.resEmbed = embed;
|
||||
this.resString = null;
|
||||
}
|
||||
|
||||
public void Call(Response res)
|
||||
{
|
||||
if(resEmbed == null)
|
||||
res.Call(resString);
|
||||
else
|
||||
res.CallEmbed(resEmbed);
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ public class BenchmarkFramework
|
||||
}
|
||||
|
||||
// Runs a command if possible.
|
||||
public String Run(String args)
|
||||
public BenchmarkFormattable Run(String args)
|
||||
{
|
||||
BenchmarkInput input = new BenchmarkInput(args);
|
||||
return ExecuteCommand(input.key, input);
|
||||
@@ -39,7 +39,7 @@ public class BenchmarkFramework
|
||||
}
|
||||
|
||||
// Executes a command with the specified name, and provides it with some extra input data.
|
||||
private String ExecuteCommand(String name, BenchmarkInput input)
|
||||
private BenchmarkFormattable ExecuteCommand(String name, BenchmarkInput input)
|
||||
{
|
||||
BenchmarkCommand command = benchmarkCommand.get(name.toLowerCase());
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ package core.benchmark;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import dataStructures.Pair;
|
||||
import utils.FileUtils;
|
||||
import utils.directoryMonitor.DirectoryMonitor;
|
||||
import utils.directoryMonitor.MonitoredFile;
|
||||
@@ -67,6 +69,78 @@ public class BenchmarkManager
|
||||
}
|
||||
}
|
||||
|
||||
// Re-evaluates and re-orders the input list based on the Levenshtein distance of the
|
||||
// original search and the contents of the provided list of benchmark entries.
|
||||
public List<BenchmarkEntry> EvaluateLevenshteinDistance(List<BenchmarkEntry> entries, String search)
|
||||
{
|
||||
// Populate cost list with heuristic results
|
||||
List<Pair<BenchmarkEntry, Integer>> cost = new ArrayList<Pair<BenchmarkEntry, Integer>>();
|
||||
int bestSoFar = Integer.MAX_VALUE;
|
||||
for(int i = 0; i < entries.size(); ++i)
|
||||
{
|
||||
BenchmarkEntry entry = entries.get(i);
|
||||
String entryString = entry.brand + " " + entry.model;
|
||||
|
||||
int heuristic = LevenshteinHeuristic(entryString, search, bestSoFar);
|
||||
if(heuristic < bestSoFar)
|
||||
bestSoFar = heuristic;
|
||||
|
||||
cost.add(new Pair<BenchmarkEntry, Integer>(entry, heuristic));
|
||||
}
|
||||
|
||||
// Sort list
|
||||
Collections.sort(cost, (i1, i2) -> i1.Second.compareTo(i2.Second));
|
||||
|
||||
// Build new output list
|
||||
List<BenchmarkEntry> sortedEntries = new ArrayList<BenchmarkEntry>();
|
||||
for(int i = 0; i < cost.size(); ++i)
|
||||
sortedEntries.add(cost.get(i).First);
|
||||
|
||||
return sortedEntries;
|
||||
}
|
||||
|
||||
// Finds the minimum integer in an array of ints and returns it.
|
||||
private int min(int[] arr)
|
||||
{
|
||||
int min = Integer.MAX_VALUE;
|
||||
for(int i = 0; i < arr.length; ++i)
|
||||
{
|
||||
if(arr[i] < min)
|
||||
min = arr[i];
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
// Returns cost based on distance of characters from string. This is a kinda sloppy way
|
||||
// to do it, but because I keep tabs on the best result so far, it could be much worse.
|
||||
// Still chucks a lot - a non-recursive result w/ memoization would be best but this will do.
|
||||
private int LevenshteinHeuristic(String str1, String str2, int bestSoFar)
|
||||
{
|
||||
int cost;
|
||||
|
||||
if(str1.length() <= 0)
|
||||
return str2.length();
|
||||
|
||||
if(str2.length() <= 0)
|
||||
return str1.length();
|
||||
|
||||
if(str1.charAt(0) == str2.charAt(0))
|
||||
cost = 0;
|
||||
else
|
||||
cost = 1;
|
||||
|
||||
int distance = Math.abs(str1.length() - str2.length());
|
||||
if(distance > bestSoFar)
|
||||
return distance;
|
||||
|
||||
int s1 = LevenshteinHeuristic(str1.substring(1), str2, bestSoFar) + 1;
|
||||
int s2 = LevenshteinHeuristic(str1, str2.substring(1), bestSoFar) + 1;
|
||||
int s3 = LevenshteinHeuristic(str1.substring(1), str2.substring(1), bestSoFar) + cost;
|
||||
|
||||
return min(new int[] {s1, s2, s3 });
|
||||
}
|
||||
|
||||
// Search for a substring in the model name
|
||||
public List<BenchmarkEntry> FindModel(String modelSubstr)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package dataStructures;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
public class KittyEmbed
|
||||
{
|
||||
public String title = null;
|
||||
public Color color = null;
|
||||
public String footerText = null;
|
||||
public String authorText = null;
|
||||
public String authorLink = null;
|
||||
public String authorImage = null;
|
||||
public String descriptionText = null;
|
||||
|
||||
public KittyEmbed()
|
||||
{
|
||||
this.title = "Untitled";
|
||||
}
|
||||
}
|
||||
@@ -5,26 +5,52 @@ import java.io.InputStream;
|
||||
import net.dv8tion.jda.core.JDA;
|
||||
import net.dv8tion.jda.core.entities.TextChannel;
|
||||
import net.dv8tion.jda.core.events.message.guild.*;
|
||||
import net.dv8tion.jda.core.EmbedBuilder;
|
||||
import utils.GlobalLog;
|
||||
import utils.LogFilter;
|
||||
|
||||
// NOTE(wisp): This isn't constructed with the factory at this time, mostly
|
||||
// because we need it to handle all the response queue behavior and everything
|
||||
// internally. So long as commands aren't exposed to the GuildMessageReceivedEvent
|
||||
// then we should be fine.
|
||||
// This isn't constructed with the factory at this time, mostly because we need it
|
||||
// to handle all the response queue behavior and everything internally. So long as
|
||||
// commands aren't exposed to the GuildMessageReceivedEvent then we should be fine.
|
||||
public class Response
|
||||
{
|
||||
// Variables
|
||||
private GuildMessageReceivedEvent event;
|
||||
private JDA kitty;
|
||||
private final int discordMessageMax = 2000;
|
||||
private final int kittyMessageMax = 1950;
|
||||
|
||||
// Constructor
|
||||
public Response(GuildMessageReceivedEvent event, JDA kitty)
|
||||
{
|
||||
this.event = event;
|
||||
this.kitty = kitty;
|
||||
}
|
||||
|
||||
// Builds a nicely formatted embedded message based on information provided
|
||||
public void CallEmbed(KittyEmbed embedInfo)
|
||||
{
|
||||
EmbedBuilder embed = new EmbedBuilder();
|
||||
|
||||
if(embedInfo.title != null)
|
||||
embed.setTitle(embedInfo.title);
|
||||
|
||||
if(embedInfo.color != null)
|
||||
embed.setColor(embedInfo.color);
|
||||
|
||||
if(embedInfo.descriptionText != null)
|
||||
embed.setDescription(embedInfo.descriptionText);
|
||||
|
||||
if(embedInfo.footerText != null)
|
||||
embed.setFooter(embedInfo.footerText, null);
|
||||
|
||||
if(embedInfo.authorImage != null || embedInfo.authorLink != null || embedInfo.authorText != null)
|
||||
embed.setAuthor(embedInfo.authorText, embedInfo.authorLink, embedInfo.authorImage);
|
||||
|
||||
event.getChannel().sendMessage(embed.build()).queue();
|
||||
}
|
||||
|
||||
// Queues a standard text-based message response to the channel that issued the command.
|
||||
public void Call(String toRespondWith)
|
||||
{
|
||||
GlobalLog.Log(LogFilter.Response, "Sending response: " + toRespondWith);
|
||||
@@ -38,6 +64,7 @@ public class Response
|
||||
}
|
||||
}
|
||||
|
||||
// Queues a standard text-based message response to the specified channel.
|
||||
public void CallToChannel(String toRespondWith, String channelID)
|
||||
{
|
||||
TextChannel channel;
|
||||
@@ -52,6 +79,7 @@ public class Response
|
||||
}
|
||||
}
|
||||
|
||||
// Immediately dispatches the message to the channel that issued the command.
|
||||
public void CallImmediate(String toRespondWith)
|
||||
{
|
||||
GlobalLog.Log(LogFilter.Response, "Sending immediate response: " + toRespondWith);
|
||||
@@ -65,13 +93,14 @@ public class Response
|
||||
}
|
||||
}
|
||||
|
||||
// This is for responding with a file rather than a String
|
||||
// Queues a file response to the channel that issued the command.
|
||||
public void CallFile(File toRespondWith, String extension)
|
||||
{
|
||||
GlobalLog.Log(LogFilter.Response, "Sending file response");
|
||||
event.getChannel().sendFile(toRespondWith, "return." + extension).queue();
|
||||
}
|
||||
|
||||
// Queues an input stream response to the channel that issued the command.
|
||||
public void CallInput(InputStream in, String extension)
|
||||
{
|
||||
GlobalLog.Log(LogFilter.Response, "Sending input stream response");
|
||||
|
||||
Reference in New Issue
Block a user