diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/CommandLineOptions.java b/vipra-cmd/src/main/java/de/vipra/cmd/CommandLineOptions.java index ac6610e5c718baf7f93e9fd2aa352c472db5577f..f89aa19f679aae08d464f413d7887c28ce035ce7 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/CommandLineOptions.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/CommandLineOptions.java @@ -20,6 +20,8 @@ public class CommandLineOptions { public static final Option ALL = Option.builder("A").longOpt("all").desc("select all models, short for -S all").build(); public static final Option CREATE = Option.builder("C").longOpt("create").desc("create new models").hasArgs().argName("models...").build(); public static final Option DELETE = Option.builder("D").longOpt("delete").desc("delete existing models").hasArgs().argName("models...").build(); + public static final Option EDIT = Option.builder("E").longOpt("edit").desc("edit config of selected models").hasArgs().argName("models...") + .build(); public static final Option IMPORT = Option.builder("I").longOpt("import").desc("import data from json into selected models").hasArgs() .argName("models...").build(); public static final Option MODEL = Option.builder("M").longOpt("model").desc("generate topics on selected models").build(); @@ -30,7 +32,7 @@ public class CommandLineOptions { private final String cmdName = "vipra"; public CommandLineOptions() { - final Option[] optionsArray = { CLEAR, DEBUG, HELP, INDEX, LIST, REREAD, SILENT, TEST, ALL, CREATE, DELETE, IMPORT, MODEL, SELECT }; + final Option[] optionsArray = { CLEAR, DEBUG, HELP, INDEX, LIST, REREAD, SILENT, TEST, ALL, CREATE, DELETE, EDIT, IMPORT, MODEL, SELECT }; options = new Options(); for (final Option option : optionsArray) options.addOption(option); @@ -118,6 +120,14 @@ public class CommandLineOptions { return getOptionValues(DELETE); } + public boolean isEdit() { + return hasOption(EDIT); + } + + public String[] modelsToEdit() { + return getOptionValues(EDIT); + } + public boolean isImport() { return hasOption(IMPORT); } diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/Main.java b/vipra-cmd/src/main/java/de/vipra/cmd/Main.java index a6c4906d73212daaf790fef8ae56929d8a449976..096f76120961e34548b7d655d053921d875617ea 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/Main.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/Main.java @@ -12,6 +12,7 @@ import de.vipra.cmd.option.ClearCommand; import de.vipra.cmd.option.Command; import de.vipra.cmd.option.CreateModelCommand; import de.vipra.cmd.option.DeleteModelCommand; +import de.vipra.cmd.option.EditModelCommand; import de.vipra.cmd.option.ImportCommand; import de.vipra.cmd.option.IndexingCommand; import de.vipra.cmd.option.ListModelsCommand; @@ -67,6 +68,9 @@ public class Main { if (opts.isList()) commands.add(new ListModelsCommand()); + if (opts.isEdit()) + commands.add(new EditModelCommand(opts.modelsToEdit())); + if (opts.isImport()) commands.add(new ImportCommand(opts.selectedModels(), opts.filesToImport())); diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/option/EditModelCommand.java b/vipra-cmd/src/main/java/de/vipra/cmd/option/EditModelCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..44552463a7610c451ddde49d155a9795080c6c6e --- /dev/null +++ b/vipra-cmd/src/main/java/de/vipra/cmd/option/EditModelCommand.java @@ -0,0 +1,65 @@ +package de.vipra.cmd.option; + +import de.vipra.util.Config; +import de.vipra.util.ConsoleUtils; +import de.vipra.util.Constants.ProcessorMode; +import de.vipra.util.Constants.WindowResolution; +import de.vipra.util.ex.DatabaseException; +import de.vipra.util.model.TopicModelConfig; +import de.vipra.util.model.TopicModelFull; +import de.vipra.util.service.MongoService; + +public class EditModelCommand implements Command { + + private final String[] names; + private MongoService<TopicModelFull, String> dbTopicModels; + + public EditModelCommand(final String[] names) { + this.names = names; + } + + private void editModel(final TopicModelConfig topicModelConfig) throws DatabaseException { + ConsoleUtils.info("editing model: " + topicModelConfig.getName()); + topicModelConfig.setDescription(ConsoleUtils.readString("description (↲ to skip)", topicModelConfig.getDescription(), true)); + topicModelConfig.setkTopics(ConsoleUtils.readInt("k topics", topicModelConfig.getkTopics(), 1, null, true)); + topicModelConfig + .setDynamicMinIterations(ConsoleUtils.readInt("dynamic min iterations", topicModelConfig.getDynamicMinIterations(), 1, null, true)); + topicModelConfig.setDynamicMaxIterations(ConsoleUtils.readInt("dynamic max iterations", topicModelConfig.getDynamicMaxIterations(), + topicModelConfig.getDynamicMinIterations(), null, true)); + topicModelConfig.setStaticIterations(ConsoleUtils.readInt("static iterations", topicModelConfig.getStaticIterations(), 1, null, true)); + topicModelConfig + .setTopicAutoNamingWords(ConsoleUtils.readInt("topic auto naming words", topicModelConfig.getTopicAutoNamingWords(), 1, null, true)); + topicModelConfig + .setMaxSimilarDocuments(ConsoleUtils.readInt("max similar documents", topicModelConfig.getMaxSimilarDocuments(), 0, null, true)); + topicModelConfig + .setDocumentMinimumLength(ConsoleUtils.readInt("document min length", topicModelConfig.getDocumentMinimumLength(), 0, null, true)); + topicModelConfig.setDocumentMinimumWordFrequency( + ConsoleUtils.readInt("document min word frequency", topicModelConfig.getDocumentMinimumWordFrequency(), 0, null, true)); + topicModelConfig.setSpotlightSupport(ConsoleUtils.readInt("spotlight support", topicModelConfig.getSpotlightSupport(), 0, null, true)); + topicModelConfig + .setSpotlightConfidence(ConsoleUtils.readDouble("spotlight confidence", topicModelConfig.getSpotlightConfidence(), 0.0, 1.0, true)); + topicModelConfig.setMinRelativeProbability( + ConsoleUtils.readDouble("min relative probability", topicModelConfig.getMinRelativeProbability(), 0.0, 1.0, true)); + topicModelConfig.setRisingDecayLambda(ConsoleUtils.readDouble("rising decay lambda", topicModelConfig.getRisingDecayLambda())); + topicModelConfig.setMaxSimilarDocumentsDivergence( + ConsoleUtils.readDouble("max similar documents divergence", topicModelConfig.getMaxSimilarDocumentsDivergence(), 0.0, 1.0, true)); + topicModelConfig + .setWindowResolution(ConsoleUtils.readEnum(WindowResolution.class, "window resolution", topicModelConfig.getWindowResolution())); + topicModelConfig.setProcessorMode(ConsoleUtils.readEnum(ProcessorMode.class, "processor mode", topicModelConfig.getProcessorMode())); + + final TopicModelFull topicModel = new TopicModelFull(topicModelConfig.getName()); + topicModel.setModelConfig(topicModelConfig); + dbTopicModels.updateSingle(topicModel, "modelConfig"); + } + + @Override + public void run() throws Exception { + final Config config = Config.getConfig(); + dbTopicModels = MongoService.getDatabaseService(config, TopicModelFull.class); + + for (final String name : names) { + editModel(config.getTopicModelConfig(name)); + } + } + +} diff --git a/vipra-ui/app/html/directives/topic-link.html b/vipra-ui/app/html/directives/topic-link.html index 7ad606fe8f90791a1f8b4db0f4d908b77ad73b0b..bcdd3845f88fc43b47ecdadd912fd9f6b8a86d5b 100644 --- a/vipra-ui/app/html/directives/topic-link.html +++ b/vipra-ui/app/html/directives/topic-link.html @@ -1,5 +1,5 @@ <span> - <topic-menu topic="topic" right="true" /> + <topic-menu topic="topic" /> <a class="topic-link" ui-sref="topics.show({id:topic.id})"> <span ng-bind="topic.name"></span> <ng-transclude/> diff --git a/vipra-ui/app/js/controllers.js b/vipra-ui/app/js/controllers.js index 4be0f3afa730721f61cf00eac93c2a1f0106271c..1a4e7a39799c413e098c4a6ef47f88626b5ac3f3 100644 --- a/vipra-ui/app/js/controllers.js +++ b/vipra-ui/app/js/controllers.js @@ -671,6 +671,16 @@ }, $scope.topic, function(data) { $scope.topic = data; $scope.isRename = false; + + // if topic list of parent view is loaded, replace name by new name + if($scope.$parent.topics) { + for(var i = 0, topic; i < $scope.$parent.topics.length; i++) { + topic = $scope.$parent.topics[i]; + if(topic.id === data.id) { + break; + } + } + } }, function(err) { $scope.errors = err; }); diff --git a/vipra-util/src/main/java/de/vipra/util/ConsoleUtils.java b/vipra-util/src/main/java/de/vipra/util/ConsoleUtils.java index 7e2ee2f0f93636a6d1091322c457b08070f21397..29cadf2964d5ca4fabd5b418a4e7863b32b7dcd9 100644 --- a/vipra-util/src/main/java/de/vipra/util/ConsoleUtils.java +++ b/vipra-util/src/main/java/de/vipra/util/ConsoleUtils.java @@ -1,5 +1,9 @@ package de.vipra.util; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + import org.fusesource.jansi.Ansi; import org.fusesource.jansi.Ansi.Color; @@ -24,7 +28,7 @@ public class ConsoleUtils { public static void error(final String msg) { if (!silent) - System.err.println(label("ERROR") + " - " + Ansi.ansi().fg(Color.RED).a(msg).reset()); + System.out.println(label("ERROR") + " - " + Ansi.ansi().fg(Color.RED).a(msg).reset()); } public static void error(final Throwable t) { @@ -35,4 +39,126 @@ public class ConsoleUtils { return StringUtils.pad(label, pad); } + public static double readDouble(String message, final Double def, final Double min, final Double max, final boolean showBounds) { + final BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + if (showBounds) + message += " (" + (min != null ? min : "-∞") + ".." + (max != null ? max : "∞") + ")"; + if (def != null) + message += " [" + def + "]"; + message += ": "; + while (true) { + System.out.print(message); + try { + final String line = in.readLine(); + if (line.isEmpty() && def != null) + return def; + final double d = Double.parseDouble(line); + if (min != null && d < min) + continue; + if (max != null && d > max) + continue; + return d; + } catch (final NumberFormatException e) {} catch (final IOException e) { + throw new RuntimeException(e); + } + } + } + + public static double readDouble(final String message, final Double def, final Double min, final Double max) { + return readDouble(message, def, min, max, true); + } + + public static double readDouble(final String message, final Double def) { + return readDouble(message, def, null, null, true); + } + + public static double readDouble(final String message) { + return readDouble(message, null, null, null, false); + } + + public static int readInt(String message, final Integer def, final Integer min, final Integer max, final boolean showBounds) { + final BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + if (showBounds) + message += " (" + (min != null ? min : "-∞") + ".." + (max != null ? max : "∞") + ")"; + if (def != null) + message += " [" + def + "]"; + message += ": "; + while (true) { + System.out.print(message); + try { + final String line = in.readLine(); + if (line.isEmpty() && def != null) + return def; + final int i = Integer.parseInt(line); + if (min != null && i < min) + continue; + if (max != null && i > max) + continue; + return i; + } catch (final NumberFormatException e) {} catch (final IOException e) { + throw new RuntimeException(e); + } + } + } + + public static int readInt(final String message, final Integer def, final Integer min, final Integer max) { + return readInt(message, def, min, max, true); + } + + public static int readInt(final String message, final Integer def) { + return readInt(message, def, null, null, true); + } + + public static int readInt(final String message) { + return readInt(message, null, null, null, false); + } + + public static String readString(String message, final String def, final boolean canBeEmpty) { + final BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + message += ": "; + while (true) { + System.out.print(message); + try { + final String line = in.readLine(); + if (line.isEmpty()) { + if (def != null) + return def; + if (!canBeEmpty) + continue; + } + return line; + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + } + + public static String readString(final String message, final String def) { + return readString(message, def, false); + } + + public static String readString(final String message) { + return readString(message, null, false); + } + + public static <T extends Enum<?>> T readEnum(final Class<T> enumClass, String message, final T def) { + final BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + if (def != null) + message += " [" + def + "]"; + message += ": "; + while (true) { + System.out.print(message); + try { + final String line = in.readLine(); + final T value = EnumUtils.searchEnum(enumClass, line); + if (value != null) + return value; + if (def != null) + return def; + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + } + } diff --git a/vipra-util/src/main/java/de/vipra/util/EnumUtils.java b/vipra-util/src/main/java/de/vipra/util/EnumUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..d7e57dc5ae4ca2782f8586921df5b831a4e9d697 --- /dev/null +++ b/vipra-util/src/main/java/de/vipra/util/EnumUtils.java @@ -0,0 +1,23 @@ +package de.vipra.util; + +public class EnumUtils { + + /** + * Finds an enum value by its name, ignoring case. + * + * @param enumeration + * Enum to be searched + * @param search + * Enum value to be searched + * @return the found enum value, or null + */ + public static <T extends Enum<?>> T searchEnum(final Class<T> enumeration, final String search) { + for (final T each : enumeration.getEnumConstants()) { + if (each.name().compareToIgnoreCase(search) == 0) { + return each; + } + } + return null; + } + +} diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicModelConfig.java b/vipra-util/src/main/java/de/vipra/util/model/TopicModelConfig.java index 366972d664942ec0d96507e6b5b66c89e9ae3fd1..4dde14aa7bd8bb9e76c2e60839ba49fa44dfd77a 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TopicModelConfig.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TopicModelConfig.java @@ -17,6 +17,7 @@ import de.vipra.util.Constants.WindowResolution; public class TopicModelConfig implements Serializable { private String name; + private String description; private int kTopics = Constants.K_TOPICS; private int dynamicMinIterations = Constants.DYNAMIC_MIN_ITER; private int dynamicMaxIterations = Constants.DYNAMIC_MAX_ITER; @@ -61,6 +62,14 @@ public class TopicModelConfig implements Serializable { this.name = name; } + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } + public int getkTopics() { return kTopics; } diff --git a/vipra-util/src/main/java/de/vipra/util/model/Window.java b/vipra-util/src/main/java/de/vipra/util/model/Window.java index 3039ca0358f909be9c26e767c4498364846cdcc9..b3350267579083cae4eb9245de58210c22239ed9 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/Window.java +++ b/vipra-util/src/main/java/de/vipra/util/model/Window.java @@ -26,15 +26,15 @@ public class Window implements Model<Integer>, Serializable, Comparable<Window> public Window() {} - public Window(Integer id) { + public Window(final Integer id) { this.id = id; } - public Window(WindowFull window) { - this.id = window.getId(); - this.startDate = window.getStartDate(); - this.endDate = window.getEndDate(); - this.windowResolution = window.getWindowResolution(); + public Window(final WindowFull window) { + id = window.getId(); + startDate = window.getStartDate(); + endDate = window.getEndDate(); + windowResolution = window.getWindowResolution(); } @Override