llm-gemini 0.20a1__tar.gz → 0.21__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {llm_gemini-0.20a1 → llm_gemini-0.21}/PKG-INFO +108 -21
- {llm_gemini-0.20a1 → llm_gemini-0.21}/README.md +105 -19
- {llm_gemini-0.20a1 → llm_gemini-0.21}/llm_gemini.egg-info/PKG-INFO +108 -21
- {llm_gemini-0.20a1 → llm_gemini-0.21}/llm_gemini.egg-info/requires.txt +2 -1
- {llm_gemini-0.20a1 → llm_gemini-0.21}/llm_gemini.py +103 -48
- {llm_gemini-0.20a1 → llm_gemini-0.21}/pyproject.toml +3 -3
- {llm_gemini-0.20a1 → llm_gemini-0.21}/tests/test_gemini.py +8 -0
- {llm_gemini-0.20a1 → llm_gemini-0.21}/LICENSE +0 -0
- {llm_gemini-0.20a1 → llm_gemini-0.21}/llm_gemini.egg-info/SOURCES.txt +0 -0
- {llm_gemini-0.20a1 → llm_gemini-0.21}/llm_gemini.egg-info/dependency_links.txt +0 -0
- {llm_gemini-0.20a1 → llm_gemini-0.21}/llm_gemini.egg-info/entry_points.txt +0 -0
- {llm_gemini-0.20a1 → llm_gemini-0.21}/llm_gemini.egg-info/top_level.txt +0 -0
- {llm_gemini-0.20a1 → llm_gemini-0.21}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: llm-gemini
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.21
|
4
4
|
Summary: LLM plugin to access Google's Gemini family of models
|
5
5
|
Author: Simon Willison
|
6
6
|
License-Expression: Apache-2.0
|
@@ -10,7 +10,7 @@ Project-URL: Issues, https://github.com/simonw/llm-gemini/issues
|
|
10
10
|
Project-URL: CI, https://github.com/simonw/llm-gemini/actions
|
11
11
|
Description-Content-Type: text/markdown
|
12
12
|
License-File: LICENSE
|
13
|
-
Requires-Dist: llm>=0.
|
13
|
+
Requires-Dist: llm>=0.26
|
14
14
|
Requires-Dist: httpx
|
15
15
|
Requires-Dist: ijson
|
16
16
|
Provides-Extra: test
|
@@ -18,6 +18,7 @@ Requires-Dist: pytest; extra == "test"
|
|
18
18
|
Requires-Dist: pytest-recording; extra == "test"
|
19
19
|
Requires-Dist: pytest-asyncio; extra == "test"
|
20
20
|
Requires-Dist: nest-asyncio; extra == "test"
|
21
|
+
Requires-Dist: cogapp; extra == "test"
|
21
22
|
Dynamic: license-file
|
22
23
|
|
23
24
|
# llm-gemini
|
@@ -63,25 +64,71 @@ llm models default gemini-2.0-flash
|
|
63
64
|
llm "A joke about a pelican and a walrus"
|
64
65
|
```
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
67
|
+
## Available models
|
68
|
+
|
69
|
+
<!-- [[[cog
|
70
|
+
import cog
|
71
|
+
from llm import cli
|
72
|
+
from click.testing import CliRunner
|
73
|
+
runner = CliRunner()
|
74
|
+
result = runner.invoke(cli.cli, ["models", "-q", "gemini/"])
|
75
|
+
lines = reversed(result.output.strip().split("\n"))
|
76
|
+
to_output = []
|
77
|
+
NOTES = {
|
78
|
+
"gemini/gemini-2.5-pro-preview-05-06": "Latest paid Gemini 2.5 Pro preview",
|
79
|
+
"gemini/gemini-2.5-flash-preview-05-20": "Gemini 2.5 Flash preview",
|
80
|
+
"gemini/gemini-2.5-flash-preview-04-17": "Earlier Gemini 2.5 Flash preview",
|
81
|
+
"gemini/gemini-2.5-pro-exp-03-25": "Free experimental release of Gemini 2.5 Pro",
|
82
|
+
"gemini/gemini-2.0-flash-thinking-exp-01-21": "Experimental \"thinking\" model from January 2025",
|
83
|
+
"gemini/gemini-1.5-flash-8b-latest": "The least expensive model",
|
84
|
+
}
|
85
|
+
for line in lines:
|
86
|
+
model_id, rest = line.split(None, 2)[1:]
|
87
|
+
note = NOTES.get(model_id, "")
|
88
|
+
to_output.append(
|
89
|
+
"- `{}`{}".format(
|
90
|
+
model_id,
|
91
|
+
': {}'.format(note) if note else ""
|
92
|
+
)
|
93
|
+
)
|
94
|
+
cog.out("\n".join(to_output))
|
95
|
+
]]] -->
|
96
|
+
- `gemini/gemini-2.5-flash-preview-05-20`: Gemini 2.5 Flash preview
|
97
|
+
- `gemini/gemini-2.5-pro-preview-05-06`: Latest paid Gemini 2.5 Pro preview
|
98
|
+
- `gemini/gemini-2.5-flash-preview-04-17`: Earlier Gemini 2.5 Flash preview
|
99
|
+
- `gemini/gemini-2.5-pro-preview-03-25`
|
100
|
+
- `gemini/gemini-2.5-pro-exp-03-25`: Free experimental release of Gemini 2.5 Pro
|
101
|
+
- `gemini/gemini-2.0-flash-lite`
|
102
|
+
- `gemini/gemini-2.0-pro-exp-02-05`
|
103
|
+
- `gemini/gemini-2.0-flash`
|
104
|
+
- `gemini/gemini-2.0-flash-thinking-exp-01-21`: Experimental "thinking" model from January 2025
|
105
|
+
- `gemini/gemini-2.0-flash-thinking-exp-1219`
|
106
|
+
- `gemini/gemma-3n-e4b-it`
|
107
|
+
- `gemini/gemma-3-27b-it`
|
108
|
+
- `gemini/gemma-3-12b-it`
|
109
|
+
- `gemini/gemma-3-4b-it`
|
110
|
+
- `gemini/gemma-3-1b-it`
|
111
|
+
- `gemini/learnlm-1.5-pro-experimental`
|
112
|
+
- `gemini/gemini-2.0-flash-exp`
|
113
|
+
- `gemini/gemini-exp-1206`
|
114
|
+
- `gemini/gemini-exp-1121`
|
115
|
+
- `gemini/gemini-exp-1114`
|
116
|
+
- `gemini/gemini-1.5-flash-8b-001`
|
117
|
+
- `gemini/gemini-1.5-flash-8b-latest`: The least expensive model
|
118
|
+
- `gemini/gemini-1.5-flash-002`
|
119
|
+
- `gemini/gemini-1.5-pro-002`
|
120
|
+
- `gemini/gemini-1.5-flash-001`
|
121
|
+
- `gemini/gemini-1.5-pro-001`
|
122
|
+
- `gemini/gemini-1.5-flash-latest`
|
123
|
+
- `gemini/gemini-1.5-pro-latest`
|
124
|
+
- `gemini/gemini-pro`
|
125
|
+
<!-- [[[end]]] -->
|
126
|
+
|
127
|
+
All of these models have aliases that omit the `gemini/` prefix, for example:
|
128
|
+
|
129
|
+
```bash
|
130
|
+
llm -m gemini-1.5-flash-8b-latest --schema 'name,age int,bio' 'invent a dog'
|
131
|
+
```
|
85
132
|
|
86
133
|
### Images, audio and video
|
87
134
|
|
@@ -154,6 +201,31 @@ To chat interactively with the model, run `llm chat`:
|
|
154
201
|
llm chat -m gemini-2.0-flash
|
155
202
|
```
|
156
203
|
|
204
|
+
### Timeouts
|
205
|
+
|
206
|
+
By default there is no `timeout` against the Gemini API. You can use the `timeout` option to protect against API requests that hang indefinitely.
|
207
|
+
|
208
|
+
With the CLI tool that looks like this, to set a 1.5 second timeout:
|
209
|
+
|
210
|
+
```bash
|
211
|
+
llm -m gemini-2.5-flash-preview-05-20 'epic saga about mice' -o timeout 1.5
|
212
|
+
```
|
213
|
+
In the Python library timeouts are used like this:
|
214
|
+
```python
|
215
|
+
import httpx, llm
|
216
|
+
|
217
|
+
model = llm.get_model("gemini/gemini-2.5-flash-preview-05-20")
|
218
|
+
|
219
|
+
try:
|
220
|
+
response = model.prompt(
|
221
|
+
"epic saga about mice", timeout=1.5
|
222
|
+
)
|
223
|
+
print(response.text())
|
224
|
+
except httpx.TimeoutException:
|
225
|
+
print("Timeout exceeded")
|
226
|
+
```
|
227
|
+
An `httpx.TimeoutException` subclass will be raised if the timeout is exceeded.
|
228
|
+
|
157
229
|
## Embeddings
|
158
230
|
|
159
231
|
The plugin also adds support for the `gemini-embedding-exp-03-07` and `text-embedding-004` embedding models.
|
@@ -186,6 +258,21 @@ llm similar readmes -c 'upload csvs to stuff' -d embed.db
|
|
186
258
|
|
187
259
|
See the [LLM embeddings documentation](https://llm.datasette.io/en/stable/embeddings/cli.html) for further details.
|
188
260
|
|
261
|
+
## Listing all Gemini API models
|
262
|
+
|
263
|
+
The `llm gemini models` command lists all of the models that are exposed by the Gemini API, some of which may not be available through this plugin.
|
264
|
+
|
265
|
+
```bash
|
266
|
+
llm gemini models
|
267
|
+
```
|
268
|
+
You can add a `--key X` option to use a different API key.
|
269
|
+
|
270
|
+
To filter models by their supported generation methods use `--method` one or more times:
|
271
|
+
```bash
|
272
|
+
llm gemini models --method embedContent
|
273
|
+
```
|
274
|
+
If you provide multiple methods you will see models that support any of them.
|
275
|
+
|
189
276
|
## Development
|
190
277
|
|
191
278
|
To set up this plugin locally, first checkout the code. Then create a new virtual environment:
|
@@ -41,25 +41,71 @@ llm models default gemini-2.0-flash
|
|
41
41
|
llm "A joke about a pelican and a walrus"
|
42
42
|
```
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
44
|
+
## Available models
|
45
|
+
|
46
|
+
<!-- [[[cog
|
47
|
+
import cog
|
48
|
+
from llm import cli
|
49
|
+
from click.testing import CliRunner
|
50
|
+
runner = CliRunner()
|
51
|
+
result = runner.invoke(cli.cli, ["models", "-q", "gemini/"])
|
52
|
+
lines = reversed(result.output.strip().split("\n"))
|
53
|
+
to_output = []
|
54
|
+
NOTES = {
|
55
|
+
"gemini/gemini-2.5-pro-preview-05-06": "Latest paid Gemini 2.5 Pro preview",
|
56
|
+
"gemini/gemini-2.5-flash-preview-05-20": "Gemini 2.5 Flash preview",
|
57
|
+
"gemini/gemini-2.5-flash-preview-04-17": "Earlier Gemini 2.5 Flash preview",
|
58
|
+
"gemini/gemini-2.5-pro-exp-03-25": "Free experimental release of Gemini 2.5 Pro",
|
59
|
+
"gemini/gemini-2.0-flash-thinking-exp-01-21": "Experimental \"thinking\" model from January 2025",
|
60
|
+
"gemini/gemini-1.5-flash-8b-latest": "The least expensive model",
|
61
|
+
}
|
62
|
+
for line in lines:
|
63
|
+
model_id, rest = line.split(None, 2)[1:]
|
64
|
+
note = NOTES.get(model_id, "")
|
65
|
+
to_output.append(
|
66
|
+
"- `{}`{}".format(
|
67
|
+
model_id,
|
68
|
+
': {}'.format(note) if note else ""
|
69
|
+
)
|
70
|
+
)
|
71
|
+
cog.out("\n".join(to_output))
|
72
|
+
]]] -->
|
73
|
+
- `gemini/gemini-2.5-flash-preview-05-20`: Gemini 2.5 Flash preview
|
74
|
+
- `gemini/gemini-2.5-pro-preview-05-06`: Latest paid Gemini 2.5 Pro preview
|
75
|
+
- `gemini/gemini-2.5-flash-preview-04-17`: Earlier Gemini 2.5 Flash preview
|
76
|
+
- `gemini/gemini-2.5-pro-preview-03-25`
|
77
|
+
- `gemini/gemini-2.5-pro-exp-03-25`: Free experimental release of Gemini 2.5 Pro
|
78
|
+
- `gemini/gemini-2.0-flash-lite`
|
79
|
+
- `gemini/gemini-2.0-pro-exp-02-05`
|
80
|
+
- `gemini/gemini-2.0-flash`
|
81
|
+
- `gemini/gemini-2.0-flash-thinking-exp-01-21`: Experimental "thinking" model from January 2025
|
82
|
+
- `gemini/gemini-2.0-flash-thinking-exp-1219`
|
83
|
+
- `gemini/gemma-3n-e4b-it`
|
84
|
+
- `gemini/gemma-3-27b-it`
|
85
|
+
- `gemini/gemma-3-12b-it`
|
86
|
+
- `gemini/gemma-3-4b-it`
|
87
|
+
- `gemini/gemma-3-1b-it`
|
88
|
+
- `gemini/learnlm-1.5-pro-experimental`
|
89
|
+
- `gemini/gemini-2.0-flash-exp`
|
90
|
+
- `gemini/gemini-exp-1206`
|
91
|
+
- `gemini/gemini-exp-1121`
|
92
|
+
- `gemini/gemini-exp-1114`
|
93
|
+
- `gemini/gemini-1.5-flash-8b-001`
|
94
|
+
- `gemini/gemini-1.5-flash-8b-latest`: The least expensive model
|
95
|
+
- `gemini/gemini-1.5-flash-002`
|
96
|
+
- `gemini/gemini-1.5-pro-002`
|
97
|
+
- `gemini/gemini-1.5-flash-001`
|
98
|
+
- `gemini/gemini-1.5-pro-001`
|
99
|
+
- `gemini/gemini-1.5-flash-latest`
|
100
|
+
- `gemini/gemini-1.5-pro-latest`
|
101
|
+
- `gemini/gemini-pro`
|
102
|
+
<!-- [[[end]]] -->
|
103
|
+
|
104
|
+
All of these models have aliases that omit the `gemini/` prefix, for example:
|
105
|
+
|
106
|
+
```bash
|
107
|
+
llm -m gemini-1.5-flash-8b-latest --schema 'name,age int,bio' 'invent a dog'
|
108
|
+
```
|
63
109
|
|
64
110
|
### Images, audio and video
|
65
111
|
|
@@ -132,6 +178,31 @@ To chat interactively with the model, run `llm chat`:
|
|
132
178
|
llm chat -m gemini-2.0-flash
|
133
179
|
```
|
134
180
|
|
181
|
+
### Timeouts
|
182
|
+
|
183
|
+
By default there is no `timeout` against the Gemini API. You can use the `timeout` option to protect against API requests that hang indefinitely.
|
184
|
+
|
185
|
+
With the CLI tool that looks like this, to set a 1.5 second timeout:
|
186
|
+
|
187
|
+
```bash
|
188
|
+
llm -m gemini-2.5-flash-preview-05-20 'epic saga about mice' -o timeout 1.5
|
189
|
+
```
|
190
|
+
In the Python library timeouts are used like this:
|
191
|
+
```python
|
192
|
+
import httpx, llm
|
193
|
+
|
194
|
+
model = llm.get_model("gemini/gemini-2.5-flash-preview-05-20")
|
195
|
+
|
196
|
+
try:
|
197
|
+
response = model.prompt(
|
198
|
+
"epic saga about mice", timeout=1.5
|
199
|
+
)
|
200
|
+
print(response.text())
|
201
|
+
except httpx.TimeoutException:
|
202
|
+
print("Timeout exceeded")
|
203
|
+
```
|
204
|
+
An `httpx.TimeoutException` subclass will be raised if the timeout is exceeded.
|
205
|
+
|
135
206
|
## Embeddings
|
136
207
|
|
137
208
|
The plugin also adds support for the `gemini-embedding-exp-03-07` and `text-embedding-004` embedding models.
|
@@ -164,6 +235,21 @@ llm similar readmes -c 'upload csvs to stuff' -d embed.db
|
|
164
235
|
|
165
236
|
See the [LLM embeddings documentation](https://llm.datasette.io/en/stable/embeddings/cli.html) for further details.
|
166
237
|
|
238
|
+
## Listing all Gemini API models
|
239
|
+
|
240
|
+
The `llm gemini models` command lists all of the models that are exposed by the Gemini API, some of which may not be available through this plugin.
|
241
|
+
|
242
|
+
```bash
|
243
|
+
llm gemini models
|
244
|
+
```
|
245
|
+
You can add a `--key X` option to use a different API key.
|
246
|
+
|
247
|
+
To filter models by their supported generation methods use `--method` one or more times:
|
248
|
+
```bash
|
249
|
+
llm gemini models --method embedContent
|
250
|
+
```
|
251
|
+
If you provide multiple methods you will see models that support any of them.
|
252
|
+
|
167
253
|
## Development
|
168
254
|
|
169
255
|
To set up this plugin locally, first checkout the code. Then create a new virtual environment:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: llm-gemini
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.21
|
4
4
|
Summary: LLM plugin to access Google's Gemini family of models
|
5
5
|
Author: Simon Willison
|
6
6
|
License-Expression: Apache-2.0
|
@@ -10,7 +10,7 @@ Project-URL: Issues, https://github.com/simonw/llm-gemini/issues
|
|
10
10
|
Project-URL: CI, https://github.com/simonw/llm-gemini/actions
|
11
11
|
Description-Content-Type: text/markdown
|
12
12
|
License-File: LICENSE
|
13
|
-
Requires-Dist: llm>=0.
|
13
|
+
Requires-Dist: llm>=0.26
|
14
14
|
Requires-Dist: httpx
|
15
15
|
Requires-Dist: ijson
|
16
16
|
Provides-Extra: test
|
@@ -18,6 +18,7 @@ Requires-Dist: pytest; extra == "test"
|
|
18
18
|
Requires-Dist: pytest-recording; extra == "test"
|
19
19
|
Requires-Dist: pytest-asyncio; extra == "test"
|
20
20
|
Requires-Dist: nest-asyncio; extra == "test"
|
21
|
+
Requires-Dist: cogapp; extra == "test"
|
21
22
|
Dynamic: license-file
|
22
23
|
|
23
24
|
# llm-gemini
|
@@ -63,25 +64,71 @@ llm models default gemini-2.0-flash
|
|
63
64
|
llm "A joke about a pelican and a walrus"
|
64
65
|
```
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
67
|
+
## Available models
|
68
|
+
|
69
|
+
<!-- [[[cog
|
70
|
+
import cog
|
71
|
+
from llm import cli
|
72
|
+
from click.testing import CliRunner
|
73
|
+
runner = CliRunner()
|
74
|
+
result = runner.invoke(cli.cli, ["models", "-q", "gemini/"])
|
75
|
+
lines = reversed(result.output.strip().split("\n"))
|
76
|
+
to_output = []
|
77
|
+
NOTES = {
|
78
|
+
"gemini/gemini-2.5-pro-preview-05-06": "Latest paid Gemini 2.5 Pro preview",
|
79
|
+
"gemini/gemini-2.5-flash-preview-05-20": "Gemini 2.5 Flash preview",
|
80
|
+
"gemini/gemini-2.5-flash-preview-04-17": "Earlier Gemini 2.5 Flash preview",
|
81
|
+
"gemini/gemini-2.5-pro-exp-03-25": "Free experimental release of Gemini 2.5 Pro",
|
82
|
+
"gemini/gemini-2.0-flash-thinking-exp-01-21": "Experimental \"thinking\" model from January 2025",
|
83
|
+
"gemini/gemini-1.5-flash-8b-latest": "The least expensive model",
|
84
|
+
}
|
85
|
+
for line in lines:
|
86
|
+
model_id, rest = line.split(None, 2)[1:]
|
87
|
+
note = NOTES.get(model_id, "")
|
88
|
+
to_output.append(
|
89
|
+
"- `{}`{}".format(
|
90
|
+
model_id,
|
91
|
+
': {}'.format(note) if note else ""
|
92
|
+
)
|
93
|
+
)
|
94
|
+
cog.out("\n".join(to_output))
|
95
|
+
]]] -->
|
96
|
+
- `gemini/gemini-2.5-flash-preview-05-20`: Gemini 2.5 Flash preview
|
97
|
+
- `gemini/gemini-2.5-pro-preview-05-06`: Latest paid Gemini 2.5 Pro preview
|
98
|
+
- `gemini/gemini-2.5-flash-preview-04-17`: Earlier Gemini 2.5 Flash preview
|
99
|
+
- `gemini/gemini-2.5-pro-preview-03-25`
|
100
|
+
- `gemini/gemini-2.5-pro-exp-03-25`: Free experimental release of Gemini 2.5 Pro
|
101
|
+
- `gemini/gemini-2.0-flash-lite`
|
102
|
+
- `gemini/gemini-2.0-pro-exp-02-05`
|
103
|
+
- `gemini/gemini-2.0-flash`
|
104
|
+
- `gemini/gemini-2.0-flash-thinking-exp-01-21`: Experimental "thinking" model from January 2025
|
105
|
+
- `gemini/gemini-2.0-flash-thinking-exp-1219`
|
106
|
+
- `gemini/gemma-3n-e4b-it`
|
107
|
+
- `gemini/gemma-3-27b-it`
|
108
|
+
- `gemini/gemma-3-12b-it`
|
109
|
+
- `gemini/gemma-3-4b-it`
|
110
|
+
- `gemini/gemma-3-1b-it`
|
111
|
+
- `gemini/learnlm-1.5-pro-experimental`
|
112
|
+
- `gemini/gemini-2.0-flash-exp`
|
113
|
+
- `gemini/gemini-exp-1206`
|
114
|
+
- `gemini/gemini-exp-1121`
|
115
|
+
- `gemini/gemini-exp-1114`
|
116
|
+
- `gemini/gemini-1.5-flash-8b-001`
|
117
|
+
- `gemini/gemini-1.5-flash-8b-latest`: The least expensive model
|
118
|
+
- `gemini/gemini-1.5-flash-002`
|
119
|
+
- `gemini/gemini-1.5-pro-002`
|
120
|
+
- `gemini/gemini-1.5-flash-001`
|
121
|
+
- `gemini/gemini-1.5-pro-001`
|
122
|
+
- `gemini/gemini-1.5-flash-latest`
|
123
|
+
- `gemini/gemini-1.5-pro-latest`
|
124
|
+
- `gemini/gemini-pro`
|
125
|
+
<!-- [[[end]]] -->
|
126
|
+
|
127
|
+
All of these models have aliases that omit the `gemini/` prefix, for example:
|
128
|
+
|
129
|
+
```bash
|
130
|
+
llm -m gemini-1.5-flash-8b-latest --schema 'name,age int,bio' 'invent a dog'
|
131
|
+
```
|
85
132
|
|
86
133
|
### Images, audio and video
|
87
134
|
|
@@ -154,6 +201,31 @@ To chat interactively with the model, run `llm chat`:
|
|
154
201
|
llm chat -m gemini-2.0-flash
|
155
202
|
```
|
156
203
|
|
204
|
+
### Timeouts
|
205
|
+
|
206
|
+
By default there is no `timeout` against the Gemini API. You can use the `timeout` option to protect against API requests that hang indefinitely.
|
207
|
+
|
208
|
+
With the CLI tool that looks like this, to set a 1.5 second timeout:
|
209
|
+
|
210
|
+
```bash
|
211
|
+
llm -m gemini-2.5-flash-preview-05-20 'epic saga about mice' -o timeout 1.5
|
212
|
+
```
|
213
|
+
In the Python library timeouts are used like this:
|
214
|
+
```python
|
215
|
+
import httpx, llm
|
216
|
+
|
217
|
+
model = llm.get_model("gemini/gemini-2.5-flash-preview-05-20")
|
218
|
+
|
219
|
+
try:
|
220
|
+
response = model.prompt(
|
221
|
+
"epic saga about mice", timeout=1.5
|
222
|
+
)
|
223
|
+
print(response.text())
|
224
|
+
except httpx.TimeoutException:
|
225
|
+
print("Timeout exceeded")
|
226
|
+
```
|
227
|
+
An `httpx.TimeoutException` subclass will be raised if the timeout is exceeded.
|
228
|
+
|
157
229
|
## Embeddings
|
158
230
|
|
159
231
|
The plugin also adds support for the `gemini-embedding-exp-03-07` and `text-embedding-004` embedding models.
|
@@ -186,6 +258,21 @@ llm similar readmes -c 'upload csvs to stuff' -d embed.db
|
|
186
258
|
|
187
259
|
See the [LLM embeddings documentation](https://llm.datasette.io/en/stable/embeddings/cli.html) for further details.
|
188
260
|
|
261
|
+
## Listing all Gemini API models
|
262
|
+
|
263
|
+
The `llm gemini models` command lists all of the models that are exposed by the Gemini API, some of which may not be available through this plugin.
|
264
|
+
|
265
|
+
```bash
|
266
|
+
llm gemini models
|
267
|
+
```
|
268
|
+
You can add a `--key X` option to use a different API key.
|
269
|
+
|
270
|
+
To filter models by their supported generation methods use `--method` one or more times:
|
271
|
+
```bash
|
272
|
+
llm gemini models --method embedContent
|
273
|
+
```
|
274
|
+
If you provide multiple methods you will see models that support any of them.
|
275
|
+
|
189
276
|
## Development
|
190
277
|
|
191
278
|
To set up this plugin locally, first checkout the code. Then create a new virtual environment:
|
@@ -40,6 +40,7 @@ GOOGLE_SEARCH_MODELS = {
|
|
40
40
|
"gemini-2.5-pro-exp-03-25",
|
41
41
|
"gemini-2.5-flash-preview-04-17",
|
42
42
|
"gemini-2.5-pro-preview-05-06",
|
43
|
+
"gemini-2.5-flash-preview-05-20",
|
43
44
|
}
|
44
45
|
|
45
46
|
# Older Google models used google_search_retrieval instead of google_search
|
@@ -54,14 +55,56 @@ GOOGLE_SEARCH_MODELS_USING_SEARCH_RETRIEVAL = {
|
|
54
55
|
}
|
55
56
|
|
56
57
|
THINKING_BUDGET_MODELS = {
|
58
|
+
"gemini-2.0-flash-thinking-exp-01-21",
|
59
|
+
"gemini-2.0-flash-thinking-exp-1219",
|
57
60
|
"gemini-2.5-flash-preview-04-17",
|
61
|
+
"gemini-2.5-pro-exp-03-25",
|
62
|
+
"gemini-2.5-pro-preview-03-25",
|
63
|
+
"gemini-2.5-pro-preview-05-06",
|
64
|
+
"gemini-2.5-flash-preview-05-20",
|
65
|
+
}
|
66
|
+
|
67
|
+
NO_VISION_MODELS = {"gemma-3-1b-it", "gemma-3n-e4b-it"}
|
68
|
+
|
69
|
+
ATTACHMENT_TYPES = {
|
70
|
+
# Text
|
71
|
+
"text/plain",
|
72
|
+
"text/csv",
|
73
|
+
# PDF
|
74
|
+
"application/pdf",
|
75
|
+
# Images
|
76
|
+
"image/png",
|
77
|
+
"image/jpeg",
|
78
|
+
"image/webp",
|
79
|
+
"image/heic",
|
80
|
+
"image/heif",
|
81
|
+
# Audio
|
82
|
+
"audio/wav",
|
83
|
+
"audio/mp3",
|
84
|
+
"audio/aiff",
|
85
|
+
"audio/aac",
|
86
|
+
"audio/ogg",
|
87
|
+
"application/ogg",
|
88
|
+
"audio/flac",
|
89
|
+
"audio/mpeg", # Treated as audio/mp3
|
90
|
+
# Video
|
91
|
+
"video/mp4",
|
92
|
+
"video/mpeg",
|
93
|
+
"video/mov",
|
94
|
+
"video/avi",
|
95
|
+
"video/x-flv",
|
96
|
+
"video/mpg",
|
97
|
+
"video/webm",
|
98
|
+
"video/wmv",
|
99
|
+
"video/3gpp",
|
100
|
+
"video/quicktime",
|
58
101
|
}
|
59
102
|
|
60
103
|
|
61
104
|
@llm.hookimpl
|
62
105
|
def register_models(register):
|
63
106
|
# Register both sync and async versions of each model
|
64
|
-
for model_id in
|
107
|
+
for model_id in (
|
65
108
|
"gemini-pro",
|
66
109
|
"gemini-1.5-pro-latest",
|
67
110
|
"gemini-1.5-flash-latest",
|
@@ -76,6 +119,12 @@ def register_models(register):
|
|
76
119
|
"gemini-exp-1206",
|
77
120
|
"gemini-2.0-flash-exp",
|
78
121
|
"learnlm-1.5-pro-experimental",
|
122
|
+
# Gemma 3 models:
|
123
|
+
"gemma-3-1b-it",
|
124
|
+
"gemma-3-4b-it",
|
125
|
+
"gemma-3-12b-it", # 12th March 2025
|
126
|
+
"gemma-3-27b-it",
|
127
|
+
"gemma-3n-e4b-it", # 20th May 2025
|
79
128
|
"gemini-2.0-flash-thinking-exp-1219",
|
80
129
|
"gemini-2.0-flash-thinking-exp-01-21",
|
81
130
|
# Released 5th Feb 2025:
|
@@ -83,8 +132,6 @@ def register_models(register):
|
|
83
132
|
"gemini-2.0-pro-exp-02-05",
|
84
133
|
# Released 25th Feb 2025:
|
85
134
|
"gemini-2.0-flash-lite",
|
86
|
-
# Released 12th March 2025:
|
87
|
-
"gemma-3-27b-it",
|
88
135
|
# 25th March 2025:
|
89
136
|
"gemini-2.5-pro-exp-03-25",
|
90
137
|
# 4th April 2025 (paid):
|
@@ -93,22 +140,29 @@ def register_models(register):
|
|
93
140
|
"gemini-2.5-flash-preview-04-17",
|
94
141
|
# 6th May 2025:
|
95
142
|
"gemini-2.5-pro-preview-05-06",
|
96
|
-
|
143
|
+
# 20th May 2025:
|
144
|
+
"gemini-2.5-flash-preview-05-20",
|
145
|
+
):
|
97
146
|
can_google_search = model_id in GOOGLE_SEARCH_MODELS
|
98
147
|
can_thinking_budget = model_id in THINKING_BUDGET_MODELS
|
148
|
+
can_vision = model_id not in NO_VISION_MODELS
|
149
|
+
can_schema = "flash-thinking" not in model_id and "gemma-3" not in model_id
|
99
150
|
register(
|
100
151
|
GeminiPro(
|
101
152
|
model_id,
|
153
|
+
can_vision=can_vision,
|
102
154
|
can_google_search=can_google_search,
|
103
155
|
can_thinking_budget=can_thinking_budget,
|
104
|
-
can_schema=
|
156
|
+
can_schema=can_schema,
|
105
157
|
),
|
106
158
|
AsyncGeminiPro(
|
107
159
|
model_id,
|
160
|
+
can_vision=can_vision,
|
108
161
|
can_google_search=can_google_search,
|
109
162
|
can_thinking_budget=can_thinking_budget,
|
110
|
-
can_schema=
|
163
|
+
can_schema=can_schema,
|
111
164
|
),
|
165
|
+
aliases=(model_id,),
|
112
166
|
)
|
113
167
|
|
114
168
|
|
@@ -150,39 +204,7 @@ class _SharedGemini:
|
|
150
204
|
supports_schema = True
|
151
205
|
supports_tools = True
|
152
206
|
|
153
|
-
attachment_types = (
|
154
|
-
# Text
|
155
|
-
"text/plain",
|
156
|
-
"text/csv",
|
157
|
-
# PDF
|
158
|
-
"application/pdf",
|
159
|
-
# Images
|
160
|
-
"image/png",
|
161
|
-
"image/jpeg",
|
162
|
-
"image/webp",
|
163
|
-
"image/heic",
|
164
|
-
"image/heif",
|
165
|
-
# Audio
|
166
|
-
"audio/wav",
|
167
|
-
"audio/mp3",
|
168
|
-
"audio/aiff",
|
169
|
-
"audio/aac",
|
170
|
-
"audio/ogg",
|
171
|
-
"application/ogg",
|
172
|
-
"audio/flac",
|
173
|
-
"audio/mpeg", # Treated as audio/mp3
|
174
|
-
# Video
|
175
|
-
"video/mp4",
|
176
|
-
"video/mpeg",
|
177
|
-
"video/mov",
|
178
|
-
"video/avi",
|
179
|
-
"video/x-flv",
|
180
|
-
"video/mpg",
|
181
|
-
"video/webm",
|
182
|
-
"video/wmv",
|
183
|
-
"video/3gpp",
|
184
|
-
"video/quicktime",
|
185
|
-
)
|
207
|
+
attachment_types = set()
|
186
208
|
|
187
209
|
class Options(llm.Options):
|
188
210
|
code_execution: Optional[bool] = Field(
|
@@ -228,6 +250,14 @@ class _SharedGemini:
|
|
228
250
|
description="Output a valid JSON object {...}",
|
229
251
|
default=None,
|
230
252
|
)
|
253
|
+
timeout: Optional[float] = Field(
|
254
|
+
description=(
|
255
|
+
"The maximum time in seconds to wait for a response. "
|
256
|
+
"If the model does not respond within this time, "
|
257
|
+
"the request will be aborted."
|
258
|
+
),
|
259
|
+
default=None,
|
260
|
+
)
|
231
261
|
|
232
262
|
class OptionsWithGoogleSearch(Options):
|
233
263
|
google_search: Optional[bool] = Field(
|
@@ -243,12 +273,14 @@ class _SharedGemini:
|
|
243
273
|
|
244
274
|
def __init__(
|
245
275
|
self,
|
246
|
-
|
276
|
+
gemini_model_id,
|
277
|
+
can_vision=True,
|
247
278
|
can_google_search=False,
|
248
279
|
can_thinking_budget=False,
|
249
280
|
can_schema=False,
|
250
281
|
):
|
251
|
-
self.model_id =
|
282
|
+
self.model_id = "gemini/{}".format(gemini_model_id)
|
283
|
+
self.gemini_model_id = gemini_model_id
|
252
284
|
self.can_google_search = can_google_search
|
253
285
|
self.supports_schema = can_schema
|
254
286
|
if can_google_search:
|
@@ -256,6 +288,8 @@ class _SharedGemini:
|
|
256
288
|
self.can_thinking_budget = can_thinking_budget
|
257
289
|
if can_thinking_budget:
|
258
290
|
self.Options = self.OptionsWithThinkingBudget
|
291
|
+
if can_vision:
|
292
|
+
self.attachment_types = ATTACHMENT_TYPES
|
259
293
|
|
260
294
|
def build_messages(self, prompt, conversation):
|
261
295
|
messages = []
|
@@ -453,14 +487,14 @@ class _SharedGemini:
|
|
453
487
|
|
454
488
|
class GeminiPro(_SharedGemini, llm.KeyModel):
|
455
489
|
def execute(self, prompt, stream, response, conversation, key):
|
456
|
-
url = f"https://generativelanguage.googleapis.com/v1beta/models/{self.
|
490
|
+
url = f"https://generativelanguage.googleapis.com/v1beta/models/{self.gemini_model_id}:streamGenerateContent"
|
457
491
|
gathered = []
|
458
492
|
body = self.build_request_body(prompt, conversation)
|
459
493
|
|
460
494
|
with httpx.stream(
|
461
495
|
"POST",
|
462
496
|
url,
|
463
|
-
timeout=
|
497
|
+
timeout=prompt.options.timeout,
|
464
498
|
headers={"x-goog-api-key": self.get_key(key)},
|
465
499
|
json=body,
|
466
500
|
) as http_response:
|
@@ -486,7 +520,7 @@ class GeminiPro(_SharedGemini, llm.KeyModel):
|
|
486
520
|
|
487
521
|
class AsyncGeminiPro(_SharedGemini, llm.AsyncKeyModel):
|
488
522
|
async def execute(self, prompt, stream, response, conversation, key):
|
489
|
-
url = f"https://generativelanguage.googleapis.com/v1beta/models/{self.
|
523
|
+
url = f"https://generativelanguage.googleapis.com/v1beta/models/{self.gemini_model_id}:streamGenerateContent"
|
490
524
|
gathered = []
|
491
525
|
body = self.build_request_body(prompt, conversation)
|
492
526
|
|
@@ -494,7 +528,7 @@ class AsyncGeminiPro(_SharedGemini, llm.AsyncKeyModel):
|
|
494
528
|
async with client.stream(
|
495
529
|
"POST",
|
496
530
|
url,
|
497
|
-
timeout=
|
531
|
+
timeout=prompt.options.timeout,
|
498
532
|
headers={"x-goog-api-key": self.get_key(key)},
|
499
533
|
json=body,
|
500
534
|
) as http_response:
|
@@ -584,8 +618,20 @@ def register_commands(cli):
|
|
584
618
|
|
585
619
|
@gemini.command()
|
586
620
|
@click.option("--key", help="API key to use")
|
587
|
-
|
588
|
-
"
|
621
|
+
@click.option(
|
622
|
+
"methods",
|
623
|
+
"--method",
|
624
|
+
multiple=True,
|
625
|
+
help="Filter by supported generation methods",
|
626
|
+
)
|
627
|
+
def models(key, methods):
|
628
|
+
"""
|
629
|
+
List of Gemini models pulled from their API
|
630
|
+
|
631
|
+
Use --method to filter by supported generation methods for example:
|
632
|
+
|
633
|
+
llm gemini models --method generateContent --method embedContent
|
634
|
+
"""
|
589
635
|
key = llm.get_key(key, "gemini", "LLM_GEMINI_KEY")
|
590
636
|
if not key:
|
591
637
|
raise click.ClickException(
|
@@ -594,7 +640,16 @@ def register_commands(cli):
|
|
594
640
|
url = f"https://generativelanguage.googleapis.com/v1beta/models"
|
595
641
|
response = httpx.get(url, headers={"x-goog-api-key": key})
|
596
642
|
response.raise_for_status()
|
597
|
-
|
643
|
+
models = response.json()["models"]
|
644
|
+
if methods:
|
645
|
+
models = [
|
646
|
+
model
|
647
|
+
for model in models
|
648
|
+
if any(
|
649
|
+
method in model["supportedGenerationMethods"] for method in methods
|
650
|
+
)
|
651
|
+
]
|
652
|
+
click.echo(json.dumps(models, indent=2))
|
598
653
|
|
599
654
|
@gemini.command()
|
600
655
|
@click.option("--key", help="API key to use")
|
@@ -1,13 +1,13 @@
|
|
1
1
|
[project]
|
2
2
|
name = "llm-gemini"
|
3
|
-
version = "0.
|
3
|
+
version = "0.21"
|
4
4
|
description = "LLM plugin to access Google's Gemini family of models"
|
5
5
|
readme = "README.md"
|
6
6
|
authors = [{name = "Simon Willison"}]
|
7
7
|
license = "Apache-2.0"
|
8
8
|
classifiers = []
|
9
9
|
dependencies = [
|
10
|
-
"llm>=0.
|
10
|
+
"llm>=0.26",
|
11
11
|
"httpx",
|
12
12
|
"ijson"
|
13
13
|
]
|
@@ -22,7 +22,7 @@ CI = "https://github.com/simonw/llm-gemini/actions"
|
|
22
22
|
gemini = "llm_gemini"
|
23
23
|
|
24
24
|
[project.optional-dependencies]
|
25
|
-
test = ["pytest", "pytest-recording", "pytest-asyncio", "nest-asyncio"]
|
25
|
+
test = ["pytest", "pytest-recording", "pytest-asyncio", "nest-asyncio", "cogapp"]
|
26
26
|
|
27
27
|
[tool.pytest.ini_options]
|
28
28
|
asyncio_mode = "strict"
|
@@ -232,6 +232,14 @@ def test_cli_gemini_models(tmpdir, monkeypatch):
|
|
232
232
|
result2 = runner.invoke(cli, ["gemini", "models", "--key", GEMINI_API_KEY])
|
233
233
|
assert result2.exit_code == 0
|
234
234
|
assert "gemini-1.5-flash-latest" in result2.output
|
235
|
+
# And with --method
|
236
|
+
result3 = runner.invoke(
|
237
|
+
cli, ["gemini", "models", "--key", GEMINI_API_KEY, "--method", "embedContent"]
|
238
|
+
)
|
239
|
+
assert result3.exit_code == 0
|
240
|
+
models = json.loads(result3.output)
|
241
|
+
for model in models:
|
242
|
+
assert "embedContent" in model["supportedGenerationMethods"]
|
235
243
|
|
236
244
|
|
237
245
|
@pytest.mark.vcr
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|