diff --git a/.github/workflows/update-quick-start-module.yml b/.github/workflows/update-quick-start-module.yml index bf6956011c9f..63ff008c38e1 100644 --- a/.github/workflows/update-quick-start-module.yml +++ b/.github/workflows/update-quick-start-module.yml @@ -7,16 +7,22 @@ on: paths: - .github/workflows/update-quick-start-module.yml - scripts/gen_quick_start_module.py + - scripts/gen_additional_platform.py - _includes/quick-start-module.js - _includes/quick_start_local.html + - _includes/quick-start-additional-platform.js + - _additional_platform/*.json push: branches: site paths: - .github/workflows/update-quick-start-module.yml - scripts/gen_quick_start_module.py + - scripts/gen_additional_platform.py - _includes/quick-start-module.js - _includes/quick_start_local.html + - _includes/quick-start-additional-platform.js + - _additional_platform/*.json workflow_dispatch: jobs: @@ -116,3 +122,40 @@ jobs: body: > This PR is auto-generated. It updates Getting Started page labels: automated pr + + update-additional-platform: + needs: [linux-nightly-matrix, windows-nightly-matrix, macos-arm64-nightly-matrix, + linux-release-matrix, windows-release-matrix, macos-arm64-release-matrix] + runs-on: "ubuntu-latest" + environment: pytorchbot-env + steps: + - name: Checkout pytorch.github.io + uses: actions/checkout@v2 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.9 + architecture: x64 + - name: Generate quick-start-additional-platform.js + shell: bash + run: | + set -ex + python3 ./scripts/gen_additional_platform.py + - name: Create Issue if failed + uses: dacbd/create-issue-action@main + if: ${{ failure() }} + with: + title: Updating additional platform quick start module failed + token: ${{secrets.PYTORCHBOT_TOKEN}} + assignees: ${{github.actor}} + labels: bug + body: Updating additional platform quick start module failed, please fix the update script or check JSON files + - name: Create Pull Request + uses: peter-evans/create-pull-request@v3 + with: + token: ${{ secrets.PYTORCHBOT_TOKEN }} + commit-message: Update quick-start-additional-platform.js + title: '[Additional Platform] Update quick-start-additional-platform.js' + body: > + This PR is auto-generated. It updates the Additional Platform Getting Started page + labels: automated pr diff --git a/_get_started/get-started-additional-platform.md b/_get_started/get-started-additional-platform.md new file mode 100644 index 000000000000..297019c671c7 --- /dev/null +++ b/_get_started/get-started-additional-platform.md @@ -0,0 +1,27 @@ +--- +layout: get_started +title: Additional Platform +permalink: /get-started/additional-platform/ +background-class: get-started-background +body-class: get-started +order: 1 +published: true +get-started-additional: true +--- + +
+
+
+ {% include quick_start_additional_platform.html %} +
+
+
+ +--- +
+ +
+ + + + diff --git a/_get_started/get-started-locally.md b/_get_started/get-started-locally.md index 6a95566a3946..361e9bffd244 100644 --- a/_get_started/get-started-locally.md +++ b/_get_started/get-started-locally.md @@ -20,6 +20,8 @@ redirect_from: "/get-started/" +

Could not find the right platform for your hardware? See the PyTorch Additional Platform page.

+ --- {% capture mac %} diff --git a/_includes/quick-start-additional-platform.js b/_includes/quick-start-additional-platform.js new file mode 100644 index 000000000000..d2bbd0fe64b5 --- /dev/null +++ b/_includes/quick-start-additional-platform.js @@ -0,0 +1,267 @@ +// ===================================================== +// Additional Platform Quick Start Module +// ===================================================== + +// Platform data loaded from JSON files (generated by gen_additional_platform.py) +var ecosystemPlatformData = {{ platformData }}; + +// HTML content loaded from _get_started/additional_platform/ directory +// (pre-converted by Python script with syntax highlighting) +var ecosystemHtmlContent = {{ markdownContent }}; + +// Get platform IDs from loaded data +var ecosystemPlatformIds = Object.keys(ecosystemPlatformData); + +// Ecosystem platform selections - simplified (no pm, no version) +var ecosystemOpts = { + build: 'stable', + os: 'linux', + platform: null +}; + +// Parse URL parameters for pre-selection +function parseUrlParams() { + var params = new URLSearchParams(window.location.search); + var platform = params.get('platform'); + var build = params.get('build') || 'stable'; + var os = params.get('os') || 'linux'; + + return { + platform: platform, + build: build, + os: os + }; +} + +// Apply URL parameter selections +function applyUrlSelections() { + var urlParams = parseUrlParams(); + + // Apply build selection + if (urlParams.build && ecosystemOpts.build !== urlParams.build) { + ecosystemOpts.build = urlParams.build; + $('.pytorch-build > .option').removeClass('selected'); + $('.pytorch-build > .option#' + urlParams.build).addClass('selected'); + } + + // Apply OS selection + if (urlParams.os && ecosystemOpts.os !== urlParams.os) { + ecosystemOpts.os = urlParams.os; + $('.os-ecosystem > .option').removeClass('selected'); + $('.os-ecosystem > .option#' + urlParams.os).addClass('selected'); + } + + // Apply platform selection + if (urlParams.platform && ecosystemPlatformData[urlParams.platform]) { + ecosystemOpts.platform = urlParams.platform; + $('.compute-platform > .option').removeClass('selected'); + $('.compute-platform > .option#' + urlParams.platform).addClass('selected'); + updateEcosystemCommand(); + updatePlatformContentDisplay(); + } +} + +// Initialize additional platform when document is ready +$(function() { + initPlatformContentContainer(); + initAdditionalPlatform(); + initAdditionalPlatformButtons(); + updatePlatformButtonStates(); + syncComputePlatformHeight(); + initPlatformContentDisplay(); + + // Apply URL parameter selections after initialization + applyUrlSelections(); +}); + +// Initialize platform content container - dynamically create divs for each platform +function initPlatformContentContainer() { + var container = $('#additional-platform-installation'); + if (!container.length) return; + + // Clear any existing static content + container.empty(); + + // Create platform content divs dynamically based on HTML content + ecosystemPlatformIds.forEach(function(platformId) { + if (ecosystemHtmlContent[platformId]) { + var contentDiv = $('
'); + // HTML content is already pre-converted with syntax highlighting + contentDiv.html(ecosystemHtmlContent[platformId]); + container.append(contentDiv); + } + }); +} + +// Note: Markdown is pre-converted to HTML by Python script (gen_additional_platform.py) +// using markdown library with codehilite extension for syntax highlighting. +// No need for client-side markdown parsing. + +// Initialize platform content display - hide all initially +function initPlatformContentDisplay() { + $('#additional-platform-installation .platform-content').hide(); +} + +// Sync left heading height with right compute platform buttons height +function syncComputePlatformHeight() { + var rightHeight = $('.compute-platform').outerHeight(); + if (rightHeight > 0) { + $('.compute-platform-heading').css('min-height', rightHeight + 'px'); + } +} + +// Populate compute platform buttons +function initAdditionalPlatformButtons() { + var platformRow = $('.compute-platform'); + if (!platformRow.length) return; + + // Generate platform buttons + ecosystemPlatformIds.forEach(function(platformId) { + var platform = ecosystemPlatformData[platformId]; + if (!platform) return; + var displayName = platform.name; + var btn = $('
' + displayName + '
'); + platformRow.append(btn); + }); + + // Sync height after buttons are generated + syncComputePlatformHeight(); + + // Bind platform button click + $('.compute-platform > .option').on('click', function() { + var platformId = this.id; + var platform = ecosystemPlatformData[platformId]; + if (!platform) return; + + // Check if supported on current OS + var supportedOS = getSupportedOS(platformId); + if (!supportedOS.includes(ecosystemOpts.os)) { + $('#command').html('' + platform.name + ' is not supported on ' + ecosystemOpts.os + ''); + return; + } + + // Select this platform + $('.compute-platform > .option').removeClass('selected'); + $(this).addClass('selected'); + ecosystemOpts.platform = platformId; + + updateEcosystemCommand(); + updatePlatformContentDisplay(); + }); +} + +// Get supported OS list from platform data structure +function getSupportedOS(platformId) { + var platform = ecosystemPlatformData[platformId]; + if (!platform) return []; + + var osSet = new Set(); + ['stable', 'preview'].forEach(function(build) { + if (platform[build]) { + Object.keys(platform[build]).forEach(function(os) { + osSet.add(os); + }); + } + }); + return Array.from(osSet); +} + +// Update platform button states (disabled/enabled) based on OS +function updatePlatformButtonStates() { + $('.compute-platform > .option').each(function() { + var platformId = this.id; + if (!platformId) return; + + var supportedOS = getSupportedOS(platformId); + var isSupported = supportedOS.includes(ecosystemOpts.os); + + if (isSupported) { + $(this).css('text-decoration', ''); + } else { + $(this).css('text-decoration', 'line-through'); + } + }); + + // If currently selected platform is not supported on new OS, deselect it + if (ecosystemOpts.platform) { + var supportedOS = getSupportedOS(ecosystemOpts.platform); + if (!supportedOS.includes(ecosystemOpts.os)) { + ecosystemOpts.platform = null; + $('.compute-platform > .option').removeClass('selected'); + $('#command').html('Select a compute platform to see the installation command.'); + updatePlatformContentDisplay(); + } + } +} + +// Update platform content display based on selected platform +function updatePlatformContentDisplay() { + // Hide all platform content first + $('#additional-platform-installation .platform-content').hide(); + + // Show selected platform content + if (ecosystemOpts.platform) { + $('#additional-platform-installation .platform-content.' + ecosystemOpts.platform).show(); + } +} + +// Initialize all click events for build/os blocks +function initAdditionalPlatform() { + // PyTorch Build + $('.pytorch-build > .option').on('click', function() { + $('.pytorch-build > .option').removeClass('selected'); + $(this).addClass('selected'); + ecosystemOpts.build = this.id; + updateEcosystemCommand(); + }); + + // OS - with platform support check + $('.os-ecosystem > .option').on('click', function() { + $('.os-ecosystem > .option').removeClass('selected'); + $(this).addClass('selected'); + ecosystemOpts.os = this.id; + + updatePlatformButtonStates(); + updateEcosystemCommand(); + }); +} + +// Update ecosystem command based on selections - simplified +function updateEcosystemCommand() { + if (!ecosystemOpts.platform) { + $('#command').html('Select a compute platform to see the installation command.'); + return; + } + + var platform = ecosystemPlatformData[ecosystemOpts.platform]; + if (!platform) { + $('#command').html('Loading platform data...'); + return; + } + + // Check if OS is supported + var supportedOS = getSupportedOS(ecosystemOpts.platform); + if (!supportedOS.includes(ecosystemOpts.os)) { + $('#command').html('' + platform.name + ' is not supported on ' + ecosystemOpts.os + ''); + return; + } + + // Get command directly from platform[build][os] + try { + var buildData = platform[ecosystemOpts.build]; + if (!buildData || !buildData[ecosystemOpts.os]) { + $('#command').html('Configuration not available for this combination'); + return; + } + + var cmd = buildData[ecosystemOpts.os]; + + if (cmd) { + $('#command').html('
' + cmd + '
'); + } else { + $('#command').html('Configuration not available for this combination'); + } + } catch (e) { + $('#command').html('Configuration not available for this combination'); + } +} diff --git a/_includes/quick_start_additional_platform.html b/_includes/quick_start_additional_platform.html new file mode 100644 index 000000000000..14f704c28b1a --- /dev/null +++ b/_includes/quick_start_additional_platform.html @@ -0,0 +1,64 @@ +

In the selector below, you will find compute platforms and configurations provided by our partners and community members. Choose your preferences and run the provided install command.

+ +
+
+
+
Compute Platform
+
+
+
PyTorch Build
+
+
+
Your OS
+
+
+
Run this Command:
+
+
+ +
+ +
+
+
Compute Platform
+
+ +
+ + +
+
+
PyTorch Build
+
+
+
Stable
+
+
+
Preview (Nightly)
+
+
+ + +
+
+
Your OS
+
+
+
Linux
+
+
+
Windows
+
+
+ + +
+
+
Run this Command:
+
+
+
Select a compute platform to see the installation command.
+
+
+
+
diff --git a/_sass/get-started.scss b/_sass/get-started.scss index ca3c335c41fe..a46dcd88614b 100644 --- a/_sass/get-started.scss +++ b/_sass/get-started.scss @@ -65,12 +65,12 @@ } .get-started-nav-link { - padding-left: rem(20px); - padding-right: rem(20px); + padding-left: rem(10px); + padding-right: rem(10px); @include desktop { - padding-left: rem(30px); - padding-right: rem(30px); + padding-left: rem(10px); + padding-right: rem(10px); } } diff --git a/scripts/gen_additional_platform.py b/scripts/gen_additional_platform.py new file mode 100644 index 000000000000..093d516c91f1 --- /dev/null +++ b/scripts/gen_additional_platform.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 +""" +Generates additional platform quick start module for +https://pytorch.org/get-started/additional-platform/ page. + +This script reads all JSON files from _additional_platform/ directory, +combines them, and generates the quick-start-additional-platform.js file. +It also reads markdown files from _get_started/additional_platform/ directory +and embeds them for dynamic content loading. + +Usage: + python3 scripts/gen_additional_platform.py + +The script will: +1. Read all JSON files from _additional_platform/ directory +2. Read all MD files from _get_started/additional_platform/ directory +3. Combine platform data into a single object (keyed by filename) +4. Replace template placeholders in _includes/quick-start-additional-platform.js +5. Output the result to assets/quick-start-additional-platform.js +""" + +import json +from pathlib import Path +from typing import Dict, Any +import markdown +from markdown.extensions.codehilite import CodeHiliteExtension +import re + +BASE_DIR = Path(__file__).parent.parent +ADDITIONAL_PLATFORM_DIR = BASE_DIR / "_additional_platform" +MARKDOWN_DIR = BASE_DIR / "_get_started" / "additional_platform" +INCLUDES_DIR = BASE_DIR / "_includes" +ASSETS_DIR = BASE_DIR / "assets" + + +def read_platform_json_files() -> Dict[str, Any]: + """Read all JSON files from _additional_platform directory.""" + platform_data = {} + + if not ADDITIONAL_PLATFORM_DIR.exists(): + print(f"Warning: {ADDITIONAL_PLATFORM_DIR} does not exist") + return platform_data + + for json_file in ADDITIONAL_PLATFORM_DIR.glob("*.json"): + try: + content = json_file.read_text() + data = json.loads(content) + # Use filename (without .json) as platform_id + platform_id = json_file.stem + platform_data[platform_id] = data + print(f"Loaded platform: {platform_id} from {json_file.name}") + except json.JSONDecodeError as e: + print(f"Error parsing {json_file.name}: {e}") + + return platform_data + + +def convert_markdown_to_html(markdown_text: str) -> str: + """Convert markdown to HTML with syntax highlighting. + + Uses Python markdown library with codehilite extension for syntax highlighting. + This produces HTML similar to Jekyll's markdownify filter. + """ + # Remove Jekyll/Kramdown special syntax (e.g., {:.no_toc}, {: #id}) + html_text = re.sub(r'\{:[^}]*\}', '', markdown_text) + + # Convert markdown to HTML with codehilite extension + # Codehilite uses Pygments for syntax highlighting (similar to Rouge used by Jekyll) + md = markdown.Markdown(extensions=[ + CodeHiliteExtension( + css_class='highlight', + guess_lang=False, + linenums=False + ), + 'fenced_code', + 'tables', + 'toc' + ]) + + html = md.convert(html_text) + return html + + +def read_markdown_files() -> Dict[str, str]: + """Read all markdown files from _get_started/additional_platform directory + and convert them to HTML with syntax highlighting.""" + html_content = {} + + if not MARKDOWN_DIR.exists(): + print(f"Warning: {MARKDOWN_DIR} does not exist") + return html_content + + for md_file in MARKDOWN_DIR.glob("*.md"): + try: + content = md_file.read_text() + # Use filename (without .md) as platform_id + platform_id = md_file.stem + # Convert markdown to HTML with syntax highlighting + html = convert_markdown_to_html(content) + html_content[platform_id] = html + print(f"Loaded and converted markdown: {platform_id} from {md_file.name}") + except Exception as e: + print(f"Error reading {md_file.name}: {e}") + + return html_content + + +def read_template() -> str: + """Read the JS template file.""" + template_path = INCLUDES_DIR / "quick-start-additional-platform.js" + if not template_path.exists(): + raise FileNotFoundError(f"Template file not found: {template_path}") + return template_path.read_text() + + +def generate_js_output(platform_data: Dict[str, Any], markdown_content: Dict[str, str]) -> str: + """Generate the final JS file by replacing template placeholders.""" + template = read_template() + + # Replace placeholders + template = template.replace("{{ platformData }}", json.dumps(platform_data, indent=2)) + # Now embedding pre-converted HTML content instead of raw markdown + template = template.replace("{{ markdownContent }}", json.dumps(markdown_content, indent=2)) + + return template + + +def write_output(content: str) -> None: + """Write the generated JS to assets directory.""" + output_path = ASSETS_DIR / "quick-start-additional-platform.js" + output_path.write_text(content) + print(f"Generated: {output_path}") + + +def main(): + """Main entry point.""" + print("Generating additional platform quick start module...") + + # Read all platform JSON files + platform_data = read_platform_json_files() + + if not platform_data: + print("No platform data found. Creating empty output.") + platform_data = {} + + # Read all markdown files + markdown_content = read_markdown_files() + + if not markdown_content: + print("No markdown content found.") + markdown_content = {} + + # Generate JS output + js_content = generate_js_output(platform_data, markdown_content) + + # Write to assets directory + write_output(js_content) + + print("Done!") + + +if __name__ == "__main__": + main()