diff --git a/AppJsonSerializerContext.cs b/AppJsonSerializerContext.cs new file mode 100644 index 0000000..dc56eea --- /dev/null +++ b/AppJsonSerializerContext.cs @@ -0,0 +1,16 @@ +using System.Text.Json.Serialization; + +namespace Toak; + +[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] +[JsonSerializable(typeof(ToakConfig))] +[JsonSerializable(typeof(WhisperResponse))] +[JsonSerializable(typeof(LlamaRequest))] +[JsonSerializable(typeof(LlamaRequestMessage))] +[JsonSerializable(typeof(LlamaResponse))] +[JsonSerializable(typeof(LlamaChoice))] +[JsonSerializable(typeof(LlamaRequestMessage[]))] +[JsonSerializable(typeof(LlamaChoice[]))] +internal partial class AppJsonSerializerContext : JsonSerializerContext +{ +} diff --git a/ConfigManager.cs b/ConfigManager.cs index b1b914d..69dbdcd 100644 --- a/ConfigManager.cs +++ b/ConfigManager.cs @@ -12,7 +12,7 @@ public class ToakConfig public string StyleMode { get; set; } = "Professional"; public bool StructureBulletPoints { get; set; } = false; public bool StructureSmartParagraphing { get; set; } = true; - public string TargetLanguage { get; set; } = string.Empty; + public string WhisperLanguage { get; set; } = string.Empty; public string LlmModel { get; set; } = "openai/gpt-oss-20b"; public string WhisperModel { get; set; } = "whisper-large-v3-turbo"; @@ -33,7 +33,7 @@ public static class ConfigManager try { var json = File.ReadAllText(ConfigPath); - return JsonSerializer.Deserialize(json) ?? new ToakConfig(); + return JsonSerializer.Deserialize(json, AppJsonSerializerContext.Default.ToakConfig) ?? new ToakConfig(); } catch (Exception) { @@ -48,7 +48,7 @@ public static class ConfigManager Directory.CreateDirectory(ConfigDir); } - var json = JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true }); + var json = JsonSerializer.Serialize(config, AppJsonSerializerContext.Default.ToakConfig); File.WriteAllText(ConfigPath, json); } } diff --git a/GroqApiClient.cs b/GroqApiClient.cs index 01167ef..f90de8c 100644 --- a/GroqApiClient.cs +++ b/GroqApiClient.cs @@ -81,7 +81,7 @@ public class GroqApiClient } var json = await response.Content.ReadAsStringAsync(); - var result = JsonSerializer.Deserialize(json); + var result = JsonSerializer.Deserialize(json, AppJsonSerializerContext.Default.WhisperResponse); return result?.Text ?? string.Empty; } @@ -98,8 +98,7 @@ public class GroqApiClient } }; - var jsonOptions = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; - var jsonContent = new StringContent(JsonSerializer.Serialize(requestBody, jsonOptions), System.Text.Encoding.UTF8, "application/json"); + var jsonContent = new StringContent(JsonSerializer.Serialize(requestBody, AppJsonSerializerContext.Default.LlamaRequest), System.Text.Encoding.UTF8, "application/json"); var response = await _httpClient.PostAsync("chat/completions", jsonContent); @@ -110,7 +109,7 @@ public class GroqApiClient } var json = await response.Content.ReadAsStringAsync(); - var result = JsonSerializer.Deserialize(json); + var result = JsonSerializer.Deserialize(json, AppJsonSerializerContext.Default.LlamaResponse); return result?.Choices?.FirstOrDefault()?.Message?.Content ?? string.Empty; } diff --git a/Program.cs b/Program.cs index 06c3601..288a735 100644 --- a/Program.cs +++ b/Program.cs @@ -1,20 +1,13 @@ using System.Diagnostics; using Toak; -bool pipeToStdout = args.Contains("--pipe") || Console.IsOutputRedirected; -bool rawOutput = args.Contains("--raw"); +bool pipeToStdout = args.Contains("--pipe") || args.Contains("-p") || Console.IsOutputRedirected; bool copyToClipboard = args.Contains("--copy"); -string translateTo = ""; -int translateIndex = Array.IndexOf(args, "--translate"); -if (translateIndex >= 0 && translateIndex < args.Length - 1) -{ - translateTo = args[translateIndex + 1]; -} -string command = args.FirstOrDefault(a => !a.StartsWith("--")) ?? ""; +string command = args.FirstOrDefault(a => !a.StartsWith("-")) ?? ""; -if (string.IsNullOrEmpty(command) && args.Length == 0) +if (args.Contains("-h") || args.Contains("--help") || (string.IsNullOrEmpty(command) && args.Length == 0)) { Console.WriteLine("Toak: High-speed Linux Dictation"); Console.WriteLine("Usage:"); @@ -25,10 +18,9 @@ if (string.IsNullOrEmpty(command) && args.Length == 0) Console.WriteLine(" toak config - Update a specific configuration setting"); Console.WriteLine(" toak show - Show current configuration"); Console.WriteLine("Flags:"); - Console.WriteLine(" --pipe - Output transcription to stdout instead of typing"); - Console.WriteLine(" --raw - Skip LLM refinement, output raw transcript"); + Console.WriteLine(" -h, --help - Show this help message"); + Console.WriteLine(" -p, --pipe - Output transcription to stdout instead of typing"); Console.WriteLine(" --copy - Copy to clipboard instead of typing"); - Console.WriteLine(" --translate - Translate output to the specified language"); return; } @@ -250,10 +242,6 @@ if (command == "toggle") AudioRecorder.StopRecording(); var config = ConfigManager.LoadConfig(); - if (!string.IsNullOrWhiteSpace(translateTo)) - { - config.TargetLanguage = translateTo; - } if (string.IsNullOrWhiteSpace(config.GroqApiKey)) { @@ -285,11 +273,8 @@ if (command == "toggle") string finalText = transcript; // 2. LLM Refinement - if (!rawOutput) - { - var systemPrompt = PromptBuilder.BuildPrompt(config); - finalText = await groq.RefineTextAsync(transcript, systemPrompt, config.LlmModel); - } + var systemPrompt = PromptBuilder.BuildPrompt(config); + finalText = await groq.RefineTextAsync(transcript, systemPrompt, config.LlmModel); // 3. Output if (pipeToStdout) diff --git a/PromptBuilder.cs b/PromptBuilder.cs index 57e782f..a87bf6c 100644 --- a/PromptBuilder.cs +++ b/PromptBuilder.cs @@ -21,10 +21,7 @@ public static class PromptBuilder sb.AppendLine(); sb.AppendLine("FORMATTING RULES:"); - if (!string.IsNullOrWhiteSpace(config.TargetLanguage)) - { - sb.AppendLine($"- CRITICAL: You must translate the text to {config.TargetLanguage} while applying all other formatting rules."); - } + if (config.ModulePunctuation) { diff --git a/Toak.csproj b/Toak.csproj index ed9781c..218df61 100644 --- a/Toak.csproj +++ b/Toak.csproj @@ -5,6 +5,7 @@ net10.0 enable enable + true diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..44563fa --- /dev/null +++ b/install.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Exit immediately if a command exits with a non-zero status +set -e + +echo "Building Toak Native AOT executable..." +dotnet publish -c Release -r linux-x64 + +echo "Installing to /usr/bin/toak... (This may prompt for your sudo password)" +sudo cp bin/Release/net10.0/linux-x64/publish/Toak /usr/bin/toak + +echo "Installation complete! You can now run 'toak' from anywhere."