AkashKumarave commited on
Commit
8809763
·
verified ·
1 Parent(s): 6fb6711

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +205 -0
app.py ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+ import json
4
+ import requests
5
+ from bs4 import BeautifulSoup
6
+ from flask import Flask, request, jsonify
7
+ from flask_cors import CORS
8
+ import cssutils
9
+ import re
10
+ from urllib.parse import urlparse, urljoin
11
+
12
+ app = Flask(__name__)
13
+ CORS(app) # Enable CORS for all routes
14
+
15
+ @app.route('/')
16
+ def home():
17
+ return "Website to Figma Converter API - Use POST /api/convert"
18
+
19
+ @app.route('/api/convert', methods=['POST'])
20
+ def convert_website():
21
+ data = request.json
22
+
23
+ if not data or 'url' not in data:
24
+ return jsonify({"success": False, "error": "URL is required"}), 400
25
+
26
+ url = data['url']
27
+
28
+ try:
29
+ # Fetch the website content
30
+ website_data = fetch_website(url)
31
+
32
+ # Parse and convert website to Figma-compatible format
33
+ figma_data = convert_to_figma_format(website_data, url)
34
+
35
+ return jsonify({
36
+ "success": True,
37
+ "data": figma_data
38
+ })
39
+
40
+ except Exception as e:
41
+ print(f"Error converting website: {e}")
42
+ return jsonify({
43
+ "success": False,
44
+ "error": str(e)
45
+ }), 500
46
+
47
+ def fetch_website(url):
48
+ """Fetch website HTML content"""
49
+ headers = {
50
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
51
+ }
52
+
53
+ response = requests.get(url, headers=headers)
54
+ response.raise_for_status()
55
+
56
+ return response.text
57
+
58
+ def convert_to_figma_format(html_content, base_url):
59
+ """Convert website HTML to Figma-compatible format"""
60
+ soup = BeautifulSoup(html_content, 'html.parser')
61
+
62
+ # Extract viewport dimensions
63
+ viewport_meta = soup.find('meta', attrs={'name': 'viewport'})
64
+ viewport_width = 1440 # Default width
65
+ viewport_height = 900 # Default height
66
+
67
+ if viewport_meta and 'content' in viewport_meta.attrs:
68
+ viewport_content = viewport_meta['content']
69
+ width_match = re.search(r'width=(\d+)', viewport_content)
70
+ if width_match:
71
+ viewport_width = int(width_match.group(1))
72
+
73
+ # Initialize the result data structure
74
+ result = {
75
+ "width": viewport_width,
76
+ "height": viewport_height,
77
+ "elements": []
78
+ }
79
+
80
+ # Process the body element and its children
81
+ body = soup.body
82
+ if body:
83
+ result["elements"] = parse_element(body, base_url)
84
+
85
+ return result
86
+
87
+ def parse_element(element, base_url, depth=0):
88
+ """Recursively parse HTML elements into Figma-compatible format"""
89
+ if depth > 10: # Limit recursion depth
90
+ return []
91
+
92
+ elements = []
93
+
94
+ # Process only element nodes (skip text nodes, etc.)
95
+ for child in element.children:
96
+ if not hasattr(child, 'name') or not child.name:
97
+ continue
98
+
99
+ # Skip invisible elements
100
+ if child.name in ['script', 'style', 'meta', 'link', 'noscript']:
101
+ continue
102
+
103
+ # Get element style
104
+ style = extract_style(child)
105
+
106
+ element_data = {
107
+ "type": determine_element_type(child),
108
+ "tag": child.name,
109
+ "style": style
110
+ }
111
+
112
+ # Handle text content
113
+ if element_data["type"] == "text":
114
+ element_data["content"] = child.get_text().strip()
115
+
116
+ # Handle image elements
117
+ if child.name == 'img' and child.get('src'):
118
+ element_data["type"] = "image"
119
+ src = child.get('src')
120
+ if not src.startswith(('http://', 'https://')):
121
+ src = urljoin(base_url, src)
122
+ element_data["src"] = src
123
+
124
+ # Handle input elements
125
+ if child.name == 'input':
126
+ input_type = child.get('type', 'text')
127
+ if input_type in ['submit', 'button']:
128
+ element_data["type"] = "button"
129
+ element_data["content"] = child.get('value', 'Button')
130
+
131
+ # Handle button elements
132
+ if child.name == 'button':
133
+ element_data["type"] = "button"
134
+ element_data["content"] = child.get_text().strip() or 'Button'
135
+
136
+ # Recursively process children
137
+ if list(child.children):
138
+ element_data["children"] = parse_element(child, base_url, depth + 1)
139
+
140
+ elements.append(element_data)
141
+
142
+ return elements
143
+
144
+ def determine_element_type(element):
145
+ """Determine the Figma element type based on HTML element"""
146
+ # Text elements
147
+ if element.name in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'span', 'a', 'label', 'li']:
148
+ return "text"
149
+
150
+ # Image elements
151
+ if element.name == 'img':
152
+ return "image"
153
+
154
+ # Button elements
155
+ if element.name == 'button' or (element.name == 'input' and element.get('type') in ['submit', 'button']):
156
+ return "button"
157
+
158
+ # Default to container
159
+ return "container"
160
+
161
+ def extract_style(element):
162
+ """Extract CSS styles from an HTML element"""
163
+ style = {}
164
+
165
+ # Extract inline styles
166
+ if element.get('style'):
167
+ inline_styles = cssutils.parseStyle(element.get('style'))
168
+ for prop in inline_styles:
169
+ style[prop.name] = prop.value
170
+
171
+ # Extract dimensions and position from attributes
172
+ if element.get('width'):
173
+ style['width'] = f"{element.get('width')}px"
174
+ if element.get('height'):
175
+ style['height'] = f"{element.get('height')}px"
176
+
177
+ # Set default dimensions for certain elements
178
+ if element.name in ['div', 'section', 'article', 'main']:
179
+ if 'width' not in style:
180
+ style['width'] = '100%'
181
+ if 'height' not in style:
182
+ style['height'] = 'auto'
183
+
184
+ # Extract colors
185
+ if element.get('color'):
186
+ style['color'] = element.get('color')
187
+ elif element.name in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']:
188
+ style['color'] = '#000000'
189
+
190
+ # Extract font sizes
191
+ if element.name == 'h1':
192
+ style['fontSize'] = '32px'
193
+ elif element.name == 'h2':
194
+ style['fontSize'] = '24px'
195
+ elif element.name == 'h3':
196
+ style['fontSize'] = '18px'
197
+ elif element.name in ['p', 'span', 'a', 'li']:
198
+ style['fontSize'] = '16px'
199
+
200
+ return style
201
+
202
+ if __name__ == '__main__':
203
+ # Get port from environment variable or use default
204
+ port = int(os.environ.get('PORT', 7860))
205
+ app.run(host='0.0.0.0', port=port)