AkashKumarave commited on
Commit
00d3b13
·
verified ·
1 Parent(s): b514f65

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -37
app.py CHANGED
@@ -4,85 +4,137 @@ import logging
4
  from fastapi import FastAPI, File, UploadFile
5
  from fastapi.middleware.cors import CORSMiddleware
6
 
 
 
 
 
7
  app = FastAPI()
8
- app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
 
 
 
 
 
 
 
 
9
 
10
  def safe_f(val, default=0.0):
11
- """Ultimate guard for float conversion"""
12
- if val is None: return default
13
- try: return float(val)
14
- except: return default
 
 
 
15
 
16
  def get_figma_color(color):
17
- """Converts PDF color to Figma RGB safely"""
18
- if color is None: return None
 
19
  try:
20
- # If color is int, convert to RGB tuple
21
  if isinstance(color, int):
22
  color = fitz.utils.getColor(color)
23
 
24
- if not isinstance(color, (list, tuple)): return None
 
 
 
 
 
 
25
 
26
- if len(color) == 1: # Grayscale
27
- return {"r": safe_f(color[0]), "g": safe_f(color[0]), "b": safe_f(color[0])}
28
- elif len(color) >= 3: # RGB
29
- return {"r": safe_f(color[0]), "g": safe_f(color[1]), "b": safe_f(color[2])}
30
- except: return None
 
 
 
 
31
  return None
32
 
 
 
 
 
33
  @app.post("/convert")
34
  async def convert_pdf(file: UploadFile = File(...)):
35
  try:
36
- data = await file.read()
37
- doc = fitz.open(stream=data, filetype="pdf")
 
38
  pages_data = []
39
 
40
  for page in doc:
41
- p_dict = {"width": safe_f(page.rect.width), "height": safe_f(page.rect.height), "elements": []}
42
-
43
- # 1. Extraction via Dictionary (Text & Images)
44
- raw = page.get_text("dict")
45
- for block in raw.get("blocks", []):
46
- if block.get("type") == 0: # TEXT
 
 
 
 
 
47
  for line in block.get("lines", []):
48
- for s in line.get("spans", []):
49
- p_dict["elements"].append({
50
  "type": "TEXT",
51
- "content": s.get("text", ""),
52
- "x": safe_f(s["bbox"][0]), "y": safe_f(s["bbox"][1]),
53
- "size": safe_f(s.get("size"), 12),
54
- "color": get_figma_color(s.get("color"))
 
55
  })
56
- elif block.get("type") == 1: # IMAGE
57
- p_dict["elements"].append({
 
58
  "type": "IMAGE",
59
  "bytes": base64.b64encode(block["image"]).decode("utf-8"),
60
- "x": safe_f(block["bbox"][0]), "y": safe_f(block["bbox"][1]),
 
61
  "width": safe_f(block["bbox"][2] - block["bbox"][0]),
62
  "height": safe_f(block["bbox"][3] - block["bbox"][1])
63
  })
64
 
65
- # 2. Extraction via Drawings (Vectors)
66
  for path in page.get_drawings():
67
  d_path = ""
68
  for item in path.get("items", []):
69
- if item[0] == "l": d_path += f"M {safe_f(item[1].x)} {safe_f(item[1].y)} L {safe_f(item[2].x)} {safe_f(item[2].y)} "
 
 
 
70
  elif item[0] == "re":
71
  r = item[1]
72
  d_path += f"M {safe_f(r.x0)} {safe_f(r.y0)} L {safe_f(r.x1)} {safe_f(r.y0)} L {safe_f(r.x1)} {safe_f(r.y1)} L {safe_f(r.x0)} {safe_f(r.y1)} Z "
 
73
  elif item[0] == "c":
74
- d_path += f"M {safe_f(item[1].x)} {safe_f(item[1].y)} C {safe_f(item[2].x)} {safe_f(item[2].y)} {safe_f(item[3].x} {safe_f(item[3].y)} {safe_f(item[4].x)} {safe_f(item[4].y)} "
75
 
76
  if d_path:
77
- p_dict["elements"].append({
78
  "type": "VECTOR",
79
  "path": d_path.strip(),
80
  "fill": get_figma_color(path.get("fill")),
81
  "stroke": get_figma_color(path.get("color")),
82
  "strokeWeight": safe_f(path.get("width"), 1.0)
83
  })
84
- pages_data.append(p_dict)
 
 
85
  doc.close()
86
  return {"pages": pages_data}
 
87
  except Exception as e:
88
- return {"error": str(e)}
 
 
 
 
 
 
 
4
  from fastapi import FastAPI, File, UploadFile
5
  from fastapi.middleware.cors import CORSMiddleware
6
 
7
+ # Set up logging for Hugging Face console
8
+ logging.basicConfig(level=logging.INFO)
9
+ logger = logging.getLogger(__name__)
10
+
11
  app = FastAPI()
12
+
13
+ # Enable CORS for Figma Plugin access
14
+ app.add_middleware(
15
+ CORSMiddleware,
16
+ allow_origins=["*"],
17
+ allow_credentials=True,
18
+ allow_methods=["*"],
19
+ allow_headers=["*"],
20
+ )
21
 
22
  def safe_f(val, default=0.0):
23
+ """Guards against float(None) errors."""
24
+ if val is None:
25
+ return default
26
+ try:
27
+ return float(val)
28
+ except (TypeError, ValueError):
29
+ return default
30
 
31
  def get_figma_color(color):
32
+ """Converts various PDF color formats to Figma 0-1 RGB."""
33
+ if color is None:
34
+ return None
35
  try:
36
+ # If color is an integer, convert to RGB tuple
37
  if isinstance(color, int):
38
  color = fitz.utils.getColor(color)
39
 
40
+ if not isinstance(color, (list, tuple)):
41
+ return None
42
+
43
+ # Handle Grayscale (1 component)
44
+ if len(color) == 1:
45
+ val = safe_f(color[0])
46
+ return {"r": val, "g": val, "b": val}
47
 
48
+ # Handle RGB/CMYK (take first 3)
49
+ if len(color) >= 3:
50
+ return {
51
+ "r": safe_f(color[0]),
52
+ "g": safe_f(color[1]),
53
+ "b": safe_f(color[2])
54
+ }
55
+ except Exception:
56
+ return None
57
  return None
58
 
59
+ @app.get("/")
60
+ async def root():
61
+ return {"status": "PDF Converter is Online", "engine": "PyMuPDF"}
62
+
63
  @app.post("/convert")
64
  async def convert_pdf(file: UploadFile = File(...)):
65
  try:
66
+ logger.info(f"Processing: {file.filename}")
67
+ pdf_bytes = await file.read()
68
+ doc = fitz.open(stream=pdf_bytes, filetype="pdf")
69
  pages_data = []
70
 
71
  for page in doc:
72
+ page_dict = {
73
+ "width": safe_f(page.rect.width),
74
+ "height": safe_f(page.rect.height),
75
+ "elements": []
76
+ }
77
+
78
+ # 1. TEXT AND IMAGES (using dict for structured layout)
79
+ raw_dict = page.get_text("dict")
80
+ for block in raw_dict.get("blocks", []):
81
+ # Type 0 is Text
82
+ if block.get("type") == 0:
83
  for line in block.get("lines", []):
84
+ for span in line.get("spans", []):
85
+ page_dict["elements"].append({
86
  "type": "TEXT",
87
+ "content": span.get("text", ""),
88
+ "x": safe_f(span["bbox"][0]),
89
+ "y": safe_f(span["bbox"][1]),
90
+ "size": safe_f(span.get("size"), 12.0),
91
+ "color": get_figma_color(span.get("color"))
92
  })
93
+ # Type 1 is Image
94
+ elif block.get("type") == 1:
95
+ page_dict["elements"].append({
96
  "type": "IMAGE",
97
  "bytes": base64.b64encode(block["image"]).decode("utf-8"),
98
+ "x": safe_f(block["bbox"][0]),
99
+ "y": safe_f(block["bbox"][1]),
100
  "width": safe_f(block["bbox"][2] - block["bbox"][0]),
101
  "height": safe_f(block["bbox"][3] - block["bbox"][1])
102
  })
103
 
104
+ # 2. VECTOR DRAWINGS (Paths, Lines, Rectangles)
105
  for path in page.get_drawings():
106
  d_path = ""
107
  for item in path.get("items", []):
108
+ # Line
109
+ if item[0] == "l":
110
+ d_path += f"M {safe_f(item[1].x)} {safe_f(item[1].y)} L {safe_f(item[2].x)} {safe_f(item[2].y)} "
111
+ # Rectangle
112
  elif item[0] == "re":
113
  r = item[1]
114
  d_path += f"M {safe_f(r.x0)} {safe_f(r.y0)} L {safe_f(r.x1)} {safe_f(r.y0)} L {safe_f(r.x1)} {safe_f(r.y1)} L {safe_f(r.x0)} {safe_f(r.y1)} Z "
115
+ # Curve
116
  elif item[0] == "c":
117
+ d_path += f"M {safe_f(item[1].x)} {safe_f(item[1].y)} C {safe_f(item[2].x)} {safe_f(item[2].y)} {safe_f(item[3].x)} {safe_f(item[3].y)} {safe_f(item[4].x)} {safe_f(item[4].y)} "
118
 
119
  if d_path:
120
+ page_dict["elements"].append({
121
  "type": "VECTOR",
122
  "path": d_path.strip(),
123
  "fill": get_figma_color(path.get("fill")),
124
  "stroke": get_figma_color(path.get("color")),
125
  "strokeWeight": safe_f(path.get("width"), 1.0)
126
  })
127
+
128
+ pages_data.append(page_dict)
129
+
130
  doc.close()
131
  return {"pages": pages_data}
132
+
133
  except Exception as e:
134
+ logger.error(f"Error during conversion: {str(e)}")
135
+ return {"error": str(e)}
136
+
137
+ if __name__ == "__main__":
138
+ import uvicorn
139
+ # Important: Hugging Face uses port 7860
140
+ uvicorn.run(app, host="0.0.0.0", port=7860)