import gradio as gr
import requests
import os
import re
SYSTEM_PROMPT = """You are an expert UI/UX designer specializing in redesigning HTML components with TailwindCSS. Transform the input HTML into a cleaner, more modern version with focus on spacing and layout precision.
Core Design Philosophy:
- SPACING FIRST: Prioritize proper spacing over complex styling
- PRESERVE EXISTING: Maintain the original color scheme and fonts when they exist
- SIMPLE & CLEAN: Focus on clean, minimal designs rather than overly decorative ones
- FLEXIBLE LAYOUTS: Use flexbox with proper flex properties for better control
Spacing & Layout Rules:
- Use consistent spacing scales: p-4, p-6, p-8 for padding; m-4, m-6, m-8 for margins
- Apply gap-4, gap-6, or gap-8 for flex/grid container spacing
- Use space-y-4, space-y-6 for vertical stacking
- Add flex-none to elements that should NOT stretch (buttons, labels, icons, fixed-width items)
- Use flex-1 or flex-auto only for elements that should grow/stretch
- Prefer specific widths (w-32, w-48, w-64) over arbitrary values
Color & Typography Preservation:
- ANALYZE the input HTML for existing color schemes (bg-*, text-*, border-*)
- REUSE those exact color classes in the redesigned version
- If input uses blue-500, continue using blue-* variants throughout
- If input has specific font classes (font-medium, text-lg), maintain that typography scale
- MANDATORY: ALWAYS add text-balance class to ALL titles and headings (h1, h2, h3, h4, h5, h6, and any element with large text like text-xl, text-2xl, etc.) for better text wrapping and visual balance
- Only introduce new colors if the original has none or uses basic colors
Dark Mode Support:
- DETECT dark mode classes in input (dark:*, bg-gray-900, text-white, etc.)
- If input HAS dark mode classes, PRESERVE and EXTEND them in the redesign
- If input has dark:bg-gray-800, continue using dark:* variants throughout
- If input has NO dark mode classes, DO NOT add any dark mode styling
- Maintain the same dark mode approach as the original (toggle-based or system-based)
Design Enhancement Guidelines:
- Improve visual hierarchy with better spacing, not more colors
- Add subtle shadows (shadow-sm, shadow-md) for depth
- Use rounded corners appropriately (rounded-lg, rounded-xl)
- Add hover states with opacity or subtle color shifts
- Implement focus states with ring utilities
- Use border utilities for clean separation
- Apply proper contrast ratios for accessibility
Layout Techniques:
- Use flex with gap instead of space-x/space-y when possible
- Apply justify-between, justify-center, items-center for alignment
- Use flex-none for buttons, icons, and fixed elements
- Apply max-w-* for content width constraints
- Use grid for complex layouts, flex for simple ones
Responsive Design Rules:
- ALWAYS ensure mobile-first responsive design
- Use responsive breakpoints: sm:, md:, lg:, xl: appropriately
- Stack elements vertically on mobile, arrange horizontally on larger screens
- Apply responsive padding: p-4 sm:p-6 lg:p-8
- Use responsive text sizes: text-sm md:text-base lg:text-lg
- Implement responsive flexbox: flex-col md:flex-row
- Add responsive gaps: gap-4 md:gap-6 lg:gap-8
- Ensure buttons and inputs are touch-friendly on mobile (min-h-10, p-3)
- Use responsive widths: w-full md:w-auto or w-full md:w-1/2
- Apply responsive margins: mt-4 md:mt-0 for layout adjustments
Technical Requirements:
- Return ONLY the redesigned HTML code
- PRESERVE ALL FUNCTIONALITY: Keep every link (href), image (src), form action, onclick, etc.
- MAINTAIN ALL ATTRIBUTES: Preserve all IDs, classes, data-*, aria-*, name, value, placeholder, etc.
- KEEP ALL CONTENT: Preserve all text content, alt texts, button labels exactly as provided
- DO NOT REMOVE: Never remove links, images, inputs, buttons, or any functional elements
- DO NOT CHANGE: Keep all URLs, image sources, form targets, and JavaScript references unchanged
- ENHANCE ONLY STYLING: Only modify TailwindCSS classes for visual improvements
- PRESERVE STRUCTURE: Maintain the same HTML element hierarchy and nesting
Critical Preservation Rules:
- If input has Link, output must have identical href and link text
- If input has , output must preserve exact src and alt
- If input has form inputs with name/value/placeholder, keep them exactly the same
- If input has buttons with onclick or type attributes, preserve them completely
- If input has any data attributes (data-*), maintain them unchanged
- All original text content must remain identical
- MANDATORY TEXT-BALANCE RULE: Every heading (h1-h6) and large text element (text-xl, text-2xl, text-3xl, etc.) MUST include the text-balance class
Framework-Specific Preservation (React/Vue/Svelte/Angular):
- REACT: Preserve all JSX syntax: {variable}, {function()}, className, onClick, onChange, etc.
- VUE: Preserve all Vue directives: v-if, v-for, v-model, @click, :class, {{interpolation}}, etc.
- SVELTE: Preserve all Svelte syntax: {#if}, {#each}, on:click, bind:value, {variable}, etc.
- ANGULAR: Preserve all Angular syntax: *ngIf, *ngFor, (click), [class], {{interpolation}}, etc.
- ALPINE.JS: Preserve all Alpine directives: x-data, x-show, x-if, @click, :class, etc.
- HTMX: Preserve all HTMX attributes: hx-get, hx-post, hx-target, hx-swap, etc.
- Keep all curly braces, template literals, and dynamic expressions unchanged
- Maintain all event handlers and binding syntax exactly as provided
Focus on creating clean, spacious, and well-proportioned designs that feel premium through proper spacing rather than complex styling, while ensuring zero functional changes."""
def extract_html_from_response(response_text):
"""Extract HTML code from model response"""
# Try to find HTML within code blocks first
html_pattern = r"```(?:html)?\s*(.*?)```"
matches = re.findall(html_pattern, response_text, re.DOTALL | re.IGNORECASE)
if matches:
return matches[0].strip()
# If no code blocks but response contains HTML tags, return the whole response
if re.search(r"<[^>]+>", response_text):
return response_text.strip()
# If no HTML found, return error
raise ValueError("No HTML content found in the response")
def redesign_html(html_input: str, user_prompt: str = "") -> str:
"""
Redesign HTML+TailwindCSS code with improved spacing, responsive design, and modern aesthetics.
This tool takes existing HTML with TailwindCSS classes and transforms it into a cleaner,
more modern version with better spacing, responsive design, and improved user experience.
IMPORTANT: This tool should only be used when users explicitly request to "redesign" HTML code.
Users must say "redesign" or similar intent for this tool to be activated.
Args:
html_input (str): The HTML code with TailwindCSS classes to be redesigned.
Can include React/Vue/Svelte/Angular syntax which will be preserved.
user_prompt (str, optional): Custom instructions for the redesign process.
Examples: "make it more colorful", "add animations",
"make it minimal", "improve mobile layout".
If empty, uses default redesign approach.
Returns:
str: The redesigned HTML code with improved TailwindCSS styling, preserving all
functionality, links, images, and framework-specific syntax.
Features:
- Preserves all functionality (links, images, forms, JavaScript)
- Maintains framework syntax (React JSX, Vue directives, etc.)
- Improves spacing and responsive design
- Preserves existing color schemes and fonts
- Adds proper flex-none for non-stretching elements
- Ensures mobile-first responsive design
- Supports dark mode when present in input
- Accepts custom user instructions for targeted redesign approaches
"""
# Check if HF_TOKEN is set
hf_token = os.getenv("HF_TOKEN")
if not hf_token:
return "Error: HF_TOKEN environment variable not set. Please set your HuggingFace token."
# Prepare the API request
url = "https://router.huggingface.co/sambanova/v1/chat/completions"
headers = {
"Authorization": f"Bearer {hf_token}",
"Content-Type": "application/json",
}
# Build messages with system prompt and user prompt
user_content = html_input
if user_prompt.strip():
user_content = f"User instructions: {user_prompt.strip()}\n\nHTML to redesign:\n{html_input}"
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_content},
]
data = {
"messages": messages,
"model": "DeepSeek-V3-0324",
"stream": False,
"temperature": 0.8,
}
try:
response = requests.post(url, headers=headers, json=data, timeout=30)
response.raise_for_status()
result = response.json()
response_content = result["choices"][0]["message"]["content"]
# Extract HTML from the response
try:
html_content = extract_html_from_response(response_content)
return html_content
except ValueError as e:
return f"Error: {str(e)}. Response was: {response_content[:200]}..."
except requests.exceptions.RequestException as e:
return f"Error: Failed to connect to API - {str(e)}"
except KeyError as e:
return f"Error: Unexpected API response format - {str(e)}"
except Exception as e:
return f"Error: {str(e)}"
# Custom CSS for better HTML code display
custom_css = """
"""
# Create Gradio interface
demo = gr.Interface(
fn=redesign_html,
inputs=[
gr.Textbox(
label="Custom Instructions (Optional)",
placeholder="Enter specific instructions for the redesign (e.g., 'make it more colorful', 'add animations', 'make it minimal')...",
lines=2,
value="",
),
gr.Textbox(
label="HTML Input",
placeholder="Paste your HTML+TailwindCSS code here...",
lines=10,
value='
This is a basic card
This is a basic card