using System; using System.Diagnostics; using System.IO; using System.Threading.Tasks; using Spectre.Console; using Toak.Api; using Toak.Configuration; using Toak.Core; namespace Toak.Commands; public static class LatencyTestCommand { public static async Task ExecuteAsync(bool verbose) { Logger.Verbose = verbose; var config = new ConfigManager().LoadConfig(); if (string.IsNullOrWhiteSpace(config.GroqApiKey)) { AnsiConsole.MarkupLine("[red]Groq API Key is not configured.[/] Run 'toak onboard'."); return; } AnsiConsole.MarkupLine("Generating 1-second silent audio file for testing..."); var testWavPath = Path.Combine(Path.GetTempPath(), "toak_latency_test.wav"); var pInfo = new ProcessStartInfo { FileName = "ffmpeg", Arguments = $"-f lavfi -i anullsrc=r=44100:cl=mono -t 1 -y {testWavPath}", UseShellExecute = false, CreateNoWindow = true, RedirectStandardError = true, RedirectStandardOutput = true }; var proc = Process.Start(pInfo); proc?.WaitForExit(); if (!File.Exists(testWavPath)) { AnsiConsole.MarkupLine("[red]Failed to generate test audio file using ffmpeg.[/]"); return; } var groq = new GroqApiClient(config.GroqApiKey); try { await AnsiConsole.Status() .StartAsync("Running latency test...", async ctx => { ctx.Status("Testing STT (Whisper)..."); var sttWatch = Stopwatch.StartNew(); var transcript = await groq.TranscribeAsync(testWavPath, config.WhisperLanguage, config.WhisperModel); sttWatch.Stop(); ctx.Status("Testing LLM (Llama)..."); var systemPrompt = PromptBuilder.BuildPrompt(config); var llmWatch = Stopwatch.StartNew(); var refinedText = await groq.RefineTextAsync("Hello world, this is a latency test.", systemPrompt, config.LlmModel); llmWatch.Stop(); var total = sttWatch.ElapsedMilliseconds + llmWatch.ElapsedMilliseconds; AnsiConsole.WriteLine(); var table = new Table(); table.AddColumn("Operation"); table.AddColumn("Latency (ms)"); table.AddRow("STT", sttWatch.ElapsedMilliseconds.ToString()); table.AddRow("LLM", llmWatch.ElapsedMilliseconds.ToString()); table.AddRow("[bold]Total[/]", $"[bold]{total}ms[/]"); AnsiConsole.Write(table); if (total < 1500) { AnsiConsole.MarkupLine($"[green]Status: OK (under 1.5s target). Total time: {(total / 1000.0):0.0}s.[/]"); } else { AnsiConsole.MarkupLine($"[yellow]Status: SLOW (over 1.5s target). Total time: {(total / 1000.0):0.0}s.[/]"); } }); } catch (Exception ex) { AnsiConsole.MarkupLine($"[red]Error during test: {ex.Message}[/]"); } finally { if (File.Exists(testWavPath)) File.Delete(testWavPath); } } }