Refactor code. Human-readable spent time tracking. master
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sat, 7 Jun 2025 19:23:25 +0000 (22:23 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sat, 7 Jun 2025 19:23:25 +0000 (22:23 +0300)
src/main/java/eu/svjatoslav/alyverkko_cli/AiTask.java
src/main/java/eu/svjatoslav/alyverkko_cli/commands/mail_correspondant/MailCorrespondentCommand.java
src/main/java/eu/svjatoslav/alyverkko_cli/commands/mail_correspondant/MailQuery.java
src/main/java/eu/svjatoslav/alyverkko_cli/configuration/Configuration.java

index 99f68a8..530e114 100644 (file)
@@ -135,6 +135,9 @@ public class AiTask {
      */
     public String runAiQuery() throws InterruptedException, IOException {
         try {
+            // Record the start time of the query
+            mailQuery.startTime = System.currentTimeMillis();
+
             // Build input prompt
             initializeInputFile(buildAiQuery());
 
@@ -158,6 +161,9 @@ public class AiTask {
             // Wait for the output thread to finish reading
             outputThread.join();
 
+            // Record the end time of the query
+            mailQuery.endTime = System.currentTimeMillis();
+
             // Clean up the AI response: remove partial prompt text, end-of-text marker, etc.
             return filterParticipantsInAiResponse(cleanupAiResponse(result.toString()));
         } finally {
index dfac423..bf291dc 100644 (file)
@@ -1,7 +1,6 @@
 package eu.svjatoslav.alyverkko_cli.commands.mail_correspondant;
 
 import eu.svjatoslav.alyverkko_cli.*;
-import eu.svjatoslav.alyverkko_cli.configuration.ConfigurationHelper;
 import eu.svjatoslav.alyverkko_cli.model.Model;
 import eu.svjatoslav.alyverkko_cli.model.ModelLibrary;
 import eu.svjatoslav.commons.cli_helper.parameter_parser.Parser;
@@ -204,56 +203,29 @@ public class MailCorrespondentCommand implements Command {
 
         System.out.println("\nReplying to mail: " + file.getName());
 
-        // Read the mail content
-        String inputFileContent = getFileContentsAsString(file);
-
-        // Split into first line and user prompt
-        int firstNewLineIndex = inputFileContent.indexOf('\n');
-        if (firstNewLineIndex == -1) {
-            throw new IllegalArgumentException("Input file is only one line long. Content: " + inputFileContent);
-        }
-        String firstLine = inputFileContent.substring(0, firstNewLineIndex);
-        String userPromptOriginal = inputFileContent.substring(firstNewLineIndex + 1);
-
-        // Parse the first line into settings
-        Map<String, String> settings = parseSettings(firstLine);
-
-        // Create MailQuery
-        MailQuery mailQuery = new MailQuery();
-        mailQuery.systemPrompt = configuration.getPromptByAlias(settings.getOrDefault("prompt", "default"));
-        String modelAlias = settings.getOrDefault("model", "default");
-        Optional<Model> modelOptional = modelLibrary.findModelByAlias(modelAlias);
-        if (!modelOptional.isPresent()) {
-            throw new IllegalArgumentException("Model with alias '" + modelAlias + "' not found.");
-        }
-        mailQuery.model = modelOptional.get();
-        mailQuery.userPrompt = userPromptOriginal;
+        MailQuery mailQuery = buildMailQueryFromFile(file);
 
-        // Record start time
-        long startTime = System.currentTimeMillis();
-
-        // Create an AiTask and run the query
+        // Run the query using the AI model while measuring the time taken
         AiTask aiTask = new AiTask(mailQuery);
         String aiGeneratedResponse = aiTask.runAiQuery();
 
-        // Record end time and calculate duration
-        long endTime = System.currentTimeMillis();
-        long durationMinutes = Math.round((endTime - startTime) / 60000.0); // Convert to minutes and round
+        saveAiResponseToFile(file, mailQuery, aiGeneratedResponse);
+    }
 
+    private static void saveAiResponseToFile(File file, MailQuery mailQuery, String aiGeneratedResponse) throws IOException {
         // Build new content
         StringBuilder resultFileContent = new StringBuilder();
 
-        // Replace the first line with DONE line
-        resultFileContent.append("DONE: prompt=").append(settings.get("prompt"))
-                .append(" model=").append(modelAlias)
-                .append(" time=").append(durationMinutes)
-                .append("\n");
+        // The First line should be "TOCOMPUTE:" with settings that were used to process this file
+        resultFileContent.append(getDoneLine(mailQuery));
+
         // Ensure the user prompt block is labeled if it isn't already
         if (!mailQuery.userPrompt.startsWith("* USER:\n")) {
             resultFileContent.append("* USER:\n");
         }
+
         // Append the original user prompt (after the first line)
-        resultFileContent.append(userPromptOriginal).append("\n");
+        resultFileContent.append(mailQuery.userPrompt).append("\n");
 
         // Append the AI response block
         resultFileContent
@@ -265,6 +237,62 @@ public class MailCorrespondentCommand implements Command {
         saveToFile(file, resultFileContent.toString());
     }
 
+    private static String getDoneLine(MailQuery mailQuery) {
+        return "DONE: prompt=" + mailQuery.systemPromptName + " model="+ mailQuery.model.alias + " duration=" + getDuration(mailQuery.startTime, mailQuery.endTime) + "\n";
+    }
+
+    private static String getDuration(long startTime, long endTime) {
+
+        long durationMillis = endTime - startTime;
+        long durationSeconds = durationMillis / 1000;
+
+        if (durationSeconds < 180){
+            return String.valueOf(durationSeconds) + "s";
+        }
+
+        long durationMinutes = durationSeconds / 60;
+        if (durationMinutes < 180) {
+            return durationMinutes + "m";
+        }
+
+        long durationHours = durationMinutes / 60;
+        return durationHours + "h";
+    }
+
+    private MailQuery buildMailQueryFromFile(File file) throws IOException {
+        MailQuery result = new MailQuery();
+
+        // Read the mail content
+        String inputFileContent = getFileContentsAsString(file);
+
+        // Split into first line and user prompt
+        int firstNewLineIndex = inputFileContent.indexOf('\n');
+        if (firstNewLineIndex == -1) {
+            throw new IllegalArgumentException("Input file is only one line long. Content: " + inputFileContent);
+        }
+
+        // The First line should start with "TOCOMPUTE:" and contain settings
+        String firstLine = inputFileContent.substring(0, firstNewLineIndex);
+        Map<String, String> fileProcessingSettings = parseSettings(firstLine);
+
+        // The rest of the file is the user prompt
+        result.userPrompt = inputFileContent.substring(firstNewLineIndex + 1);
+
+        // Set system prompt
+        result.systemPromptName = fileProcessingSettings.getOrDefault("prompt", "default");
+        result.systemPrompt = configuration.getPromptByName(result.systemPromptName);
+
+        // Set AI model
+        String modelAlias = fileProcessingSettings.getOrDefault("model", "default");
+        Optional<Model> modelOptional = modelLibrary.findModelByAlias(modelAlias);
+        if (!modelOptional.isPresent()) {
+            throw new IllegalArgumentException("Model with alias '" + modelAlias + "' not found.");
+        }
+        result.model = modelOptional.get();
+
+        return result;
+    }
+
     /**
      * Parses the "TOCOMPUTE:" line, which should look like:
      * <pre>TOCOMPUTE: key1=value1 key2=value2 ...</pre>
index a33584f..51a3e0b 100644 (file)
@@ -15,6 +15,12 @@ public class MailQuery {
      */
     public String systemPrompt;
 
+    /**
+     * The name of the system prompt, which can be used to reference
+     * a specific system prompt configuration file.
+     */
+    public String systemPromptName;
+
     /**
      * The user's prompt text (the main request or query).
      */
@@ -25,6 +31,16 @@ public class MailQuery {
      */
     public Model model;
 
+    /**
+     * The start time of the query (milliseconds since epoch).
+     */
+    public long startTime;
+
+    /**
+     * The end time of the query (milliseconds since epoch).
+     */
+    public long endTime;
+
     /**
      * Returns a string containing a summary of the {@link MailQuery} object.
      *
index 4e0c52e..8394e42 100644 (file)
@@ -69,14 +69,14 @@ public class Configuration {
 
     /**
      * Retrieves the contents of a prompt file by alias, e.g. "writer"
-     * maps to "writer.txt" in the prompts directory.
+     * maps to "writer.txt" in the prompt's directory.
      *
-     * @param alias the name of the prompt file (without ".txt").
+     * @param promptName the name of the prompt file (without ".txt").
      * @return the full text content of the prompt file.
      * @throws IOException if reading the prompt file fails.
      */
-    public String getPromptByAlias(String alias) throws IOException {
-        File promptFile = new File(promptsDirectory, alias + ".txt");
+    public String getPromptByName(String promptName) throws IOException {
+        File promptFile = new File(promptsDirectory, promptName + ".txt");
         return getFileContentsAsString(promptFile);
     }
 }