gptel: Make gptel-post-response-* easier to use
* gptel.el (gptel-end-of-response, gptel-post-response-hook, gptel-post-response-functions, gptel--insert-response, gptel-response-filter-functions): Rename gptel-post-response-hook -> gptel-post-response-functions The new abnormal hook now calls its functions with the start and end positions of the response, to make it easier to act on the response. * gptel-curl.el (gptel-curl--stream-cleanup): Corresponding changes. * README.org: Mention breaking change.
This commit is contained in:
parent
d6ef79f621
commit
612aea3456
3 changed files with 46 additions and 26 deletions
|
@ -319,7 +319,7 @@ To be minimally annoying, GPTel does not move the cursor by default. Add the fo
|
||||||
To be minimally annoying, GPTel does not move the cursor by default. Add the following to your configuration to move the cursor:
|
To be minimally annoying, GPTel does not move the cursor by default. Add the following to your configuration to move the cursor:
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(add-hook 'gptel-post-response-hook 'gptel-end-of-response)
|
(add-hook 'gptel-post-response-functions 'gptel-end-of-response)
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
You can also call =gptel-end-of-response= as a command at any time.
|
You can also call =gptel-end-of-response= as a command at any time.
|
||||||
|
@ -420,6 +420,8 @@ There are several more: [[https://github.com/CarlQLange/chatgpt-arcana.el][chatg
|
||||||
|
|
||||||
** Breaking Changes
|
** Breaking Changes
|
||||||
|
|
||||||
|
- =gptel-post-response-hook= has been renamed to =gptel-post-response-functions=, and functions in this hook are now called with two arguments: the start and end buffer positions of the response. This should make it easy to act on the response text without having to locate it first.
|
||||||
|
|
||||||
- Possible breakage, see #120: If streaming responses stop working for you after upgrading to v0.5, try reinstalling gptel and deleting its native comp eln cache in =native-comp-eln-load-path=.
|
- Possible breakage, see #120: If streaming responses stop working for you after upgrading to v0.5, try reinstalling gptel and deleting its native comp eln cache in =native-comp-eln-load-path=.
|
||||||
|
|
||||||
- The user option =gptel-host= is deprecated. If the defaults don't work for you, use =gptel-make-openai= (which see) to customize server settings.
|
- The user option =gptel-host= is deprecated. If the defaults don't work for you, use =gptel-make-openai= (which see) to customize server settings.
|
||||||
|
|
|
@ -67,11 +67,11 @@ PROMPTS is the data to send, TOKEN is a unique identifier."
|
||||||
(list (format "-d%s" data))
|
(list (format "-d%s" data))
|
||||||
(letrec
|
(letrec
|
||||||
((temp-filename (make-temp-file "gptel-curl-data" nil ".json" data))
|
((temp-filename (make-temp-file "gptel-curl-data" nil ".json" data))
|
||||||
(cleanup-fn (lambda ()
|
(cleanup-fn (lambda (&rest _)
|
||||||
(when (file-exists-p temp-filename)
|
(when (file-exists-p temp-filename)
|
||||||
(delete-file temp-filename)
|
(delete-file temp-filename)
|
||||||
(remove-hook 'gptel-post-response-hook cleanup-fn)))))
|
(remove-hook 'gptel-post-response-functions cleanup-fn)))))
|
||||||
(add-hook 'gptel-post-response-hook cleanup-fn)
|
(add-hook 'gptel-post-response-functions cleanup-fn)
|
||||||
(list "--data-binary"
|
(list "--data-binary"
|
||||||
(format "@%s" temp-filename))))
|
(format "@%s" temp-filename))))
|
||||||
(when (not (string-empty-p gptel-proxy))
|
(when (not (string-empty-p gptel-proxy))
|
||||||
|
@ -177,12 +177,15 @@ PROCESS and _STATUS are process parameters."
|
||||||
(tracking-marker (plist-get info :tracking-marker))
|
(tracking-marker (plist-get info :tracking-marker))
|
||||||
(start-marker (plist-get info :position))
|
(start-marker (plist-get info :position))
|
||||||
(http-status (plist-get info :http-status))
|
(http-status (plist-get info :http-status))
|
||||||
(http-msg (plist-get info :status)))
|
(http-msg (plist-get info :status))
|
||||||
|
response-beg response-end)
|
||||||
(if (equal http-status "200")
|
(if (equal http-status "200")
|
||||||
(progn
|
(progn
|
||||||
;; Finish handling response
|
;; Finish handling response
|
||||||
(with-current-buffer (marker-buffer start-marker)
|
(with-current-buffer (marker-buffer start-marker)
|
||||||
(pulse-momentary-highlight-region (+ start-marker 2) tracking-marker)
|
(setq response-beg (+ start-marker 2)
|
||||||
|
response-end (marker-position tracking-marker))
|
||||||
|
(pulse-momentary-highlight-region response-beg tracking-marker)
|
||||||
(when gptel-mode (save-excursion (goto-char tracking-marker)
|
(when gptel-mode (save-excursion (goto-char tracking-marker)
|
||||||
(insert "\n\n" (gptel-prompt-prefix-string)))))
|
(insert "\n\n" (gptel-prompt-prefix-string)))))
|
||||||
(with-current-buffer gptel-buffer
|
(with-current-buffer gptel-buffer
|
||||||
|
@ -214,7 +217,7 @@ PROCESS and _STATUS are process parameters."
|
||||||
(gptel--update-status
|
(gptel--update-status
|
||||||
(format " Response Error: %s" http-msg) 'error))))
|
(format " Response Error: %s" http-msg) 'error))))
|
||||||
(with-current-buffer gptel-buffer
|
(with-current-buffer gptel-buffer
|
||||||
(run-hooks 'gptel-post-response-hook)))
|
(run-hook-with-args 'gptel-post-response-functions response-beg response-end)))
|
||||||
(setf (alist-get process gptel-curl--process-alist nil 'remove) nil)
|
(setf (alist-get process gptel-curl--process-alist nil 'remove) nil)
|
||||||
(kill-buffer proc-buf)))
|
(kill-buffer proc-buf)))
|
||||||
|
|
||||||
|
|
53
gptel.el
53
gptel.el
|
@ -193,13 +193,17 @@ if the command-line argument size is limited by the operating system."
|
||||||
'(gptel--convert-org)
|
'(gptel--convert-org)
|
||||||
"Abnormal hook for transforming the response from ChatGPT.
|
"Abnormal hook for transforming the response from ChatGPT.
|
||||||
|
|
||||||
This is useful if you want to format the response in some way,
|
This is used to format the response in some way, such as filling
|
||||||
such as filling paragraphs, adding annotations or recording
|
paragraphs, adding annotations or recording information in the
|
||||||
information in the response like links.
|
response like links.
|
||||||
|
|
||||||
Each function in this hook receives two arguments, the response
|
Each function in this hook receives two arguments, the response
|
||||||
string to transform and the ChatGPT interaction buffer. It
|
string to transform and the ChatGPT interaction buffer. It
|
||||||
should return the transformed string."
|
should return the transformed string.
|
||||||
|
|
||||||
|
NOTE: This is only used for non-streaming responses. To
|
||||||
|
transform streaming responses, use `gptel-post-stream-hook' and
|
||||||
|
`gptel-post-response-functions'."
|
||||||
:group 'gptel
|
:group 'gptel
|
||||||
:type 'hook)
|
:type 'hook)
|
||||||
|
|
||||||
|
@ -211,12 +215,21 @@ to ChatGPT. Note: this hook only runs if the request succeeds."
|
||||||
:group 'gptel
|
:group 'gptel
|
||||||
:type 'hook)
|
:type 'hook)
|
||||||
|
|
||||||
(defcustom gptel-post-response-hook nil
|
(define-obsolete-variable-alias
|
||||||
"Hook run after inserting the LLM response into the current buffer.
|
'gptel-post-response-hook 'gptel-post-response-functions
|
||||||
|
"0.6.0"
|
||||||
|
"Post-response functions are now called with two arguments: the
|
||||||
|
start and end buffer positions of the response.")
|
||||||
|
|
||||||
|
(defcustom gptel-post-response-functions nil
|
||||||
|
"Abnormal hook run after inserting the LLM response into the current buffer.
|
||||||
|
|
||||||
This hook is called in the buffer from which the prompt was sent
|
This hook is called in the buffer from which the prompt was sent
|
||||||
to the LLM, and after the full response has been inserted. Note:
|
to the LLM, and after the full response has been inserted. Each
|
||||||
this hook runs even if the request fails."
|
function is called with two arguments: the response beginning and
|
||||||
|
end positions.
|
||||||
|
|
||||||
|
Note: this hook runs even if the request fails."
|
||||||
:group 'gptel
|
:group 'gptel
|
||||||
:type 'hook)
|
:type 'hook)
|
||||||
|
|
||||||
|
@ -497,9 +510,9 @@ Note: This will move the cursor."
|
||||||
(scroll-up-command))
|
(scroll-up-command))
|
||||||
(error nil))))
|
(error nil))))
|
||||||
|
|
||||||
(defun gptel-end-of-response (&optional arg)
|
(defun gptel-end-of-response (_ _ &optional arg)
|
||||||
"Move point to the end of the LLM response ARG times."
|
"Move point to the end of the LLM response ARG times."
|
||||||
(interactive "p")
|
(interactive (list nil nil current-prefix-arg))
|
||||||
(dotimes (_ (if arg (abs arg) 1))
|
(dotimes (_ (if arg (abs arg) 1))
|
||||||
(text-property-search-forward 'gptel 'response t)
|
(text-property-search-forward 'gptel 'response t)
|
||||||
(when (looking-at (concat "\n\\{1,2\\}"
|
(when (looking-at (concat "\n\\{1,2\\}"
|
||||||
|
@ -859,7 +872,8 @@ INFO is a plist containing information relevant to this buffer.
|
||||||
See `gptel--url-get-response' for details."
|
See `gptel--url-get-response' for details."
|
||||||
(let* ((status-str (plist-get info :status))
|
(let* ((status-str (plist-get info :status))
|
||||||
(gptel-buffer (plist-get info :buffer))
|
(gptel-buffer (plist-get info :buffer))
|
||||||
(start-marker (plist-get info :position)))
|
(start-marker (plist-get info :position))
|
||||||
|
response-beg response-end)
|
||||||
;; Handle read-only buffers
|
;; Handle read-only buffers
|
||||||
(when (with-current-buffer gptel-buffer
|
(when (with-current-buffer gptel-buffer
|
||||||
(or buffer-read-only
|
(or buffer-read-only
|
||||||
|
@ -890,16 +904,17 @@ See `gptel--url-get-response' for details."
|
||||||
(insert "\n\n")
|
(insert "\n\n")
|
||||||
(when gptel-mode
|
(when gptel-mode
|
||||||
(insert (gptel-response-prefix-string))))
|
(insert (gptel-response-prefix-string))))
|
||||||
(let ((p (point)))
|
(setq response-beg (point)) ;Save response start position
|
||||||
(insert response)
|
(insert response)
|
||||||
(pulse-momentary-highlight-region p (point)))
|
(setq response-end (point))
|
||||||
(when gptel-mode (insert "\n\n" (gptel-prompt-prefix-string))))
|
(pulse-momentary-highlight-region response-beg response-end)
|
||||||
|
(when gptel-mode (insert "\n\n" (gptel-prompt-prefix-string)))) ;Save response end position
|
||||||
(when gptel-mode (gptel--update-status " Ready" 'success))))
|
(when gptel-mode (gptel--update-status " Ready" 'success))))
|
||||||
(gptel--update-status
|
(gptel--update-status
|
||||||
(format " Response Error: %s" status-str) 'error)
|
(format " Response Error: %s" status-str) 'error)
|
||||||
(message "ChatGPT response error: (%s) %s"
|
(message "ChatGPT response error: (%s) %s"
|
||||||
status-str (plist-get info :error)))
|
status-str (plist-get info :error)))
|
||||||
(run-hooks 'gptel-post-response-hook))))
|
(run-hook-with-args 'gptel-post-response-functions response-beg response-end))))
|
||||||
|
|
||||||
(defun gptel-set-topic ()
|
(defun gptel-set-topic ()
|
||||||
"Set a topic and limit this conversation to the current heading.
|
"Set a topic and limit this conversation to the current heading.
|
||||||
|
@ -1192,12 +1207,12 @@ text stream."
|
||||||
(temp-buf (generate-new-buffer-name "*gptel-temp*"))
|
(temp-buf (generate-new-buffer-name "*gptel-temp*"))
|
||||||
(start-pt (make-marker))
|
(start-pt (make-marker))
|
||||||
(cleanup-fn
|
(cleanup-fn
|
||||||
(lambda ()
|
(lambda (&rest _)
|
||||||
(when (buffer-live-p (get-buffer temp-buf))
|
(when (buffer-live-p (get-buffer temp-buf))
|
||||||
(set-marker start-pt nil)
|
(set-marker start-pt nil)
|
||||||
(kill-buffer temp-buf))
|
(kill-buffer temp-buf))
|
||||||
(remove-hook 'gptel-post-response-hook cleanup-fn))))
|
(remove-hook 'gptel-post-response-functions cleanup-fn))))
|
||||||
(add-hook 'gptel-post-response-hook cleanup-fn)
|
(add-hook 'gptel-post-response-functions cleanup-fn)
|
||||||
(lambda (str)
|
(lambda (str)
|
||||||
(let ((noop-p))
|
(let ((noop-p))
|
||||||
(with-current-buffer (get-buffer-create temp-buf)
|
(with-current-buffer (get-buffer-create temp-buf)
|
||||||
|
|
Loading…
Add table
Reference in a new issue