diff --git a/GPTEL_SETUP.md b/GPTEL_SETUP.md new file mode 100644 index 0000000..8adc7a4 --- /dev/null +++ b/GPTEL_SETUP.md @@ -0,0 +1,254 @@ +# gptel Configuration Guide + +## 🎉 What Was Configured + +Your Doom Emacs now has a comprehensive gptel setup with: + +### ✅ Installed Packages +1. **gptel** - Main LLM client +2. **gptel-quick** - Quick lookups in popup +3. **gptel-extensions** - Extra utility functions +4. **gptel-autocomplete** - Inline code completion + +### ✅ Configured Features +- ✨ OpenRouter backend with multiple models (Gemini, Claude) +- 📝 Org-mode as default (better for saving conversations) +- ⌨️ Comprehensive keybindings under `SPC a` prefix +- 🎨 5 task-specific presets (coder, explain, refactor, quick, docs) +- 🤖 Auto-completion in programming modes +- 🛠️ Custom helper functions for quick explanations and proofreading + +--- + +## 🔐 IMPORTANT: Secure Your API Key + +**⚠️ WARNING**: Your OpenRouter API key is currently hardcoded in `ai.el`. This is a security risk! + +### Recommended Setup: Use auth-source + +1. **Create encrypted credentials file:** + ```bash + touch ~/.authinfo.gpg + chmod 600 ~/.authinfo.gpg + ``` + +2. **Add your API key to `~/.authinfo.gpg`:** + ``` + machine openrouter.ai login apikey password sk-or-v1-YOUR_KEY_HERE + ``` + + Emacs will prompt for a password to encrypt this file. + +3. **Update `~/.config/doom/ai.el`:** + + Replace the `:key` line in the `gptel-make-openai` section: + ```elisp + ;; BEFORE (insecure): + :key "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" + + ;; AFTER (secure): + :key (auth-source-pick-first-password :host "openrouter.ai") + ``` + +4. **Reload Doom:** + ```bash + doom sync + ``` + +--- + +## ⌨️ Keybindings Reference + +All gptel commands are under `SPC a` (AI prefix): + +| Keybinding | Command | Description | +|------------|---------|-------------| +| `SPC a g` | `gptel` | Open gptel chat buffer | +| `SPC a s` | `gptel-send` | Send prompt to LLM | +| `SPC a m` | `gptel-menu` | Open transient menu (change model, backend, etc) | +| `SPC a r` | `gptel-rewrite` | Rewrite selected region with AI | +| `SPC a c` | `gptel-add` | Add region/buffer to context | +| `SPC a f` | `gptel-add-file` | Add file to context | +| `SPC a q` | `gptel-quick` | Quick lookup in popup (word/region) | +| `SPC a l` | Load buffer into session | Send whole buffer as context | +| `SPC a b` | Send whole buffer | Send entire buffer to AI | +| `SPC a R` | Refactor region | Refactor selected code | +| `SPC a e` | Quick explain | Explain selected code quickly | +| `SPC a p` | Proofread text | Fix grammar/spelling in selection | + +### In gptel buffer: +- `C-c RET` - Send message +- `C-c C-c` - Open menu +- `C-c C-k` - Abort request + +### Auto-completion (in programming modes): +- `M-TAB` or `C-c TAB` - Trigger completion + +--- + +## 🎨 Using Presets + +Presets let you switch AI behavior for specific tasks: + +1. Open gptel menu: `SPC a m` or `C-c C-c` +2. Select "Preset" option +3. Choose from: + - **coder** - Expert coding assistant (uses Claude Sonnet 4.5) + - **explain** - Explain code to beginners + - **refactor** - Code refactoring expert + - **quick** - Quick, concise answers (uses fast Gemini Flash) + - **docs** - Documentation writer + +Or use `C-u SPC a s` to adjust settings on-the-fly! + +--- + +## 🚀 Quick Start Workflows + +### 1. Chat with AI +``` +SPC a g → Opens gptel buffer +Type question → Write your prompt +C-c RET → Send (or SPC a s) +``` + +### 2. Rewrite Code +``` +1. Select code region (visual mode) +2. SPC a r +3. Type instruction: "Add error handling" +4. Review changes and accept +``` + +### 3. Add Context (Multi-file awareness) +``` +1. Open reference file +2. SPC a c (adds buffer to context) +3. Open gptel: SPC a g +4. Now AI knows about the reference file! +``` + +### 4. Quick Explanations +``` +1. Hover over word or select code +2. SPC a q +3. See explanation in popup! +``` + +### 5. Code Completion +``` +Start typing code... +M-TAB → Shows AI completion as ghost text +TAB → Accept completion +``` + +--- + +## 🏠 Local Models with Ollama (Optional) + +Want to run AI locally for privacy? + +1. **Install Ollama:** + ```bash + # Linux + curl -fsSL https://ollama.com/install.sh | sh + + # Start Ollama + ollama serve + ``` + +2. **Pull models:** + ```bash + ollama pull qwen2.5-coder:latest + ollama pull mistral:latest + ``` + +3. **Uncomment Ollama config in `ai.el`:** + + Look for the "Optional: Add Ollama" section around line 126 and uncomment: + ```elisp + (after! gptel + (gptel-make-ollama "Ollama" + :host "localhost:11434" + :stream t + :models '(qwen2.5-coder:latest + mistral:latest + llama3.2:latest))) + ``` + +4. **To make Ollama default**, uncomment lines 136-141 as well + +5. **Reload:** `doom sync` + +6. **Switch backends:** `SPC a m` → Select "Backend" → Choose "Ollama" + +--- + +## 🎯 Pro Tips + +1. **Save conversations**: gptel uses org-mode by default, so just save the buffer! + +2. **Switch models on-the-fly**: `C-u SPC a s` before sending + +3. **Context management**: + - Add files in Dired: Mark files → `SPC a c` + - Remove context: `SPC a m` → Manage context + +4. **Org-mode features**: + - Each heading can be a separate conversation branch + - Set properties: `M-x gptel-org-set-properties` + - Set topic: `M-x gptel-org-set-topic` + +5. **Custom instructions**: Use `SPC a r` on selected code and give specific instructions + +6. **Programmatic use**: See helper functions at bottom of `ai.el` for examples + +--- + +## 📚 Next Steps + +1. **Secure your API key** (see section above) +2. **Run:** `doom sync` to install packages +3. **Restart Emacs** +4. **Try:** `SPC a g` to start chatting! +5. **Watch:** "Every LLM in Emacs, with gptel" video (17 min) + +--- + +## 🐛 Troubleshooting + +### Packages not loading? +```bash +doom sync +doom build +``` + +### Transient version error? +```elisp +;; Add to ai.el before gptel config: +(setq package-install-upgrade-built-in t) +``` +Then: `M-x package-install RET transient RET` + +### API key not working? +- Check `~/.authinfo.gpg` format +- Ensure proper encryption password +- Test: `(auth-source-pick-first-password :host "openrouter.ai")` + +### Autocomplete not showing? +- Enable manually: `M-x gptel-autocomplete-mode` +- Check if in prog-mode buffer +- May need specific model configuration + +--- + +## 📖 Resources + +- [gptel GitHub](https://github.com/karthink/gptel) +- [gptel Manual](https://gptel.org/manual.html) +- [OpenRouter Docs](https://openrouter.ai/docs) +- [Ollama Models](https://ollama.com/library) + +--- + +**Enjoy your AI-powered Emacs! 🎉** diff --git a/ai.el b/ai.el index dad011b..f23104b 100644 --- a/ai.el +++ b/ai.el @@ -1,17 +1,171 @@ ;;; ai.el -*- lexical-binding: t; -*- -(setq gptel-model 'google/gemini-2.5-flash ;; Default model - gptel-backend - (gptel-make-openai "OpenRouter" ;Any name you want - :host "openrouter.ai" - :endpoint "/api/v1/chat/completions" - :stream t - :key "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" ;can be a function that returns the key - :models '(google/gemini-2.5-flash - google/gemini-2.5-pro - anthropic/claude-sonnet-4 - anthropic/claude-sonnet-4.5 - ))) +;;; ============================================================================ +;;; gptel Configuration +;;; ============================================================================ + +;; Core gptel setup +(use-package! gptel + :config + ;; Default backend: OpenRouter + (setq gptel-model 'google/gemini-2.5-flash + gptel-backend + (gptel-make-openai "OpenRouter" + :host "openrouter.ai" + :endpoint "/api/v1/chat/completions" + :stream t + :key "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" + :models '(google/gemini-2.5-flash + google/gemini-2.5-pro + anthropic/claude-sonnet-4 + anthropic/claude-sonnet-4.5))) + + ;; Use org-mode by default for better note-taking + (setq gptel-default-mode 'org-mode) + + ;; Move cursor to end of response automatically + (add-hook 'gptel-post-response-functions 'gptel-end-of-response) + + ;; Keybindings + (map! :leader + (:prefix ("a" . "AI") + :desc "gptel chat" "g" #'gptel + :desc "gptel send" "s" #'gptel-send + :desc "gptel menu" "m" #'gptel-menu + :desc "gptel rewrite" "r" #'gptel-rewrite + :desc "Add context" "c" #'gptel-add + :desc "Add file to context" "f" #'gptel-add-file)) + + ;; Additional keybindings in gptel buffer + (map! :map gptel-mode-map + "C-c RET" #'gptel-send + "C-c C-k" #'gptel-abort + "C-c C-c" #'gptel-menu)) + +;; gptel presets for different tasks +(after! gptel + ;; Coding assistant preset + (gptel-make-preset 'coder + :description "Expert coding assistant" + :backend "OpenRouter" + :model 'anthropic/claude-sonnet-4.5 + :system "You are an expert coding assistant. Provide high-quality code solutions, refactorings, and explanations. Be concise but thorough. Include error handling and follow best practices.") + + ;; Code explainer preset + (gptel-make-preset 'explain + :description "Explain code to beginners" + :system "Explain this code to a novice programmer. Use simple language and break down complex concepts.") + + ;; Refactoring preset + (gptel-make-preset 'refactor + :description "Code refactoring expert" + :model 'anthropic/claude-sonnet-4.5 + :system "You are a code refactoring expert. Improve code quality, readability, and performance while maintaining functionality. Explain your changes.") + + ;; Quick answers preset + (gptel-make-preset 'quick + :description "Quick, concise answers" + :model 'google/gemini-2.5-flash + :system "Provide quick, concise answers. Be direct and to the point.") + + ;; Documentation writer preset + (gptel-make-preset 'docs + :description "Documentation writer" + :system "Write clear, comprehensive documentation. Include examples and explain edge cases.")) + +;;; ============================================================================ +;;; gptel-quick - Quick lookups and explanations +;;; ============================================================================ + +(use-package! gptel-quick + :after gptel + :config + ;; Include context from gptel-add if available + (setq gptel-quick-use-context t) + + (map! :leader + (:prefix "a" + :desc "Quick lookup" "q" #'gptel-quick))) + +;;; ============================================================================ +;;; gptel-extensions - Extra utility functions +;;; ============================================================================ + +(use-package! gptel-extensions + :after gptel + :config + (map! :leader + (:prefix "a" + :desc "Load buffer into session" "l" #'gptel-extensions-load-buffer + :desc "Send whole buffer" "b" #'gptel-extensions-send-whole-buffer + :desc "Refactor region" "R" #'gptel-extensions-refactor))) + +;;; ============================================================================ +;;; gptel-autocomplete - Inline code completion +;;; ============================================================================ + +(use-package! gptel-autocomplete + :after gptel + :config + ;; Enable in programming modes + (add-hook 'prog-mode-hook #'gptel-autocomplete-mode) + + ;; Configure keybindings for autocomplete + (map! :map gptel-autocomplete-mode-map + "M-TAB" #'gptel-autocomplete-complete + "C-c TAB" #'gptel-autocomplete-complete) + + ;; Optional: Configure which model to use for completion + ;; (setq gptel-autocomplete-model 'google/gemini-2.5-flash) + ) + +;;; ============================================================================ +;;; Optional: Add Ollama for local models (commented out by default) +;;; ============================================================================ + +;; Uncomment to add Ollama support for local models +;; (after! gptel +;; (gptel-make-ollama "Ollama" +;; :host "localhost:11434" +;; :stream t +;; :models '(qwen2.5-coder:latest +;; mistral:latest +;; llama3.2:latest))) + +;; To make Ollama default, uncomment: +;; (setq gptel-model 'qwen2.5-coder:latest +;; gptel-backend (gptel-make-ollama "Ollama" +;; :host "localhost:11434" +;; :stream t +;; :models '(qwen2.5-coder:latest +;; mistral:latest))) + +;;; ============================================================================ +;;; Helper functions +;;; ============================================================================ + +(defun my/gptel-quick-explain-region () + "Quickly explain selected code region." + (interactive) + (when (use-region-p) + (let ((code (buffer-substring-no-properties (region-beginning) (region-end)))) + (gptel-request code + :system "Explain this code concisely in 2-3 sentences." + :callback (lambda (response info) + (message "Explanation: %s" response)))))) + +(defun my/gptel-proofread-region () + "Proofread and improve selected text." + (interactive) + (when (use-region-p) + (gptel-rewrite-region (region-beginning) (region-end) + "Fix spelling, grammar, and improve clarity. Keep the same tone and style."))) + +;; Add keybindings for helper functions +(map! :leader + (:prefix "a" + :desc "Quick explain" "e" #'my/gptel-quick-explain-region + :desc "Proofread text" "p" #'my/gptel-proofread-region)) ;;; Claude Code Configuration diff --git a/packages.el b/packages.el index 904abb2..7eee863 100644 --- a/packages.el +++ b/packages.el @@ -3,8 +3,19 @@ (package! super-save) +;; gptel and extensions (package! gptel) +;; gptel extensions +(package! gptel-quick + :recipe (:host github :repo "karthink/gptel-quick")) + +(package! gptel-extensions + :recipe (:host github :repo "kamushadenes/gptel-extensions.el")) + +(package! gptel-autocomplete + :recipe (:host github :repo "JDNdeveloper/gptel-autocomplete")) + (package! org-re-reveal) (package! copilot