gemini-reverse 1.0.8 → 1.0.10
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/CHANGELOG-EN.md +75 -0
- package/CHANGELOG-IDN.md +75 -0
- package/README-IDN.md +800 -0
- package/README.md +2 -0
- package/package.json +1 -1
package/CHANGELOG-EN.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
> **Language / Bahasa:** [English](CHANGELOG-EN.md) · [Indonesia](CHANGELOG-IDN.md) | **README:** [EN](README.md) · [IDN](README-IDN.md)
|
|
4
|
+
|
|
5
|
+
All notable changes to this project will be documented in this file.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## [1.0.7]
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **Extended Thinking** — `extended_thinking` parameter on `generateContent`, `generateContentStream`, `sendMessage`, and `sendMessageStream`. Enables deeper reasoning mode on supported models. Model header is extended at request time with the thinking flag and session ID.
|
|
13
|
+
- **`StreamingFrameParser`** — New stateful incremental frame parser class replacing the stateless `parseResponseByFrame`. Buffers partial frames efficiently across network chunks without rescanning already-processed bytes.
|
|
14
|
+
- **Quota & Usage Info** — `client.quotas`, `client.usageInfo`, and `client.abuseStatus` properties are populated automatically at initialization via `CHECK_GEMINI_QUOTA`, `CHECK_QUOTA`, `GET_USAGE_INFO`, and `GET_ABUSE_STATUS` RPCs.
|
|
15
|
+
- **Activity Watchdog** — Background timer (`_startActivityWatchdog`) sends periodic heartbeats every 60–300 seconds to keep the session alive without requiring explicit user requests.
|
|
16
|
+
- **`_checkAccountStatus()`** — Internal method that guards RPC calls from running on restricted accounts.
|
|
17
|
+
- **`_parseRpcResults()`** — Internal helper iterator for extracting typed bodies from batch RPC responses, including rejection code handling (code 7 → mark unauthenticated).
|
|
18
|
+
- **`_sessionid`** — Per-session UUID generated at constructor and refreshed on each `init()`. Used as a field in the model header for each generation request.
|
|
19
|
+
- **`source_path` in `_batchExecute`** — Optional parameter (default `/app`, `/usage` for `_fetchUsageInfo`).
|
|
20
|
+
- **`model_number` in `AvailableModel`** — New field mirrored from model header into request payload (`inner[79]`).
|
|
21
|
+
- **`buildModelIdNumberMapping()`** — Static method on `AvailableModel` returning a `modelId → modelNumber` mapping.
|
|
22
|
+
- **New models** — `BASIC_LITE` (`gemini-3-lite`), `PLUS_LITE` (`gemini-3-lite-plus`), `ADVANCED_LITE` (`gemini-3-lite-advanced`).
|
|
23
|
+
- **New GRPC keys** — Added from `pr`: `GET_CONVERSATION_TURN`, `UPDATE_CONVERSATION`, `MARK_LAST_CONVERSATION_TURN`, `GENERATE_HEADLINE`, `GET_GEM`, `DELETE_GEM_AND_CONVERSATIONS`, `CREATE_TASK`, `GET_TASK`, `GET_ALL_TASKS`, `GET_TASKS_IN_CONVERSATION`, `GET_CANDIDATES`, `LIST_DISCOVERY_CARDS`, `GET_DISCOVERY_CARD`, `LIST_DISCOVERY_BANNERS`, `LIST_GEMINI_APP_ARTIFACTS`, `DELETE_GEMINI_APP_ARTIFACTS`, `LIST_MEMORIES`, `CREATE_MEMORY`, `UPDATE_MEMORY`, `DELETE_MEMORY`, `DELETE_ALL_MEMORIES`, `CHECK_GEMINI_QUOTA`, `CHECK_QUOTA`, `GET_ABUSE_STATUS`, `UPDATE_USER_PREFERENCES`, `READ_USER_PREFERENCES`, `CONTINUE_SHARED_CONVERSATION`, `GET_USAGE_INFO`.
|
|
24
|
+
- **Auto-refresh jitter** — Cookie refresh interval now applies ±15 seconds of random jitter to prevent synchronized background requests.
|
|
25
|
+
- **`_fetchPreferences()` / `_syncActivity()`** — Replaced monolithic `_sendBardSettings` / `_sendBardActivity` with dedicated methods that cleanly separate preference sync from activity heartbeat.
|
|
26
|
+
- **Case-insensitive model resolution** — `_resolveModelByName` now matches model names and display names case-insensitively.
|
|
27
|
+
- **`_fetchRecentChats` account guard** — Skips fetching chat history if account status is not available.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- **Model header format** — Updated from `[4]` to `[4,5,6,8]` with a `model_number` appended at the end. Header `x-goog-ext-73010990-jspb` changed from `[0]` to `[0,0,0]`.
|
|
31
|
+
- **`Headers.BATCH_EXEC`** — Updated to match the new model header format.
|
|
32
|
+
- **Inner request array** — Size increased from 69 to 81 elements. `inner[68]` changed from `2` to `1`. New slots `inner[79]` (model_number) and `inner[80]` (thinking mode: `2` = extended, `1` = standard).
|
|
33
|
+
- **`_initRpc`** — Now calls `_fetchPreferences`, `_syncActivity`, `_fetchRecentChats`, `_fetchQuota`, `_fetchExtraQuota`, `_fetchAbuseStatus`, `_fetchUsageInfo` in sequence.
|
|
34
|
+
- **`THINKING` models removed** — `BASIC_THINKING`, `PLUS_THINKING`, `ADVANCED_THINKING` replaced by the `LITE` model family.
|
|
35
|
+
- **Upload cookies** — `uploadFile` now forwards session cookies alongside the `Push-ID` and REFERER headers.
|
|
36
|
+
- **HTML entity decoding** — Extended to cover numeric entities (`{`, ``) and additional named entities.
|
|
37
|
+
- **Video download headers** — `_downloadFile` in `video.js` now sends `Origin` and `Referer` headers.
|
|
38
|
+
- **`fetchGems` language** — Uses `this.language` instead of hardcoded `'en'`.
|
|
39
|
+
- **Auto-init on first call** — `generateContent` and `generateContentStream` call `init()` automatically if the client is not running.
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
- **Upload failure** — Fixed missing `Push-ID` header, content-type, and REFERER headers in `uploadFile`.
|
|
43
|
+
- **Quota key format** — Null entries in quota ID list are now filtered before joining, producing clean numeric keys (e.g. `11`, `4`) instead of `-11`, `-4`.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## [1.0.8]
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
- Fixed quota key format — null entries in quota ID list are now filtered before joining, producing clean numeric keys (e.g. `11`, `4`) instead of `-11`, `-4`.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## [1.0.6]
|
|
55
|
+
|
|
56
|
+
### Fixed
|
|
57
|
+
- Fixed file upload — upload now correctly sends cookies and required headers.
|
|
58
|
+
- Fixed media download for generated video and audio.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## [1.0.5]
|
|
63
|
+
|
|
64
|
+
### Fixed
|
|
65
|
+
- Fixed image generation parsing — `GeneratedImage` now uses `client_ref` pattern instead of requiring direct cookie injection.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## [1.0.4]
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
- Initial public release.
|
|
73
|
+
- `GeminiClient` with cookie-based authentication.
|
|
74
|
+
- Chat sessions, streaming, image generation, deep research, gems.
|
|
75
|
+
- TypeScript declarations.
|
package/CHANGELOG-IDN.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
> **Language / Bahasa:** [English](CHANGELOG-EN.md) · [Indonesia](CHANGELOG-IDN.md) | **README:** [EN](README.md) · [IDN](README-IDN.md)
|
|
4
|
+
|
|
5
|
+
Semua perubahan penting pada proyek ini dicatat di sini.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## [1.0.7]
|
|
10
|
+
|
|
11
|
+
### Ditambahkan
|
|
12
|
+
- **Extended Thinking** — Parameter `extended_thinking` pada `generateContent`, `generateContentStream`, `sendMessage`, dan `sendMessageStream`. Mengaktifkan mode penalaran mendalam pada model yang mendukung. Model header dimodifikasi saat request dengan menyertakan flag thinking dan session ID.
|
|
13
|
+
- **`StreamingFrameParser`** — Class parser frame stateful yang baru, menggantikan `parseResponseByFrame` yang stateless. Frame parsial di-buffer secara efisien antar chunk jaringan tanpa perlu memindai ulang data yang sudah diproses.
|
|
14
|
+
- **Quota & Info Penggunaan** — Property `client.quotas`, `client.usageInfo`, dan `client.abuseStatus` terisi otomatis saat inisialisasi lewat RPC `CHECK_GEMINI_QUOTA`, `CHECK_QUOTA`, `GET_USAGE_INFO`, dan `GET_ABUSE_STATUS`.
|
|
15
|
+
- **Activity Watchdog** — Timer background yang mengirim heartbeat setiap 60–300 detik secara acak untuk menjaga sesi tetap aktif tanpa perlu request manual.
|
|
16
|
+
- **`_checkAccountStatus()`** — Method internal untuk memastikan RPC tidak dijalankan pada akun yang dibatasi.
|
|
17
|
+
- **`_parseRpcResults()`** — Helper internal untuk mengekstrak isi dari respons batch RPC, termasuk penanganan rejection code (kode 7 → tandai sebagai unauthenticated).
|
|
18
|
+
- **`_sessionid`** — UUID per-sesi yang dibuat di constructor dan diperbarui setiap `init()`. Digunakan sebagai field di model header tiap request.
|
|
19
|
+
- **`source_path` di `_batchExecute`** — Parameter opsional (default `/app`, diisi `/usage` untuk `_fetchUsageInfo`).
|
|
20
|
+
- **`model_number` di `AvailableModel`** — Field baru yang diteruskan dari model header ke payload request (`inner[79]`).
|
|
21
|
+
- **`buildModelIdNumberMapping()`** — Method static pada `AvailableModel` yang menghasilkan mapping `modelId → modelNumber`.
|
|
22
|
+
- **Model baru** — `BASIC_LITE` (`gemini-3-lite`), `PLUS_LITE` (`gemini-3-lite-plus`), `ADVANCED_LITE` (`gemini-3-lite-advanced`).
|
|
23
|
+
- **GRPC key baru** — `GET_CONVERSATION_TURN`, `UPDATE_CONVERSATION`, `MARK_LAST_CONVERSATION_TURN`, `GENERATE_HEADLINE`, `GET_GEM`, `DELETE_GEM_AND_CONVERSATIONS`, `CREATE_TASK`, `GET_TASK`, `GET_ALL_TASKS`, `GET_TASKS_IN_CONVERSATION`, `GET_CANDIDATES`, `LIST_DISCOVERY_CARDS`, `GET_DISCOVERY_CARD`, `LIST_DISCOVERY_BANNERS`, `LIST_GEMINI_APP_ARTIFACTS`, `DELETE_GEMINI_APP_ARTIFACTS`, `LIST_MEMORIES`, `CREATE_MEMORY`, `UPDATE_MEMORY`, `DELETE_MEMORY`, `DELETE_ALL_MEMORIES`, `CHECK_GEMINI_QUOTA`, `CHECK_QUOTA`, `GET_ABUSE_STATUS`, `UPDATE_USER_PREFERENCES`, `READ_USER_PREFERENCES`, `CONTINUE_SHARED_CONVERSATION`, `GET_USAGE_INFO`.
|
|
24
|
+
- **Jitter pada auto-refresh** — Interval refresh cookie kini ditambahkan jitter acak ±15 detik agar request background tidak tersinkronisasi.
|
|
25
|
+
- **`_fetchPreferences()` / `_syncActivity()`** — Menggantikan `_sendBardSettings` / `_sendBardActivity` dengan method yang lebih khusus, memisahkan sinkronisasi preferensi dari heartbeat aktivitas.
|
|
26
|
+
- **Pencocokan model tidak case-sensitive** — `_resolveModelByName` sekarang mencocokkan nama model dan display name tanpa memperhatikan huruf besar/kecil.
|
|
27
|
+
- **Guard akun di `_fetchRecentChats`** — Pengambilan riwayat chat dilewati kalau status akun tidak tersedia.
|
|
28
|
+
|
|
29
|
+
### Diubah
|
|
30
|
+
- **Format model header** — Diperbarui dari `[4]` menjadi `[4,5,6,8]` dengan `model_number` ditambahkan di akhir. Header `x-goog-ext-73010990-jspb` berubah dari `[0]` menjadi `[0,0,0]`.
|
|
31
|
+
- **`Headers.BATCH_EXEC`** — Diperbarui mengikuti format model header baru.
|
|
32
|
+
- **Array inner request** — Ukuran bertambah dari 69 menjadi 81 elemen. `inner[68]` berubah dari `2` menjadi `1`. Slot baru: `inner[79]` (model_number) dan `inner[80]` (mode thinking: `2` = extended, `1` = standar).
|
|
33
|
+
- **`_initRpc`** — Kini memanggil `_fetchPreferences`, `_syncActivity`, `_fetchRecentChats`, `_fetchQuota`, `_fetchExtraQuota`, `_fetchAbuseStatus`, `_fetchUsageInfo` secara berurutan.
|
|
34
|
+
- **Model THINKING dihapus** — `BASIC_THINKING`, `PLUS_THINKING`, `ADVANCED_THINKING` digantikan oleh keluarga model LITE.
|
|
35
|
+
- **Cookie pada upload** — `uploadFile` sekarang juga meneruskan cookie sesi bersama header `Push-ID` dan REFERER.
|
|
36
|
+
- **Decode HTML entity** — Diperluas untuk mencakup entity numerik (`{`, ``) dan beberapa entity bernama tambahan.
|
|
37
|
+
- **Header download video** — `_downloadFile` di `video.js` sekarang menyertakan header `Origin` dan `Referer`.
|
|
38
|
+
- **Bahasa di `fetchGems`** — Sekarang menggunakan `this.language` daripada hardcode `'en'`.
|
|
39
|
+
- **Auto-init saat pemanggilan pertama** — `generateContent` dan `generateContentStream` otomatis memanggil `init()` kalau client belum berjalan.
|
|
40
|
+
|
|
41
|
+
### Diperbaiki
|
|
42
|
+
- **Upload gagal** — Header `Push-ID`, content-type, dan REFERER yang hilang di `uploadFile` sudah diperbaiki.
|
|
43
|
+
- **Format kunci quota** — Entry null pada daftar ID quota sekarang difilter sebelum digabung, menghasilkan kunci numerik yang benar (mis. `11`, `4`) bukan `-11`, `-4`.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## [1.0.8]
|
|
48
|
+
|
|
49
|
+
### Diperbaiki
|
|
50
|
+
- Format kunci quota — entry null difilter sebelum digabung sehingga menghasilkan kunci numerik yang bersih (mis. `11`, `4`) bukan `-11`, `-4`.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## [1.0.6]
|
|
55
|
+
|
|
56
|
+
### Diperbaiki
|
|
57
|
+
- Upload file sudah mengirim cookie dan header yang diperlukan dengan benar.
|
|
58
|
+
- Unduhan media untuk video dan audio yang dihasilkan sudah diperbaiki.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## [1.0.5]
|
|
63
|
+
|
|
64
|
+
### Diperbaiki
|
|
65
|
+
- Parsing image generation diperbaiki — `GeneratedImage` sekarang pakai pola `client_ref` dan tidak lagi butuh injeksi cookie langsung.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## [1.0.4]
|
|
70
|
+
|
|
71
|
+
### Ditambahkan
|
|
72
|
+
- Rilis publik pertama.
|
|
73
|
+
- `GeminiClient` dengan autentikasi berbasis cookie.
|
|
74
|
+
- Chat session, streaming, image generation, deep research, gems.
|
|
75
|
+
- Deklarasi TypeScript.
|
package/README-IDN.md
ADDED
|
@@ -0,0 +1,800 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# Gemini-Reverse
|
|
4
|
+
|
|
5
|
+
Client Node.js tidak resmi untuk [Google Gemini](https://gemini.google.com), terinspirasi dari [Gemini-API](https://github.com/HanaokaYuzu/Gemini-API) — proyek reverse engineering Python oleh [@HanaokaYuzu](https://github.com/HanaokaYuzu).
|
|
6
|
+
|
|
7
|
+
> **Language / Bahasa:** [English](README.md) · [Indonesia](README-IDN.md) | **Changelog:** [EN](CHANGELOG-EN.md) · [IDN](CHANGELOG-IDN.md)
|
|
8
|
+
|
|
9
|
+
## Fitur
|
|
10
|
+
|
|
11
|
+
- **Cookie Persisten** — Cookie diperbarui otomatis di latar belakang dengan jitter acak agar tidak tersinkronisasi. Cocok untuk layanan yang berjalan terus-menerus.
|
|
12
|
+
- **Buat Gambar** — Buat dan edit gambar secara langsung menggunakan bahasa natural.
|
|
13
|
+
- **Buat Video & Audio** — Dukung pembuatan video dan konten audio/musik secara native.
|
|
14
|
+
- **Deep Research** — Alur kerja riset mendalam lengkap: buat rencana, pantau status, dan ambil hasil.
|
|
15
|
+
- **Extended Thinking** — Aktifkan mode penalaran lebih dalam pada model yang mendukung.
|
|
16
|
+
- **System Prompt** — Kustomisasi system prompt model lewat [Gemini Gems](https://gemini.google.com/gems/view).
|
|
17
|
+
- **Dukungan Ekstensi** — Gunakan ekstensi Gemini seperti YouTube dan Gmail dalam percakapan.
|
|
18
|
+
- **Output Terklasifikasi** — Teks, pikiran, gambar, video, dan audio dikelompokkan otomatis dalam respons.
|
|
19
|
+
- **Mode Streaming** — Respons diterima secara bertahap menggunakan parser frame stateful yang efisien.
|
|
20
|
+
- **Penemuan Model Dinamis** — Model yang tersedia untuk akun Anda ditemukan otomatis saat inisialisasi.
|
|
21
|
+
- **Quota & Info Penggunaan** — Batas quota, penggunaan komputasi, dan status abuse akun tersedia setelah inisialisasi.
|
|
22
|
+
- **Activity Watchdog** — Heartbeat berjalan di latar belakang untuk menjaga sesi tetap aktif.
|
|
23
|
+
- **Dukungan TypeScript** — Deklarasi tipe TypeScript lengkap sudah tersedia.
|
|
24
|
+
|
|
25
|
+
## Daftar Isi
|
|
26
|
+
|
|
27
|
+
- [Fitur](#fitur)
|
|
28
|
+
- [Daftar Isi](#daftar-isi)
|
|
29
|
+
- [Instalasi](#instalasi)
|
|
30
|
+
- [Autentikasi](#autentikasi)
|
|
31
|
+
- [Penggunaan](#penggunaan)
|
|
32
|
+
- [Inisialisasi](#inisialisasi)
|
|
33
|
+
- [Buat Konten](#buat-konten)
|
|
34
|
+
- [Buat Konten dengan File](#buat-konten-dengan-file)
|
|
35
|
+
- [Percakapan Multi-Giliran](#percakapan-multi-giliran)
|
|
36
|
+
- [Lanjutkan Percakapan Sebelumnya](#lanjutkan-percakapan-sebelumnya)
|
|
37
|
+
- [Baca Riwayat Percakapan](#baca-riwayat-percakapan)
|
|
38
|
+
- [Daftar Chat Terbaru](#daftar-chat-terbaru)
|
|
39
|
+
- [Hapus Percakapan](#hapus-percakapan)
|
|
40
|
+
- [Mode Sementara](#mode-sementara)
|
|
41
|
+
- [Mode Streaming](#mode-streaming)
|
|
42
|
+
- [Extended Thinking](#extended-thinking)
|
|
43
|
+
- [Pilih Model Bahasa](#pilih-model-bahasa)
|
|
44
|
+
- [Daftar Model Tersedia](#daftar-model-tersedia)
|
|
45
|
+
- [Pakai System Prompt dengan Gemini Gems](#pakai-system-prompt-dengan-gemini-gems)
|
|
46
|
+
- [Kelola Custom Gems](#kelola-custom-gems)
|
|
47
|
+
- [Buat Custom Gem](#buat-custom-gem)
|
|
48
|
+
- [Edit Gem yang Ada](#edit-gem-yang-ada)
|
|
49
|
+
- [Hapus Custom Gem](#hapus-custom-gem)
|
|
50
|
+
- [Lihat Proses Berpikir Model](#lihat-proses-berpikir-model)
|
|
51
|
+
- [Ambil Gambar dari Respons](#ambil-gambar-dari-respons)
|
|
52
|
+
- [Buat dan Edit Gambar](#buat-dan-edit-gambar)
|
|
53
|
+
- [Ambil Video dan Audio](#ambil-video-dan-audio)
|
|
54
|
+
- [Gunakan Ekstensi Gemini](#gunakan-ekstensi-gemini)
|
|
55
|
+
- [Cek dan Ganti Kandidat Balasan](#cek-dan-ganti-kandidat-balasan)
|
|
56
|
+
- [Deep Research](#deep-research)
|
|
57
|
+
- [Status Akun](#status-akun)
|
|
58
|
+
- [Quota dan Info Penggunaan](#quota-dan-info-penggunaan)
|
|
59
|
+
- [Penanganan Error](#penanganan-error)
|
|
60
|
+
- [Persistensi Cookie](#persistensi-cookie)
|
|
61
|
+
- [TypeScript](#typescript)
|
|
62
|
+
- [Struktur Proyek](#struktur-proyek)
|
|
63
|
+
- [Referensi](#referensi)
|
|
64
|
+
|
|
65
|
+
## Instalasi
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npm install gemini-reverse
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Autentikasi
|
|
72
|
+
|
|
73
|
+
- Buka [gemini.google.com](https://gemini.google.com) dan masuk dengan akun Google kamu
|
|
74
|
+
- Tekan F12 untuk buka DevTools, masuk ke tab `Application` → `Cookies` → `https://gemini.google.com`
|
|
75
|
+
- Salin nilai `__Secure-1PSID` (dan opsional `__Secure-1PSIDTS`)
|
|
76
|
+
|
|
77
|
+
> `__Secure-1PSIDTS` bersifat opsional — client akan mencoba memperbarui dan menyimpannya secara otomatis setelah inisialisasi pertama berhasil.
|
|
78
|
+
|
|
79
|
+
## Penggunaan
|
|
80
|
+
|
|
81
|
+
### Inisialisasi
|
|
82
|
+
|
|
83
|
+
Import package dan buat client dengan cookie kamu. Setelah berhasil diinisialisasi, client akan memperbarui `__Secure-1PSIDTS` otomatis di latar belakang dengan jitter acak, dan menjalankan heartbeat watchdog untuk menjaga sesi tetap aktif.
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
const { GeminiClient } = require('gemini-reverse');
|
|
87
|
+
|
|
88
|
+
const client = new GeminiClient({
|
|
89
|
+
secure_1psid: 'SECURE_1PSID_KAMU',
|
|
90
|
+
secure_1psidts: 'SECURE_1PSIDTS_KAMU', // opsional
|
|
91
|
+
proxy: null, // opsional, mis. 'http://host:port'
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
await client.init({
|
|
95
|
+
timeout: 300000, // timeout request dalam ms, default 300000
|
|
96
|
+
autoClose: false, // tutup client otomatis setelah tidak aktif
|
|
97
|
+
closeDelay: 300000, // jeda sebelum ditutup dalam ms
|
|
98
|
+
autoRefresh: true, // perbarui cookie + jalankan activity watchdog
|
|
99
|
+
refreshInterval: 540000 // interval refresh cookie dalam ms
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
> `autoClose` dan `closeDelay` berguna untuk menutup client otomatis saat tidak aktif. Pada layanan yang selalu berjalan seperti chatbot, disarankan set `autoClose: true` dengan nilai `closeDelay` yang masuk akal supaya penggunaan resource lebih efisien.
|
|
104
|
+
|
|
105
|
+
### Buat Konten
|
|
106
|
+
|
|
107
|
+
Kirim pertanyaan satu arah dengan `generateContent`, yang mengembalikan objek `ModelOutput` berisi teks, gambar, pemikiran model, dan metadata percakapan.
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
const response = await client.generateContent({ prompt: 'Halo Dunia!' });
|
|
111
|
+
console.log(response.text);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Buat Konten dengan File
|
|
115
|
+
|
|
116
|
+
Gemini mendukung input file seperti gambar dan dokumen. Sertakan daftar path file atau objek `Buffer` bersama prompt teks kamu.
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
const response = await client.generateContent({
|
|
120
|
+
prompt: 'Deskripsikan isi file-file ini.',
|
|
121
|
+
files: ['./dokumen.pdf', './foto.png'],
|
|
122
|
+
});
|
|
123
|
+
console.log(response.text);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Percakapan Multi-Giliran
|
|
127
|
+
|
|
128
|
+
Pakai `startChat` untuk membuat `ChatSession` dan kirim pesan lewat sesi itu. Riwayat percakapan dikelola otomatis dan diperbarui tiap giliran.
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
const chat = client.startChat();
|
|
132
|
+
|
|
133
|
+
const res1 = await chat.sendMessage({ prompt: 'Nama saya Alice.' });
|
|
134
|
+
console.log(res1.text);
|
|
135
|
+
|
|
136
|
+
const res2 = await chat.sendMessage({ prompt: 'Siapa nama saya?' });
|
|
137
|
+
console.log(res2.text); // mengingat konteks sebelumnya
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Lanjutkan Percakapan Sebelumnya
|
|
141
|
+
|
|
142
|
+
Masukkan metadata dari `ChatSession` sebelumnya ke `startChat` untuk melanjutkan percakapan. Metadata bisa disimpan ke file atau database agar bisa dipulihkan setelah proses di-restart.
|
|
143
|
+
|
|
144
|
+
```js
|
|
145
|
+
const chat = client.startChat();
|
|
146
|
+
await chat.sendMessage({ prompt: 'Cuaca hari ini cerah.' });
|
|
147
|
+
|
|
148
|
+
// Simpan metadata sesi
|
|
149
|
+
const savedMetadata = chat.metadata;
|
|
150
|
+
const savedCid = chat.cid;
|
|
151
|
+
|
|
152
|
+
// Lanjutkan di sesi baru
|
|
153
|
+
const previousChat = client.startChat({ metadata: savedMetadata });
|
|
154
|
+
const response = await previousChat.sendMessage({ prompt: 'Apa pesan saya sebelumnya?' });
|
|
155
|
+
console.log(response.text);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Baca Riwayat Percakapan
|
|
159
|
+
|
|
160
|
+
Ambil riwayat percakapan lengkap dengan `readChat` menggunakan ID chat. Mengembalikan objek `ChatHistory` berisi daftar `ChatTurn` dari terbaru ke terlama.
|
|
161
|
+
|
|
162
|
+
```js
|
|
163
|
+
const chat = client.startChat();
|
|
164
|
+
await chat.sendMessage({ prompt: 'Apa ibu kota Prancis?' });
|
|
165
|
+
|
|
166
|
+
const history = await client.readChat(chat.cid);
|
|
167
|
+
if (history) {
|
|
168
|
+
for (const turn of history.turns) {
|
|
169
|
+
console.log(`[${turn.role.toUpperCase()}] ${turn.text}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Kamu juga bisa baca riwayat langsung dari sesi:
|
|
175
|
+
|
|
176
|
+
```js
|
|
177
|
+
const history = await chat.readHistory(10); // ambil 10 giliran terakhir
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Daftar Chat Terbaru
|
|
181
|
+
|
|
182
|
+
Pakai `listChats` untuk mendapatkan daftar sesi chat terbaru yang di-cache saat inisialisasi.
|
|
183
|
+
|
|
184
|
+
```js
|
|
185
|
+
const chats = client.listChats();
|
|
186
|
+
if (chats) {
|
|
187
|
+
for (const info of chats) {
|
|
188
|
+
console.log(`${info.cid}: ${info.title} (disematkan: ${info.is_pinned})`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Hapus Percakapan
|
|
194
|
+
|
|
195
|
+
Hapus chat tertentu dari riwayat Gemini di server dengan `deleteChat` menggunakan ID chat.
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
const chat = client.startChat();
|
|
199
|
+
await chat.sendMessage({ prompt: 'Ini percakapan sementara.' });
|
|
200
|
+
|
|
201
|
+
await client.deleteChat(chat.cid);
|
|
202
|
+
console.log(`Chat dihapus: ${chat.cid}`);
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Mode Sementara
|
|
206
|
+
|
|
207
|
+
Tambahkan `temporary: true` ke `generateContent` atau `sendMessage` supaya percakapan tidak tersimpan ke riwayat Gemini.
|
|
208
|
+
|
|
209
|
+
```js
|
|
210
|
+
const response = await client.generateContent({
|
|
211
|
+
prompt: 'Halo Dunia!',
|
|
212
|
+
temporary: true,
|
|
213
|
+
});
|
|
214
|
+
console.log(response.text);
|
|
215
|
+
|
|
216
|
+
// Juga bisa dipakai di dalam sesi chat
|
|
217
|
+
const chat = client.startChat();
|
|
218
|
+
await chat.sendMessage({ prompt: 'Cuaca hari ini cerah.', temporary: false });
|
|
219
|
+
const res2 = await chat.sendMessage({ prompt: 'Apa pesan terakhir saya?', temporary: true });
|
|
220
|
+
console.log(res2.text);
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Mode Streaming
|
|
224
|
+
|
|
225
|
+
Untuk respons yang panjang, pakai mode streaming agar output diterima secara bertahap. Di balik layar, respons menggunakan `StreamingFrameParser` stateful sehingga frame parsial di-buffer dengan efisien. Atribut `text_delta` hanya berisi **karakter baru** sejak yield terakhir.
|
|
226
|
+
|
|
227
|
+
```js
|
|
228
|
+
for await (const chunk of client.generateContentStream({
|
|
229
|
+
prompt: 'Apa bedanya promise dengan async/await?',
|
|
230
|
+
})) {
|
|
231
|
+
process.stdout.write(chunk.text_delta);
|
|
232
|
+
}
|
|
233
|
+
console.log();
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Streaming juga bisa dipakai di dalam sesi chat:
|
|
237
|
+
|
|
238
|
+
```js
|
|
239
|
+
const chat = client.startChat();
|
|
240
|
+
for await (const chunk of chat.sendMessageStream({ prompt: 'Ceritakan sebuah kisah panjang.' })) {
|
|
241
|
+
process.stdout.write(chunk.text_delta);
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Extended Thinking
|
|
246
|
+
|
|
247
|
+
Tambahkan `extended_thinking: true` untuk mengaktifkan mode penalaran mendalam. Model akan meluangkan lebih banyak waktu berpikir sebelum menjawab. Didukung pada model tier Pro dan Advanced.
|
|
248
|
+
|
|
249
|
+
```js
|
|
250
|
+
const { Model } = require('gemini-reverse');
|
|
251
|
+
|
|
252
|
+
const response = await client.generateContent({
|
|
253
|
+
prompt: 'Selesaikan langkah demi langkah: Kereta melaju 120 km/jam dan harus menempuh 450 km. Berapa lama waktu yang dibutuhkan?',
|
|
254
|
+
model: Model.ADVANCED_PRO,
|
|
255
|
+
extended_thinking: true,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
if (response.thoughts) {
|
|
259
|
+
console.log('Proses berpikir:', response.thoughts);
|
|
260
|
+
}
|
|
261
|
+
console.log('Jawaban:', response.text);
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Juga bisa dipakai di streaming dan chat:
|
|
265
|
+
|
|
266
|
+
```js
|
|
267
|
+
const chat = client.startChat({ model: Model.ADVANCED_FLASH });
|
|
268
|
+
const res = await chat.sendMessage({
|
|
269
|
+
prompt: 'Jelaskan masalah P vs NP.',
|
|
270
|
+
extended_thinking: true,
|
|
271
|
+
});
|
|
272
|
+
console.log(res.text);
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Pilih Model Bahasa
|
|
276
|
+
|
|
277
|
+
Tentukan model yang akan dipakai dengan mengisi argumen `model`. Model yang tersedia ditemukan secara dinamis saat inisialisasi berdasarkan tier akun kamu.
|
|
278
|
+
|
|
279
|
+
```js
|
|
280
|
+
const { Model } = require('gemini-reverse');
|
|
281
|
+
|
|
282
|
+
// Pakai konstanta bawaan
|
|
283
|
+
const response1 = await client.generateContent({
|
|
284
|
+
prompt: 'Apa versi model kamu?',
|
|
285
|
+
model: Model.BASIC_FLASH,
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// Pakai nama model sebagai string (tidak case-sensitive)
|
|
289
|
+
const chat = client.startChat({ model: 'gemini-3-pro' });
|
|
290
|
+
|
|
291
|
+
// Pakai model header kustom
|
|
292
|
+
const chat2 = client.startChat({
|
|
293
|
+
model: {
|
|
294
|
+
model_name: 'kustom',
|
|
295
|
+
model_header: {
|
|
296
|
+
'x-goog-ext-525001261-jspb': '[1,null,null,null,"MODEL_ID",null,null,0,[4,5,6,8],null,null,1,null,null,1]',
|
|
297
|
+
'x-goog-ext-73010989-jspb': '[0]',
|
|
298
|
+
'x-goog-ext-73010990-jspb': '[0,0,0]',
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Daftar konstanta model:**
|
|
305
|
+
|
|
306
|
+
| Konstanta | `model_name` | Keterangan |
|
|
307
|
+
|---|---|---|
|
|
308
|
+
| `Model.UNSPECIFIED` | `unspecified` | Default, Gemini yang memilih |
|
|
309
|
+
| `Model.BASIC_PRO` | `gemini-3-pro` | Tier gratis |
|
|
310
|
+
| `Model.BASIC_FLASH` | `gemini-3-flash` | Tier gratis, paling cepat |
|
|
311
|
+
| `Model.BASIC_LITE` | `gemini-3-lite` | Tier gratis, ringan |
|
|
312
|
+
| `Model.PLUS_PRO` | `gemini-3-pro-plus` | Tier Plus |
|
|
313
|
+
| `Model.PLUS_FLASH` | `gemini-3-flash-plus` | Tier Plus |
|
|
314
|
+
| `Model.PLUS_LITE` | `gemini-3-lite-plus` | Tier Plus |
|
|
315
|
+
| `Model.ADVANCED_PRO` | `gemini-3-pro-advanced` | Tier Advanced |
|
|
316
|
+
| `Model.ADVANCED_FLASH` | `gemini-3-flash-advanced` | Tier Advanced |
|
|
317
|
+
| `Model.ADVANCED_LITE` | `gemini-3-lite-advanced` | Tier Advanced |
|
|
318
|
+
|
|
319
|
+
### Daftar Model Tersedia
|
|
320
|
+
|
|
321
|
+
Client otomatis menemukan model yang bisa diakses akun kamu saat inisialisasi. Pakai `listModels` untuk melihatnya.
|
|
322
|
+
|
|
323
|
+
```js
|
|
324
|
+
await client.init();
|
|
325
|
+
|
|
326
|
+
const models = client.listModels();
|
|
327
|
+
if (models) {
|
|
328
|
+
for (const model of models) {
|
|
329
|
+
console.log(`${model.model_id} → ${model.model_name || model.display_name}`);
|
|
330
|
+
console.log(` capacity: ${model.capacity}, model_number: ${model.model_number}, advanced_only: ${model.advanced_only}`);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Pakai System Prompt dengan Gemini Gems
|
|
336
|
+
|
|
337
|
+
System prompt bisa diterapkan ke percakapan lewat [Gemini Gems](https://gemini.google.com/gems/view). Isi argumen `gem` di `generateContent` atau `startChat` — bisa berupa objek `Gem` maupun string ID gem.
|
|
338
|
+
|
|
339
|
+
```js
|
|
340
|
+
// Ambil semua gems dari akun
|
|
341
|
+
await client.fetchGems();
|
|
342
|
+
const gems = client.gems;
|
|
343
|
+
|
|
344
|
+
// Cari gem tertentu
|
|
345
|
+
const codingPartner = gems.get({ name: 'Coding partner' });
|
|
346
|
+
|
|
347
|
+
const response = await client.generateContent({
|
|
348
|
+
prompt: 'Apa system prompt kamu?',
|
|
349
|
+
gem: codingPartner,
|
|
350
|
+
});
|
|
351
|
+
console.log(response.text);
|
|
352
|
+
|
|
353
|
+
// Pakai gem di percakapan multi-giliran
|
|
354
|
+
const chat = client.startChat({ gem: codingPartner });
|
|
355
|
+
const res2 = await chat.sendMessage({ prompt: 'Bantu saya menulis binary search.' });
|
|
356
|
+
console.log(res2.text);
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
> Ada beberapa gem bawaan yang tersembunyi secara default. Pakai `fetchGems({ includeHidden: true })` untuk menyertakannya.
|
|
360
|
+
|
|
361
|
+
### Kelola Custom Gems
|
|
362
|
+
|
|
363
|
+
Kamu bisa membuat, mengedit, dan menghapus custom gem secara programatik. Gem bawaan sistem tidak bisa dimodifikasi.
|
|
364
|
+
|
|
365
|
+
#### Buat Custom Gem
|
|
366
|
+
|
|
367
|
+
```js
|
|
368
|
+
const newGem = await client.createGem({
|
|
369
|
+
name: 'Tutor Python',
|
|
370
|
+
prompt: 'Kamu adalah tutor Python yang membantu. Selalu sertakan contoh kode yang bisa langsung dijalankan.',
|
|
371
|
+
description: 'Gem khusus untuk belajar Python',
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
console.log(`Dibuat: ${newGem.id}`);
|
|
375
|
+
|
|
376
|
+
// Langsung pakai gem yang baru dibuat
|
|
377
|
+
const response = await client.generateContent({
|
|
378
|
+
prompt: 'Jelaskan list comprehension.',
|
|
379
|
+
gem: newGem,
|
|
380
|
+
});
|
|
381
|
+
console.log(response.text);
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
#### Edit Gem yang Ada
|
|
385
|
+
|
|
386
|
+
> Saat mengedit gem, semua parameter (`name`, `prompt`, `description`) harus diisi meskipun hanya satu yang berubah.
|
|
387
|
+
|
|
388
|
+
```js
|
|
389
|
+
await client.fetchGems();
|
|
390
|
+
const pythonTutor = client.gems.get({ name: 'Tutor Python' });
|
|
391
|
+
|
|
392
|
+
const updatedGem = await client.updateGem({
|
|
393
|
+
gem: pythonTutor,
|
|
394
|
+
name: 'Tutor Python Lanjutan',
|
|
395
|
+
prompt: 'Kamu adalah tutor Python ahli. Fokus pada performa dan best practice.',
|
|
396
|
+
description: 'Asisten pemrograman Python tingkat lanjut',
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
console.log(`Diperbarui: ${updatedGem.id}`);
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
#### Hapus Custom Gem
|
|
403
|
+
|
|
404
|
+
```js
|
|
405
|
+
await client.fetchGems();
|
|
406
|
+
const gemToDelete = client.gems.get({ name: 'Tutor Python Lanjutan' });
|
|
407
|
+
|
|
408
|
+
await client.deleteGem(gemToDelete); // bisa juga isi string ID gem
|
|
409
|
+
console.log(`Dihapus: ${gemToDelete.name}`);
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Lihat Proses Berpikir Model
|
|
413
|
+
|
|
414
|
+
Saat memakai model dengan kemampuan berpikir, proses penalaran internalnya bisa diakses lewat `response.thoughts`.
|
|
415
|
+
|
|
416
|
+
```js
|
|
417
|
+
const response = await client.generateContent({
|
|
418
|
+
prompt: 'Berapa 17 × 23?',
|
|
419
|
+
model: Model.BASIC_FLASH,
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
if (response.thoughts) {
|
|
423
|
+
console.log('Proses berpikir:', response.thoughts);
|
|
424
|
+
}
|
|
425
|
+
console.log('Jawaban:', response.text);
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### Ambil Gambar dari Respons
|
|
429
|
+
|
|
430
|
+
Gambar dalam respons tersimpan sebagai daftar objek `Image` yang bisa diakses lewat `response.images`. Tiap gambar punya `url`, `title`, dan deskripsi `alt`.
|
|
431
|
+
|
|
432
|
+
```js
|
|
433
|
+
const response = await client.generateContent({ prompt: 'Kirimin beberapa foto kucing dong.' });
|
|
434
|
+
|
|
435
|
+
for (const image of response.images) {
|
|
436
|
+
console.log(`${image.title}: ${image.url}`);
|
|
437
|
+
console.log(`Alt: ${image.alt}`);
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Buat dan Edit Gambar
|
|
442
|
+
|
|
443
|
+
Minta Gemini untuk membuat atau mengedit gambar menggunakan bahasa natural. Gambar yang dihasilkan dikembalikan sebagai objek `GeneratedImage` dan bisa disimpan ke disk.
|
|
444
|
+
|
|
445
|
+
> Google membatasi ketersediaan fitur pembuatan gambar berdasarkan wilayah dan jenis akun. Pengguna di bawah 18 tahun tidak dapat menggunakan fitur ini.
|
|
446
|
+
|
|
447
|
+
```js
|
|
448
|
+
const response = await client.generateContent({
|
|
449
|
+
prompt: 'Buatkan gambar realistis kucing pakai baju astronot.',
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
for (let i = 0; i < response.images.length; i++) {
|
|
453
|
+
const image = response.images[i];
|
|
454
|
+
const savedPath = await image.save({
|
|
455
|
+
path: './temp',
|
|
456
|
+
filename: `kucing_angkasa_${i}.png`,
|
|
457
|
+
verbose: true,
|
|
458
|
+
});
|
|
459
|
+
console.log(`Tersimpan di: ${savedPath}`);
|
|
460
|
+
}
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
> Kalau kamu minta Gemini "mengirimkan" gambar, yang dikembalikan adalah gambar dari web (`WebImage`). Kalau minta "membuat" gambar, yang dikembalikan adalah gambar buatan AI (`GeneratedImage`). Keduanya dikategorikan otomatis di `response.images`.
|
|
464
|
+
|
|
465
|
+
### Ambil Video dan Audio
|
|
466
|
+
|
|
467
|
+
Gemini bisa membuat video pendek dan audio/musik. Hasilnya dikembalikan sebagai objek `GeneratedVideo` dan `GeneratedMedia` di `response.videos` dan `response.media`.
|
|
468
|
+
|
|
469
|
+
> Fitur ini mungkin membutuhkan langganan Gemini aktif.
|
|
470
|
+
|
|
471
|
+
```js
|
|
472
|
+
// Buat video
|
|
473
|
+
const videoResponse = await client.generateContent({
|
|
474
|
+
prompt: 'Buatkan video pendek ombak di pantai.',
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
for (const video of videoResponse.videos) {
|
|
478
|
+
const result = await video.save({ savePath: './temp', verbose: true });
|
|
479
|
+
console.log('Video:', result.video);
|
|
480
|
+
console.log('Thumbnail:', result.video_thumbnail);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Buat audio/musik
|
|
484
|
+
const mediaResponse = await client.generateContent({
|
|
485
|
+
prompt: 'Buatkan melodi piano yang menenangkan.',
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
for (const media of mediaResponse.media) {
|
|
489
|
+
// downloadType: 'audio' | 'video' | 'both' (default)
|
|
490
|
+
const result = await media.save({ savePath: './temp', downloadType: 'both', verbose: true });
|
|
491
|
+
console.log('MP3:', result.audio);
|
|
492
|
+
console.log('MP4:', result.video);
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
> `GeneratedMedia.save()` menerima parameter `downloadType`: `"audio"`, `"video"`, atau `"both"` (default). Kalau konten masih dalam proses dibuat, metode ini akan otomatis polling sampai selesai (HTTP 206).
|
|
497
|
+
|
|
498
|
+
### Gunakan Ekstensi Gemini
|
|
499
|
+
|
|
500
|
+
Untuk memakai ekstensi Gemini (Gmail, YouTube, dll.), aktifkan dulu di [situs Gemini](https://gemini.google.com/extensions). Setelah itu tinggal panggil lewat prompt dengan awalan `@` atau dalam bahasa natural.
|
|
501
|
+
|
|
502
|
+
> Pastikan Gemini Apps Activity sudah aktif di akun kamu.
|
|
503
|
+
|
|
504
|
+
```js
|
|
505
|
+
const gmailResponse = await client.generateContent({
|
|
506
|
+
prompt: '@Gmail Apa pesan terbaru di inbox saya?',
|
|
507
|
+
});
|
|
508
|
+
console.log(gmailResponse.text);
|
|
509
|
+
|
|
510
|
+
const youtubeResponse = await client.generateContent({
|
|
511
|
+
prompt: '@YouTube Apa video terbaru dari channel Fireship?',
|
|
512
|
+
});
|
|
513
|
+
console.log(youtubeResponse.text);
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### Cek dan Ganti Kandidat Balasan
|
|
517
|
+
|
|
518
|
+
Kadang respons Gemini berisi beberapa kandidat balasan dengan konten yang berbeda. Kamu bisa melihat semua kandidat dan memilih salah satu untuk melanjutkan percakapan.
|
|
519
|
+
|
|
520
|
+
```js
|
|
521
|
+
const chat = client.startChat();
|
|
522
|
+
const response = await chat.sendMessage({ prompt: 'Rekomendasikan buku fiksi ilmiah.' });
|
|
523
|
+
|
|
524
|
+
// Lihat semua kandidat
|
|
525
|
+
response.candidates.forEach((candidate, i) => {
|
|
526
|
+
console.log(`[${i}] ${candidate.text.slice(0, 80)}...`);
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
if (response.candidates.length > 1) {
|
|
530
|
+
// Pilih kandidat kedua
|
|
531
|
+
chat.chooseCandidate(1);
|
|
532
|
+
|
|
533
|
+
const followup = await chat.sendMessage({ prompt: 'Ceritakan lebih lanjut.' });
|
|
534
|
+
console.log(followup.text);
|
|
535
|
+
} else {
|
|
536
|
+
console.log('Hanya ada satu kandidat.');
|
|
537
|
+
}
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Deep Research
|
|
541
|
+
|
|
542
|
+
Fitur deep research Gemini adalah agen otonom yang menjelajah web, menganalisis sumber, dan menghasilkan laporan komprehensif.
|
|
543
|
+
|
|
544
|
+
> Fitur ini mungkin membutuhkan langganan Gemini aktif.
|
|
545
|
+
|
|
546
|
+
**Cara cepat — satu pemanggilan:**
|
|
547
|
+
|
|
548
|
+
```js
|
|
549
|
+
const result = await client.deepResearch(
|
|
550
|
+
'Bandingkan 3 penyedia cloud terbesar dan fitur AI mereka',
|
|
551
|
+
10000, // interval polling dalam ms
|
|
552
|
+
600000, // timeout dalam ms
|
|
553
|
+
(status) => console.log(`Status: ${status.state} — ${status.notes.slice(0, 1).join(', ')}`),
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
console.log(`Selesai: ${result.done}`);
|
|
557
|
+
console.log(result.text);
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
**Alur langkah demi langkah** untuk kontrol lebih penuh:
|
|
561
|
+
|
|
562
|
+
```js
|
|
563
|
+
// Langkah 1: Buat rencana riset
|
|
564
|
+
const plan = await client.createDeepResearchPlan(
|
|
565
|
+
'Apa perkembangan terbaru dalam komputasi kuantum?'
|
|
566
|
+
);
|
|
567
|
+
|
|
568
|
+
console.log(`Judul: ${plan.title}`);
|
|
569
|
+
console.log(`ETA: ${plan.eta_text}`);
|
|
570
|
+
for (const step of plan.steps) {
|
|
571
|
+
console.log(` - ${step}`);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Langkah 2: Mulai riset
|
|
575
|
+
const startOutput = await client.startDeepResearch(plan);
|
|
576
|
+
console.log('Riset dimulai:', startOutput.text.slice(0, 100));
|
|
577
|
+
|
|
578
|
+
// Langkah 3: Tunggu sampai selesai
|
|
579
|
+
const result = await client.waitForDeepResearch(
|
|
580
|
+
plan,
|
|
581
|
+
10000, // interval polling dalam ms
|
|
582
|
+
600000, // timeout dalam ms
|
|
583
|
+
(status) => console.log(`[${status.state}] ${status.notes[0] || ''}`),
|
|
584
|
+
);
|
|
585
|
+
|
|
586
|
+
console.log(result.text);
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
### Status Akun
|
|
590
|
+
|
|
591
|
+
Client mendeteksi tier akun kamu saat inisialisasi dan menyimpannya di `client.accountStatus`.
|
|
592
|
+
|
|
593
|
+
```js
|
|
594
|
+
const { AccountStatus } = require('gemini-reverse');
|
|
595
|
+
|
|
596
|
+
await client.init();
|
|
597
|
+
|
|
598
|
+
if (client.accountStatus === AccountStatus.AVAILABLE) {
|
|
599
|
+
console.log('Akun aktif dan bisa digunakan.');
|
|
600
|
+
} else if (client.accountStatus === AccountStatus.UNAUTHENTICATED) {
|
|
601
|
+
console.error('Cookie sudah kedaluwarsa atau tidak valid.');
|
|
602
|
+
} else if (client.accountStatus === AccountStatus.LOCATION_REJECTED) {
|
|
603
|
+
console.error('Gemini tidak tersedia di wilayah kamu.');
|
|
604
|
+
} else {
|
|
605
|
+
console.warn(`Status akun: ${client.accountStatus.name} — ${client.accountStatus.description}`);
|
|
606
|
+
}
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
**Semua nilai status akun:**
|
|
610
|
+
|
|
611
|
+
| Konstanta | Kode | Keterangan |
|
|
612
|
+
|---|---|---|
|
|
613
|
+
| `AccountStatus.AVAILABLE` | 1000 | Akun aktif dan punya akses normal |
|
|
614
|
+
| `AccountStatus.ACCESS_TEMPORARILY_UNAVAILABLE` | 1014 | Akses dibatasi sementara, mungkin karena wilayah |
|
|
615
|
+
| `AccountStatus.UNAUTHENTICATED` | 1016 | Cookie kedaluwarsa atau tidak valid |
|
|
616
|
+
| `AccountStatus.ACCOUNT_REJECTED` | 1021 | Akses akun ditolak |
|
|
617
|
+
| `AccountStatus.ACCOUNT_UNTRUSTED` | 1033 | Tidak lolos pemeriksaan keamanan |
|
|
618
|
+
| `AccountStatus.TOS_PENDING` | 1040 | Perlu menerima Syarat Layanan terbaru |
|
|
619
|
+
| `AccountStatus.TOS_OUT_OF_DATE` | 1042 | Syarat Layanan sudah tidak berlaku |
|
|
620
|
+
| `AccountStatus.ACCOUNT_REJECTED_BY_GUARDIAN` | 1054 | Diblokir oleh orang tua atau wali |
|
|
621
|
+
| `AccountStatus.GUARDIAN_APPROVAL_REQUIRED` | 1057 | Butuh persetujuan orang tua |
|
|
622
|
+
| `AccountStatus.LOCATION_REJECTED` | 1060 | Tidak tersedia di negara/wilayah kamu |
|
|
623
|
+
|
|
624
|
+
### Quota dan Info Penggunaan
|
|
625
|
+
|
|
626
|
+
Setelah inisialisasi, client otomatis mengambil batas quota dan data penggunaan akun. Hasilnya bisa diakses lewat `client.quotas`, `client.usageInfo`, dan `client.abuseStatus`.
|
|
627
|
+
|
|
628
|
+
```js
|
|
629
|
+
await client.init();
|
|
630
|
+
|
|
631
|
+
// Batas quota (Flash, Pro, fitur ekstra)
|
|
632
|
+
const quotas = client.quotas;
|
|
633
|
+
for (const [id, q] of Object.entries(quotas)) {
|
|
634
|
+
if (q.label) {
|
|
635
|
+
const remaining = q.remaining !== null ? `${q.remaining}/${q.total}` : 'tidak terbatas';
|
|
636
|
+
console.log(`${q.label}: ${remaining} kredit (${q.usage_percentage?.toFixed(1) ?? '?'}% terpakai)`);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Data penggunaan komputasi (periode 5 jam dan mingguan)
|
|
641
|
+
const usage = client.usageInfo;
|
|
642
|
+
if (usage.tier) {
|
|
643
|
+
console.log(`Tier akun: ${usage.tier.label}`);
|
|
644
|
+
}
|
|
645
|
+
if (usage.current_5h) {
|
|
646
|
+
console.log(`5 jam terakhir: ${usage.current_5h.remaining_credits} kredit tersisa (${usage.current_5h.usage_percentage}% terpakai)`);
|
|
647
|
+
}
|
|
648
|
+
if (usage.weekly) {
|
|
649
|
+
console.log(`Mingguan: ${usage.weekly.remaining_credits} kredit tersisa`);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Status abuse
|
|
653
|
+
const abuse = client.abuseStatus;
|
|
654
|
+
if (abuse) {
|
|
655
|
+
console.log(`Akun bersih: ${abuse.is_clean}`);
|
|
656
|
+
}
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
## Penanganan Error
|
|
660
|
+
|
|
661
|
+
```js
|
|
662
|
+
const {
|
|
663
|
+
AuthError,
|
|
664
|
+
APIError,
|
|
665
|
+
GeminiError,
|
|
666
|
+
TimeoutError,
|
|
667
|
+
UsageLimitExceeded,
|
|
668
|
+
ModelInvalid,
|
|
669
|
+
TemporarilyBlocked,
|
|
670
|
+
} = require('gemini-reverse');
|
|
671
|
+
|
|
672
|
+
try {
|
|
673
|
+
const response = await chat.sendMessage({ prompt: 'Halo!' });
|
|
674
|
+
console.log(response.text);
|
|
675
|
+
} catch (e) {
|
|
676
|
+
if (e instanceof AuthError) {
|
|
677
|
+
console.error('Cookie kedaluwarsa atau tidak valid. Perbarui cookie kamu.');
|
|
678
|
+
} else if (e instanceof UsageLimitExceeded) {
|
|
679
|
+
console.error('Batas penggunaan tercapai. Coba lagi nanti atau ganti model.');
|
|
680
|
+
} else if (e instanceof TemporarilyBlocked) {
|
|
681
|
+
console.error('IP diblokir sementara oleh Google. Coba pakai proxy atau tunggu sebentar.');
|
|
682
|
+
} else if (e instanceof TimeoutError) {
|
|
683
|
+
console.error('Request timeout. Coba naikkan nilai timeout di init().');
|
|
684
|
+
} else if (e instanceof ModelInvalid) {
|
|
685
|
+
console.error('Model tidak valid atau tidak tersedia. Coba model lain.');
|
|
686
|
+
} else if (e instanceof APIError) {
|
|
687
|
+
console.error('API error:', e.message);
|
|
688
|
+
} else {
|
|
689
|
+
throw e;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
## Persistensi Cookie
|
|
695
|
+
|
|
696
|
+
Kalau aplikasi kamu berjalan di container (mis. Docker), simpan cache cookie yang diperbarui otomatis ke volume dengan mengatur variabel environment `GEMINI_COOKIE_PATH` ke path yang bisa ditulis.
|
|
697
|
+
|
|
698
|
+
```yaml
|
|
699
|
+
# docker-compose.yml
|
|
700
|
+
services:
|
|
701
|
+
app:
|
|
702
|
+
environment:
|
|
703
|
+
GEMINI_COOKIE_PATH: /tmp/gemini_cache
|
|
704
|
+
volumes:
|
|
705
|
+
- ./gemini_cookies:/tmp/gemini_cache
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
Secara default, cache disimpan di `utils/temp/` relatif terhadap direktori package.
|
|
709
|
+
|
|
710
|
+
## TypeScript
|
|
711
|
+
|
|
712
|
+
Package ini sudah menyertakan deklarasi TypeScript lengkap.
|
|
713
|
+
|
|
714
|
+
```ts
|
|
715
|
+
import {
|
|
716
|
+
GeminiClient,
|
|
717
|
+
ChatSession,
|
|
718
|
+
ModelOutput,
|
|
719
|
+
ChatHistory,
|
|
720
|
+
ChatTurn,
|
|
721
|
+
ChatInfo,
|
|
722
|
+
Gem,
|
|
723
|
+
AvailableModel,
|
|
724
|
+
Model,
|
|
725
|
+
AccountStatus,
|
|
726
|
+
DeepResearchPlan,
|
|
727
|
+
DeepResearchResult,
|
|
728
|
+
StreamingFrameParser,
|
|
729
|
+
} from 'gemini-reverse';
|
|
730
|
+
|
|
731
|
+
const client = new GeminiClient({ secure_1psid: '...' });
|
|
732
|
+
await client.init();
|
|
733
|
+
|
|
734
|
+
const chat: ChatSession = client.startChat({ model: 'gemini-3-flash' });
|
|
735
|
+
const response: ModelOutput = await chat.sendMessage({
|
|
736
|
+
prompt: 'Halo!',
|
|
737
|
+
extended_thinking: false,
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
console.log(response.text);
|
|
741
|
+
|
|
742
|
+
const history: ChatHistory | null = await chat.readHistory();
|
|
743
|
+
if (history) {
|
|
744
|
+
history.turns.forEach((turn: ChatTurn) => console.log(turn.role, turn.text));
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
const models: AvailableModel[] | null = client.listModels();
|
|
748
|
+
|
|
749
|
+
// Akses quota dan info penggunaan setelah init
|
|
750
|
+
console.log(client.quotas);
|
|
751
|
+
console.log(client.usageInfo);
|
|
752
|
+
console.log(client.abuseStatus);
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
## Struktur Proyek
|
|
756
|
+
|
|
757
|
+
```
|
|
758
|
+
gemini-reverse/
|
|
759
|
+
├── index.js # entry point & ekspor
|
|
760
|
+
├── index.d.ts # deklarasi TypeScript
|
|
761
|
+
├── client.js # GeminiClient + ChatSession
|
|
762
|
+
├── constants.js # Endpoint, GRPC, Headers, Model, AccountStatus, ErrorCode
|
|
763
|
+
├── exceptions.js # kelas error kustom
|
|
764
|
+
├── types/
|
|
765
|
+
│ ├── availablemodel.js # AvailableModel (model dinamis dari API)
|
|
766
|
+
│ ├── candidate.js # Candidate
|
|
767
|
+
│ ├── chathistory.js # ChatTurn, ChatHistory
|
|
768
|
+
│ ├── chatinfo.js # ChatInfo
|
|
769
|
+
│ ├── gem.js # Gem, GemJar
|
|
770
|
+
│ ├── grpc.js # RPCData
|
|
771
|
+
│ ├── image.js # Image, WebImage, GeneratedImage
|
|
772
|
+
│ ├── modeloutput.js # ModelOutput
|
|
773
|
+
│ ├── research.js # DeepResearchPlan, DeepResearchStatus
|
|
774
|
+
│ ├── researchresult.js # DeepResearchResult
|
|
775
|
+
│ └── video.js # Video, GeneratedVideo, GeneratedMedia
|
|
776
|
+
├── utils/
|
|
777
|
+
│ ├── accessToken.js # penanganan cookie & request init
|
|
778
|
+
│ ├── parsing.js # utilitas parsing respons + StreamingFrameParser
|
|
779
|
+
│ ├── research.js # ekstraktor payload deep research
|
|
780
|
+
│ ├── rotate.js # rotasi cookie
|
|
781
|
+
│ └── upload.js # helper upload file
|
|
782
|
+
└── components/
|
|
783
|
+
├── chatMixin.js # metode riwayat chat
|
|
784
|
+
├── gemMixin.js # metode manajemen gem
|
|
785
|
+
└── researchMixin.js # metode deep research
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
## Referensi
|
|
789
|
+
|
|
790
|
+
[Google AI Studio](https://ai.google.dev/tutorials/ai-studio_quickstart)
|
|
791
|
+
|
|
792
|
+
[Gemini-API (Python)](https://github.com/HanaokaYuzu/Gemini-API) oleh [@HanaokaYuzu](https://github.com/HanaokaYuzu)
|
|
793
|
+
|
|
794
|
+
[acheong08/Bard](https://github.com/acheong08/Bard)
|
|
795
|
+
|
|
796
|
+
---
|
|
797
|
+
|
|
798
|
+
**Disclaimer:** Ini adalah package tidak resmi dan tidak ada hubungannya dengan Google. Autentikasi berbasis cookie bisa saja berhenti bekerja kalau Google mengubah API internalnya. Gunakan dengan risiko sendiri.
|
|
799
|
+
|
|
800
|
+
**Lisensi:** MIT
|
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
An unofficial Node.js client for [Google Gemini](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
6
|
|
|
7
|
+
> **Language / Bahasa:** [English](README.md) · [Indonesia](README-IDN.md) | **Changelog:** [EN](CHANGELOG-EN.md) · [IDN](CHANGELOG-IDN.md)
|
|
8
|
+
|
|
7
9
|
## Features
|
|
8
10
|
|
|
9
11
|
- **Persistent Cookies** — Automatically refreshes cookies in the background with jitter to prevent synchronized requests. Optimized for always-on services.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gemini-reverse",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "Unofficial Node.js client for gemini.google.com — inspired by Gemini-API (Python). Supports streaming, chat sessions, gems, file uploads, and TypeScript.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|