feat: better onboarding
This commit is contained in:
+10
-4
@@ -124,7 +124,9 @@ func cancelCmd() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func configureCmd() *cobra.Command {
|
func configureCmd() *cobra.Command {
|
||||||
return &cobra.Command{
|
var onboarding bool
|
||||||
|
|
||||||
|
cmd := &cobra.Command{
|
||||||
Use: "configure",
|
Use: "configure",
|
||||||
Short: "Interactive configuration setup",
|
Short: "Interactive configuration setup",
|
||||||
Long: `Interactive configuration wizard for hyprvoice.
|
Long: `Interactive configuration wizard for hyprvoice.
|
||||||
@@ -134,12 +136,16 @@ This will guide you through setting up:
|
|||||||
- LLM post-processing
|
- LLM post-processing
|
||||||
- Text injection and notification preferences`,
|
- Text injection and notification preferences`,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return runConfigure()
|
return runConfigure(onboarding)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.Flags().BoolVar(&onboarding, "onboarding", false, "Run the guided onboarding wizard")
|
||||||
|
|
||||||
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runConfigure() error {
|
func runConfigure(onboarding bool) error {
|
||||||
// Load existing config or create default
|
// Load existing config or create default
|
||||||
cfg, err := config.Load()
|
cfg, err := config.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -147,7 +153,7 @@ func runConfigure() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run TUI wizard
|
// Run TUI wizard
|
||||||
result, err := tui.Run(cfg)
|
result, err := tui.Run(cfg, onboarding)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("configuration wizard error: %w", err)
|
return fmt.Errorf("configuration wizard error: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,11 +43,19 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Run starts the TUI configuration wizard
|
// Run starts the TUI configuration wizard
|
||||||
func Run(existingConfig *config.Config) (*ConfigureResult, error) {
|
// If onboarding is true, forces the guided wizard flow even if config exists
|
||||||
if existingConfig != nil && hasUserChanges(existingConfig) {
|
func Run(existingConfig *config.Config, onboarding bool) (*ConfigureResult, error) {
|
||||||
|
if !onboarding && existingConfig != nil && hasUserChanges(existingConfig) {
|
||||||
return runEditExisting(existingConfig)
|
return runEditExisting(existingConfig)
|
||||||
}
|
}
|
||||||
return runFreshInstall(existingConfig)
|
|
||||||
|
result, err := runFreshInstall(existingConfig)
|
||||||
|
if err != nil || result.Cancelled {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// wizard done, transition to menu for review/save
|
||||||
|
return runEditExisting(result.Config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasUserChanges detects if config has user modifications
|
// hasUserChanges detects if config has user modifications
|
||||||
@@ -92,7 +100,7 @@ func runEditExisting(cfg *config.Config) (*ConfigureResult, error) {
|
|||||||
return &ConfigureResult{Cancelled: true}, nil
|
return &ConfigureResult{Cancelled: true}, nil
|
||||||
|
|
||||||
case SectionProviders:
|
case SectionProviders:
|
||||||
if err := editProviders(cfg); err != nil {
|
if err := editProviders(cfg, false); err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
configuredProviders = getConfiguredProviders(cfg)
|
configuredProviders = getConfiguredProviders(cfg)
|
||||||
@@ -131,7 +139,7 @@ func runEditExisting(cfg *config.Config) (*ConfigureResult, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case SectionAdvanced:
|
case SectionAdvanced:
|
||||||
if err := editAdvanced(cfg); err != nil {
|
if err := editAdvanced(cfg, false); err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,12 +19,16 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// editAdvanced handles the advanced settings submenu
|
// editAdvanced handles the advanced settings submenu
|
||||||
func editAdvanced(cfg *config.Config) error {
|
func editAdvanced(cfg *config.Config, onboarding bool) error {
|
||||||
|
exitLabel := "Done"
|
||||||
|
if onboarding {
|
||||||
|
exitLabel = "Next"
|
||||||
|
}
|
||||||
for {
|
for {
|
||||||
options := []huh.Option[AdvancedSection]{
|
options := []huh.Option[AdvancedSection]{
|
||||||
huh.NewOption(formatAdvancedRecordingLabel(cfg), AdvancedRecording),
|
huh.NewOption(formatAdvancedRecordingLabel(cfg), AdvancedRecording),
|
||||||
huh.NewOption(formatAdvancedInjectionTimeoutLabel(cfg), AdvancedInjectionTimeout),
|
huh.NewOption(formatAdvancedInjectionTimeoutLabel(cfg), AdvancedInjectionTimeout),
|
||||||
huh.NewOption("Back to Main Menu", AdvancedBack),
|
huh.NewOption(exitLabel, AdvancedBack),
|
||||||
}
|
}
|
||||||
|
|
||||||
var selected AdvancedSection
|
var selected AdvancedSection
|
||||||
|
|||||||
@@ -291,154 +291,3 @@ func selectPostProcessingOptions(current config.LLMPostProcessingConfig) (config
|
|||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureLLM(configuredProviders []string, cfg *config.Config) (bool, string, string, config.LLMPostProcessingConfig, config.LLMCustomPromptConfig, error) {
|
|
||||||
var llmProviders []string
|
|
||||||
for _, name := range configuredProviders {
|
|
||||||
p := provider.GetProvider(name)
|
|
||||||
if p != nil && p.SupportsLLM() {
|
|
||||||
llmProviders = append(llmProviders, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
postProcessing := config.LLMPostProcessingConfig{
|
|
||||||
RemoveStutters: true,
|
|
||||||
AddPunctuation: true,
|
|
||||||
FixGrammar: true,
|
|
||||||
RemoveFillerWords: true,
|
|
||||||
}
|
|
||||||
customPrompt := config.LLMCustomPromptConfig{
|
|
||||||
Enabled: false,
|
|
||||||
Prompt: "",
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(llmProviders) == 0 {
|
|
||||||
return false, "", "", postProcessing, customPrompt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var enableLLM bool = true
|
|
||||||
enableForm := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewConfirm().
|
|
||||||
Title("Enable LLM Post-Processing? (Recommended)").
|
|
||||||
Description("LLM improves transcription by fixing grammar, removing stutters, and cleaning up text").
|
|
||||||
Affirmative("Yes (Recommended)").
|
|
||||||
Negative("No").
|
|
||||||
Value(&enableLLM),
|
|
||||||
),
|
|
||||||
).WithTheme(getTheme())
|
|
||||||
|
|
||||||
if err := enableForm.Run(); err != nil {
|
|
||||||
return false, "", "", postProcessing, customPrompt, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !enableLLM {
|
|
||||||
return false, "", "", postProcessing, customPrompt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var llmOptions []huh.Option[string]
|
|
||||||
for _, name := range llmProviders {
|
|
||||||
p := provider.GetProvider(name)
|
|
||||||
if p != nil {
|
|
||||||
switch name {
|
|
||||||
case "openai":
|
|
||||||
llmOptions = append(llmOptions, huh.NewOption("OpenAI GPT", "openai"))
|
|
||||||
case "groq":
|
|
||||||
llmOptions = append(llmOptions, huh.NewOption("Groq Llama (fast)", "groq"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var selectedProvider string
|
|
||||||
if cfg.LLM.Provider != "" {
|
|
||||||
selectedProvider = cfg.LLM.Provider
|
|
||||||
} else if len(llmOptions) > 0 {
|
|
||||||
selectedProvider = llmOptions[0].Value
|
|
||||||
}
|
|
||||||
|
|
||||||
providerForm := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewSelect[string]().
|
|
||||||
Title("LLM Provider").
|
|
||||||
Description("Choose which service to use for text post-processing").
|
|
||||||
Options(llmOptions...).
|
|
||||||
Value(&selectedProvider),
|
|
||||||
),
|
|
||||||
).WithTheme(getTheme())
|
|
||||||
|
|
||||||
if err := providerForm.Run(); err != nil {
|
|
||||||
return false, "", "", postProcessing, customPrompt, err
|
|
||||||
}
|
|
||||||
|
|
||||||
modelOptions := getLLMModelOptions(selectedProvider)
|
|
||||||
var selectedModel string
|
|
||||||
if cfg.LLM.Model != "" {
|
|
||||||
selectedModel = cfg.LLM.Model
|
|
||||||
} else if len(modelOptions) > 0 {
|
|
||||||
selectedModel = modelOptions[0].Value
|
|
||||||
}
|
|
||||||
|
|
||||||
modelForm := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewSelect[string]().
|
|
||||||
Title("LLM Model").
|
|
||||||
Options(modelOptions...).
|
|
||||||
Value(&selectedModel),
|
|
||||||
),
|
|
||||||
).WithTheme(getTheme())
|
|
||||||
|
|
||||||
if err := modelForm.Run(); err != nil {
|
|
||||||
return false, "", "", postProcessing, customPrompt, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.LLM.PostProcessing.RemoveStutters || cfg.LLM.PostProcessing.AddPunctuation ||
|
|
||||||
cfg.LLM.PostProcessing.FixGrammar || cfg.LLM.PostProcessing.RemoveFillerWords {
|
|
||||||
postProcessing = cfg.LLM.PostProcessing
|
|
||||||
}
|
|
||||||
|
|
||||||
var ppErr error
|
|
||||||
postProcessing, ppErr = selectPostProcessingOptions(postProcessing)
|
|
||||||
if ppErr != nil {
|
|
||||||
return false, "", "", postProcessing, customPrompt, ppErr
|
|
||||||
}
|
|
||||||
|
|
||||||
var enableCustomPrompt bool
|
|
||||||
var customPromptText string
|
|
||||||
if cfg.LLM.CustomPrompt.Enabled {
|
|
||||||
enableCustomPrompt = true
|
|
||||||
customPromptText = cfg.LLM.CustomPrompt.Prompt
|
|
||||||
}
|
|
||||||
|
|
||||||
customForm := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewConfirm().
|
|
||||||
Title("Add custom prompt?").
|
|
||||||
Description("Add extra instructions for the LLM").
|
|
||||||
Value(&enableCustomPrompt),
|
|
||||||
),
|
|
||||||
).WithTheme(getTheme())
|
|
||||||
|
|
||||||
if err := customForm.Run(); err != nil {
|
|
||||||
return false, "", "", postProcessing, customPrompt, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if enableCustomPrompt {
|
|
||||||
promptForm := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewText().
|
|
||||||
Title("Custom Prompt").
|
|
||||||
Description("Additional instructions (e.g., 'Format as bullet points')").
|
|
||||||
Value(&customPromptText).
|
|
||||||
CharLimit(500),
|
|
||||||
),
|
|
||||||
).WithTheme(getTheme())
|
|
||||||
|
|
||||||
if err := promptForm.Run(); err != nil {
|
|
||||||
return false, "", "", postProcessing, customPrompt, err
|
|
||||||
}
|
|
||||||
customPrompt.Enabled = true
|
|
||||||
customPrompt.Prompt = customPromptText
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, selectedProvider, selectedModel, postProcessing, customPrompt, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -36,13 +36,17 @@ func getConfiguredProviders(cfg *config.Config) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// editProviders handles the providers section edit with submenu
|
// editProviders handles the providers section edit with submenu
|
||||||
func editProviders(cfg *config.Config) error {
|
func editProviders(cfg *config.Config, onboarding bool) error {
|
||||||
|
exitLabel := "Done"
|
||||||
|
if onboarding {
|
||||||
|
exitLabel = "Next"
|
||||||
|
}
|
||||||
for {
|
for {
|
||||||
var options []huh.Option[string]
|
var options []huh.Option[string]
|
||||||
for _, name := range AllProviders {
|
for _, name := range AllProviders {
|
||||||
options = append(options, huh.NewOption(formatProviderOption(cfg, name), name))
|
options = append(options, huh.NewOption(formatProviderOption(cfg, name), name))
|
||||||
}
|
}
|
||||||
options = append(options, huh.NewOption("Back", "back"))
|
options = append(options, huh.NewOption(exitLabel, "back"))
|
||||||
|
|
||||||
var selected string
|
var selected string
|
||||||
form := huh.NewForm(
|
form := huh.NewForm(
|
||||||
|
|||||||
@@ -165,85 +165,3 @@ func getTranscriptionModelOptions(provider string) []huh.Option[string] {
|
|||||||
return []huh.Option[string]{}
|
return []huh.Option[string]{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureTranscription(configuredProviders []string, cfg *config.Config) (string, string, string, error) {
|
|
||||||
var transcriptionOptions []huh.Option[string]
|
|
||||||
for _, name := range configuredProviders {
|
|
||||||
p := provider.GetProvider(name)
|
|
||||||
if p != nil && p.SupportsTranscription() {
|
|
||||||
switch name {
|
|
||||||
case "openai":
|
|
||||||
transcriptionOptions = append(transcriptionOptions,
|
|
||||||
huh.NewOption("OpenAI Whisper", "openai"))
|
|
||||||
case "groq":
|
|
||||||
transcriptionOptions = append(transcriptionOptions,
|
|
||||||
huh.NewOption("Groq Whisper (transcription)", "groq-transcription"),
|
|
||||||
huh.NewOption("Groq Whisper (translate to English)", "groq-translation"))
|
|
||||||
case "mistral":
|
|
||||||
transcriptionOptions = append(transcriptionOptions,
|
|
||||||
huh.NewOption("Mistral Voxtral", "mistral-transcription"))
|
|
||||||
case "elevenlabs":
|
|
||||||
transcriptionOptions = append(transcriptionOptions,
|
|
||||||
huh.NewOption("ElevenLabs Scribe", "elevenlabs"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(transcriptionOptions) == 0 {
|
|
||||||
return "", "", "", fmt.Errorf("no transcription-capable providers configured")
|
|
||||||
}
|
|
||||||
|
|
||||||
var selectedProvider string
|
|
||||||
if cfg.Transcription.Provider != "" {
|
|
||||||
selectedProvider = cfg.Transcription.Provider
|
|
||||||
} else if len(transcriptionOptions) > 0 {
|
|
||||||
selectedProvider = transcriptionOptions[0].Value
|
|
||||||
}
|
|
||||||
|
|
||||||
providerForm := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewSelect[string]().
|
|
||||||
Title("Transcription Provider").
|
|
||||||
Description("Choose which service to use for speech-to-text").
|
|
||||||
Options(transcriptionOptions...).
|
|
||||||
Value(&selectedProvider),
|
|
||||||
),
|
|
||||||
).WithTheme(getTheme())
|
|
||||||
|
|
||||||
if err := providerForm.Run(); err != nil {
|
|
||||||
return "", "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
modelOptions := getTranscriptionModelOptions(selectedProvider)
|
|
||||||
var selectedModel string
|
|
||||||
if cfg.Transcription.Model != "" {
|
|
||||||
selectedModel = cfg.Transcription.Model
|
|
||||||
} else if len(modelOptions) > 0 {
|
|
||||||
selectedModel = modelOptions[0].Value
|
|
||||||
}
|
|
||||||
|
|
||||||
var language string
|
|
||||||
if cfg.Transcription.Language != "" {
|
|
||||||
language = cfg.Transcription.Language
|
|
||||||
}
|
|
||||||
|
|
||||||
modelForm := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewSelect[string]().
|
|
||||||
Title("Transcription Model").
|
|
||||||
Options(modelOptions...).
|
|
||||||
Value(&selectedModel),
|
|
||||||
huh.NewInput().
|
|
||||||
Title("Language").
|
|
||||||
Description("ISO-639-1 code (e.g., 'en', 'es', 'fr') or empty for auto-detect").
|
|
||||||
Placeholder("auto-detect").
|
|
||||||
Value(&language),
|
|
||||||
),
|
|
||||||
).WithTheme(getTheme())
|
|
||||||
|
|
||||||
if err := modelForm.Run(); err != nil {
|
|
||||||
return "", "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return selectedProvider, selectedModel, language, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,111 +8,68 @@ import (
|
|||||||
"github.com/leonardotrapani/hyprvoice/internal/config"
|
"github.com/leonardotrapani/hyprvoice/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// runFreshInstall runs the full configuration wizard for fresh installs
|
// runFreshInstall runs the guided onboarding flow for fresh installs
|
||||||
|
// Uses the same screens as the menu for consistency
|
||||||
func runFreshInstall(cfg *config.Config) (*ConfigureResult, error) {
|
func runFreshInstall(cfg *config.Config) (*ConfigureResult, error) {
|
||||||
fmt.Println(Logo())
|
fmt.Println(Logo())
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println(StyleMuted.Render("Voice-powered typing for Wayland/Hyprland"))
|
fmt.Println(StyleMuted.Render("Voice-powered typing for Wayland/Hyprland"))
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
selectedProviders, err := selectProviders()
|
// 1. Providers - same screen as menu
|
||||||
|
if err := editProviders(cfg, true); err != nil {
|
||||||
|
return &ConfigureResult{Cancelled: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
configuredProviders := getConfiguredProviders(cfg)
|
||||||
|
if len(configuredProviders) == 0 {
|
||||||
|
return &ConfigureResult{Cancelled: true}, fmt.Errorf("no providers configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Transcription - same screen as menu
|
||||||
|
var err error
|
||||||
|
configuredProviders, err = editTranscription(cfg, configuredProviders)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &ConfigureResult{Cancelled: true}, nil
|
return &ConfigureResult{Cancelled: true}, nil
|
||||||
}
|
}
|
||||||
if len(selectedProviders) == 0 {
|
|
||||||
return &ConfigureResult{Cancelled: true}, fmt.Errorf("no providers selected")
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.Providers == nil {
|
// 3. LLM - same screen as menu
|
||||||
cfg.Providers = make(map[string]config.ProviderConfig)
|
configuredProviders, err = editLLM(cfg, configuredProviders)
|
||||||
}
|
|
||||||
|
|
||||||
for _, providerName := range selectedProviders {
|
|
||||||
apiKey, err := inputAPIKey(providerName)
|
|
||||||
if err != nil {
|
|
||||||
return &ConfigureResult{Cancelled: true}, nil
|
|
||||||
}
|
|
||||||
cfg.Providers[providerName] = config.ProviderConfig{APIKey: apiKey}
|
|
||||||
}
|
|
||||||
|
|
||||||
transcriptionProvider, transcriptionModel, language, err := configureTranscription(selectedProviders, cfg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &ConfigureResult{Cancelled: true}, nil
|
return &ConfigureResult{Cancelled: true}, nil
|
||||||
}
|
}
|
||||||
cfg.Transcription.Provider = transcriptionProvider
|
|
||||||
cfg.Transcription.Model = transcriptionModel
|
|
||||||
cfg.Transcription.Language = language
|
|
||||||
|
|
||||||
llmEnabled, llmProvider, llmModel, postProcessing, customPrompt, err := configureLLM(selectedProviders, cfg)
|
|
||||||
if err != nil {
|
|
||||||
return &ConfigureResult{Cancelled: true}, nil
|
|
||||||
}
|
|
||||||
cfg.LLM.Enabled = llmEnabled
|
|
||||||
cfg.LLM.Provider = llmProvider
|
|
||||||
cfg.LLM.Model = llmModel
|
|
||||||
cfg.LLM.PostProcessing = postProcessing
|
|
||||||
cfg.LLM.CustomPrompt = customPrompt
|
|
||||||
|
|
||||||
|
// 4. Keywords
|
||||||
keywords, err := inputKeywords(cfg.Keywords)
|
keywords, err := inputKeywords(cfg.Keywords)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &ConfigureResult{Cancelled: true}, nil
|
return &ConfigureResult{Cancelled: true}, nil
|
||||||
}
|
}
|
||||||
cfg.Keywords = keywords
|
cfg.Keywords = keywords
|
||||||
|
|
||||||
|
// 5. Injection backends
|
||||||
backends, err := selectBackends(cfg.Injection.Backends)
|
backends, err := selectBackends(cfg.Injection.Backends)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &ConfigureResult{Cancelled: true}, nil
|
return &ConfigureResult{Cancelled: true}, nil
|
||||||
}
|
}
|
||||||
cfg.Injection.Backends = backends
|
cfg.Injection.Backends = backends
|
||||||
|
|
||||||
notificationsEnabled, err := configureNotifications(cfg.Notifications.Enabled)
|
// 6. Notifications - same screen as menu
|
||||||
|
if err := editNotifications(cfg); err != nil {
|
||||||
|
return &ConfigureResult{Cancelled: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Advanced settings prompt
|
||||||
|
wantAdvanced, err := askAdvancedSettings()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &ConfigureResult{Cancelled: true}, nil
|
return &ConfigureResult{Cancelled: true}, nil
|
||||||
}
|
}
|
||||||
cfg.Notifications.Enabled = notificationsEnabled
|
if wantAdvanced {
|
||||||
|
if err := editAdvanced(cfg, true); err != nil {
|
||||||
confirmed, err := showSummary(cfg)
|
return &ConfigureResult{Cancelled: true}, nil
|
||||||
if err != nil || !confirmed {
|
|
||||||
return &ConfigureResult{Cancelled: true}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ConfigureResult{Config: cfg, Cancelled: false}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func selectProviders() ([]string, error) {
|
|
||||||
options := []huh.Option[string]{
|
|
||||||
huh.NewOption("OpenAI - Whisper transcription + GPT for LLM", "openai"),
|
|
||||||
huh.NewOption("Groq - Fast Whisper transcription + Llama for LLM", "groq"),
|
|
||||||
huh.NewOption("Mistral - Voxtral transcription (European languages)", "mistral"),
|
|
||||||
huh.NewOption("ElevenLabs - Scribe transcription (99 languages)", "elevenlabs"),
|
|
||||||
}
|
|
||||||
|
|
||||||
var selected []string
|
|
||||||
form := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewMultiSelect[string]().
|
|
||||||
Title("Which providers do you want to configure?").
|
|
||||||
Description("Select all providers you have API keys for").
|
|
||||||
Options(options...).
|
|
||||||
Value(&selected),
|
|
||||||
),
|
|
||||||
).WithTheme(getTheme())
|
|
||||||
|
|
||||||
if err := form.Run(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
valid := make([]string, 0)
|
|
||||||
for _, s := range selected {
|
|
||||||
for _, p := range AllProviders {
|
|
||||||
if s == p {
|
|
||||||
valid = append(valid, s)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return valid, nil
|
return &ConfigureResult{Config: cfg, Cancelled: false}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func inputKeywords(existingKeywords []string) ([]string, error) {
|
func inputKeywords(existingKeywords []string) ([]string, error) {
|
||||||
@@ -186,28 +143,19 @@ func selectBackends(existingBackends []string) ([]string, error) {
|
|||||||
return selected, nil
|
return selected, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureNotifications(existingEnabled bool) (bool, error) {
|
func askAdvancedSettings() (bool, error) {
|
||||||
enabled := existingEnabled
|
var want bool
|
||||||
|
|
||||||
desc := "Show notifications for recording status changes"
|
|
||||||
if existingEnabled {
|
|
||||||
desc = "Currently: enabled. " + desc
|
|
||||||
} else {
|
|
||||||
desc = "Currently: disabled. " + desc
|
|
||||||
}
|
|
||||||
|
|
||||||
form := huh.NewForm(
|
form := huh.NewForm(
|
||||||
huh.NewGroup(
|
huh.NewGroup(
|
||||||
huh.NewConfirm().
|
huh.NewConfirm().
|
||||||
Title("Enable desktop notifications?").
|
Title("Configure advanced settings?").
|
||||||
Description(desc).
|
Description("Recording parameters, injection timeouts, etc.").
|
||||||
Value(&enabled),
|
Value(&want),
|
||||||
),
|
),
|
||||||
).WithTheme(getTheme())
|
).WithTheme(getTheme())
|
||||||
|
|
||||||
if err := form.Run(); err != nil {
|
if err := form.Run(); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
return want, nil
|
||||||
return enabled, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user