183 lines
8.2 KiB
C#
183 lines
8.2 KiB
C#
using System.Diagnostics;
|
|
using Spectre.Console;
|
|
using Toak.Configuration;
|
|
using Toak.Core.Skills;
|
|
|
|
namespace Toak.Commands;
|
|
|
|
public static class OnboardCommand
|
|
{
|
|
public static async Task ExecuteAsync(bool verbose)
|
|
{
|
|
Core.Logger.Verbose = verbose;
|
|
var configManager = new ConfigManager();
|
|
var config = configManager.LoadConfig();
|
|
|
|
AnsiConsole.Write(new FigletText("Toak").Color(Color.Green));
|
|
AnsiConsole.MarkupLine("[grey]Welcome to the Toak configuration wizard.[/]");
|
|
AnsiConsole.WriteLine();
|
|
|
|
config.LlmProvider = AnsiConsole.Prompt(
|
|
new SelectionPrompt<string>()
|
|
.Title("Select [green]LLM Provider[/]:")
|
|
.AddChoices(new[] { "groq", "together", "cerebras", "fireworks" })
|
|
.UseConverter(c => c == "groq" ? "Groq (Default)" : c == "together" ? "Together AI" : c == "cerebras" ? "Cerebras" : "Fireworks AI"));
|
|
|
|
if (config.LlmProvider == "together")
|
|
{
|
|
config.TogetherApiKey = AnsiConsole.Prompt(
|
|
new TextPrompt<string>("Together AI API Key:")
|
|
.DefaultValue(string.IsNullOrWhiteSpace(config.TogetherApiKey) ? "" : config.TogetherApiKey)
|
|
.AllowEmpty());
|
|
|
|
config.LlmModel = AnsiConsole.Prompt(
|
|
new SelectionPrompt<string>()
|
|
.Title("Select [green]LLM Model[/]:")
|
|
.AddChoices(new[] { "meta-llama/Llama-3.3-70B-Instruct-Turbo", "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", "openai/gpt-oss-20b" }));
|
|
}
|
|
else if (config.LlmProvider == "cerebras")
|
|
{
|
|
config.CerebrasApiKey = AnsiConsole.Prompt(
|
|
new TextPrompt<string>("Cerebras API Key:")
|
|
.DefaultValue(string.IsNullOrWhiteSpace(config.CerebrasApiKey) ? "" : config.CerebrasApiKey)
|
|
.AllowEmpty());
|
|
|
|
config.LlmModel = AnsiConsole.Prompt(
|
|
new SelectionPrompt<string>()
|
|
.Title("Select [green]LLM Model[/]:")
|
|
.AddChoices(new[] { "llama3.1-8b", "gpt-oss-120b" }));
|
|
}
|
|
else if (config.LlmProvider == "fireworks")
|
|
{
|
|
config.FireworksApiKey = AnsiConsole.Prompt(
|
|
new TextPrompt<string>("Fireworks API Key:")
|
|
.DefaultValue(string.IsNullOrWhiteSpace(config.FireworksApiKey) ? "" : config.FireworksApiKey)
|
|
.AllowEmpty());
|
|
|
|
config.LlmModel = AnsiConsole.Prompt(
|
|
new SelectionPrompt<string>()
|
|
.Title("Select [green]LLM Model[/]:")
|
|
.AddChoices(new[] { "accounts/fireworks/models/deepseek-v3p1", "fireworks/gpt-oss-120b", "fireworks/deepseek-v3p2", "fireworks/qwen3-8b", "fireworks/minimax-m2p5" })
|
|
.UseConverter(c => c.Split('/').Last()));
|
|
}
|
|
else
|
|
{
|
|
config.GroqApiKey = AnsiConsole.Prompt(
|
|
new TextPrompt<string>("Groq API Key:")
|
|
.DefaultValue(string.IsNullOrWhiteSpace(config.GroqApiKey) ? "" : config.GroqApiKey)
|
|
.AllowEmpty());
|
|
|
|
config.LlmModel = AnsiConsole.Prompt(
|
|
new SelectionPrompt<string>()
|
|
.Title("Select [green]LLM Model[/]:")
|
|
.AddChoices(new[] { "openai/gpt-oss-20b", "llama-3.1-8b-instant", "llama-3.3-70b-versatile" })
|
|
.UseConverter(c => c == "openai/gpt-oss-20b" ? "openai/gpt-oss-20b (Fastest)" : c == "llama-3.1-8b-instant" ? "llama-3.1-8b-instant (Cheapest)" : "llama-3.3-70b-versatile (More Accurate)"));
|
|
|
|
if (config.LlmModel.Contains(" ")) config.LlmModel = config.LlmModel.Split(' ')[0];
|
|
}
|
|
|
|
config.ReasoningEffort = AnsiConsole.Prompt(
|
|
new SelectionPrompt<string>()
|
|
.Title("Select [green]Reasoning Effort[/]:")
|
|
.AddChoices(new[] { "none", "low" })
|
|
.UseConverter(c => c == "none" ? "None (Standard)" : "Low (Moderate Reasoning)"));
|
|
|
|
config.WhisperProvider = AnsiConsole.Prompt(
|
|
new SelectionPrompt<string>()
|
|
.Title("Select [green]Whisper Provider[/]:")
|
|
.AddChoices(new[] { "groq", "fireworks" })
|
|
.UseConverter(c => c == "groq" ? "Groq (Default)" : "Fireworks AI"));
|
|
|
|
if (config.WhisperProvider == "fireworks")
|
|
{
|
|
if (string.IsNullOrWhiteSpace(config.FireworksApiKey))
|
|
{
|
|
config.FireworksApiKey = AnsiConsole.Prompt(
|
|
new TextPrompt<string>("Fireworks API Key (required for Whisper):")
|
|
.DefaultValue("")
|
|
.AllowEmpty());
|
|
}
|
|
|
|
config.WhisperModel = AnsiConsole.Prompt(
|
|
new SelectionPrompt<string>()
|
|
.Title("Select [green]Whisper Model[/]:")
|
|
.AddChoices(new[] { "fireworks/whisper-v3", "fireworks/whisper-v3-turbo" }));
|
|
}
|
|
else
|
|
{
|
|
if (string.IsNullOrWhiteSpace(config.GroqApiKey))
|
|
{
|
|
config.GroqApiKey = AnsiConsole.Prompt(
|
|
new TextPrompt<string>("Groq API Key (required for Whisper):")
|
|
.DefaultValue("")
|
|
.AllowEmpty());
|
|
}
|
|
|
|
config.WhisperModel = AnsiConsole.Prompt(
|
|
new SelectionPrompt<string>()
|
|
.Title("Select [green]Whisper Model[/]:")
|
|
.AddChoices(new[] { "whisper-large-v3", "whisper-large-v3-turbo" })
|
|
.UseConverter(c => c == "whisper-large-v3" ? "whisper-large-v3 (Accurate)" : "whisper-large-v3-turbo (Fast)"));
|
|
}
|
|
|
|
config.WhisperLanguage = AnsiConsole.Prompt(
|
|
new TextPrompt<string>("Microphone Spoken Language (e.g. en, es, zh):")
|
|
.DefaultValue(string.IsNullOrWhiteSpace(config.WhisperLanguage) ? "en" : config.WhisperLanguage)
|
|
.AllowEmpty()
|
|
.Validate(lang =>
|
|
{
|
|
if (string.IsNullOrWhiteSpace(lang)) return ValidationResult.Success();
|
|
if (lang.Contains(",") || lang.Contains(" "))
|
|
return ValidationResult.Error("[red]Please provide only one language code (e.g., 'en' not 'en, es')[/]");
|
|
|
|
return ValidationResult.Success();
|
|
}));
|
|
|
|
var sessionType = Environment.GetEnvironmentVariable("XDG_SESSION_TYPE")?.ToLowerInvariant();
|
|
var typingBackends = sessionType == "wayland" ? new[] { "wtype", "ydotool", "xdotool" } : new[] { "xdotool", "ydotool" };
|
|
|
|
config.TypingBackend = AnsiConsole.Prompt(
|
|
new SelectionPrompt<string>()
|
|
.Title($"Select [green]Typing Backend[/] (Detected: {sessionType}):")
|
|
.AddChoices(typingBackends));
|
|
|
|
config.AudioBackend = AnsiConsole.Prompt(
|
|
new SelectionPrompt<string>()
|
|
.Title("Select [green]Audio Recording Backend[/]:")
|
|
.AddChoices(new[] { "pw-record", "ffmpeg" })
|
|
.UseConverter(c => c == "pw-record" ? "pw-record (Default PipeWire)" : "ffmpeg (Universal PulseAudio)"));
|
|
|
|
var availableSkills = SkillRegistry.AllSkills.Select(s => s.Name).ToList();
|
|
|
|
if (availableSkills.Any())
|
|
{
|
|
config.ActiveSkills = AnsiConsole.Prompt(
|
|
new MultiSelectionPrompt<string>()
|
|
.Title("Select [green]Active Skills[/]:")
|
|
.NotRequired()
|
|
.InstructionsText("[grey](Press [blue]<space>[/] to toggle a skill, [green]<enter>[/] to accept)[/]")
|
|
.AddChoices(availableSkills));
|
|
}
|
|
|
|
configManager.SaveConfig(config);
|
|
|
|
AnsiConsole.MarkupLine("\n[bold green]Configuration saved successfully![/]");
|
|
|
|
try
|
|
{
|
|
var processInfo = new ProcessStartInfo("systemctl", "--user restart toak.service")
|
|
{
|
|
CreateNoWindow = true,
|
|
UseShellExecute = false
|
|
};
|
|
Process.Start(processInfo)?.WaitForExit();
|
|
AnsiConsole.MarkupLine("[grey]Restarted Toak daemon service.[/]");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Core.Logger.LogDebug($"Failed to restart toak service: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
|