Files
gradio-app--gradio/scripts/upload_docs_json.py
T
wehub-resource-sync adf0d17497
publish / version_or_publish (push) Has been cancelled
storybook-build / changes (push) Has been cancelled
storybook-build / :storybook-build (push) Has been cancelled
Sync Gradio Skills to Hugging Face / sync-skills (push) Has been cancelled
functional / changes (push) Has been cancelled
functional / build-frontend (push) Has been cancelled
functional / functional-test-SSR=false (push) Has been cancelled
functional / functional-reload (push) Has been cancelled
js / changes (push) Has been cancelled
js / js-test (push) Has been cancelled
docs-build / changes (push) Has been cancelled
docs-build / docs-build (push) Has been cancelled
docs-build / website-build (push) Has been cancelled
functional / functional-test-SSR=true (push) Has been cancelled
hygiene / hygiene-test (push) Has been cancelled
python / changes (push) Has been cancelled
python / build (push) Has been cancelled
python / test-ubuntu-latest-flaky (push) Has been cancelled
python / test-ubuntu-latest-not-flaky (push) Has been cancelled
python / test-windows-latest-flaky (push) Has been cancelled
python / test-windows-latest-not-flaky (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:17:32 +08:00

153 lines
5.0 KiB
Python

import json
import re
from pathlib import Path
from subprocess import run
import html2text
from bs4 import BeautifulSoup
from huggingface_hub import HfApi
api = HfApi()
def obj_divs_to_markdown(html: str) -> str:
soup = BeautifulSoup(html, "html.parser")
objs = soup.select("div.obj")
if not objs:
return ""
obj_html = "\n".join(div.decode_contents() for div in objs)
md_text = html2text.html2text(obj_html).replace(
"![](https://raw.githubusercontent.com/gradio-\napp/gradio/main/js/_website/src/lib/assets/img/anchor.svg)",
"",
)
md_text = md_text.replace("🔗\n", "")
md_text = re.sub(r"###\s*Guides[\s\S]*\Z", "", md_text)
return md_text
MAX_LEN = 2000
OVERLAP = 200
H3_PATTERN = re.compile(r"^(###\s+.+)$", re.M)
H2_PATTERN = re.compile(r"^(##\s+.+)$", re.M)
def split_with_overlap(text: str, max_len: int = MAX_LEN, overlap: int = OVERLAP):
"""Yield slices of text each ≤ max_len, adding `overlap` chars of context."""
start = 0
while start < len(text):
end = start + max_len
yield text[start:end]
start = end - overlap
def markdown_to_docs(
markdown: str,
*,
page_url: str,
page_title: str,
docs: list,
split_by_h2: bool = False,
):
"""
Convert a Markdown string into an array of doc dictionaries, each ≤ 2000 chars.
Sections are split on h_type headings; oversized sections are broken up with overlap.
"""
H_PATTERN = H2_PATTERN if split_by_h2 else H3_PATTERN
headings = [
(m.start(), m.end(), m.group(1).lstrip("# ").strip())
for m in H_PATTERN.finditer(markdown)
]
headings.append((len(markdown), len(markdown), None))
for idx in range(len(headings) - 1):
start, h_end, h_text = headings[idx]
next_start, _, _ = headings[idx + 1]
section_body = markdown[h_end:next_start].lstrip()
chunks = (
[section_body]
if len(section_body) <= MAX_LEN
else list(split_with_overlap(section_body))
)
for i, chunk in enumerate(chunks):
heading = h_text
docs.append(
dict(
text=chunk.replace("# ", "").replace("#", ""),
heading1=heading,
source_page_url=page_url,
source_page_title=page_title,
)
)
return docs
if __name__ == "__main__":
ROOT = Path(__file__).parent.parent
DOCS_DIR = (ROOT / "js/_website/build/docs").resolve()
GUIDES_DIR = (ROOT / "guides").resolve()
docs = []
for dir in DOCS_DIR.iterdir():
if dir.is_dir():
for file in dir.iterdir():
if file.is_file() and file.suffix == ".html":
html = file.read_text(encoding="utf-8")
markdown = obj_divs_to_markdown(html)
page_url = f"https://gradio.app/docs/{dir.name}/{file.name.replace('.html', '')}"
page_title = f"{dir.name.replace('-', ' ').title()} - {file.name.replace('.html', '').replace('-', ' ').title()} Docs"
docs = markdown_to_docs(
markdown, page_url=page_url, page_title=page_title, docs=docs
)
for dir in GUIDES_DIR.iterdir():
if dir.is_dir() and dir.name not in ["assets", "cn"]:
for file in dir.iterdir():
if file.is_file() and file.suffix == ".md":
markdown = file.read_text(encoding="utf-8")
page_name = file.name.replace(".md", "")
page_name = re.sub(r"^\d+_", "", page_name)
dir_name = dir.name.replace("-", " ")
dir_name = re.sub(r"^\d+_", "", dir_name)
page_url = f"https://gradio.app/guides/{page_name}"
page_title = f"{dir_name.title()} - {page_name.replace('-', ' ').title()} Guide"
docs = markdown_to_docs(
markdown,
page_url=page_url,
page_title=page_title,
docs=docs,
split_by_h2=True,
)
print(f"Generated {len(docs)} chunks.")
with open((ROOT / "scripts/docs.json").resolve(), "w") as f:
json.dump(docs, f)
result = run(
["git", "log", "-1", "--pretty=format:%H|%s"],
capture_output=True,
text=True,
check=True,
)
sha, subject = result.stdout.strip().split("|", 1)
commit_hash = sha[:7]
commit_message = subject if len(subject) <= 30 else subject[:30] + "..."
try:
commit_info = api.upload_file(
path_or_fileobj=(ROOT / "scripts/docs.json").resolve(),
path_in_repo="docs.json",
repo_id="gradio/docs",
repo_type="dataset",
commit_message=f"Changes from: {commit_hash} '{commit_message}'",
)
print("✅ docs.json uploaded")
except Exception as e:
print(f"❌ Error uploading docs.json: {e}")