gptel: Consolidate HTTP request process
* gptel.el (gptel-request, gptel-send, gptel--url-get-response): Consolidate the HTTP query construction into `gptel-request`, and use it as the single point for sending gptel queries. This simplifies the code, makes it easier to debug and (later) advise or otherwise modify. To this end, `gptel-send` reuses `gptel-request` and no longer does its own thing. Adjust other HTTP request-related functions accordingly. * gptel-curl.el (gptel-curl--get-args, gptel-curl--get-response): Receive the full request data instead of constructing it partly in `gptel-curl--get-args`.
This commit is contained in:
parent
e5f54d1d09
commit
260be9d8d4
2 changed files with 30 additions and 35 deletions
|
@ -47,16 +47,14 @@
|
||||||
(defvar gptel-curl--process-alist nil
|
(defvar gptel-curl--process-alist nil
|
||||||
"Alist of active GPTel curl requests.")
|
"Alist of active GPTel curl requests.")
|
||||||
|
|
||||||
(defun gptel-curl--get-args (prompts token)
|
(defun gptel-curl--get-args (data token)
|
||||||
"Produce list of arguments for calling Curl.
|
"Produce list of arguments for calling Curl.
|
||||||
|
|
||||||
PROMPTS is the data to send, TOKEN is a unique identifier."
|
REQUEST-DATA is the data to send, TOKEN is a unique identifier."
|
||||||
(let* ((url (let ((backend-url (gptel-backend-url gptel-backend)))
|
(let* ((url (let ((backend-url (gptel-backend-url gptel-backend)))
|
||||||
(if (functionp backend-url)
|
(if (functionp backend-url)
|
||||||
(funcall backend-url) backend-url)))
|
(funcall backend-url) backend-url)))
|
||||||
(data (encode-coding-string
|
(data-json (encode-coding-string (gptel--json-encode data) 'utf-8))
|
||||||
(gptel--json-encode (gptel--request-data gptel-backend prompts))
|
|
||||||
'utf-8))
|
|
||||||
(headers
|
(headers
|
||||||
(append '(("Content-Type" . "application/json"))
|
(append '(("Content-Type" . "application/json"))
|
||||||
(when-let ((header (gptel-backend-header gptel-backend)))
|
(when-let ((header (gptel-backend-header gptel-backend)))
|
||||||
|
@ -68,15 +66,15 @@ PROMPTS is the data to send, TOKEN is a unique identifier."
|
||||||
(mapcar (lambda (pair) (cons (intern (car pair)) (cdr pair)))
|
(mapcar (lambda (pair) (cons (intern (car pair)) (cdr pair)))
|
||||||
headers))
|
headers))
|
||||||
"request headers"))
|
"request headers"))
|
||||||
(gptel--log data "request body"))
|
(gptel--log data-json "request body"))
|
||||||
(append
|
(append
|
||||||
gptel-curl--common-args
|
gptel-curl--common-args
|
||||||
(gptel-backend-curl-args gptel-backend)
|
(gptel-backend-curl-args gptel-backend)
|
||||||
(list (format "-w(%s . %%{size_header})" token))
|
(list (format "-w(%s . %%{size_header})" token))
|
||||||
(if (length< data gptel-curl-file-size-threshold)
|
(if (length< data-json gptel-curl-file-size-threshold)
|
||||||
(list (format "-d%s" data))
|
(list (format "-d%s" data-json))
|
||||||
(letrec
|
(letrec
|
||||||
((temp-filename (make-temp-file "gptel-curl-data" nil ".json" data))
|
((temp-filename (make-temp-file "gptel-curl-data" nil ".json" data-json))
|
||||||
(cleanup-fn (lambda (&rest _)
|
(cleanup-fn (lambda (&rest _)
|
||||||
(when (file-exists-p temp-filename)
|
(when (file-exists-p temp-filename)
|
||||||
(delete-file temp-filename)
|
(delete-file temp-filename)
|
||||||
|
@ -99,7 +97,7 @@ PROMPTS is the data to send, TOKEN is a unique identifier."
|
||||||
"Retrieve response to prompt in INFO.
|
"Retrieve response to prompt in INFO.
|
||||||
|
|
||||||
INFO is a plist with the following keys:
|
INFO is a plist with the following keys:
|
||||||
- :prompt (the prompt being sent)
|
- :data (the data being sent)
|
||||||
- :buffer (the gptel buffer)
|
- :buffer (the gptel buffer)
|
||||||
- :position (marker at which to insert the response).
|
- :position (marker at which to insert the response).
|
||||||
|
|
||||||
|
@ -108,7 +106,7 @@ the response is inserted into the current buffer after point."
|
||||||
(let* ((token (md5 (format "%s%s%s%s"
|
(let* ((token (md5 (format "%s%s%s%s"
|
||||||
(random) (emacs-pid) (user-full-name)
|
(random) (emacs-pid) (user-full-name)
|
||||||
(recent-keys))))
|
(recent-keys))))
|
||||||
(args (gptel-curl--get-args (plist-get info :prompt) token))
|
(args (gptel-curl--get-args (plist-get info :data) token))
|
||||||
(stream (and gptel-stream (gptel-backend-stream gptel-backend)))
|
(stream (and gptel-stream (gptel-backend-stream gptel-backend)))
|
||||||
(process (apply #'start-process "gptel-curl"
|
(process (apply #'start-process "gptel-curl"
|
||||||
(generate-new-buffer "*gptel-curl*") "curl" args)))
|
(generate-new-buffer "*gptel-curl*") "curl" args)))
|
||||||
|
|
39
gptel.el
39
gptel.el
|
@ -805,11 +805,14 @@ file."
|
||||||
(cl-defun gptel-request
|
(cl-defun gptel-request
|
||||||
(&optional prompt &key callback
|
(&optional prompt &key callback
|
||||||
(buffer (current-buffer))
|
(buffer (current-buffer))
|
||||||
position context
|
position context dry-run
|
||||||
(stream nil) (in-place nil)
|
(stream nil) (in-place nil)
|
||||||
(system gptel--system-message))
|
(system gptel--system-message))
|
||||||
"Request a response from the `gptel-backend' for PROMPT.
|
"Request a response from the `gptel-backend' for PROMPT.
|
||||||
|
|
||||||
|
The request is asynchronous, the function immediately returns
|
||||||
|
with the data that was sent.
|
||||||
|
|
||||||
Note: This function is not fully self-contained. Consider
|
Note: This function is not fully self-contained. Consider
|
||||||
let-binding the parameters `gptel-backend' and `gptel-model'
|
let-binding the parameters `gptel-backend' and `gptel-model'
|
||||||
around calls to it as required.
|
around calls to it as required.
|
||||||
|
@ -832,7 +835,7 @@ with the RESPONSE (a string) and INFO (a plist):
|
||||||
RESPONSE is nil if there was no response or an error.
|
RESPONSE is nil if there was no response or an error.
|
||||||
|
|
||||||
The INFO plist has (at least) the following keys:
|
The INFO plist has (at least) the following keys:
|
||||||
:prompt - The full prompt that was sent with the request
|
:data - The request data included with the query
|
||||||
:position - marker at the point the request was sent, unless
|
:position - marker at the point the request was sent, unless
|
||||||
POSITION is specified.
|
POSITION is specified.
|
||||||
:buffer - The buffer current when the request was sent,
|
:buffer - The buffer current when the request was sent,
|
||||||
|
@ -887,6 +890,9 @@ STREAM is a boolean that determines if the response should be
|
||||||
streamed, as in `gptel-stream'. Do not set this if you are
|
streamed, as in `gptel-stream'. Do not set this if you are
|
||||||
specifying a custom CALLBACK!
|
specifying a custom CALLBACK!
|
||||||
|
|
||||||
|
If DRY-RUN is non-nil, construct and return the full
|
||||||
|
query data as usual, but do not send the request.
|
||||||
|
|
||||||
Model parameters can be let-bound around calls to this function."
|
Model parameters can be let-bound around calls to this function."
|
||||||
(declare (indent 1))
|
(declare (indent 1))
|
||||||
(let* ((gptel-stream stream)
|
(let* ((gptel-stream stream)
|
||||||
|
@ -908,19 +914,22 @@ Model parameters can be let-bound around calls to this function."
|
||||||
;; FIXME Dear reader, welcome to Jank City:
|
;; FIXME Dear reader, welcome to Jank City:
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(let ((gptel--system-message system)
|
(let ((gptel--system-message system)
|
||||||
|
(gptel-model (buffer-local-value 'gptel-model buffer))
|
||||||
(gptel-backend (buffer-local-value 'gptel-backend buffer)))
|
(gptel-backend (buffer-local-value 'gptel-backend buffer)))
|
||||||
(insert prompt)
|
(insert prompt)
|
||||||
(gptel--create-prompt))))
|
(gptel--create-prompt))))
|
||||||
((consp prompt) prompt)))
|
((consp prompt) prompt)))
|
||||||
(info (list :prompt full-prompt
|
(request-data (gptel--request-data gptel-backend full-prompt))
|
||||||
|
(info (list :data request-data
|
||||||
:buffer buffer
|
:buffer buffer
|
||||||
:position start-marker)))
|
:position start-marker)))
|
||||||
(when context (plist-put info :context context))
|
(when context (plist-put info :context context))
|
||||||
(when in-place (plist-put info :in-place in-place))
|
(when in-place (plist-put info :in-place in-place))
|
||||||
(funcall
|
(unless dry-run
|
||||||
(if gptel-use-curl
|
(funcall (if gptel-use-curl
|
||||||
#'gptel-curl-get-response #'gptel--url-get-response)
|
#'gptel-curl-get-response #'gptel--url-get-response)
|
||||||
info callback)))
|
info callback))
|
||||||
|
request-data))
|
||||||
|
|
||||||
;; TODO: Handle multiple requests(#15). (Only one request from one buffer at a time?)
|
;; TODO: Handle multiple requests(#15). (Only one request from one buffer at a time?)
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
|
@ -943,18 +952,7 @@ waiting for the response."
|
||||||
(call-interactively #'gptel-menu)
|
(call-interactively #'gptel-menu)
|
||||||
(message "Querying %s..." (gptel-backend-name gptel-backend))
|
(message "Querying %s..." (gptel-backend-name gptel-backend))
|
||||||
(gptel--sanitize-model)
|
(gptel--sanitize-model)
|
||||||
(let* ((response-pt
|
(gptel-request nil :stream gptel-stream)
|
||||||
(if (use-region-p)
|
|
||||||
(set-marker (make-marker) (region-end))
|
|
||||||
(gptel--at-word-end (point-marker))))
|
|
||||||
(gptel-buffer (current-buffer))
|
|
||||||
(full-prompt (gptel--create-prompt response-pt)))
|
|
||||||
(funcall
|
|
||||||
(if gptel-use-curl
|
|
||||||
#'gptel-curl-get-response #'gptel--url-get-response)
|
|
||||||
(list :prompt full-prompt
|
|
||||||
:buffer gptel-buffer
|
|
||||||
:position response-pt)))
|
|
||||||
(gptel--update-status " Waiting..." 'warning)))
|
(gptel--update-status " Waiting..." 'warning)))
|
||||||
|
|
||||||
(defun gptel--insert-response (response info)
|
(defun gptel--insert-response (response info)
|
||||||
|
@ -1113,7 +1111,7 @@ BUFFER is the LLM interaction buffer."
|
||||||
"Fetch response to prompt in INFO from the LLM.
|
"Fetch response to prompt in INFO from the LLM.
|
||||||
|
|
||||||
INFO is a plist with the following keys:
|
INFO is a plist with the following keys:
|
||||||
- :prompt (the prompt being sent)
|
- :data (the data being sent)
|
||||||
- :buffer (the gptel buffer)
|
- :buffer (the gptel buffer)
|
||||||
- :position (marker at which to insert the response).
|
- :position (marker at which to insert the response).
|
||||||
|
|
||||||
|
@ -1130,8 +1128,7 @@ the response is inserted into the current buffer after point."
|
||||||
(funcall header) header))))
|
(funcall header) header))))
|
||||||
(url-request-data
|
(url-request-data
|
||||||
(encode-coding-string
|
(encode-coding-string
|
||||||
(gptel--json-encode (gptel--request-data
|
(gptel--json-encode (plist-get info :data))
|
||||||
gptel-backend (plist-get info :prompt)))
|
|
||||||
'utf-8)))
|
'utf-8)))
|
||||||
(when gptel-log-level ;logging
|
(when gptel-log-level ;logging
|
||||||
(when (eq gptel-log-level 'debug)
|
(when (eq gptel-log-level 'debug)
|
||||||
|
|
Loading…
Add table
Reference in a new issue