: sudo systemctl stop alyverkko-cli
: sudo systemctl disable alyverkko-cli
-* Usage
+* Task preparation
+
+The Älyverkko CLI application expects input files for processing in
+the form of plain text files within the specified mail directory
+(configured in the [[id:0fcdae48-81c5-4ae1-bdb9-64ae74e87c45][YAML configuration file]]).
+
+Suggested usage flow is to prepare AI assignments within the Älyverkko
+CLI mail directory using normal text editor. Once AI assignment is
+ready for processing, you should [[id:883d6e7c-60e0-422b-8c00-5cdc9dfec20d][initiate AI processing]] on that file.
+
+** joinfiles command
+
+To simplify appending together multiple files from filesystem for AI
+processing in a single query, *joinfiles* command can be used. It
+prompts user for the name of the output file (without extension),
+thereafter it scans and recursively appends contents of all files in
+the current directory and its subdirectories.
+
+Usage example:
+: alyverkko-cli joinfiles
+
+This is useful for example when you want to submit entire software
+project source code directory to AI for processing.
+
+* Initiate AI processing
:PROPERTIES:
:ID: 883d6e7c-60e0-422b-8c00-5cdc9dfec20d
:END:
-The Älyverkko CLI application expects input files for processing in
-the form of plain text files within the specified mail directory
-(configured in the [[id:0fcdae48-81c5-4ae1-bdb9-64ae74e87c45][YAML configuration file]]). Each file should begin
-with a `TOCOMPUTE:` marker on the first line to be considered for
+Once your task file is prepared, you should place *TOCOMPUTE:* marker
+on the first line of that file, so that it will be considered for
processing.
-When the application detects a new or modified file in the mail
+When the Älyverkko CLI detects a new or modified file in the mail
directory:
1. It checks if file has "TOCOMPUTE:" on the first line. If no, file
thread. "TOCOMPUTE:" is removed from the beginning of the file to
avoid processing same file again.
-Suggested way to use mail processing mode is to prepare assignments
-within the Älyverkko CLI mail directory using normal text editor. Feel
-free to save intermediary states. Once AI assignment is ready, add
+Note: During AI task file preparation, feel free to save intermediary
+states as often as needed because AI engine will keep ignoring the
+file until *TOCOMPUTE:* line appears. Once AI assignment is ready, add
: TOCOMPUTE:
to the beginning of the file and save one last time. Älyverkko CLI
-will detect new task within one second and will start processing it.
+will detect new task approximately within one second after file is
+saved and will start processing it.
If your text editor automatically reloads file when it was changed by
other process in the filesystem, AI response will appear within text
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.13.0</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.12.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>1.3.2</version>
+ </dependency>
</dependencies>
<build>
package eu.svjatoslav.alyverkko_cli;
+import eu.svjatoslav.alyverkko_cli.commands.JoinFilesCommand;
import eu.svjatoslav.alyverkko_cli.commands.ListModelsCommand;
import eu.svjatoslav.alyverkko_cli.configuration.Configuration;
import eu.svjatoslav.alyverkko_cli.commands.MailCorrespondentCommand;
private final java.util.List<Command> commands = java.util.Arrays.asList(
new ListModelsCommand(),
- new MailCorrespondentCommand()
+ new MailCorrespondentCommand(),
+ new JoinFilesCommand()
);
public static void main(final String[] args) throws IOException, InterruptedException {
--- /dev/null
+package eu.svjatoslav.alyverkko_cli.commands;
+
+import eu.svjatoslav.alyverkko_cli.*;
+import org.apache.commons.io.FilenameUtils;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.*;
+
+import static eu.svjatoslav.alyverkko_cli.Main.configuration;
+import static eu.svjatoslav.alyverkko_cli.configuration.Configuration.loadConfiguration;
+
+public class JoinFilesCommand implements Command {
+
+ @Override
+ public String getName() {
+ return "joinfiles";
+ }
+
+ public Path baseDirectory;
+
+ @Override
+ public void execute(String[] cliArguments) throws IOException {
+ configuration = loadConfiguration();
+ if (configuration == null){
+ System.out.println("Failed to load configuration file");
+ return;
+ }
+
+ // Ask for file name to be created
+ System.out.print("Enter the output file name (without extension): ");
+ String fileName = System.console().readLine();
+
+ // Create the output file with .org extension
+ File outputFile = new File(FilenameUtils.normalize(fileName + ".org"));
+
+ // create output file within the mail directory
+ outputFile = new File(configuration.getMailDirectory(), outputFile.getName());
+
+
+ try (BufferedWriter writer = Files.newBufferedWriter(outputFile.toPath(), StandardCharsets.UTF_8)) {
+ baseDirectory = Paths.get(".");
+ joinFilesRecursively(baseDirectory, writer);
+ }
+
+ System.out.println("Files have been joined into: " + outputFile.getAbsolutePath());
+ System.out.println("Opening editor to edit the file...");
+
+ // TODO: make editor configurable
+ String command = "emc " + outputFile.getAbsolutePath();
+
+ // opening editor
+ Runtime.getRuntime().exec(command);
+ }
+
+ private void joinFilesRecursively(Path directoryToIndex, BufferedWriter writer) throws IOException {
+ DirectoryStream<Path> stream = Files.newDirectoryStream(directoryToIndex);
+
+ for (Path entry : stream) {
+ if (Files.isDirectory(entry)) {
+ joinFilesRecursively(entry, writer);
+ } else if (Files.isRegularFile(entry)) {
+ String contentType = Files.probeContentType(entry);
+
+ if (contentType != null && contentType.startsWith("text/")) writeFile(writer, entry);
+ }
+ }
+ }
+
+ private void writeFile(BufferedWriter writer, Path entry) throws IOException {
+ writeFileHeader(writer, entry);
+
+ String fileContent = new String(Files.readAllBytes(entry));
+
+ // remove empty lines from the beginning and end of the file
+ fileContent = fileContent.replaceAll("(?m)^\\s*$", "");
+
+ writer.write(fileContent + "\n");
+ }
+
+ private void writeFileHeader(BufferedWriter writer, Path entry) throws IOException {
+ String relativePath = baseDirectory.relativize(entry).toString();
+ writer.write( "* file: " + relativePath + "\n\n");
+ }
+}
+
public class Configuration {
- private static final String DEFAULT_CONFIG_FILE_PATH = "~/.config/alyverkko-cli.yaml".replaceFirst("^~", System.getProperty("user.home"));;
+ private static final String DEFAULT_CONFIG_FILE_PATH = "~/.config/alyverkko-cli.yaml".replaceFirst("^~", System.getProperty("user.home"));
@JsonProperty("mail_directory")
private File mailDirectory;