// Mail Directory
String mailDir = getInputWithDefault(
- "Enter the mail directory for AI tasks. This is where your task files will be stored.",
+ "\nEnter the mail directory for AI tasks. This is where your task files will be stored.",
existingConfig != null ? existingConfig.getMailDirectory().getPath() : "~/.config/alyverkko-cli/mail"
);
config.setMailDirectory(new File(mailDir));
// Models Directory
String modelsDir = getInputWithDefault(
- "Enter the directory for AI models. This should contain your GGUF model files.",
+ "\nEnter the directory for AI models. This should contain your GGUF model files.",
existingConfig != null ? existingConfig.getModelsDirectory().getPath() : "~/.config/alyverkko-cli/models"
);
config.setModelsDirectory(new File(modelsDir));
// Prompts Directory
String promptsDir = getInputWithDefault(
- "Enter the directory for prompts. This should contain text files with your AI prompts.",
+ "\nEnter the directory for prompts. This should contain text files with your AI prompts.",
existingConfig != null ? existingConfig.getPromptsDirectory().getPath() : "~/.config/alyverkko-cli/prompts"
);
config.setPromptsDirectory(new File(promptsDir));
// Llama CLI Path
String llamaCliPath = getInputWithDefault(
- "Enter the path to the llama-cli executable. This is the command-line interface for llama.cpp.",
+ "\nEnter the path to the llama-cli executable. This is the command-line interface for llama.cpp.",
existingConfig != null ? existingConfig.getLlamaCliPath().getPath() : "/usr/local/bin/llama-cli"
);
config.setLlamaCliPath(new File(llamaCliPath));
// Default Temperature
float defaultTemp = getFloatInputWithDefault(
- "Enter default temperature (0-1). A lower value makes the AI more deterministic, while a higher value makes it more creative.",
+ "\nEnter default temperature (0-2). A lower value makes the AI more deterministic, while a higher value makes it more creative.",
existingConfig != null ? existingConfig.getDefaultTemperature() : 0.7f,
- 0f, 1f
+ 0f, 2f
);
config.setDefaultTemperature(defaultTemp);
// Thread Counts
int threadCount = getIntInputWithDefault(
- "Enter number of threads for AI processing. This should typically match the number of CPU cores available.",
+ "\nEnter number of CPU threads for AI response generation. " +
+ "RAM data transfer speed is usually the bottleneck here. " +
+ "On a typical PC, while you might have 12 CPU cores, " +
+ "RAM bandwidth can get already saturated with only 6 CPU threads. " +
+ "Once RAM bandwidth is saturated, using more CPU threads " +
+ "will not improve performance while it will keep CPU cores needlessly busy.",
existingConfig != null ? existingConfig.getThreadCount() : 6,
- 1, 16
+ 1, null
);
config.setThreadCount(threadCount);
int batchThreadCount = getIntInputWithDefault(
- "Enter number of batch threads. This controls how many prompts are processed in parallel.",
+ "\nEnter number of CPU threads for input prompt processing. " +
+ "CPU computing power is usually the bottleneck here (not the RAM bandwidth). " +
+ "So you can utilize all CPU cores that you have here.",
existingConfig != null ? existingConfig.getBatchThreadCount() : 10,
- 1, 32
+ 1, null
);
config.setBatchThreadCount(batchThreadCount);
// Models Setup
- System.out.println("\nModel configuration:");
+ System.out.println("\nModel configuration.");
List<ConfigurationModel> models = new ArrayList<>();
+ if (existingConfig != null) {
+ models.addAll(existingConfig.getModels());
+ }
- // Suggest models based on models directory
- suggestModels(config.getModelsDirectory(), models);
+ String choice = getInput("Would you like to try to autodiscover available models ?", "Y");
+ if (choice.equalsIgnoreCase("Y")) {
+ discoverAndSuggestNewModels(config.getModelsDirectory(), models);
+ }
+ System.out.println("\nYou can now add models manually.");
while (true) {
- System.out.println("\nEnter model details or leave alias empty to finish.");
- String alias = getInput("Model alias: ");
+ String alias = getInput("Enter desired model alias (leave empty to finish adding models): ");
if (StringUtils.isBlank(alias)) break;
String filePath = getInputWithDefault(
- "Enter filesystem path relative to models directory. " +
+ "\nEnter filesystem path relative to models directory. " +
"Press Tab for suggestions or Enter to accept default.",
null
);
int contextSize = getIntInputWithDefault(
- "Enter context size in tokens. A higher value allows the model to remember more context.",
+ "\nEnter context size in tokens. A higher value allows the model to remember more context.",
64000,
1024,
128000
}
}
- private int getIntInputWithDefault(String prompt, int defaultValue, int min, int max) {
+ private int getIntInputWithDefault(String prompt, int defaultValue, Integer min, Integer max) {
while (true) {
String input = getInput(prompt, String.valueOf(defaultValue));
try {
int value = Integer.parseInt(input);
- if (value >= min && value <= max) return value;
- System.out.println("Value must be between " + min + " and " + max);
+
+ if (max != null && value > max) {
+ System.out.println("Value must be less than or equal to " + max);
+ continue;
+ }
+
+ if (min != null && value < min) {
+ System.out.println("Value must be greater than or equal to " + min);
+ continue;
+ }
+
+ return value;
} catch (NumberFormatException e) {
System.out.println("Invalid number format. Try again.");
}
}
}
- private void suggestModels(File modelsDir, List<ConfigurationModel> existingModels) {
+ private void discoverAndSuggestNewModels(File modelsDir, List<ConfigurationModel> existingModels) {
if (!modelsDir.exists()) {
System.out.println("Models directory does not exist. Please create it first.");
return;
for (File modelFile : modelFiles) {
String relativePath = modelsDir.toPath().relativize(modelFile.toPath()).toString();
- String alias = suggestAlias(relativePath);
-
- if (!existingAliases.contains(alias)) {
- System.out.println("\nFound new model: " + relativePath);
- System.out.println("Suggested alias: " + alias);
- System.out.println("Would you like to add this model? (y/N)");
- String choice = getInput("Add model? ", "N");
- if (choice.equalsIgnoreCase("Y")) {
- ConfigurationModel model = new ConfigurationModel();
- model.setAlias(alias);
- model.setFilesystemPath(relativePath);
- model.setContextSizeTokens(64000); // Default value
- existingModels.add(model);
- existingAliases.add(alias);
- }
- }
+
+ boolean alreadyExists = existingModels.stream()
+ .anyMatch(m -> m.getFilesystemPath().equals(relativePath));
+
+ if (!alreadyExists) suggestAddingModel(existingModels, relativePath, existingAliases);
+
}
} catch (IOException e) {
System.err.println("Error scanning models directory: " + e.getMessage());
}
}
+ private void suggestAddingModel(List<ConfigurationModel> existingModels, String relativePath, List<String> existingAliases) {
+ String alias = suggestAlias(relativePath);
+ System.out.println("\nFound new model: " + relativePath);
+ System.out.println("Suggested alias: " + alias);
+ String choice = getInput("Would you like to add this model? (y/N) ", "N");
+ if (choice.equalsIgnoreCase("Y")) {
+ ConfigurationModel model = new ConfigurationModel();
+ model.setAlias(alias);
+ model.setFilesystemPath(relativePath);
+ int contextSize = getIntInputWithDefault(
+ "\nEnter context size in tokens. A higher value allows the model to remember more context.",
+ 64000,
+ 1024,
+ null
+ );
+ model.setContextSizeTokens(contextSize);
+ existingModels.add(model);
+ existingAliases.add(alias);
+ }
+ }
+
private String suggestAlias(String filePath) {
String fileName = new File(filePath).getName();
String alias = fileName.replaceAll("[^a-zA-Z0-9]", "-").toLowerCase();
return alias.replaceAll("-+", "-").replaceAll("^-|-$", "");
}
-
private String getInput(String prompt, String defaultValue) {
Scanner scanner = new Scanner(System.in);
System.out.print(prompt + (defaultValue != null ? " [" + defaultValue + "]" : "") + ": ");