gptel-gemini: Add streaming responses, simplify configuration
* gptel-gemini.el (gptel-make-gemini, gptel-curl--parse-stream, gptel--request-data, gptel--parse-buffer): Enable streaming for the Gemini backend, as well as the temperature and max tokens parameters when making requests. Simplify the user configuration required. * README.org: Fix formatting errors. Update the configuration instructions for Gemini. This closes #149.
This commit is contained in:
parent
84cd7bf5a4
commit
3dd00a7457
2 changed files with 64 additions and 21 deletions
11
README.org
11
README.org
|
@ -202,26 +202,25 @@ You can pick this backend from the transient menu when using gptel (see Usage),
|
||||||
|
|
||||||
#+html: </details>
|
#+html: </details>
|
||||||
|
|
||||||
|
#+html: <details><summary>
|
||||||
**** Gemini
|
**** Gemini
|
||||||
#+html: </summary>
|
#+html: </summary>
|
||||||
|
|
||||||
Register a backend with
|
Register a backend with
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
|
;; :key can be a function that returns the API key.
|
||||||
(gptel-make-gemini
|
(gptel-make-gemini
|
||||||
"Gemini"
|
"Gemini"
|
||||||
:key "YOUR_GEMINI_API_KEY"
|
:key "YOUR_GEMINI_API_KEY"
|
||||||
:host "generativelanguage.googleapis.com"
|
:stream t)
|
||||||
:protocol "https"
|
|
||||||
:endpoint "/v1beta/models/gemini-pro:generateContent"
|
|
||||||
)
|
|
||||||
#+end_src
|
#+end_src
|
||||||
These are the required parameters, refer to the documentation of =gptel-make-gemini= for more. Currently stream is not functional.
|
These are the required parameters, refer to the documentation of =gptel-make-gemini= for more.
|
||||||
|
|
||||||
You can pick this backend from the transient menu when using gptel (see Usage), or set this as the default value of =gptel-backend=:
|
You can pick this backend from the transient menu when using gptel (see Usage), or set this as the default value of =gptel-backend=:
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
;; OPTIONAL configuration
|
;; OPTIONAL configuration
|
||||||
(setq-default gptel-model "Gemini-Pro" ;Pick your default model
|
(setq-default gptel-model "gemini-pro" ;Pick your default model
|
||||||
gptel-backend (gptel-make-gemini "Gemini" :host ...))
|
gptel-backend (gptel-make-gemini "Gemini" :host ...))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
;;; Code:
|
;;; Code:
|
||||||
(require 'gptel)
|
(require 'gptel)
|
||||||
(require 'cl-generic)
|
(require 'cl-generic)
|
||||||
|
(require 'map)
|
||||||
|
|
||||||
;;; Gemini
|
;;; Gemini
|
||||||
(cl-defstruct
|
(cl-defstruct
|
||||||
|
@ -32,14 +33,42 @@
|
||||||
(:copier nil)
|
(:copier nil)
|
||||||
(:include gptel-backend)))
|
(:include gptel-backend)))
|
||||||
|
|
||||||
|
(cl-defmethod gptel-curl--parse-stream ((_backend gptel-gemini) _info)
|
||||||
|
(let* ((json-object-type 'plist)
|
||||||
|
(content-strs))
|
||||||
|
(condition-case nil
|
||||||
|
;; while-let is Emacs 29.1+ only
|
||||||
|
(while (prog1 (search-forward "{" nil t)
|
||||||
|
(backward-char 1))
|
||||||
|
(save-match-data
|
||||||
|
(when-let*
|
||||||
|
((response (json-read))
|
||||||
|
(text (map-nested-elt
|
||||||
|
response '(:candidates 0 :content :parts 0 :text))))
|
||||||
|
(push text content-strs))))
|
||||||
|
(error
|
||||||
|
(goto-char (match-beginning 0))))
|
||||||
|
(apply #'concat (nreverse content-strs))))
|
||||||
|
|
||||||
(cl-defmethod gptel--parse-response ((_backend gptel-gemini) response _info)
|
(cl-defmethod gptel--parse-response ((_backend gptel-gemini) response _info)
|
||||||
(map-nested-elt response '(:candidates 0 :content :parts 0 :text)))
|
(map-nested-elt response '(:candidates 0 :content :parts 0 :text)))
|
||||||
|
|
||||||
(cl-defmethod gptel--request-data ((_backend gptel-gemini) prompts)
|
(cl-defmethod gptel--request-data ((_backend gptel-gemini) prompts)
|
||||||
"JSON encode PROMPTS for sending to Gemini."
|
"JSON encode PROMPTS for sending to Gemini."
|
||||||
(let ((prompts-plist
|
(let ((prompts-plist
|
||||||
`(:contents [,@prompts]
|
`(:contents [,@prompts]))
|
||||||
)))
|
params)
|
||||||
|
(when gptel-temperature
|
||||||
|
(setq params
|
||||||
|
(plist-put params
|
||||||
|
:temperature (max temperature 1.0))))
|
||||||
|
(when gptel-max-tokens
|
||||||
|
(setq params
|
||||||
|
(plist-put params
|
||||||
|
:maxOutputTokens gptel-max-tokens)))
|
||||||
|
(when params
|
||||||
|
(plist-put prompts-plist
|
||||||
|
:generationConfig params))
|
||||||
prompts-plist))
|
prompts-plist))
|
||||||
|
|
||||||
(cl-defmethod gptel--parse-buffer ((_backend gptel-gemini) &optional max-entries)
|
(cl-defmethod gptel--parse-buffer ((_backend gptel-gemini) &optional max-entries)
|
||||||
|
@ -56,8 +85,10 @@
|
||||||
(list :text (string-trim
|
(list :text (string-trim
|
||||||
(buffer-substring-no-properties (prop-match-beginning prop)
|
(buffer-substring-no-properties (prop-match-beginning prop)
|
||||||
(prop-match-end prop))
|
(prop-match-end prop))
|
||||||
(format "[\t\r\n ]*%s[\t\r\n ]*" (regexp-quote (gptel-prompt-prefix-string)))
|
(format "[\t\r\n ]*\\(?:%s\\)?[\t\r\n ]*"
|
||||||
(format "[\t\r\n ]*%s[\t\r\n ]*" (regexp-quote (gptel-response-prefix-string)))))
|
(regexp-quote (gptel-prompt-prefix-string)))
|
||||||
|
(format "[\t\r\n ]*\\(?:%s\\)?[\t\r\n ]*"
|
||||||
|
(regexp-quote (gptel-response-prefix-string)))))
|
||||||
)
|
)
|
||||||
prompts)
|
prompts)
|
||||||
(and max-entries (cl-decf max-entries)))
|
(and max-entries (cl-decf max-entries)))
|
||||||
|
@ -65,27 +96,30 @@
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(cl-defun gptel-make-gemini
|
(cl-defun gptel-make-gemini
|
||||||
(name &key header key
|
(name &key header key stream
|
||||||
(host "generativelanguage.googleapis.com")
|
(host "generativelanguage.googleapis.com")
|
||||||
(protocol "https")
|
(protocol "https")
|
||||||
(models "gemini-pro")
|
(models '("gemini-pro"))
|
||||||
(endpoint "/v1beta/models/gemini-pro:generateContent"))
|
(endpoint "/v1beta/models/gemini-pro:"))
|
||||||
|
|
||||||
"Register a Gemini backend for gptel with NAME.
|
"Register a Gemini backend for gptel with NAME.
|
||||||
|
|
||||||
Keyword arguments:
|
Keyword arguments:
|
||||||
|
|
||||||
HOST (optional) is the API host, typically \"generativelanguage.googleapis.com\".
|
HOST (optional) is the API host, defaults to
|
||||||
|
\"generativelanguage.googleapis.com\".
|
||||||
|
|
||||||
MODELS is a list of available model names.
|
MODELS is a list of available model names. Currently only
|
||||||
|
\"gemini-pro\" is available.
|
||||||
|
|
||||||
STREAM is a boolean to toggle streaming responses, defaults to
|
STREAM is a boolean to toggle streaming responses, defaults to
|
||||||
false.
|
false.
|
||||||
|
|
||||||
PROTOCOL (optional) specifies the protocol, https by default.
|
PROTOCOL (optional) specifies the protocol, \"https\" by default.
|
||||||
|
|
||||||
ENDPOINT (optional) is the API endpoint for completions, defaults to
|
ENDPOINT (optional) is the API endpoint for completions, defaults to
|
||||||
\"/v1beta/models/gemini-pro:generateContent\".
|
\"/v1beta/models/gemini-pro:streamGenerateContent\" if STREAM is true and
|
||||||
|
\"/v1beta/models/gemini-pro:generateContent\" otherwise.
|
||||||
|
|
||||||
HEADER (optional) is for additional headers to send with each
|
HEADER (optional) is for additional headers to send with each
|
||||||
request. It should be an alist or a function that retuns an
|
request. It should be an alist or a function that retuns an
|
||||||
|
@ -101,10 +135,20 @@ function that returns the key."
|
||||||
:models models
|
:models models
|
||||||
:protocol protocol
|
:protocol protocol
|
||||||
:endpoint endpoint
|
:endpoint endpoint
|
||||||
:stream nil
|
:stream stream
|
||||||
:url (if protocol
|
:url
|
||||||
(concat protocol "://" host endpoint "?key=" key)
|
(let ((key (cond
|
||||||
(concat host endpoint "?key=" key)))))
|
((functionp key) (funcall key))
|
||||||
|
((symbolp key) (symbol-value key))
|
||||||
|
((stringp key) key)
|
||||||
|
(t (user-error "gptel-make-gemini: arg :key is malformed")))))
|
||||||
|
(if protocol
|
||||||
|
(concat protocol "://" host endpoint
|
||||||
|
(if stream
|
||||||
|
"streamGenerateContent"
|
||||||
|
"generateContent")
|
||||||
|
"?key=" key)
|
||||||
|
(concat host endpoint "?key=" key))))))
|
||||||
(prog1 backend
|
(prog1 backend
|
||||||
(setf (alist-get name gptel--known-backends
|
(setf (alist-get name gptel--known-backends
|
||||||
nil nil #'equal)
|
nil nil #'equal)
|
||||||
|
|
Loading…
Add table
Reference in a new issue