| """
|
| Download a multi-language code corpus from GitHub for base pretraining.
|
|
|
| Downloads tarballs of several popular repositories across Python, JS/TS,
|
| Rust, Go, C/C++, and Java. Extracts source files and concatenates them
|
| into a single training corpus.
|
| """
|
|
|
| import io
|
| import os
|
| import tarfile
|
| import time
|
| import requests
|
|
|
| DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "data")
|
| RAW_DIR = os.path.join(DATA_DIR, "raw")
|
| CORPUS_PATH = os.path.join(DATA_DIR, "corpus.txt")
|
|
|
|
|
| REPOS = [
|
| ("python/cpython", "main", 8_000_000),
|
| ("microsoft/TypeScript", "main", 8_000_000),
|
| ("rust-lang/rust", "master", 8_000_000),
|
| ("golang/go", "master", 8_000_000),
|
| ("nginx/nginx", "master", 5_000_000),
|
| ("json-iterator/go", "master", 3_000_000),
|
| ("pytorch/pytorch", "main", 8_000_000),
|
| ("tokio-rs/tokio", "master", 5_000_000),
|
| ("numpy/numpy", "main", 5_000_000),
|
| ("axios/axios", "v1.x", 3_000_000),
|
| ("lodash/lodash", "master", 3_000_000),
|
| ("redis/redis", "unstable", 5_000_000),
|
| ]
|
|
|
|
|
| CODE_EXTENSIONS = {
|
| ".py", ".js", ".ts", ".mjs", ".jsx", ".tsx",
|
| ".rs", ".go", ".c", ".h", ".cpp", ".cc", ".cxx",
|
| ".hpp", ".hxx", ".cu", ".cuh", ".java",
|
| ".sh", ".bash", ".yml", ".yaml", ".toml",
|
| ".cfg", ".ini", ".json", ".xml", ".sql",
|
| ".md", ".txt", ".rst",
|
| }
|
|
|
|
|
| SKIP_DIRS = {
|
| "test", "tests", "testing", "__pycache__", ".git",
|
| "node_modules", "vendor", "third_party", "thirdparty",
|
| "dist", "build", "target", ".github", "docs",
|
| "benchmark", "benchmarks", "examples", "example",
|
| "fixtures", "testdata", "test_data", "mocks",
|
| }
|
|
|
|
|
| def download_repo_tarball(user_repo: str, branch: str) -> bytes | None:
|
| """Download a repository tarball from GitHub."""
|
| url = f"https://codeload.github.com/{user_repo}/tar.gz/refs/heads/{branch}"
|
| print(f" Downloading {user_repo}@{branch}...")
|
| try:
|
| r = requests.get(url, timeout=120, stream=True)
|
| if r.status_code != 200:
|
|
|
| url2 = f"https://codeload.github.com/{user_repo}/tar.gz/refs/tags/{branch}"
|
| r = requests.get(url2, timeout=120, stream=True)
|
| if r.status_code != 200:
|
| print(f" FAILED (status {r.status_code})")
|
| return None
|
| content = r.content
|
| print(f" Downloaded {len(content) / 1e6:.1f} MB")
|
| return content
|
| except Exception as e:
|
| print(f" ERROR: {e}")
|
| return None
|
|
|
|
|
| def extract_code_files(tarball_bytes: bytes, max_bytes: int) -> list[str]:
|
| """Extract code files from a tarball, up to max_bytes total."""
|
| files = []
|
| total = 0
|
| try:
|
| with tarfile.open(fileobj=io.BytesIO(tarball_bytes), mode="r:gz") as tar:
|
| for member in tar.getmembers():
|
| if not member.isfile():
|
| continue
|
| path = member.name
|
| parts = path.split("/")
|
|
|
| if any(skip in parts for skip in SKIP_DIRS):
|
| continue
|
|
|
| _, ext = os.path.splitext(path)
|
| if ext.lower() not in CODE_EXTENSIONS:
|
| continue
|
|
|
| if member.size > 500_000:
|
| continue
|
| try:
|
| f = tar.extractfile(member)
|
| if f is None:
|
| continue
|
| content = f.read()
|
| try:
|
| text = content.decode("utf-8", errors="ignore")
|
| except Exception:
|
| continue
|
| files.append(text)
|
| total += len(text)
|
| if total >= max_bytes:
|
| break
|
| except Exception:
|
| continue
|
| except Exception as e:
|
| print(f" Extraction error: {e}")
|
| print(f" Extracted {len(files)} files, {total / 1e6:.1f} MB of code")
|
| return files
|
|
|
|
|
| def main():
|
| os.makedirs(RAW_DIR, exist_ok=True)
|
| os.makedirs(DATA_DIR, exist_ok=True)
|
|
|
| all_code = []
|
|
|
| for user_repo, branch, max_bytes in REPOS:
|
| tarball = download_repo_tarball(user_repo, branch)
|
| if tarball is None:
|
| continue
|
| files = extract_code_files(tarball, max_bytes)
|
| all_code.extend(files)
|
| time.sleep(1)
|
|
|
|
|
| print(f"\nTotal files: {len(all_code)}")
|
| total_size = sum(len(f) for f in all_code)
|
| print(f"Total corpus size: {total_size / 1e6:.1f} MB")
|
|
|
| with open(CORPUS_PATH, "w", encoding="utf-8") as f:
|
| for i, code in enumerate(all_code):
|
|
|
| f.write(code)
|
| f.write("\n<|endoftext|>\n")
|
|
|
| print(f"Corpus written to {CORPUS_PATH}")
|
| return total_size
|
|
|
|
|
| if __name__ == "__main__":
|
| main()
|
|
|