perplexity-notebooklm 0.2.2__tar.gz → 0.3.0__tar.gz
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.
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/.claude-plugin/marketplace.json +1 -1
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/.claude-plugin/plugin.json +1 -1
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/CHANGELOG.md +14 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/PKG-INFO +1 -1
- perplexity_notebooklm-0.3.0/docs/superpowers/specs/2026-06-27-dual-mcp-tools-design.md +69 -0
- perplexity_notebooklm-0.3.0/perplexity_mcp/nlm_tools.py +138 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/server.py +11 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/pyproject.toml +1 -1
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/skills/perplexity-notebooklm/SKILL.md +7 -3
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/.github/workflows/publish.yml +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/.gitignore +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/CLAUDE.md +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/LICENSE +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/README.md +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/README.pt-BR.md +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/auth/.env.example +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/auth/extract_cookies.md +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/commands/dual-research.md +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/commands/notebook-enrich.md +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/docs/BENCHMARK.md +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/docs/INNOVATION.md +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/docs/INSTALL.md +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/docs/REFINAMENTO_github_study.md +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/docs/assets/banner.svg +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/docs/benchmark_perplexity_mcp_repos.md +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/dual_flow.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/evals/run.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/evals/scenarios.jsonl +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/evals/score.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/hooks/hooks.json +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/hooks/sessionstart.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/notebooklm_write/__init__.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/notebooklm_write/add_source.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/notebooklm_write/browser.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/notebooklm_write/embed.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/notebooklm_write/ledger.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/notebooklm_write/nlm_http.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/__init__.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/adapter.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/agentic.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/auth_login.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/backends/__init__.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/backends/helallao.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/cited_search.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/doctor.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/resilience.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/security.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/validate.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/verify_citations.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/rag.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/scripts/confirm_sources_pwm.py +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/uv.lock +0 -0
- {perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/watch.py +0 -0
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
Formato: [Keep a Changelog](https://keepachangelog.com). Versionamento semântico.
|
|
4
4
|
|
|
5
|
+
## [0.3.0] — 2026-06-27
|
|
6
|
+
|
|
7
|
+
### Adicionado
|
|
8
|
+
- **Fluxo dual como tools MCP first-class** (`perplexity_mcp/nlm_tools.py`): o server
|
|
9
|
+
`perplexity-pro` agora expõe 9 tools além das do Perplexity —
|
|
10
|
+
`notebooklm_list`, `notebooklm_read_summary`, `notebooklm_add_text/add_url/add_file`,
|
|
11
|
+
`notebooklm_generate`, `dual_research_to_notebook`, `dual_notebook_to_research`,
|
|
12
|
+
`dual_research_to_media`. O Claude chama tudo direto via MCP (não mais skill rodando Python).
|
|
13
|
+
- **Annotations de segurança**: leitura = `readOnlyHint`; escrita = `destructiveHint`
|
|
14
|
+
(checkpoint humano = permission prompt do Claude Code).
|
|
15
|
+
- **Registro condicional/gracioso**: as tools só sobem se o extra `notebooklm` estiver
|
|
16
|
+
instalado (`find_spec`); install Perplexity-only fica intacto. Erro real de registro
|
|
17
|
+
loga no stderr (não polui o protocolo stdio).
|
|
18
|
+
|
|
5
19
|
## [0.2.2] — 2026-06-27
|
|
6
20
|
|
|
7
21
|
### CI
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: perplexity-notebooklm
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Integração dual NotebookLM <-> Perplexity (conta Pro, sem API key) via MCP + skill
|
|
5
5
|
Project-URL: Homepage, https://github.com/wgardim-hub/notebooklm2perplexity
|
|
6
6
|
Project-URL: Repository, https://github.com/wgardim-hub/notebooklm2perplexity
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Spec: Fluxo dual como tools MCP first-class
|
|
2
|
+
|
|
3
|
+
## Contexto
|
|
4
|
+
Hoje o MCP `perplexity-pro` expõe só Perplexity (ask/search/reason/research/healthcheck).
|
|
5
|
+
NotebookLM + o fluxo dual existem em `notebooklm_write/nlm_http.py` e `dual_flow.py`, mas
|
|
6
|
+
são acessados pela **skill rodando Python via venv** — não como tools MCP. Resultado: o
|
|
7
|
+
Claude não chama add_source/list/dual diretamente pela interface MCP. Esta feature expõe
|
|
8
|
+
tudo como tools, uniformizando o produto pela camada MCP.
|
|
9
|
+
|
|
10
|
+
## Objetivo
|
|
11
|
+
Adicionar NotebookLM (primitivas) + dual como tools no **mesmo** server `perplexity-pro`,
|
|
12
|
+
com registro condicional e annotations de segurança.
|
|
13
|
+
|
|
14
|
+
## Não-objetivos
|
|
15
|
+
- Não muda os helpers (`nlm_http`/`dual_flow`) — as tools são adaptadores finos.
|
|
16
|
+
- Não remove o caminho da skill (continua válido); só passa a preferir as tools MCP.
|
|
17
|
+
- Sem novas capacidades de NotebookLM além das já implementadas.
|
|
18
|
+
|
|
19
|
+
## Arquitetura
|
|
20
|
+
- **Novo `perplexity_mcp/nlm_tools.py`** com `register(mcp)`: define e registra as tools.
|
|
21
|
+
Imports de `nlm_http`/`dual_flow` são lazy (dentro das funções) → import do módulo não
|
|
22
|
+
quebra em install Perplexity-only.
|
|
23
|
+
- **`server.py`**: em `main()`/`_register()`, chamar `nlm_tools.register(mcp)` dentro de
|
|
24
|
+
`try/except Exception` — se `notebooklm-py` ausente, loga e segue (Perplexity-only intacto).
|
|
25
|
+
- **Annotations**: usar `ToolAnnotations`/`annotations` do FastMCP — `readOnlyHint=True` nas
|
|
26
|
+
de leitura; escrita marcada como destrutiva (`readOnlyHint=False`). Se a versão do FastMCP
|
|
27
|
+
instalada não suportar annotations, fallback: descrição explícita ("ESCREVE no notebook")
|
|
28
|
+
+ permission prompt do Claude Code (checkpoint humano default).
|
|
29
|
+
|
|
30
|
+
## Tools (retornam string/markdown human-readable)
|
|
31
|
+
Leitura (readOnly):
|
|
32
|
+
- `notebooklm_list()` — notebooks (id + título), via `nlm_http.list_notebooks_sync`.
|
|
33
|
+
- `notebooklm_read_summary(notebook_id)` — resumo, via `read_summary_sync`.
|
|
34
|
+
Escrita (destrutiva — checkpoint via permission prompt):
|
|
35
|
+
- `notebooklm_add_text(notebook_id, title, content)` — `add_text_sync`.
|
|
36
|
+
- `notebooklm_add_url(notebook_id, url)` — `add_url_sync` (web/YouTube auto).
|
|
37
|
+
- `notebooklm_add_file(notebook_id, file_path)` — `add_file_sync`.
|
|
38
|
+
- `notebooklm_generate(notebook_id, kind)` — `generate_artifact_sync` (audio|video|mind_map).
|
|
39
|
+
Dual:
|
|
40
|
+
- `dual_research_to_notebook(query, notebook_id, tool="research", verify=True, dedup=True)` (escrita).
|
|
41
|
+
- `dual_notebook_to_research(notebook_id, tool="search")` (leitura+pesquisa; não escreve).
|
|
42
|
+
- `dual_research_to_media(query, notebook_id, kind="mind_map", tool="search")` (escrita).
|
|
43
|
+
|
|
44
|
+
## Fluxo de dados
|
|
45
|
+
Claude → tool MCP → helper sync (`nlm_http`/`dual_flow`) → cited_search/notebooklm-py →
|
|
46
|
+
resultado. Cada tool formata o resultado (`.ok`/`.detail`/source_id/answer) em string.
|
|
47
|
+
|
|
48
|
+
## Erros
|
|
49
|
+
Helpers já retornam objetos de resultado (não levantam em falha esperada). As tools
|
|
50
|
+
formatam: Chrome fechado/cookie stale → mensagem clara ("abra Chrome :9222 logado").
|
|
51
|
+
Exceções inesperadas → capturadas e retornadas como texto de erro (sem stacktrace cru).
|
|
52
|
+
|
|
53
|
+
## Testes
|
|
54
|
+
- Unit (offline): `register(mcp)` adiciona as 9 tools (`mcp.list_tools()`); sem notebooklm-py
|
|
55
|
+
→ `register` é no-op gracioso; annotations de leitura/escrita corretas.
|
|
56
|
+
- Live (Chrome :9222): `notebooklm_list` retorna notebooks; `dual_notebook_to_research` retorna
|
|
57
|
+
análise. (Camada fina; helpers já validados e2e em sessões anteriores.)
|
|
58
|
+
|
|
59
|
+
## Arquivos
|
|
60
|
+
- Criar: `perplexity_mcp/nlm_tools.py`.
|
|
61
|
+
- Modificar: `perplexity_mcp/server.py` (registro condicional).
|
|
62
|
+
- Docs: `skills/perplexity-notebooklm/SKILL.md` (usar `mcp__perplexity-pro__*` direto),
|
|
63
|
+
`README*.md`, `CHANGELOG.md`; bump `0.3.0` (pyproject + plugin + marketplace).
|
|
64
|
+
|
|
65
|
+
## Verificação
|
|
66
|
+
- `mcp.list_tools()` lista Perplexity + 9 novas tools.
|
|
67
|
+
- Install Perplexity-only (sem extra notebooklm): server sobe, tools NotebookLM ausentes, sem erro.
|
|
68
|
+
- 1 tool de leitura e 1 dual funcionam live com Chrome :9222.
|
|
69
|
+
- Harness `evals/run.py` segue verde.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""Tools MCP de NotebookLM + fluxo dual (registradas no server `perplexity-pro`).
|
|
2
|
+
|
|
3
|
+
Adaptadores FINOS sobre os helpers já validados (`notebooklm_write.nlm_http` e
|
|
4
|
+
`dual_flow`). `register(mcp)` é chamado pelo server dentro de try/except — se o extra
|
|
5
|
+
`notebooklm` (notebooklm-py) não estiver instalado, o import falha e o server segue
|
|
6
|
+
só com as tools do Perplexity (degradação graciosa).
|
|
7
|
+
|
|
8
|
+
Annotations: leitura = readOnlyHint; escrita = destructiveHint (o cliente trata as de
|
|
9
|
+
escrita com cautela; o checkpoint humano é o permission prompt do Claude Code).
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from mcp.types import ToolAnnotations
|
|
15
|
+
|
|
16
|
+
_RO = ToolAnnotations(readOnlyHint=True, destructiveHint=False)
|
|
17
|
+
_WRITE = ToolAnnotations(readOnlyHint=False, destructiveHint=True)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _err(exc: Exception) -> str:
|
|
21
|
+
return f"erro: {type(exc).__name__}: {exc}"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def register(mcp) -> None:
|
|
25
|
+
"""Registra as 9 tools de NotebookLM/dual no server MCP. Import lazy dos helpers.
|
|
26
|
+
|
|
27
|
+
No-op se o extra `notebooklm` (notebooklm-py) não estiver instalado — Perplexity-only
|
|
28
|
+
não expõe tools que não conseguiriam rodar.
|
|
29
|
+
"""
|
|
30
|
+
import importlib.util
|
|
31
|
+
|
|
32
|
+
if importlib.util.find_spec("notebooklm") is None:
|
|
33
|
+
return # extra notebooklm ausente → não registra as tools
|
|
34
|
+
|
|
35
|
+
# ---- NotebookLM: leitura ----
|
|
36
|
+
def notebooklm_list() -> str:
|
|
37
|
+
"""Lista os notebooks do NotebookLM da conta (id — título). Requer Chrome :9222 logado."""
|
|
38
|
+
try:
|
|
39
|
+
from notebooklm_write.nlm_http import list_notebooks_sync
|
|
40
|
+
|
|
41
|
+
nbs = list_notebooks_sync()
|
|
42
|
+
return "\n".join(f"{nb_id} — {title}" for nb_id, title in nbs) or "(nenhum notebook)"
|
|
43
|
+
except Exception as exc:
|
|
44
|
+
return _err(exc)
|
|
45
|
+
|
|
46
|
+
def notebooklm_read_summary(notebook_id: str) -> str:
|
|
47
|
+
"""Lê o resumo de um notebook (texto). Útil p/ enriquecer/fact-check no Perplexity."""
|
|
48
|
+
try:
|
|
49
|
+
from notebooklm_write.nlm_http import read_summary_sync
|
|
50
|
+
|
|
51
|
+
return read_summary_sync(notebook_id) or "(resumo vazio)"
|
|
52
|
+
except Exception as exc:
|
|
53
|
+
return _err(exc)
|
|
54
|
+
|
|
55
|
+
# ---- NotebookLM: escrita (ESCREVE na conta — não-reversível) ----
|
|
56
|
+
def notebooklm_add_text(notebook_id: str, title: str, content: str) -> str:
|
|
57
|
+
"""ESCREVE: adiciona uma fonte de texto ao notebook."""
|
|
58
|
+
try:
|
|
59
|
+
from notebooklm_write.nlm_http import add_text_sync
|
|
60
|
+
|
|
61
|
+
r = add_text_sync(notebook_id, title, content)
|
|
62
|
+
return f"ok={r.ok} source_id={r.source_id} | {r.detail}"
|
|
63
|
+
except Exception as exc:
|
|
64
|
+
return _err(exc)
|
|
65
|
+
|
|
66
|
+
def notebooklm_add_url(notebook_id: str, url: str) -> str:
|
|
67
|
+
"""ESCREVE: adiciona fonte por URL (web ou YouTube, auto-detectado)."""
|
|
68
|
+
try:
|
|
69
|
+
from notebooklm_write.nlm_http import add_url_sync
|
|
70
|
+
|
|
71
|
+
r = add_url_sync(notebook_id, url)
|
|
72
|
+
return f"ok={r.ok} source_id={r.source_id} | {r.detail}"
|
|
73
|
+
except Exception as exc:
|
|
74
|
+
return _err(exc)
|
|
75
|
+
|
|
76
|
+
def notebooklm_add_file(notebook_id: str, file_path: str) -> str:
|
|
77
|
+
"""ESCREVE: adiciona fonte por arquivo local (PDF/DOCX/MD/...)."""
|
|
78
|
+
try:
|
|
79
|
+
from notebooklm_write.nlm_http import add_file_sync
|
|
80
|
+
|
|
81
|
+
r = add_file_sync(notebook_id, file_path)
|
|
82
|
+
return f"ok={r.ok} source_id={r.source_id} | {r.detail}"
|
|
83
|
+
except Exception as exc:
|
|
84
|
+
return _err(exc)
|
|
85
|
+
|
|
86
|
+
def notebooklm_generate(notebook_id: str, kind: str) -> str:
|
|
87
|
+
"""ESCREVE: gera artefato no notebook. kind: audio | video | mind_map (áudio/vídeo gastam cota)."""
|
|
88
|
+
try:
|
|
89
|
+
from notebooklm_write.nlm_http import generate_artifact_sync
|
|
90
|
+
|
|
91
|
+
r = generate_artifact_sync(notebook_id, kind)
|
|
92
|
+
return f"ok={r.ok} kind={r.kind} | {r.detail}"
|
|
93
|
+
except Exception as exc:
|
|
94
|
+
return _err(exc)
|
|
95
|
+
|
|
96
|
+
# ---- Dual ----
|
|
97
|
+
def dual_research_to_notebook(
|
|
98
|
+
query: str, notebook_id: str, tool: str = "research", verify: bool = True, dedup: bool = True
|
|
99
|
+
) -> str:
|
|
100
|
+
"""ESCREVE: pesquisa no Perplexity e injeta como fonte (verify filtra citações, dedup evita repetir). tool: research|search|reason."""
|
|
101
|
+
try:
|
|
102
|
+
from dual_flow import research_to_notebook
|
|
103
|
+
|
|
104
|
+
r = research_to_notebook(query, notebook_id, tool=tool, verify=verify, dedup=dedup)
|
|
105
|
+
return f"source_added={r.source_added} | {r.detail}"
|
|
106
|
+
except Exception as exc:
|
|
107
|
+
return _err(exc)
|
|
108
|
+
|
|
109
|
+
def dual_notebook_to_research(notebook_id: str, tool: str = "search") -> str:
|
|
110
|
+
"""Lê o resumo do notebook e enriquece/fact-check no Perplexity (NÃO escreve). tool: search|reason|research."""
|
|
111
|
+
try:
|
|
112
|
+
from dual_flow import notebook_to_research
|
|
113
|
+
|
|
114
|
+
r = notebook_to_research(notebook_id, tool=tool)
|
|
115
|
+
return r.answer or "(sem resposta)"
|
|
116
|
+
except Exception as exc:
|
|
117
|
+
return _err(exc)
|
|
118
|
+
|
|
119
|
+
def dual_research_to_media(
|
|
120
|
+
query: str, notebook_id: str, kind: str = "mind_map", tool: str = "search"
|
|
121
|
+
) -> str:
|
|
122
|
+
"""ESCREVE: pesquisa → fonte no notebook → gera artefato (kind: audio|video|mind_map)."""
|
|
123
|
+
try:
|
|
124
|
+
from dual_flow import research_to_media
|
|
125
|
+
|
|
126
|
+
r = research_to_media(query, notebook_id, kind=kind, tool=tool)
|
|
127
|
+
return f"source_added={r.source_added} artifact_ok={r.artifact_ok} | {r.detail}"
|
|
128
|
+
except Exception as exc:
|
|
129
|
+
return _err(exc)
|
|
130
|
+
|
|
131
|
+
# Registro com annotations (leitura vs escrita).
|
|
132
|
+
for fn in (notebooklm_list, notebooklm_read_summary, dual_notebook_to_research):
|
|
133
|
+
mcp.tool(annotations=_RO)(fn)
|
|
134
|
+
for fn in (
|
|
135
|
+
notebooklm_add_text, notebooklm_add_url, notebooklm_add_file, notebooklm_generate,
|
|
136
|
+
dual_research_to_notebook, dual_research_to_media,
|
|
137
|
+
):
|
|
138
|
+
mcp.tool(annotations=_WRITE)(fn)
|
|
@@ -13,6 +13,7 @@ autenticada — espelha o comportamento do upstream.
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
15
15
|
import os
|
|
16
|
+
import sys
|
|
16
17
|
|
|
17
18
|
from pathlib import Path
|
|
18
19
|
|
|
@@ -96,6 +97,16 @@ def _register() -> None:
|
|
|
96
97
|
mcp.tool()(perplexity_reason)
|
|
97
98
|
mcp.tool()(perplexity_research)
|
|
98
99
|
|
|
100
|
+
# NotebookLM + dual: só sobem se o extra `notebooklm` estiver instalado (gracioso).
|
|
101
|
+
# `register` já faz no-op se notebooklm-py ausente; aqui logamos qualquer erro REAL
|
|
102
|
+
# de registro no stderr (stdout é o protocolo MCP — não pode poluir) em vez de silenciar.
|
|
103
|
+
try:
|
|
104
|
+
from . import nlm_tools
|
|
105
|
+
|
|
106
|
+
nlm_tools.register(mcp)
|
|
107
|
+
except Exception as exc:
|
|
108
|
+
print(f"[perplexity-pro] aviso: tools NotebookLM/dual não registradas: {exc}", file=sys.stderr)
|
|
109
|
+
|
|
99
110
|
|
|
100
111
|
def main() -> None:
|
|
101
112
|
global BACKEND
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "perplexity-notebooklm"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "Integração dual NotebookLM <-> Perplexity (conta Pro, sem API key) via MCP + skill"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10,<3.14" # 3.14 quebra wheels do curl_cffi; testado em 3.12/3.13
|
{perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/skills/perplexity-notebooklm/SKILL.md
RENAMED
|
@@ -5,9 +5,13 @@ description: Use quando o usuário quiser pesquisar/enriquecer/fact-check com Pe
|
|
|
5
5
|
|
|
6
6
|
# Perplexity ↔ NotebookLM (fluxo dual)
|
|
7
7
|
|
|
8
|
-
Integra dois lados, ambos sem API key paga:
|
|
9
|
-
- **Perplexity
|
|
10
|
-
- **NotebookLM
|
|
8
|
+
Integra dois lados, ambos sem API key paga. **Preferir as tools MCP** (v0.3.0+) — o Claude chama direto, sem rodar Python:
|
|
9
|
+
- **Perplexity**: `mcp__perplexity-pro__perplexity_ask|search|reason|research`, `healthcheck`.
|
|
10
|
+
- **NotebookLM**: `mcp__perplexity-pro__notebooklm_list|read_summary|add_text|add_url|add_file|generate`.
|
|
11
|
+
- **Dual**: `mcp__perplexity-pro__dual_research_to_notebook` (PPLX→NLM, verify+dedup), `dual_notebook_to_research` (NLM→PPLX), `dual_research_to_media` (research→fonte→artefato).
|
|
12
|
+
- Tools de escrita têm annotation destrutiva → o Claude Code pede aprovação (checkpoint humano). Os helpers Python (`dual_flow`, `nlm_http`) seguem válidos como fallback.
|
|
13
|
+
|
|
14
|
+
Detalhes do backend: Perplexity por cookies no `.env`; NotebookLM por cookie-bridge (HTTP/RPC, fallback Selenium).
|
|
11
15
|
|
|
12
16
|
### Auth NotebookLM = cookie-bridge (uma vez)
|
|
13
17
|
O Google bloqueia login sob automação. Solução: abrir um Chrome real logado com porta de debug; o `nlm_http` extrai os cookies dele e gera o `storage_state` (depois as chamadas são HTTP puras, sem browser, até o cookie expirar).
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/docs/REFINAMENTO_github_study.md
RENAMED
|
File without changes
|
|
File without changes
|
{perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/docs/benchmark_perplexity_mcp_repos.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/backends/__init__.py
RENAMED
|
File without changes
|
{perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/backends/helallao.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{perplexity_notebooklm-0.2.2 → perplexity_notebooklm-0.3.0}/perplexity_mcp/verify_citations.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|