Spaces:
Sleeping
Sleeping
File size: 5,881 Bytes
eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 eba4c06 044a142 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
import re
import requests
import nbformat
RAW_ROOT = "https://raw.githubusercontent.com/Qiskit/textbook/main/notebooks/"
# README locations we now support
_SECTIONS: dict[str, str] = {
"intro": "intro/README.md",
"ch-states": "ch-states/README.md",
"ch-gates": "ch-gates/README.md",
"ch-algorithms":"ch-algorithms/README.md",
}
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# internals
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def _scrape_readme(rel_path: str) -> list[str]:
"""Return *.ipynb files mentioned in a README; empty list on failure."""
try:
md = requests.get(f"{RAW_ROOT}{rel_path}", timeout=10).text
# markdown link target: (...filename.ipynb)
return re.findall(r"\(([^)]+?\.ipynb)\)", md)
except requests.RequestException:
return []
def _discover_files() -> list[str]:
"""Aggregate notebooks from all configured READMEs (no fallback)."""
files: list[str] = []
for dir_key, readme in _SECTIONS.items():
found = _scrape_readme(readme)
# Prepend the directory path if the README gives bare filenames
prefixed = [
name if "/" in name else f"{dir_key}/{name}" for name in found
]
files.extend(prefixed)
return files
def _pretty(path: str) -> str:
"""'ch-states/bloch_sphere.ipynb' β 'Bloch Sphere'."""
fname = path.rsplit("/", 1)[-1]
return fname.replace("-", " ").replace(".ipynb", "").title()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# public tools
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def get_theory_topics() -> dict[str, str]:
"""Return a mapping of friendly topic names to notebook file paths.
Discovers available Jupyter notebooks from the Qiskit textbook across all
four main chapters (intro, ch-states, ch-gates, ch-algorithms) by scraping
their respective README files.
Returns:
dict[str, str]: A dictionary mapping human-readable topic names to their
corresponding notebook file paths. For example:
{'What Is Quantum': 'intro/what-is-quantum.ipynb',
'Bloch Sphere': 'ch-states/bloch_sphere.ipynb'}
Returns an empty dictionary if network requests fail.
Note:
If network requests fail, returns an empty dictionary instead of
falling back to hardcoded content.
"""
try:
discovered_files = _discover_files()
if not discovered_files:
return {}
return {_pretty(p): p for p in discovered_files}
except Exception:
return {}
def get_theory(
topic: str,
markdown_only: bool = True,
include_headers: bool = True,
) -> str:
"""Download and parse a Qiskit textbook notebook, returning its content as text.
Accepts flexible topic identification: pretty names ("Teleportation"),
slugs ("teleportation"), or full paths ("intro/teleportation.ipynb").
Downloads the notebook from GitHub and extracts its content.
Args:
topic (str): The quantum topic to fetch. Can be:
- Pretty name: "Teleportation", "What Is Quantum"
- Slug: "teleportation", "what-is-quantum"
- Full path: "intro/teleportation.ipynb"
markdown_only (bool, optional): If True, include only markdown cells.
If False, also include code cells wrapped in ```python blocks.
Defaults to True.
include_headers (bool, optional): If True, prepend an H1 header with
the topic name for better readability. Defaults to True.
Returns:
str: The concatenated content of the notebook as formatted text,
with cells separated by double newlines. Returns error messages
if the topic is not found or if network requests fail.
Example:
>>> content = get_theory("teleportation")
>>> print(content[:100])
# Teleportation
Quantum teleportation is a process by which quantum information...
"""
topics = get_theory_topics()
# Build lenient lookup table
lookup: dict[str, str] = {}
for nice, path in topics.items():
slug = path.rsplit("/", 1)[-1].removesuffix(".ipynb")
lookup[nice.lower()] = path
lookup[slug.lower()] = path
lookup[path.lower()] = path
key = topic.lower()
if key not in lookup:
if not topics:
return "Unable to get theory - no topics available (network may be down)"
available_topics = ', '.join(topics.keys())
return f"Topic unknown: '{topic}'. Available topics: {available_topics}"
path = lookup[key]
try:
raw_json = requests.get(f"{RAW_ROOT}{path}", timeout=20).text
nb = nbformat.reads(raw_json, as_version=4)
except Exception:
return "Unable to get theory - failed to download or parse notebook content"
chunks: list[str] = []
if include_headers:
chunks.append(f"# {_pretty(path)}\n")
for cell in nb.cells:
if cell.cell_type == "markdown":
chunks.append(cell.source)
elif cell.cell_type == "code" and not markdown_only:
chunks.append(f"```python\n{cell.source}\n```")
return "\n\n".join(chunks) |