mirror of
https://github.com/K-Dense-AI/claude-scientific-skills.git
synced 2026-03-28 07:25:14 +08:00
Implements the open-notebook skill as a comprehensive integration for the open-source, self-hosted alternative to Google NotebookLM. Addresses the gap created by Google not providing a public NotebookLM API. Developed using TDD with 44 tests covering skill structure, SKILL.md frontmatter/content, reference documentation, example scripts, API endpoint coverage, and marketplace.json registration. Includes: - SKILL.md with full documentation, code examples, and provider matrix - references/api_reference.md covering all 20+ REST API endpoint groups - references/examples.md with complete research workflow examples - references/configuration.md with Docker, env vars, and security setup - references/architecture.md with system design and data flow diagrams - scripts/ with 3 example scripts (notebook, source, chat) + test suite - marketplace.json updated to register the new skill Closes #56 https://claude.ai/code/session_015CqcNWNYmDF9sqxKxziXcz
143 lines
4.1 KiB
Python
143 lines
4.1 KiB
Python
"""
|
|
Open Notebook - Notebook Management Example
|
|
|
|
Demonstrates creating, listing, updating, and deleting notebooks
|
|
using the Open Notebook REST API.
|
|
|
|
Prerequisites:
|
|
pip install requests
|
|
|
|
Usage:
|
|
export OPEN_NOTEBOOK_URL="http://localhost:5055"
|
|
python notebook_management.py
|
|
"""
|
|
|
|
import os
|
|
import requests
|
|
|
|
BASE_URL = os.getenv("OPEN_NOTEBOOK_URL", "http://localhost:5055") + "/api"
|
|
|
|
|
|
def create_notebook(name, description=""):
|
|
"""Create a new notebook."""
|
|
response = requests.post(f"{BASE_URL}/notebooks", json={
|
|
"name": name,
|
|
"description": description,
|
|
})
|
|
response.raise_for_status()
|
|
notebook = response.json()
|
|
print(f"Created notebook: {notebook['id']} - {notebook['name']}")
|
|
return notebook
|
|
|
|
|
|
def list_notebooks(archived=False):
|
|
"""List all notebooks, optionally filtering by archived status."""
|
|
response = requests.get(f"{BASE_URL}/notebooks", params={
|
|
"archived": archived,
|
|
})
|
|
response.raise_for_status()
|
|
notebooks = response.json()
|
|
print(f"Found {len(notebooks)} notebook(s):")
|
|
for nb in notebooks:
|
|
print(f" - {nb['id']}: {nb['name']} "
|
|
f"(sources: {nb.get('source_count', 0)}, "
|
|
f"notes: {nb.get('note_count', 0)})")
|
|
return notebooks
|
|
|
|
|
|
def get_notebook(notebook_id):
|
|
"""Retrieve a single notebook by ID."""
|
|
response = requests.get(f"{BASE_URL}/notebooks/{notebook_id}")
|
|
response.raise_for_status()
|
|
return response.json()
|
|
|
|
|
|
def update_notebook(notebook_id, name=None, description=None, archived=None):
|
|
"""Update notebook fields."""
|
|
payload = {}
|
|
if name is not None:
|
|
payload["name"] = name
|
|
if description is not None:
|
|
payload["description"] = description
|
|
if archived is not None:
|
|
payload["archived"] = archived
|
|
response = requests.put(
|
|
f"{BASE_URL}/notebooks/{notebook_id}", json=payload
|
|
)
|
|
response.raise_for_status()
|
|
updated = response.json()
|
|
print(f"Updated notebook: {updated['id']} - {updated['name']}")
|
|
return updated
|
|
|
|
|
|
def delete_notebook(notebook_id, delete_sources=False):
|
|
"""Delete a notebook and optionally its exclusive sources."""
|
|
# Preview what will be deleted
|
|
preview = requests.get(
|
|
f"{BASE_URL}/notebooks/{notebook_id}/delete-preview"
|
|
).json()
|
|
print(f"Deletion will affect {preview.get('note_count', 0)} notes "
|
|
f"and {preview.get('source_count', 0)} sources")
|
|
|
|
response = requests.delete(
|
|
f"{BASE_URL}/notebooks/{notebook_id}",
|
|
params={"delete_sources": delete_sources},
|
|
)
|
|
response.raise_for_status()
|
|
print(f"Deleted notebook: {notebook_id}")
|
|
|
|
|
|
def link_source_to_notebook(notebook_id, source_id):
|
|
"""Associate an existing source with a notebook."""
|
|
response = requests.post(
|
|
f"{BASE_URL}/notebooks/{notebook_id}/sources/{source_id}"
|
|
)
|
|
response.raise_for_status()
|
|
print(f"Linked source {source_id} to notebook {notebook_id}")
|
|
|
|
|
|
def unlink_source_from_notebook(notebook_id, source_id):
|
|
"""Remove the association between a source and a notebook."""
|
|
response = requests.delete(
|
|
f"{BASE_URL}/notebooks/{notebook_id}/sources/{source_id}"
|
|
)
|
|
response.raise_for_status()
|
|
print(f"Unlinked source {source_id} from notebook {notebook_id}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Demo workflow
|
|
print("=== Notebook Management Demo ===\n")
|
|
|
|
# Create notebooks
|
|
nb1 = create_notebook(
|
|
"Protein Folding Research",
|
|
"Literature review on AlphaFold and related methods"
|
|
)
|
|
nb2 = create_notebook(
|
|
"CRISPR Gene Editing",
|
|
"Survey of CRISPR-Cas9 applications in therapeutics"
|
|
)
|
|
|
|
# List all notebooks
|
|
print()
|
|
list_notebooks()
|
|
|
|
# Update a notebook
|
|
print()
|
|
update_notebook(nb1["id"], description="Updated: Including ESMFold comparisons")
|
|
|
|
# Archive a notebook
|
|
print()
|
|
update_notebook(nb2["id"], archived=True)
|
|
print("\nActive notebooks:")
|
|
list_notebooks(archived=False)
|
|
|
|
print("\nArchived notebooks:")
|
|
list_notebooks(archived=True)
|
|
|
|
# Clean up
|
|
print()
|
|
delete_notebook(nb1["id"])
|
|
delete_notebook(nb2["id"])
|