Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/notebooklm/_artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,8 @@ async def generate_mind_map(
self,
notebook_id: str,
source_ids: builtins.list[str] | None = None,
language: str = "en",
instructions: str | None = None,
) -> dict[str, Any]:
"""Generate an interactive mind map.

Expand All @@ -997,6 +999,8 @@ async def generate_mind_map(
Args:
notebook_id: The notebook ID.
source_ids: Source IDs to include. If None, uses all sources.
language: Language code (default: "en").
instructions: Custom instructions for mind map generation.

Returns:
Dictionary with 'mind_map' (JSON data) and 'note_id'.
Expand All @@ -1014,7 +1018,7 @@ async def generate_mind_map(
None,
None,
None,
["interactive_mindmap", [["[CONTEXT]", ""]], ""],
["interactive_mindmap", [["[CONTEXT]", instructions or ""]], language],
None,
[2, None, [1]],
]
Expand Down
17 changes: 14 additions & 3 deletions src/notebooklm/cli/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -995,15 +995,20 @@ async def _generate():
help="Notebook ID (uses current if not set)",
)
@click.option("--source", "-s", "source_ids", multiple=True, help="Limit to specific source IDs")
@click.option("--language", default=None, help="Output language (default: from config or 'en')")
@click.option("--instructions", default=None, help="Custom instructions for mind map generation")
@json_option
@with_client
def generate_mind_map(ctx, notebook_id, source_ids, json_output, client_auth):
def generate_mind_map(
ctx, notebook_id, source_ids, language, instructions, json_output, client_auth
):
"""Generate mind map.

\b
Use --json for machine-readable output.
"""
nb_id = require_notebook(notebook_id)
resolved_language = resolve_language(language)

async def _run():
async with NotebookLMClient(client_auth) as client:
Expand All @@ -1013,12 +1018,18 @@ async def _run():
# Show status spinner only for console output
if json_output:
result = await client.artifacts.generate_mind_map(
nb_id_resolved, source_ids=sources
nb_id_resolved,
source_ids=sources,
language=resolved_language,
instructions=instructions,
)
else:
with console.status("Generating mind map..."):
result = await client.artifacts.generate_mind_map(
nb_id_resolved, source_ids=sources
nb_id_resolved,
source_ids=sources,
language=resolved_language,
instructions=instructions,
)

_output_mind_map_result(result, json_output)
Expand Down
34 changes: 34 additions & 0 deletions tests/integration/test_artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,40 @@ async def test_generate_mind_map_handles_dict_not_string(
assert result["mind_map"] == mind_map_dict
assert result["note_id"] == "note_dict_001"

@pytest.mark.asyncio
async def test_generate_mind_map_language_and_instructions(
self,
auth_tokens,
httpx_mock: HTTPXMock,
build_rpc_response,
):
"""generate_mind_map passes language and instructions to the RPC payload."""
captured_params = []

async with NotebookLMClient(auth_tokens) as client:

async def capturing_rpc_call(method, params, **kwargs):
if method == RPCMethod.GENERATE_MIND_MAP:
captured_params.append(params)
return None

with patch.object(
client.artifacts._core,
"rpc_call",
side_effect=capturing_rpc_call,
):
await client.artifacts.generate_mind_map(
"nb_123",
source_ids=["src_001"],
language="ja",
instructions="Focus on key relationships",
)

assert len(captured_params) == 1
mind_map_config = captured_params[0][5]
assert mind_map_config[2] == "ja"
assert mind_map_config[1][0][1] == "Focus on key relationships"

@pytest.mark.asyncio
async def test_generate_mind_map_with_source_ids_none_fetches_sources(
self,
Expand Down
Loading