notebooklm-api/README.md

7.1 KiB
Raw Permalink Blame History

notebooklm-api

REST + WebSocket API server điều khiển Google NotebookLM qua Puppeteer — giả lập thao tác người dùng thật trong Chrome.

Dùng để tích hợp NotebookLM vào chatbot, n8n, Make, Python scripts, ERP, hoặc bất kỳ hệ thống nào cần xử lý tài liệu bằng AI.


Tính năng

  • Xác thực — Mở Google login một lần, session lưu vĩnh viễn
  • Notebooks — Tạo, liệt kê, xoá notebooks
  • Sources — Thêm nguồn từ URL website, file local (.pdf, .docx, .txt, ...) hoặc văn bản paste
  • Chat đồng bộ — Gửi câu hỏi, nhận câu trả lời đầy đủ (POST)
  • Chat streaming — Nhận câu trả lời theo từng chunk realtime (WebSocket)
  • Queue tự động — Các request song song được xếp hàng, không race condition
  • Swagger UI — Tài liệu API tương tác tại /docs

Cài đặt nhanh

git clone <repo>
cd notebooklm-api
bash setup.sh

Hoặc thủ công:

npm install
cp .env.example .env   # tuỳ chỉnh nếu cần
npm start

Server khởi động tại http://localhost:3456
Swagger UI tại http://localhost:3456/docs


Đăng nhập lần đầu

# Mở browser để đăng nhập Google
curl -X POST http://localhost:3456/api/auth/login

Chrome sẽ mở → đăng nhập Google → API tự trả về khi xong. Session lưu trong ./chrome-profile/ — các lần sau tự động đăng nhập.

Dừng server: luôn dùng Ctrl+C (không dùng kill -9 để tránh mất cookies).


Biến môi trường

Biến Mặc định Mô tả
PORT 3456 Cổng HTTP/WebSocket
HEADLESS false true = ẩn cửa sổ Chrome
CHROME_PATH tự phát hiện Đường dẫn Chrome tuỳ chỉnh
API_KEY (trống) Nếu đặt, request phải có header x-api-key

API nhanh

Auth

GET  /api/auth/status      Kiểm tra đăng nhập
POST /api/auth/login       Mở browser đăng nhập Google

Notebooks

GET    /api/notebooks           Danh sách notebooks
POST   /api/notebooks           Tạo notebook  { "title": "..." }
DELETE /api/notebooks/:id       Xoá notebook

Sources

GET  /api/notebooks/:id/sources         Danh sách sources
POST /api/notebooks/:id/sources         Thêm source

Body thêm source:

{ "type": "url",  "content": "https://...", "title": "Tuỳ chọn" }
{ "type": "text", "content": "Nội dung...", "title": "Tên tài liệu" }
{ "type": "file", "content": "/đường/dẫn/tuyệt/đối/file.pdf" }

Định dạng file hỗ trợ: .pdf .txt .md .docx .doc .pptx .ppt .xlsx .xls .mp3 .mp4 .jpg .png

Chat

POST /api/notebooks/:id/chat            Hỏi đồng bộ  { "message": "..." }
GET  /api/notebooks/:id/chat/history    Lịch sử hội thoại
WS   /api/notebooks/:id/chat/stream     Chat streaming (WebSocket)

Tiện ích

GET /health     Trạng thái server + queue
GET /docs       Swagger UI

Ví dụ sử dụng

curl

NB=<notebook-id>

# Tạo notebook
curl -X POST http://localhost:3456/api/notebooks \
  -H "Content-Type: application/json" \
  -d '{"title": "Dự án Q3"}'

# Thêm URL
curl -X POST http://localhost:3456/api/notebooks/$NB/sources \
  -H "Content-Type: application/json" \
  -d '{"type":"url","content":"https://example.com/bai-viet"}'

# Thêm file local
curl -X POST http://localhost:3456/api/notebooks/$NB/sources \
  -H "Content-Type: application/json" \
  -d '{"type":"file","content":"/Users/me/Documents/report.pdf"}' \
  --max-time 90

# Hỏi
curl -X POST http://localhost:3456/api/notebooks/$NB/chat \
  -H "Content-Type: application/json" \
  -d '{"message":"Tóm tắt nội dung chính"}' --max-time 120

Python

import requests

BASE  = "http://localhost:3456"
NB_ID = "<notebook-id>"

# Thêm file
requests.post(f"{BASE}/api/notebooks/{NB_ID}/sources",
              json={"type": "file", "content": "/path/to/file.pdf"},
              timeout=90)

# Hỏi
answer = requests.post(f"{BASE}/api/notebooks/{NB_ID}/chat",
                       json={"message": "Tóm tắt tài liệu"},
                       timeout=120).json()["answer"]
print(answer)

WebSocket streaming

const ws = new WebSocket('ws://localhost:3456/api/notebooks/<NB_ID>/chat/stream');

ws.onopen = () => ws.send(JSON.stringify({ message: 'Tóm tắt nội dung' }));

ws.onmessage = ({ data }) => {
  const msg = JSON.parse(data);
  if (msg.type === 'chunk') process.stdout.write(msg.data);
  if (msg.type === 'done')  console.log('\n[Xong]');
  if (msg.type === 'error') console.error('[Lỗi]', msg.data);
};

Cấu trúc dự án

notebooklm-api/
├── src/
│   ├── server.js          Express app + debug routes
│   ├── browser.js         Puppeteer BrowserManager (singleton)
│   ├── nlm.js             Logic automation NotebookLM (core)
│   ├── queue.js           AsyncQueue — tuần tự hoá thao tác browser
│   ├── selectors.js       CSS selectors đã xác nhận trên DOM thực
│   ├── swagger.js         OpenAPI spec
│   └── routes/
│       ├── auth.js        /api/auth/*
│       ├── notebooks.js   /api/notebooks/*
│       └── chat-ws.js     WebSocket streaming
├── chrome-profile/        Session Chrome (KHÔNG xoá)
├── .env                   Biến môi trường
├── setup.sh               Script cài đặt nhanh
└── API.md                 Tài liệu API đầy đủ

Debug endpoints

Dùng khi selector bị hỏng sau khi Google cập nhật UI:

GET /debug/screenshot              Chụp ảnh Chrome hiện tại (base64 PNG)
GET /debug/home                    Liệt kê buttons trên trang chủ
GET /debug/notebook-btns/:id       Liệt kê buttons trên trang notebook
GET /debug/notebook-menu/:id       Hover card + click "..." menu, trả về menu items
GET /debug/sources/:id             Inspect DOM source panel
GET /debug/source-items/:id        HTML đầy đủ của từng source item
GET /debug/add-source-dialog/:id   Click "Thêm nguồn", snapshot dialog
GET /debug/add-url-flow/:id        Trace từng bước flow thêm URL
GET /debug/add-file-flow/:id       Trace từng bước flow upload file
GET /debug/chat/:id                Liệt kê textarea/input trên trang notebook
GET /debug/page-state/:id          Trạng thái overlay trước/sau click

Lưu ý

  • 1 thao tác tại 1 thời điểm — queue tự xếp hàng, không cần lo concurrency
  • Upload file có thể mất 3060 giây — đặt --max-time 90 khi dùng curl
  • Chat timeout mặc định 90 giây — câu hỏi phức tạp có thể cần tăng lên
  • Chrome crash? Xoá chrome-profile/SingletonLock rồi restart
  • Google có thể giới hạn automation — nếu bị chặn, đợi vài phút rồi thử lại

Scripts

npm start      # Production
npm run dev    # Development (auto-restart khi thay đổi file)