diff --git a/tasks/prd.jsonc b/tasks/prd.jsonc new file mode 100644 index 0000000..aa3da2b --- /dev/null +++ b/tasks/prd.jsonc @@ -0,0 +1,266 @@ +{ + "project": "hyprvoice LLM Post-Processing", + "description": "Add LLM post-processing phase with unified provider system, TUI configure command, and configurable cleanup options", + "issue": "https://github.com/LeonardoTrapani/hyprvoice/issues/4", + "tasks": [ + { + "title": "Create Provider interface and registry", + "steps": [ + "Create new package internal/provider", + "Define Provider interface: Name(), RequiresAPIKey(), ValidateAPIKey(key), SupportsTranscription(), SupportsLLM(), DefaultTranscriptionModel(), DefaultLLMModel(), TranscriptionModels(), LLMModels()", + "Create ProviderConfig struct with APIKey field", + "Implement OpenAIProvider: transcription (whisper-1) + LLM (gpt-4o-mini)", + "Implement GroqProvider: transcription (whisper-large-v3, turbo) + LLM (llama-3.3-70b-versatile)", + "Implement MistralProvider: transcription only (voxtral-mini-latest)", + "Implement ElevenLabsProvider: transcription only (scribe_v1, scribe_v2)", + "Create GetProvider(name) and ListProviders() functions", + "Create ListProvidersWithLLM() and ListProvidersWithTranscription() helpers" + ], + "verify": [ + "All providers implement the interface", + "GetProvider returns correct provider for each name", + "Capability methods return correct values", + "Typecheck passes" + ], + "passes": false + }, + { + "title": "Refactor config to unified provider structure", + "steps": [ + "Add Providers map[string]ProviderConfig to Config struct", + "Add global Keywords []string field to Config", + "Remove api_key from TranscriptionConfig, keep provider/model/language", + "Add LLMConfig with Enabled (default true), Provider, Model", + "Add LLMPostProcessingConfig: RemoveStutters, AddPunctuation, FixGrammar, RemoveFillerWords (all default true)", + "Add LLMCustomPromptConfig: Enabled, Prompt", + "Add migration in Load() to detect old format (transcription.api_key) and convert to providers map", + "Migration logs: 'Config migrated. Run hyprvoice configure to update format.'", + "Update ToTranscriberConfig() to resolve API key from Providers", + "Add ToLLMConfig() method", + "Environment variables still work as fallback" + ], + "verify": [ + "Old config with transcription.api_key still loads (backward compatible)", + "New config with [providers.openai] works", + "Environment variable fallback works", + "Migration logs warning", + "Typecheck passes", + "go test ./internal/config/... passes" + ], + "passes": false + }, + { + "title": "Create LLM adapter interface and implementations", + "steps": [ + "Create internal/llm package", + "Define LLMAdapter interface: Process(ctx, text) (string, error)", + "Define Config struct with all options", + "Create prompt.go with BuildSystemPrompt(opts, keywords) and BuildUserPrompt(text, customPrompt)", + "Implement OpenAIAdapter using chat completions API", + "Implement GroqAdapter using Groq API (OpenAI-compatible)", + "Create NewAdapter(config) factory function" + ], + "verify": [ + "Both adapters implement interface", + "Prompt builder generates correct prompts", + "Factory returns correct adapter", + "Typecheck passes" + ], + "passes": false + }, + { + "title": "Integrate LLM phase into pipeline", + "steps": [ + "Update internal/pipeline/pipeline.go", + "After transcription, check if LLM enabled", + "If enabled, create adapter and process text", + "Use processed text for injection", + "On failure, fall back to raw text with warning", + "Add LLM processing notification" + ], + "verify": [ + "Pipeline unchanged when LLM disabled", + "LLM processes text when enabled", + "Graceful fallback on LLM error", + "Typecheck passes" + ], + "passes": false + }, + { + "title": "Pass keywords to transcription adapters", + "steps": [ + "Add Keywords []string to transcriber.Config", + "Update ToTranscriberConfig() to pass keywords", + "OpenAI transcriber uses keywords in initial_prompt", + "Groq transcriber uses keywords in prompt parameter", + "Other transcribers ignore if unsupported" + ], + "verify": [ + "Keywords passed to transcription", + "OpenAI includes in request", + "Non-supporting transcribers still work", + "Typecheck passes" + ], + "passes": false + }, + { + "title": "Add TUI dependencies and base components", + "steps": [ + "Run: go get github.com/charmbracelet/bubbletea github.com/charmbracelet/lipgloss github.com/charmbracelet/huh", + "Create internal/tui package", + "Create styles.go with lipgloss styles: header, label, success, error, muted, highlight, selected", + "Create theme.go with color scheme matching hyprvoice branding" + ], + "verify": [ + "Dependencies in go.mod", + "Styles render in terminal", + "Typecheck passes" + ], + "passes": false + }, + { + "title": "Create TUI configure - fresh install flow", + "steps": [ + "Create internal/tui/configure.go with Run() function", + "Welcome screen with hyprvoice ASCII/branding", + "Provider selection: multi-select which to configure (OpenAI, Groq, Mistral, ElevenLabs)", + "For each selected: API key input with password mask", + "Transcription: provider dropdown (only configured + supports transcription), model dropdown", + "LLM: 'Enable post-processing? (Recommended)' - defaults YES", + "If LLM yes: provider (only configured + supports LLM), model, post-processing toggles (all default true), custom prompt", + "Keywords: comma-separated input", + "Injection: backend multi-select with descriptions", + "Notifications: enable toggle", + "Summary screen with confirm" + ], + "verify": [ + "Fresh install walks through all steps", + "Only shows providers user selected for API keys", + "Transcription only shows configured + capable providers", + "LLM defaults to enabled, Yes is recommended", + "Typecheck passes" + ], + "passes": false + }, + { + "title": "Create TUI configure - edit existing flow", + "steps": [ + "Detect if config exists and has user changes", + "Show section picker: 'What to configure?' multi-select", + "Sections: Providers, Transcription, LLM, Keywords, Injection, Notifications, Full Setup", + "For each section, show only that form", + "Smart provider detection: if user picks unconfigured provider, prompt for API key", + "If provider already configured, show 'Using existing key' (no re-prompt unless in Providers section)", + "Merge with existing config, preserve unedited sections" + ], + "verify": [ + "Existing config shows section picker", + "Single section only edits that section", + "Unconfigured provider triggers key prompt", + "Configured providers don't re-prompt", + "Unedited sections preserved", + "Typecheck passes" + ], + "passes": false + }, + { + "title": "Replace old configure with TUI", + "steps": [ + "Update cmd/hyprvoice/main.go configureCmd to call tui.Run()", + "Remove runInteractiveConfig and related helpers (maskAPIKey, formatBackends, etc.)", + "Update saveConfig to write new TOML structure with [providers.X]", + "Ensure validation before save", + "Show next steps after successful save" + ], + "verify": [ + "hyprvoice configure launches TUI", + "Old code removed", + "Saved config valid TOML with new structure", + "Typecheck passes" + ], + "passes": false + }, + { + "title": "Update default config template", + "steps": [ + "Update SaveDefaultConfig() in config.go", + "Add [providers.openai] and [providers.groq] sections", + "Add keywords = [] global", + "Add [llm] with enabled = true, provider, model", + "Add [llm.post_processing] all true", + "Add [llm.custom_prompt] enabled = false", + "Clear comments explaining structure", + "Add migration note about old format" + ], + "verify": [ + "Default config valid TOML", + "LLM enabled by default", + "Post-processing all true by default", + "Comments clear", + "Typecheck passes" + ], + "passes": false + }, + { + "title": "Add LLM processing notification", + "steps": [ + "Add MsgLLMProcessing to notify types", + "Default: title='Hyprvoice', body='Processing...'", + "Add to MessagesConfig", + "Trigger when LLM starts", + "Make configurable" + ], + "verify": [ + "Type defined", + "Notification appears", + "Configurable in config", + "Typecheck passes" + ], + "passes": false + }, + { + "title": "Update README documentation", + "steps": [ + "Add '## LLM Post-Processing' section", + "Document unified provider structure with examples", + "Document post-processing options", + "Document custom prompt with use cases", + "Document keywords (helps transcription + LLM)", + "Example configs for common setups", + "Document migration from old format", + "Note LLM enabled by default" + ], + "verify": [ + "README clear", + "Examples valid TOML", + "Migration documented", + "Keywords explained" + ], + "passes": false + }, + { + "title": "End-to-end testing", + "steps": [ + "Test old config loads (backward compatible)", + "Test new config works", + "Test LLM enabled by default improves output", + "Test LLM can be disabled", + "Test each post-processing option", + "Test custom prompt", + "Test keywords in transcription", + "Test TUI fresh install flow", + "Test TUI edit existing flow", + "Test smart provider detection", + "Test config hot-reload" + ], + "verify": [ + "Old configs work unchanged", + "New configs work", + "LLM improves text quality", + "TUI flows intuitive and state-aware", + "No regressions" + ], + "passes": false + } + ] +}