gemini-reverse 1.0.1 → 1.0.3
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.
- package/README.md +139 -154
- package/client.js +668 -152
- package/components/chatMixin.js +129 -70
- package/components/index.js +2 -1
- package/components/researchMixin.js +202 -0
- package/constants.js +157 -36
- package/index.d.ts +254 -46
- package/index.js +35 -5
- package/package.json +1 -1
- package/types/availablemodel.js +76 -0
- package/types/candidate.js +31 -17
- package/types/chathistory.js +36 -0
- package/types/chatinfo.js +23 -0
- package/types/index.js +26 -2
- package/types/modeloutput.js +16 -28
- package/types/research.js +65 -0
- package/types/researchresult.js +21 -0
- package/types/video.js +195 -0
- package/utils/accessToken.js +15 -7
- package/utils/index.js +22 -3
- package/utils/parsing.js +67 -38
- package/utils/research.js +175 -0
package/README.md
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-

|
|
2
|
-
|
|
3
1
|
# Gemini-Reverse
|
|
4
2
|
|
|
5
3
|
An unofficial Node.js client for [gemini.google.com](https://gemini.google.com), inspired by [Gemini-API](https://github.com/HanaokaYuzu/Gemini-API) — a Python reverse engineering project by [@HanaokaYuzu](https://github.com/HanaokaYuzu).
|
|
6
4
|
|
|
7
|
-
This package ports the core concepts and functionality of the original Python library to Node.js, with full CommonJS and TypeScript support.
|
|
8
|
-
|
|
9
5
|
---
|
|
10
6
|
|
|
11
7
|
## Features
|
|
@@ -14,7 +10,11 @@ This package ports the core concepts and functionality of the original Python li
|
|
|
14
10
|
- Streaming support with text deltas
|
|
15
11
|
- Multi-turn chat sessions with conversation history
|
|
16
12
|
- File and image upload support
|
|
13
|
+
- Video and media (audio) support
|
|
17
14
|
- Gem (system prompt) management — create, update, delete, fetch
|
|
15
|
+
- Deep research support — create plan, start, poll, and get results
|
|
16
|
+
- Dynamic model discovery from account RPC
|
|
17
|
+
- Account status detection
|
|
18
18
|
- Auto cookie refresh to keep sessions alive
|
|
19
19
|
- TypeScript type declarations included
|
|
20
20
|
- Proxy support
|
|
@@ -31,32 +31,28 @@ npm install gemini-reverse
|
|
|
31
31
|
|
|
32
32
|
## Authentication
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
3. Copy the value of `__Secure-1PSID` (and optionally `__Secure-1PSIDTS`)
|
|
40
|
-
|
|
41
|
-
> `__Secure-1PSIDTS` is optional — the client will attempt to refresh and cache it automatically after the first successful init.
|
|
34
|
+
```
|
|
35
|
+
1. Open gemini.google.com and log in
|
|
36
|
+
2. DevTools → Application → Cookies → https://gemini.google.com
|
|
37
|
+
3. Copy __Secure-1PSID (and optionally __Secure-1PSIDTS)
|
|
38
|
+
```
|
|
42
39
|
|
|
43
40
|
---
|
|
44
41
|
|
|
45
42
|
## Quick Start
|
|
46
43
|
|
|
47
44
|
```js
|
|
48
|
-
const { GeminiClient } = require('gemini-
|
|
45
|
+
const { GeminiClient } = require('gemini-reverse');
|
|
49
46
|
|
|
50
|
-
const client = new GeminiClient({
|
|
51
|
-
secure_1psid: 'YOUR_SECURE_1PSID',
|
|
52
|
-
});
|
|
47
|
+
const client = new GeminiClient({ secure_1psid: 'YOUR_SECURE_1PSID' });
|
|
53
48
|
|
|
54
49
|
await client.init();
|
|
55
50
|
|
|
56
51
|
const chat = client.startChat();
|
|
57
52
|
const response = await chat.sendMessage({ prompt: 'Hello, Gemini!' });
|
|
58
|
-
|
|
59
53
|
console.log(response.text);
|
|
54
|
+
|
|
55
|
+
await client.close();
|
|
60
56
|
```
|
|
61
57
|
|
|
62
58
|
---
|
|
@@ -66,22 +62,18 @@ console.log(response.text);
|
|
|
66
62
|
### Initialize Client
|
|
67
63
|
|
|
68
64
|
```js
|
|
69
|
-
const client = new GeminiClient({
|
|
70
|
-
secure_1psid: 'YOUR_SECURE_1PSID',
|
|
71
|
-
secure_1psidts: 'YOUR_SECURE_1PSIDTS', // optional
|
|
72
|
-
proxy: 'http://host:port', // optional
|
|
73
|
-
});
|
|
74
|
-
|
|
75
65
|
await client.init({
|
|
76
|
-
timeout: 300000,
|
|
77
|
-
autoClose: false,
|
|
78
|
-
closeDelay: 300000,
|
|
79
|
-
autoRefresh: true,
|
|
80
|
-
refreshInterval: 540000
|
|
66
|
+
timeout: 300000,
|
|
67
|
+
autoClose: false,
|
|
68
|
+
closeDelay: 300000,
|
|
69
|
+
autoRefresh: true,
|
|
70
|
+
refreshInterval: 540000,
|
|
71
|
+
verbose: false,
|
|
72
|
+
watchdogTimeout: 30000,
|
|
81
73
|
});
|
|
82
74
|
```
|
|
83
75
|
|
|
84
|
-
### Generate Content
|
|
76
|
+
### Generate Content
|
|
85
77
|
|
|
86
78
|
```js
|
|
87
79
|
const response = await client.generateContent({ prompt: 'What is the capital of France?' });
|
|
@@ -99,106 +91,118 @@ for await (const chunk of client.generateContentStream({ prompt: 'Tell me a long
|
|
|
99
91
|
### Chat Session
|
|
100
92
|
|
|
101
93
|
```js
|
|
102
|
-
const chat = client.startChat({ model: 'gemini-3
|
|
94
|
+
const chat = client.startChat({ model: 'gemini-3-flash' });
|
|
103
95
|
|
|
104
96
|
const res1 = await chat.sendMessage({ prompt: 'My name is Alice.' });
|
|
105
|
-
console.log(res1.text);
|
|
106
|
-
|
|
107
97
|
const res2 = await chat.sendMessage({ prompt: 'What is my name?' });
|
|
108
|
-
console.log(res2.text);
|
|
98
|
+
console.log(res2.text);
|
|
109
99
|
```
|
|
110
100
|
|
|
111
101
|
### Streaming in Chat
|
|
112
102
|
|
|
113
103
|
```js
|
|
114
|
-
const chat = client.startChat(
|
|
115
|
-
|
|
104
|
+
const chat = client.startChat();
|
|
116
105
|
for await (const chunk of chat.sendMessageStream({ prompt: 'Explain quantum computing.' })) {
|
|
117
106
|
process.stdout.write(chunk.text_delta);
|
|
118
107
|
}
|
|
119
108
|
```
|
|
120
109
|
|
|
121
|
-
### Temporary Chat
|
|
110
|
+
### Temporary Chat
|
|
122
111
|
|
|
123
112
|
```js
|
|
124
|
-
const chat = client.startChat();
|
|
125
113
|
const response = await chat.sendMessage({ prompt: 'This will not appear in history.', temporary: true });
|
|
126
114
|
```
|
|
127
115
|
|
|
128
116
|
### Send with Files
|
|
129
117
|
|
|
130
118
|
```js
|
|
131
|
-
const chat = client.startChat();
|
|
132
119
|
const response = await chat.sendMessage({
|
|
133
120
|
prompt: 'Describe this image.',
|
|
134
121
|
files: ['./photo.jpg'],
|
|
135
122
|
});
|
|
136
|
-
console.log(response.text);
|
|
137
123
|
```
|
|
138
124
|
|
|
139
125
|
### Multiple Candidates
|
|
140
126
|
|
|
141
127
|
```js
|
|
142
|
-
const chat = client.startChat();
|
|
143
128
|
const response = await chat.sendMessage({ prompt: 'Give me a poem.' });
|
|
144
|
-
|
|
145
|
-
// list all candidates
|
|
146
129
|
response.candidates.forEach((c, i) => console.log(`[${i}] ${c.text}`));
|
|
147
|
-
|
|
148
|
-
// choose a specific candidate to continue the conversation
|
|
149
130
|
chat.chooseCandidate(1);
|
|
150
131
|
```
|
|
151
132
|
|
|
152
133
|
### Models
|
|
153
134
|
|
|
154
135
|
```js
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
136
|
+
const models = client.listModels();
|
|
137
|
+
if (models) {
|
|
138
|
+
for (const m of models) {
|
|
139
|
+
console.log(m.model_id, m.model_name, m.display_name);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const chat = client.startChat({ model: 'gemini-3-flash' });
|
|
144
|
+
|
|
145
|
+
const { Model } = require('gemini-reverse');
|
|
146
|
+
const chat2 = client.startChat({ model: Model.BASIC_FLASH });
|
|
147
|
+
|
|
148
|
+
const chat3 = client.startChat({
|
|
149
|
+
model: { model_name: 'my-model', model_header: { 'x-goog-ext-525001261-jspb': '...' } },
|
|
168
150
|
});
|
|
169
151
|
```
|
|
170
152
|
|
|
171
|
-
**
|
|
153
|
+
**Built-in model constants:**
|
|
172
154
|
|
|
173
|
-
|
|
|
155
|
+
| Constant | model_name |
|
|
174
156
|
|---|---|
|
|
175
|
-
| `
|
|
176
|
-
| `
|
|
177
|
-
| `
|
|
178
|
-
| `
|
|
157
|
+
| `Model.UNSPECIFIED` | `unspecified` (default) |
|
|
158
|
+
| `Model.BASIC_PRO` | `gemini-3-pro` |
|
|
159
|
+
| `Model.BASIC_FLASH` | `gemini-3-flash` |
|
|
160
|
+
| `Model.BASIC_THINKING` | `gemini-3-flash-thinking` |
|
|
161
|
+
| `Model.PLUS_PRO` | `gemini-3-pro-plus` |
|
|
162
|
+
| `Model.PLUS_FLASH` | `gemini-3-flash-plus` |
|
|
163
|
+
| `Model.PLUS_THINKING` | `gemini-3-flash-thinking-plus` |
|
|
164
|
+
| `Model.ADVANCED_PRO` | `gemini-3-pro-advanced` |
|
|
165
|
+
| `Model.ADVANCED_FLASH` | `gemini-3-flash-advanced` |
|
|
166
|
+
| `Model.ADVANCED_THINKING` | `gemini-3-flash-thinking-advanced` |
|
|
179
167
|
|
|
180
168
|
### Images
|
|
181
169
|
|
|
182
|
-
Responses may include web images or AI-generated images.
|
|
183
|
-
|
|
184
170
|
```js
|
|
185
|
-
const response = await chat.sendMessage({ prompt: 'Send me an image of a cat.' });
|
|
186
|
-
|
|
187
171
|
for (const img of response.images) {
|
|
188
172
|
console.log(img.url, img.title, img.alt);
|
|
189
173
|
await img.save({ path: './downloads', verbose: true });
|
|
190
174
|
}
|
|
191
175
|
```
|
|
192
176
|
|
|
193
|
-
###
|
|
177
|
+
### Videos & Media
|
|
194
178
|
|
|
195
179
|
```js
|
|
196
|
-
const
|
|
180
|
+
for (const video of response.videos) {
|
|
181
|
+
await video.save({ savePath: './downloads', verbose: true });
|
|
182
|
+
}
|
|
183
|
+
for (const media of response.media) {
|
|
184
|
+
await media.save({ savePath: './downloads', downloadType: 'both', verbose: true });
|
|
185
|
+
}
|
|
186
|
+
```
|
|
197
187
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
188
|
+
### Chat History
|
|
189
|
+
|
|
190
|
+
```js
|
|
191
|
+
const history = await client.readChat('c_YOUR_CHAT_ID');
|
|
192
|
+
if (history) {
|
|
193
|
+
for (const turn of history.turns) {
|
|
194
|
+
console.log(turn.role, turn.text);
|
|
195
|
+
}
|
|
201
196
|
}
|
|
197
|
+
|
|
198
|
+
const chats = client.listChats();
|
|
199
|
+
if (chats) {
|
|
200
|
+
for (const info of chats) {
|
|
201
|
+
console.log(info.cid, info.title, info.is_pinned);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const sessionHistory = await chat.readHistory(10);
|
|
202
206
|
```
|
|
203
207
|
|
|
204
208
|
### Delete Chat
|
|
@@ -207,61 +211,69 @@ for (const turn of turns) {
|
|
|
207
211
|
await client.deleteChat('c_YOUR_CHAT_ID');
|
|
208
212
|
```
|
|
209
213
|
|
|
214
|
+
### Deep Research
|
|
215
|
+
|
|
216
|
+
```js
|
|
217
|
+
const plan = await client.createDeepResearchPlan('History of artificial intelligence');
|
|
218
|
+
console.log(plan.title, plan.steps);
|
|
219
|
+
|
|
220
|
+
const startOutput = await client.startDeepResearch(plan);
|
|
221
|
+
|
|
222
|
+
const result = await client.waitForDeepResearch(plan, 10000, 600000, (status) => {
|
|
223
|
+
console.log(status.state, status.notes);
|
|
224
|
+
});
|
|
225
|
+
console.log(result.text);
|
|
226
|
+
|
|
227
|
+
const result2 = await client.deepResearch('Explain quantum computing', 10000, 600000);
|
|
228
|
+
console.log(result2.text);
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Account Status
|
|
232
|
+
|
|
233
|
+
```js
|
|
234
|
+
const { AccountStatus } = require('gemini-reverse');
|
|
235
|
+
|
|
236
|
+
if (client.accountStatus === AccountStatus.UNAUTHENTICATED) {
|
|
237
|
+
console.error('Cookies expired.');
|
|
238
|
+
} else if (client.accountStatus === AccountStatus.LOCATION_REJECTED) {
|
|
239
|
+
console.error('Gemini not available in your region.');
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
210
243
|
### Gems
|
|
211
244
|
|
|
212
245
|
```js
|
|
213
|
-
// fetch all gems
|
|
214
246
|
const gems = await client.fetchGems();
|
|
215
|
-
|
|
216
|
-
// get by name
|
|
217
247
|
const gem = gems.get({ name: 'Coding partner' });
|
|
218
|
-
|
|
219
|
-
// filter user-created gems
|
|
220
248
|
const myGems = gems.filter({ predefined: false });
|
|
249
|
+
const chat = client.startChat({ gem });
|
|
221
250
|
|
|
222
|
-
// use a gem in chat
|
|
223
|
-
const chat = client.startChat({ gem: gem });
|
|
224
|
-
|
|
225
|
-
// create a gem
|
|
226
251
|
const newGem = await client.createGem({
|
|
227
252
|
name: 'My Assistant',
|
|
228
253
|
prompt: 'You are a helpful assistant that speaks formally.',
|
|
229
|
-
description: 'Formal assistant gem',
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
// update a gem
|
|
233
|
-
await client.updateGem({
|
|
234
|
-
gem: newGem,
|
|
235
|
-
name: 'My Assistant v2',
|
|
236
|
-
prompt: 'You are a helpful assistant that speaks casually.',
|
|
237
254
|
});
|
|
238
255
|
|
|
239
|
-
|
|
256
|
+
await client.updateGem({ gem: newGem, name: 'My Assistant v2', prompt: 'Speak casually.' });
|
|
240
257
|
await client.deleteGem(newGem);
|
|
241
258
|
```
|
|
242
259
|
|
|
243
|
-
### Close Client
|
|
244
|
-
|
|
245
|
-
```js
|
|
246
|
-
await client.close();
|
|
247
|
-
```
|
|
248
|
-
|
|
249
260
|
---
|
|
250
261
|
|
|
251
|
-
##
|
|
252
|
-
|
|
253
|
-
This package includes full TypeScript declarations out of the box.
|
|
254
|
-
|
|
255
|
-
```ts
|
|
256
|
-
import { GeminiClient, ChatSession, ModelOutput, ConversationTurn, Gem, Model } from 'gemini-api';
|
|
257
|
-
|
|
258
|
-
const client = new GeminiClient({ secure_1psid: '...' });
|
|
259
|
-
await client.init();
|
|
262
|
+
## Error Handling
|
|
260
263
|
|
|
261
|
-
|
|
262
|
-
const
|
|
264
|
+
```js
|
|
265
|
+
const { AuthError, APIError, GeminiError, TimeoutError, UsageLimitExceeded, ModelInvalid, TemporarilyBlocked } = require('gemini-reverse');
|
|
263
266
|
|
|
264
|
-
|
|
267
|
+
try {
|
|
268
|
+
const response = await chat.sendMessage({ prompt: 'Hello!' });
|
|
269
|
+
} catch (e) {
|
|
270
|
+
if (e instanceof AuthError) console.error('Cookie expired or invalid.');
|
|
271
|
+
else if (e instanceof UsageLimitExceeded) console.error('Usage limit reached.');
|
|
272
|
+
else if (e instanceof TemporarilyBlocked) console.error('IP temporarily blocked.');
|
|
273
|
+
else if (e instanceof TimeoutError) console.error('Request timed out.');
|
|
274
|
+
else if (e instanceof ModelInvalid) console.error('Invalid model.');
|
|
275
|
+
else if (e instanceof APIError) console.error('API error:', e.message);
|
|
276
|
+
}
|
|
265
277
|
```
|
|
266
278
|
|
|
267
279
|
---
|
|
@@ -269,77 +281,50 @@ console.log(response.text);
|
|
|
269
281
|
## Project Structure
|
|
270
282
|
|
|
271
283
|
```
|
|
272
|
-
gemini-
|
|
273
|
-
├── index.js
|
|
274
|
-
├── index.d.ts
|
|
275
|
-
├── client.js
|
|
276
|
-
├── constants.js
|
|
277
|
-
├── exceptions.js
|
|
284
|
+
gemini-reverse/
|
|
285
|
+
├── index.js
|
|
286
|
+
├── index.d.ts
|
|
287
|
+
├── client.js
|
|
288
|
+
├── constants.js
|
|
289
|
+
├── exceptions.js
|
|
278
290
|
├── types/
|
|
291
|
+
│ ├── availablemodel.js
|
|
279
292
|
│ ├── candidate.js
|
|
280
|
-
│ ├──
|
|
293
|
+
│ ├── chathistory.js
|
|
294
|
+
│ ├── chatinfo.js
|
|
281
295
|
│ ├── gem.js
|
|
282
296
|
│ ├── grpc.js
|
|
283
297
|
│ ├── image.js
|
|
284
|
-
│
|
|
298
|
+
│ ├── modeloutput.js
|
|
299
|
+
│ ├── research.js
|
|
300
|
+
│ ├── researchresult.js
|
|
301
|
+
│ └── video.js
|
|
285
302
|
├── utils/
|
|
286
303
|
│ ├── accessToken.js
|
|
287
304
|
│ ├── parsing.js
|
|
305
|
+
│ ├── research.js
|
|
288
306
|
│ ├── rotate.js
|
|
289
307
|
│ └── upload.js
|
|
290
308
|
└── components/
|
|
291
309
|
├── chatMixin.js
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
---
|
|
296
|
-
|
|
297
|
-
## Error Handling
|
|
298
|
-
|
|
299
|
-
```js
|
|
300
|
-
const {
|
|
301
|
-
AuthError,
|
|
302
|
-
APIError,
|
|
303
|
-
GeminiError,
|
|
304
|
-
TimeoutError,
|
|
305
|
-
UsageLimitExceeded,
|
|
306
|
-
ModelInvalid,
|
|
307
|
-
TemporarilyBlocked,
|
|
308
|
-
} = require('gemini-api');
|
|
309
|
-
|
|
310
|
-
try {
|
|
311
|
-
const response = await chat.sendMessage({ prompt: 'Hello!' });
|
|
312
|
-
} catch (e) {
|
|
313
|
-
if (e instanceof AuthError) {
|
|
314
|
-
console.error('Cookie expired or invalid.');
|
|
315
|
-
} else if (e instanceof UsageLimitExceeded) {
|
|
316
|
-
console.error('Usage limit reached. Try again later or switch models.');
|
|
317
|
-
} else if (e instanceof TemporarilyBlocked) {
|
|
318
|
-
console.error('IP temporarily blocked. Try using a proxy.');
|
|
319
|
-
} else if (e instanceof TimeoutError) {
|
|
320
|
-
console.error('Request timed out.');
|
|
321
|
-
} else if (e instanceof ModelInvalid) {
|
|
322
|
-
console.error('Invalid or unavailable model.');
|
|
323
|
-
} else if (e instanceof APIError) {
|
|
324
|
-
console.error('API error:', e.message);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
310
|
+
├── gemMixin.js
|
|
311
|
+
└── researchMixin.js
|
|
327
312
|
```
|
|
328
313
|
|
|
329
314
|
---
|
|
330
315
|
|
|
331
316
|
## Credits
|
|
332
317
|
|
|
333
|
-
Inspired by [Gemini-API](https://github.com/HanaokaYuzu/Gemini-API) by [@HanaokaYuzu](https://github.com/HanaokaYuzu)
|
|
318
|
+
Inspired by [Gemini-API](https://github.com/HanaokaYuzu/Gemini-API) by [@HanaokaYuzu](https://github.com/HanaokaYuzu).
|
|
334
319
|
|
|
335
320
|
---
|
|
336
321
|
|
|
337
322
|
## Disclaimer
|
|
338
323
|
|
|
339
|
-
|
|
324
|
+
Unofficial package, not affiliated with Google. Use at your own risk.
|
|
340
325
|
|
|
341
326
|
---
|
|
342
327
|
|
|
343
328
|
## License
|
|
344
329
|
|
|
345
|
-
MIT
|
|
330
|
+
MIT
|