Spaces:
Running
Running
""" | |
Specialized screenshot capture for documentation steps in support_docs.py | |
Captures specific HuggingFace Spaces deployment screenshots | |
""" | |
import asyncio | |
import os | |
from pathlib import Path | |
from playwright.async_api import async_playwright | |
import logging | |
import json | |
from datetime import datetime | |
# Configure logging | |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s') | |
logger = logging.getLogger(__name__) | |
# Documentation-specific screenshot configurations | |
DOCS_SCREENSHOTS = { | |
# Step 1: Generate & Create Space | |
"huggingface_spaces_page": { | |
"url": "https://huggingface.co/spaces", | |
"description": "HuggingFace Spaces main page", | |
"output": "img/hf_spaces_main.png", | |
"actions": [], | |
"wait_time": 3000 | |
}, | |
"new_space_button": { | |
"url": "https://huggingface.co/spaces", | |
"description": "New Space button", | |
"output": "img/hf_new_space_button.png", | |
"actions": [], | |
"selector": "button:has-text('New Space')", | |
"wait_time": 2000 | |
}, | |
"space_creation_form": { | |
"url": "https://huggingface.co/new-space", | |
"description": "Space creation form (img17.png replacement)", | |
"output": "img/img17.png", | |
"actions": [], | |
"wait_time": 3000 | |
}, | |
"hardware_selection": { | |
"url": "https://huggingface.co/new-space", | |
"description": "Hardware selection options (img16.png replacement)", | |
"output": "img/img16.png", | |
"actions": [ | |
{"type": "scroll", "y": 400} | |
], | |
"wait_time": 2000 | |
}, | |
# Step 2: Upload Files | |
"files_tab": { | |
"url": "https://huggingface.co/spaces/{username}/{space_name}/tree/main", | |
"description": "Files tab in Space", | |
"output": "img/hf_files_tab.png", | |
"actions": [], | |
"wait_time": 2000 | |
}, | |
"upload_files_button": { | |
"url": "https://huggingface.co/spaces/{username}/{space_name}/tree/main", | |
"description": "Upload files interface (img12.png replacement)", | |
"output": "img/img12.png", | |
"actions": [ | |
{"type": "click", "selector": "button:has-text('Upload files')"} | |
], | |
"wait_time": 2000 | |
}, | |
"files_after_upload": { | |
"url": "https://huggingface.co/spaces/{username}/{space_name}/tree/main", | |
"description": "Files view after upload (img8.png replacement)", | |
"output": "img/img8.png", | |
"actions": [], | |
"wait_time": 2000 | |
}, | |
# Step 3: Configure API Secrets | |
"settings_tab": { | |
"url": "https://huggingface.co/spaces/{username}/{space_name}/settings", | |
"description": "Settings tab navigation (img4.png replacement)", | |
"output": "img/img4.png", | |
"actions": [], | |
"wait_time": 2000 | |
}, | |
"variables_secrets_section": { | |
"url": "https://huggingface.co/spaces/{username}/{space_name}/settings", | |
"description": "Variables and secrets section", | |
"output": "img/hf_variables_secrets.png", | |
"actions": [ | |
{"type": "scroll", "y": 300} | |
], | |
"wait_time": 2000 | |
}, | |
"new_secret_form": { | |
"url": "https://huggingface.co/spaces/{username}/{space_name}/settings", | |
"description": "New secret configuration form (img3.png replacement)", | |
"output": "img/img3.png", | |
"actions": [ | |
{"type": "click", "selector": "button:has-text('New secret')"} | |
], | |
"wait_time": 2000 | |
}, | |
# Step 4: Monitor Build | |
"build_logs": { | |
"url": "https://huggingface.co/spaces/{username}/{space_name}", | |
"description": "Build process logs (img7.png replacement)", | |
"output": "img/img7.png", | |
"actions": [], | |
"wait_time": 3000 | |
}, | |
"successful_deployment": { | |
"url": "https://huggingface.co/spaces/{username}/{space_name}", | |
"description": "Successfully deployed Space (img1.png replacement)", | |
"output": "img/img1.png", | |
"actions": [], | |
"wait_time": 5000 | |
} | |
} | |
# Local app screenshots for main documentation | |
LOCAL_APP_SCREENSHOTS = { | |
"config_tab_full": { | |
"url": "http://localhost:7860", | |
"description": "Full configuration tab", | |
"output": "img/config_tab_full.png", | |
"actions": [ | |
{"type": "click", "selector": "button:has-text('Configure Space')"} | |
], | |
"wait_time": 2000, | |
"full_page": True | |
}, | |
"template_selection": { | |
"url": "http://localhost:7860", | |
"description": "Template selection with dropdown open", | |
"output": "img/template_selection.png", | |
"actions": [ | |
{"type": "click", "selector": "button:has-text('Configure Space')"}, | |
{"type": "wait", "time": 1000}, | |
{"type": "click", "selector": "div.gr-dropdown"} | |
], | |
"wait_time": 1500 | |
}, | |
"space_identity_section": { | |
"url": "http://localhost:7860", | |
"description": "Space identity configuration", | |
"output": "img/space_identity_config.png", | |
"actions": [ | |
{"type": "click", "selector": "button:has-text('Configure Space')"}, | |
{"type": "scroll", "y": 200} | |
], | |
"wait_time": 1000 | |
}, | |
"system_config_section": { | |
"url": "http://localhost:7860", | |
"description": "System configuration section", | |
"output": "img/system_config_section.png", | |
"actions": [ | |
{"type": "click", "selector": "button:has-text('Configure Space')"}, | |
{"type": "scroll", "y": 600} | |
], | |
"wait_time": 1000 | |
}, | |
"api_config_section": { | |
"url": "http://localhost:7860", | |
"description": "API configuration section", | |
"output": "img/api_config_section.png", | |
"actions": [ | |
{"type": "click", "selector": "button:has-text('Configure Space')"}, | |
{"type": "scroll", "y": 1200} | |
], | |
"wait_time": 1000 | |
}, | |
"preview_tab_active": { | |
"url": "http://localhost:7860", | |
"description": "Preview tab with active chat", | |
"output": "img/preview_tab_active.png", | |
"actions": [ | |
{"type": "click", "selector": "button:has-text('Preview')"}, | |
{"type": "wait", "time": 2000}, | |
{"type": "type", "selector": "textarea", "text": "Tell me about quantum mechanics"}, | |
{"type": "click", "selector": "button:has-text('Send')"}, | |
{"type": "wait", "time": 4000} | |
], | |
"wait_time": 1000 | |
}, | |
"docs_tab_overview": { | |
"url": "http://localhost:7860", | |
"description": "Documentation tab overview", | |
"output": "img/docs_tab_overview.png", | |
"actions": [ | |
{"type": "click", "selector": "button:has-text('Docs')"} | |
], | |
"wait_time": 2000 | |
}, | |
"docs_deployment_steps": { | |
"url": "http://localhost:7860", | |
"description": "Deployment steps accordion expanded", | |
"output": "img/docs_deployment_steps.png", | |
"actions": [ | |
{"type": "click", "selector": "button:has-text('Docs')"}, | |
{"type": "wait", "time": 1000}, | |
{"type": "click", "selector": "button:has-text('🗳️ Step 3: Generate & Deploy')"} | |
], | |
"wait_time": 2000 | |
} | |
} | |
async def capture_screenshot(page, config, replace_values=None): | |
"""Capture a single screenshot based on configuration""" | |
url = config['url'] | |
if replace_values: | |
for key, value in replace_values.items(): | |
url = url.replace(f"{{{key}}}", value) | |
logger.info(f"Capturing: {config['description']} -> {config['output']}") | |
try: | |
# Navigate to URL | |
await page.goto(url, wait_until='networkidle') | |
# Execute actions | |
for action in config.get('actions', []): | |
if action['type'] == 'click': | |
await page.click(action['selector']) | |
await page.wait_for_timeout(500) | |
elif action['type'] == 'type': | |
await page.fill(action['selector'], action['text']) | |
elif action['type'] == 'wait': | |
await page.wait_for_timeout(action['time']) | |
elif action['type'] == 'scroll': | |
await page.evaluate(f"window.scrollBy(0, {action['y']})") | |
await page.wait_for_timeout(500) | |
# Wait for any animations | |
await page.wait_for_timeout(config.get('wait_time', 1000)) | |
# Take screenshot | |
output_path = Path(config['output']) | |
output_path.parent.mkdir(parents=True, exist_ok=True) | |
screenshot_options = { | |
"path": str(output_path), | |
"full_page": config.get('full_page', False) | |
} | |
if config.get('selector'): | |
element = page.locator(config['selector']) | |
await element.screenshot(path=str(output_path)) | |
else: | |
await page.screenshot(**screenshot_options) | |
logger.info(f"✅ Saved: {output_path}") | |
return True | |
except Exception as e: | |
logger.error(f"❌ Failed: {config['description']} - {str(e)}") | |
return False | |
async def capture_huggingface_screenshots(username=None, space_name=None): | |
"""Capture HuggingFace-specific screenshots""" | |
logger.info("Capturing HuggingFace screenshots...") | |
if not username or not space_name: | |
logger.warning("No username/space_name provided. Using placeholders.") | |
username = "your-username" | |
space_name = "your-space-name" | |
replace_values = { | |
"username": username, | |
"space_name": space_name | |
} | |
async with async_playwright() as p: | |
browser = await p.chromium.launch(headless=False) | |
context = await browser.new_context( | |
viewport={'width': 1280, 'height': 800}, | |
device_scale_factor=2 | |
) | |
page = await context.new_page() | |
for name, config in DOCS_SCREENSHOTS.items(): | |
await capture_screenshot(page, config, replace_values) | |
await page.wait_for_timeout(1000) | |
await browser.close() | |
async def capture_local_app_screenshots(): | |
"""Capture local app screenshots""" | |
logger.info("Capturing local app screenshots...") | |
logger.info("Make sure the app is running on http://localhost:7860") | |
async with async_playwright() as p: | |
browser = await p.chromium.launch(headless=False) | |
context = await browser.new_context( | |
viewport={'width': 1280, 'height': 800}, | |
device_scale_factor=2 | |
) | |
page = await context.new_page() | |
for name, config in LOCAL_APP_SCREENSHOTS.items(): | |
await capture_screenshot(page, config) | |
await page.wait_for_timeout(1000) | |
await browser.close() | |
async def main(): | |
"""Main entry point""" | |
import sys | |
if len(sys.argv) > 1: | |
if sys.argv[1] == "local": | |
await capture_local_app_screenshots() | |
elif sys.argv[1] == "huggingface": | |
username = sys.argv[2] if len(sys.argv) > 2 else None | |
space_name = sys.argv[3] if len(sys.argv) > 3 else None | |
await capture_huggingface_screenshots(username, space_name) | |
else: | |
logger.error("Usage: python capture_docs_screenshots.py [local|huggingface] [username] [space_name]") | |
else: | |
# Capture both sets | |
await capture_local_app_screenshots() | |
logger.info("\nNow capturing HuggingFace screenshots...") | |
await capture_huggingface_screenshots() | |
if __name__ == "__main__": | |
asyncio.run(main()) |