From 36af271a71606b628a395950f3233a55afc91800 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Wed, 13 Aug 2025 12:01:33 -0500 Subject: added user and LLM model and version + timestamp for all responses --- modules/ai-config.el | 127 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 107 insertions(+), 20 deletions(-) (limited to 'modules') diff --git a/modules/ai-config.el b/modules/ai-config.el index 643bac0b..196a2fad 100644 --- a/modules/ai-config.el +++ b/modules/ai-config.el @@ -20,9 +20,6 @@ ;;; Code: -;; ----------------------------------- GPTel ----------------------------------- -;; integration with ChatGPT and other large language models. - (defvar default-directive "You are a large language model living in Emacs. You understand philosophy, critical theory, and comparative literature at a university graduate student level. You are concise and always provide references to source material.") @@ -38,38 +35,128 @@ "You are a large language model and a funny conversation partner who asks good questions.") -(defun toggle-gptel () - "Toggle the visibility of the ChatGPT buffer." +;; -------------------------------- Toggle GPTel ------------------------------- +;; Toggle GPTel's buffer in a side window + +(defun cj/toggle-gptel () + "Toggle the visibility of the ChatGPT buffer without prompting for a name." (interactive) - (let ((buffer (get-buffer "*ChatGPT*"))) - (if (and buffer (get-buffer-window buffer)) - (delete-window (get-buffer-window buffer)) - (if buffer - (display-buffer-in-side-window buffer '((side . right) (window-width . 0.4))) - (gptel))))) + (let ((buffer (get-buffer "*AI-Assistant*"))) + (if (and buffer (get-buffer-window buffer)) + (delete-window (get-buffer-window buffer)) + (if buffer + (display-buffer-in-side-window buffer '((side . right) (window-width . 0.4))) + ;; Call gptel with a fixed buffer name to skip prompt + (gptel "*AI-Assistant*" gptel-model))))) + +;; ;; defer prefixing the prompt until gptel is actually loaded +;; (with-eval-after-load 'gptel +;; ;; Define the var if the package hasn't yet +;; (unless (boundp 'gptel-prompt-prefix-alist) +;; (defvar gptel-prompt-prefix-alist nil +;; "Alist mapping major modes to prompt prefixes for gptel.") +;; (add-to-list 'gptel-prompt-prefix-alist +;; (cons 'org-mode +;; (concat "*** cj " +;; (format-time-string "[%Y-%m-%d %H:%M:%S]") +;; "\n"))))) + +;; ----------------------------------- GPTel ----------------------------------- +;; Emacs integration with large language models (use-package gptel - :defer t + :defer .5 :commands (gptel gptel-send) :bind - (("C-h G" . gptel) - ("" . toggle-gptel) + (("C-h G" . cj/toggle-gptel) + ("" . cj/toggle-gptel) (:map gptel-mode-map - ("C-" . gptel-send))) + ("C-" . gptel-send))) :custom - (gptel-model "gpt-4") (gptel-default-mode 'org-mode) + (gptel-expert-commands t) + (gptel-track-media t) + (gptel-include-reasoning 'ignore) + (gptel-model 'gpt-4o) + (gptel-log-level 'info) + (gptel--debug nil) :config (setq gptel-directives - `((default . ,default-directive) - (code-only . ,code-only-directive) - (writing . ,writing-directive) - (chat . ,chat-directive))) + `((default . ,default-directive) + (code-only . ,code-only-directive) + (writing . ,writing-directive) + (chat . ,chat-directive))) + + ;; fancy prompt + (add-to-list 'gptel-prompt-prefix-alist + (cons 'org-mode + (concat "*** cj " + (format-time-string "[%Y-%m-%d %H:%M:%S]") + "\n"))) ;; Grab the secret from the auth file (setq auth-sources `((:source ,authinfo-file))) (setq gptel-api-key (auth-source-pick-first-password :host "api.openai.com"))) +;; -------------------------- GPTel Fancy Org Headers -------------------------- +;; each response will be generated under it's own org mode header with backend +;; and model indicated. This is useful for leveraging several LLMs and comparing +;; and saving responses between them. + +(defun cj/gptel-backend-and-model () + "Return gptel backend and model with timestamp in the desired format." + (let ((backend (if (boundp 'gptel-backend) (aref gptel-backend 1))) + (model (if (boundp 'gptel-model) gptel-model)) + (timestamp (format-time-string "[%Y-%m-%d %H:%M:%S]"))) + (format "%s: %s %s" backend model timestamp))) + +(defun cj/gptel-insert-model-in-non-gptel-buffers () + "Add the backend, model, and timestamp in non-dedicated GPTel buffers. +To be used in `gptel-pre-response-hook`." + (unless (member 'gptel-mode local-minor-modes) + (goto-char (point-max)) + (insert (format "\n%s: " (cj/gptel-backend-and-model))) + (goto-char (point-max)))) + +(defun cj/gptel-insert-model-in-chat-buffers (response-begin-pos response-end-pos) + "Add the backend, model, and timestamp in dedicated chat buffers. +Can be used with the `gptel-post-response-functions` hook." + (let* ((gptel-org-prefix (alist-get 'org-mode gptel-prompt-prefix-alist)) + (inserted-string (format "%s %s\n" + (substring gptel-org-prefix 0 (string-match " " gptel-org-prefix)) + (cj/gptel-backend-and-model))) + (len-inserted (length inserted-string))) + (goto-char response-begin-pos) + (insert inserted-string) + (goto-char (+ response-end-pos len-inserted)))) + +;; (defun cj/gptel-backend-and-model () +;; "Return gptel backend and model (if any)." +;; (let ((backend (if (boundp 'gptel-backend) (aref gptel-backend 1))) +;; (model (if (boundp 'gptel-model) gptel-model))) +;; (format "(%s %s)" backend model))) + +;; (defun cj/gptel-insert-model-in-non-gptel-buffers () +;; "This function will add the backend and model in the \"dynamic\" buffers, not in dedicated chat buffers. +;; To be used in `gptel-pre-response-hook'." +;; (unless (member 'gptel-mode local-minor-modes) +;; (goto-char (point-max)) +;; (insert (format "\n%s: " (cj/gptel-backend-and-model))) +;; (goto-char (point-max)))) +;; (add-hook 'gptel-pre-response-hook 'cj/gptel-insert-model-in-non-gptel-buffers) + +;; (defun cj/gptel-insert-model-in-chat-buffers (response-begin-pos response-end-pos) +;; "This function adds the backend and model in dedicated chat buffers. +;; Can be used with the `gptel-post-response-functions' hook." +;; (let* ((gptel-org-prefix (alist-get 'org-mode gptel-prompt-prefix-alist)) +;; (inserted-string (format "%s %s\n" +;; (substring gptel-org-prefix 0 (string-match " " gptel-org-prefix)) +;; (cj/gptel-backend-and-model))) +;; (len-inserted (length inserted-string ))) +;; (goto-char response-begin-pos) +;; (insert inserted-string) +;; (goto-char (+ response-end-pos len-inserted)))) +;; (add-hook 'gptel-post-response-functions 'cj/gptel-insert-model-in-chat-buffers) (provide 'ai-config) ;;; ai-config.el ends here -- cgit v1.2.3