docs: connect Pages API references to practical guides

Signed-off-by: zhifu gao <[email protected]>
This commit is contained in:
zhifu gao
2026-09-10 09:18:28 +00:00
parent c87086f1ce
commit 87bcc4bcc5
3 changed files with 133 additions and 0 deletions
+10
View File
@@ -28,6 +28,15 @@ jobs:
with:
python-version: '3.11'
- name: Read retained Chinese API reference
uses: actions/checkout@v4
with:
ref: gh-pages
path: previous-pages
sparse-checkout: zh/api.html
sparse-checkout-cone-mode: false
persist-credentials: false
- name: Generate API docs
run: python3 scripts/gen_api_docs.py
@@ -40,6 +49,7 @@ jobs:
python3 web-pages/product-site/build.py --output /tmp/funasr-docs-site
python3 web-pages/product-site/validate.py /tmp/funasr-docs-site
python3 web-pages/product-site/export_docs.py --site /tmp/funasr-docs-site --output gh-pages-output
python3 web-pages/product-site/link_api_guides.py --output gh-pages-output --previous previous-pages
- name: Deploy to gh-pages
uses: peaceiris/actions-gh-pages@v3
+46
View File
@@ -0,0 +1,46 @@
"""Connect API references to maintained guides without renumbering entries."""
import argparse
from pathlib import Path
from bs4 import BeautifulSoup
def link_api_guides(output: Path, previous: Path) -> None:
rendered = {}
for route, prefix, labels in (
('api.html', 'en/', ('Native Transformers quickstart', 'Python SDK guide')),
('zh/api.html', '', ('原生 Transformers 入门', 'Python SDK 指南')),
):
target = output / route
# The Chinese reference is retained by keep_files, not generated on main.
source = target if target.exists() else previous / route
soup = BeautifulSoup(source.read_text(encoding='utf-8'), 'html.parser')
welcome = soup.select('#api-welcome')
existing = soup.select('#api-practical-guides')
if len(welcome) != 1 or len(existing) > 1:
raise ValueError(f'{route}: expected one api-welcome and at most one guide entry')
if existing:
existing[0].decompose()
guides = soup.new_tag('p', id='api-practical-guides')
for index, (slug, label) in enumerate(zip(('native-transformers', 'python-api'), labels)):
if index:
guides.append(' | ')
link = soup.new_tag('a', href=f'https://www.funasr.com/{prefix}docs/{slug}.html')
link.string = label
guides.append(link)
welcome[0].append(guides)
rendered[target] = str(soup)
# Validate both inputs before changing the outgoing publication directory.
for target, content in rendered.items():
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(content, encoding='utf-8')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--output', type=Path, required=True)
parser.add_argument('--previous', type=Path, required=True)
args = parser.parse_args()
link_api_guides(args.output, args.previous)
@@ -0,0 +1,77 @@
from pathlib import Path
import sys
from bs4 import BeautifulSoup
import pytest
SITE = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(SITE))
def test_api_guides_preserve_entries_and_localize_destinations(tmp_path):
from link_api_guides import link_api_guides
output, previous = tmp_path / 'output', tmp_path / 'previous'
output.mkdir()
(previous / 'zh').mkdir(parents=True)
original = '<html><body><main><div id="api-welcome"><h2>API</h2></div><div class="api-detail" id="e3"><h2>AutoModel</h2><pre>a &lt; b</pre></div><a href="#e3">AutoModel</a></main><script>const x = "<unchanged>";</script></body></html>'
(output / 'api.html').write_text(original)
(previous / 'zh/api.html').write_text(original)
link_api_guides(output, previous)
first = {}
for route, prefix, label in [('api.html', 'en/', 'Python SDK guide'), ('zh/api.html', '', 'Python SDK 指南')]:
text = (output / route).read_text()
first[route] = text
soup = BeautifulSoup(text, 'html.parser')
before = BeautifulSoup(original, 'html.parser')
assert str(soup.select_one('#e3')) == str(before.select_one('#e3'))
assert soup.script.string == before.script.string
assert soup.select_one('a[href="#e3"]')
links = soup.select('#api-practical-guides a')
assert [a['href'] for a in links] == [
f'https://www.funasr.com/{prefix}docs/native-transformers.html',
f'https://www.funasr.com/{prefix}docs/python-api.html',
]
assert links[1].get_text() == label
link_api_guides(output, previous)
assert all((output / route).read_text() == text for route, text in first.items())
assert (previous / 'zh/api.html').read_text() == original
def test_invalid_legacy_page_does_not_partially_write(tmp_path):
from link_api_guides import link_api_guides
output, previous = tmp_path / 'output', tmp_path / 'previous'
output.mkdir()
(previous / 'zh').mkdir(parents=True)
original = '<div id="api-welcome">API</div>'
(output / 'api.html').write_text(original)
(previous / 'zh/api.html').write_text('<div>No API welcome</div>')
with pytest.raises(ValueError, match='api-welcome'):
link_api_guides(output, previous)
assert (output / 'api.html').read_text() == original
assert not (output / 'zh/api.html').exists()
def test_pages_workflow_restores_only_the_legacy_api_input():
workflow = (SITE.parents[1] / '.github/workflows/update-api-docs.yml').read_text()
assert 'ref: gh-pages' in workflow
assert 'sparse-checkout: zh/api.html' in workflow
assert 'link_api_guides.py --output gh-pages-output --previous previous-pages' in workflow
@pytest.mark.parametrize('bad', [None, '<div id="api-welcome"></div><div id="api-welcome"></div>'])
def test_missing_or_duplicate_legacy_welcome_fails_closed(tmp_path, bad):
from link_api_guides import link_api_guides
output, previous = tmp_path / 'output', tmp_path / 'previous'
output.mkdir()
(previous / 'zh').mkdir(parents=True)
original = '<div id="api-welcome">API</div>'
(output / 'api.html').write_text(original)
if bad is not None:
(previous / 'zh/api.html').write_text(bad)
with pytest.raises((ValueError, FileNotFoundError)):
link_api_guides(output, previous)
assert (output / 'api.html').read_text() == original
assert not (output / 'zh/api.html').exists()