-
Notifications
You must be signed in to change notification settings - Fork 162
Defining custom gptel commands
GPTel provides gptel-request
, a lower level function, to query ChatGPT with custom behavior.
Its signature is as follows:
(gptel-request
"my prompt" ;the prompt to send to ChatGPT
;; The below keys are all optional
:buffer some-buffer-or-name ;defaults to (current-buffer)
:system "Chat directive here" ;defaults to gptel--system-message
:position some-pt ;defaults to (point)
:context (list "any other info") ;will be available to the callback
:callback (lambda (response info) ...)) ;called with the response and an info plist
;defaults to inserting the response at :position
See its documentation for details.
For example, to define a command that accepts a prompt in the minibuffer and pops up a window with the response, you could define the following:
(defvar gptel-lookup--history nil)
(defun gptel-lookup (prompt)
(interactive (list (read-string "Ask ChatGPT: " nil gptel-lookup--history)))
(when (string= prompt "") (user-error "A prompt is required."))
(gptel-request
prompt
:callback
(lambda (response info)
(if (not response)
(message "gptel-lookup failed with message: %s" (plist-get info :status))
(with-current-buffer (get-buffer-create "*gptel-lookup*")
(let ((inhibit-read-only t))
(erase-buffer)
(insert response))
(special-mode)
(display-buffer (current-buffer)
`((display-buffer-in-side-window)
(side . bottom)
(window-height . ,#'fit-window-to-buffer))))))))
A command that asks ChatGPT to rewrite and replace the current region, sentence or line. Calling with a prefix-arg will query the user for the instructions to include with the text. (Note that gptel includes a refactoring interface, so this is purely for demonstration.)
(defun gptel-rewrite-and-replace (bounds &optional directive)
(interactive
(list
(cond
((use-region-p) (cons (region-beginning) (region-end)))
((derived-mode-p 'text-mode)
(list (bounds-of-thing-at-point 'sentence)))
(t (cons (line-beginning-position) (line-end-position))))
(and current-prefix-arg
(read-string "ChatGPT Directive: "
"You are a prose editor. Rewrite my prompt more professionally."))))
(gptel-request
(buffer-substring-no-properties (car bounds) (cdr bounds)) ;the prompt
:system (or directive "You are a prose editor. Rewrite my prompt more professionally.")
:buffer (current-buffer)
:context (cons (set-marker (make-marker) (car bounds))
(set-marker (make-marker) (cdr bounds)))
:callback
(lambda (response info)
(if (not response)
(message "ChatGPT response failed with: %s" (plist-get info :status))
(let* ((bounds (plist-get info :context))
(beg (car bounds))
(end (cdr bounds))
(buf (plist-get info :buffer)))
(with-current-buffer buf
(save-excursion
(goto-char beg)
(kill-region beg end)
(insert response)
(set-marker beg nil)
(set-marker end nil)
(message "Rewrote line. Original line saved to kill-ring."))))))))
A slightly more comprehensive use of gptel-request
can be found in the gptel-quick package. The included gptel-quick
command shows a short summary or explanation of the word at point, or an active region, in a popup. This is useful for quickly looking up names, words, phrases, or summarizing/explaining prose or snippets of code, with minimal friction:
gptel-quick-simple.webm
And you can tweak the detail in the response on the fly:
gptel-quick-make-longer.webm
;; Create a kagi backend if you don't have one defined
(defvar gptel--kagi
(gptel-make-kagi "Kagi" :key "YOUR_KAGI_KEY")) ;or function that returns a key
;; Function that requests kagi for a url summary and shows it in a side-window
(defun my/kagi-summarize (url)
(let ((gptel-backend gptel--kagi)
(gptel-model "summarize:agnes")) ;or summarize:cecil, summarize:daphne, summarize:muriel
(gptel-request
url
:callback
(lambda (response info)
(if response
(with-current-buffer (get-buffer-create "*Kagi Summary*")
(let ((inhibit-read-only t))
(erase-buffer)
(visual-line-mode 1)
(insert response)
(display-buffer
(current-buffer)
'((display-buffer-in-side-window
display-buffer-at-bottom)
(side . bottom))))
(special-mode 1))
(message "gptel-request failed with message: %s"
(plist-get info :status)))))))
;; Make this function available to Embark
(keymap-set embark-url-map "=" #'my/kagi-summarize)
Running embark-act
on a (text or video) link followed by =
will pop up a summary of the link contents at the bottom of the screen.