CoolFace
Apppublic

Celestiorax/dante-notebooklm-runner

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
App README

DANTE NotebookLM Runner

Runner externo Python/Docker para conectar o DANTE ao NotebookLM usando notebooklm-py.

O Worker do Cloudflare continua sendo apenas a ponte segura. Ele valida CORS, rate limit, status, gates e sanitizacao; este runner fica fora do frontend e guarda a sessao Google/NotebookLM como secret backend-only.

Por que existe

notebooklm-py e qualquer fluxo com Python, cookies Google, storage_state.json ou Playwright nao cabem com seguranca dentro do Cloudflare Worker. O desenho correto e:

DANTE UI/Worker -> /api/notebooklm/* -> runner HTTPS -> notebooklm-py -> NotebookLM

Contrato HTTP

  • GET /health
  • GET /auth/status
  • GET /auth/check
  • GET /auth/diagnostics
  • GET /auth/login-instructions
  • POST /auth/refresh
  • GET /notebooks
  • POST /notebooks/list
  • POST /notebooks/create
  • POST /notebooks/use
  • POST /sources/add-url
  • POST /sources/add-text
  • POST /sources/add-file
  • POST /sources/add
  • POST /sources/sync-manifest
  • POST /chat/ask
  • POST /artifacts/generate
  • GET /artifacts/{id}/status
  • GET /artifacts/{id}/download
  • POST /artifacts/download/metadata

GET /health e publico e retorna apenas o contrato seguro de readiness:

json
{"ok": true, "status": "ready", "ready": true, "healthy": true, "runner": "notebooklm_runner", "degraded": false}

Todos os demais endpoints exigem Authorization: Bearer NOTEBOOKLM_RUNNER_TOKEN.

Setup local

bash
python -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
uvicorn app.main:app --host 0.0.0.0 --port 8788

Docker

bash
docker build -t dante-notebooklm-runner .
docker run --env-file .env -p 8788:8788 dante-notebooklm-runner

Autenticacao NotebookLM no Hugging Face

Use uma conta Google dedicada. Gere storage_state.json ou NOTEBOOKLM_AUTH_JSON no host do runner e monte como secret/volume. Nunca copie essa sessao para Git, Worker, frontend, log publico ou prompt.

O Hugging Face Space deve ter storage persistente anexado em /data, read-write. Sem esse mount, o Space pode ate ficar online, mas a sessao Google volta a expirar ou desaparecer entre rebuilds/restarts.

Configure estas Variables no Space:

  • NOTEBOOKLM_HOME=/data/.notebooklm
  • NOTEBOOKLM_PROFILE=default
  • NOTEBOOKLM_STORAGE_STATE_PATH=/data/.notebooklm/profiles/default/storage_state.json
  • NOTEBOOKLM_DEFAULT_NOTEBOOK_ID=2315989e-2333-4639-8442-e52fd3005768
  • NOTEBOOKLM_RUNNER_REQUIRE_AUTH=true
  • NOTEBOOKLM_HL=pt-BR
  • NOTEBOOKLM_BASE_URL=https://notebooklm.google.com
  • NOTEBOOKLM_REAL_WRITE_ENABLED=false
  • NOTEBOOKLM_REAL_ARTIFACT_GENERATION_ENABLED=false

Configure estes Secrets no Space:

  • NOTEBOOKLM_RUNNER_TOKEN
  • NOTEBOOKLM_AUTH_JSON, opcional e apenas como bootstrap/fallback

Prioridade de auth:

  1. 1.NOTEBOOKLM_STORAGE_STATE_PATH, se o arquivo existe e tem tamanho maior que zero.
  2. 2.NOTEBOOKLM_HOME/profiles/<profile>/storage_state.json.
  3. 3.NOTEBOOKLM_AUTH_JSON como bootstrap backend-only; o runner valida o JSON, grava no storage_state.json resolvido e passa a preferir o arquivo persistente.
  4. 4.Sem storage e sem bootstrap, o runner retorna missing_auth e needs_login=true.

/auth/status nao prova login real. Ele mostra estado de storage e a ultima validacao conhecida. Somente /auth/check chama NotebookLM de verdade com client.notebooks.list() e pode retornar ok=true.

Interpretacao segura:

  • auth_json=present_backend_only: existe secret de bootstrap no backend; isso nao significa login valido.
  • storage_state=generated_from_auth_json: o bootstrap foi gravado no path persistente.
  • storage_state=present: existe arquivo de sessao; ainda precisa passar em /auth/check.
  • status=auth_expired_or_invalid: NotebookLM redirecionou para login ou rejeitou a sessao.
  • persistent_storage_detected=false: anexar storage persistente em /data ou corrigir permissoes.

Quando a sessao expirar, o DANTE deve mostrar NotebookLM precisa reautenticar e apontar para este runbook; nunca deve pedir senha Google na UI. Reautentique pelo terminal/Dev Mode do Space se o fluxo estiver disponivel, ou substitua o Secret NOTEBOOKLM_AUTH_JSON por um bootstrap novo e faca rebuild. Nunca retorne, copie para log ou comite cookies, tokens, JSON de auth ou storage_state.json.

Adapter real

O runner usa NotebookLMClient.from_storage() da biblioteca pinada notebooklm-py e faz binding defensivo dos metodos publicos reais:

  • client.notebooks.list()
  • client.notebooks.create(title)
  • client.notebooks.get(notebook_id)
  • client.sources.add_url(notebook_id, url)
  • client.sources.add_text(notebook_id, title, content)
  • client.chat.ask(notebook_id, prompt, ...)
  • client.artifacts.generate_* quando artifact_type e suportado

Reads podem executar com auth valido. Writes reais retornam status=blocked, reason=real_write_disabled, executed=false ate NOTEBOOKLM_REAL_WRITE_ENABLED=true. Artefatos reais ficam bloqueados ate NOTEBOOKLM_REAL_ARTIFACT_GENERATION_ENABLED=true.

Se a API do notebooklm-py mudar, o runner retorna status=adapter_error ou status=unsupported com mensagem sanitizada, sem traceback publico.

Testes

Local:

bash
python -m compileall app
python -m pytest

Producao/Hugging Face, em PowerShell:

powershell
$base = "https://SEU-SPACE.hf.space"
$headers = @{ Authorization = "Bearer $env:NOTEBOOKLM_RUNNER_TOKEN" }
Invoke-RestMethod "$base/health" -Headers $headers
Invoke-RestMethod "$base/auth/status" -Headers $headers
Invoke-RestMethod "$base/auth/diagnostics" -Headers $headers
Invoke-RestMethod "$base/auth/check" -Headers $headers
Invoke-RestMethod "$base/auth/login-instructions" -Headers $headers
Invoke-RestMethod "$base/notebooks" -Headers $headers
Invoke-RestMethod "$base/notebooks/list" -Headers $headers -Method Post -Body "{}" -ContentType "application/json"
Invoke-RestMethod "$base/notebooks/create" -Headers $headers -Method Post -Body '{"title":"DANTE smoke","dry_run":false}' -ContentType "application/json"
Invoke-RestMethod "$base/sources/add-text" -Headers $headers -Method Post -Body '{"notebook_id":"NOTEBOOK_ID","title":"Smoke.md","text":"Teste DANTE","dry_run":false}' -ContentType "application/json"
Invoke-RestMethod "$base/chat/ask" -Headers $headers -Method Post -Body '{"notebook_id":"NOTEBOOK_ID","prompt":"Resuma as fontes em uma frase."}' -ContentType "application/json"

Com NOTEBOOKLM_REAL_WRITE_ENABLED=false, o create/add-text real deve voltar bloqueado. Para writes reais, habilite a flag somente depois dos gates do DANTE estarem validados.

Worker secrets

Configure no Cloudflare:

bash
npx wrangler secret put NOTEBOOKLM_RUNNER_URL
npx wrangler secret put NOTEBOOKLM_RUNNER_TOKEN
npx wrangler secret put NOTEBOOKLM_ENABLED
npx wrangler secret put NOTEBOOKLM_REAL_WRITE_ENABLED
npx wrangler secret put NOTEBOOKLM_REAL_ARTIFACT_GENERATION_ENABLED

Mantenha NOTEBOOKLM_REAL_WRITE_ENABLED=false e NOTEBOOKLM_REAL_ARTIFACT_GENERATION_ENABLED=false ate health, auth, Admin Lock, Approval Center e Risk Manager estarem validados.

Nunca fazer

  • Nao commitar storage_state.json, NOTEBOOKLM_AUTH_JSON, cookies, tokens ou emails sensiveis.
  • Nao aceitar requests diretos do browser no runner.
  • Nao habilitar write/artifacts reais sem gates.
  • Nao retornar tracebacks com secrets.
  • Nao marcar DANTE como real_controlled antes de /health, /auth/status e smoke tests passarem.