codenuk_backend_mine/services/ai-mockup-service/docs/INTEGRATION_GUIDE.md
2025-10-10 08:56:39 +05:30

15 KiB

SVG-Based Wireframe Generation - Integration Guide

This guide explains how to implement and integrate the SVG-based wireframe generation system that converts natural language prompts into precise, scalable vector graphics.

🎯 Why SVG Instead of JSON?

Advantages of SVG Approach:

  1. Precise Positioning: Exact coordinates and dimensions
  2. Better Performance: Direct rendering without parsing overhead
  3. Scalable Graphics: Vector-based, resolution-independent
  4. Rich Styling: Colors, gradients, shadows, and effects
  5. Standard Format: Widely supported across platforms

Comparison:

Aspect JSON Approach SVG Approach
Precision Approximate positioning Exact positioning
Performance Slower (parsing + generation) Faster (direct rendering)
Styling Limited color options Full CSS styling support
Complexity Simple shapes only Complex paths and effects
Maintenance Frontend logic heavy Backend logic heavy

🏗️ System Architecture

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   Frontend      │    │    Backend       │    │   Claude AI     │
│   (React)       │◄──►│   (Flask)        │◄──►│   (API)         │
│                 │    │                  │    │                 │
│ • tldraw Canvas │    │ • Prompt         │    │ • Natural       │
│ • SVG Parser    │    │   Processing     │    │   Language      │
│ • Response      │    │ • SVG Generation │    │   Analysis      │
│   Handler       │    │ • Response       │    │ • Layout        │
└─────────────────┘    │   Routing        │    │   Generation    │
                       └──────────────────┘    └─────────────────┘

🔄 Data Flow

1. User Input

User types: "Dashboard with header, sidebar, and 3 stats cards"

2. Frontend Request

const response = await fetch('/generate-wireframe', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ prompt: userPrompt })
})

3. Backend Processing

# Flask backend receives prompt
@app.route('/generate-wireframe', methods=['POST'])
def generate_wireframe():
    prompt = request.json.get('prompt')
    
    # Send to Claude AI
    claude_response = call_claude_api(prompt)
    
    # Generate SVG from AI response
    svg_content = generate_svg_wireframe(claude_response)
    
    # Return SVG with proper content type
    return svg_content, 200, {'Content-Type': 'image/svg+xml'}

4. SVG Response

<svg width="800" height="600" viewBox="0 0 800 600">
  <defs>
    <filter id="shadow" y="-40%" x="-40%" width="180%" height="180%">
      <feDropShadow dx="1" dy="1" stdDeviation="1.2" flood-opacity=".5"/>
    </filter>
  </defs>
  <g>
    <!-- Header -->
    <rect x="0" y="0" width="800" height="60" fill="#f0f0f0"/>
    <text x="20" y="35" font-family="Arial" font-size="16">Dashboard Header</text>
    
    <!-- Sidebar -->
    <rect x="0" y="60" width="200" height="540" fill="#e0e0e0"/>
    <text x="20" y="85" font-family="Arial" font-size="14">Navigation</text>
    
    <!-- Stats Cards -->
    <rect x="220" y="80" width="160" height="120" fill="#ffffff" filter="url(#shadow)"/>
    <text x="240" y="100" font-family="Arial" font-size="12">Stats Card 1</text>
    
    <rect x="400" y="80" width="160" height="120" fill="#ffffff" filter="url(#shadow)"/>
    <text x="420" y="100" font-family="Arial" font-size="12">Stats Card 2</text>
    
    <rect x="580" y="80" width="160" height="120" fill="#ffffff" filter="url(#shadow)"/>
    <text x="600" y="100" font-family="Arial" font-size="12">Stats Card 3</text>
  </g>
</svg>

5. Frontend Rendering

// Check response type
const contentType = response.headers.get('content-type')

if (contentType && contentType.includes('image/svg+xml')) {
  // Handle SVG response
  const svgString = await response.text()
  await parseSVGAndRender(editor, svgString)
} else {
  // Fallback to JSON
  const data = await response.json()
  await generateWireframeFromSpec(editor, data.wireframe)
}

🔧 Implementation Steps

Step 1: Backend SVG Generation

1.1 Install Dependencies

pip install flask flask-cors anthropic

1.2 Create SVG Generator

import xml.etree.ElementTree as ET

def generate_svg_wireframe(layout_spec):
    """Generate SVG wireframe from layout specification"""
    
    # Create SVG root element
    svg = ET.Element('svg', {
        'width': '800',
        'height': '600',
        'viewBox': '0 0 800 600',
        'xmlns': 'http://www.w3.org/2000/svg'
    })
    
    # Add definitions (filters, gradients)
    defs = ET.SubElement(svg, 'defs')
    shadow_filter = ET.SubElement(defs, 'filter', {
        'id': 'shadow',
        'y': '-40%', 'x': '-40%',
        'width': '180%', 'height': '180%'
    })
    ET.SubElement(shadow_filter, 'feDropShadow', {
        'dx': '1', 'dy': '1',
        'stdDeviation': '1.2',
        'flood-opacity': '.5'
    })
    
    # Create main group
    main_group = ET.SubElement(svg, 'g')
    
    # Generate layout elements
    generate_header(main_group, layout_spec.get('header', {}))
    generate_sidebar(main_group, layout_spec.get('sidebar', {}))
    generate_main_content(main_group, layout_spec.get('main_content', {}))
    generate_footer(main_group, layout_spec.get('footer', {}))
    
    return ET.tostring(svg, encoding='unicode')

def generate_header(group, header_spec):
    """Generate header section"""
    if not header_spec.get('enabled', False):
        return
    
    # Header background
    ET.SubElement(group, 'rect', {
        'x': '0', 'y': '0',
        'width': '800', 'height': '60',
        'fill': '#f0f0f0'
    })
    
    # Header text
    ET.SubElement(group, 'text', {
        'x': '20', 'y': '35',
        'font-family': 'Arial',
        'font-size': '16',
        'fill': '#333333'
    }).text = header_spec.get('title', 'Header')

1.3 Update Flask Endpoint

@app.route('/generate-wireframe', methods=['POST'])
def generate_wireframe():
    try:
        prompt = request.json.get('prompt')
        if not prompt:
            return jsonify({'error': 'Prompt is required'}), 400
        
        # Call Claude AI
        claude_response = call_claude_api(prompt)
        
        # Parse AI response and generate SVG
        layout_spec = parse_claude_response(claude_response)
        svg_content = generate_svg_wireframe(layout_spec)
        
        # Return SVG with proper headers
        response = make_response(svg_content)
        response.headers['Content-Type'] = 'image/svg+xml'
        response.headers['Cache-Control'] = 'no-cache'
        return response
        
    except Exception as e:
        logger.error(f"Error generating wireframe: {str(e)}")
        return jsonify({'error': 'Internal server error'}), 500

Step 2: Frontend SVG Parsing

2.1 SVG Parser Functions

const parseSVGAndRender = async (editor: Editor, svgString: string) => {
  try {
    // Parse SVG string
    const parser = new DOMParser()
    const svgDoc = parser.parseFromString(svgString, 'image/svg+xml')
    const svgElement = svgDoc.querySelector('svg')
    
    if (!svgElement) {
      throw new Error('Invalid SVG content')
    }
    
    // Get dimensions
    const viewBox = svgElement.getAttribute('viewBox')?.split(' ').map(Number) || [0, 0, 800, 600]
    const [, , svgWidth, svgHeight] = viewBox
    
    // Create main frame
    editor.createShape({
      id: createShapeId(),
      type: "frame",
      x: 50, y: 50,
      props: {
        w: Math.max(800, svgWidth),
        h: Math.max(600, svgHeight),
        name: "SVG Wireframe",
      },
    })
    
    // Render SVG elements
    await renderSVGElements(editor, svgElement, 50, 50, svgWidth, svgHeight)
    
  } catch (error) {
    console.error('SVG parsing error:', error)
    // Fallback to basic wireframe
    await generateFallbackWireframe(editor, "SVG parsing failed")
  }
}

2.2 Element Renderers

const renderSVGRect = async (editor: Editor, element: SVGElement, offsetX: number, offsetY: number) => {
  const x = parseFloat(element.getAttribute('x') || '0') + offsetX
  const y = parseFloat(element.getAttribute('y') || '0') + offsetY
  const width = parseFloat(element.getAttribute('width') || '100')
  const height = parseFloat(element.getAttribute('height') || '100')
  const fill = element.getAttribute('fill') || 'none'
  const stroke = element.getAttribute('stroke') || 'black'
  
  editor.createShape({
    id: createShapeId(),
    type: "geo",
    x, y,
    props: {
      w: Math.max(10, width),
      h: Math.max(10, height),
      geo: "rectangle",
      fill: fill === 'none' ? 'none' : 'semi',
      color: mapColorToTldraw(stroke),
    },
  })
}

🎨 SVG Styling and Effects

Shadows and Filters

<defs>
  <filter id="shadow" y="-40%" x="-40%" width="180%" height="180%">
    <feDropShadow dx="1" dy="1" stdDeviation="1.2" flood-opacity=".5"/>
  </filter>
  
  <filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur stdDeviation="3" result="coloredBlur"/>
    <feMerge> 
      <feMergeNode in="coloredBlur"/>
      <feMergeNode in="SourceGraphic"/>
    </feMerge>
  </filter>
</defs>

Gradients

<defs>
  <linearGradient id="headerGradient" x1="0%" y1="0%" x2="100%" y2="0%">
    <stop offset="0%" style="stop-color:#4facfe;stop-opacity:1" />
    <stop offset="100%" style="stop-color:#00f2fe;stop-opacity:1" />
  </linearGradient>
</defs>

<rect x="0" y="0" width="800" height="60" fill="url(#headerGradient)"/>

Text Styling

<text x="20" y="35" 
      font-family="Arial, sans-serif" 
      font-size="16" 
      font-weight="bold"
      fill="#333333"
      text-anchor="start">
  Dashboard Header
</text>

🔄 Response Type Detection

Content-Type Based Routing

const generateFromPrompt = async (prompt: string) => {
  try {
    const response = await fetch('/generate-wireframe', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ prompt })
    })
    
    // Detect response type
    const contentType = response.headers.get('content-type')
    
    if (contentType && contentType.includes('image/svg+xml')) {
      // SVG response - parse and render
      const svgString = await response.text()
      await parseSVGAndRender(editor, svgString)
    } else {
      // JSON response - fallback processing
      const data = await response.json()
      await generateWireframeFromSpec(editor, data.wireframe)
    }
    
  } catch (error) {
    console.error('Generation error:', error)
    await generateFallbackWireframe(editor, prompt)
  }
}

🧪 Testing and Validation

Backend Testing

def test_svg_generation():
    """Test SVG generation functionality"""
    
    # Test layout specification
    layout_spec = {
        'header': {'enabled': True, 'title': 'Test Header'},
        'sidebar': {'enabled': True, 'width': 200},
        'main_content': {'sections': []},
        'footer': {'enabled': True, 'height': 60}
    }
    
    # Generate SVG
    svg_content = generate_svg_wireframe(layout_spec)
    
    # Validate SVG structure
    assert '<svg' in svg_content
    assert 'width="800"' in svg_content
    assert 'height="600"' in svg_content
    assert 'Test Header' in svg_content
    
    print("✅ SVG generation test passed")

if __name__ == '__main__':
    test_svg_generation()

Frontend Testing

const testSVGParsing = async () => {
  const testSVG = `
    <svg width="100" height="100" viewBox="0 0 100 100">
      <rect x="10" y="10" width="80" height="80" fill="#f0f0f0"/>
      <text x="20" y="60">Test</text>
    </svg>
  `
  
  try {
    await parseSVGAndRender(mockEditor, testSVG)
    console.log('✅ SVG parsing test passed')
  } catch (error) {
    console.error('❌ SVG parsing test failed:', error)
  }
}

🚀 Performance Optimization

SVG Optimization Techniques

  1. Minimize DOM Elements: Use groups for related elements
  2. Optimize Paths: Simplify complex paths
  3. Reduce Attributes: Use CSS classes for common styles
  4. Compression: Gzip SVG responses

Caching Strategies

from functools import lru_cache

@lru_cache(maxsize=100)
def generate_cached_svg(prompt_hash):
    """Cache SVG generation for repeated prompts"""
    return generate_svg_wireframe(get_cached_layout(prompt_hash))

🔮 Future Enhancements

Advanced SVG Features

  • Animations: CSS animations and transitions
  • Interactivity: Click handlers and hover effects
  • Responsive Design: ViewBox scaling and media queries
  • Accessibility: ARIA labels and screen reader support

Integration Possibilities

  • Design Systems: Consistent component libraries
  • Export Options: PNG, PDF, and other formats
  • Collaboration: Real-time editing and version control
  • Analytics: Usage tracking and performance metrics

📋 Implementation Checklist

  • Backend SVG generation functions
  • Frontend SVG parsing and rendering
  • Response type detection and routing
  • Error handling and fallback mechanisms
  • Testing and validation
  • Performance optimization
  • Documentation and examples

🆘 Troubleshooting

Common Issues

  1. SVG Not Rendering: Check content-type headers
  2. Parsing Errors: Validate SVG XML structure
  3. Performance Issues: Optimize SVG complexity
  4. CORS Problems: Configure proper origins

Debug Tips

  • Use browser dev tools to inspect SVG responses
  • Check network tab for content-type headers
  • Validate SVG content with online validators
  • Monitor console for parsing errors

This integration guide provides a comprehensive approach to implementing SVG-based wireframe generation. The system offers better performance, precision, and styling capabilities compared to JSON-based approaches.