# 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 ```bash git clone cd notebooklm-api bash setup.sh ``` Hoặc thủ công: ```bash 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 ```bash # 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: ```json { "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 ```bash NB= # 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 ```python import requests BASE = "http://localhost:3456" NB_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 ```javascript const ws = new WebSocket('ws://localhost:3456/api/notebooks//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 30–60 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 ```bash npm start # Production npm run dev # Development (auto-restart khi thay đổi file) ```