AkashKumarave commited on
Commit
59f237a
·
verified ·
1 Parent(s): 916861c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -195
app.py CHANGED
@@ -1,200 +1,58 @@
1
- import os
2
- import json
3
- import requests
4
- from bs4 import BeautifulSoup
5
- from flask import Flask, request, jsonify
6
- from flask_cors import CORS
7
- import cssutils
8
- import re
9
- from urllib.parse import urlparse, urljoin
10
- from playwright.sync_api import sync_playwright
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 with Playwright for dynamic 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
- print("Figma data:", json.dumps(figma_data, indent=2)) # Debug log
36
- return jsonify({
37
- "success": True,
38
- "data": figma_data
39
- })
40
-
41
- except Exception as e:
42
- print(f"Error converting website: {e}")
43
- return jsonify({
44
- "success": False,
45
- "error": str(e)
46
- }), 500
47
-
48
- def fetch_website(url):
49
- """Fetch website HTML content using Playwright for rendered DOM"""
50
- with sync_playwright() as p:
51
- browser = p.chromium.launch(headless=True)
52
- page = browser.new_page()
53
- page.goto(url, wait_until="networkidle")
54
- html_content = page.content()
55
- browser.close()
56
- return html_content
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
- for child in element.children:
95
- if not hasattr(child, 'name') or not child.name:
96
- continue
97
-
98
- # Skip invisible elements
99
- if child.name in ['script', 'style', 'meta', 'link', 'noscript']:
100
- continue
101
-
102
- # Get element style (inline and computed)
103
- style = extract_style(child)
104
-
105
- element_data = {
106
- "type": determine_element_type(child),
107
- "tag": child.name,
108
- "style": style
109
  }
110
-
111
- # Handle text content
112
- if element_data["type"] == "text":
113
- text_content = child.get_text().strip()
114
- if text_content:
115
- element_data["content"] = text_content
116
-
117
- # Handle image elements
118
- if child.name == 'img' and child.get('src'):
119
- element_data["type"] = "image"
120
- src = child.get('src')
121
- if not src.startswith(('http://', 'https://')):
122
- src = urljoin(base_url, src)
123
- element_data["src"] = src
124
-
125
- # Handle input elements
126
- if child.name == 'input':
127
- input_type = child.get('type', 'text')
128
- if input_type in ['submit', 'button']:
129
- element_data["type"] = "button"
130
- element_data["content"] = child.get('value', 'Button')
131
-
132
- # Handle button elements
133
- if child.name == 'button':
134
- element_data["type"] = "button"
135
- element_data["content"] = child.get_text().strip() or 'Button'
136
-
137
- # Recursively process children
138
- if list(child.children):
139
- element_data["children"] = parse_element(child, base_url, depth + 1)
140
-
141
- elements.append(element_data)
142
-
143
- return elements
144
-
145
- def determine_element_type(element):
146
- """Determine the Figma element type based on HTML element"""
147
- if element.name in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'span', 'a', 'label', 'li']:
148
- return "text"
149
- if element.name == 'img':
150
- return "image"
151
- if element.name == 'button' or (element.name == 'input' and element.get('type') in ['submit', 'button']):
152
- return "button"
153
- return "container"
154
 
155
- def extract_style(element):
156
- """Extract CSS styles from an HTML element"""
157
- style = {}
158
-
159
- # Extract inline styles
160
- if element.get('style'):
161
- try:
162
- inline_styles = cssutils.parseStyle(element['style'])
163
- for prop in inline_styles:
164
- style[prop.name] = prop.value
165
- except Exception as e:
166
- print(f"Error parsing inline styles for {element.name}: {e}")
167
-
168
- # Add default styles for specific elements
169
- if element.name in ['div', 'section', 'article', 'main']:
170
- style.setdefault('width', '100%')
171
- style.setdefault('height', 'auto')
172
- style.setdefault('display', 'block')
173
-
174
- # Extract colors and backgrounds
175
- if element.get('color'):
176
- style['color'] = element['color']
177
- elif element.name in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']:
178
- style.setdefault('color', '#000000')
179
-
180
- # Extract font sizes
181
- if element.name == 'h1':
182
- style.setdefault('fontSize', '32px')
183
- elif element.name == 'h2':
184
- style.setdefault('fontSize', '24px')
185
- elif element.name == 'h3':
186
- style.setdefault('fontSize', '18px')
187
- elif element.name in ['p', 'span', 'a', 'li']:
188
- style.setdefault('fontSize', '16px')
189
-
190
- # Add layout-related styles
191
- style.setdefault('position', 'relative')
192
- style.setdefault('margin', '0')
193
- style.setdefault('padding', '0')
194
- style.setdefault('boxSizing', 'border-box')
195
-
196
- # Add computed styles (simulated)
197
- if element.name in ['div', 'section', 'article']:
198
- style.setdefault('backgroundColor', 'transparent')
199
-
200
- return style
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.responses import JSONResponse
3
+ from pdf2json import Pdf2Json
4
+ from io import BytesIO
5
+ import base64
 
 
 
 
 
6
 
7
+ app = FastAPI()
 
8
 
9
+ @app.post("/api/convert")
10
+ async def convert_pdf(file: bytes = File(...)):
 
 
 
 
 
 
 
 
 
 
 
11
  try:
12
+ # Parse PDF
13
+ pdf_parser = Pdf2Json(BytesIO(file))
14
+ pdf_data = pdf_parser.get_json()
15
+
16
+ # Process PDF data
17
+ result = {
18
+ "width": pdf_data["width"], # Page width in pixels
19
+ "height": pdf_data["height"], # Page height in pixels
20
+ "texts": [],
21
+ "images": [],
22
+ "shapes": []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
+ # Extract text
26
+ for text in pdf_data["texts"]:
27
+ result["texts"].append({
28
+ "content": text["content"],
29
+ "x": text["x"],
30
+ "y": text["y"],
31
+ "fontFamily": text["font"] or "Arial",
32
+ "fontStyle": text["style"] or "Regular",
33
+ "fontSize": text["size"],
34
+ "color": {"r": text["color"]["r"]/255, "g": text["color"]["g"]/255, "b": text["color"]["b"]/255}
35
+ })
36
+
37
+ # Extract images
38
+ for img in pdf_data["images"]:
39
+ result["images"].append({
40
+ "data": base64.b64encode(img["data"]).decode('utf-8'),
41
+ "x": img["x"],
42
+ "y": img["y"],
43
+ "width": img["width"],
44
+ "height": img["height"]
45
+ })
46
+
47
+ # Extract shapes
48
+ for shape in pdf_data["shapes"]:
49
+ result["shapes"].append({
50
+ "path": shape["path"],
51
+ "x": shape["x"],
52
+ "y": shape["y"],
53
+ "color": {"r": shape["color"]["r"]/255, "g": shape["color"]["g"]/255, "b": shape["color"]["b"]/255}
54
+ })
55
+
56
+ return JSONResponse(content=result)
57
+ except Exception as e:
58
+ raise HTTPException(status_code=500, detail=str(e))