Skip to content

Commit fce67c3

Browse files
committed
more adjustments based on code review
1 parent 0677243 commit fce67c3

File tree

1 file changed

+74
-65
lines changed

1 file changed

+74
-65
lines changed

chatgpt-shell-google.el

Lines changed: 74 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
;;; chatgpt-shell-google.el --- Google-specific logic -*- lexical-binding: t -*-
22

3-
;; Copyright (C) 2023 Alvaro Ramirez
3+
;; Copyright (C) 2023-2025 Alvaro Ramirez
44

55
;; Author: Alvaro Ramirez https://xenodium.com
66
;; URL: https://github.com/xenodium/chatgpt-shell
@@ -27,8 +27,10 @@
2727

2828
(eval-when-compile
2929
(require 'cl-lib))
30+
(require 'let-alist)
3031
(require 'shell-maker)
3132
(require 'map)
33+
(require 'rx)
3234
(require 'json)
3335

3436
(defvar chatgpt-shell-proxy)
@@ -92,73 +94,72 @@ supports \"generateContent\".
9294
9395
This is used to filter the list of models returned from
9496
https://generativelanguage.googleapis.com"
95-
(when-let* ((description (gethash "description" api-response))
96-
((not (string-match-p (rx (or "discontinued" "deprecated")) description)))
97-
(supported-methods (gethash "supportedGenerationMethods" api-response)))
98-
(seq-contains-p supported-methods "generateContent")))
97+
(let-alist api-response
98+
(if (not (string-match-p (rx (or "discontinued" "deprecated")) .description))
99+
(seq-contains-p .supportedGenerationMethods "generateContent"))))
99100

100101
(defun chatgpt-shell-google--fetch-model-versions ()
101102
"Retrieves the list of generative models from the Google API."
102-
(let ((url (concat chatgpt-shell-google-api-url-base "/v1beta/models?key="
103-
(chatgpt-shell-google-key))))
104-
(with-current-buffer (url-retrieve-synchronously url)
105-
(goto-char (if (boundp 'url-http-end-of-headers)
106-
url-http-end-of-headers
107-
(error "`url-http-end-of-headers' marker is not defined")))
108-
(let ((json-object-type 'hash-table)
109-
(json-array-type 'list)
110-
(json-key-type 'string))
111-
(let ((parsed-response
112-
(json-read-from-string
113-
(buffer-substring-no-properties (point) (point-max)))))
114-
(seq-filter #'chatgpt-shell-google--current-generative-model-p
115-
(gethash "models" parsed-response)))))))
116-
117-
(defun chatgpt-shell-google--convert-model (api-response)
103+
(if-let* ((api-key (chatgpt-shell-google-key)))
104+
(let ((url (concat chatgpt-shell-google-api-url-base "/v1beta/models?key=" api-key)))
105+
(with-current-buffer (url-retrieve-synchronously url)
106+
(goto-char (if (boundp 'url-http-end-of-headers)
107+
url-http-end-of-headers
108+
(error "`url-http-end-of-headers' marker is not defined")))
109+
(if-let* ((parsed-response
110+
(shell-maker--json-parse-string
111+
(buffer-substring-no-properties (point) (point-max)))))
112+
(let-alist parsed-response
113+
(seq-filter #'chatgpt-shell-google--current-generative-model-p .models)))))
114+
(error "Set your Google API Key.")))
115+
116+
(defun chatgpt-shell-google--parse-model (api-response)
118117
"Convert the API-RESPONSE returned by Gemini into a
119118
the model description needed by `chatgpt-shell'."
120-
(let ((model-name (gethash "name" model))
121-
(model-cwindow (gethash "inputTokenLimit" model)))
122-
(let ((model-version (string-remove-prefix "models/" model-name)))
123-
(let ((model-shortversion (string-remove-prefix "gemini-" model-version))
124-
(model-urlpath (concat "/v1beta/" model-name))
125-
;; The model descriptor does not stipulate whether grounding is supported.
126-
;; So this logic just checks the name.
127-
(model-supports-grounding (or
128-
(string-prefix-p "gemini-1.5" model-version)
129-
(string-prefix-p "gemini-2.0" model-version))))
130-
(chatgpt-shell-google-make-model :version model-version
131-
:short-version model-shortversion
132-
:grounding-search model-supports-grounding
133-
:path model-urlpath
134-
:token-width 4
135-
:context-window model-cwindow)))))
119+
(let-alist api-response
120+
(let* ((model-version (string-remove-prefix "models/" .name))
121+
(model-shortversion (string-remove-prefix "gemini-" model-version))
122+
(model-urlpath (concat "/v1beta/" .name))
123+
;; The api-response descriptor does not stipulate whether grounding is supported.
124+
;; This logic applies a heuristic based on the model name (aka version).
125+
(model-supports-grounding
126+
(if (string-match-p (rx bol (or "gemini-1.5" "gemini-2.0")) model-version) t nil)))
127+
(chatgpt-shell-google-make-model :version model-version
128+
:short-version model-shortversion
129+
:grounding-search model-supports-grounding
130+
:path model-urlpath
131+
:token-width 4
132+
:context-window .inputTokenLimit))))
136133

137134
(cl-defun chatgpt-shell-google-load-models (&key override)
138135
"Query Google for the list of Gemini LLM models available.
139136
140-
The data is retrieved from
141-
https://ai.google.dev/gemini-api/docs/models/gemini. This fn then the
142-
models retrieved to `chatgpt-shell-models' unless a model with the same
143-
name is already present.
137+
By default, this package uses a static list of models as returned from
138+
`chatgpt-shell-google-models'. But some users may want to choose from
139+
a fresher set of available models.
140+
141+
This function retrieves data from
142+
https://ai.google.dev/gemini-api/docs/models/gemini. This fn then
143+
appends the models retrieved to the `chatgpt-shell-models' list, unless
144+
a model with the same name is already present.
144145
145146
By default, replace the existing Google models in `chatgpt-shell-models'
146-
with the newly retrieved models. When OVERRIDE is non-nil (interactively
147-
with a prefix argument), replace all the Google models with those
148-
retrieved."
147+
with the newly retrieved models. When OVERRIDE is non-nil, which
148+
happens when the function is invoked interactively with a prefix
149+
argument, replace all the Google models with those retrieved."
150+
149151
(interactive (list :override current-prefix-arg))
150152
(let* ((goog-predicate (lambda (model)
151153
(string= (map-elt model :provider) "Google")))
152154
(goog-index (or (cl-position-if goog-predicate chatgpt-shell-models)
153155
(length chatgpt-shell-models))))
154156
(setq chatgpt-shell-models (and (not override)
155157
(cl-remove-if goog-predicate chatgpt-shell-models)))
156-
(let* ((existing-gemini-models (mapcar (lambda (model)
157-
(map-elt model :version))
158-
(cl-remove-if-not goog-predicate
159-
chatgpt-shell-models)))
158+
(let* ((existing-gemini-models
159+
(mapcar (lambda (model) (map-elt model :version))
160+
(cl-remove-if-not goog-predicate chatgpt-shell-models)))
160161
(new-gemini-models
161-
(mapcar #'chatgpt-shell-google--convert-model (chatgpt-shell-google--fetch-model-versions))))
162+
(mapcar #'chatgpt-shell-google--parse-model (chatgpt-shell-google--fetch-model-versions))))
162163
(setq chatgpt-shell-models
163164
(append (seq-take chatgpt-shell-models goog-index)
164165
new-gemini-models
@@ -167,12 +168,13 @@ retrieved."
167168
(length new-gemini-models)
168169
(length existing-gemini-models)))))
169170

170-
(defun chatgpt-shell-google-toggle-grounding ()
171+
(defun chatgpt-shell-google-toggle-grounding-with-google-search ()
171172
"Toggle the `:grounding-search' boolean for the currently-selected model.
172173
173174
Google's documentation states that All Gemini 1.5 and 2.0 models support
174-
grounding, and `:grounding-search' will be `t' for those models. For
175-
models that support grounding, this package will include a
175+
grounding with Google search, and `:grounding-search' will be `t' for
176+
those models. For models that support grounding, this package will
177+
include a
176178
177179
(tools .((google_search . ())))
178180
@@ -182,29 +184,36 @@ in the request payload for 2.0+ models, or
182184
183185
for 1.5-era models.
184186
185-
But some of the experimental models may not support grounding. If
186-
`chatgpt-shell' tries to send a tools parameter as above to a model that
187-
does not support grounding, the API returns an error. In that case, the
188-
user can use this function to toggle grounding on the model, so that
189-
this package does not send the tools parameter in subsequent outbound
190-
requests to that model.
187+
But some of the experimental models of those versions may not support
188+
grounding. If `chatgpt-shell' tries to send a tools parameter as above
189+
to a model that does not support grounding, the API returns an error.
190+
191+
And in some cases users may wish to not _use_ grounding in Search, even
192+
though it is available.
193+
194+
In either case, the user can invoke this function to toggle
195+
grounding-in-google-search on the model. This package will send the
196+
tools parameter in subsequent outbound requests to that model, when
197+
grounding is enabled.
191198
192-
Returns the newly toggled value of `:grounding-search'."
199+
Returns the new boolean value of `:grounding-search'."
193200
(interactive)
194201
(when-let* ((current-model (chatgpt-shell--resolved-model))
195202
(is-google (string= (map-elt current-model :provider) "Google"))
196203
(current-grounding-cons (assq :grounding-search current-model)))
197-
(setf (cdr current-grounding-cons) (not (cdr current-grounding-cons)))))
204+
(let ((toggled (not (cdr current-grounding-cons))))
205+
(setf (cdr current-grounding-cons) toggled)
206+
(message "Grounding in Google search: %s" (if toggled "ON" "OFF"))
207+
toggled)))
198208

199-
(defun chatgpt-shell-google--get-grounding-tool-keyword (model)
209+
(defun chatgpt-shell-google--get-grounding-in-search-tool-keyword (model)
200210
"Retrieves the keyword for the grounding tool.
201211
202212
This gets set once for each model, based on a heuristic."
203213
(when-let* ((current-model model)
204214
(is-google (string= (map-elt current-model :provider) "Google"))
205215
(version (map-elt current-model :version)))
206-
(save-match-data
207-
(if (string-match "1\\.5" version) "google_search_retrieval" "google_search"))))
216+
(if (string-match "1\\.5" version) "google_search_retrieval" "google_search")))
208217

209218
(defun chatgpt-shell-google-models ()
210219
"Build a list of Google LLM models available."
@@ -312,9 +321,9 @@ or
312321
(when prompt
313322
(list (cons prompt nil))))))))
314323
(when (map-elt model :grounding-search)
315-
;; Google's docs say that grounding is supported for all Gemini 1.5 and 2.0 models.
324+
;; Grounding in Google Search is supported for both Gemini 1.5 and 2.0 models.
316325
;; But the API is slightly different between them. This uses the correct tool name.
317-
`((tools . ((,(intern (chatgpt-shell-google--get-grounding-tool-keyword model)) . ())))))
326+
`((tools . ((,(intern (chatgpt-shell-google--get-grounding-in-search-tool-keyword model)) . ())))))
318327
`((generation_config . ((temperature . ,(or (map-elt settings :temperature) 1))
319328
;; 1 is most diverse output.
320329
(topP . 1))))))

0 commit comments

Comments
 (0)