notebooklm-sdk 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +148 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -1
- package/dist/index.d.ts +52 -1
- package/dist/index.js +149 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
Generate AI podcasts, chat with documents, run web research, and manage notebooks programmatically — from Node.js, Bun, or Deno.
|
|
10
10
|
|
|
11
|
-
>
|
|
11
|
+
> **Unofficial.** This SDK reverse-engineers the NotebookLM internal API. It may break when Google updates their service. Not affiliated with Google.
|
|
12
12
|
|
|
13
13
|
TypeScript port of [notebooklm-py](https://github.com/teng-lin/notebooklm-py).
|
|
14
14
|
|
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ __export(enums_exports, {
|
|
|
21
21
|
ArtifactTypeCode: () => exports.ArtifactTypeCode,
|
|
22
22
|
AudioFormat: () => exports.AudioFormat,
|
|
23
23
|
AudioLength: () => exports.AudioLength,
|
|
24
|
+
ChatMode: () => exports.ChatMode,
|
|
24
25
|
ExportType: () => exports.ExportType,
|
|
25
26
|
InfographicDetail: () => exports.InfographicDetail,
|
|
26
27
|
InfographicOrientation: () => exports.InfographicOrientation,
|
|
@@ -38,6 +39,7 @@ __export(enums_exports, {
|
|
|
38
39
|
VideoStyle: () => exports.VideoStyle,
|
|
39
40
|
artifactStatusFromCode: () => artifactStatusFromCode,
|
|
40
41
|
artifactTypeFromCode: () => artifactTypeFromCode,
|
|
42
|
+
chatModeToParams: () => chatModeToParams,
|
|
41
43
|
sourceStatusFromCode: () => sourceStatusFromCode,
|
|
42
44
|
sourceTypeFromCode: () => sourceTypeFromCode
|
|
43
45
|
});
|
|
@@ -59,7 +61,10 @@ function artifactStatusFromCode(code) {
|
|
|
59
61
|
function sourceStatusFromCode(code) {
|
|
60
62
|
return SOURCE_STATUS_MAP[code] ?? "unknown";
|
|
61
63
|
}
|
|
62
|
-
|
|
64
|
+
function chatModeToParams(mode) {
|
|
65
|
+
return CHAT_MODE_PARAMS[mode];
|
|
66
|
+
}
|
|
67
|
+
exports.RPCMethod = void 0; exports.ArtifactTypeCode = void 0; var ArtifactStatusCode, SourceStatusCode; exports.AudioFormat = void 0; exports.AudioLength = void 0; exports.VideoFormat = void 0; exports.VideoStyle = void 0; exports.QuizQuantity = void 0; exports.QuizDifficulty = void 0; exports.InfographicOrientation = void 0; exports.InfographicDetail = void 0; exports.InfographicStyle = void 0; exports.SlideDeckFormat = void 0; exports.SlideDeckLength = void 0; exports.ExportType = void 0; var SOURCE_TYPE_MAP, ARTIFACT_TYPE_MAP, ARTIFACT_STATUS_MAP, SOURCE_STATUS_MAP; exports.ChatMode = void 0; var CHAT_MODE_PARAMS; exports.ShareAccess = void 0; exports.ShareViewLevel = void 0; exports.SharePermission = void 0;
|
|
63
68
|
var init_enums = __esm({
|
|
64
69
|
"src/types/enums.ts"() {
|
|
65
70
|
exports.RPCMethod = {
|
|
@@ -243,6 +248,22 @@ var init_enums = __esm({
|
|
|
243
248
|
3: "error",
|
|
244
249
|
5: "preparing"
|
|
245
250
|
};
|
|
251
|
+
exports.ChatMode = {
|
|
252
|
+
/** General purpose — balanced length and style. */
|
|
253
|
+
DEFAULT: "default",
|
|
254
|
+
/** Educational focus with longer, learning-oriented responses. */
|
|
255
|
+
LEARNING_GUIDE: "learning_guide",
|
|
256
|
+
/** Short, concise answers. */
|
|
257
|
+
CONCISE: "concise",
|
|
258
|
+
/** Verbose, detailed answers. */
|
|
259
|
+
DETAILED: "detailed"
|
|
260
|
+
};
|
|
261
|
+
CHAT_MODE_PARAMS = {
|
|
262
|
+
default: [1, 1],
|
|
263
|
+
learning_guide: [3, 4],
|
|
264
|
+
concise: [1, 5],
|
|
265
|
+
detailed: [1, 4]
|
|
266
|
+
};
|
|
246
267
|
exports.ShareAccess = {
|
|
247
268
|
/** Only explicitly shared users can access */
|
|
248
269
|
RESTRICTED: 0,
|
|
@@ -1133,6 +1154,39 @@ ${opts.extraInstructions}` : cfg.prompt;
|
|
|
1133
1154
|
if (!url) throw new exports.ArtifactNotReadyError("infographic", { artifactId });
|
|
1134
1155
|
return this._fetchMediaWithCookies(url);
|
|
1135
1156
|
}
|
|
1157
|
+
/** Get AI-suggested report formats based on notebook content. */
|
|
1158
|
+
async suggestReports(notebookId) {
|
|
1159
|
+
const params = [[2], notebookId];
|
|
1160
|
+
const result = await this.rpc.call(exports.RPCMethod.GET_SUGGESTED_REPORTS, params, {
|
|
1161
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1162
|
+
allowNull: true,
|
|
1163
|
+
timeoutMs: 12e4
|
|
1164
|
+
});
|
|
1165
|
+
if (!Array.isArray(result) || !result.length) return [];
|
|
1166
|
+
const items = Array.isArray(result[0]) ? result[0] : result;
|
|
1167
|
+
const suggestions = [];
|
|
1168
|
+
for (const item of items) {
|
|
1169
|
+
if (Array.isArray(item) && item.length >= 5) {
|
|
1170
|
+
suggestions.push({
|
|
1171
|
+
title: typeof item[0] === "string" ? item[0] : "",
|
|
1172
|
+
description: typeof item[1] === "string" ? item[1] : "",
|
|
1173
|
+
prompt: typeof item[4] === "string" ? item[4] : "",
|
|
1174
|
+
audienceLevel: typeof item[5] === "number" ? item[5] : 2
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
return suggestions;
|
|
1179
|
+
}
|
|
1180
|
+
/** Revise an individual slide in a completed slide deck using a prompt. */
|
|
1181
|
+
async reviseSlide(notebookId, artifactId, slideIndex, prompt) {
|
|
1182
|
+
if (slideIndex < 0) throw new Error("slideIndex must be >= 0");
|
|
1183
|
+
const params = [[2], artifactId, [[[slideIndex, prompt]]]];
|
|
1184
|
+
const result = await this.rpc.call(exports.RPCMethod.REVISE_SLIDE, params, {
|
|
1185
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1186
|
+
allowNull: true
|
|
1187
|
+
});
|
|
1188
|
+
return this._parseGenerationResult(result);
|
|
1189
|
+
}
|
|
1136
1190
|
/** Get parsed headers and rows from a completed data table artifact. */
|
|
1137
1191
|
async getDataTableContent(notebookId, artifactId) {
|
|
1138
1192
|
const artifacts = await this._listRaw(notebookId);
|
|
@@ -1356,6 +1410,19 @@ var ChatAPI = class {
|
|
|
1356
1410
|
}
|
|
1357
1411
|
return null;
|
|
1358
1412
|
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Set the chat mode for a notebook. Persists on the server — affects all
|
|
1415
|
+
* subsequent `ask()` calls until changed.
|
|
1416
|
+
*/
|
|
1417
|
+
async setMode(notebookId, mode) {
|
|
1418
|
+
const [goal, length] = chatModeToParams(mode);
|
|
1419
|
+
const chatSettings = [[goal], [length]];
|
|
1420
|
+
const params = [notebookId, [[null, null, null, null, null, null, null, chatSettings]]];
|
|
1421
|
+
await this.rpc.call(exports.RPCMethod.RENAME_NOTEBOOK, params, {
|
|
1422
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
1423
|
+
allowNull: true
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1359
1426
|
clearCache(conversationId) {
|
|
1360
1427
|
if (conversationId) {
|
|
1361
1428
|
this.conversationCache.delete(conversationId);
|
|
@@ -1526,6 +1593,9 @@ var NotebooksAPI = class {
|
|
|
1526
1593
|
}
|
|
1527
1594
|
return "";
|
|
1528
1595
|
}
|
|
1596
|
+
async removeFromRecent(notebookId) {
|
|
1597
|
+
await this.rpc.call(exports.RPCMethod.REMOVE_RECENTLY_VIEWED, [notebookId], { allowNull: true });
|
|
1598
|
+
}
|
|
1529
1599
|
async getDescription(notebookId) {
|
|
1530
1600
|
const params = [notebookId, [2]];
|
|
1531
1601
|
const result = await this.rpc.call(exports.RPCMethod.SUMMARIZE, params, {
|
|
@@ -2133,6 +2203,74 @@ var SourcesAPI = class {
|
|
|
2133
2203
|
const uploadResult = await uploadResp.text();
|
|
2134
2204
|
return uploadResult.trim();
|
|
2135
2205
|
}
|
|
2206
|
+
/** Get the AI-generated Source Guide (summary + keywords) for a source. */
|
|
2207
|
+
async getGuide(notebookId, sourceId) {
|
|
2208
|
+
const params = [[[[sourceId]]]];
|
|
2209
|
+
const result = await this.rpc.call(exports.RPCMethod.GET_SOURCE_GUIDE, params, {
|
|
2210
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
2211
|
+
allowNull: true,
|
|
2212
|
+
timeoutMs: 12e4
|
|
2213
|
+
});
|
|
2214
|
+
let summary = "";
|
|
2215
|
+
let keywords = [];
|
|
2216
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
2217
|
+
const outer = result[0];
|
|
2218
|
+
if (Array.isArray(outer) && outer.length > 0) {
|
|
2219
|
+
const inner = outer[0];
|
|
2220
|
+
if (Array.isArray(inner)) {
|
|
2221
|
+
if (inner.length > 1 && Array.isArray(inner[1]) && typeof inner[1][0] === "string") {
|
|
2222
|
+
summary = inner[1][0];
|
|
2223
|
+
}
|
|
2224
|
+
if (inner.length > 2 && Array.isArray(inner[2]) && Array.isArray(inner[2][0])) {
|
|
2225
|
+
keywords = inner[2][0].filter((k) => typeof k === "string");
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
return { summary, keywords };
|
|
2231
|
+
}
|
|
2232
|
+
/** Get the full indexed text content of a source. */
|
|
2233
|
+
async getFulltext(notebookId, sourceId) {
|
|
2234
|
+
const params = [[sourceId], [2], [2]];
|
|
2235
|
+
const result = await this.rpc.call(exports.RPCMethod.GET_SOURCE, params, {
|
|
2236
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
2237
|
+
allowNull: true
|
|
2238
|
+
});
|
|
2239
|
+
if (!Array.isArray(result) || !result.length) {
|
|
2240
|
+
throw new Error(`Source ${sourceId} not found in notebook ${notebookId}`);
|
|
2241
|
+
}
|
|
2242
|
+
let title = "";
|
|
2243
|
+
let url = null;
|
|
2244
|
+
if (Array.isArray(result[0]) && result[0].length > 1) {
|
|
2245
|
+
title = typeof result[0][1] === "string" ? result[0][1] : "";
|
|
2246
|
+
const meta = result[0][2];
|
|
2247
|
+
if (Array.isArray(meta) && meta.length > 7 && Array.isArray(meta[7]) && typeof meta[7][0] === "string") {
|
|
2248
|
+
url = meta[7][0];
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
let content = "";
|
|
2252
|
+
if (Array.isArray(result[3]) && result[3].length > 0) {
|
|
2253
|
+
const texts = extractAllText(result[3][0]);
|
|
2254
|
+
content = texts.join("\n");
|
|
2255
|
+
}
|
|
2256
|
+
return { sourceId, title, content, url, charCount: content.length };
|
|
2257
|
+
}
|
|
2258
|
+
/** Check if a source has newer content available. Returns true if fresh, false if stale. */
|
|
2259
|
+
async checkFreshness(notebookId, sourceId) {
|
|
2260
|
+
const params = [null, [sourceId], [2]];
|
|
2261
|
+
const result = await this.rpc.call(exports.RPCMethod.CHECK_SOURCE_FRESHNESS, params, {
|
|
2262
|
+
sourcePath: `/notebook/${notebookId}`,
|
|
2263
|
+
allowNull: true
|
|
2264
|
+
});
|
|
2265
|
+
if (result === true) return true;
|
|
2266
|
+
if (result === false) return false;
|
|
2267
|
+
if (Array.isArray(result)) {
|
|
2268
|
+
if (result.length === 0) return true;
|
|
2269
|
+
const first = result[0];
|
|
2270
|
+
if (Array.isArray(first) && first.length > 1 && first[1] === true) return true;
|
|
2271
|
+
}
|
|
2272
|
+
return false;
|
|
2273
|
+
}
|
|
2136
2274
|
async delete(notebookId, sourceId) {
|
|
2137
2275
|
const params = [notebookId, [sourceId], [2]];
|
|
2138
2276
|
await this.rpc.call(exports.RPCMethod.DELETE_SOURCE, params, {
|
|
@@ -2187,6 +2325,15 @@ function extractSourceId(result) {
|
|
|
2187
2325
|
console.log("extractSourceId debug info: could not parse:", JSON.stringify(result, null, 2));
|
|
2188
2326
|
throw new Error("Could not extract source ID from API response");
|
|
2189
2327
|
}
|
|
2328
|
+
function extractAllText(data, maxDepth = 100) {
|
|
2329
|
+
if (maxDepth <= 0) return [];
|
|
2330
|
+
const texts = [];
|
|
2331
|
+
for (const item of data) {
|
|
2332
|
+
if (typeof item === "string" && item.length > 0) texts.push(item);
|
|
2333
|
+
else if (Array.isArray(item)) texts.push(...extractAllText(item, maxDepth - 1));
|
|
2334
|
+
}
|
|
2335
|
+
return texts;
|
|
2336
|
+
}
|
|
2190
2337
|
function sleep2(ms) {
|
|
2191
2338
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2192
2339
|
}
|