feat: Add Native AOT compilation and source-generated JSON serialization, streamline CLI arguments, and remove translation functionality.
This commit is contained in:
16
AppJsonSerializerContext.cs
Normal file
16
AppJsonSerializerContext.cs
Normal file
@@ -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
|
||||
{
|
||||
}
|
||||
@@ -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<ToakConfig>(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ public class GroqApiClient
|
||||
}
|
||||
|
||||
var json = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonSerializer.Deserialize<WhisperResponse>(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<LlamaResponse>(json);
|
||||
var result = JsonSerializer.Deserialize(json, AppJsonSerializerContext.Default.LlamaResponse);
|
||||
|
||||
return result?.Choices?.FirstOrDefault()?.Message?.Content ?? string.Empty;
|
||||
}
|
||||
|
||||
29
Program.cs
29
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 <key> <value> - 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 <lang> - 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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PublishAot>true</PublishAot>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
12
install.sh
Executable file
12
install.sh
Executable file
@@ -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."
|
||||
Reference in New Issue
Block a user