-
-
Notifications
You must be signed in to change notification settings - Fork 120
Add build script for llms.txt and markdown docs #1732
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Azaya89
wants to merge
5
commits into
main
Choose a base branch
from
llm-txt
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+218
−5
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -132,3 +132,6 @@ hvplot/_version.py | |
| # pixi | ||
| .pixi | ||
| pixi.lock | ||
|
|
||
| # Sphinx doctree cache | ||
| .sphinx-doctrees/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,209 @@ | ||
| """ | ||
| Build markdown docs and llms.txt for hvPlot's LLM-facing documentation set. | ||
|
|
||
| Run as part of the docs build pipeline: | ||
| pixi run docs-build | ||
| """ | ||
|
|
||
| import shutil | ||
| import subprocess | ||
| import sys | ||
| from collections.abc import Callable | ||
| from pathlib import Path | ||
|
|
||
| ROOT = Path(__file__).parent.parent | ||
| DOC_DIR = ROOT / 'doc' | ||
| BUILTDOCS_DIR = ROOT / 'builtdocs' | ||
| OUTPUT_DIR = BUILTDOCS_DIR / 'markdown' | ||
| MARKDOWN_BASE_URL = '/markdown' | ||
|
|
||
| EXCLUDED_DIR_NAMES = {'user_guide', '.ipynb_checkpoints'} | ||
|
|
||
|
|
||
| def _is_included(rel_path: Path) -> bool: | ||
| if any(part in EXCLUDED_DIR_NAMES for part in rel_path.parts): | ||
| return False | ||
|
|
||
| if rel_path.suffix not in {'.md', '.ipynb'}: | ||
| return False | ||
|
|
||
| return True | ||
|
|
||
|
|
||
| def _iter_source_docs() -> list[Path]: | ||
| docs = [ | ||
| path | ||
| for path in DOC_DIR.rglob('*') | ||
| if path.is_file() and _is_included(path.relative_to(DOC_DIR)) | ||
| ] | ||
| return sorted(docs) | ||
|
|
||
|
|
||
| def _convert_notebook(notebook_path: Path, output_dir: Path) -> bool: | ||
| output_dir.mkdir(parents=True, exist_ok=True) | ||
| result = subprocess.run( | ||
| [ | ||
| sys.executable, | ||
| '-m', | ||
| 'jupyter', | ||
| 'nbconvert', | ||
| '--to', | ||
| 'markdown', | ||
| '--output-dir', | ||
| str(output_dir), | ||
| str(notebook_path), | ||
| ], | ||
| capture_output=True, | ||
| text=True, | ||
| ) | ||
| if result.returncode != 0: | ||
| rel = notebook_path.relative_to(DOC_DIR) | ||
| print(f' Warning: failed to convert {rel}: {result.stderr.strip()}') | ||
| return False | ||
| return True | ||
|
|
||
|
|
||
| def build_markdown_docs() -> list[Path]: | ||
| generated: list[Path] = [] | ||
| for source in _iter_source_docs(): | ||
| rel = source.relative_to(DOC_DIR) | ||
| destination_dir = OUTPUT_DIR / rel.parent | ||
|
|
||
| if source.suffix == '.md': | ||
| destination = OUTPUT_DIR / rel | ||
| destination.parent.mkdir(parents=True, exist_ok=True) | ||
| shutil.copy2(source, destination) | ||
| generated.append(rel) | ||
| print(f' Copied {rel}') | ||
| continue | ||
|
|
||
| if _convert_notebook(source, destination_dir): | ||
| generated.append(rel.with_suffix('.md')) | ||
| print(f' Converted {rel}') | ||
|
|
||
| return generated | ||
|
|
||
|
|
||
| def _default_label(path: Path) -> str: | ||
| return path.stem.replace('_', ' ') | ||
|
|
||
|
|
||
| def _section_label(path: Path) -> str: | ||
| if path == Path('index.md'): | ||
| return 'home' | ||
| if path.parent == Path('.'): | ||
| return path.stem.replace('_', ' ') | ||
| return path.parent.as_posix().replace('-', ' ') | ||
|
|
||
|
|
||
| def _api_manual_label(path: Path) -> str: | ||
| name = path.stem | ||
| for prefix in ('hvplot.hvPlot.', 'hvplot.plotting.'): | ||
| if name.startswith(prefix): | ||
| name = name.removeprefix(prefix) | ||
| break | ||
| return name.replace('_', ' ') | ||
|
|
||
|
|
||
| def _reference_label(path: Path) -> str: | ||
| if path.stem != 'index': | ||
| return _default_label(path) | ||
|
|
||
| if path.parent == Path('ref'): | ||
| return 'reference' | ||
|
|
||
| return path.parent.name.replace('_', ' ') | ||
|
|
||
|
|
||
| def _build_links( | ||
| paths: list[Path], label_builder: Callable[[Path], str] = _default_label | ||
| ) -> list[str]: | ||
| return [ | ||
| f'- [{label_builder(path)}]({MARKDOWN_BASE_URL}/{path.as_posix()})' | ||
| for path in sorted(paths) | ||
| ] | ||
|
|
||
|
|
||
| def _top_level_paths(generated_paths: list[Path]) -> list[Path]: | ||
| return [p for p in generated_paths if len(p.parts) == 1] | ||
|
|
||
|
|
||
| def _section_paths(generated_paths: list[Path], section: str) -> list[Path]: | ||
| return [p for p in generated_paths if p.is_relative_to(Path(section))] | ||
|
|
||
|
|
||
| def generate_llms_txt(generated_paths: list[Path]) -> None: | ||
| top_level_paths = _top_level_paths(generated_paths) | ||
| tutorial_paths = _section_paths(generated_paths, 'tutorials') | ||
| gallery_paths = _section_paths(generated_paths, 'gallery') | ||
| ref_paths = [ | ||
| p | ||
| for p in _section_paths(generated_paths, 'ref') | ||
| if not p.is_relative_to(Path('ref/api/manual')) | ||
| ] | ||
| api_manual_paths = _section_paths(generated_paths, 'ref/api/manual') | ||
|
|
||
| lines = [ | ||
| '# hvPlot', | ||
| '', | ||
| 'hvPlot is a high-level plotting API for the HoloViz ecosystem built on HoloViews.', | ||
| 'This file points to the generated markdown documentation selected for code-writing utility.', | ||
| '', | ||
| f'All links resolve under {MARKDOWN_BASE_URL}/.', | ||
| '', | ||
| ] | ||
|
|
||
| if top_level_paths: | ||
| lines.extend(['## Home', '']) | ||
| lines.extend(_build_links(top_level_paths, _section_label)) | ||
| lines.append('') | ||
|
|
||
| if tutorial_paths: | ||
| lines.extend(['## Tutorials', '']) | ||
| lines.extend( | ||
| [ | ||
| 'Step-by-step guides to help you master hvPlot and explore the full HoloViz ecosystem.', | ||
| '', | ||
| ] | ||
| ) | ||
| lines.extend(_build_links(tutorial_paths)) | ||
| lines.append('') | ||
|
|
||
| if gallery_paths: | ||
| lines.extend(['## Gallery', '']) | ||
| lines.extend( | ||
| ['Example visualizations using hvPlot with different backends and datasets.', ''] | ||
| ) | ||
| lines.extend(_build_links(gallery_paths)) | ||
| lines.append('') | ||
|
|
||
| if ref_paths: | ||
| lines.extend(['## Reference', '']) | ||
| lines.extend( | ||
| ['API reference and pages that provide detailed information about hvPlot’s usage.', ''] | ||
| ) | ||
| lines.extend(_build_links(ref_paths, _reference_label)) | ||
| lines.append('') | ||
|
|
||
| if api_manual_paths: | ||
| lines.extend(['## API', '']) | ||
| lines.extend(['hvPlot plotting APIs', '']) | ||
| lines.extend(_build_links(api_manual_paths, _api_manual_label)) | ||
| lines.append('') | ||
|
|
||
| llms_txt = BUILTDOCS_DIR / 'llms.txt' | ||
| llms_txt.write_text('\n'.join(lines), encoding='utf-8') | ||
| print(f'Generated {llms_txt}') | ||
|
|
||
|
|
||
| def main() -> None: | ||
| OUTPUT_DIR.mkdir(parents=True, exist_ok=True) | ||
| print('Building markdown docs for hvPlot scope...') | ||
| generated = build_markdown_docs() | ||
| print('Generating llms.txt...') | ||
| generate_llms_txt(generated) | ||
| print('Done!') | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| main() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't that making the docs build much slower?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to set
-d .sphinx-doctrees?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was due to Sphinx parallel build issues. I first encountered the problem here: https://github.com/holoviz/holoviz/actions/runs/27723798712/job/82015403537
It's not much slower IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok but this is another repository. Does hvPlot suffer from the same error?
How much slower is it without being parallel? On which machine did it run?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I think the problem is upstream from Sphinx
I didn't do a comparison tbh but it ran on my mac pretty fast. These are basically just text files so it wasn't slow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Sphinx build runs all the notebooks, it is not just processing text files.
Ok so let's check whether the problem is still present upstream before disabling anything.