sanjayankur31 commited on
Commit
b41ccf1
·
verified ·
1 Parent(s): 41b0a0e

chore: import scripts to process nml-docs

Browse files
scripts/data/Readme.md ADDED
@@ -0,0 +1 @@
 
 
1
+ Scripts to generate vector stores.
scripts/data/generate-single-nml-md.sh ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Copyright 2025 Ankur Sinha
4
+ # Author: Ankur Sinha <sanjay DOT ankur AT gmail DOT com>
5
+ # File : data/scripts/generate-single-nml-md.sh
6
+ #
7
+
8
+
9
+ git clone --depth 1 https://github.com/NeuroML/Documentation nml-docs
10
+
11
+ echo "Generating bibs"
12
+ find . -name "*.bib" -type f -execdir bash -c '
13
+ for file; do
14
+ pandoc "$file" --citeproc -t markdown_strict -o "${file%.bib}.md"
15
+ done
16
+ ' bash {} +
17
+
18
+ python3 jupyterbook2singlemd.py "nml-docs/source"
19
+ mv -v single-page-markdown.md nml-docs-single-page.md
20
+ mv -v single-page-markdown-schema.md nml-docs-single-page-schema.md
21
+ mv -v url-map.json nml-docs-single-page-url-map.json
22
+
23
+ echo "Please delete the nml-docs folder and copy the generated file over to the data/files folder"
scripts/data/jupyterbook2singlemd.py ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Generate a single page markdown from Jupyter book sources
4
+
5
+ File: data/scripts/jupyterbook2singlemd.py
6
+
7
+ Copyright 2026 Ankur Sinha
8
+ Author: Ankur Sinha <sanjay DOT ankur AT gmail DOT com>
9
+ """
10
+
11
+ import json
12
+ import logging
13
+ import re
14
+ import sys
15
+ from itertools import takewhile
16
+ from pathlib import Path
17
+
18
+ import colorlog
19
+
20
+ logging.basicConfig(level=logging.NOTSET)
21
+ logger = logging.getLogger(__name__)
22
+ logger.setLevel(logging.DEBUG)
23
+
24
+ formatter = colorlog.ColoredFormatter(
25
+ "%(log_color)s%(name)s (%(levelname)s): %(message)s"
26
+ )
27
+ handler = colorlog.StreamHandler()
28
+ handler.setLevel(logging.INFO)
29
+ handler.setFormatter(formatter)
30
+
31
+ logger.addHandler(handler)
32
+
33
+
34
+ def runner(source: str):
35
+ """Main runner
36
+
37
+ :param source: TODO
38
+ :returns: TODO
39
+
40
+ """
41
+ toc = f"{source}/_toc.yml"
42
+ filelist = []
43
+ url_base = "https://docs.neuroml.org"
44
+ url_map = {"DEFAULT": {"url": url_base}}
45
+ with open(toc, "r") as toc_f:
46
+ for line in toc_f:
47
+ if "file:" in line or "root:" in line:
48
+ if "file:" in line:
49
+ source_file = Path(line.split("file:")[1].strip())
50
+ else:
51
+ source_file = Path(line.split("root:")[1].strip())
52
+
53
+ if source_file.suffix == "":
54
+ source_file_full = f"{source_file}.md"
55
+ else:
56
+ source_file_full = str(source_file)
57
+
58
+ # ignore notebooks
59
+ if source_file_full.endswith("ipynb"):
60
+ continue
61
+ print(f"Found: {source_file_full}")
62
+ filelist.append(source_file_full)
63
+ logger.debug(f"{filelist = }")
64
+
65
+ text = ""
66
+ schema_text = ""
67
+ # ignore lines starting with these
68
+ start_ignores = (
69
+ "----",
70
+ "language: ",
71
+ "lines: ",
72
+ ":class: ",
73
+ ":align: ",
74
+ ":alt: ",
75
+ ":scale: ",
76
+ ":gutter: ",
77
+ ":columns: ",
78
+ ":widths: ",
79
+ ":width: ",
80
+ ":delim: ",
81
+ ":all:",
82
+ "%",
83
+ )
84
+
85
+ # matches replace below
86
+ admons = ["admonition", "note", "warning", "tip", "important"]
87
+
88
+ # note that the order in which these are listed is important, since the
89
+ # regular expression substitutions are done sequentially in multiple passes
90
+ refs = {}
91
+ replacements = {
92
+ r"{ref}`(.+?)>`": r"\1>",
93
+ r"{ref}`(.+?)`": r"\1",
94
+ r"{doc}`(.+?)>`": r"\1>",
95
+ r"{eq}`(.+?)>`": r" (see equation \1)",
96
+ r"{cite}`(.+?)`": r"[citation: \1]",
97
+ r"{superscript}`(.+?)`": r"^\1",
98
+ # table inside tabs
99
+ r"`{4}{tab-item} (.+)\n`{3}{csv-table}\n": r"Table of \1 (separator='$')\n```\nName $ description $ reference\n",
100
+ # simple tabs
101
+ r"`{4}{tab-item} (.+)\n": r"\1\n",
102
+ # figures
103
+ r"{(image|figure)} (.+)": r"\nFigure: \2",
104
+ # admons
105
+ r"{(admonition|tip|warning|note|important)}": r"\nNOTE: ",
106
+ # other bracketed bits
107
+ r"{(code|code-block|download|grid-item-card|grid|tab-set|csv-table)}": r"",
108
+ # misc
109
+ r"(schema:|units:|<i>|</i>|&emsp;|`{5}|`{4})": r"",
110
+ r"(`{4})": r"\n",
111
+ }
112
+
113
+ for srcfile in filelist:
114
+ srcfilepath = Path(f"{source}/{srcfile}")
115
+ print(f"Processing {srcfilepath}")
116
+ adding_text_to = ""
117
+
118
+ with open(srcfilepath, "r") as srcfile_f:
119
+ in_block: list[str] = []
120
+ section_ref = ""
121
+ for line in srcfile_f:
122
+ # handle code includes
123
+ if line.startswith(start_ignores):
124
+ logger.warning(f"Ignoring line: {line = }")
125
+ continue
126
+ # logger.debug(f"Processing line: {line = }")
127
+
128
+ # section heading
129
+ if line.startswith("(") and line.strip().endswith(")="):
130
+ section_ref = f"<{line[1:-3]}>"
131
+ continue
132
+
133
+ # header
134
+ if not in_block and line.startswith("#"):
135
+ header = line.replace("#", "", count=-1)
136
+ url_map[header.strip()] = {
137
+ "url": f"{url_base}/{srcfile.replace('.md', '.html')}"
138
+ }
139
+
140
+ # section ref preceds headers, processed in the next line after section heading is processed
141
+ if len(section_ref) > 0:
142
+ refs[section_ref] = (
143
+ "(see section: " + line.replace("#", "").strip() + ")"
144
+ )
145
+ section_ref = ""
146
+
147
+ adding_text_to += "\n" + line
148
+ continue
149
+
150
+ if line.startswith("`"):
151
+ leading_backticks = "".join(
152
+ takewhile(lambda char: char == "`", line)
153
+ )
154
+
155
+ # single backticks arent blocks
156
+ if len(leading_backticks) < 2:
157
+ adding_text_to += line
158
+ continue
159
+
160
+ if len(in_block) and in_block[-1] == leading_backticks:
161
+ logger.debug(f"Leaving block: {leading_backticks}")
162
+ adding_text_to += f"{line.rstrip()}\n"
163
+ in_block.pop()
164
+ continue
165
+
166
+ in_block.append(leading_backticks)
167
+ logger.debug(f"Entered block {leading_backticks}")
168
+
169
+ if "{literalinclude}" in line:
170
+ file_to_include = line.split("{literalinclude}")[1].strip()
171
+ with open(
172
+ f"{srcfilepath.parent}/{file_to_include}", "r"
173
+ ) as incfile_f:
174
+ included_cont = incfile_f.read()
175
+ adding_text_to += f"\n\n```\n\n{included_cont}\n\n"
176
+ continue
177
+
178
+ if "{bibliography}" in line:
179
+ file_to_include = (
180
+ line.split("{bibliography}")[1]
181
+ .strip()
182
+ .replace(".bib", ".md")
183
+ )
184
+ logger.info(f"Including bibliography file {file_to_include = }")
185
+ with open(
186
+ f"{srcfilepath.parent}/{file_to_include}", "r"
187
+ ) as incfile_f:
188
+ included_cont = incfile_f.read()
189
+ adding_text_to += f"\n\n{included_cont}\n\n"
190
+ continue
191
+
192
+ isadmon = False
193
+ for m in admons:
194
+ if f"{{{m}}}" in line:
195
+ isadmon = True
196
+ admon_text = line.split(f"{{{m}}}")
197
+ adding_text_to += (
198
+ "```\n"
199
+ + m.upper()
200
+ + "\n"
201
+ + admon_text[1].strip()
202
+ + "\n\n"
203
+ )
204
+ break
205
+
206
+ if not isadmon:
207
+ adding_text_to += line
208
+
209
+ else:
210
+ adding_text_to += line.rstrip() + "\n"
211
+
212
+ if "Schemas/" in str(srcfilepath):
213
+ schema_text += adding_text_to
214
+ else:
215
+ text += adding_text_to
216
+
217
+ for pat, rep in replacements.items():
218
+ text = re.sub(pat, rep, text, count=0, flags=re.M)
219
+ for pat, rep in refs.items():
220
+ text = re.sub(pat, rep, text, count=0)
221
+
222
+ for pat, rep in replacements.items():
223
+ schema_text = re.sub(pat, rep, schema_text, count=0, flags=re.M)
224
+ for pat, rep in refs.items():
225
+ schema_text = re.sub(pat, rep, schema_text, count=0)
226
+
227
+ with open("single-page-markdown.md", "w") as out:
228
+ print(text, file=out)
229
+
230
+ with open("single-page-markdown-schema.md", "w") as out:
231
+ print(schema_text, file=out)
232
+
233
+ with open("url-map.json", "w") as f:
234
+ json.dump(url_map, f)
235
+ # print(refs)
236
+
237
+
238
+ if __name__ == "__main__":
239
+ if len(sys.argv) != 2:
240
+ sys.exit("Only one argument permitted: location of source folder")
241
+ runner(sys.argv[1])