notebooklm-kit 0.0.1 → 2.1.1
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/LICENSE +22 -0
- package/README.md +4102 -0
- package/dist/src/auth/auth.d.ts +46 -0
- package/dist/src/auth/auth.d.ts.map +1 -0
- package/dist/src/auth/auth.js +323 -0
- package/dist/src/auth/auth.js.map +1 -0
- package/dist/src/auth/refresh.d.ts +150 -0
- package/dist/src/auth/refresh.d.ts.map +1 -0
- package/dist/src/auth/refresh.js +433 -0
- package/dist/src/auth/refresh.js.map +1 -0
- package/dist/src/client/notebooklm-client.d.ts +372 -0
- package/dist/src/client/notebooklm-client.d.ts.map +1 -0
- package/dist/src/client/notebooklm-client.js +550 -0
- package/dist/src/client/notebooklm-client.js.map +1 -0
- package/dist/src/index.d.ts +50 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +45 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/rpc/rpc-client.d.ts +48 -0
- package/dist/src/rpc/rpc-client.d.ts.map +1 -0
- package/dist/src/rpc/rpc-client.js +94 -0
- package/dist/src/rpc/rpc-client.js.map +1 -0
- package/dist/src/rpc/rpc-methods.d.ts +127 -0
- package/dist/src/rpc/rpc-methods.d.ts.map +1 -0
- package/dist/src/rpc/rpc-methods.js +169 -0
- package/dist/src/rpc/rpc-methods.js.map +1 -0
- package/dist/src/services/artifacts.d.ts +1017 -0
- package/dist/src/services/artifacts.d.ts.map +1 -0
- package/dist/src/services/artifacts.js +5413 -0
- package/dist/src/services/artifacts.js.map +1 -0
- package/dist/src/services/generation.d.ts +147 -0
- package/dist/src/services/generation.d.ts.map +1 -0
- package/dist/src/services/generation.js +479 -0
- package/dist/src/services/generation.js.map +1 -0
- package/dist/src/services/notebook-language.d.ts +109 -0
- package/dist/src/services/notebook-language.d.ts.map +1 -0
- package/dist/src/services/notebook-language.js +204 -0
- package/dist/src/services/notebook-language.js.map +1 -0
- package/dist/src/services/notebooks.d.ts +26 -0
- package/dist/src/services/notebooks.d.ts.map +1 -0
- package/dist/src/services/notebooks.js +539 -0
- package/dist/src/services/notebooks.js.map +1 -0
- package/dist/src/services/notes.d.ts +72 -0
- package/dist/src/services/notes.d.ts.map +1 -0
- package/dist/src/services/notes.js +340 -0
- package/dist/src/services/notes.js.map +1 -0
- package/dist/src/services/sources.d.ts +1085 -0
- package/dist/src/services/sources.d.ts.map +1 -0
- package/dist/src/services/sources.js +2675 -0
- package/dist/src/services/sources.js.map +1 -0
- package/dist/src/types/artifact.d.ts +258 -0
- package/dist/src/types/artifact.d.ts.map +1 -0
- package/dist/src/types/artifact.js +42 -0
- package/dist/src/types/artifact.js.map +1 -0
- package/dist/src/types/common.d.ts +226 -0
- package/dist/src/types/common.d.ts.map +1 -0
- package/dist/src/types/common.js +80 -0
- package/dist/src/types/common.js.map +1 -0
- package/dist/src/types/languages.d.ts +179 -0
- package/dist/src/types/languages.d.ts.map +1 -0
- package/dist/src/types/languages.js +254 -0
- package/dist/src/types/languages.js.map +1 -0
- package/dist/src/types/note.d.ts +41 -0
- package/dist/src/types/note.d.ts.map +1 -0
- package/dist/src/types/note.js +12 -0
- package/dist/src/types/note.js.map +1 -0
- package/dist/src/types/notebook.d.ts +81 -0
- package/dist/src/types/notebook.d.ts.map +1 -0
- package/dist/src/types/notebook.js +5 -0
- package/dist/src/types/notebook.js.map +1 -0
- package/dist/src/types/source.d.ts +241 -0
- package/dist/src/types/source.d.ts.map +1 -0
- package/dist/src/types/source.js +60 -0
- package/dist/src/types/source.js.map +1 -0
- package/dist/src/utils/batch-execute.d.ts +58 -0
- package/dist/src/utils/batch-execute.d.ts.map +1 -0
- package/dist/src/utils/batch-execute.js +398 -0
- package/dist/src/utils/batch-execute.js.map +1 -0
- package/dist/src/utils/chunked-decoder.d.ts +11 -0
- package/dist/src/utils/chunked-decoder.d.ts.map +1 -0
- package/dist/src/utils/chunked-decoder.js +326 -0
- package/dist/src/utils/chunked-decoder.js.map +1 -0
- package/dist/src/utils/chunked-parser.d.ts +61 -0
- package/dist/src/utils/chunked-parser.d.ts.map +1 -0
- package/dist/src/utils/chunked-parser.js +609 -0
- package/dist/src/utils/chunked-parser.js.map +1 -0
- package/dist/src/utils/errors.d.ts +58 -0
- package/dist/src/utils/errors.d.ts.map +1 -0
- package/dist/src/utils/errors.js +357 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/dist/src/utils/quota.d.ts +213 -0
- package/dist/src/utils/quota.d.ts.map +1 -0
- package/dist/src/utils/quota.js +518 -0
- package/dist/src/utils/quota.js.map +1 -0
- package/dist/src/utils/streaming-client.d.ts +129 -0
- package/dist/src/utils/streaming-client.d.ts.map +1 -0
- package/dist/src/utils/streaming-client.js +559 -0
- package/dist/src/utils/streaming-client.js.map +1 -0
- package/package.json +85 -7
- package/index.js +0 -2
package/README.md
ADDED
|
@@ -0,0 +1,4102 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# @photon-ai/NotebookLM-kit
|
|
4
|
+
|
|
5
|
+
> A TypeScript SDK for programmatic access to Google NotebookLM.
|
|
6
|
+
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/notebooklm-kit)
|
|
10
|
+
[](https://www.typescriptlang.org/)
|
|
11
|
+
[](./LICENSE)
|
|
12
|
+
[](https://discord.gg/bZd4CMd2H5)
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
The NotebookLM Kit provides a clean, service-based interface to all NotebookLM features. Perfect for building AI research assistants, study tools, content generators, and automated knowledge management systems.
|
|
17
|
+
|
|
18
|
+
> [!NOTE]
|
|
19
|
+
> **✨ Looking for advanced features, custom integrations, or enterprise support? Contact us at [vandit@photon.codes](mailto:vandit@photon.codes).**
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
<table>
|
|
24
|
+
<thead>
|
|
25
|
+
<tr>
|
|
26
|
+
<th>Feature</th>
|
|
27
|
+
<th>Method</th>
|
|
28
|
+
<th>Example</th>
|
|
29
|
+
</tr>
|
|
30
|
+
</thead>
|
|
31
|
+
<tbody>
|
|
32
|
+
<tr style="height: 30px;"><td colspan="3"></td></tr>
|
|
33
|
+
<tr>
|
|
34
|
+
<td colspan="3" style="padding-top: 20px; padding-bottom: 20px;"><strong style="font-size: 1.2em;"><a href="#notebooks">Notebook Management</a></strong> <small><code>list()</code>, <code>create()</code>, <code>get()</code>, <code>update()</code>, <code>delete()</code>, <code>share()</code></small></td>
|
|
35
|
+
</tr>
|
|
36
|
+
<tr style="height: 30px;"><td colspan="3"></td></tr>
|
|
37
|
+
<tr>
|
|
38
|
+
<td>List Notebooks</td>
|
|
39
|
+
<td><code>sdk.notebooks.list()</code></td>
|
|
40
|
+
<td><a href="examples/notebook-list.ts">notebook-list.ts</a></td>
|
|
41
|
+
</tr>
|
|
42
|
+
<tr>
|
|
43
|
+
<td>Create Notebook</td>
|
|
44
|
+
<td><code>sdk.notebooks.create()</code></td>
|
|
45
|
+
<td><a href="examples/notebook-create.ts">notebook-create.ts</a></td>
|
|
46
|
+
</tr>
|
|
47
|
+
<tr>
|
|
48
|
+
<td>Get Notebook</td>
|
|
49
|
+
<td><code>sdk.notebooks.get()</code></td>
|
|
50
|
+
<td><a href="examples/notebook-get.ts">notebook-get.ts</a></td>
|
|
51
|
+
</tr>
|
|
52
|
+
<tr>
|
|
53
|
+
<td>Update Notebook</td>
|
|
54
|
+
<td><code>sdk.notebooks.update()</code></td>
|
|
55
|
+
<td><a href="examples/notebook-update.ts">notebook-update.ts</a></td>
|
|
56
|
+
</tr>
|
|
57
|
+
<tr>
|
|
58
|
+
<td>Delete Notebook</td>
|
|
59
|
+
<td><code>sdk.notebooks.delete()</code></td>
|
|
60
|
+
<td><a href="examples/notebook-delete.ts">notebook-delete.ts</a></td>
|
|
61
|
+
</tr>
|
|
62
|
+
<tr>
|
|
63
|
+
<td>Share Notebook</td>
|
|
64
|
+
<td><code>sdk.notebooks.share()</code></td>
|
|
65
|
+
<td><a href="examples/notebook-share.ts">notebook-share.ts</a></td>
|
|
66
|
+
</tr>
|
|
67
|
+
<tr style="height: 30px;"><td colspan="3"></td></tr>
|
|
68
|
+
<tr>
|
|
69
|
+
<td colspan="3" style="padding-top: 20px; padding-bottom: 20px;"><strong style="font-size: 1.2em;"><a href="#sources">Source Management</a></strong> <small><code>list()</code>, <code>get()</code>, <code>add.url()</code>, <code>add.text()</code>, <code>add.youtube()</code>, <code>add.file()</code>, <code>add.drive()</code>, <code>add.batch()</code>, <code>add.web.searchAndWait()</code>, <code>update()</code>, <code>delete()</code>, <code>status()</code></small></td>
|
|
70
|
+
</tr>
|
|
71
|
+
<tr style="height: 30px;"><td colspan="3"></td></tr>
|
|
72
|
+
<tr>
|
|
73
|
+
<td>List Sources</td>
|
|
74
|
+
<td><code>sdk.sources.list()</code></td>
|
|
75
|
+
<td><a href="examples/source-list.ts">source-list.ts</a></td>
|
|
76
|
+
</tr>
|
|
77
|
+
<tr>
|
|
78
|
+
<td>Add URL Source</td>
|
|
79
|
+
<td><code>sdk.sources.add.url()</code></td>
|
|
80
|
+
<td><a href="examples/source-add-url.ts">source-add-url.ts</a></td>
|
|
81
|
+
</tr>
|
|
82
|
+
<tr>
|
|
83
|
+
<td>Add Text Source</td>
|
|
84
|
+
<td><code>sdk.sources.add.text()</code></td>
|
|
85
|
+
<td><a href="examples/source-add-text.ts">source-add-text.ts</a></td>
|
|
86
|
+
</tr>
|
|
87
|
+
<tr>
|
|
88
|
+
<td>Add YouTube Source</td>
|
|
89
|
+
<td><code>sdk.sources.add.youtube()</code></td>
|
|
90
|
+
<td><a href="examples/source-add-youtube.ts">source-add-youtube.ts</a></td>
|
|
91
|
+
</tr>
|
|
92
|
+
<tr>
|
|
93
|
+
<td>Add File Source</td>
|
|
94
|
+
<td><code>sdk.sources.add.file()</code></td>
|
|
95
|
+
<td><a href="examples/source-add-file.ts">source-add-file.ts</a></td>
|
|
96
|
+
</tr>
|
|
97
|
+
<tr>
|
|
98
|
+
<td>Add Drive Source</td>
|
|
99
|
+
<td><code>sdk.sources.add.drive()</code></td>
|
|
100
|
+
<td><a href="examples/source-add-drive.ts">source-add-drive.ts</a></td>
|
|
101
|
+
</tr>
|
|
102
|
+
<tr>
|
|
103
|
+
<td>Add Batch Sources</td>
|
|
104
|
+
<td><code>sdk.sources.add.batch()</code></td>
|
|
105
|
+
<td><a href="examples/source-add-batch.ts">source-add-batch.ts</a></td>
|
|
106
|
+
</tr>
|
|
107
|
+
<tr>
|
|
108
|
+
<td>Web Search Source</td>
|
|
109
|
+
<td><code>sdk.sources.add.web.searchAndWait()</code></td>
|
|
110
|
+
<td><a href="examples/source-web-search.ts">source-web-search.ts</a></td>
|
|
111
|
+
</tr>
|
|
112
|
+
<tr>
|
|
113
|
+
<td>Advanced Web Search</td>
|
|
114
|
+
<td><code>sdk.sources.add.web.searchAndWait()</code></td>
|
|
115
|
+
<td><a href="examples/source-web-search-advanced.ts">source-web-search-advanced.ts</a></td>
|
|
116
|
+
</tr>
|
|
117
|
+
<tr>
|
|
118
|
+
<td>Get Source</td>
|
|
119
|
+
<td><code>sdk.sources.get()</code></td>
|
|
120
|
+
<td><a href="examples/source-get.ts">source-get.ts</a></td>
|
|
121
|
+
</tr>
|
|
122
|
+
<tr>
|
|
123
|
+
<td>Update Source</td>
|
|
124
|
+
<td><code>sdk.sources.update()</code></td>
|
|
125
|
+
<td><a href="examples/source-update.ts">source-update.ts</a></td>
|
|
126
|
+
</tr>
|
|
127
|
+
<tr>
|
|
128
|
+
<td>Delete Source</td>
|
|
129
|
+
<td><code>sdk.sources.delete()</code></td>
|
|
130
|
+
<td><a href="examples/source-delete.ts">source-delete.ts</a></td>
|
|
131
|
+
</tr>
|
|
132
|
+
<tr>
|
|
133
|
+
<td>Check Source Status</td>
|
|
134
|
+
<td><code>sdk.sources.status()</code></td>
|
|
135
|
+
<td><a href="examples/source-status.ts">source-status.ts</a></td>
|
|
136
|
+
</tr>
|
|
137
|
+
<tr style="height: 30px;"><td colspan="3"></td></tr>
|
|
138
|
+
<tr>
|
|
139
|
+
<td colspan="3" style="padding-top: 20px; padding-bottom: 20px;"><strong style="font-size: 1.2em;"><a href="#artifacts">Artifact Generation</a></strong> <small><code>create()</code>, <code>list()</code>, <code>get()</code>, <code>download()</code>, <code>rename()</code>, <code>delete()</code>, <code>share()</code></small></td>
|
|
140
|
+
</tr>
|
|
141
|
+
<tr style="height: 30px;"><td colspan="3"></td></tr>
|
|
142
|
+
<tr>
|
|
143
|
+
<td>Create Artifact</td>
|
|
144
|
+
<td><code>sdk.artifacts.create()</code></td>
|
|
145
|
+
<td><a href="examples/artifact-create.ts">artifact-create.ts</a></td>
|
|
146
|
+
</tr>
|
|
147
|
+
<tr>
|
|
148
|
+
<td>Create Artifact (Subservices)</td>
|
|
149
|
+
<td><code>sdk.artifacts.{type}.create()</code></td>
|
|
150
|
+
<td><a href="examples/artifact-create-subservices.ts">artifact-create-subservices.ts</a></td>
|
|
151
|
+
</tr>
|
|
152
|
+
<tr>
|
|
153
|
+
<td>List Artifacts</td>
|
|
154
|
+
<td><code>sdk.artifacts.list()</code></td>
|
|
155
|
+
<td><a href="examples/artifact-list.ts">artifact-list.ts</a></td>
|
|
156
|
+
</tr>
|
|
157
|
+
<tr>
|
|
158
|
+
<td>Get Artifact</td>
|
|
159
|
+
<td><code>sdk.artifacts.get()</code></td>
|
|
160
|
+
<td><a href="examples/artifact-get.ts">artifact-get.ts</a></td>
|
|
161
|
+
</tr>
|
|
162
|
+
<tr>
|
|
163
|
+
<td>Download Artifact</td>
|
|
164
|
+
<td><code>sdk.artifacts.download()</code></td>
|
|
165
|
+
<td><a href="examples/artifact-download.ts">artifact-download.ts</a></td>
|
|
166
|
+
</tr>
|
|
167
|
+
<tr>
|
|
168
|
+
<td>Download Video</td>
|
|
169
|
+
<td><code>sdk.artifacts.download()</code></td>
|
|
170
|
+
<td><a href="examples/artifact-video.ts">artifact-video.ts</a></td>
|
|
171
|
+
</tr>
|
|
172
|
+
<tr>
|
|
173
|
+
<td>Download Slides</td>
|
|
174
|
+
<td><code>sdk.artifacts.download()</code></td>
|
|
175
|
+
<td><a href="examples/slide-download-test.ts">slide-download-test.ts</a></td>
|
|
176
|
+
</tr>
|
|
177
|
+
<tr>
|
|
178
|
+
<td>Rename Artifact</td>
|
|
179
|
+
<td><code>sdk.artifacts.rename()</code></td>
|
|
180
|
+
<td><a href="examples/artifact-rename.ts">artifact-rename.ts</a></td>
|
|
181
|
+
</tr>
|
|
182
|
+
<tr>
|
|
183
|
+
<td>Delete Artifact</td>
|
|
184
|
+
<td><code>sdk.artifacts.delete()</code></td>
|
|
185
|
+
<td><a href="examples/artifact-delete.ts">artifact-delete.ts</a></td>
|
|
186
|
+
</tr>
|
|
187
|
+
<tr>
|
|
188
|
+
<td>Share Artifact</td>
|
|
189
|
+
<td><code>sdk.artifacts.share()</code></td>
|
|
190
|
+
<td><a href="examples/artifact-share.ts">artifact-share.ts</a></td>
|
|
191
|
+
</tr>
|
|
192
|
+
<tr style="height: 30px;"><td colspan="3"></td></tr>
|
|
193
|
+
<tr>
|
|
194
|
+
<td colspan="3" style="padding-top: 20px; padding-bottom: 20px;"><strong style="font-size: 1.2em;"><a href="#generation--chat">Chat & Generation</a></strong> <small><code>chat()</code>, <code>chatStream()</code>, <code>setChatConfig()</code></small></td>
|
|
195
|
+
</tr>
|
|
196
|
+
<tr style="height: 30px;"><td colspan="3"></td></tr>
|
|
197
|
+
<tr>
|
|
198
|
+
<td>Chat</td>
|
|
199
|
+
<td><code>sdk.generation.chat()</code></td>
|
|
200
|
+
<td><a href="examples/chat-basic.ts">chat-basic.ts</a></td>
|
|
201
|
+
</tr>
|
|
202
|
+
<tr>
|
|
203
|
+
<td>Stream Chat</td>
|
|
204
|
+
<td><code>sdk.generation.chatStream()</code></td>
|
|
205
|
+
<td><a href="examples/chat-conversation.ts">chat-conversation.ts</a></td>
|
|
206
|
+
</tr>
|
|
207
|
+
<tr>
|
|
208
|
+
<td>Set Chat Config</td>
|
|
209
|
+
<td><code>sdk.generation.setChatConfig()</code></td>
|
|
210
|
+
<td><a href="examples/generation-set-chat-config.ts">generation-set-chat-config.ts</a></td>
|
|
211
|
+
</tr>
|
|
212
|
+
<tr style="height: 30px;"><td colspan="3"></td></tr>
|
|
213
|
+
<tr>
|
|
214
|
+
<td colspan="3" style="padding-top: 20px; padding-bottom: 20px;"><strong style="font-size: 1.2em;"><a href="#notes">Notes Management</a></strong> <small><code>list()</code>, <code>create()</code>, <code>update()</code>, <code>delete()</code></small></td>
|
|
215
|
+
</tr>
|
|
216
|
+
<tr style="height: 30px;"><td colspan="3"></td></tr>
|
|
217
|
+
<tr>
|
|
218
|
+
<td>List Notes</td>
|
|
219
|
+
<td><code>sdk.notes.list()</code></td>
|
|
220
|
+
<td><a href="examples/note-list.ts">note-list.ts</a></td>
|
|
221
|
+
</tr>
|
|
222
|
+
<tr>
|
|
223
|
+
<td>Create Note</td>
|
|
224
|
+
<td><code>sdk.notes.create()</code></td>
|
|
225
|
+
<td><a href="examples/note-create.ts">note-create.ts</a></td>
|
|
226
|
+
</tr>
|
|
227
|
+
<tr>
|
|
228
|
+
<td>Update Note</td>
|
|
229
|
+
<td><code>sdk.notes.update()</code></td>
|
|
230
|
+
<td><a href="examples/note-update.ts">note-update.ts</a></td>
|
|
231
|
+
</tr>
|
|
232
|
+
<tr>
|
|
233
|
+
<td>Delete Note</td>
|
|
234
|
+
<td><code>sdk.notes.delete()</code></td>
|
|
235
|
+
<td><a href="examples/note-delete.ts">note-delete.ts</a></td>
|
|
236
|
+
</tr>
|
|
237
|
+
</tbody>
|
|
238
|
+
</table>
|
|
239
|
+
|
|
240
|
+
## Installation
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
npm install notebooklm-kit
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**From source:**
|
|
247
|
+
```bash
|
|
248
|
+
git clone https://github.com/photon-hq/notebooklm-kit.git && cd notebooklm-kit && npm run setup
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Requirements:** Node.js >=18.0.0
|
|
252
|
+
|
|
253
|
+
## Version
|
|
254
|
+
|
|
255
|
+
Current version: **2.1.1**
|
|
256
|
+
|
|
257
|
+
## Available Scripts
|
|
258
|
+
|
|
259
|
+
When working with the repository, you can use the following npm scripts:
|
|
260
|
+
|
|
261
|
+
| Script | Description |
|
|
262
|
+
|--------|-------------|
|
|
263
|
+
| `npm install` | Install dependencies and automatically build (runs postinstall) |
|
|
264
|
+
| `npm run setup` | Full setup: install dependencies, Playwright, and build |
|
|
265
|
+
| `npm run build` | Compile TypeScript to JavaScript |
|
|
266
|
+
| `npm run build:dev` | Build only (no reinstall) |
|
|
267
|
+
| `npm run dev` | Watch mode (auto-rebuild on file changes) |
|
|
268
|
+
| `npm run clean` | Remove compiled dist/ directory |
|
|
269
|
+
|
|
270
|
+
<details>
|
|
271
|
+
<summary><strong>Development</strong></summary>
|
|
272
|
+
|
|
273
|
+
**First-time setup:**
|
|
274
|
+
```bash
|
|
275
|
+
npm run setup
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Build only (no reinstall):**
|
|
279
|
+
```bash
|
|
280
|
+
npm run build:dev
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**Watch mode (auto-rebuild):**
|
|
284
|
+
```bash
|
|
285
|
+
npm run dev
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Clean build:**
|
|
289
|
+
```bash
|
|
290
|
+
npm run clean && npm run build
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
</details>
|
|
294
|
+
|
|
295
|
+
## Quick Start
|
|
296
|
+
|
|
297
|
+
### 1. Install the package
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
npm install notebooklm-kit
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### 2. Set up authentication
|
|
304
|
+
|
|
305
|
+
**Auto (browser):** Create `.env` with `GOOGLE_EMAIL` and `GOOGLE_PASSWORD` (no 2FA required)
|
|
306
|
+
|
|
307
|
+
**Manual:** Create `.env` with `NOTEBOOKLM_AUTH_TOKEN` and `NOTEBOOKLM_COOKIES` from browser DevTools (Network → Cookie header, Console → `window.WIZ_global_data.SNlM0e`)
|
|
308
|
+
|
|
309
|
+
### 3. Use the SDK
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
import { NotebookLMClient } from 'notebooklm-kit';
|
|
313
|
+
import dotenv from 'dotenv';
|
|
314
|
+
|
|
315
|
+
// Load .env file from project root (automatically detected)
|
|
316
|
+
dotenv.config();
|
|
317
|
+
|
|
318
|
+
async function main() {
|
|
319
|
+
const sdk = new NotebookLMClient({
|
|
320
|
+
// Credentials are automatically loaded from .env file
|
|
321
|
+
// Priority: NOTEBOOKLM_AUTH_TOKEN/NOTEBOOKLM_COOKIES > GOOGLE_EMAIL/GOOGLE_PASSWORD
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
try {
|
|
325
|
+
await sdk.connect();
|
|
326
|
+
|
|
327
|
+
// List notebooks
|
|
328
|
+
const notebooks = await sdk.notebooks.list();
|
|
329
|
+
console.log(`Found ${notebooks.length} notebooks`);
|
|
330
|
+
|
|
331
|
+
// Create a notebook
|
|
332
|
+
const notebook = await sdk.notebooks.create({
|
|
333
|
+
title: 'My Research',
|
|
334
|
+
emoji: '📚',
|
|
335
|
+
});
|
|
336
|
+
console.log(`Created: ${notebook.title}`);
|
|
337
|
+
|
|
338
|
+
} catch (error) {
|
|
339
|
+
console.error('Error:', error);
|
|
340
|
+
} finally {
|
|
341
|
+
sdk.dispose();
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
main();
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**Note:** The SDK automatically loads credentials from environment variables. See [SDK Initialization](#sdk-initialization) for all configuration options.
|
|
349
|
+
|
|
350
|
+
### Running Examples
|
|
351
|
+
|
|
352
|
+
The repository includes working examples in the [`examples/`](examples/) directory. To run them:
|
|
353
|
+
|
|
354
|
+
1. **Set up your `.env` file** in the project root (see [Authentication](#2-set-up-authentication) above)
|
|
355
|
+
2. **Run any example** using `tsx`:
|
|
356
|
+
```bash
|
|
357
|
+
npx tsx examples/notebook-list.ts
|
|
358
|
+
npx tsx examples/chat-basic.ts
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Chat Example Usage:**
|
|
362
|
+
```bash
|
|
363
|
+
# Interactive mode (prompts for notebook and message)
|
|
364
|
+
npx tsx examples/chat-basic.ts
|
|
365
|
+
|
|
366
|
+
# With notebook ID and message (streaming mode - default)
|
|
367
|
+
npx tsx examples/chat-basic.ts <notebook-id> "What are the key findings?"
|
|
368
|
+
|
|
369
|
+
# Non-streaming mode (get complete response at once)
|
|
370
|
+
npx tsx examples/chat-basic.ts <notebook-id> "What are the key findings?" --no-stream
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
**Note:** The examples automatically detect and load the `.env` file from the project root, regardless of where you run them from.
|
|
374
|
+
|
|
375
|
+
## Features
|
|
376
|
+
|
|
377
|
+
### `sdk.notebooks` - Notebook Management
|
|
378
|
+
|
|
379
|
+
| Feature | Description | Method | Example |
|
|
380
|
+
|---------|-------------|--------|---------|
|
|
381
|
+
| List Notebooks | List all your notebooks (recently viewed) | [`sdk.notebooks.list()`](#list-notebooks) | [notebook-list.ts](examples/notebook-list.ts) |
|
|
382
|
+
| Get Notebook | Get full details of a specific notebook | [`sdk.notebooks.get(notebookId)`](#get-notebook) | [notebook-get.ts](examples/notebook-get.ts) |
|
|
383
|
+
| Create Notebook | Create a new notebook (auto-generates title if empty) | [`sdk.notebooks.create(options)`](#create-notebook) | [notebook-create.ts](examples/notebook-create.ts) |
|
|
384
|
+
| Update Notebook | Update notebook title or emoji | [`sdk.notebooks.update(notebookId, options)`](#update-notebook) | [notebook-update.ts](examples/notebook-update.ts) |
|
|
385
|
+
| Delete Notebook | Delete one or more notebooks | [`sdk.notebooks.delete(notebookIds)`](#delete-notebook) | [notebook-delete.ts](examples/notebook-delete.ts) |
|
|
386
|
+
| Share Notebook | Share notebook with users or enable link sharing | [`sdk.notebooks.share(notebookId, options)`](#share-notebook) | [notebook-share.ts](examples/notebook-share.ts) |
|
|
387
|
+
|
|
388
|
+
### `sdk.sources` - Source Management
|
|
389
|
+
|
|
390
|
+
| Feature | Description | Method | Example |
|
|
391
|
+
|---------|-------------|--------|---------|
|
|
392
|
+
| List Sources | List all sources in a notebook | [`sdk.sources.list(notebookId)`](#list-sources) | [source-list.ts](examples/source-list.ts) |
|
|
393
|
+
| Get Source | Get one or all sources | [`sdk.sources.get(notebookId, sourceId?)`](#get-source) | [source-get.ts](examples/source-get.ts) |
|
|
394
|
+
| Add URL | Add a source from a web page URL | [`sdk.sources.add.url(notebookId, options)`](#add-url-source) | [source-add-url.ts](examples/source-add-url.ts) |
|
|
395
|
+
| Add Text | Add a source from text content | [`sdk.sources.add.text(notebookId, options)`](#add-text-source) | [source-add-text.ts](examples/source-add-text.ts) |
|
|
396
|
+
| Add File | Add a source from a file (PDF, image, etc.) | [`sdk.sources.add.file(notebookId, options)`](#add-file-source) | [source-add-file.ts](examples/source-add-file.ts) |
|
|
397
|
+
| Add YouTube | Add a YouTube video as a source | [`sdk.sources.add.youtube(notebookId, options)`](#add-youtube-source) | [source-add-youtube.ts](examples/source-add-youtube.ts) |
|
|
398
|
+
| Add Google Drive | Add a Google Drive file as a source | [`sdk.sources.add.drive(notebookId, options)`](#add-google-drive-source) | [source-add-drive.ts](examples/source-add-drive.ts) |
|
|
399
|
+
| Batch Add | Add multiple sources at once | [`sdk.sources.add.batch(notebookId, options)`](#batch-add-sources) | [source-add-batch.ts](examples/source-add-batch.ts) |
|
|
400
|
+
| Web Search (Simple) | Search web and wait for results | [`sdk.sources.add.web.searchAndWait(notebookId, options)`](#web-search-simple) | [source-web-search.ts](examples/source-web-search.ts) |
|
|
401
|
+
| Web Search (Advanced) | Multi-step web search workflow | [`sdk.sources.add.web.search()`](#web-search-advanced) → `getResults()` → `addDiscovered()` | [source-web-search-advanced.ts](examples/source-web-search-advanced.ts) |
|
|
402
|
+
| Update Source | Update source metadata | [`sdk.sources.update(notebookId, sourceId, updates)`](#update-source) | [source-update.ts](examples/source-update.ts) |
|
|
403
|
+
| Delete Source | Delete a source from a notebook | [`sdk.sources.delete(notebookId, sourceId)`](#delete-source) | [source-delete.ts](examples/source-delete.ts) |
|
|
404
|
+
| Check Status | Check source processing status | [`sdk.sources.status(notebookId)`](#check-processing-status) | [source-status.ts](examples/source-status.ts) |
|
|
405
|
+
|
|
406
|
+
### `sdk.artifacts` - Artifact Management
|
|
407
|
+
|
|
408
|
+
| Feature | Description | Method | Example |
|
|
409
|
+
|---------|-------------|--------|---------|
|
|
410
|
+
| Create Artifact | Create study material (quiz, flashcards, mind map, etc.) | [`sdk.artifacts.create()`](#create-artifact) or `sdk.artifacts.{type}.create()` | [artifact-create.ts](examples/artifact-create.ts)<br>[artifact-create-subservices.ts](examples/artifact-create-subservices.ts) |
|
|
411
|
+
| List Artifacts | List all artifacts in a notebook (with filtering) | [`sdk.artifacts.list()`](#list-artifacts) | [artifact-list.ts](examples/artifact-list.ts) |
|
|
412
|
+
| Get Artifact | Get artifact details (auto-fetches content when ready) | [`sdk.artifacts.get()`](#get-artifact) | [artifact-get.ts](examples/artifact-get.ts) |
|
|
413
|
+
| Download Artifact | Download artifact data to disk (quiz/flashcard JSON, audio file) | [`sdk.artifacts.download()`](#download-artifact) | [artifact-download.ts](examples/artifact-download.ts) |
|
|
414
|
+
| Download Video | Download video artifact as MP4 file | [`sdk.artifacts.download()`](#download-artifact) | [artifact-video.ts](examples/artifact-video.ts) |
|
|
415
|
+
| Download Slides | Download slide deck as PDF or PNG files | [`sdk.artifacts.download()`](#download-artifact) | [slide-download-test.ts](examples/slide-download-test.ts) |
|
|
416
|
+
| Rename Artifact | Rename an artifact | [`sdk.artifacts.rename()`](#rename-artifact) | [artifact-rename.ts](examples/artifact-rename.ts) |
|
|
417
|
+
| Delete Artifact | Delete an artifact | [`sdk.artifacts.delete()`](#delete-artifact) | [artifact-delete.ts](examples/artifact-delete.ts) |
|
|
418
|
+
| Share Artifact | Share artifact/notebook with users or enable link sharing | [`sdk.artifacts.share()`](#share-artifact) | [artifact-share.ts](examples/artifact-share.ts) |
|
|
419
|
+
|
|
420
|
+
### `sdk.generation` - Generation & Chat
|
|
421
|
+
|
|
422
|
+
| Feature | Description | Method | Example |
|
|
423
|
+
|---------|-------------|--------|---------|
|
|
424
|
+
| Chat (Non-streaming) | Chat with notebook content - returns complete response | [`sdk.generation.chat(notebookId, prompt, options?)`](#chat) | [chat-basic.ts](examples/chat-basic.ts) |
|
|
425
|
+
| Chat Stream | Chat with real-time streaming response chunks | [`sdk.generation.chatStream(notebookId, prompt, options?)`](#chat-stream) | [chat-basic.ts](examples/chat-basic.ts) |
|
|
426
|
+
| Chat Conversation | Multi-turn conversations with history tracking | [`sdk.generation.chat(notebookId, prompt, { conversationHistory })`](#chat) | [chat-conversation.ts](examples/chat-conversation.ts) |
|
|
427
|
+
| Set Chat Config | Configure chat (custom prompt, learning guide, response length) | [`sdk.generation.setChatConfig(notebookId, config)`](#set-chat-configuration) | [generation-set-chat-config.ts](examples/generation-set-chat-config.ts) |
|
|
428
|
+
|
|
429
|
+
### `sdk.notes` - Notes Management
|
|
430
|
+
|
|
431
|
+
| Feature | Description | Method | Example |
|
|
432
|
+
|---------|-------------|--------|---------|
|
|
433
|
+
| List Notes | List all notes in a notebook | [`sdk.notes.list(notebookId)`](#list-notes) | [note-list.ts](examples/note-list.ts) |
|
|
434
|
+
| Create Note | Create a new note | [`sdk.notes.create(notebookId, options)`](#create-note) | [note-create.ts](examples/note-create.ts) |
|
|
435
|
+
| Update Note | Update a note | [`sdk.notes.update(notebookId, noteId, options)`](#update-note) | [note-update.ts](examples/note-update.ts) |
|
|
436
|
+
| Delete Note | Delete a note | [`sdk.notes.delete(notebookId, noteIds)`](#delete-note) | [note-delete.ts](examples/note-delete.ts) |
|
|
437
|
+
|
|
438
|
+
## Core Concepts
|
|
439
|
+
|
|
440
|
+
### SDK Initialization
|
|
441
|
+
|
|
442
|
+
**Methods:** `sdk.connect()` | `sdk.dispose()`
|
|
443
|
+
|
|
444
|
+
**Basic Usage:**
|
|
445
|
+
```typescript
|
|
446
|
+
import { NotebookLMClient } from 'notebooklm-kit';
|
|
447
|
+
import dotenv from 'dotenv';
|
|
448
|
+
|
|
449
|
+
dotenv.config(); // Load .env from project root
|
|
450
|
+
|
|
451
|
+
const sdk = new NotebookLMClient({
|
|
452
|
+
// Credentials loaded automatically from environment variables:
|
|
453
|
+
// NOTEBOOKLM_AUTH_TOKEN, NOTEBOOKLM_COOKIES
|
|
454
|
+
// or GOOGLE_EMAIL, GOOGLE_PASSWORD
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
try {
|
|
458
|
+
await sdk.connect(); // Initialize SDK, authenticate, start auto-refresh
|
|
459
|
+
|
|
460
|
+
// Now you can use sdk.notebooks, sdk.sources, etc.
|
|
461
|
+
const notebooks = await sdk.notebooks.list();
|
|
462
|
+
|
|
463
|
+
} finally {
|
|
464
|
+
sdk.dispose(); // Always cleanup
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**Explicit Credentials:**
|
|
469
|
+
```typescript
|
|
470
|
+
const sdk = new NotebookLMClient({
|
|
471
|
+
authToken: process.env.NOTEBOOKLM_AUTH_TOKEN!,
|
|
472
|
+
cookies: process.env.NOTEBOOKLM_COOKIES!,
|
|
473
|
+
// or
|
|
474
|
+
auth: {
|
|
475
|
+
email: process.env.GOOGLE_EMAIL!,
|
|
476
|
+
password: process.env.GOOGLE_PASSWORD!,
|
|
477
|
+
},
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
await sdk.connect();
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
**Enable Debug Mode:**
|
|
484
|
+
|
|
485
|
+
Debug mode provides detailed logging for troubleshooting, API calls, authentication, and internal operations.
|
|
486
|
+
|
|
487
|
+
**Option 1: Environment Variable (Recommended)**
|
|
488
|
+
```bash
|
|
489
|
+
# In your .env file
|
|
490
|
+
NOTEBOOKLM_DEBUG=true
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
**Option 2: Config Option**
|
|
494
|
+
```typescript
|
|
495
|
+
const sdk = new NotebookLMClient({
|
|
496
|
+
debug: true, // Enable debug logging
|
|
497
|
+
// ... other config
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
await sdk.connect();
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
**Option 3: Development Mode**
|
|
504
|
+
```bash
|
|
505
|
+
# Automatically enables debug in development
|
|
506
|
+
NODE_ENV=development
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
**What Debug Mode Logs:**
|
|
510
|
+
- ✅ RPC call details (method names, arguments, responses)
|
|
511
|
+
- ✅ Authentication flow (login steps, credential extraction)
|
|
512
|
+
- ✅ Auto-refresh operations (token refresh attempts, timing)
|
|
513
|
+
- ✅ Streaming responses (chunk processing, parsing)
|
|
514
|
+
- ✅ Error details (full stack traces, API responses)
|
|
515
|
+
- ✅ Response parsing (chunked data processing, validation)
|
|
516
|
+
|
|
517
|
+
**Example Debug Output:**
|
|
518
|
+
```
|
|
519
|
+
[DEBUG] RPC Call: wXbhsf with args: [null, 1, null, [2]]
|
|
520
|
+
[DEBUG] Response received: 200 OK
|
|
521
|
+
[DEBUG] Parsing chunked response: 3 chunks found
|
|
522
|
+
[DEBUG] Auto-refresh: Token expires in 5 minutes, refreshing now...
|
|
523
|
+
[DEBUG] Authentication: Extracting credentials from browser...
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
**Disable Debug:**
|
|
527
|
+
```typescript
|
|
528
|
+
// Explicitly disable (overrides environment variable)
|
|
529
|
+
const sdk = new NotebookLMClient({
|
|
530
|
+
debug: false,
|
|
531
|
+
});
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
```bash
|
|
535
|
+
# Or in .env
|
|
536
|
+
NOTEBOOKLM_DEBUG=false
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
<details>
|
|
540
|
+
<summary><strong>Connection Flow</strong></summary>
|
|
541
|
+
|
|
542
|
+
1. **Credentials Resolution** (in priority order):
|
|
543
|
+
- Provided in config (`authToken`/`cookies`)
|
|
544
|
+
- Environment variables (`NOTEBOOKLM_AUTH_TOKEN`/`NOTEBOOKLM_COOKIES`)
|
|
545
|
+
- Saved credentials (`credentials.json` in project root) - **reused automatically**
|
|
546
|
+
- Auto-login (if `auth.email`/`auth.password` provided) - **only if no saved credentials**
|
|
547
|
+
|
|
548
|
+
**Note:** Set `FORCE_REAUTH=true` in `.env` to force re-authentication and ignore saved credentials
|
|
549
|
+
|
|
550
|
+
2. **Initialization:**
|
|
551
|
+
- Creates RPC client with credentials
|
|
552
|
+
- Initializes all services (`notebooks`, `sources`, `artifacts`, etc.)
|
|
553
|
+
- Starts auto-refresh manager (if enabled)
|
|
554
|
+
|
|
555
|
+
3. **Auto-Refresh:**
|
|
556
|
+
- Begins automatically after `connect()`
|
|
557
|
+
- Runs in background, doesn't block operations
|
|
558
|
+
- Updates credentials and cookies automatically
|
|
559
|
+
|
|
560
|
+
</details>
|
|
561
|
+
|
|
562
|
+
<details>
|
|
563
|
+
<summary><strong>Cleanup</strong></summary>
|
|
564
|
+
|
|
565
|
+
**Always call `dispose()` when done:**
|
|
566
|
+
- Stops auto-refresh background timers
|
|
567
|
+
- Prevents memory leaks
|
|
568
|
+
- Resets client state
|
|
569
|
+
- Required for graceful shutdown
|
|
570
|
+
|
|
571
|
+
```typescript
|
|
572
|
+
try {
|
|
573
|
+
await sdk.connect();
|
|
574
|
+
// ... use SDK ...
|
|
575
|
+
} finally {
|
|
576
|
+
await sdk.dispose(); // Always cleanup
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
</details>
|
|
581
|
+
|
|
582
|
+
### Authentication Overview
|
|
583
|
+
|
|
584
|
+
Authentication is handled automatically when you call `sdk.connect()`. Credentials are resolved in this priority order:
|
|
585
|
+
|
|
586
|
+
1. Provided in config (`authToken`/`cookies`)
|
|
587
|
+
2. Environment variables (`NOTEBOOKLM_AUTH_TOKEN`/`NOTEBOOKLM_COOKIES`)
|
|
588
|
+
3. Saved credentials (`credentials.json` in project root)
|
|
589
|
+
4. Auto-login (if `auth.email`/`auth.password` provided)
|
|
590
|
+
|
|
591
|
+
See the [Authentication](#authentication) section for detailed setup instructions and all configuration options.
|
|
592
|
+
|
|
593
|
+
### Quota Limits
|
|
594
|
+
|
|
595
|
+
Reference: [Official Documentation](https://support.google.com/notebooklm/answer/16213268)
|
|
596
|
+
|
|
597
|
+
**Plan Types:** `standard` (default) | `plus` | `pro` | `ultra`
|
|
598
|
+
|
|
599
|
+
| Limit | Standard | Plus | Pro | Ultra |
|
|
600
|
+
|-------|----------|------|-----|-------|
|
|
601
|
+
| **Notebooks** | 100/user | 200/user | 500/user | 500/user |
|
|
602
|
+
| **Sources/Notebook** | 50 | 100 | 300 | 600 |
|
|
603
|
+
| **Words/Source** | 500,000 | 500,000 | 500,000 | 500,000 |
|
|
604
|
+
| **File Size** | 200MB | 200MB | 200MB | 200MB |
|
|
605
|
+
| **Chats/Day** | 50 | 200 | 500 | 5,000 |
|
|
606
|
+
| **Audio/Video/Day** | 3 | 6 | 20 | 200 |
|
|
607
|
+
| **Reports/Day** | 10 | 20 | 100 | 1,000 |
|
|
608
|
+
| **Deep Research/Month** | 10 | 90 | 600 | 6,000 |
|
|
609
|
+
| **Mind Maps** | Unlimited | Unlimited | Unlimited | Unlimited |
|
|
610
|
+
|
|
611
|
+
<details>
|
|
612
|
+
<summary><strong>Important Notes</strong></summary>
|
|
613
|
+
|
|
614
|
+
- **Daily quotas** reset after 24 hours
|
|
615
|
+
- **Monthly quotas** reset after 30 days
|
|
616
|
+
- **Word/File Limits:** NotebookLM rejects sources >500k words or >200MB. Copy-protected PDFs cannot be imported.
|
|
617
|
+
- **Server-Side Enforcement:** Data Tables, Infographics, Slides (limits vary)
|
|
618
|
+
- **Client-Side Validation:** Optional (`enforceQuotas: true`), disabled by default
|
|
619
|
+
- **Plan Selection:** Set during SDK initialization: `plan: 'pro'`
|
|
620
|
+
|
|
621
|
+
</details>
|
|
622
|
+
|
|
623
|
+
## Authentication
|
|
624
|
+
|
|
625
|
+
### Auto-Login (Recommended)
|
|
626
|
+
|
|
627
|
+
**Method:** Use `auth` config with email/password
|
|
628
|
+
|
|
629
|
+
```typescript
|
|
630
|
+
const sdk = new NotebookLMClient({
|
|
631
|
+
auth: {
|
|
632
|
+
email: process.env.GOOGLE_EMAIL,
|
|
633
|
+
password: process.env.GOOGLE_PASSWORD,
|
|
634
|
+
headless: true, // default: true
|
|
635
|
+
},
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
await sdk.connect(); // Logs in, extracts auth token, prompts for cookies, saves to credentials.json
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
<details>
|
|
642
|
+
<summary><strong>Environment Variables (.env file)</strong></summary>
|
|
643
|
+
|
|
644
|
+
**File Location:** Create `.env` in your **project root** directory (same directory as `package.json`).
|
|
645
|
+
|
|
646
|
+
```bash
|
|
647
|
+
# .env file location: /path/to/your-project/.env
|
|
648
|
+
|
|
649
|
+
# Option 1: Auto-login with email/password (recommended - requires no 2FA)
|
|
650
|
+
GOOGLE_EMAIL="your-email@gmail.com"
|
|
651
|
+
GOOGLE_PASSWORD="your-password"
|
|
652
|
+
|
|
653
|
+
# Option 2: Manual credentials (for production or when auto-login isn't available)
|
|
654
|
+
NOTEBOOKLM_AUTH_TOKEN="ACi2F2NZSD7yrNvFMrCkP3vZJY1R:1766720233448"
|
|
655
|
+
NOTEBOOKLM_COOKIES="_ga=GA1.1.1949425436.1764104083; SID=g.a0005AiwX...; ..."
|
|
656
|
+
|
|
657
|
+
# Optional: Retry configuration
|
|
658
|
+
NOTEBOOKLM_MAX_RETRIES=1 # Default: 1
|
|
659
|
+
NOTEBOOKLM_RETRY_DELAY=1000 # Default: 1000ms
|
|
660
|
+
NOTEBOOKLM_RETRY_MAX_DELAY=5000 # Default: 5000ms
|
|
661
|
+
|
|
662
|
+
# Optional: Debug mode (enables detailed logging)
|
|
663
|
+
NOTEBOOKLM_DEBUG=true # Enable debug logging for troubleshooting
|
|
664
|
+
|
|
665
|
+
# Optional: Force re-authentication (ignore saved credentials)
|
|
666
|
+
FORCE_REAUTH=true
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
**Important:**
|
|
670
|
+
- `.env` file must be in the **project root** (not in subdirectories)
|
|
671
|
+
- Account must NOT have 2FA enabled (or use app-specific passwords)
|
|
672
|
+
- The `.env` file is automatically ignored by git (see `.gitignore`)
|
|
673
|
+
|
|
674
|
+
</details>
|
|
675
|
+
|
|
676
|
+
### Manual Credentials
|
|
677
|
+
|
|
678
|
+
**Method:** Provide `authToken` and `cookies` directly
|
|
679
|
+
|
|
680
|
+
```typescript
|
|
681
|
+
const sdk = new NotebookLMClient({
|
|
682
|
+
authToken: process.env.NOTEBOOKLM_AUTH_TOKEN!,
|
|
683
|
+
cookies: process.env.NOTEBOOKLM_COOKIES!,
|
|
684
|
+
enforceQuotas: true, // optional
|
|
685
|
+
plan: 'standard', // optional: 'standard' | 'plus' | 'pro' | 'ultra'
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
await sdk.connect();
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
<details>
|
|
692
|
+
<summary><strong>Getting Credentials</strong></summary>
|
|
693
|
+
|
|
694
|
+
1. **Auth Token**: Open https://notebooklm.google.com → DevTools (F12) → Console → Run: `window.WIZ_global_data.SNlM0e`
|
|
695
|
+
2. **Cookies**: DevTools → Network tab → Any request → Headers → Copy Cookie value
|
|
696
|
+
|
|
697
|
+
</details>
|
|
698
|
+
|
|
699
|
+
### Saved Credentials
|
|
700
|
+
|
|
701
|
+
**Location:** `credentials.json` in project root (e.g., `notebooklm-kit/credentials.json`)
|
|
702
|
+
|
|
703
|
+
When using auto-login with email/password:
|
|
704
|
+
1. Browser opens and authenticates
|
|
705
|
+
2. Auth token is extracted automatically
|
|
706
|
+
3. You're prompted to manually paste cookies
|
|
707
|
+
4. Credentials are saved to `credentials.json` for future use
|
|
708
|
+
|
|
709
|
+
**Subsequent runs:**
|
|
710
|
+
- Saved credentials are automatically reused (no browser prompt)
|
|
711
|
+
- Faster startup - no need to re-enter cookies
|
|
712
|
+
- Credentials file is in project root for easy viewing/editing
|
|
713
|
+
|
|
714
|
+
**To force re-authentication:**
|
|
715
|
+
- Set `FORCE_REAUTH=true` in `.env`, or
|
|
716
|
+
- Delete `credentials.json` file
|
|
717
|
+
|
|
718
|
+
**Security Note:** `credentials.json` contains sensitive authentication data. It's automatically added to `.gitignore` to prevent accidental commits.
|
|
719
|
+
|
|
720
|
+
### Auto-Refresh Configuration
|
|
721
|
+
|
|
722
|
+
**Default:** Enabled with `'auto'` strategy (recommended)
|
|
723
|
+
|
|
724
|
+
```typescriptimproved
|
|
725
|
+
// Default: auto strategy (expiration-based + time-based fallback)
|
|
726
|
+
const sdk = new NotebookLMClient({
|
|
727
|
+
auth: { email: '...', password: '...' },
|
|
728
|
+
// autoRefresh: true (default)
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
// Time-based (simple, predictable)
|
|
732
|
+
autoRefresh: { strategy: 'time', interval: 10 * 60 * 1000 }
|
|
733
|
+
|
|
734
|
+
// Expiration-based (maximum efficiency)
|
|
735
|
+
autoRefresh: { strategy: 'expiration', refreshAhead: 5 * 60 * 1000 }
|
|
736
|
+
|
|
737
|
+
// Disable
|
|
738
|
+
autoRefresh: false
|
|
739
|
+
|
|
740
|
+
// Manual refresh
|
|
741
|
+
await sdk.refreshCredentials();
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
<details>
|
|
745
|
+
<summary><strong>Auto-Refresh Details</strong></summary>
|
|
746
|
+
|
|
747
|
+
- Credentials updated automatically after refresh
|
|
748
|
+
- Cookies kept in sync
|
|
749
|
+
- Runs in background, doesn't block operations
|
|
750
|
+
- See [Auto-Refresh Strategies](#auto-refresh-strategies) in Core Concepts
|
|
751
|
+
|
|
752
|
+
</details>
|
|
753
|
+
|
|
754
|
+
### Quota Management
|
|
755
|
+
|
|
756
|
+
**Method:** `sdk.getUsage()` | `sdk.getRemaining()` | `sdk.getQuotaManager()`
|
|
757
|
+
|
|
758
|
+
```typescript
|
|
759
|
+
const sdk = new NotebookLMClient({
|
|
760
|
+
auth: { email: '...', password: '...' },
|
|
761
|
+
enforceQuotas: true, // Enable client-side validation (disabled by default)
|
|
762
|
+
plan: 'pro', // Set plan for accurate limits
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
await sdk.connect();
|
|
766
|
+
|
|
767
|
+
// Check usage
|
|
768
|
+
const usage = sdk.getUsage();
|
|
769
|
+
const remaining = sdk.getRemaining('chats');
|
|
770
|
+
const limits = sdk.getQuotaManager().getLimits();
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
<details>
|
|
774
|
+
<summary><strong>Quota Notes</strong></summary>
|
|
775
|
+
|
|
776
|
+
- **Disabled by default** - enable with `enforceQuotas: true`
|
|
777
|
+
- Throws `RateLimitError` if limit exceeded (when enabled)
|
|
778
|
+
- Server-side enforcement always active (even if client-side disabled)
|
|
779
|
+
- See [Quota Limits](#quota-limits) table in Core Concepts
|
|
780
|
+
|
|
781
|
+
</details>
|
|
782
|
+
|
|
783
|
+
## Notebooks
|
|
784
|
+
|
|
785
|
+
Examples: [notebook-list.ts](examples/notebook-list.ts) | [notebook-get.ts](examples/notebook-get.ts) | [notebook-create.ts](examples/notebook-create.ts) | [notebook-update.ts](examples/notebook-update.ts) | [notebook-delete.ts](examples/notebook-delete.ts) | [notebook-share.ts](examples/notebook-share.ts)
|
|
786
|
+
|
|
787
|
+
### List Notebooks
|
|
788
|
+
|
|
789
|
+
**Method:** `sdk.notebooks.list()`
|
|
790
|
+
|
|
791
|
+
**Example:** [notebook-list.ts](examples/notebook-list.ts)
|
|
792
|
+
|
|
793
|
+
**Returns:** `Promise<Notebook[]>`
|
|
794
|
+
|
|
795
|
+
**Description:**
|
|
796
|
+
Lists all your notebooks (recently viewed). Returns a lightweight array of notebooks with essential information for display/selection.
|
|
797
|
+
|
|
798
|
+
**Return Fields:**
|
|
799
|
+
- `projectId: string` - Unique notebook ID (required for other operations)
|
|
800
|
+
- `title: string` - Notebook title
|
|
801
|
+
- `emoji: string` - Visual identifier
|
|
802
|
+
- `sourceCount: number` - Number of sources in the notebook
|
|
803
|
+
|
|
804
|
+
<details>
|
|
805
|
+
<summary><strong>Notes</strong></summary>
|
|
806
|
+
|
|
807
|
+
- Automatically filters out system notebooks (e.g., "OpenStax's Biology")
|
|
808
|
+
- Returns only notebooks you've recently viewed
|
|
809
|
+
- Does not include full notebook details (use `get()` for that)
|
|
810
|
+
- Does not include sources array (use `sources` service for source operations)
|
|
811
|
+
- Does not include sharing info (use `get()` for sharing details)
|
|
812
|
+
|
|
813
|
+
</details>
|
|
814
|
+
|
|
815
|
+
**Usage:**
|
|
816
|
+
```typescript
|
|
817
|
+
const notebooks = await sdk.notebooks.list()
|
|
818
|
+
console.log(`Found ${notebooks.length} notebooks`)
|
|
819
|
+
notebooks.forEach(nb => {
|
|
820
|
+
console.log(`${nb.emoji} ${nb.title} (${nb.sourceCount} sources)`)
|
|
821
|
+
})
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
---
|
|
825
|
+
|
|
826
|
+
### Get Notebook
|
|
827
|
+
|
|
828
|
+
**Method:** `sdk.notebooks.get(notebookId)`
|
|
829
|
+
|
|
830
|
+
**Example:** [notebook-get.ts](examples/notebook-get.ts)
|
|
831
|
+
|
|
832
|
+
**Parameters:**
|
|
833
|
+
- `notebookId: string` - The notebook ID (required)
|
|
834
|
+
|
|
835
|
+
**Returns:** `Promise<Notebook>`
|
|
836
|
+
|
|
837
|
+
**Description:**
|
|
838
|
+
Retrieves full details of a specific notebook, including analytics and sharing information. Makes parallel RPC calls to get complete notebook data.
|
|
839
|
+
|
|
840
|
+
**Return Fields:**
|
|
841
|
+
- `projectId: string` - Unique notebook ID
|
|
842
|
+
- `title: string` - Notebook title
|
|
843
|
+
- `emoji: string` - Visual identifier
|
|
844
|
+
- `sourceCount?: number` - Number of sources (analytics)
|
|
845
|
+
- `lastAccessed?: string` - Last accessed timestamp (ISO format, analytics)
|
|
846
|
+
- `sharing?: SharingSettings` - Sharing configuration:
|
|
847
|
+
- `isShared: boolean` - Whether notebook is shared
|
|
848
|
+
- `shareUrl?: string` - Share URL if shared
|
|
849
|
+
- `shareId?: string` - Share ID
|
|
850
|
+
- `publicAccess?: boolean` - Whether public access is enabled
|
|
851
|
+
- `allowedUsers?: string[]` - Array of user emails with access
|
|
852
|
+
|
|
853
|
+
<details>
|
|
854
|
+
<summary><strong>Notes</strong></summary>
|
|
855
|
+
|
|
856
|
+
- Validates notebook ID format before making RPC calls
|
|
857
|
+
- Calls both `RPC_GET_PROJECT` and `RPC_GET_SHARING_DETAILS` in parallel for efficiency
|
|
858
|
+
- Sharing data is optional - won't fail if unavailable
|
|
859
|
+
- Does not include sources array (use `sources` service for source operations)
|
|
860
|
+
- `lastAccessed` is extracted from notebook metadata if available
|
|
861
|
+
|
|
862
|
+
</details>
|
|
863
|
+
|
|
864
|
+
**Usage:**
|
|
865
|
+
```typescript
|
|
866
|
+
const notebook = await sdk.notebooks.get('notebook-id')
|
|
867
|
+
console.log(`Title: ${notebook.title}`)
|
|
868
|
+
console.log(`Sources: ${notebook.sourceCount || 0}`)
|
|
869
|
+
console.log(`Last accessed: ${notebook.lastAccessed || 'Never'}`)
|
|
870
|
+
if (notebook.sharing?.isShared) {
|
|
871
|
+
console.log(`Share URL: ${notebook.sharing.shareUrl}`)
|
|
872
|
+
}
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
---
|
|
876
|
+
|
|
877
|
+
### Create Notebook
|
|
878
|
+
|
|
879
|
+
**Method:** `sdk.notebooks.create(options)`
|
|
880
|
+
|
|
881
|
+
**Example:** [notebook-create.ts](examples/notebook-create.ts)
|
|
882
|
+
|
|
883
|
+
**Parameters:**
|
|
884
|
+
- `options: CreateNotebookOptions`
|
|
885
|
+
- `title: string` - Notebook title (optional, auto-generated if empty)
|
|
886
|
+
- `description?: string` - Initial description (optional)
|
|
887
|
+
- `emoji?: string` - Notebook emoji (optional)
|
|
888
|
+
|
|
889
|
+
**Returns:** `Promise<Notebook>`
|
|
890
|
+
|
|
891
|
+
**Description:**
|
|
892
|
+
Creates a new notebook. Automatically generates a title if not provided. Validates title length before creation.
|
|
893
|
+
|
|
894
|
+
**Return Fields:**
|
|
895
|
+
- `projectId: string` - Unique notebook ID (use this for subsequent operations)
|
|
896
|
+
- `title: string` - Notebook title (as provided or auto-generated)
|
|
897
|
+
- `emoji: string` - Default emoji
|
|
898
|
+
|
|
899
|
+
**Auto-Generated Title Format:**
|
|
900
|
+
If `title` is empty or not provided, generates: `"Untitled Notebook {current date}"`
|
|
901
|
+
Example: `"Untitled Notebook 12/30/2024"`
|
|
902
|
+
|
|
903
|
+
<details>
|
|
904
|
+
<summary><strong>Validation</strong></summary>
|
|
905
|
+
|
|
906
|
+
- Title maximum length: 100 characters
|
|
907
|
+
- Throws `APIError` if title exceeds limit
|
|
908
|
+
- Empty title is allowed (will be auto-generated)
|
|
909
|
+
|
|
910
|
+
</details>
|
|
911
|
+
|
|
912
|
+
<details>
|
|
913
|
+
<summary><strong>Notes</strong></summary>
|
|
914
|
+
|
|
915
|
+
- Quota is checked before creation (if quota manager is enabled)
|
|
916
|
+
- Usage is recorded after successful creation
|
|
917
|
+
- Returns immediately with notebook ID - no waiting required
|
|
918
|
+
- Does not include `sourceCount`, `lastAccessed`, or `sharing` (not available for new notebooks)
|
|
919
|
+
|
|
920
|
+
</details>
|
|
921
|
+
|
|
922
|
+
**Usage:**
|
|
923
|
+
```typescript
|
|
924
|
+
// With title
|
|
925
|
+
const notebook = await sdk.notebooks.create({
|
|
926
|
+
title: 'My Research Project',
|
|
927
|
+
})
|
|
928
|
+
|
|
929
|
+
// With title and emoji
|
|
930
|
+
const notebook = await sdk.notebooks.create({
|
|
931
|
+
title: 'My Research Project',
|
|
932
|
+
emoji: '📚',
|
|
933
|
+
})
|
|
934
|
+
|
|
935
|
+
// Auto-generated title
|
|
936
|
+
const untitled = await sdk.notebooks.create({})
|
|
937
|
+
|
|
938
|
+
// With description and emoji
|
|
939
|
+
const notebook = await sdk.notebooks.create({
|
|
940
|
+
title: 'Project Notes',
|
|
941
|
+
description: 'Initial project description',
|
|
942
|
+
emoji: '🔬',
|
|
943
|
+
})
|
|
944
|
+
```
|
|
945
|
+
|
|
946
|
+
---
|
|
947
|
+
|
|
948
|
+
### Update Notebook
|
|
949
|
+
|
|
950
|
+
**Method:** `sdk.notebooks.update(notebookId, options)`
|
|
951
|
+
|
|
952
|
+
**Example:** [notebook-update.ts](examples/notebook-update.ts)
|
|
953
|
+
|
|
954
|
+
**Parameters:**
|
|
955
|
+
- `notebookId: string` - The notebook ID (required, automatically trimmed)
|
|
956
|
+
- `options: UpdateNotebookOptions`
|
|
957
|
+
- `title?: string` - New title (optional)
|
|
958
|
+
- `emoji?: string` - New emoji (optional)
|
|
959
|
+
- `metadata?: Record<string, any>` - Other metadata updates (optional)
|
|
960
|
+
|
|
961
|
+
**Returns:** `Promise<Notebook>` (same as `get()` - full notebook details)
|
|
962
|
+
|
|
963
|
+
**Description:**
|
|
964
|
+
Updates notebook title, description, or emoji. Returns full notebook details after update (same structure as `get()`). Supports updating emoji only, title only, or both together.
|
|
965
|
+
|
|
966
|
+
<details>
|
|
967
|
+
<summary><strong>Validation</strong></summary>
|
|
968
|
+
|
|
969
|
+
- At least one field (`title`, `description`, or `emoji`) must be provided
|
|
970
|
+
- Title maximum length: 100 characters
|
|
971
|
+
- Notebook ID is automatically trimmed (removes trailing spaces)
|
|
972
|
+
- Returns error if notebook doesn't exist
|
|
973
|
+
|
|
974
|
+
</details>
|
|
975
|
+
|
|
976
|
+
**Return Fields:**
|
|
977
|
+
Same as `get()` - includes `projectId`, `title`, `emoji`, `sourceCount`, `lastAccessed`, `sharing`
|
|
978
|
+
|
|
979
|
+
<details>
|
|
980
|
+
<summary><strong>Notes</strong></summary>
|
|
981
|
+
|
|
982
|
+
- Notebook ID is trimmed automatically to prevent issues with trailing spaces
|
|
983
|
+
- Only provided fields are updated (partial updates supported)
|
|
984
|
+
- Returns full notebook object after update (not just updated fields)
|
|
985
|
+
- Does not validate notebook existence first (for performance) - returns error if not found
|
|
986
|
+
|
|
987
|
+
</details>
|
|
988
|
+
|
|
989
|
+
**Usage:**
|
|
990
|
+
```typescript
|
|
991
|
+
// Update title only
|
|
992
|
+
const updated = await sdk.notebooks.update('notebook-id', {
|
|
993
|
+
title: 'Updated Title',
|
|
994
|
+
})
|
|
995
|
+
|
|
996
|
+
// Update emoji only
|
|
997
|
+
const updated = await sdk.notebooks.update('notebook-id', {
|
|
998
|
+
emoji: '🔥',
|
|
999
|
+
})
|
|
1000
|
+
|
|
1001
|
+
// Update both title and emoji
|
|
1002
|
+
const updated = await sdk.notebooks.update('notebook-id', {
|
|
1003
|
+
title: 'New Title',
|
|
1004
|
+
emoji: '⭐',
|
|
1005
|
+
})
|
|
1006
|
+
|
|
1007
|
+
// Update all fields
|
|
1008
|
+
const updated = await sdk.notebooks.update('notebook-id', {
|
|
1009
|
+
title: 'New Title',
|
|
1010
|
+
emoji: '🎯',
|
|
1011
|
+
})
|
|
1012
|
+
```
|
|
1013
|
+
|
|
1014
|
+
---
|
|
1015
|
+
|
|
1016
|
+
### Delete Notebook
|
|
1017
|
+
|
|
1018
|
+
**Method:** `sdk.notebooks.delete(notebookIds)`
|
|
1019
|
+
|
|
1020
|
+
**Example:** [notebook-delete.ts](examples/notebook-delete.ts)
|
|
1021
|
+
|
|
1022
|
+
**Parameters:**
|
|
1023
|
+
- `notebookIds: string | string[]` - Single notebook ID or array of IDs (required)
|
|
1024
|
+
|
|
1025
|
+
**Returns:** `Promise<DeleteNotebookResult>`
|
|
1026
|
+
|
|
1027
|
+
**Description:**
|
|
1028
|
+
Deletes one or more notebooks. Returns confirmation with deleted IDs and count.
|
|
1029
|
+
|
|
1030
|
+
**Return Fields:**
|
|
1031
|
+
- `deleted: string[]` - Array of deleted notebook IDs
|
|
1032
|
+
- `count: number` - Number of notebooks deleted
|
|
1033
|
+
|
|
1034
|
+
<details>
|
|
1035
|
+
<summary><strong>Validation</strong></summary>
|
|
1036
|
+
|
|
1037
|
+
- All provided IDs are validated before deletion
|
|
1038
|
+
- Throws `APIError` if any ID is invalid
|
|
1039
|
+
- Supports both single ID and array of IDs
|
|
1040
|
+
|
|
1041
|
+
</details>
|
|
1042
|
+
|
|
1043
|
+
<details>
|
|
1044
|
+
<summary><strong>Notes</strong></summary>
|
|
1045
|
+
|
|
1046
|
+
- No confirmation required - deletion is immediate
|
|
1047
|
+
- Batch deletion is supported (pass array of IDs)
|
|
1048
|
+
- Returns validation/confirmation object (not void)
|
|
1049
|
+
- All IDs are validated before any deletion occurs
|
|
1050
|
+
|
|
1051
|
+
</details>
|
|
1052
|
+
|
|
1053
|
+
**Usage:**
|
|
1054
|
+
```typescript
|
|
1055
|
+
// Delete single notebook
|
|
1056
|
+
const result = await sdk.notebooks.delete('notebook-id')
|
|
1057
|
+
console.log(`Deleted ${result.count} notebook: ${result.deleted[0]}`)
|
|
1058
|
+
|
|
1059
|
+
// Delete multiple notebooks
|
|
1060
|
+
const result = await sdk.notebooks.delete(['id-1', 'id-2', 'id-3'])
|
|
1061
|
+
console.log(`Deleted ${result.count} notebooks: ${result.deleted.join(', ')}`)
|
|
1062
|
+
```
|
|
1063
|
+
|
|
1064
|
+
---
|
|
1065
|
+
|
|
1066
|
+
### Share Notebook
|
|
1067
|
+
|
|
1068
|
+
**Method:** `sdk.notebooks.share(notebookId, options)`
|
|
1069
|
+
|
|
1070
|
+
**Example:** [notebook-share.ts](examples/notebook-share.ts)
|
|
1071
|
+
|
|
1072
|
+
**Parameters:**
|
|
1073
|
+
- `notebookId: string` - The notebook ID (required, automatically trimmed)
|
|
1074
|
+
- `options: ShareNotebookOptions`
|
|
1075
|
+
- `users?: Array<{email: string, role: 2|3|4}>` - Users to share with (optional)
|
|
1076
|
+
- `notify?: boolean` - Notify users (default: true, only used when users are provided)
|
|
1077
|
+
- `accessType?: 1|2` - Access type: 1=anyone with link, 2=restricted (optional, default: 2)
|
|
1078
|
+
|
|
1079
|
+
**Returns:** `Promise<ShareNotebookResult>`
|
|
1080
|
+
|
|
1081
|
+
**Description:**
|
|
1082
|
+
Shares notebook with users or enables link sharing. Supports multiple users with different roles. Automatically fetches updated sharing state after operation.
|
|
1083
|
+
|
|
1084
|
+
**User Roles:**
|
|
1085
|
+
|
|
1086
|
+
| Role | Value | Description |
|
|
1087
|
+
|------|-------|-------------|
|
|
1088
|
+
| Editor | `2` | Can edit notebook content |
|
|
1089
|
+
| Viewer | `3` | Can view notebook only |
|
|
1090
|
+
| Remove | `4` | Remove user from shared list |
|
|
1091
|
+
|
|
1092
|
+
**Access Types:**
|
|
1093
|
+
|
|
1094
|
+
| Access Type | Value | Description |
|
|
1095
|
+
|-------------|-------|-------------|
|
|
1096
|
+
| Anyone with link | `1` | Public access via share link |
|
|
1097
|
+
| Restricted | `2` | Only specified users can access |
|
|
1098
|
+
|
|
1099
|
+
**Return Fields:**
|
|
1100
|
+
- `shareUrl: string` - Share URL (always present, even if not shared)
|
|
1101
|
+
- `success: boolean` - Whether the share operation succeeded
|
|
1102
|
+
- `notebookId: string` - The notebook ID that was shared
|
|
1103
|
+
- `accessType: 1|2` - Access type: 1=anyone with link, 2=restricted
|
|
1104
|
+
- `isShared: boolean` - Whether the notebook is shared (true if shared with users or link enabled)
|
|
1105
|
+
- `users?: Array<{email: string, role: 2|3}>` - Users with access (only present if users were shared)
|
|
1106
|
+
|
|
1107
|
+
**Notify Behavior:**
|
|
1108
|
+
- `notify` is only used when `users` are provided
|
|
1109
|
+
- Default: `true` (users are notified when permissions change)
|
|
1110
|
+
- Set to `false` to share silently
|
|
1111
|
+
- Not used when only changing link access (no user changes)
|
|
1112
|
+
|
|
1113
|
+
<details>
|
|
1114
|
+
<summary><strong>Validation</strong></summary>
|
|
1115
|
+
|
|
1116
|
+
- Email addresses are validated using regex before sharing
|
|
1117
|
+
- Throws `APIError` if any email is invalid
|
|
1118
|
+
- Supports multiple users in a single call
|
|
1119
|
+
|
|
1120
|
+
</details>
|
|
1121
|
+
|
|
1122
|
+
<details>
|
|
1123
|
+
<summary><strong>Notes</strong></summary>
|
|
1124
|
+
- Notebook ID is automatically trimmed
|
|
1125
|
+
- Makes prerequisite `JFMDGd` call before sharing (to initialize sharing state)
|
|
1126
|
+
- After successful share, makes another `JFMDGd` call to fetch updated state
|
|
1127
|
+
- `shareUrl` is always returned (constructed from notebook ID if not explicitly shared)
|
|
1128
|
+
- Supports sharing with multiple users in a single operation
|
|
1129
|
+
- Can combine user sharing with link access in one call
|
|
1130
|
+
|
|
1131
|
+
</details>
|
|
1132
|
+
|
|
1133
|
+
**Usage:**
|
|
1134
|
+
```typescript
|
|
1135
|
+
// Share with users (restricted access, notify enabled by default)
|
|
1136
|
+
const result = await sdk.notebooks.share('notebook-id', {
|
|
1137
|
+
users: [
|
|
1138
|
+
{ email: 'user1@example.com', role: 2 }, // editor
|
|
1139
|
+
{ email: 'user2@example.com', role: 3 }, // viewer
|
|
1140
|
+
],
|
|
1141
|
+
notify: true,
|
|
1142
|
+
accessType: 2, // restricted
|
|
1143
|
+
})
|
|
1144
|
+
|
|
1145
|
+
// Share with users (silent, no notification)
|
|
1146
|
+
const result = await sdk.notebooks.share('notebook-id', {
|
|
1147
|
+
users: [
|
|
1148
|
+
{ email: 'user@example.com', role: 2 },
|
|
1149
|
+
],
|
|
1150
|
+
notify: false,
|
|
1151
|
+
accessType: 2,
|
|
1152
|
+
})
|
|
1153
|
+
|
|
1154
|
+
// Enable link sharing (anyone with link)
|
|
1155
|
+
const result = await sdk.notebooks.share('notebook-id', {
|
|
1156
|
+
accessType: 1, // 1=anyone with link, 2=restricted
|
|
1157
|
+
})
|
|
1158
|
+
|
|
1159
|
+
// Remove user (role: 4)
|
|
1160
|
+
const result = await sdk.notebooks.share('notebook-id', {
|
|
1161
|
+
users: [
|
|
1162
|
+
{ email: 'user@example.com', role: 4 }, // remove
|
|
1163
|
+
],
|
|
1164
|
+
accessType: 2,
|
|
1165
|
+
})
|
|
1166
|
+
```
|
|
1167
|
+
|
|
1168
|
+
<details>
|
|
1169
|
+
<summary><b>Sources</b> - Add & manage sources</summary>
|
|
1170
|
+
|
|
1171
|
+
### Methods
|
|
1172
|
+
|
|
1173
|
+
#### `addFromURL(notebookId: string, options: AddURLSourceOptions)` → `Promise<string>`
|
|
1174
|
+
Add a source from a URL (web page, YouTube, etc.).
|
|
1175
|
+
|
|
1176
|
+
**Parameters:**
|
|
1177
|
+
- `notebookId: string` - The notebook ID
|
|
1178
|
+
- `options.url: string` - URL to add
|
|
1179
|
+
|
|
1180
|
+
**Returns:**
|
|
1181
|
+
- `string` - Source ID
|
|
1182
|
+
|
|
1183
|
+
**Example:**
|
|
1184
|
+
```typescript
|
|
1185
|
+
const sourceId = await sdk.sources.addFromURL('notebook-id', {
|
|
1186
|
+
url: 'https://example.com/article',
|
|
1187
|
+
})
|
|
1188
|
+
```
|
|
1189
|
+
|
|
1190
|
+
---
|
|
1191
|
+
|
|
1192
|
+
#### `addFromText(notebookId: string, options: AddTextSourceOptions)` → `Promise<string>`
|
|
1193
|
+
Add a source from text content.
|
|
1194
|
+
|
|
1195
|
+
**Parameters:**
|
|
1196
|
+
- `notebookId: string` - The notebook ID
|
|
1197
|
+
- `options.title: string` - Source title
|
|
1198
|
+
- `options.content: string` - Text content
|
|
1199
|
+
|
|
1200
|
+
**Returns:**
|
|
1201
|
+
- `string` - Source ID
|
|
1202
|
+
|
|
1203
|
+
**Example:**
|
|
1204
|
+
```typescript
|
|
1205
|
+
const sourceId = await sdk.sources.addFromText('notebook-id', {
|
|
1206
|
+
title: 'Research Notes',
|
|
1207
|
+
content: 'Your text content here...',
|
|
1208
|
+
})
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
---
|
|
1212
|
+
|
|
1213
|
+
#### `addFromFile(notebookId: string, options: AddFileSourceOptions)` → `Promise<string>`
|
|
1214
|
+
Add a source from a file (PDF, image, etc.).
|
|
1215
|
+
|
|
1216
|
+
**Parameters:**
|
|
1217
|
+
- `notebookId: string` - The notebook ID
|
|
1218
|
+
- `options.content: Buffer` - File content as Buffer
|
|
1219
|
+
- `options.fileName: string` - File name
|
|
1220
|
+
- `options.mimeType: string` - MIME type (e.g., 'application/pdf')
|
|
1221
|
+
|
|
1222
|
+
**Returns:**
|
|
1223
|
+
- `string` - Source ID
|
|
1224
|
+
|
|
1225
|
+
**Example:**
|
|
1226
|
+
```typescript
|
|
1227
|
+
import { readFile } from 'fs/promises'
|
|
1228
|
+
|
|
1229
|
+
const buffer = await readFile('./document.pdf')
|
|
1230
|
+
const sourceId = await sdk.sources.addFromFile('notebook-id', {
|
|
1231
|
+
content: buffer,
|
|
1232
|
+
fileName: 'document.pdf',
|
|
1233
|
+
mimeType: 'application/pdf',
|
|
1234
|
+
})
|
|
1235
|
+
```
|
|
1236
|
+
|
|
1237
|
+
---
|
|
1238
|
+
|
|
1239
|
+
#### `addYouTube(notebookId: string, options: AddYouTubeSourceOptions)` → `Promise<string>`
|
|
1240
|
+
Add a YouTube video as a source.
|
|
1241
|
+
|
|
1242
|
+
**Parameters:**
|
|
1243
|
+
- `notebookId: string` - The notebook ID
|
|
1244
|
+
- `options.urlOrId: string` - YouTube URL or video ID
|
|
1245
|
+
|
|
1246
|
+
**Returns:**
|
|
1247
|
+
- `string` - Source ID
|
|
1248
|
+
|
|
1249
|
+
**Example:**
|
|
1250
|
+
```typescript
|
|
1251
|
+
const sourceId = await sdk.sources.addYouTube('notebook-id', {
|
|
1252
|
+
urlOrId: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
|
1253
|
+
})
|
|
1254
|
+
```
|
|
1255
|
+
|
|
1256
|
+
---
|
|
1257
|
+
|
|
1258
|
+
#### `searchWebAndWait(notebookId: string, options: SearchWebOptions)` → `Promise<SearchWebResult>`
|
|
1259
|
+
Search the web or Google Drive and wait for results.
|
|
1260
|
+
|
|
1261
|
+
**Parameters:**
|
|
1262
|
+
- `notebookId: string` - The notebook ID
|
|
1263
|
+
- `options.query: string` - Search query
|
|
1264
|
+
- `options.sourceType: SearchSourceType` - WEB or GOOGLE_DRIVE
|
|
1265
|
+
- `options.mode: ResearchMode` - STANDARD or DEEP
|
|
1266
|
+
|
|
1267
|
+
**Returns:**
|
|
1268
|
+
- `SearchWebResult` - Object with:
|
|
1269
|
+
- `sessionId: string` - Session ID for adding sources
|
|
1270
|
+
- `sources: Array<{sourceId: string, title: string, ...}>` - Found sources
|
|
1271
|
+
|
|
1272
|
+
**Example:**
|
|
1273
|
+
```typescript
|
|
1274
|
+
import { SearchSourceType, ResearchMode } from 'notebooklm-kit'
|
|
1275
|
+
|
|
1276
|
+
const result = await sdk.sources.searchWebAndWait('notebook-id', {
|
|
1277
|
+
query: 'machine learning trends 2024',
|
|
1278
|
+
sourceType: SearchSourceType.WEB,
|
|
1279
|
+
mode: ResearchMode.STANDARD,
|
|
1280
|
+
})
|
|
1281
|
+
|
|
1282
|
+
// Add selected sources
|
|
1283
|
+
const sourceIds = await sdk.sources.addDiscovered('notebook-id', {
|
|
1284
|
+
sessionId: result.sessionId,
|
|
1285
|
+
sourceIds: result.sources.slice(0, 5).map(s => s.sourceId),
|
|
1286
|
+
})
|
|
1287
|
+
```
|
|
1288
|
+
|
|
1289
|
+
---
|
|
1290
|
+
|
|
1291
|
+
#### `pollProcessing(notebookId: string)` → `Promise<SourceProcessingStatus>`
|
|
1292
|
+
Check source processing status.
|
|
1293
|
+
|
|
1294
|
+
**Parameters:**
|
|
1295
|
+
- `notebookId: string` - The notebook ID
|
|
1296
|
+
|
|
1297
|
+
**Returns:**
|
|
1298
|
+
- `SourceProcessingStatus` - Object with:
|
|
1299
|
+
- `readyCount: number` - Number of ready sources
|
|
1300
|
+
- `totalCount: number` - Total sources
|
|
1301
|
+
- `processingCount: number` - Sources being processed
|
|
1302
|
+
- `failedCount: number` - Failed sources
|
|
1303
|
+
- `allReady: boolean` - Whether all sources are ready
|
|
1304
|
+
|
|
1305
|
+
**Example:**
|
|
1306
|
+
```typescript
|
|
1307
|
+
const status = await sdk.sources.pollProcessing('notebook-id')
|
|
1308
|
+
console.log(`Ready: ${status.readyCount}/${status.totalCount}`)
|
|
1309
|
+
```
|
|
1310
|
+
|
|
1311
|
+
</details>
|
|
1312
|
+
|
|
1313
|
+
## Sources
|
|
1314
|
+
|
|
1315
|
+
Examples: [source-list.ts](examples/source-list.ts) | [source-get.ts](examples/source-get.ts) | [source-add-url.ts](examples/source-add-url.ts) | [source-add-text.ts](examples/source-add-text.ts) | [source-add-file.ts](examples/source-add-file.ts) | [source-add-youtube.ts](examples/source-add-youtube.ts) | [source-add-drive.ts](examples/source-add-drive.ts) | [source-add-batch.ts](examples/source-add-batch.ts) | [source-web-search.ts](examples/source-web-search.ts) | [source-web-search-advanced.ts](examples/source-web-search-advanced.ts) | [source-update.ts](examples/source-update.ts) | [source-delete.ts](examples/source-delete.ts) | [source-status.ts](examples/source-status.ts)
|
|
1316
|
+
|
|
1317
|
+
### List Sources
|
|
1318
|
+
|
|
1319
|
+
**Method:** `sdk.sources.list(notebookId)`
|
|
1320
|
+
|
|
1321
|
+
**Example:** [source-list.ts](examples/source-list.ts)
|
|
1322
|
+
|
|
1323
|
+
**Parameters:**
|
|
1324
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1325
|
+
|
|
1326
|
+
**Returns:** `Promise<Source[]>`
|
|
1327
|
+
|
|
1328
|
+
**Description:**
|
|
1329
|
+
Retrieves a list of all sources (URLs, text, files, YouTube videos, Google Drive files, etc.) associated with a notebook. Sources are extracted from the notebook response efficiently without requiring a separate RPC call.
|
|
1330
|
+
|
|
1331
|
+
**Return Fields:**
|
|
1332
|
+
- `sourceId: string` - Unique identifier for the source
|
|
1333
|
+
- `title?: string` - Source title/name
|
|
1334
|
+
- `type?: SourceType` - Source type (URL, TEXT, PDF, YOUTUBE_VIDEO, GOOGLE_DRIVE, IMAGE, etc.)
|
|
1335
|
+
- `url?: string` - Source URL (for URL/YouTube sources)
|
|
1336
|
+
- `createdAt?: string` - Creation timestamp (ISO format)
|
|
1337
|
+
- `updatedAt?: string` - Last modified timestamp (ISO format)
|
|
1338
|
+
- `status?: SourceStatus` - Processing status (`PROCESSING`, `READY`, `FAILED`)
|
|
1339
|
+
- `metadata?: Record<string, any>` - Additional metadata (file size, MIME type, etc.)
|
|
1340
|
+
|
|
1341
|
+
**Source Types:**
|
|
1342
|
+
- `URL` - Web page URL
|
|
1343
|
+
- `TEXT` - Text content
|
|
1344
|
+
- `PDF` - PDF file
|
|
1345
|
+
- `YOUTUBE_VIDEO` - YouTube video
|
|
1346
|
+
- `GOOGLE_DRIVE` - Google Drive file
|
|
1347
|
+
- `IMAGE` - Image file
|
|
1348
|
+
- `VIDEO_FILE` - Video file upload
|
|
1349
|
+
- `PDF_FROM_DRIVE` - PDF from Google Drive
|
|
1350
|
+
- `TEXT_NOTE` - Text note
|
|
1351
|
+
- `MIND_MAP_NOTE` - Mind map note
|
|
1352
|
+
|
|
1353
|
+
<details>
|
|
1354
|
+
<summary><strong>Notes</strong></summary>
|
|
1355
|
+
|
|
1356
|
+
- Sources are extracted from the notebook response (same RPC as `notebooks.get()`)
|
|
1357
|
+
- Processing status is inferred from source metadata
|
|
1358
|
+
- Returns empty array if notebook has no sources
|
|
1359
|
+
- File size and MIME type are included in metadata when available
|
|
1360
|
+
|
|
1361
|
+
</details>
|
|
1362
|
+
|
|
1363
|
+
**Usage:**
|
|
1364
|
+
```typescript
|
|
1365
|
+
// List all sources
|
|
1366
|
+
const sources = await sdk.sources.list('notebook-id')
|
|
1367
|
+
console.log(`Found ${sources.length} sources`)
|
|
1368
|
+
|
|
1369
|
+
// Filter by type
|
|
1370
|
+
const pdfs = sources.filter(s => s.type === SourceType.PDF)
|
|
1371
|
+
const urls = sources.filter(s => s.type === SourceType.URL)
|
|
1372
|
+
|
|
1373
|
+
// Check processing status
|
|
1374
|
+
const ready = sources.filter(s => s.status === SourceStatus.READY)
|
|
1375
|
+
const processing = sources.filter(s => s.status === SourceStatus.PROCESSING)
|
|
1376
|
+
```
|
|
1377
|
+
|
|
1378
|
+
---
|
|
1379
|
+
|
|
1380
|
+
### Get Source
|
|
1381
|
+
|
|
1382
|
+
**Method:** `sdk.sources.get(notebookId, sourceId?)`
|
|
1383
|
+
|
|
1384
|
+
**Example:** [source-get.ts](examples/source-get.ts)
|
|
1385
|
+
|
|
1386
|
+
**Parameters:**
|
|
1387
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1388
|
+
- `sourceId?: string` - Optional source ID to get a single source
|
|
1389
|
+
|
|
1390
|
+
**Returns:** `Promise<Source | Source[]>` - Single source if `sourceId` provided, array of all sources if omitted
|
|
1391
|
+
|
|
1392
|
+
**Description:**
|
|
1393
|
+
Get one or all sources from a notebook. If `sourceId` is provided, returns a single source. If omitted, returns all sources (same as `list()`).
|
|
1394
|
+
|
|
1395
|
+
**Return Fields:**
|
|
1396
|
+
Same as `list()` - see [List Sources](#list-sources) for field descriptions.
|
|
1397
|
+
|
|
1398
|
+
<details>
|
|
1399
|
+
<summary><strong>Notes</strong></summary>
|
|
1400
|
+
|
|
1401
|
+
- Returns array if `sourceId` is omitted (same as `list()`)
|
|
1402
|
+
- Returns single source object if `sourceId` is provided
|
|
1403
|
+
- Throws error if source not found when `sourceId` is provided
|
|
1404
|
+
- Efficiently reuses notebook data (no separate RPC call)
|
|
1405
|
+
|
|
1406
|
+
</details>
|
|
1407
|
+
|
|
1408
|
+
**Usage:**
|
|
1409
|
+
```typescript
|
|
1410
|
+
// Get all sources
|
|
1411
|
+
const allSources = await sdk.sources.get('notebook-id')
|
|
1412
|
+
|
|
1413
|
+
// Get specific source
|
|
1414
|
+
const source = await sdk.sources.get('notebook-id', 'source-id')
|
|
1415
|
+
console.log(source.title)
|
|
1416
|
+
```
|
|
1417
|
+
|
|
1418
|
+
---
|
|
1419
|
+
|
|
1420
|
+
### Add URL Source
|
|
1421
|
+
|
|
1422
|
+
**Method:** `sdk.sources.add.url(notebookId, options)`
|
|
1423
|
+
|
|
1424
|
+
**Example:** [source-add-url.ts](examples/source-add-url.ts)
|
|
1425
|
+
|
|
1426
|
+
**Parameters:**
|
|
1427
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1428
|
+
- `options: AddSourceFromURLOptions`
|
|
1429
|
+
- `url: string` - URL to add (required)
|
|
1430
|
+
- `title?: string` - Optional custom title
|
|
1431
|
+
|
|
1432
|
+
**Returns:** `Promise<string>` - Source ID
|
|
1433
|
+
|
|
1434
|
+
**Description:**
|
|
1435
|
+
Adds a web page URL as a source. Returns immediately after source is queued. Use `status()` to check if source is ready.
|
|
1436
|
+
|
|
1437
|
+
<details>
|
|
1438
|
+
<summary><strong>Notes</strong></summary>
|
|
1439
|
+
|
|
1440
|
+
- Returns immediately after source is queued (does not wait for processing)
|
|
1441
|
+
- Quota is checked before adding
|
|
1442
|
+
- Use `status()` to check if source is ready
|
|
1443
|
+
- URL must be a valid HTTP/HTTPS URL
|
|
1444
|
+
|
|
1445
|
+
</details>
|
|
1446
|
+
|
|
1447
|
+
**Usage:**
|
|
1448
|
+
```typescript
|
|
1449
|
+
const sourceId = await sdk.sources.add.url('notebook-id', {
|
|
1450
|
+
url: 'https://ai.google.dev/',
|
|
1451
|
+
title: 'Google AI Developer',
|
|
1452
|
+
})
|
|
1453
|
+
|
|
1454
|
+
// Check if ready
|
|
1455
|
+
const status = await sdk.sources.status('notebook-id')
|
|
1456
|
+
if (!status.processing.includes(sourceId)) {
|
|
1457
|
+
console.log('Source is ready!')
|
|
1458
|
+
}
|
|
1459
|
+
```
|
|
1460
|
+
|
|
1461
|
+
---
|
|
1462
|
+
|
|
1463
|
+
### Add Text Source
|
|
1464
|
+
|
|
1465
|
+
**Method:** `sdk.sources.add.text(notebookId, options)`
|
|
1466
|
+
|
|
1467
|
+
**Example:** [source-add-text.ts](examples/source-add-text.ts)
|
|
1468
|
+
|
|
1469
|
+
**Parameters:**
|
|
1470
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1471
|
+
- `options: AddSourceFromTextOptions`
|
|
1472
|
+
- `content: string` - Text content (required)
|
|
1473
|
+
- `title: string` - Source title (required)
|
|
1474
|
+
|
|
1475
|
+
**Returns:** `Promise<string>` - Source ID
|
|
1476
|
+
|
|
1477
|
+
**Description:**
|
|
1478
|
+
Adds text content as a source. Useful for adding notes, research summaries, or any text-based content.
|
|
1479
|
+
|
|
1480
|
+
**Usage:**
|
|
1481
|
+
```typescript
|
|
1482
|
+
const sourceId = await sdk.sources.add.text('notebook-id', {
|
|
1483
|
+
title: 'Research Notes',
|
|
1484
|
+
content: 'Key findings from research...',
|
|
1485
|
+
})
|
|
1486
|
+
```
|
|
1487
|
+
|
|
1488
|
+
---
|
|
1489
|
+
|
|
1490
|
+
### Add File Source
|
|
1491
|
+
|
|
1492
|
+
**Method:** `sdk.sources.add.file(notebookId, options)`
|
|
1493
|
+
|
|
1494
|
+
**Parameters:**
|
|
1495
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1496
|
+
- `options: AddSourceFromFileOptions`
|
|
1497
|
+
- `content: Buffer | string` - File content as Buffer or base64 string (required)
|
|
1498
|
+
- `fileName: string` - File name (required)
|
|
1499
|
+
- `mimeType?: string` - MIME type (optional, auto-detected if not provided)
|
|
1500
|
+
|
|
1501
|
+
**Returns:** `Promise<string>` - Source ID
|
|
1502
|
+
|
|
1503
|
+
**Description:**
|
|
1504
|
+
Adds a file (PDF, image, video, etc.) as a source. Supports files as Buffer or base64 string.
|
|
1505
|
+
|
|
1506
|
+
**Supported File Types:**
|
|
1507
|
+
- PDF files
|
|
1508
|
+
- Image files (PNG, JPG, etc.)
|
|
1509
|
+
- Video files
|
|
1510
|
+
- Other document types
|
|
1511
|
+
|
|
1512
|
+
**Usage:**
|
|
1513
|
+
```typescript
|
|
1514
|
+
import fs from 'fs'
|
|
1515
|
+
|
|
1516
|
+
// From file buffer
|
|
1517
|
+
const fileBuffer = fs.readFileSync('document.pdf')
|
|
1518
|
+
const sourceId = await sdk.sources.add.file('notebook-id', {
|
|
1519
|
+
content: fileBuffer,
|
|
1520
|
+
fileName: 'document.pdf',
|
|
1521
|
+
mimeType: 'application/pdf',
|
|
1522
|
+
})
|
|
1523
|
+
|
|
1524
|
+
// From base64 string
|
|
1525
|
+
const base64Content = fileBuffer.toString('base64')
|
|
1526
|
+
const sourceId = await sdk.sources.add.file('notebook-id', {
|
|
1527
|
+
content: base64Content,
|
|
1528
|
+
fileName: 'document.pdf',
|
|
1529
|
+
})
|
|
1530
|
+
```
|
|
1531
|
+
|
|
1532
|
+
---
|
|
1533
|
+
|
|
1534
|
+
### Add YouTube Source
|
|
1535
|
+
|
|
1536
|
+
**Method:** `sdk.sources.add.youtube(notebookId, options)`
|
|
1537
|
+
|
|
1538
|
+
**Example:** [source-add-youtube.ts](examples/source-add-youtube.ts)
|
|
1539
|
+
|
|
1540
|
+
**Parameters:**
|
|
1541
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1542
|
+
- `options: AddYouTubeSourceOptions`
|
|
1543
|
+
- `urlOrId: string` - YouTube URL or video ID (required)
|
|
1544
|
+
- `title?: string` - Optional custom title
|
|
1545
|
+
|
|
1546
|
+
**Returns:** `Promise<string>` - Source ID
|
|
1547
|
+
|
|
1548
|
+
**Description:**
|
|
1549
|
+
Adds a YouTube video as a source. Accepts either full YouTube URL or just the video ID.
|
|
1550
|
+
|
|
1551
|
+
**Usage:**
|
|
1552
|
+
```typescript
|
|
1553
|
+
// From YouTube URL
|
|
1554
|
+
const sourceId = await sdk.sources.add.youtube('notebook-id', {
|
|
1555
|
+
urlOrId: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
|
1556
|
+
})
|
|
1557
|
+
|
|
1558
|
+
// From video ID
|
|
1559
|
+
const sourceId = await sdk.sources.add.youtube('notebook-id', {
|
|
1560
|
+
urlOrId: 'dQw4w9WgXcQ',
|
|
1561
|
+
})
|
|
1562
|
+
```
|
|
1563
|
+
|
|
1564
|
+
---
|
|
1565
|
+
|
|
1566
|
+
### Add Google Drive Source
|
|
1567
|
+
|
|
1568
|
+
**Method:** `sdk.sources.add.drive(notebookId, options)`
|
|
1569
|
+
|
|
1570
|
+
**Parameters:**
|
|
1571
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1572
|
+
- `options: AddGoogleDriveSourceOptions`
|
|
1573
|
+
- `fileId: string` - Google Drive file ID (required)
|
|
1574
|
+
- `title?: string` - Optional custom title
|
|
1575
|
+
- `mimeType?: string` - MIME type (optional, inferred if not provided)
|
|
1576
|
+
|
|
1577
|
+
**Returns:** `Promise<string>` - Source ID
|
|
1578
|
+
|
|
1579
|
+
**Description:**
|
|
1580
|
+
Adds a Google Drive file as a source. Requires the file ID from Google Drive.
|
|
1581
|
+
|
|
1582
|
+
<details>
|
|
1583
|
+
<summary><strong>Deprecated</strong></summary>
|
|
1584
|
+
|
|
1585
|
+
This method is deprecated. Use `add.batch()` with `type: 'gdrive'` instead.
|
|
1586
|
+
|
|
1587
|
+
</details>
|
|
1588
|
+
|
|
1589
|
+
**Usage:**
|
|
1590
|
+
```typescript
|
|
1591
|
+
const sourceId = await sdk.sources.add.drive('notebook-id', {
|
|
1592
|
+
fileId: '1a2b3c4d5e6f7g8h9i0j',
|
|
1593
|
+
mimeType: 'application/vnd.google-apps.document',
|
|
1594
|
+
title: 'My Document',
|
|
1595
|
+
})
|
|
1596
|
+
```
|
|
1597
|
+
|
|
1598
|
+
---
|
|
1599
|
+
|
|
1600
|
+
### Batch Add Sources
|
|
1601
|
+
|
|
1602
|
+
**Method:** `sdk.sources.add.batch(notebookId, options)`
|
|
1603
|
+
|
|
1604
|
+
**Example:** [source-add-batch.ts](examples/source-add-batch.ts)
|
|
1605
|
+
|
|
1606
|
+
**Parameters:**
|
|
1607
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1608
|
+
- `options: BatchAddSourcesOptions`
|
|
1609
|
+
- `sources: Array<...>` - Array of source inputs (required)
|
|
1610
|
+
- `waitForProcessing?: boolean` - Whether to wait for all sources to be processed (default: false)
|
|
1611
|
+
- `timeout?: number` - Timeout in ms if `waitForProcessing` is true (default: 300000 = 5 minutes)
|
|
1612
|
+
- `pollInterval?: number` - Poll interval in ms (default: 2000 = 2 seconds)
|
|
1613
|
+
- `onProgress?: (ready: number, total: number) => void` - Progress callback
|
|
1614
|
+
|
|
1615
|
+
**Returns:** `Promise<string[]>` - Array of source IDs
|
|
1616
|
+
|
|
1617
|
+
**Description:**
|
|
1618
|
+
Adds multiple sources at once. Supports mixed source types (URLs, text, files, YouTube, Google Drive) in a single call.
|
|
1619
|
+
|
|
1620
|
+
**Source Types:**
|
|
1621
|
+
- `{ type: 'url', url: string, title?: string }` - URL source
|
|
1622
|
+
- `{ type: 'text', title: string, content: string }` - Text source
|
|
1623
|
+
- `{ type: 'file', content: Buffer | string, fileName: string, mimeType?: string }` - File source
|
|
1624
|
+
- `{ type: 'youtube', urlOrId: string, title?: string }` - YouTube source
|
|
1625
|
+
- `{ type: 'gdrive', fileId: string, title?: string, mimeType?: string }` - Google Drive source
|
|
1626
|
+
|
|
1627
|
+
**Usage:**
|
|
1628
|
+
```typescript
|
|
1629
|
+
const sourceIds = await sdk.sources.add.batch('notebook-id', {
|
|
1630
|
+
sources: [
|
|
1631
|
+
{ type: 'url', url: 'https://example.com', title: 'Example' },
|
|
1632
|
+
{ type: 'text', title: 'Notes', content: 'Content here...' },
|
|
1633
|
+
{ type: 'youtube', urlOrId: 'dQw4w9WgXcQ' },
|
|
1634
|
+
],
|
|
1635
|
+
waitForProcessing: true, // Optional: wait for all to be ready
|
|
1636
|
+
timeout: 300000, // 5 minutes
|
|
1637
|
+
onProgress: (ready, total) => {
|
|
1638
|
+
console.log(`Progress: ${ready}/${total}`)
|
|
1639
|
+
},
|
|
1640
|
+
})
|
|
1641
|
+
```
|
|
1642
|
+
|
|
1643
|
+
---
|
|
1644
|
+
|
|
1645
|
+
### Web Search (Simple)
|
|
1646
|
+
|
|
1647
|
+
**Method:** `sdk.sources.add.web.searchAndWait(notebookId, options)`
|
|
1648
|
+
|
|
1649
|
+
**Example:** [source-web-search.ts](examples/source-web-search.ts)
|
|
1650
|
+
|
|
1651
|
+
**Parameters:**
|
|
1652
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1653
|
+
- `options: SearchWebAndWaitOptions`
|
|
1654
|
+
- `query: string` - Search query (required)
|
|
1655
|
+
- `sourceType?: SearchSourceType` - Source type: `WEB` (default) or `GOOGLE_DRIVE`
|
|
1656
|
+
- `mode?: ResearchMode` - Research mode: `FAST` (default) or `DEEP` (web only)
|
|
1657
|
+
- `timeout?: number` - Max wait time in ms (default: 60000 = 60 seconds)
|
|
1658
|
+
- `pollInterval?: number` - Poll interval in ms (default: 2000 = 2 seconds)
|
|
1659
|
+
- `onProgress?: (status) => void` - Progress callback
|
|
1660
|
+
|
|
1661
|
+
**Returns:** `Promise<WebSearchResult>` - Results with `sessionId`, `web` sources, and `drive` sources
|
|
1662
|
+
|
|
1663
|
+
**Description:**
|
|
1664
|
+
**RECOMMENDED FOR SIMPLE WORKFLOWS** - One call that searches and waits for results automatically. Returns all discovered sources once available (or timeout). Perfect for automated workflows where you don't need to see intermediate steps.
|
|
1665
|
+
|
|
1666
|
+
**Research Modes:**
|
|
1667
|
+
- `ResearchMode.FAST` - Quick search (~10-30 seconds, default)
|
|
1668
|
+
- `ResearchMode.DEEP` - Comprehensive research (~60-120 seconds, web only)
|
|
1669
|
+
|
|
1670
|
+
**Source Types:**
|
|
1671
|
+
- `SearchSourceType.WEB` - Search web (default)
|
|
1672
|
+
- `SearchSourceType.GOOGLE_DRIVE` - Search Google Drive (FAST mode only)
|
|
1673
|
+
|
|
1674
|
+
**Return Fields:**
|
|
1675
|
+
- `sessionId: string` - Required for adding sources (use with `addDiscovered()`)
|
|
1676
|
+
- `web: DiscoveredWebSource[]` - Discovered web sources
|
|
1677
|
+
- `drive: DiscoveredDriveSource[]` - Discovered Google Drive sources
|
|
1678
|
+
|
|
1679
|
+
<details>
|
|
1680
|
+
<summary><strong>Notes</strong></summary>
|
|
1681
|
+
|
|
1682
|
+
- Automatically polls for results until available or timeout
|
|
1683
|
+
- Returns results once count stabilizes (assumes search complete)
|
|
1684
|
+
- Progress callback shows result count as search progresses
|
|
1685
|
+
- Use returned `sessionId` with `addDiscovered()` to add selected sources
|
|
1686
|
+
|
|
1687
|
+
</details>
|
|
1688
|
+
|
|
1689
|
+
**Usage:**
|
|
1690
|
+
```typescript
|
|
1691
|
+
import { ResearchMode, SearchSourceType } from 'notebooklm-kit'
|
|
1692
|
+
|
|
1693
|
+
// Simple search and wait
|
|
1694
|
+
const result = await sdk.sources.add.web.searchAndWait('notebook-id', {
|
|
1695
|
+
query: 'machine learning research papers 2024',
|
|
1696
|
+
mode: ResearchMode.DEEP, // Comprehensive search
|
|
1697
|
+
sourceType: SearchSourceType.WEB,
|
|
1698
|
+
timeout: 120000, // Wait up to 2 minutes
|
|
1699
|
+
onProgress: (status) => {
|
|
1700
|
+
console.log(`Found ${status.resultCount} results so far...`)
|
|
1701
|
+
},
|
|
1702
|
+
})
|
|
1703
|
+
|
|
1704
|
+
console.log(`Found ${result.web.length} web sources`)
|
|
1705
|
+
console.log(`Session ID: ${result.sessionId}`)
|
|
1706
|
+
|
|
1707
|
+
// Add selected sources
|
|
1708
|
+
const addedIds = await sdk.sources.add.web.addDiscovered('notebook-id', {
|
|
1709
|
+
sessionId: result.sessionId,
|
|
1710
|
+
webSources: result.web.slice(0, 5), // Top 5
|
|
1711
|
+
})
|
|
1712
|
+
```
|
|
1713
|
+
|
|
1714
|
+
---
|
|
1715
|
+
|
|
1716
|
+
### Web Search (Advanced)
|
|
1717
|
+
|
|
1718
|
+
**Method:** `sdk.sources.add.web.search(notebookId, options)` → `sdk.sources.add.web.getResults(notebookId, sessionId)` → `sdk.sources.add.web.addDiscovered(notebookId, options)`
|
|
1719
|
+
|
|
1720
|
+
**Example:** [source-web-search-advanced.ts](examples/source-web-search-advanced.ts)
|
|
1721
|
+
|
|
1722
|
+
**Description:**
|
|
1723
|
+
**MULTI-STEP WORKFLOW** - For cases where you want to see results and make decisions at each step. Returns intermediate results so you can validate, filter, or select before adding sources.
|
|
1724
|
+
|
|
1725
|
+
**Workflow Steps:**
|
|
1726
|
+
1. **`search()`** - Start search, returns `sessionId` immediately
|
|
1727
|
+
2. **`getResults(sessionId)`** - Get discovered sources (can call multiple times to poll)
|
|
1728
|
+
3. **`addDiscovered(sessionId, selectedSources)`** - Add your selected sources
|
|
1729
|
+
|
|
1730
|
+
**Step 1: Start Search**
|
|
1731
|
+
|
|
1732
|
+
**Method:** `sdk.sources.add.web.search(notebookId, options)`
|
|
1733
|
+
|
|
1734
|
+
**Parameters:**
|
|
1735
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1736
|
+
- `options: SearchWebSourcesOptions`
|
|
1737
|
+
- `query: string` - Search query (required)
|
|
1738
|
+
- `sourceType?: SearchSourceType` - `WEB` (default) or `GOOGLE_DRIVE`
|
|
1739
|
+
- `mode?: ResearchMode` - `FAST` (default) or `DEEP` (web only)
|
|
1740
|
+
|
|
1741
|
+
**Returns:** `Promise<string>` - Session ID (required for steps 2 and 3)
|
|
1742
|
+
|
|
1743
|
+
**Step 2: Get Results**
|
|
1744
|
+
|
|
1745
|
+
**Method:** `sdk.sources.add.web.getResults(notebookId, sessionId?)`
|
|
1746
|
+
|
|
1747
|
+
**Parameters:**
|
|
1748
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1749
|
+
- `sessionId?: string` - Session ID from step 1 (optional - if omitted, returns all results)
|
|
1750
|
+
|
|
1751
|
+
**Returns:** `Promise<{ web: DiscoveredWebSource[], drive: DiscoveredDriveSource[] }>`
|
|
1752
|
+
|
|
1753
|
+
**Step 3: Add Discovered Sources**
|
|
1754
|
+
|
|
1755
|
+
**Method:** `sdk.sources.add.web.addDiscovered(notebookId, options)`
|
|
1756
|
+
|
|
1757
|
+
**Parameters:**
|
|
1758
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1759
|
+
- `options: AddDiscoveredSourcesOptions`
|
|
1760
|
+
- `sessionId: string` - Session ID from step 1 (required)
|
|
1761
|
+
- `webSources?: DiscoveredWebSource[]` - Web sources to add
|
|
1762
|
+
- `driveSources?: DiscoveredDriveSource[]` - Drive sources to add
|
|
1763
|
+
|
|
1764
|
+
**Returns:** `Promise<string[]>` - Array of added source IDs
|
|
1765
|
+
|
|
1766
|
+
**Usage:**
|
|
1767
|
+
```typescript
|
|
1768
|
+
// Step 1: Start search
|
|
1769
|
+
const sessionId = await sdk.sources.add.web.search('notebook-id', {
|
|
1770
|
+
query: 'quantum computing',
|
|
1771
|
+
mode: ResearchMode.FAST,
|
|
1772
|
+
})
|
|
1773
|
+
|
|
1774
|
+
// Step 2: Poll for results (you control when/how often)
|
|
1775
|
+
let results
|
|
1776
|
+
do {
|
|
1777
|
+
await new Promise(r => setTimeout(r, 2000)) // Wait 2 seconds
|
|
1778
|
+
results = await sdk.sources.add.web.getResults('notebook-id', sessionId)
|
|
1779
|
+
console.log(`Found ${results.web.length} sources...`)
|
|
1780
|
+
} while (results.web.length === 0)
|
|
1781
|
+
|
|
1782
|
+
// Step 3: Filter and add selected sources
|
|
1783
|
+
const relevant = results.web.filter(s => s.url.includes('arxiv.org'))
|
|
1784
|
+
const addedIds = await sdk.sources.add.web.addDiscovered('notebook-id', {
|
|
1785
|
+
sessionId,
|
|
1786
|
+
webSources: relevant,
|
|
1787
|
+
})
|
|
1788
|
+
```
|
|
1789
|
+
|
|
1790
|
+
---
|
|
1791
|
+
|
|
1792
|
+
### Get Search Results
|
|
1793
|
+
|
|
1794
|
+
**Method:** `sdk.sources.add.web.getResults(notebookId, sessionId?)`
|
|
1795
|
+
|
|
1796
|
+
**Parameters:**
|
|
1797
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1798
|
+
- `sessionId?: string` - Optional session ID to filter results
|
|
1799
|
+
|
|
1800
|
+
**Returns:** `Promise<{ web: DiscoveredWebSource[], drive: DiscoveredDriveSource[] }>`
|
|
1801
|
+
|
|
1802
|
+
**Description:**
|
|
1803
|
+
Returns discovered sources from search sessions. If `sessionId` is provided, filters results to that specific session. If omitted, returns all results (may include results from other searches).
|
|
1804
|
+
|
|
1805
|
+
**Usage:**
|
|
1806
|
+
```typescript
|
|
1807
|
+
// Get results for specific session
|
|
1808
|
+
const results = await sdk.sources.add.web.getResults('notebook-id', sessionId)
|
|
1809
|
+
|
|
1810
|
+
// Get all results (no filtering)
|
|
1811
|
+
const allResults = await sdk.sources.add.web.getResults('notebook-id')
|
|
1812
|
+
```
|
|
1813
|
+
|
|
1814
|
+
---
|
|
1815
|
+
|
|
1816
|
+
### Add Discovered Sources
|
|
1817
|
+
|
|
1818
|
+
**Method:** `sdk.sources.add.web.addDiscovered(notebookId, options)`
|
|
1819
|
+
|
|
1820
|
+
**Parameters:**
|
|
1821
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1822
|
+
- `options: AddDiscoveredSourcesOptions`
|
|
1823
|
+
- `sessionId: string` - Session ID from search (required)
|
|
1824
|
+
- `webSources?: DiscoveredWebSource[]` - Web sources to add
|
|
1825
|
+
- `driveSources?: DiscoveredDriveSource[]` - Drive sources to add
|
|
1826
|
+
|
|
1827
|
+
**Returns:** `Promise<string[]>` - Array of added source IDs
|
|
1828
|
+
|
|
1829
|
+
**Description:**
|
|
1830
|
+
Adds selected discovered sources from search results. You decide which sources to add (from `getResults()` or `searchAndWait()`).
|
|
1831
|
+
|
|
1832
|
+
**Usage:**
|
|
1833
|
+
```typescript
|
|
1834
|
+
// After searchAndWait()
|
|
1835
|
+
const result = await sdk.sources.add.web.searchAndWait(...)
|
|
1836
|
+
const addedIds = await sdk.sources.add.web.addDiscovered('notebook-id', {
|
|
1837
|
+
sessionId: result.sessionId,
|
|
1838
|
+
webSources: result.web.slice(0, 5), // Top 5
|
|
1839
|
+
})
|
|
1840
|
+
|
|
1841
|
+
// After manual search workflow
|
|
1842
|
+
const addedIds = await sdk.sources.add.web.addDiscovered('notebook-id', {
|
|
1843
|
+
sessionId: sessionId,
|
|
1844
|
+
webSources: filteredSources,
|
|
1845
|
+
driveSources: selectedDriveSources,
|
|
1846
|
+
})
|
|
1847
|
+
```
|
|
1848
|
+
|
|
1849
|
+
---
|
|
1850
|
+
|
|
1851
|
+
### Update Source
|
|
1852
|
+
|
|
1853
|
+
**Method:** `sdk.sources.update(notebookId, sourceId, updates)`
|
|
1854
|
+
|
|
1855
|
+
**Parameters:**
|
|
1856
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1857
|
+
- `sourceId: string` - The source ID (required)
|
|
1858
|
+
- `updates: Partial<Source>` - Fields to update
|
|
1859
|
+
- `title?: string` - New title
|
|
1860
|
+
|
|
1861
|
+
**Returns:** `Promise<void>`
|
|
1862
|
+
|
|
1863
|
+
**Description:**
|
|
1864
|
+
Updates source metadata. Currently supports updating the title.
|
|
1865
|
+
|
|
1866
|
+
**Usage:**
|
|
1867
|
+
```typescript
|
|
1868
|
+
await sdk.sources.update('notebook-id', 'source-id', {
|
|
1869
|
+
title: 'Updated Source Title',
|
|
1870
|
+
})
|
|
1871
|
+
```
|
|
1872
|
+
|
|
1873
|
+
---
|
|
1874
|
+
|
|
1875
|
+
### Delete Source
|
|
1876
|
+
|
|
1877
|
+
**Method:** `sdk.sources.delete(notebookId, sourceId)`
|
|
1878
|
+
|
|
1879
|
+
**Example:** [source-delete.ts](examples/source-delete.ts)
|
|
1880
|
+
|
|
1881
|
+
**Parameters:**
|
|
1882
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1883
|
+
- `sourceId: string` - The source ID (required)
|
|
1884
|
+
|
|
1885
|
+
**Returns:** `Promise<void>`
|
|
1886
|
+
|
|
1887
|
+
**Description:**
|
|
1888
|
+
Deletes a source from a notebook.
|
|
1889
|
+
|
|
1890
|
+
**Usage:**
|
|
1891
|
+
```typescript
|
|
1892
|
+
await sdk.sources.delete('notebook-id', 'source-id')
|
|
1893
|
+
```
|
|
1894
|
+
|
|
1895
|
+
---
|
|
1896
|
+
|
|
1897
|
+
### Check Processing Status
|
|
1898
|
+
|
|
1899
|
+
**Method:** `sdk.sources.status(notebookId)`
|
|
1900
|
+
|
|
1901
|
+
**Example:** [source-status.ts](examples/source-status.ts)
|
|
1902
|
+
|
|
1903
|
+
**Parameters:**
|
|
1904
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1905
|
+
|
|
1906
|
+
**Returns:** `Promise<SourceProcessingStatus>`
|
|
1907
|
+
|
|
1908
|
+
**Description:**
|
|
1909
|
+
Checks the processing status of all sources in a notebook. Returns information about which sources are still processing and whether all sources are ready.
|
|
1910
|
+
|
|
1911
|
+
**Return Fields:**
|
|
1912
|
+
- `allReady: boolean` - Whether all sources are ready
|
|
1913
|
+
- `processing: string[]` - Array of source IDs still processing
|
|
1914
|
+
|
|
1915
|
+
**Usage:**
|
|
1916
|
+
```typescript
|
|
1917
|
+
const status = await sdk.sources.status('notebook-id')
|
|
1918
|
+
|
|
1919
|
+
if (status.allReady) {
|
|
1920
|
+
console.log('All sources are ready!')
|
|
1921
|
+
} else {
|
|
1922
|
+
console.log(`Still processing: ${status.processing.length} sources`)
|
|
1923
|
+
console.log('Processing IDs:', status.processing)
|
|
1924
|
+
}
|
|
1925
|
+
```
|
|
1926
|
+
|
|
1927
|
+
---
|
|
1928
|
+
|
|
1929
|
+
## Artifacts
|
|
1930
|
+
|
|
1931
|
+
Examples: [artifact-create.ts](examples/artifact-create.ts) | [artifact-create-subservices.ts](examples/artifact-create-subservices.ts) | [artifact-list.ts](examples/artifact-list.ts) | [artifact-get.ts](examples/artifact-get.ts) | [artifact-download.ts](examples/artifact-download.ts) | [artifact-video.ts](examples/artifact-video.ts) | [slide-download-test.ts](examples/slide-download-test.ts) | [artifact-rename.ts](examples/artifact-rename.ts) | [artifact-delete.ts](examples/artifact-delete.ts) | [artifact-share.ts](examples/artifact-share.ts)
|
|
1932
|
+
|
|
1933
|
+
### Create Artifact
|
|
1934
|
+
|
|
1935
|
+
**Method:** `sdk.artifacts.create(notebookId, type, options)` or `sdk.artifacts.{type}.create(notebookId, options)`
|
|
1936
|
+
|
|
1937
|
+
**Examples:**
|
|
1938
|
+
- [artifact-create.ts](examples/artifact-create.ts) - Using main `create()` method
|
|
1939
|
+
- [artifact-create-subservices.ts](examples/artifact-create-subservices.ts) - Using type-safe sub-service methods
|
|
1940
|
+
|
|
1941
|
+
**Parameters:**
|
|
1942
|
+
- `notebookId: string` - The notebook ID (required)
|
|
1943
|
+
- `type: ArtifactType` - Artifact type (required for main method)
|
|
1944
|
+
- `options: CreateArtifactOptions`
|
|
1945
|
+
- `title?: string` - Artifact title (optional)
|
|
1946
|
+
- `instructions?: string` - Instructions for generation (optional)
|
|
1947
|
+
- `sourceIds?: string[]` - Source IDs to use (optional - automatically uses all sources if omitted)
|
|
1948
|
+
- `customization?: object` - Type-specific customization options (optional)
|
|
1949
|
+
|
|
1950
|
+
**Returns:** `Promise<Artifact>` (or `Promise<VideoOverview>` / `Promise<AudioOverview>` for video/audio)
|
|
1951
|
+
|
|
1952
|
+
**Description:**
|
|
1953
|
+
Creates a study material artifact (quiz, flashcards, report, mind map, infographic, slide deck, audio, video). Supports customization options for 6 out of 8 artifact types. Returns immediately with artifact metadata - check `state` field to see if artifact is ready.
|
|
1954
|
+
|
|
1955
|
+
**Artifact Types:**
|
|
1956
|
+
|
|
1957
|
+
| Type | Value | Customization | Sub-Service |
|
|
1958
|
+
|------|-------|---------------|-------------|
|
|
1959
|
+
| Quiz | `ArtifactType.QUIZ` | ✅ Yes | `sdk.artifacts.quiz.create()` |
|
|
1960
|
+
| Flashcards | `ArtifactType.FLASHCARDS` | ✅ Yes | `sdk.artifacts.flashcard.create()` |
|
|
1961
|
+
| Report | `ArtifactType.REPORT` | ❌ No | `sdk.artifacts.report.create()` |
|
|
1962
|
+
| Mind Map | `ArtifactType.MIND_MAP` | ❌ No | `sdk.artifacts.mindmap.create()` |
|
|
1963
|
+
| Infographic | `ArtifactType.INFOGRAPHIC` | ✅ Yes | `sdk.artifacts.infographic.create()` |
|
|
1964
|
+
| Slide Deck | `ArtifactType.SLIDE_DECK` | ✅ Yes | `sdk.artifacts.slide.create()` |
|
|
1965
|
+
| Audio | `ArtifactType.AUDIO` | ✅ Yes | `sdk.artifacts.audio.create()` |
|
|
1966
|
+
| Video | `ArtifactType.VIDEO` | ✅ Yes | `sdk.artifacts.video.create()` |
|
|
1967
|
+
|
|
1968
|
+
**Customization Options:**
|
|
1969
|
+
|
|
1970
|
+
<details>
|
|
1971
|
+
<summary><strong>Quiz Customization</strong></summary>
|
|
1972
|
+
|
|
1973
|
+
| Option | Values | Description | Default |
|
|
1974
|
+
|-------|--------|-------------|---------|
|
|
1975
|
+
| `numberOfQuestions` | `1`, `2`, `3` | **1** = Fewer (5-10 questions), **2** = Standard (10-15 questions), **3** = More (15-20+ questions) | `2` |
|
|
1976
|
+
| `difficulty` | `1`, `2`, `3` | **1** = Easy (basic recall), **2** = Medium (application), **3** = Hard (analysis/synthesis) | `2` |
|
|
1977
|
+
| `language` | `string` | Language code (e.g., `'en'`, `'hi'`, `'es'`). Use `NotebookLMLanguage` enum for type safety. Supports 80+ languages. | `'en'` |
|
|
1978
|
+
|
|
1979
|
+
**Example:**
|
|
1980
|
+
```typescript
|
|
1981
|
+
customization: {
|
|
1982
|
+
numberOfQuestions: 2, // Standard (10-15 questions)
|
|
1983
|
+
difficulty: 2, // Medium difficulty
|
|
1984
|
+
language: NotebookLMLanguage.ENGLISH,
|
|
1985
|
+
}
|
|
1986
|
+
```
|
|
1987
|
+
|
|
1988
|
+
</details>
|
|
1989
|
+
|
|
1990
|
+
<details>
|
|
1991
|
+
<summary><strong>Flashcard Customization</strong></summary>
|
|
1992
|
+
|
|
1993
|
+
| Option | Values | Description | Default |
|
|
1994
|
+
|-------|--------|-------------|---------|
|
|
1995
|
+
| `numberOfCards` | `1`, `2`, `3` | **1** = Fewer (10-15 cards), **2** = Standard (15-25 cards), **3** = More (25-40+ cards) | `2` |
|
|
1996
|
+
| `difficulty` | `1`, `2`, `3` | **1** = Easy (basic terms), **2** = Medium (concepts), **3** = Hard (complex relationships) | `2` |
|
|
1997
|
+
| `language` | `string` | Language code (e.g., `'en'`, `'hi'`, `'es'`). Use `NotebookLMLanguage` enum for type safety. Supports 80+ languages. | `'en'` |
|
|
1998
|
+
|
|
1999
|
+
**Example:**
|
|
2000
|
+
```typescript
|
|
2001
|
+
customization: {
|
|
2002
|
+
numberOfCards: 3, // More cards (25-40+)
|
|
2003
|
+
difficulty: 1, // Easy (basic terms)
|
|
2004
|
+
language: NotebookLMLanguage.ENGLISH,
|
|
2005
|
+
}
|
|
2006
|
+
```
|
|
2007
|
+
|
|
2008
|
+
</details>
|
|
2009
|
+
|
|
2010
|
+
<details>
|
|
2011
|
+
<summary><strong>Slide Deck Customization</strong></summary>
|
|
2012
|
+
|
|
2013
|
+
| Option | Values | Description | Default |
|
|
2014
|
+
|-------|--------|-------------|---------|
|
|
2015
|
+
| `format` | `2`, `3` | **2** = Presenter slides (concise, bullet points), **3** = Detailed deck (comprehensive, full content) | `2` |
|
|
2016
|
+
| `length` | `1`, `2` | **1** = Short (5-10 slides), **2** = Default (10-15 slides) | `2` |
|
|
2017
|
+
| `language` | `string` | Language code (e.g., `'en'`, `'hi'`, `'es'`). Use `NotebookLMLanguage` enum for type safety. Supports 80+ languages. | `'en'` |
|
|
2018
|
+
|
|
2019
|
+
**Example:**
|
|
2020
|
+
```typescript
|
|
2021
|
+
customization: {
|
|
2022
|
+
format: 2, // Presenter slides (concise)
|
|
2023
|
+
length: 2, // Default (10-15 slides)
|
|
2024
|
+
language: NotebookLMLanguage.ENGLISH,
|
|
2025
|
+
}
|
|
2026
|
+
```
|
|
2027
|
+
|
|
2028
|
+
</details>
|
|
2029
|
+
|
|
2030
|
+
<details>
|
|
2031
|
+
<summary><strong>Infographic Customization</strong></summary>
|
|
2032
|
+
|
|
2033
|
+
| Option | Values | Description | Default |
|
|
2034
|
+
|-------|--------|-------------|---------|
|
|
2035
|
+
| `orientation` | `1`, `2`, `3` | **1** = Landscape (wide format), **2** = Portrait (tall format), **3** = Square (1:1 aspect ratio) | `1` |
|
|
2036
|
+
| `levelOfDetail` | `1`, `2`, `3` | **1** = Concise (key points only), **2** = Standard (balanced detail), **3** = Detailed (comprehensive information) | `2` |
|
|
2037
|
+
| `language` | `string` | Language code (e.g., `'en'`, `'hi'`, `'es'`). Use `NotebookLMLanguage` enum for type safety. Supports 80+ languages. | `'en'` |
|
|
2038
|
+
|
|
2039
|
+
**Example:**
|
|
2040
|
+
```typescript
|
|
2041
|
+
customization: {
|
|
2042
|
+
orientation: 1, // Landscape (wide format)
|
|
2043
|
+
levelOfDetail: 2, // Standard detail
|
|
2044
|
+
language: NotebookLMLanguage.ENGLISH,
|
|
2045
|
+
}
|
|
2046
|
+
```
|
|
2047
|
+
|
|
2048
|
+
</details>
|
|
2049
|
+
|
|
2050
|
+
<details>
|
|
2051
|
+
<summary><strong>Audio Customization</strong></summary>
|
|
2052
|
+
|
|
2053
|
+
| Option | Values | Description | Default |
|
|
2054
|
+
|-------|--------|-------------|---------|
|
|
2055
|
+
| `format` | `0`, `1`, `2`, `3` | **0** = Deep dive (comprehensive analysis), **1** = Brief (quick summary), **2** = Critique (critical analysis), **3** = Debate (multiple perspectives) | `0` |
|
|
2056
|
+
| `length` | `1`, `2`, `3` | **1** = Short (2-5 minutes), **2** = Default (5-10 minutes), **3** = Long (10-15+ minutes) | `2` |
|
|
2057
|
+
| `language` | `string` | Language code (e.g., `'en'`, `'hi'`, `'es'`). Use `NotebookLMLanguage` enum for type safety. Supports 80+ languages. | `'en'` |
|
|
2058
|
+
|
|
2059
|
+
**Note:** If `sourceIds` is omitted, all sources in the notebook are automatically used.
|
|
2060
|
+
|
|
2061
|
+
**Example:**
|
|
2062
|
+
```typescript
|
|
2063
|
+
customization: {
|
|
2064
|
+
format: 0, // Deep dive (comprehensive analysis)
|
|
2065
|
+
length: 2, // Default (5-10 minutes)
|
|
2066
|
+
language: NotebookLMLanguage.ENGLISH,
|
|
2067
|
+
}
|
|
2068
|
+
```
|
|
2069
|
+
|
|
2070
|
+
</details>
|
|
2071
|
+
|
|
2072
|
+
<details>
|
|
2073
|
+
<summary><strong>Video Customization</strong></summary>
|
|
2074
|
+
|
|
2075
|
+
| Option | Values | Description | Default |
|
|
2076
|
+
|-------|--------|-------------|---------|
|
|
2077
|
+
| `format` | `1`, `2` | **1** = Explainer (comprehensive explanation), **2** = Brief (quick overview) | `1` |
|
|
2078
|
+
| `visualStyle` | `0-10` | Visual style for the video (see table below) | `0` |
|
|
2079
|
+
| `focus` | `string` | What should the AI hosts focus on? (optional, e.g., "Key concepts and main findings") | - |
|
|
2080
|
+
| `customStyleDescription` | `string` | Custom visual style description (required when `visualStyle=1`) | - |
|
|
2081
|
+
| `language` | `string` | Language code (e.g., `'en'`, `'hi'`, `'es'`). Use `NotebookLMLanguage` enum for type safety. Supports 80+ languages. | `'en'` |
|
|
2082
|
+
|
|
2083
|
+
**Visual Style Options:**
|
|
2084
|
+
|
|
2085
|
+
| Value | Style Name | Description |
|
|
2086
|
+
|-------|------------|-------------|
|
|
2087
|
+
| `0` | Auto-select | AI chooses the best style automatically (default) |
|
|
2088
|
+
| `1` | Custom | Requires `customStyleDescription` - describe your desired style |
|
|
2089
|
+
| `2` | Classic | Traditional, professional style |
|
|
2090
|
+
| `3` | Whiteboard | Hand-drawn whiteboard style |
|
|
2091
|
+
| `4` | Kawaii | Cute, colorful style |
|
|
2092
|
+
| `5` | Anime | Anime-inspired style |
|
|
2093
|
+
| `6` | Watercolour | Watercolor painting style |
|
|
2094
|
+
| `7` | Anime (alternative) | Alternative anime style |
|
|
2095
|
+
| `8` | Retro print | Vintage print/poster style |
|
|
2096
|
+
| `9` | Heritage | Traditional ink-wash/woodcut style |
|
|
2097
|
+
| `10` | Paper-craft | Layered paper cutout style |
|
|
2098
|
+
|
|
2099
|
+
**Note:**
|
|
2100
|
+
- All styles except Custom (`1`) support only the `focus` option
|
|
2101
|
+
- Custom (`1`) additionally requires `customStyleDescription`
|
|
2102
|
+
- If `sourceIds` is omitted, all sources in the notebook are automatically used
|
|
2103
|
+
|
|
2104
|
+
**Example:**
|
|
2105
|
+
```typescript
|
|
2106
|
+
// Auto-select style
|
|
2107
|
+
customization: {
|
|
2108
|
+
format: 1, // Explainer
|
|
2109
|
+
visualStyle: 0, // Auto-select (AI chooses)
|
|
2110
|
+
focus: 'Key concepts and main findings',
|
|
2111
|
+
language: NotebookLMLanguage.ENGLISH,
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
// Custom style
|
|
2115
|
+
customization: {
|
|
2116
|
+
format: 1, // Explainer
|
|
2117
|
+
visualStyle: 1, // Custom
|
|
2118
|
+
customStyleDescription: 'Modern minimalist design with blue and white colors',
|
|
2119
|
+
focus: 'Key concepts and main findings',
|
|
2120
|
+
language: NotebookLMLanguage.ENGLISH,
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
// Specific style (e.g., Whiteboard)
|
|
2124
|
+
customization: {
|
|
2125
|
+
format: 1, // Explainer
|
|
2126
|
+
visualStyle: 3, // Whiteboard style
|
|
2127
|
+
focus: 'Step-by-step explanation of the process',
|
|
2128
|
+
language: NotebookLMLanguage.ENGLISH,
|
|
2129
|
+
}
|
|
2130
|
+
```
|
|
2131
|
+
|
|
2132
|
+
</details>
|
|
2133
|
+
|
|
2134
|
+
<details>
|
|
2135
|
+
<summary><strong>Report & Mind Map (No Customization)</strong></summary>
|
|
2136
|
+
|
|
2137
|
+
**Report** and **Mind Map** artifacts do not support customization options. They only support:
|
|
2138
|
+
- `title?: string` - Artifact title (optional)
|
|
2139
|
+
- `instructions?: string` - Custom instructions for generation (optional)
|
|
2140
|
+
- `sourceIds?: string[]` - Source IDs to use (optional - automatically uses all sources if omitted)
|
|
2141
|
+
|
|
2142
|
+
**Example:**
|
|
2143
|
+
```typescript
|
|
2144
|
+
// Create report
|
|
2145
|
+
const report = await sdk.artifacts.report.create('notebook-id', {
|
|
2146
|
+
title: 'Research Report',
|
|
2147
|
+
instructions: 'Create a comprehensive research report',
|
|
2148
|
+
sourceIds: ['source-id-1', 'source-id-2'], // Optional
|
|
2149
|
+
})
|
|
2150
|
+
|
|
2151
|
+
// Create mind map
|
|
2152
|
+
const mindMap = await sdk.artifacts.mindmap.create('notebook-id', {
|
|
2153
|
+
title: 'Concept Map',
|
|
2154
|
+
instructions: 'Create a visual mind map of key concepts',
|
|
2155
|
+
sourceIds: ['source-id-1'], // Optional
|
|
2156
|
+
})
|
|
2157
|
+
```
|
|
2158
|
+
|
|
2159
|
+
</details>
|
|
2160
|
+
|
|
2161
|
+
**Source Selection:**
|
|
2162
|
+
|
|
2163
|
+
- `sourceIds` is **optional** for all artifact types
|
|
2164
|
+
- If omitted or empty, **all sources** in the notebook are automatically used
|
|
2165
|
+
- If provided, only the specified sources are used
|
|
2166
|
+
|
|
2167
|
+
**Return Fields:**
|
|
2168
|
+
- `artifactId: string` - Unique artifact ID (required for other operations)
|
|
2169
|
+
- `type: ArtifactType` - Artifact type
|
|
2170
|
+
- `state: ArtifactState` - Current state: `CREATING`, `READY`, or `FAILED`
|
|
2171
|
+
- `title: string` - Artifact title
|
|
2172
|
+
- `sourceIds?: string[]` - Source IDs used to create the artifact
|
|
2173
|
+
- `createdAt?: string` - Creation timestamp
|
|
2174
|
+
- `updatedAt?: string` - Last update timestamp
|
|
2175
|
+
|
|
2176
|
+
<details>
|
|
2177
|
+
<summary><strong>Notes</strong></summary>
|
|
2178
|
+
|
|
2179
|
+
- Artifacts are created asynchronously - check `state` field to see if ready
|
|
2180
|
+
- Use `get(artifactId)` to fetch full artifact data when `state === READY`
|
|
2181
|
+
- Quota is checked before creation (if quota manager is enabled)
|
|
2182
|
+
- Usage is recorded after successful creation
|
|
2183
|
+
- Audio and video artifacts return `AudioOverview` / `VideoOverview` instead of `Artifact`
|
|
2184
|
+
- Sub-services provide type-safe convenience methods (e.g., `sdk.artifacts.quiz.create()`)
|
|
2185
|
+
|
|
2186
|
+
</details>
|
|
2187
|
+
|
|
2188
|
+
**Usage:**
|
|
2189
|
+
```typescript
|
|
2190
|
+
import { ArtifactType } from 'notebooklm-kit'
|
|
2191
|
+
|
|
2192
|
+
// Generic create method
|
|
2193
|
+
const quiz = await sdk.artifacts.create('notebook-id', ArtifactType.QUIZ, {
|
|
2194
|
+
title: 'Chapter 1 Quiz',
|
|
2195
|
+
instructions: 'Create questions covering key concepts',
|
|
2196
|
+
customization: {
|
|
2197
|
+
numberOfQuestions: 2, // Standard
|
|
2198
|
+
difficulty: 2, // Medium
|
|
2199
|
+
language: 'en',
|
|
2200
|
+
},
|
|
2201
|
+
})
|
|
2202
|
+
|
|
2203
|
+
// Using sub-services (type-safe)
|
|
2204
|
+
const quiz = await sdk.artifacts.quiz.create('notebook-id', {
|
|
2205
|
+
title: 'Chapter 1 Quiz',
|
|
2206
|
+
instructions: 'Create questions covering key concepts',
|
|
2207
|
+
customization: {
|
|
2208
|
+
numberOfQuestions: 2,
|
|
2209
|
+
difficulty: 2,
|
|
2210
|
+
language: 'en',
|
|
2211
|
+
},
|
|
2212
|
+
})
|
|
2213
|
+
|
|
2214
|
+
const flashcards = await sdk.artifacts.flashcard.create('notebook-id', {
|
|
2215
|
+
customization: {
|
|
2216
|
+
numberOfCards: 3, // More cards
|
|
2217
|
+
difficulty: 1, // Easy
|
|
2218
|
+
},
|
|
2219
|
+
})
|
|
2220
|
+
|
|
2221
|
+
const video = await sdk.artifacts.video.create('notebook-id', {
|
|
2222
|
+
instructions: 'Create a summary video',
|
|
2223
|
+
customization: {
|
|
2224
|
+
format: 1,
|
|
2225
|
+
visualStyle: 0,
|
|
2226
|
+
language: 'en',
|
|
2227
|
+
},
|
|
2228
|
+
})
|
|
2229
|
+
|
|
2230
|
+
// Check if ready
|
|
2231
|
+
if (quiz.state === ArtifactState.READY) {
|
|
2232
|
+
const fullQuiz = await sdk.artifacts.get(quiz.artifactId, 'notebook-id')
|
|
2233
|
+
}
|
|
2234
|
+
```
|
|
2235
|
+
|
|
2236
|
+
---
|
|
2237
|
+
|
|
2238
|
+
### List Artifacts
|
|
2239
|
+
|
|
2240
|
+
**Method:** `sdk.artifacts.list(notebookId, options?)`
|
|
2241
|
+
|
|
2242
|
+
**Example:** [artifact-list.ts](examples/artifact-list.ts)
|
|
2243
|
+
|
|
2244
|
+
**Parameters:**
|
|
2245
|
+
- `notebookId: string` - The notebook ID (required)
|
|
2246
|
+
- `options?: { type?: ArtifactType; state?: ArtifactState }` - Filtering options (optional)
|
|
2247
|
+
|
|
2248
|
+
**Returns:** `Promise<Artifact[]>`
|
|
2249
|
+
|
|
2250
|
+
**Description:**
|
|
2251
|
+
Lists all artifacts in a notebook. Supports filtering by type and/or state. Returns lightweight artifact metadata for display/selection.
|
|
2252
|
+
|
|
2253
|
+
**Return Fields:**
|
|
2254
|
+
- `artifactId: string` - Unique artifact ID
|
|
2255
|
+
- `type: ArtifactType` - Artifact type
|
|
2256
|
+
- `state: ArtifactState` - Current state (`CREATING`, `READY`, `FAILED`)
|
|
2257
|
+
- `title: string` - Artifact title
|
|
2258
|
+
- `sourceIds?: string[]` - Source IDs used
|
|
2259
|
+
- `createdAt?: string` - Creation timestamp
|
|
2260
|
+
- `updatedAt?: string` - Last update timestamp
|
|
2261
|
+
|
|
2262
|
+
<details>
|
|
2263
|
+
<summary><strong>Notes</strong></summary>
|
|
2264
|
+
|
|
2265
|
+
- Returns all artifact types (quiz, flashcards, report, mind map, infographic, slide deck, audio, video)
|
|
2266
|
+
- Filtering is optional - returns all artifacts if no filters provided
|
|
2267
|
+
- Does not include full artifact content (use `get()` for that)
|
|
2268
|
+
- Check `state` field to see if artifacts are ready before fetching content
|
|
2269
|
+
|
|
2270
|
+
</details>
|
|
2271
|
+
|
|
2272
|
+
**Usage:**
|
|
2273
|
+
```typescript
|
|
2274
|
+
import { ArtifactType, ArtifactState } from 'notebooklm-kit'
|
|
2275
|
+
|
|
2276
|
+
// List all artifacts
|
|
2277
|
+
const artifacts = await sdk.artifacts.list('notebook-id')
|
|
2278
|
+
console.log(`Found ${artifacts.length} artifacts`)
|
|
2279
|
+
|
|
2280
|
+
// Filter by type
|
|
2281
|
+
const quizzes = await sdk.artifacts.list('notebook-id', {
|
|
2282
|
+
type: ArtifactType.QUIZ,
|
|
2283
|
+
})
|
|
2284
|
+
|
|
2285
|
+
// Filter by state
|
|
2286
|
+
const ready = await sdk.artifacts.list('notebook-id', {
|
|
2287
|
+
state: ArtifactState.READY,
|
|
2288
|
+
})
|
|
2289
|
+
|
|
2290
|
+
// Filter by both type and state
|
|
2291
|
+
const readyQuizzes = await sdk.artifacts.list('notebook-id', {
|
|
2292
|
+
type: ArtifactType.QUIZ,
|
|
2293
|
+
state: ArtifactState.READY,
|
|
2294
|
+
})
|
|
2295
|
+
|
|
2296
|
+
// Display artifacts
|
|
2297
|
+
artifacts.forEach(artifact => {
|
|
2298
|
+
console.log(`${artifact.title} (${artifact.type}) - ${artifact.state}`)
|
|
2299
|
+
})
|
|
2300
|
+
```
|
|
2301
|
+
|
|
2302
|
+
---
|
|
2303
|
+
|
|
2304
|
+
### Get Artifact
|
|
2305
|
+
|
|
2306
|
+
**Method:** `sdk.artifacts.get(artifactId, notebookId?, options?)`
|
|
2307
|
+
|
|
2308
|
+
**Examples:** [artifact-get.ts](examples/artifact-get.ts) | [artifact-video.ts](examples/artifact-video.ts) (video-specific) | [slide-download-test.ts](examples/slide-download-test.ts) (slide-specific)
|
|
2309
|
+
|
|
2310
|
+
**Parameters:**
|
|
2311
|
+
- `artifactId: string` - The artifact ID from `create()` or `list()` (required)
|
|
2312
|
+
- `notebookId?: string` - Optional notebook ID (helpful for audio/video if get() needs it)
|
|
2313
|
+
- `options?: { exportToDocs?: boolean; exportToSheets?: boolean }` - Export options (for reports only)
|
|
2314
|
+
|
|
2315
|
+
**Returns:** `Promise<Artifact | QuizData | FlashcardData | AudioArtifact | VideoArtifact | any>`
|
|
2316
|
+
|
|
2317
|
+
**Description:**
|
|
2318
|
+
Retrieves detailed artifact information. Automatically fetches full content when artifact is `READY`:
|
|
2319
|
+
- **Quiz/Flashcards**: Returns full data (questions, flashcards array, CSV)
|
|
2320
|
+
- **Audio**: Returns audio metadata (use `download()` to get audio file)
|
|
2321
|
+
- **Video**: Returns video URL in `videoData` field (use `download()` to download video file)
|
|
2322
|
+
- **Slides**: Returns slide image URLs (use `download()` to download slides as PDF/PNG)
|
|
2323
|
+
- **Reports**: Returns basic metadata (use `download()` to get report content, or `get()` with export options for Google Docs/Sheets)
|
|
2324
|
+
- **Infographics**: Returns image data with dimensions
|
|
2325
|
+
- **Mind Maps**: Returns with `experimental: true` flag
|
|
2326
|
+
|
|
2327
|
+
**Return Types by Artifact Type:**
|
|
2328
|
+
|
|
2329
|
+
| Type | Returns | Content |
|
|
2330
|
+
|------|---------|---------|
|
|
2331
|
+
| Quiz | `QuizData` | Questions, options, correct answers, explanations |
|
|
2332
|
+
| Flashcards | `FlashcardData` | Flashcards array, CSV, totalCards |
|
|
2333
|
+
| Audio | `AudioArtifact` | Audio metadata (use `download()` for audio file) |
|
|
2334
|
+
| Video | `Artifact` | Video URL in `videoData` field (use `download()` to download) |
|
|
2335
|
+
| Slides | `Artifact` | Slide image URLs in `slideUrls` array (use `download()` to download) |
|
|
2336
|
+
| Report | `Artifact` | Basic metadata (artifactId, notebookId, state, title) - use `download()` for content or export options |
|
|
2337
|
+
| Infographic | `InfographicImageData` | Image data, dimensions, URL |
|
|
2338
|
+
| Mind Map | `Artifact` | Metadata with `experimental: true` |
|
|
2339
|
+
|
|
2340
|
+
**Important Notes:**
|
|
2341
|
+
- **Videos & Slides**: `get()` returns URLs/links only, not downloaded files. Use `download()` method to actually download files.
|
|
2342
|
+
- **Reports**: `get()` returns basic metadata only. Use `download()` to get report content, or use export options below.
|
|
2343
|
+
- **Audio**: `get()` may not include audio data. Use `download()` to get the audio file.
|
|
2344
|
+
|
|
2345
|
+
**Report Export Options:**
|
|
2346
|
+
- `exportToDocs?: boolean` - Export to Google Docs and return export URL
|
|
2347
|
+
- `exportToSheets?: boolean` - Export to Google Sheets and return export URL
|
|
2348
|
+
- If neither provided, returns basic artifact metadata only (use `download()` for content)
|
|
2349
|
+
|
|
2350
|
+
<details>
|
|
2351
|
+
<summary><strong>Validation</strong></summary>
|
|
2352
|
+
|
|
2353
|
+
- Export options (`exportToDocs`, `exportToSheets`) can only be used with `REPORT` artifacts
|
|
2354
|
+
- Throws error if export options are used on non-report artifacts
|
|
2355
|
+
- `notebookId` is required for audio artifacts (must match `artifactId`)
|
|
2356
|
+
|
|
2357
|
+
</details>
|
|
2358
|
+
|
|
2359
|
+
<details>
|
|
2360
|
+
<summary><strong>Notes</strong></summary>
|
|
2361
|
+
|
|
2362
|
+
- Automatically detects artifact type and fetches appropriate content
|
|
2363
|
+
- For `READY` artifacts, returns full data instead of just metadata
|
|
2364
|
+
- For `CREATING` or `FAILED` artifacts, returns metadata only
|
|
2365
|
+
- **Videos & Slides**: Returns URLs only (use `download()` to download files)
|
|
2366
|
+
- **Reports**: Returns basic metadata only (use `download()` for content or export options)
|
|
2367
|
+
- Quiz and flashcards return full structured data
|
|
2368
|
+
- Audio may not include audio data in `get()` - use `download()` to get audio file
|
|
2369
|
+
|
|
2370
|
+
</details>
|
|
2371
|
+
|
|
2372
|
+
**Usage:**
|
|
2373
|
+
```typescript
|
|
2374
|
+
import { ArtifactType, ArtifactState } from 'notebooklm-kit'
|
|
2375
|
+
|
|
2376
|
+
// Get quiz with full data
|
|
2377
|
+
const quiz = await sdk.artifacts.get('quiz-id', 'notebook-id')
|
|
2378
|
+
if (quiz.state === ArtifactState.READY) {
|
|
2379
|
+
console.log(`Quiz: ${quiz.title}`)
|
|
2380
|
+
console.log(`Questions: ${quiz.questions?.length || 0}`)
|
|
2381
|
+
quiz.questions?.forEach((q, i) => {
|
|
2382
|
+
console.log(`Q${i + 1}: ${q.question}`)
|
|
2383
|
+
})
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
// Get flashcards with full data
|
|
2387
|
+
const flashcards = await sdk.artifacts.get('flashcard-id', 'notebook-id')
|
|
2388
|
+
if (flashcards.state === ArtifactState.READY) {
|
|
2389
|
+
console.log(`Total cards: ${flashcards.totalCards}`)
|
|
2390
|
+
flashcards.flashcards?.forEach(card => {
|
|
2391
|
+
console.log(`Q: ${card.question} | A: ${card.answer}`)
|
|
2392
|
+
})
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2395
|
+
// Get video URL (use download() to download file)
|
|
2396
|
+
const video = await sdk.artifacts.get('video-id', 'notebook-id')
|
|
2397
|
+
console.log(`Video URL: ${video.videoData}`)
|
|
2398
|
+
// To download: await sdk.artifacts.download('video-id', './downloads', 'notebook-id')
|
|
2399
|
+
|
|
2400
|
+
// Get slide URLs (use download() to download files)
|
|
2401
|
+
const slides = await sdk.artifacts.get('slide-id', 'notebook-id')
|
|
2402
|
+
console.log(`Slide URLs: ${slides.slideUrls?.length || 0} slides`)
|
|
2403
|
+
slides.slideUrls?.forEach((url, i) => {
|
|
2404
|
+
console.log(`Slide ${i + 1}: ${url}`)
|
|
2405
|
+
})
|
|
2406
|
+
// To download: await sdk.artifacts.download('slide-id', './downloads', 'notebook-id')
|
|
2407
|
+
|
|
2408
|
+
// Get report metadata (use download() for content or export options)
|
|
2409
|
+
const report = await sdk.artifacts.get('report-id', 'notebook-id')
|
|
2410
|
+
console.log(`Report: ${report.title} (${report.state})`)
|
|
2411
|
+
// To get content: await sdk.artifacts.download('report-id', './downloads', 'notebook-id')
|
|
2412
|
+
|
|
2413
|
+
// Export report to Google Docs
|
|
2414
|
+
const report = await sdk.artifacts.get('report-id', 'notebook-id', {
|
|
2415
|
+
exportToDocs: true,
|
|
2416
|
+
})
|
|
2417
|
+
console.log(`Docs URL: ${report.exportUrl}`)
|
|
2418
|
+
|
|
2419
|
+
// Export report to Google Sheets
|
|
2420
|
+
const report = await sdk.artifacts.get('report-id', 'notebook-id', {
|
|
2421
|
+
exportToSheets: true,
|
|
2422
|
+
})
|
|
2423
|
+
console.log(`Sheets URL: ${report.exportUrl}`)
|
|
2424
|
+
|
|
2425
|
+
// Get audio metadata (use download() to get audio file)
|
|
2426
|
+
const audioArtifact = await sdk.artifacts.audio.create('notebook-id')
|
|
2427
|
+
const audio = await sdk.artifacts.get(audioArtifact.audioId, 'notebook-id')
|
|
2428
|
+
console.log(`Audio: ${audio.title} (${audio.state})`)
|
|
2429
|
+
// To download: await sdk.artifacts.download(audioArtifact.audioId, './downloads', 'notebook-id')
|
|
2430
|
+
```
|
|
2431
|
+
|
|
2432
|
+
---
|
|
2433
|
+
|
|
2434
|
+
### Download Artifact
|
|
2435
|
+
|
|
2436
|
+
**Method:** `sdk.artifacts.download(artifactId, folderPath, notebookId?)`
|
|
2437
|
+
|
|
2438
|
+
**Example:** [artifact-download.ts](examples/artifact-download.ts)
|
|
2439
|
+
|
|
2440
|
+
**Parameters:**
|
|
2441
|
+
- `artifactId: string` - The artifact ID from `create()` or `list()` (required)
|
|
2442
|
+
- `folderPath: string` - Output folder path (required)
|
|
2443
|
+
- `notebookId?: string` - Optional notebook ID (helpful for audio/video if download needs it)
|
|
2444
|
+
|
|
2445
|
+
**Returns:** `Promise<{ filePath: string; data: any }>`
|
|
2446
|
+
|
|
2447
|
+
**Description:**
|
|
2448
|
+
Downloads artifact content and saves to disk. Automatically determines file format and saves with appropriate filename.
|
|
2449
|
+
|
|
2450
|
+
**Supported Artifacts:**
|
|
2451
|
+
|
|
2452
|
+
| Type | Format | Filename | Content |
|
|
2453
|
+
|------|--------|----------|---------|
|
|
2454
|
+
| Quiz | JSON | `quiz_{artifactId}_{timestamp}.json` | Complete quiz data with questions, options, answers, explanations |
|
|
2455
|
+
| Flashcards | JSON | `flashcard_{artifactId}_{timestamp}.json` | Complete flashcard data with array, CSV, totalCards |
|
|
2456
|
+
| Audio | Audio file | `audio_{artifactId}.mp3` | Audio file (binary) |
|
|
2457
|
+
| Video | MP4 file | `<artifact-title>.mp4` | Video downloaded as MP4 using Playwright |
|
|
2458
|
+
| Slides | PDF file | `<artifact-title>.pdf` or `<artifact-title>/slide_*.png` | Slides downloaded as PDF (default) or PNG files using Playwright |
|
|
2459
|
+
|
|
2460
|
+
<details>
|
|
2461
|
+
<summary><strong>Notes</strong></summary>
|
|
2462
|
+
|
|
2463
|
+
- Quiz and flashcards are saved as JSON files with complete data
|
|
2464
|
+
- Audio is saved as binary file (format depends on backend)
|
|
2465
|
+
- Video and slides are downloaded using Playwright for authentication
|
|
2466
|
+
- Videos are downloaded as MP4 files
|
|
2467
|
+
- Slides are downloaded as PDF (default) or PNG files
|
|
2468
|
+
- For PDF downloads, `pdf-lib` package is recommended (falls back to PNG if not available)
|
|
2469
|
+
- PNG files are saved in a subfolder named after the artifact
|
|
2470
|
+
- Files are saved with timestamps to avoid overwrites (except for slides which use artifact title)
|
|
2471
|
+
- Returns both file path and parsed data (for quiz/flashcards)
|
|
2472
|
+
|
|
2473
|
+
</details>
|
|
2474
|
+
|
|
2475
|
+
**Usage:**
|
|
2476
|
+
```typescript
|
|
2477
|
+
// Download quiz
|
|
2478
|
+
const result = await sdk.artifacts.download('quiz-id', './downloads', 'notebook-id')
|
|
2479
|
+
console.log(`Saved to: ${result.filePath}`)
|
|
2480
|
+
console.log(`Questions: ${result.data.questions?.length || 0}`)
|
|
2481
|
+
|
|
2482
|
+
// Download flashcards
|
|
2483
|
+
const result = await sdk.artifacts.download('flashcard-id', './downloads', 'notebook-id')
|
|
2484
|
+
console.log(`Saved to: ${result.filePath}`)
|
|
2485
|
+
console.log(`Total cards: ${result.data.totalCards}`)
|
|
2486
|
+
|
|
2487
|
+
// Download audio (use audioId from create() or list())
|
|
2488
|
+
const audio = await sdk.artifacts.audio.create('notebook-id')
|
|
2489
|
+
const result = await sdk.artifacts.download(audio.audioId, './downloads', 'notebook-id')
|
|
2490
|
+
console.log(`Audio saved to: ${result.filePath}`)
|
|
2491
|
+
|
|
2492
|
+
// Download video (use download() method)
|
|
2493
|
+
const result = await sdk.artifacts.download('video-id', './downloads', 'notebook-id')
|
|
2494
|
+
console.log(`Video saved to: ${result.filePath}`)
|
|
2495
|
+
|
|
2496
|
+
// Download slides (use download() method)
|
|
2497
|
+
const slidesResult = await sdk.artifacts.download('slide-id', './downloads', 'notebook-id')
|
|
2498
|
+
console.log(`Slides saved to: ${slidesResult.filePath}`)
|
|
2499
|
+
|
|
2500
|
+
// Download report (use download() method)
|
|
2501
|
+
const reportResult = await sdk.artifacts.download('report-id', './downloads', 'notebook-id')
|
|
2502
|
+
console.log(`Report saved to: ${reportResult.filePath}`)
|
|
2503
|
+
```
|
|
2504
|
+
|
|
2505
|
+
---
|
|
2506
|
+
|
|
2507
|
+
### Download Video
|
|
2508
|
+
|
|
2509
|
+
**Method:** `sdk.artifacts.download(videoId, outputPath, notebookId)`
|
|
2510
|
+
|
|
2511
|
+
**Example:** [artifact-video.ts](examples/artifact-video.ts)
|
|
2512
|
+
|
|
2513
|
+
**Parameters:**
|
|
2514
|
+
- `videoId` (string, required): The video artifact ID
|
|
2515
|
+
- `outputPath` (string, required): Directory path to save the downloaded video
|
|
2516
|
+
- `notebookId` (string, required): The notebook ID containing the video
|
|
2517
|
+
|
|
2518
|
+
**Returns:** `{ filePath: string, data: Artifact }` - File path and artifact data
|
|
2519
|
+
|
|
2520
|
+
**Description:**
|
|
2521
|
+
Downloads a video artifact as an MP4 file. Uses Playwright for authentication and Node's native http/https for reliable download with real-time progress tracking. The video file is saved with the artifact title as the filename.
|
|
2522
|
+
|
|
2523
|
+
**Important Notes:**
|
|
2524
|
+
- **Use `get()` to get video URL**: `get()` returns the video URL in `videoData` field, not a downloaded file
|
|
2525
|
+
- **Use `download()` to download**: `download()` method downloads the video file to disk
|
|
2526
|
+
- Video must be in `READY` state before downloading (check with `get()` first)
|
|
2527
|
+
- Requires `GOOGLE_EMAIL` and `GOOGLE_PASSWORD` environment variables for authentication
|
|
2528
|
+
- Uses Playwright for authentication and Node's http/https for reliable streaming download
|
|
2529
|
+
- Shows real-time download progress (percentage and progress bar)
|
|
2530
|
+
- Video is saved as `<artifact-title>.mp4` in the specified output directory
|
|
2531
|
+
|
|
2532
|
+
**Usage:**
|
|
2533
|
+
```typescript
|
|
2534
|
+
// Get video URL (get() returns URL only)
|
|
2535
|
+
const video = await sdk.artifacts.get('video-id', 'notebook-id')
|
|
2536
|
+
console.log(`Video URL: ${video.videoData}`)
|
|
2537
|
+
|
|
2538
|
+
// Download video (download() saves file to disk)
|
|
2539
|
+
const result = await sdk.artifacts.download('video-id', './downloads', 'notebook-id')
|
|
2540
|
+
console.log(`Video saved to: ${result.filePath}`)
|
|
2541
|
+
```
|
|
2542
|
+
|
|
2543
|
+
**Example Workflow:**
|
|
2544
|
+
```typescript
|
|
2545
|
+
// 1. Check video status and get URL
|
|
2546
|
+
const video = await sdk.artifacts.get('video-id', 'notebook-id')
|
|
2547
|
+
console.log(`Video URL: ${video.videoData}`)
|
|
2548
|
+
if (video.state === ArtifactState.READY) {
|
|
2549
|
+
// 2. Download video
|
|
2550
|
+
const downloaded = await sdk.artifacts.download('video-id', './downloads', 'notebook-id')
|
|
2551
|
+
console.log(`Downloaded: ${downloaded.filePath}`)
|
|
2552
|
+
}
|
|
2553
|
+
```
|
|
2554
|
+
|
|
2555
|
+
---
|
|
2556
|
+
|
|
2557
|
+
### Download Slides
|
|
2558
|
+
|
|
2559
|
+
**Method:** `sdk.artifacts.download(slideId, outputPath, notebookId, { downloadAs })`
|
|
2560
|
+
|
|
2561
|
+
**Example:** [slide-download-test.ts](examples/slide-download-test.ts)
|
|
2562
|
+
|
|
2563
|
+
**Interactive Example (`slide-download-test.ts`):**
|
|
2564
|
+
|
|
2565
|
+
The `slide-download-test.ts` example provides an interactive script for downloading slide decks:
|
|
2566
|
+
|
|
2567
|
+
1. **Lists and selects notebooks** - Shows all available notebooks and prompts for selection
|
|
2568
|
+
2. **Lists and selects slide artifacts** - Displays all ready slide deck artifacts for the selected notebook
|
|
2569
|
+
3. **Extracts slide image URLs** - Recursively searches artifact data structure to find slide image URLs
|
|
2570
|
+
4. **Authenticates with Google** - Uses Playwright to authenticate with Google (handles 2FA)
|
|
2571
|
+
5. **Downloads images** - Downloads each slide image using authenticated browser session
|
|
2572
|
+
6. **Saves in requested format** - Saves as PNG (individual files) or PDF (single file)
|
|
2573
|
+
|
|
2574
|
+
**Environment Variables for `slide-download-test.ts`:**
|
|
2575
|
+
- `NOTEBOOK_ID` - Optional: Pre-select a notebook ID (skips notebook selection)
|
|
2576
|
+
- `GOOGLE_EMAIL` - Required: Google account email for authentication
|
|
2577
|
+
- `GOOGLE_PASSWORD` - Required: Google account password for authentication
|
|
2578
|
+
- `DOWNLOAD_AS` - Optional: `'pdf'` or `'png'` (defaults to interactive prompt)
|
|
2579
|
+
- `OUTPUT_DIR` - Optional: Output directory path (defaults to `./downloads`)
|
|
2580
|
+
|
|
2581
|
+
**Usage:**
|
|
2582
|
+
```bash
|
|
2583
|
+
# Using tsx (recommended)
|
|
2584
|
+
NOTEBOOK_ID=your-notebook-id GOOGLE_EMAIL=your@email.com GOOGLE_PASSWORD=yourpassword DOWNLOAD_AS=pdf npx tsx examples/slide-download-test.ts
|
|
2585
|
+
|
|
2586
|
+
# Or set environment variables separately
|
|
2587
|
+
export GOOGLE_EMAIL=your@email.com
|
|
2588
|
+
export GOOGLE_PASSWORD=yourpassword
|
|
2589
|
+
export DOWNLOAD_AS=pdf
|
|
2590
|
+
npx tsx examples/slide-download-test.ts
|
|
2591
|
+
```
|
|
2592
|
+
|
|
2593
|
+
**SDK Method Parameters:**
|
|
2594
|
+
- `slideId` (string, required): The slide artifact ID
|
|
2595
|
+
- `outputPath` (string, required): Directory path to save the downloaded slides
|
|
2596
|
+
- `notebookId` (string, required): The notebook ID containing the slides
|
|
2597
|
+
- `downloadAs` (string, optional): Download format - `'pdf'` (default) or `'png'`
|
|
2598
|
+
|
|
2599
|
+
**Returns:** `{ filePath: string, data: Artifact }` - File path and artifact data
|
|
2600
|
+
|
|
2601
|
+
**Description:**
|
|
2602
|
+
Downloads a slide deck artifact as PDF (default) or PNG files. Uses Playwright for authentication and handles the download automatically. PDF format saves all slides in a single file, while PNG format saves each slide as a separate image file.
|
|
2603
|
+
|
|
2604
|
+
**Format Options:**
|
|
2605
|
+
|
|
2606
|
+
**PDF (default):**
|
|
2607
|
+
- Single PDF file containing all slides
|
|
2608
|
+
- Filename: `<artifact-title>.pdf`
|
|
2609
|
+
- Saved directly in the output directory
|
|
2610
|
+
|
|
2611
|
+
**PNG:**
|
|
2612
|
+
- Individual PNG files for each slide
|
|
2613
|
+
- Saved in a subfolder named after the artifact: `<artifact-title>/`
|
|
2614
|
+
- Filenames: `slide_1.png`, `slide_2.png`, etc.
|
|
2615
|
+
|
|
2616
|
+
**Important Notes:**
|
|
2617
|
+
- **Use `get()` to get slide URLs**: `get()` returns slide image URLs in `slideUrls` array, not downloaded files
|
|
2618
|
+
- **Use `download()` to download**: `download()` method downloads the slides to disk
|
|
2619
|
+
- Slides must be in `READY` state before downloading (check with `get()` first)
|
|
2620
|
+
- Requires cookies to be configured in the RPC client
|
|
2621
|
+
- Uses Playwright headless browser for authenticated download
|
|
2622
|
+
- PDF generation uses `pdf-lib` if available, falls back to PNG if not installed
|
|
2623
|
+
- PNG files are always saved individually in a subfolder
|
|
2624
|
+
|
|
2625
|
+
**Usage:**
|
|
2626
|
+
```typescript
|
|
2627
|
+
// Get slide URLs (get() returns URLs only)
|
|
2628
|
+
const slides = await sdk.artifacts.get('slide-id', 'notebook-id')
|
|
2629
|
+
console.log(`Slide URLs: ${slides.slideUrls?.length || 0} slides`)
|
|
2630
|
+
slides.slideUrls?.forEach((url, i) => {
|
|
2631
|
+
console.log(`Slide ${i + 1}: ${url}`)
|
|
2632
|
+
})
|
|
2633
|
+
|
|
2634
|
+
// Download as PDF (default) - use download() method
|
|
2635
|
+
const result = await sdk.artifacts.download('slide-id', './downloads', 'notebook-id')
|
|
2636
|
+
console.log(`PDF saved to: ${result.filePath}`)
|
|
2637
|
+
|
|
2638
|
+
// Download as PNG files - use download() method
|
|
2639
|
+
const resultPng = await sdk.artifacts.download('slide-id', './downloads', 'notebook-id', {
|
|
2640
|
+
downloadAs: 'png'
|
|
2641
|
+
})
|
|
2642
|
+
console.log(`PNG files saved to: ${resultPng.filePath}`)
|
|
2643
|
+
```
|
|
2644
|
+
|
|
2645
|
+
**Example Workflow:**
|
|
2646
|
+
```typescript
|
|
2647
|
+
// 1. Check slide status and get URLs
|
|
2648
|
+
const slides = await sdk.artifacts.get('slide-id', 'notebook-id')
|
|
2649
|
+
console.log(`Slide URLs: ${slides.slideUrls?.length || 0} slides`)
|
|
2650
|
+
if (slides.state === ArtifactState.READY) {
|
|
2651
|
+
// 2. Download as PDF (default)
|
|
2652
|
+
const downloaded = await sdk.artifacts.download('slide-id', './downloads', 'notebook-id')
|
|
2653
|
+
console.log(`Downloaded PDF: ${downloaded.filePath}`)
|
|
2654
|
+
|
|
2655
|
+
// Or download as PNG files
|
|
2656
|
+
const pngSlides = await sdk.artifacts.download('slide-id', './downloads', 'notebook-id', {
|
|
2657
|
+
downloadAs: 'png'
|
|
2658
|
+
})
|
|
2659
|
+
console.log(`Downloaded PNGs: ${pngSlides.filePath}`)
|
|
2660
|
+
}
|
|
2661
|
+
```
|
|
2662
|
+
|
|
2663
|
+
---
|
|
2664
|
+
|
|
2665
|
+
### Rename Artifact
|
|
2666
|
+
|
|
2667
|
+
**Method:** `sdk.artifacts.rename(artifactId, newTitle)`
|
|
2668
|
+
|
|
2669
|
+
**Example:** [artifact-rename.ts](examples/artifact-rename.ts)
|
|
2670
|
+
|
|
2671
|
+
**Parameters:**
|
|
2672
|
+
- `artifactId: string` - The artifact ID (required)
|
|
2673
|
+
- `newTitle: string` - New title (required)
|
|
2674
|
+
|
|
2675
|
+
**Returns:** `Promise<Artifact>`
|
|
2676
|
+
|
|
2677
|
+
**Description:**
|
|
2678
|
+
Renames an artifact. Updates only the title field. Works for all artifact types.
|
|
2679
|
+
|
|
2680
|
+
**Return Fields:**
|
|
2681
|
+
Same as `get()` - returns updated artifact with new title
|
|
2682
|
+
|
|
2683
|
+
<details>
|
|
2684
|
+
<summary><strong>Notes</strong></summary>
|
|
2685
|
+
|
|
2686
|
+
- Only updates the title - other fields remain unchanged
|
|
2687
|
+
- Works for all artifact types (quiz, flashcards, report, mind map, infographic, slide deck, audio, video)
|
|
2688
|
+
- Returns full artifact object after update
|
|
2689
|
+
|
|
2690
|
+
</details>
|
|
2691
|
+
|
|
2692
|
+
**Usage:**
|
|
2693
|
+
```typescript
|
|
2694
|
+
// Rename any artifact
|
|
2695
|
+
const updated = await sdk.artifacts.rename('artifact-id', 'My Updated Quiz')
|
|
2696
|
+
console.log(`New title: ${updated.title}`)
|
|
2697
|
+
|
|
2698
|
+
// Rename audio artifact (use audioId from create() or list())
|
|
2699
|
+
const audio = await sdk.artifacts.audio.create('notebook-id')
|
|
2700
|
+
const renamed = await sdk.artifacts.rename(audio.audioId, 'My Audio Overview')
|
|
2701
|
+
```
|
|
2702
|
+
|
|
2703
|
+
---
|
|
2704
|
+
|
|
2705
|
+
### Delete Artifact
|
|
2706
|
+
|
|
2707
|
+
**Method:** `sdk.artifacts.delete(artifactId, notebookId?)`
|
|
2708
|
+
|
|
2709
|
+
**Example:** [artifact-delete.ts](examples/artifact-delete.ts)
|
|
2710
|
+
|
|
2711
|
+
**Parameters:**
|
|
2712
|
+
- `artifactId: string` - The artifact ID from `create()` or `list()` (required)
|
|
2713
|
+
- `notebookId?: string` - Optional notebook ID (helpful if `get()` fails for audio/video)
|
|
2714
|
+
|
|
2715
|
+
**Returns:** `Promise<void>`
|
|
2716
|
+
|
|
2717
|
+
**Description:**
|
|
2718
|
+
Permanently deletes an artifact. Works for all artifact types. This action cannot be undone. Automatically detects artifact type and uses the correct RPC method.
|
|
2719
|
+
|
|
2720
|
+
<details>
|
|
2721
|
+
<summary><strong>Notes</strong></summary>
|
|
2722
|
+
|
|
2723
|
+
- Deletion is permanent and cannot be undone
|
|
2724
|
+
- Works for all artifact types (quiz, flashcards, report, mind map, infographic, slide deck, audio, video)
|
|
2725
|
+
- Automatically detects artifact type by calling `get()` first
|
|
2726
|
+
- Audio and video artifacts use V5N4be RPC with `[[2], artifactId]` structure
|
|
2727
|
+
- Other artifacts use WxBZtb RPC with `[artifactId]` structure
|
|
2728
|
+
- If `get()` fails, tries both methods (V5N4be first, then standard delete)
|
|
2729
|
+
- Audio and video artifacts have their own artifactId (not the notebook ID)
|
|
2730
|
+
|
|
2731
|
+
</details>
|
|
2732
|
+
|
|
2733
|
+
**Usage:**
|
|
2734
|
+
```typescript
|
|
2735
|
+
// Delete any artifact (recommended - automatically detects type)
|
|
2736
|
+
await sdk.artifacts.delete('artifact-id')
|
|
2737
|
+
|
|
2738
|
+
// Delete with notebook ID (helpful if get() fails)
|
|
2739
|
+
await sdk.artifacts.delete('artifact-id', 'notebook-id')
|
|
2740
|
+
|
|
2741
|
+
// Note: Audio and video artifacts have their own artifactId from create() or list()
|
|
2742
|
+
const audio = await sdk.artifacts.audio.create('notebook-id')
|
|
2743
|
+
await sdk.artifacts.delete(audio.audioId) // Use audioId, not notebookId
|
|
2744
|
+
```
|
|
2745
|
+
|
|
2746
|
+
---
|
|
2747
|
+
|
|
2748
|
+
### Share Artifact
|
|
2749
|
+
|
|
2750
|
+
**Method:** `sdk.artifacts.share(notebookId, options)`
|
|
2751
|
+
|
|
2752
|
+
**Example:** [artifact-share.ts](examples/artifact-share.ts)
|
|
2753
|
+
|
|
2754
|
+
**Parameters:**
|
|
2755
|
+
- `notebookId: string` - The notebook ID (required, artifacts are shared at notebook level)
|
|
2756
|
+
- `options: ShareArtifactOptions`
|
|
2757
|
+
- `users?: Array<{email: string, role: 2|3|4}>` - Users to share with (optional)
|
|
2758
|
+
- `notify?: boolean` - Notify users (default: true, only used when users are provided)
|
|
2759
|
+
- `accessType?: 1|2` - Access type: 1=anyone with link, 2=restricted (optional, default: 2)
|
|
2760
|
+
|
|
2761
|
+
**Returns:** `Promise<ShareArtifactResult>`
|
|
2762
|
+
|
|
2763
|
+
**Description:**
|
|
2764
|
+
Shares an artifact (or the notebook containing the artifact) with specific users or makes it publicly accessible via a shareable link. Artifacts are shared at the notebook level, so sharing an artifact shares the entire notebook.
|
|
2765
|
+
|
|
2766
|
+
**User Roles:**
|
|
2767
|
+
|
|
2768
|
+
| Role | Value | Description |
|
|
2769
|
+
|------|-------|-------------|
|
|
2770
|
+
| Editor | `2` | Can edit notebook content |
|
|
2771
|
+
| Viewer | `3` | Can view notebook only |
|
|
2772
|
+
| Remove | `4` | Remove user from shared list |
|
|
2773
|
+
|
|
2774
|
+
**Access Types:**
|
|
2775
|
+
|
|
2776
|
+
| Access Type | Value | Description |
|
|
2777
|
+
|-------------|-------|-------------|
|
|
2778
|
+
| Anyone with link | `1` | Public access via share link |
|
|
2779
|
+
| Restricted | `2` | Only specified users can access |
|
|
2780
|
+
|
|
2781
|
+
**Return Fields:**
|
|
2782
|
+
- `shareUrl: string` - Share URL (always present)
|
|
2783
|
+
- `success: boolean` - Whether the share operation succeeded
|
|
2784
|
+
- `notebookId: string` - The notebook ID that was shared
|
|
2785
|
+
- `accessType: 1|2` - Access type
|
|
2786
|
+
- `isShared: boolean` - Whether the notebook is shared
|
|
2787
|
+
- `users?: Array<{email: string, role: 2|3}>` - Users with access (if users were shared)
|
|
2788
|
+
|
|
2789
|
+
<details>
|
|
2790
|
+
<summary><strong>Validation</strong></summary>
|
|
2791
|
+
|
|
2792
|
+
- Email addresses are validated using regex before sharing
|
|
2793
|
+
- Throws `APIError` if any email is invalid
|
|
2794
|
+
- Must provide either `users` array or `accessType=1` (anyone with link)
|
|
2795
|
+
- Supports multiple users in a single call
|
|
2796
|
+
|
|
2797
|
+
</details>
|
|
2798
|
+
|
|
2799
|
+
<details>
|
|
2800
|
+
<summary><strong>Notes</strong></summary>
|
|
2801
|
+
|
|
2802
|
+
- Artifacts are shared at the notebook level - sharing an artifact shares the entire notebook
|
|
2803
|
+
- `notify` is only used when `users` are provided
|
|
2804
|
+
- Default: `true` (users are notified when permissions change)
|
|
2805
|
+
- Set to `false` to share silently
|
|
2806
|
+
- `shareUrl` is always returned (constructed from notebook ID if not explicitly shared)
|
|
2807
|
+
|
|
2808
|
+
</details>
|
|
2809
|
+
|
|
2810
|
+
**Usage:**
|
|
2811
|
+
```typescript
|
|
2812
|
+
// Share with users (restricted access, notify enabled by default)
|
|
2813
|
+
const result = await sdk.artifacts.share('notebook-id', {
|
|
2814
|
+
users: [
|
|
2815
|
+
{ email: 'user1@example.com', role: 2 }, // editor
|
|
2816
|
+
{ email: 'user2@example.com', role: 3 }, // viewer
|
|
2817
|
+
],
|
|
2818
|
+
notify: true,
|
|
2819
|
+
accessType: 2, // restricted
|
|
2820
|
+
})
|
|
2821
|
+
|
|
2822
|
+
// Share with users (silent, no notification)
|
|
2823
|
+
const result = await sdk.artifacts.share('notebook-id', {
|
|
2824
|
+
users: [
|
|
2825
|
+
{ email: 'user@example.com', role: 2 },
|
|
2826
|
+
],
|
|
2827
|
+
notify: false,
|
|
2828
|
+
accessType: 2,
|
|
2829
|
+
})
|
|
2830
|
+
|
|
2831
|
+
// Enable link sharing (anyone with link)
|
|
2832
|
+
const result = await sdk.artifacts.share('notebook-id', {
|
|
2833
|
+
accessType: 1, // anyone with link
|
|
2834
|
+
})
|
|
2835
|
+
console.log(`Share URL: ${result.shareUrl}`)
|
|
2836
|
+
|
|
2837
|
+
// Remove user (role: 4)
|
|
2838
|
+
const result = await sdk.artifacts.share('notebook-id', {
|
|
2839
|
+
users: [
|
|
2840
|
+
{ email: 'user@example.com', role: 4 }, // remove
|
|
2841
|
+
],
|
|
2842
|
+
accessType: 2,
|
|
2843
|
+
})
|
|
2844
|
+
```
|
|
2845
|
+
|
|
2846
|
+
## Generation & Chat
|
|
2847
|
+
|
|
2848
|
+
Examples: [chat-basic.ts](examples/chat-basic.ts) | [chat-conversation.ts](examples/chat-conversation.ts) | [generation-set-chat-config.ts](examples/generation-set-chat-config.ts)
|
|
2849
|
+
|
|
2850
|
+
**Key Features:**
|
|
2851
|
+
- ✅ **Streaming & Non-streaming modes** - Choose real-time streaming (`chatStream()`) or complete responses (`chat()`)
|
|
2852
|
+
- ✅ **Source selection** - Chat with all sources or specific ones (interactive or programmatic)
|
|
2853
|
+
- ✅ **Citation extraction** - Automatic citation tracking from responses
|
|
2854
|
+
- ✅ **Conversation management** - Track conversations with IDs and history
|
|
2855
|
+
- ✅ **Type-safe configuration** - Full TypeScript support with `ChatConfig` interface
|
|
2856
|
+
- ✅ **Improved parser** - Based on Python SDK implementation for better reliability
|
|
2857
|
+
|
|
2858
|
+
**Choosing Between `chat()` and `chatStream()`:**
|
|
2859
|
+
- **Use `chat()`** when you want the complete response at once (simpler, blocking)
|
|
2860
|
+
- Returns complete response text after all chunks are received
|
|
2861
|
+
- Best for scripts, automation, or when you need the full response before processing
|
|
2862
|
+
- Use the `--no-stream` flag in the example script
|
|
2863
|
+
- **Use `chatStream()`** when you want real-time updates (better UX, progressive display)
|
|
2864
|
+
- Yields chunks as they arrive for real-time display
|
|
2865
|
+
- Automatically handles thinking content buffering and revision detection
|
|
2866
|
+
- Only displays the final response (no thinking steps or revision markers)
|
|
2867
|
+
- Best for interactive applications or when you want immediate feedback
|
|
2868
|
+
- Both methods support the same options (source selection, conversation history, etc.)
|
|
2869
|
+
- Both methods extract citations and track conversation metadata
|
|
2870
|
+
|
|
2871
|
+
---
|
|
2872
|
+
|
|
2873
|
+
### Chat (Non-Streaming)
|
|
2874
|
+
|
|
2875
|
+
**Method:** `sdk.generation.chat(notebookId, prompt, options?)`
|
|
2876
|
+
|
|
2877
|
+
**Examples:**
|
|
2878
|
+
- [chat-basic.ts](examples/chat-basic.ts) - Basic chat with all sources
|
|
2879
|
+
- [chat-conversation.ts](examples/chat-conversation.ts) - Chat with conversation history
|
|
2880
|
+
|
|
2881
|
+
**Note:** The SDK now uses an improved parser based on the Python SDK implementation, providing better error handling, citation extraction, and streaming support. The chat request format has been restructured to match the official API format for better compatibility.
|
|
2882
|
+
|
|
2883
|
+
**Parameters:**
|
|
2884
|
+
- `notebookId: string` - The notebook ID (required)
|
|
2885
|
+
- `prompt: string` - Chat message/prompt (required)
|
|
2886
|
+
- `options?: object` - Optional chat options:
|
|
2887
|
+
- `sourceIds?: string[]` - Specific source IDs to query (uses all sources if omitted)
|
|
2888
|
+
- `conversationHistory?: Array<{ message: string; role: 'user' | 'assistant' }>` - Conversation history for follow-up messages
|
|
2889
|
+
- `conversationId?: string` - Conversation ID for continuing a conversation (auto-generated if not provided)
|
|
2890
|
+
|
|
2891
|
+
**Returns:** `Promise<ChatResponseData>` - Complete AI response with metadata
|
|
2892
|
+
|
|
2893
|
+
**Type Import:**
|
|
2894
|
+
```typescript
|
|
2895
|
+
import type { ChatResponseData } from 'notebooklm-kit';
|
|
2896
|
+
```
|
|
2897
|
+
|
|
2898
|
+
**ChatResponseData Interface:**
|
|
2899
|
+
```typescript
|
|
2900
|
+
interface ChatResponseData {
|
|
2901
|
+
text: string; // Complete response text (thinking headers removed)
|
|
2902
|
+
rawData?: any; // Raw response data from API
|
|
2903
|
+
chunks?: StreamChunk[]; // All chunks received during streaming
|
|
2904
|
+
conversationId?: string; // Conversation ID for continuing the conversation
|
|
2905
|
+
citations: number[]; // Citation numbers extracted from response
|
|
2906
|
+
}
|
|
2907
|
+
```
|
|
2908
|
+
|
|
2909
|
+
**Description:**
|
|
2910
|
+
Chat with your notebook content using AI. Returns the complete response after all chunks are received. This is the non-streaming mode - use `chatStream()` for real-time streaming responses.
|
|
2911
|
+
|
|
2912
|
+
**Response Format:**
|
|
2913
|
+
- `text`: The complete response text with thinking headers automatically removed
|
|
2914
|
+
- `rawData`: Raw response structure from the API (for advanced use cases)
|
|
2915
|
+
- `chunks`: Array of all stream chunks received (if you need to inspect individual chunks)
|
|
2916
|
+
- `conversationId`: ID for continuing the conversation
|
|
2917
|
+
- `citations`: Array of citation numbers found in the response (e.g., `[1, 2, 3]`)
|
|
2918
|
+
|
|
2919
|
+
**Features:**
|
|
2920
|
+
- ✅ Automatic source detection (uses all sources if none specified)
|
|
2921
|
+
- ✅ Source selection support (filter to specific sources)
|
|
2922
|
+
- ✅ Conversation history tracking
|
|
2923
|
+
- ✅ Citation extraction
|
|
2924
|
+
- ✅ Conversation ID management
|
|
2925
|
+
- ✅ Type-safe options
|
|
2926
|
+
|
|
2927
|
+
<details>
|
|
2928
|
+
<summary><strong>Notes</strong></summary>
|
|
2929
|
+
|
|
2930
|
+
- **Response format**: Returns `ChatResponseData` object with `text`, `citations`, `conversationId`, etc.
|
|
2931
|
+
- **Text extraction**: The `text` field contains the complete response with thinking headers automatically removed
|
|
2932
|
+
- **Citation extraction**: Citations are automatically extracted and available in the `citations` array
|
|
2933
|
+
- **Conversation tracking**: Conversation ID is auto-generated if not provided and returned in response
|
|
2934
|
+
- **Source selection**: If `sourceIds` is provided, only those sources are used for context
|
|
2935
|
+
- **Auto source detection**: If `sourceIds` is omitted, all sources in the notebook are automatically fetched and used
|
|
2936
|
+
- **Conversation history**: Use `conversationHistory` for follow-up messages to maintain context
|
|
2937
|
+
- **Quota management**: Quota is checked before chat (if quota manager is enabled)
|
|
2938
|
+
- **Usage tracking**: Usage is recorded after successful chat
|
|
2939
|
+
- **Response aggregation**: Response is aggregated from all streaming chunks and returned as complete text
|
|
2940
|
+
- **For streaming**: Use `chatStream()` for real-time streaming responses
|
|
2941
|
+
|
|
2942
|
+
</details>
|
|
2943
|
+
|
|
2944
|
+
**Usage:**
|
|
2945
|
+
```typescript
|
|
2946
|
+
// Chat with all sources (non-streaming)
|
|
2947
|
+
const response = await sdk.generation.chat(
|
|
2948
|
+
'notebook-id',
|
|
2949
|
+
'What are the main findings from the research?'
|
|
2950
|
+
)
|
|
2951
|
+
console.log(response.text) // Complete response text
|
|
2952
|
+
console.log(`Citations: [${response.citations.join(', ')}]`)
|
|
2953
|
+
console.log(`Conversation ID: ${response.conversationId}`)
|
|
2954
|
+
|
|
2955
|
+
// Chat with specific sources
|
|
2956
|
+
const response = await sdk.generation.chat(
|
|
2957
|
+
'notebook-id',
|
|
2958
|
+
'Summarize the methodology section',
|
|
2959
|
+
{ sourceIds: ['source-id-1', 'source-id-2'] }
|
|
2960
|
+
)
|
|
2961
|
+
console.log(response.text)
|
|
2962
|
+
|
|
2963
|
+
// Follow-up message with conversation history
|
|
2964
|
+
const response1 = await sdk.generation.chat('notebook-id', 'What is machine learning?')
|
|
2965
|
+
const response2 = await sdk.generation.chat('notebook-id', 'Tell me more', {
|
|
2966
|
+
conversationId: response1.conversationId,
|
|
2967
|
+
conversationHistory: [
|
|
2968
|
+
{ message: 'What is machine learning?', role: 'user' },
|
|
2969
|
+
{ message: response1.text, role: 'assistant' }
|
|
2970
|
+
]
|
|
2971
|
+
})
|
|
2972
|
+
console.log(response2.text)
|
|
2973
|
+
```
|
|
2974
|
+
|
|
2975
|
+
---
|
|
2976
|
+
|
|
2977
|
+
### Chat Stream (Streaming)
|
|
2978
|
+
|
|
2979
|
+
**Method:** `sdk.generation.chatStream(notebookId, prompt, options?)`
|
|
2980
|
+
|
|
2981
|
+
**Examples:**
|
|
2982
|
+
- [chat-basic.ts](examples/chat-basic.ts) - Streaming chat with all sources
|
|
2983
|
+
- [chat-conversation.ts](examples/chat-conversation.ts) - Streaming multi-turn conversations
|
|
2984
|
+
|
|
2985
|
+
**Parameters:**
|
|
2986
|
+
- `notebookId: string` - The notebook ID (required)
|
|
2987
|
+
- `prompt: string` - Chat message/prompt (required)
|
|
2988
|
+
- `options?: object` - Optional chat options:
|
|
2989
|
+
- `sourceIds?: string[]` - Specific source IDs to query (uses all sources if omitted)
|
|
2990
|
+
- `conversationHistory?: Array<{ message: string; role: 'user' | 'assistant' }>` - Conversation history for follow-up messages
|
|
2991
|
+
- `conversationId?: string` - Conversation ID for continuing a conversation (auto-generated if not provided)
|
|
2992
|
+
- `onChunk?: (chunk: StreamChunk) => void` - Callback function called for each chunk
|
|
2993
|
+
- `showThinking?: boolean` - Whether to include thinking process in output (default: false)
|
|
2994
|
+
|
|
2995
|
+
**Returns:** `AsyncGenerator<StreamChunk, void, unknown>` - Async generator yielding stream chunks
|
|
2996
|
+
|
|
2997
|
+
**Type Import:**
|
|
2998
|
+
```typescript
|
|
2999
|
+
import type { StreamChunk } from 'notebooklm-kit';
|
|
3000
|
+
```
|
|
3001
|
+
|
|
3002
|
+
**Description:**
|
|
3003
|
+
Stream chat responses in real-time. Returns an async generator that yields chunks as they arrive from the API. Each chunk contains the **full accumulated text** up to that point (snapshot-based, not delta-based), allowing you to display responses as they're generated.
|
|
3004
|
+
|
|
3005
|
+
**Key Behaviors:**
|
|
3006
|
+
- **Snapshot-based streaming**: Each `chunk.text` contains the complete response accumulated so far, not just the new portion
|
|
3007
|
+
- **Thinking content buffering**: Thinking content (marked with `**Header**`) is automatically buffered and only the final response is displayed
|
|
3008
|
+
- **Revision detection**: If the AI revises its response mid-stream, the revision is automatically handled and only the final version is shown
|
|
3009
|
+
- **No revision markers**: The streaming client automatically filters out thinking steps and revision markers for a clean output
|
|
3010
|
+
|
|
3011
|
+
**StreamChunk Interface:**
|
|
3012
|
+
```typescript
|
|
3013
|
+
interface StreamChunk {
|
|
3014
|
+
chunkNumber: number; // Chunk number (1-based, increments with each chunk)
|
|
3015
|
+
byteCount: number; // Byte count for this chunk
|
|
3016
|
+
text: string; // FULL accumulated text from start to this point (snapshot-based)
|
|
3017
|
+
thinking: string[]; // Thinking headers extracted from text (e.g., ["Analyzing sources", "Formulating response"])
|
|
3018
|
+
response: string; // Response text with thinking headers removed
|
|
3019
|
+
metadata?: [string, string, number]; // [conversationId, messageId, timestamp]
|
|
3020
|
+
messageIds?: [string, string]; // Message IDs: [conversationId, messageId]
|
|
3021
|
+
timestamp?: number; // Timestamp from metadata
|
|
3022
|
+
citations?: number[]; // Citation numbers extracted from text (e.g., [1, 2, 3])
|
|
3023
|
+
rawData?: any; // Raw parsed data from API
|
|
3024
|
+
isError?: boolean; // Is this an error chunk?
|
|
3025
|
+
errorCode?: number; // Error code if isError is true
|
|
3026
|
+
isThinking?: boolean; // Does this chunk contain thinking content?
|
|
3027
|
+
isResponse?: boolean; // Does this chunk contain response content?
|
|
3028
|
+
formatting?: any; // Formatting information
|
|
3029
|
+
}
|
|
3030
|
+
```
|
|
3031
|
+
|
|
3032
|
+
**Important Notes:**
|
|
3033
|
+
- `chunk.text` contains the **complete accumulated response** (not incremental)
|
|
3034
|
+
- To display incrementally, compare `chunk.text.length` with previous chunk length
|
|
3035
|
+
- Thinking content is automatically filtered - you'll only see the final response
|
|
3036
|
+
- Citations are extracted from the text using pattern matching `[1]`, `[2]`, etc.
|
|
3037
|
+
- Conversation ID is available in `chunk.metadata[0]` or `chunk.messageIds[0]`
|
|
3038
|
+
|
|
3039
|
+
**Features:**
|
|
3040
|
+
- ✅ Real-time streaming responses
|
|
3041
|
+
- ✅ Citation extraction from each chunk
|
|
3042
|
+
- ✅ Conversation metadata tracking
|
|
3043
|
+
- ✅ Thinking/response separation
|
|
3044
|
+
- ✅ Error detection and handling
|
|
3045
|
+
- ✅ Progress callbacks via `onChunk`
|
|
3046
|
+
|
|
3047
|
+
<details>
|
|
3048
|
+
<summary><strong>Notes</strong></summary>
|
|
3049
|
+
|
|
3050
|
+
- **Snapshot-based streaming**: Each `chunk.text` contains the complete accumulated response from the start, not just the new portion
|
|
3051
|
+
- **Incremental display**: To display incrementally, compare `chunk.text.length` with previous chunk length and extract the new portion
|
|
3052
|
+
- **Thinking content handling**: Thinking content (marked with `**Header**`) is automatically buffered and filtered - only the final response is displayed
|
|
3053
|
+
- **Revision detection**: If the AI revises its response mid-stream, the revision is automatically detected and only the final version is shown
|
|
3054
|
+
- **No revision markers**: The client automatically handles revisions without showing "Response revised by AI" markers
|
|
3055
|
+
- **Citation extraction**: Citations are automatically extracted from text using pattern matching `[1]`, `[2]`, etc.
|
|
3056
|
+
- **Conversation tracking**: Conversation ID and message IDs are available in `chunk.metadata` or `chunk.messageIds`
|
|
3057
|
+
- **Quota management**: Quota is checked before streaming starts (if quota manager is enabled)
|
|
3058
|
+
- **Usage tracking**: Usage is recorded after streaming completes
|
|
3059
|
+
- **Callback support**: Use `onChunk` callback for real-time processing of each chunk
|
|
3060
|
+
- **Error handling**: Error chunks are detected via `chunk.isError` and `chunk.errorCode`
|
|
3061
|
+
|
|
3062
|
+
</details>
|
|
3063
|
+
|
|
3064
|
+
**Usage:**
|
|
3065
|
+
|
|
3066
|
+
**Basic Streaming (Snapshot-based):**
|
|
3067
|
+
```typescript
|
|
3068
|
+
// Since chunk.text contains the FULL accumulated response, display incrementally
|
|
3069
|
+
let lastDisplayedLength = 0;
|
|
3070
|
+
|
|
3071
|
+
for await (const chunk of sdk.generation.chatStream('notebook-id', 'What is this about?')) {
|
|
3072
|
+
// chunk.text contains complete response so far - extract only new portion
|
|
3073
|
+
if (chunk.text.length > lastDisplayedLength) {
|
|
3074
|
+
const newText = chunk.text.substring(lastDisplayedLength);
|
|
3075
|
+
process.stdout.write(newText);
|
|
3076
|
+
lastDisplayedLength = chunk.text.length;
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
```
|
|
3080
|
+
|
|
3081
|
+
**Simple Streaming (Using response field):**
|
|
3082
|
+
```typescript
|
|
3083
|
+
// Use chunk.response which has thinking headers already removed
|
|
3084
|
+
let lastResponseLength = 0;
|
|
3085
|
+
|
|
3086
|
+
for await (const chunk of sdk.generation.chatStream('notebook-id', 'Explain this')) {
|
|
3087
|
+
if (chunk.response && chunk.response.length > lastResponseLength) {
|
|
3088
|
+
const newText = chunk.response.substring(lastResponseLength);
|
|
3089
|
+
process.stdout.write(newText);
|
|
3090
|
+
lastResponseLength = chunk.response.length;
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
```
|
|
3094
|
+
|
|
3095
|
+
**Streaming with Callback:**
|
|
3096
|
+
```typescript
|
|
3097
|
+
for await (const chunk of sdk.generation.chatStream('notebook-id', 'Explain this', {
|
|
3098
|
+
onChunk: (chunk) => {
|
|
3099
|
+
console.log(`Chunk ${chunk.chunkNumber}: ${chunk.byteCount} bytes`);
|
|
3100
|
+
if (chunk.citations && chunk.citations.length > 0) {
|
|
3101
|
+
console.log(`Citations: ${chunk.citations.join(', ')}`);
|
|
3102
|
+
}
|
|
3103
|
+
}
|
|
3104
|
+
})) {
|
|
3105
|
+
// Display incrementally
|
|
3106
|
+
if (chunk.text.length > lastDisplayedLength) {
|
|
3107
|
+
const newText = chunk.text.substring(lastDisplayedLength);
|
|
3108
|
+
process.stdout.write(newText);
|
|
3109
|
+
lastDisplayedLength = chunk.text.length;
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
3112
|
+
```
|
|
3113
|
+
|
|
3114
|
+
**Streaming with Specific Sources:**
|
|
3115
|
+
```typescript
|
|
3116
|
+
let lastDisplayedLength = 0;
|
|
3117
|
+
|
|
3118
|
+
for await (const chunk of sdk.generation.chatStream(
|
|
3119
|
+
'notebook-id',
|
|
3120
|
+
'Compare these sources',
|
|
3121
|
+
{ sourceIds: ['source-id-1', 'source-id-2'] }
|
|
3122
|
+
)) {
|
|
3123
|
+
if (chunk.text.length > lastDisplayedLength) {
|
|
3124
|
+
const newText = chunk.text.substring(lastDisplayedLength);
|
|
3125
|
+
process.stdout.write(newText);
|
|
3126
|
+
lastDisplayedLength = chunk.text.length;
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
3129
|
+
```
|
|
3130
|
+
|
|
3131
|
+
**Collect Citations and Metadata:**
|
|
3132
|
+
```typescript
|
|
3133
|
+
const citations = new Set<number>();
|
|
3134
|
+
let conversationId: string | undefined;
|
|
3135
|
+
let messageIds: [string, string] | undefined;
|
|
3136
|
+
let lastDisplayedLength = 0;
|
|
3137
|
+
|
|
3138
|
+
for await (const chunk of sdk.generation.chatStream('notebook-id', 'What are the key findings?')) {
|
|
3139
|
+
// Track conversation ID and message IDs
|
|
3140
|
+
if (chunk.metadata) {
|
|
3141
|
+
conversationId = chunk.metadata[0];
|
|
3142
|
+
messageIds = chunk.metadata.slice(0, 2) as [string, string];
|
|
3143
|
+
}
|
|
3144
|
+
|
|
3145
|
+
// Collect citations
|
|
3146
|
+
if (chunk.citations) {
|
|
3147
|
+
chunk.citations.forEach(citation => citations.add(citation));
|
|
3148
|
+
}
|
|
3149
|
+
|
|
3150
|
+
// Display response incrementally
|
|
3151
|
+
if (chunk.text.length > lastDisplayedLength) {
|
|
3152
|
+
const newText = chunk.text.substring(lastDisplayedLength);
|
|
3153
|
+
process.stdout.write(newText);
|
|
3154
|
+
lastDisplayedLength = chunk.text.length;
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
console.log(`\nConversation ID: ${conversationId}`);
|
|
3159
|
+
console.log(`Message IDs: ${messageIds?.join(', ')}`);
|
|
3160
|
+
console.log(`Citations: [${Array.from(citations).sort((a, b) => a - b).join(', ')}]`);
|
|
3161
|
+
```
|
|
3162
|
+
|
|
3163
|
+
**Example Output Format:**
|
|
3164
|
+
```
|
|
3165
|
+
The provided sources primarily discuss the field of Artificial Intelligence (AI)
|
|
3166
|
+
and the transformative research paper "Attention Is All You Need" [1, 2].
|
|
3167
|
+
|
|
3168
|
+
The transformer architecture introduced in 2017 revolutionized AI by enabling
|
|
3169
|
+
parallel processing and becoming the foundation for modern large language models [3, 4].
|
|
3170
|
+
```
|
|
3171
|
+
|
|
3172
|
+
**Note:** The streaming client automatically:
|
|
3173
|
+
- Buffers thinking content (won't display it)
|
|
3174
|
+
- Detects and handles revisions (only shows final response)
|
|
3175
|
+
- Removes thinking headers from output
|
|
3176
|
+
- Extracts citations from text
|
|
3177
|
+
- Tracks conversation metadata
|
|
3178
|
+
|
|
3179
|
+
---
|
|
3180
|
+
|
|
3181
|
+
### Set Chat Configuration
|
|
3182
|
+
|
|
3183
|
+
**Method:** `sdk.generation.setChatConfig(notebookId, config)`
|
|
3184
|
+
|
|
3185
|
+
**Example:** [generation-set-chat-config.ts](examples/generation-set-chat-config.ts)
|
|
3186
|
+
|
|
3187
|
+
**Parameters:**
|
|
3188
|
+
- `notebookId: string` - The notebook ID (required)
|
|
3189
|
+
- `config: ChatConfig` - Chat configuration object (type-safe):
|
|
3190
|
+
- `type: 'default' | 'custom' | 'learning-guide'` - Configuration type (required)
|
|
3191
|
+
- `customText?: string` - Custom prompt text (required if type is 'custom')
|
|
3192
|
+
- `responseLength: 'default' | 'shorter' | 'longer'` - Response length (required)
|
|
3193
|
+
|
|
3194
|
+
**Returns:** `Promise<any>` - Configuration result
|
|
3195
|
+
|
|
3196
|
+
**Type Import:**
|
|
3197
|
+
```typescript
|
|
3198
|
+
import type { ChatConfig } from 'notebooklm-kit';
|
|
3199
|
+
```
|
|
3200
|
+
|
|
3201
|
+
**Description:**
|
|
3202
|
+
Configure chat behavior before sending messages. Set the chat mode (default, custom prompt, or learning guide) and response length. This configuration affects all subsequent chat messages until changed. This is optional - you can use chat without setting configuration.
|
|
3203
|
+
|
|
3204
|
+
**Configuration Types:**
|
|
3205
|
+
- **`default`**: Standard conversational responses - balanced and informative
|
|
3206
|
+
- **`custom`**: Responses following a custom instruction/persona (requires `customText`)
|
|
3207
|
+
- **`learning-guide`**: Educational responses optimized for learning and understanding
|
|
3208
|
+
|
|
3209
|
+
**Response Lengths:**
|
|
3210
|
+
- **`default`**: Standard length responses - balanced detail
|
|
3211
|
+
- **`shorter`**: Concise, brief responses - quick summaries
|
|
3212
|
+
- **`longer`**: Detailed, comprehensive responses - in-depth explanations
|
|
3213
|
+
|
|
3214
|
+
**Usage:**
|
|
3215
|
+
```typescript
|
|
3216
|
+
// Set default configuration
|
|
3217
|
+
await sdk.generation.setChatConfig('notebook-id', {
|
|
3218
|
+
type: 'default',
|
|
3219
|
+
responseLength: 'default'
|
|
3220
|
+
})
|
|
3221
|
+
|
|
3222
|
+
// Set custom configuration with custom prompt
|
|
3223
|
+
await sdk.generation.setChatConfig('notebook-id', {
|
|
3224
|
+
type: 'custom',
|
|
3225
|
+
customText: 'respond as a PhD student explaining complex concepts simply',
|
|
3226
|
+
responseLength: 'longer'
|
|
3227
|
+
})
|
|
3228
|
+
|
|
3229
|
+
// Set learning guide configuration
|
|
3230
|
+
await sdk.generation.setChatConfig('notebook-id', {
|
|
3231
|
+
type: 'learning-guide',
|
|
3232
|
+
responseLength: 'shorter'
|
|
3233
|
+
})
|
|
3234
|
+
|
|
3235
|
+
// Example: Configure for academic writing style
|
|
3236
|
+
await sdk.generation.setChatConfig('notebook-id', {
|
|
3237
|
+
type: 'custom',
|
|
3238
|
+
customText: 'respond in an academic writing style with citations',
|
|
3239
|
+
responseLength: 'longer'
|
|
3240
|
+
})
|
|
3241
|
+
```
|
|
3242
|
+
|
|
3243
|
+
**Note:** Configuration persists for the notebook until changed. You can update it anytime by calling `setChatConfig()` again with new values.
|
|
3244
|
+
|
|
3245
|
+
---
|
|
3246
|
+
|
|
3247
|
+
---
|
|
3248
|
+
- ⚠️ This action is permanent and cannot be undone
|
|
3249
|
+
- Each conversation has a unique ID that persists across sessions
|
|
3250
|
+
- Use conversation IDs to manage multiple parallel conversations
|
|
3251
|
+
- Deleting a conversation removes all message history for that conversation
|
|
3252
|
+
|
|
3253
|
+
---
|
|
3254
|
+
|
|
3255
|
+
## Notes
|
|
3256
|
+
|
|
3257
|
+
Examples: [note-list.ts](examples/note-list.ts) | [note-create.ts](examples/note-create.ts) | [note-update.ts](examples/note-update.ts) | [note-delete.ts](examples/note-delete.ts)
|
|
3258
|
+
|
|
3259
|
+
### List Notes
|
|
3260
|
+
|
|
3261
|
+
**Method:** `sdk.notes.list(notebookId)`
|
|
3262
|
+
|
|
3263
|
+
**Example:** [note-list.ts](examples/note-list.ts)
|
|
3264
|
+
|
|
3265
|
+
**Parameters:**
|
|
3266
|
+
- `notebookId: string` - The notebook ID (required)
|
|
3267
|
+
|
|
3268
|
+
**Returns:** `Promise<Note[]>`
|
|
3269
|
+
|
|
3270
|
+
**Description:**
|
|
3271
|
+
Lists all notes in a notebook. Returns an array of notes with their titles, content, and metadata.
|
|
3272
|
+
|
|
3273
|
+
**Return Fields:**
|
|
3274
|
+
- `noteId: string` - Unique note ID (required for update/delete operations)
|
|
3275
|
+
- `title: string` - Note title
|
|
3276
|
+
- `content: string` - Note content
|
|
3277
|
+
- `tags?: string[]` - Note tags (if any)
|
|
3278
|
+
- `createdAt?: string` - Creation timestamp (if available)
|
|
3279
|
+
- `updatedAt?: string` - Last modified timestamp (if available)
|
|
3280
|
+
|
|
3281
|
+
<details>
|
|
3282
|
+
<summary><strong>Notes</strong></summary>
|
|
3283
|
+
|
|
3284
|
+
- Returns empty array if notebook has no notes
|
|
3285
|
+
- Notes are returned in the order they appear in the notebook
|
|
3286
|
+
- Content may be truncated in list view (use individual note operations for full content)
|
|
3287
|
+
- Tags are optional and may be empty
|
|
3288
|
+
|
|
3289
|
+
</details>
|
|
3290
|
+
|
|
3291
|
+
**Usage:**
|
|
3292
|
+
```typescript
|
|
3293
|
+
const notes = await sdk.notes.list('notebook-id')
|
|
3294
|
+
console.log(`Found ${notes.length} notes`)
|
|
3295
|
+
|
|
3296
|
+
notes.forEach((note, index) => {
|
|
3297
|
+
console.log(`${index + 1}. ${note.title}`)
|
|
3298
|
+
console.log(` ID: ${note.noteId}`)
|
|
3299
|
+
if (note.tags && note.tags.length > 0) {
|
|
3300
|
+
console.log(` Tags: ${note.tags.join(', ')}`)
|
|
3301
|
+
}
|
|
3302
|
+
})
|
|
3303
|
+
```
|
|
3304
|
+
|
|
3305
|
+
---
|
|
3306
|
+
|
|
3307
|
+
### Create Note
|
|
3308
|
+
|
|
3309
|
+
**Method:** `sdk.notes.create(notebookId, options)`
|
|
3310
|
+
|
|
3311
|
+
**Example:** [note-create.ts](examples/note-create.ts)
|
|
3312
|
+
|
|
3313
|
+
**Parameters:**
|
|
3314
|
+
- `notebookId: string` - The notebook ID (required)
|
|
3315
|
+
- `options: CreateNoteOptions`
|
|
3316
|
+
- `title: string` - Note title (required)
|
|
3317
|
+
- `content?: string` - Note content (optional, defaults to empty string)
|
|
3318
|
+
- `tags?: string[]` - Note tags (optional)
|
|
3319
|
+
- `noteType?: NoteType[]` - Note type (optional, defaults to `[NoteType.REGULAR]`)
|
|
3320
|
+
|
|
3321
|
+
**Returns:** `Promise<Note>`
|
|
3322
|
+
|
|
3323
|
+
**Description:**
|
|
3324
|
+
Creates a new note in the notebook. Notes are useful for adding your own annotations, reminders, or summaries alongside the notebook content.
|
|
3325
|
+
|
|
3326
|
+
**Return Fields:**
|
|
3327
|
+
- `noteId: string` - Unique note ID (use this for update/delete operations)
|
|
3328
|
+
- `title: string` - Note title (as provided)
|
|
3329
|
+
- `content: string` - Note content (may be empty initially)
|
|
3330
|
+
|
|
3331
|
+
<details>
|
|
3332
|
+
<summary><strong>Notes</strong></summary>
|
|
3333
|
+
|
|
3334
|
+
- Title is required - cannot create a note without a title
|
|
3335
|
+
- Content is optional and can be added later via `update()`
|
|
3336
|
+
- Tags are optional and can be added during creation or later
|
|
3337
|
+
- Note type defaults to `REGULAR` (1) - use `GENERATED` (2) for AI-generated notes
|
|
3338
|
+
- Returns immediately with note ID - no waiting required
|
|
3339
|
+
|
|
3340
|
+
</details>
|
|
3341
|
+
|
|
3342
|
+
**Usage:**
|
|
3343
|
+
```typescript
|
|
3344
|
+
// Create a simple note
|
|
3345
|
+
const note = await sdk.notes.create('notebook-id', {
|
|
3346
|
+
title: 'Meeting Notes',
|
|
3347
|
+
content: 'Key points from today\'s meeting...',
|
|
3348
|
+
})
|
|
3349
|
+
console.log(`Created note: ${note.noteId}`)
|
|
3350
|
+
|
|
3351
|
+
// Create a note with tags
|
|
3352
|
+
const note = await sdk.notes.create('notebook-id', {
|
|
3353
|
+
title: 'Research Findings',
|
|
3354
|
+
content: 'Important findings...',
|
|
3355
|
+
tags: ['research', 'findings'],
|
|
3356
|
+
})
|
|
3357
|
+
|
|
3358
|
+
// Create a note with just a title (add content later)
|
|
3359
|
+
const note = await sdk.notes.create('notebook-id', {
|
|
3360
|
+
title: 'Quick Reminder',
|
|
3361
|
+
})
|
|
3362
|
+
```
|
|
3363
|
+
|
|
3364
|
+
---
|
|
3365
|
+
|
|
3366
|
+
### Update Note
|
|
3367
|
+
|
|
3368
|
+
**Method:** `sdk.notes.update(notebookId, noteId, options)`
|
|
3369
|
+
|
|
3370
|
+
**Example:** [note-update.ts](examples/note-update.ts)
|
|
3371
|
+
|
|
3372
|
+
**Parameters:**
|
|
3373
|
+
- `notebookId: string` - The notebook ID (required)
|
|
3374
|
+
- `noteId: string` - The note ID (required)
|
|
3375
|
+
- `options: UpdateNoteOptions`
|
|
3376
|
+
- `title?: string` - New title (optional, defaults to empty string)
|
|
3377
|
+
- `content?: string` - New content (optional, defaults to empty string)
|
|
3378
|
+
- `tags?: string[]` - New tags (optional, defaults to empty array)
|
|
3379
|
+
|
|
3380
|
+
**Returns:** `Promise<Note>`
|
|
3381
|
+
|
|
3382
|
+
**Description:**
|
|
3383
|
+
Updates a note's title, content, and tags. All fields can be updated together or individually. If a field is not provided, it defaults to an empty value.
|
|
3384
|
+
|
|
3385
|
+
<details>
|
|
3386
|
+
<summary><strong>Notes</strong></summary>
|
|
3387
|
+
|
|
3388
|
+
- Both `title` and `content` are always sent (defaults to empty string if not provided)
|
|
3389
|
+
- Tags default to empty array if not provided
|
|
3390
|
+
- All fields are updated together in a single operation
|
|
3391
|
+
- Returns updated note object with the provided title
|
|
3392
|
+
|
|
3393
|
+
</details>
|
|
3394
|
+
|
|
3395
|
+
**Usage:**
|
|
3396
|
+
```typescript
|
|
3397
|
+
// Update title and content
|
|
3398
|
+
const updated = await sdk.notes.update('notebook-id', 'note-id', {
|
|
3399
|
+
title: 'Updated Meeting Notes',
|
|
3400
|
+
content: 'Updated content with new information...',
|
|
3401
|
+
})
|
|
3402
|
+
|
|
3403
|
+
// Update all fields including tags
|
|
3404
|
+
const updated = await sdk.notes.update('notebook-id', 'note-id', {
|
|
3405
|
+
title: 'Final Meeting Notes',
|
|
3406
|
+
content: 'Final content...',
|
|
3407
|
+
tags: ['meeting', 'final'],
|
|
3408
|
+
})
|
|
3409
|
+
|
|
3410
|
+
// Update both title and content
|
|
3411
|
+
const updated = await sdk.notes.update('notebook-id', 'note-id', {
|
|
3412
|
+
title: 'Final Meeting Notes',
|
|
3413
|
+
content: 'Final content...',
|
|
3414
|
+
tags: ['meeting', 'final'],
|
|
3415
|
+
})
|
|
3416
|
+
```
|
|
3417
|
+
|
|
3418
|
+
---
|
|
3419
|
+
|
|
3420
|
+
### Delete Note
|
|
3421
|
+
|
|
3422
|
+
**Method:** `sdk.notes.delete(notebookId, noteIds)`
|
|
3423
|
+
|
|
3424
|
+
**Example:** [note-delete.ts](examples/note-delete.ts)
|
|
3425
|
+
|
|
3426
|
+
**Parameters:**
|
|
3427
|
+
- `notebookId: string` - The notebook ID (required)
|
|
3428
|
+
- `noteIds: string | string[]` - Single note ID or array of note IDs (required)
|
|
3429
|
+
|
|
3430
|
+
**Returns:** `Promise<void>`
|
|
3431
|
+
|
|
3432
|
+
**Description:**
|
|
3433
|
+
Deletes one or more notes from the notebook. This action cannot be undone.
|
|
3434
|
+
|
|
3435
|
+
<details>
|
|
3436
|
+
<summary><strong>Notes</strong></summary>
|
|
3437
|
+
|
|
3438
|
+
- Supports both single note ID and array of note IDs
|
|
3439
|
+
- Batch deletion is supported (pass array of IDs)
|
|
3440
|
+
- Deletion is permanent and cannot be undone
|
|
3441
|
+
- No confirmation required - deletion is immediate
|
|
3442
|
+
|
|
3443
|
+
</details>
|
|
3444
|
+
|
|
3445
|
+
**Usage:**
|
|
3446
|
+
```typescript
|
|
3447
|
+
// Delete single note
|
|
3448
|
+
await sdk.notes.delete('notebook-id', 'note-id')
|
|
3449
|
+
|
|
3450
|
+
// Delete multiple notes
|
|
3451
|
+
await sdk.notes.delete('notebook-id', [
|
|
3452
|
+
'note-id-1',
|
|
3453
|
+
'note-id-2',
|
|
3454
|
+
'note-id-3',
|
|
3455
|
+
])
|
|
3456
|
+
```
|
|
3457
|
+
|
|
3458
|
+
## Language Support
|
|
3459
|
+
|
|
3460
|
+
NotebookLM supports **80+ languages** for artifacts, chat responses, and all notebook operations.
|
|
3461
|
+
|
|
3462
|
+
### Notebook Default Language
|
|
3463
|
+
|
|
3464
|
+
Each notebook has a **default output language** that is used for:
|
|
3465
|
+
- Artifact creation (audio, video, report, infographics, slide decks)
|
|
3466
|
+
- Chat responses
|
|
3467
|
+
- All other notebook operations
|
|
3468
|
+
|
|
3469
|
+
**If you don't specify a language when creating an artifact, it will use the notebook's default language.**
|
|
3470
|
+
|
|
3471
|
+
#### Get Notebook Default Language
|
|
3472
|
+
|
|
3473
|
+
```typescript
|
|
3474
|
+
// Get the current default language for a notebook
|
|
3475
|
+
const language = await sdk.notebookLanguage.get('notebook-id');
|
|
3476
|
+
console.log(`Default language: ${language}`); // 'en', 'de', 'ja', etc.
|
|
3477
|
+
```
|
|
3478
|
+
|
|
3479
|
+
#### Set Notebook Default Language
|
|
3480
|
+
|
|
3481
|
+
```typescript
|
|
3482
|
+
import { NotebookLMLanguage } from 'notebooklm-kit';
|
|
3483
|
+
|
|
3484
|
+
// Set the notebook's default language to German
|
|
3485
|
+
await sdk.notebookLanguage.set('notebook-id', NotebookLMLanguage.GERMAN);
|
|
3486
|
+
|
|
3487
|
+
// Set to Japanese
|
|
3488
|
+
await sdk.notebookLanguage.set('notebook-id', NotebookLMLanguage.JAPANESE);
|
|
3489
|
+
|
|
3490
|
+
// Set using language code directly
|
|
3491
|
+
await sdk.notebookLanguage.set('notebook-id', 'de');
|
|
3492
|
+
```
|
|
3493
|
+
|
|
3494
|
+
#### Get Language Information
|
|
3495
|
+
|
|
3496
|
+
```typescript
|
|
3497
|
+
// Get language info with metadata
|
|
3498
|
+
const info = await sdk.notebookLanguage.getInfo('notebook-id');
|
|
3499
|
+
console.log(`Language: ${info.language}`); // 'de'
|
|
3500
|
+
console.log(`Name: ${info.name}`); // 'German'
|
|
3501
|
+
console.log(`Native Name: ${info.nativeName}`); // 'Deutsch'
|
|
3502
|
+
```
|
|
3503
|
+
|
|
3504
|
+
### Supported Languages
|
|
3505
|
+
|
|
3506
|
+
Use the `NotebookLMLanguage` enum for type safety:
|
|
3507
|
+
|
|
3508
|
+
```typescript
|
|
3509
|
+
import { NotebookLMLanguage } from 'notebooklm-kit'
|
|
3510
|
+
|
|
3511
|
+
NotebookLMLanguage.ENGLISH // 'en'
|
|
3512
|
+
NotebookLMLanguage.HINDI // 'hi'
|
|
3513
|
+
NotebookLMLanguage.SPANISH // 'es'
|
|
3514
|
+
NotebookLMLanguage.FRENCH // 'fr'
|
|
3515
|
+
NotebookLMLanguage.GERMAN // 'de'
|
|
3516
|
+
NotebookLMLanguage.JAPANESE // 'ja'
|
|
3517
|
+
NotebookLMLanguage.CHINESE_SIMPLIFIED // 'zh'
|
|
3518
|
+
NotebookLMLanguage.ARABIC // 'ar'
|
|
3519
|
+
NotebookLMLanguage.TURKISH // 'tr'
|
|
3520
|
+
// ... and 70+ more languages
|
|
3521
|
+
```
|
|
3522
|
+
|
|
3523
|
+
### Artifact Language Support
|
|
3524
|
+
|
|
3525
|
+
**Artifacts that support language customization:**
|
|
3526
|
+
- ✅ **Audio Overview** - `customization.language`
|
|
3527
|
+
- ✅ **Video Overview** - `customization.language`
|
|
3528
|
+
- ✅ **Report** - Uses notebook default language automatically
|
|
3529
|
+
- ✅ **Infographic** - `customization.language`
|
|
3530
|
+
- ✅ **Slide Deck** - `customization.language`
|
|
3531
|
+
|
|
3532
|
+
**Artifacts that don't support language customization:**
|
|
3533
|
+
- ❌ **Quiz** - Language is set via instructions, not customization
|
|
3534
|
+
- ❌ **Flashcards** - Language is set via instructions, not customization
|
|
3535
|
+
- ❌ **Mind Map** - No language customization available
|
|
3536
|
+
|
|
3537
|
+
### Using Language in Artifacts
|
|
3538
|
+
|
|
3539
|
+
#### Option 1: Use Notebook Default (Recommended)
|
|
3540
|
+
|
|
3541
|
+
```typescript
|
|
3542
|
+
// Set notebook default language once
|
|
3543
|
+
await sdk.notebookLanguage.set('notebook-id', NotebookLMLanguage.GERMAN);
|
|
3544
|
+
|
|
3545
|
+
// All artifacts will use German by default
|
|
3546
|
+
const audio = await sdk.artifacts.create('notebook-id', ArtifactType.AUDIO, {
|
|
3547
|
+
// No language specified - uses notebook default (German)
|
|
3548
|
+
});
|
|
3549
|
+
|
|
3550
|
+
const video = await sdk.artifacts.create('notebook-id', ArtifactType.VIDEO, {
|
|
3551
|
+
// No language specified - uses notebook default (German)
|
|
3552
|
+
});
|
|
3553
|
+
```
|
|
3554
|
+
|
|
3555
|
+
#### Option 2: Override for Specific Artifacts
|
|
3556
|
+
|
|
3557
|
+
```typescript
|
|
3558
|
+
// Set notebook default to German
|
|
3559
|
+
await sdk.notebookLanguage.set('notebook-id', NotebookLMLanguage.GERMAN);
|
|
3560
|
+
|
|
3561
|
+
// Most artifacts use German
|
|
3562
|
+
const audio = await sdk.artifacts.create('notebook-id', ArtifactType.AUDIO, {
|
|
3563
|
+
// Uses German (notebook default)
|
|
3564
|
+
});
|
|
3565
|
+
|
|
3566
|
+
// But this one uses Japanese
|
|
3567
|
+
const video = await sdk.artifacts.create('notebook-id', ArtifactType.VIDEO, {
|
|
3568
|
+
customization: {
|
|
3569
|
+
language: NotebookLMLanguage.JAPANESE, // Overrides notebook default
|
|
3570
|
+
},
|
|
3571
|
+
});
|
|
3572
|
+
```
|
|
3573
|
+
|
|
3574
|
+
#### Option 3: Explicit Language for Each Artifact
|
|
3575
|
+
|
|
3576
|
+
```typescript
|
|
3577
|
+
// Always specify language explicitly
|
|
3578
|
+
const audio = await sdk.artifacts.create('notebook-id', ArtifactType.AUDIO, {
|
|
3579
|
+
customization: {
|
|
3580
|
+
language: NotebookLMLanguage.SPANISH,
|
|
3581
|
+
},
|
|
3582
|
+
});
|
|
3583
|
+
|
|
3584
|
+
const video = await sdk.artifacts.create('notebook-id', ArtifactType.VIDEO, {
|
|
3585
|
+
customization: {
|
|
3586
|
+
language: NotebookLMLanguage.FRENCH,
|
|
3587
|
+
},
|
|
3588
|
+
});
|
|
3589
|
+
```
|
|
3590
|
+
|
|
3591
|
+
### Language Examples
|
|
3592
|
+
|
|
3593
|
+
```typescript
|
|
3594
|
+
import { NotebookLMLanguage } from 'notebooklm-kit';
|
|
3595
|
+
|
|
3596
|
+
// Create artifacts in different languages
|
|
3597
|
+
const germanAudio = await sdk.artifacts.create('notebook-id', ArtifactType.AUDIO, {
|
|
3598
|
+
customization: {
|
|
3599
|
+
language: NotebookLMLanguage.GERMAN, // 'de'
|
|
3600
|
+
},
|
|
3601
|
+
});
|
|
3602
|
+
|
|
3603
|
+
const japaneseVideo = await sdk.artifacts.create('notebook-id', ArtifactType.VIDEO, {
|
|
3604
|
+
customization: {
|
|
3605
|
+
language: NotebookLMLanguage.JAPANESE, // 'ja'
|
|
3606
|
+
},
|
|
3607
|
+
});
|
|
3608
|
+
|
|
3609
|
+
const hindiSlides = await sdk.artifacts.create('notebook-id', ArtifactType.SLIDE_DECK, {
|
|
3610
|
+
customization: {
|
|
3611
|
+
language: NotebookLMLanguage.HINDI, // 'hi'
|
|
3612
|
+
},
|
|
3613
|
+
});
|
|
3614
|
+
|
|
3615
|
+
const spanishInfographic = await sdk.artifacts.create('notebook-id', ArtifactType.INFOGRAPHIC, {
|
|
3616
|
+
customization: {
|
|
3617
|
+
language: NotebookLMLanguage.SPANISH, // 'es'
|
|
3618
|
+
},
|
|
3619
|
+
});
|
|
3620
|
+
```
|
|
3621
|
+
|
|
3622
|
+
## Advanced Configuration
|
|
3623
|
+
|
|
3624
|
+
```typescript
|
|
3625
|
+
const sdk = new NotebookLMClient({
|
|
3626
|
+
authToken: process.env.NOTEBOOKLM_AUTH_TOKEN!,
|
|
3627
|
+
cookies: process.env.NOTEBOOKLM_COOKIES!,
|
|
3628
|
+
|
|
3629
|
+
// Enable debug logging
|
|
3630
|
+
debug: true,
|
|
3631
|
+
|
|
3632
|
+
// Auto-refresh configuration
|
|
3633
|
+
autoRefresh: {
|
|
3634
|
+
enabled: true,
|
|
3635
|
+
interval: 5 * 60 * 1000, // 5 minutes
|
|
3636
|
+
},
|
|
3637
|
+
|
|
3638
|
+
// Retry configuration
|
|
3639
|
+
maxRetries: 3,
|
|
3640
|
+
|
|
3641
|
+
// Custom headers
|
|
3642
|
+
headers: {
|
|
3643
|
+
'User-Agent': 'My Custom Agent',
|
|
3644
|
+
},
|
|
3645
|
+
})
|
|
3646
|
+
|
|
3647
|
+
// Manually refresh
|
|
3648
|
+
await sdk.refreshCredentials()
|
|
3649
|
+
|
|
3650
|
+
// Get RPC client
|
|
3651
|
+
const rpcClient = sdk.getRPCClient()
|
|
3652
|
+
```
|
|
3653
|
+
|
|
3654
|
+
## Error Handling
|
|
3655
|
+
|
|
3656
|
+
```typescript
|
|
3657
|
+
import {
|
|
3658
|
+
NotebookLMError,
|
|
3659
|
+
NotebookLMAuthError,
|
|
3660
|
+
RateLimitError,
|
|
3661
|
+
APIError,
|
|
3662
|
+
} from 'notebooklm-kit'
|
|
3663
|
+
|
|
3664
|
+
try {
|
|
3665
|
+
const quiz = await sdk.artifacts.create('notebook-id', ArtifactType.QUIZ, {
|
|
3666
|
+
instructions: 'Create a quiz',
|
|
3667
|
+
customization: { numberOfQuestions: 2, difficulty: 2, language: 'en' },
|
|
3668
|
+
})
|
|
3669
|
+
} catch (error) {
|
|
3670
|
+
if (error instanceof NotebookLMAuthError) {
|
|
3671
|
+
console.error('Authentication failed - refresh your cookies')
|
|
3672
|
+
} else if (error instanceof RateLimitError) {
|
|
3673
|
+
console.error('Rate limit exceeded:', error.message)
|
|
3674
|
+
} else if (error instanceof APIError) {
|
|
3675
|
+
console.error('API error:', error.message)
|
|
3676
|
+
} else if (error instanceof NotebookLMError) {
|
|
3677
|
+
console.error('NotebookLM error:', error.message)
|
|
3678
|
+
}
|
|
3679
|
+
}
|
|
3680
|
+
```
|
|
3681
|
+
|
|
3682
|
+
## Best Practices
|
|
3683
|
+
|
|
3684
|
+
### Resource Management
|
|
3685
|
+
|
|
3686
|
+
**Always dispose of the SDK when done** to prevent memory leaks and stop background processes:
|
|
3687
|
+
|
|
3688
|
+
```typescript
|
|
3689
|
+
import { NotebookLMClient } from 'notebooklm-kit';
|
|
3690
|
+
|
|
3691
|
+
async function main() {
|
|
3692
|
+
const sdk = new NotebookLMClient();
|
|
3693
|
+
|
|
3694
|
+
try {
|
|
3695
|
+
await sdk.connect();
|
|
3696
|
+
// ... use SDK ...
|
|
3697
|
+
} finally {
|
|
3698
|
+
await sdk.dispose(); // Always cleanup
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
```
|
|
3702
|
+
|
|
3703
|
+
**Graceful shutdown for long-running applications:**
|
|
3704
|
+
|
|
3705
|
+
```typescript
|
|
3706
|
+
// Handle process termination gracefully
|
|
3707
|
+
process.on('SIGINT', async () => {
|
|
3708
|
+
console.log('Shutting down...');
|
|
3709
|
+
await sdk.dispose();
|
|
3710
|
+
process.exit(0);
|
|
3711
|
+
});
|
|
3712
|
+
|
|
3713
|
+
process.on('SIGTERM', async () => {
|
|
3714
|
+
console.log('Terminating...');
|
|
3715
|
+
await sdk.dispose();
|
|
3716
|
+
process.exit(0);
|
|
3717
|
+
});
|
|
3718
|
+
```
|
|
3719
|
+
|
|
3720
|
+
### Error Handling
|
|
3721
|
+
|
|
3722
|
+
**Use specific error types** for better error handling:
|
|
3723
|
+
|
|
3724
|
+
```typescript
|
|
3725
|
+
import {
|
|
3726
|
+
NotebookLMError,
|
|
3727
|
+
NotebookLMAuthError,
|
|
3728
|
+
RateLimitError,
|
|
3729
|
+
APIError,
|
|
3730
|
+
} from 'notebooklm-kit';
|
|
3731
|
+
|
|
3732
|
+
try {
|
|
3733
|
+
const notebook = await sdk.notebooks.create({ title: 'My Notebook' });
|
|
3734
|
+
} catch (error) {
|
|
3735
|
+
if (error instanceof NotebookLMAuthError) {
|
|
3736
|
+
// Authentication failed - credentials expired or invalid
|
|
3737
|
+
console.error('Please refresh your credentials');
|
|
3738
|
+
// Optionally: Force re-authentication
|
|
3739
|
+
// Set FORCE_REAUTH=true in .env or delete credentials.json
|
|
3740
|
+
} else if (error instanceof RateLimitError) {
|
|
3741
|
+
// Rate limit exceeded - wait before retrying
|
|
3742
|
+
console.error('Rate limit exceeded. Please wait before retrying.');
|
|
3743
|
+
// Implement exponential backoff
|
|
3744
|
+
} else if (error instanceof APIError) {
|
|
3745
|
+
// API error - check error code and message
|
|
3746
|
+
if (error.code === 143) {
|
|
3747
|
+
console.error('Resource not found');
|
|
3748
|
+
} else if (error.isRetryable()) {
|
|
3749
|
+
// Retry transient errors
|
|
3750
|
+
console.error('Transient error, will retry:', error.message);
|
|
3751
|
+
} else {
|
|
3752
|
+
console.error('API error:', error.message);
|
|
3753
|
+
}
|
|
3754
|
+
} else if (error instanceof NotebookLMError) {
|
|
3755
|
+
// Generic NotebookLM error
|
|
3756
|
+
console.error('NotebookLM error:', error.message);
|
|
3757
|
+
} else {
|
|
3758
|
+
// Unexpected error
|
|
3759
|
+
console.error('Unexpected error:', error);
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
```
|
|
3763
|
+
|
|
3764
|
+
**Retry logic for transient errors:**
|
|
3765
|
+
|
|
3766
|
+
```typescript
|
|
3767
|
+
async function createNotebookWithRetry(title: string, maxRetries = 3) {
|
|
3768
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
3769
|
+
try {
|
|
3770
|
+
return await sdk.notebooks.create({ title });
|
|
3771
|
+
} catch (error) {
|
|
3772
|
+
if (error instanceof APIError && error.isRetryable() && attempt < maxRetries - 1) {
|
|
3773
|
+
const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
|
|
3774
|
+
console.log(`Retry ${attempt + 1}/${maxRetries} after ${delay}ms...`);
|
|
3775
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
3776
|
+
continue;
|
|
3777
|
+
}
|
|
3778
|
+
throw error; // Re-throw if not retryable or max retries reached
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
```
|
|
3783
|
+
|
|
3784
|
+
### Credential Management
|
|
3785
|
+
|
|
3786
|
+
**Use saved credentials** for faster startup (credentials are automatically saved after first auto-login):
|
|
3787
|
+
|
|
3788
|
+
```typescript
|
|
3789
|
+
// First run: Auto-login saves credentials to credentials.json
|
|
3790
|
+
const sdk = new NotebookLMClient({
|
|
3791
|
+
auth: {
|
|
3792
|
+
email: process.env.GOOGLE_EMAIL!,
|
|
3793
|
+
password: process.env.GOOGLE_PASSWORD!,
|
|
3794
|
+
},
|
|
3795
|
+
});
|
|
3796
|
+
|
|
3797
|
+
await sdk.connect(); // Saves credentials for future use
|
|
3798
|
+
|
|
3799
|
+
// Subsequent runs: Credentials loaded automatically from credentials.json
|
|
3800
|
+
// No need to provide email/password again
|
|
3801
|
+
const sdk2 = new NotebookLMClient();
|
|
3802
|
+
await sdk2.connect(); // Uses saved credentials
|
|
3803
|
+
```
|
|
3804
|
+
|
|
3805
|
+
**Force re-authentication when needed:**
|
|
3806
|
+
|
|
3807
|
+
```typescript
|
|
3808
|
+
// Option 1: Set environment variable
|
|
3809
|
+
// FORCE_REAUTH=true
|
|
3810
|
+
|
|
3811
|
+
// Option 2: Delete credentials.json file
|
|
3812
|
+
// rm credentials.json
|
|
3813
|
+
|
|
3814
|
+
// Option 3: Explicitly provide new credentials
|
|
3815
|
+
const sdk = new NotebookLMClient({
|
|
3816
|
+
auth: {
|
|
3817
|
+
email: process.env.GOOGLE_EMAIL!,
|
|
3818
|
+
password: process.env.GOOGLE_PASSWORD!,
|
|
3819
|
+
},
|
|
3820
|
+
});
|
|
3821
|
+
```
|
|
3822
|
+
|
|
3823
|
+
### Quota Management
|
|
3824
|
+
|
|
3825
|
+
**Check quota before operations** to avoid rate limit errors:
|
|
3826
|
+
|
|
3827
|
+
```typescript
|
|
3828
|
+
// Check remaining quota
|
|
3829
|
+
const remainingChats = sdk.getRemaining('chats');
|
|
3830
|
+
if (remainingChats <= 0) {
|
|
3831
|
+
console.warn('No chat quota remaining. Please wait or upgrade plan.');
|
|
3832
|
+
return;
|
|
3833
|
+
}
|
|
3834
|
+
|
|
3835
|
+
// Use chat
|
|
3836
|
+
const response = await sdk.generation.chat(notebookId, 'Your question');
|
|
3837
|
+
```
|
|
3838
|
+
|
|
3839
|
+
**Monitor usage:**
|
|
3840
|
+
|
|
3841
|
+
```typescript
|
|
3842
|
+
const usage = sdk.getUsage();
|
|
3843
|
+
console.log(`Notebooks: ${usage.notebooks.used}/${usage.notebooks.limit}`);
|
|
3844
|
+
console.log(`Chats: ${usage.chats.used}/${usage.chats.limit}`);
|
|
3845
|
+
console.log(`Sources: ${usage.sources.used}/${usage.sources.limit}`);
|
|
3846
|
+
```
|
|
3847
|
+
|
|
3848
|
+
### Source Processing
|
|
3849
|
+
|
|
3850
|
+
**Wait for sources to process** before creating artifacts:
|
|
3851
|
+
|
|
3852
|
+
```typescript
|
|
3853
|
+
// Add source
|
|
3854
|
+
const sourceId = await sdk.sources.add.url(notebookId, {
|
|
3855
|
+
url: 'https://example.com/article',
|
|
3856
|
+
});
|
|
3857
|
+
|
|
3858
|
+
// Wait for processing to complete
|
|
3859
|
+
let status = await sdk.sources.status(notebookId);
|
|
3860
|
+
while (status.sources.find(s => s.sourceId === sourceId)?.state !== 'READY') {
|
|
3861
|
+
await new Promise(resolve => setTimeout(resolve, 2000)); // Wait 2 seconds
|
|
3862
|
+
status = await sdk.sources.status(notebookId);
|
|
3863
|
+
}
|
|
3864
|
+
|
|
3865
|
+
// Now create artifact (source is ready)
|
|
3866
|
+
const quiz = await sdk.artifacts.create(notebookId, ArtifactType.QUIZ);
|
|
3867
|
+
```
|
|
3868
|
+
|
|
3869
|
+
### Artifact State Checking
|
|
3870
|
+
|
|
3871
|
+
**Check artifact state** before downloading or using:
|
|
3872
|
+
|
|
3873
|
+
```typescript
|
|
3874
|
+
// Create artifact
|
|
3875
|
+
const artifact = await sdk.artifacts.create(notebookId, ArtifactType.QUIZ);
|
|
3876
|
+
|
|
3877
|
+
// Wait for artifact to be ready
|
|
3878
|
+
let currentArtifact = artifact;
|
|
3879
|
+
while (currentArtifact.state !== ArtifactState.READY) {
|
|
3880
|
+
if (currentArtifact.state === ArtifactState.FAILED) {
|
|
3881
|
+
throw new Error('Artifact generation failed');
|
|
3882
|
+
}
|
|
3883
|
+
|
|
3884
|
+
await new Promise(resolve => setTimeout(resolve, 2000)); // Wait 2 seconds
|
|
3885
|
+
currentArtifact = await sdk.artifacts.get(artifact.artifactId, notebookId);
|
|
3886
|
+
}
|
|
3887
|
+
|
|
3888
|
+
// Now download or use the artifact
|
|
3889
|
+
const quizData = await sdk.artifacts.download(artifact.artifactId, './downloads', notebookId);
|
|
3890
|
+
```
|
|
3891
|
+
|
|
3892
|
+
### Async/Await Patterns
|
|
3893
|
+
|
|
3894
|
+
**Use async/await consistently** for better error handling:
|
|
3895
|
+
|
|
3896
|
+
```typescript
|
|
3897
|
+
// ✅ Good: Proper async/await
|
|
3898
|
+
async function processNotebook(notebookId: string) {
|
|
3899
|
+
try {
|
|
3900
|
+
const sources = await sdk.sources.list(notebookId);
|
|
3901
|
+
const artifacts = await sdk.artifacts.list(notebookId);
|
|
3902
|
+
return { sources, artifacts };
|
|
3903
|
+
} catch (error) {
|
|
3904
|
+
console.error('Failed to process notebook:', error);
|
|
3905
|
+
throw error;
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
|
|
3909
|
+
// ❌ Avoid: Mixing promises and async/await
|
|
3910
|
+
function processNotebookBad(notebookId: string) {
|
|
3911
|
+
sdk.sources.list(notebookId).then(sources => {
|
|
3912
|
+
// Error handling is harder here
|
|
3913
|
+
});
|
|
3914
|
+
}
|
|
3915
|
+
```
|
|
3916
|
+
|
|
3917
|
+
### Connection Lifecycle
|
|
3918
|
+
|
|
3919
|
+
**Connect once, reuse the SDK instance:**
|
|
3920
|
+
|
|
3921
|
+
```typescript
|
|
3922
|
+
// ✅ Good: Connect once, reuse
|
|
3923
|
+
const sdk = new NotebookLMClient();
|
|
3924
|
+
await sdk.connect();
|
|
3925
|
+
|
|
3926
|
+
// Use SDK multiple times
|
|
3927
|
+
const notebooks = await sdk.notebooks.list();
|
|
3928
|
+
const sources = await sdk.sources.list(notebookId);
|
|
3929
|
+
const artifacts = await sdk.artifacts.list(notebookId);
|
|
3930
|
+
|
|
3931
|
+
await sdk.dispose(); // Cleanup when done
|
|
3932
|
+
|
|
3933
|
+
// ❌ Avoid: Connecting multiple times
|
|
3934
|
+
// Don't call connect() multiple times - reuse the same instance
|
|
3935
|
+
```
|
|
3936
|
+
|
|
3937
|
+
### Debug Mode
|
|
3938
|
+
|
|
3939
|
+
**Enable debug mode for troubleshooting:**
|
|
3940
|
+
|
|
3941
|
+
```typescript
|
|
3942
|
+
// In development
|
|
3943
|
+
const sdk = new NotebookLMClient({
|
|
3944
|
+
debug: process.env.NODE_ENV === 'development',
|
|
3945
|
+
});
|
|
3946
|
+
|
|
3947
|
+
// Or via environment variable
|
|
3948
|
+
// NOTEBOOKLM_DEBUG=true
|
|
3949
|
+
|
|
3950
|
+
// Debug mode shows:
|
|
3951
|
+
// - RPC call details
|
|
3952
|
+
// - Authentication flow
|
|
3953
|
+
// - Auto-refresh operations
|
|
3954
|
+
// - Error details
|
|
3955
|
+
// - Response parsing
|
|
3956
|
+
```
|
|
3957
|
+
|
|
3958
|
+
### Batch Operations
|
|
3959
|
+
|
|
3960
|
+
**Use batch operations** when adding multiple sources:
|
|
3961
|
+
|
|
3962
|
+
```typescript
|
|
3963
|
+
// ✅ Good: Batch add sources
|
|
3964
|
+
await sdk.sources.add.batch(notebookId, {
|
|
3965
|
+
sources: [
|
|
3966
|
+
{ type: 'url', url: 'https://example.com/1' },
|
|
3967
|
+
{ type: 'url', url: 'https://example.com/2' },
|
|
3968
|
+
{ type: 'url', url: 'https://example.com/3' },
|
|
3969
|
+
],
|
|
3970
|
+
});
|
|
3971
|
+
|
|
3972
|
+
// ❌ Avoid: Adding sources one by one
|
|
3973
|
+
// This is slower and uses more API calls
|
|
3974
|
+
```
|
|
3975
|
+
|
|
3976
|
+
### Streaming Responses
|
|
3977
|
+
|
|
3978
|
+
**Use streaming for long responses** to show progress:
|
|
3979
|
+
|
|
3980
|
+
```typescript
|
|
3981
|
+
// Stream chat response for better UX
|
|
3982
|
+
const stream = await sdk.generation.chatStream(notebookId, 'Long question...');
|
|
3983
|
+
|
|
3984
|
+
for await (const chunk of stream) {
|
|
3985
|
+
if (chunk.type === 'content') {
|
|
3986
|
+
process.stdout.write(chunk.content); // Show progress
|
|
3987
|
+
} else if (chunk.type === 'citations') {
|
|
3988
|
+
console.log('\nCitations:', chunk.citations);
|
|
3989
|
+
}
|
|
3990
|
+
}
|
|
3991
|
+
```
|
|
3992
|
+
|
|
3993
|
+
### Environment Variables
|
|
3994
|
+
|
|
3995
|
+
**Use environment variables** for configuration:
|
|
3996
|
+
|
|
3997
|
+
```typescript
|
|
3998
|
+
// ✅ Good: Use .env file
|
|
3999
|
+
// .env
|
|
4000
|
+
NOTEBOOKLM_AUTH_TOKEN=...
|
|
4001
|
+
NOTEBOOKLM_COOKIES=...
|
|
4002
|
+
NOTEBOOKLM_DEBUG=true
|
|
4003
|
+
|
|
4004
|
+
// ❌ Avoid: Hardcoding credentials
|
|
4005
|
+
const sdk = new NotebookLMClient({
|
|
4006
|
+
authToken: 'hardcoded-token', // Don't do this!
|
|
4007
|
+
});
|
|
4008
|
+
```
|
|
4009
|
+
|
|
4010
|
+
### Recommended Patterns
|
|
4011
|
+
|
|
4012
|
+
**Complete example with best practices:**
|
|
4013
|
+
|
|
4014
|
+
```typescript
|
|
4015
|
+
import { NotebookLMClient, ArtifactType, ArtifactState } from 'notebooklm-kit';
|
|
4016
|
+
import dotenv from 'dotenv';
|
|
4017
|
+
|
|
4018
|
+
dotenv.config();
|
|
4019
|
+
|
|
4020
|
+
async function main() {
|
|
4021
|
+
const sdk = new NotebookLMClient({
|
|
4022
|
+
debug: process.env.NOTEBOOKLM_DEBUG === 'true',
|
|
4023
|
+
});
|
|
4024
|
+
|
|
4025
|
+
try {
|
|
4026
|
+
await sdk.connect();
|
|
4027
|
+
|
|
4028
|
+
// Check quota before operations
|
|
4029
|
+
const remaining = sdk.getRemaining('chats');
|
|
4030
|
+
if (remaining <= 0) {
|
|
4031
|
+
console.warn('No chat quota remaining');
|
|
4032
|
+
return;
|
|
4033
|
+
}
|
|
4034
|
+
|
|
4035
|
+
// Create notebook
|
|
4036
|
+
const notebook = await sdk.notebooks.create({
|
|
4037
|
+
title: 'Research Project',
|
|
4038
|
+
emoji: '📚',
|
|
4039
|
+
});
|
|
4040
|
+
|
|
4041
|
+
// Add source and wait for processing
|
|
4042
|
+
const sourceId = await sdk.sources.add.url(notebook.projectId, {
|
|
4043
|
+
url: 'https://example.com/article',
|
|
4044
|
+
});
|
|
4045
|
+
|
|
4046
|
+
// Wait for source to be ready
|
|
4047
|
+
let status = await sdk.sources.status(notebook.projectId);
|
|
4048
|
+
while (status.sources.find(s => s.sourceId === sourceId)?.state !== 'READY') {
|
|
4049
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
4050
|
+
status = await sdk.sources.status(notebook.projectId);
|
|
4051
|
+
}
|
|
4052
|
+
|
|
4053
|
+
// Create artifact and wait for completion
|
|
4054
|
+
const artifact = await sdk.artifacts.create(
|
|
4055
|
+
notebook.projectId,
|
|
4056
|
+
ArtifactType.QUIZ,
|
|
4057
|
+
{
|
|
4058
|
+
customization: {
|
|
4059
|
+
numberOfQuestions: 10,
|
|
4060
|
+
difficulty: 2,
|
|
4061
|
+
},
|
|
4062
|
+
}
|
|
4063
|
+
);
|
|
4064
|
+
|
|
4065
|
+
// Wait for artifact to be ready
|
|
4066
|
+
let currentArtifact = artifact;
|
|
4067
|
+
while (currentArtifact.state !== ArtifactState.READY) {
|
|
4068
|
+
if (currentArtifact.state === ArtifactState.FAILED) {
|
|
4069
|
+
throw new Error('Artifact generation failed');
|
|
4070
|
+
}
|
|
4071
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
4072
|
+
currentArtifact = await sdk.artifacts.get(
|
|
4073
|
+
artifact.artifactId,
|
|
4074
|
+
notebook.projectId
|
|
4075
|
+
);
|
|
4076
|
+
}
|
|
4077
|
+
|
|
4078
|
+
// Download artifact
|
|
4079
|
+
const quizData = await sdk.artifacts.download(
|
|
4080
|
+
artifact.artifactId,
|
|
4081
|
+
'./downloads',
|
|
4082
|
+
notebook.projectId
|
|
4083
|
+
);
|
|
4084
|
+
|
|
4085
|
+
console.log('Success!', quizData);
|
|
4086
|
+
|
|
4087
|
+
} catch (error) {
|
|
4088
|
+
console.error('Error:', error);
|
|
4089
|
+
process.exit(1);
|
|
4090
|
+
} finally {
|
|
4091
|
+
await sdk.dispose(); // Always cleanup
|
|
4092
|
+
}
|
|
4093
|
+
}
|
|
4094
|
+
|
|
4095
|
+
// Graceful shutdown
|
|
4096
|
+
process.on('SIGINT', async () => {
|
|
4097
|
+
console.log('\nShutting down...');
|
|
4098
|
+
process.exit(0);
|
|
4099
|
+
});
|
|
4100
|
+
|
|
4101
|
+
main();
|
|
4102
|
+
```
|