Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import json | |
| import os | |
| from PIL import Image | |
| import tempfile | |
| # from utils.extractor import DesignTokenExtractor | |
| # from utils.token_generator import TokenCodeGenerator | |
| def create_token_preview(tokens): | |
| """Create HTML preview of extracted tokens""" | |
| html = """ | |
| <div style="font-family: system-ui, sans-serif; padding: 20px; background: #f9fafb; border-radius: 8px;"> | |
| <h3 style="margin-top: 0; color: #1f2937;">Extracted Design Tokens</h3> | |
| """ | |
| # Color palette preview | |
| if 'colors' in tokens and tokens['colors']: | |
| html += """ | |
| <div style="margin-bottom: 24px;"> | |
| <h4 style="color: #6b7280; font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em;">Colors</h4> | |
| <div style="display: flex; gap: 12px; flex-wrap: wrap;"> | |
| """ | |
| for name, color in tokens['colors'].items(): | |
| html += f""" | |
| <div style="text-align: center;"> | |
| <div style="width: 80px; height: 80px; background: {color['hex']}; | |
| border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);"></div> | |
| <div style="margin-top: 8px;"> | |
| <div style="font-size: 12px; font-weight: 600; color: #374151;">{name}</div> | |
| <div style="font-size: 11px; color: #9ca3af;">{color['hex']}</div> | |
| <div style="font-size: 10px; color: #9ca3af;">{int(color.get('proportion', 0) * 100)}%</div> | |
| </div> | |
| </div> | |
| """ | |
| html += "</div></div>" | |
| # Spacing preview | |
| if 'spacing' in tokens and tokens['spacing']: | |
| html += """ | |
| <div style="margin-bottom: 24px;"> | |
| <h4 style="color: #6b7280; font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em;">Spacing</h4> | |
| <div style="display: flex; gap: 16px; align-items: flex-end;"> | |
| """ | |
| for name, value in tokens['spacing'].items(): | |
| try: | |
| height = value.replace('px', '') | |
| html += f""" | |
| <div style="text-align: center;"> | |
| <div style="width: 60px; height: {height}px; background: #3b82f6; | |
| border-radius: 4px; opacity: 0.8;"></div> | |
| <div style="margin-top: 8px;"> | |
| <div style="font-size: 12px; font-weight: 600; color: #374151;">{name}</div> | |
| <div style="font-size: 11px; color: #9ca3af;">{value}</div> | |
| </div> | |
| </div> | |
| """ | |
| except: | |
| pass | |
| html += "</div></div>" | |
| # Typography preview | |
| if 'typography' in tokens and tokens['typography']: | |
| html += """ | |
| <div style="margin-bottom: 24px;"> | |
| <h4 style="color: #6b7280; font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em;">Typography</h4> | |
| """ | |
| for name, props in tokens['typography'].items(): | |
| size = props.get('size', '16px') | |
| weight = props.get('weight', '400') | |
| family = props.get('family', 'sans-serif') | |
| html += f""" | |
| <div style="margin-bottom: 12px; padding: 12px; background: white; border-radius: 6px;"> | |
| <div style="font-size: {size}; font-weight: {weight}; font-family: {family}; color: #1f2937;"> | |
| Sample {name.title()} Text | |
| </div> | |
| <div style="font-size: 11px; color: #9ca3af; margin-top: 4px;"> | |
| {family} • {size} • Weight {weight} | |
| </div> | |
| </div> | |
| """ | |
| html += "</div>" | |
| html += "</div>" | |
| return html | |
| def process_screenshot(image, output_format, progress=None): | |
| """Process uploaded screenshot and extract design tokens""" | |
| if image is None: | |
| return None, "Please upload a screenshot", None | |
| # Temporary stub implementation for testing | |
| try: | |
| # Mock tokens for testing | |
| tokens = { | |
| "colors": { | |
| "primary": {"hex": "#3B82F6", "rgb": "rgb(59, 130, 246)", "proportion": 0.25}, | |
| "secondary": {"hex": "#8B5CF6", "rgb": "rgb(139, 92, 246)", "proportion": 0.15} | |
| }, | |
| "spacing": { | |
| "small": "8px", | |
| "medium": "16px", | |
| "large": "32px" | |
| }, | |
| "typography": { | |
| "heading": {"family": "sans-serif", "size": "32px", "weight": "700"}, | |
| "body": {"family": "sans-serif", "size": "16px", "weight": "400"} | |
| } | |
| } | |
| # Simple CSS output for testing | |
| code_output = ":root {\n --color-primary: #3B82F6;\n --color-secondary: #8B5CF6;\n --spacing-small: 8px;\n --spacing-medium: 16px;\n --spacing-large: 32px;\n}" | |
| # Save output file | |
| output_filename = "design_tokens.css" | |
| with open(output_filename, "w") as f: | |
| f.write(code_output) | |
| # Create preview visualization | |
| preview_html = create_token_preview(tokens) | |
| return preview_html, code_output, output_filename | |
| except Exception as e: | |
| return None, f"Error processing screenshot: {str(e)}", None | |
| def create_gradio_app(): | |
| """Create the main Gradio application""" | |
| with gr.Blocks( | |
| title="Design Token Extractor", | |
| theme=gr.themes.Soft(), | |
| css=""" | |
| .gradio-container { | |
| font-family: 'Inter', system-ui, sans-serif; | |
| } | |
| .gr-button-primary { | |
| background-color: #3b82f6 !important; | |
| } | |
| """ | |
| ) as app: | |
| gr.Markdown( | |
| """ | |
| # 🎨 Design Token Extractor | |
| Transform UI screenshots into structured design token libraries using AI-powered analysis. | |
| Upload a screenshot to automatically extract colors, spacing, typography, and component tokens. | |
| --- | |
| """ | |
| ) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| input_image = gr.Image( | |
| label="Upload UI Screenshot", | |
| type="pil", | |
| sources=["upload", "clipboard"], | |
| height=400 | |
| ) | |
| output_format = gr.Radio( | |
| choices=[ | |
| "CSS Variables", | |
| "Tailwind Config", | |
| "JSON Tokens", | |
| "Style Dictionary", | |
| "SCSS Variables" | |
| ], | |
| value="CSS Variables", | |
| label="Output Format", | |
| info="Choose the format for your design tokens" | |
| ) | |
| extract_btn = gr.Button( | |
| "🚀 Extract Design Tokens", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| gr.Markdown( | |
| """ | |
| ### Tips for best results: | |
| - Use high-quality screenshots (min 800px width) | |
| - Include various UI elements for comprehensive extraction | |
| - Screenshots with clear color hierarchy work best | |
| - Ensure good contrast between elements | |
| """ | |
| ) | |
| with gr.Column(scale=1): | |
| preview = gr.HTML( | |
| label="Token Preview", | |
| value="<div style='padding: 20px; text-align: center; color: #9ca3af;'>Upload a screenshot to see extracted tokens</div>" | |
| ) | |
| code_output = gr.Code( | |
| label="Generated Code", | |
| language="css", | |
| lines=20, | |
| value="// Your design tokens will appear here" | |
| ) | |
| download_file = gr.File( | |
| label="Download Tokens", | |
| visible=True | |
| ) | |
| # Examples section commented out until example images are available | |
| # gr.Markdown("### Example Screenshots") | |
| # gr.Examples( | |
| # examples=[ | |
| # ["examples/dashboard.png", "CSS Variables"], | |
| # ["examples/landing_page.png", "Tailwind Config"], | |
| # ["examples/mobile_app.png", "JSON Tokens"] | |
| # ], | |
| # inputs=[input_image, output_format], | |
| # cache_examples=False | |
| # ) | |
| # Connect the extraction function | |
| extract_btn.click( | |
| fn=process_screenshot, | |
| inputs=[input_image, output_format], | |
| outputs=[preview, code_output, download_file] | |
| ) | |
| # Add footer | |
| gr.Markdown( | |
| """ | |
| --- | |
| ### Features: | |
| - **Color Extraction**: Identifies dominant colors and creates semantic color roles | |
| - **Spacing Detection**: Analyzes layout patterns to extract consistent spacing values | |
| - **Typography Analysis**: Detects font styles and creates text hierarchy tokens | |
| - **Multiple Output Formats**: Export to CSS, Tailwind, JSON, Style Dictionary, or SCSS | |
| Built with ❤️ using Gradio and computer vision models | |
| """ | |
| ) | |
| return app | |
| if __name__ == "__main__": | |
| app = create_gradio_app() | |
| app.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=True, | |
| show_error=True | |
| ) |