ABDALLALSWAITI commited on
Commit
c8a2b09
·
verified ·
1 Parent(s): d895233

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +14 -108
app.py CHANGED
@@ -10,10 +10,7 @@ import logging
10
  from typing import List, Optional
11
 
12
  # Configure logging
13
- logging.basicConfig(
14
- level=logging.INFO,
15
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
16
- )
17
  logger = logging.getLogger(__name__)
18
 
19
  # Create FastAPI app
@@ -32,58 +29,21 @@ app.add_middleware(
32
  allow_headers=["*"],
33
  )
34
 
35
- @app.on_event("startup")
36
- async def startup_event():
37
- """Startup event - runs after server starts"""
38
- logger.info("=" * 60)
39
- logger.info("HTML to PDF Converter API Starting...")
40
- logger.info("=" * 60)
41
- logger.info("Checking dependencies...")
42
-
43
- # Check if node is available
44
- try:
45
- result = subprocess.run(['node', '--version'], capture_output=True, text=True, timeout=5)
46
- logger.info(f"Node.js version: {result.stdout.strip()}")
47
- except Exception as e:
48
- logger.error(f"Node.js not found: {e}")
49
-
50
- # Check if chromium is available
51
- chromium_path = os.environ.get('PUPPETEER_EXECUTABLE_PATH', '/usr/bin/chromium')
52
- if os.path.exists(chromium_path):
53
- logger.info(f"Chromium found at: {chromium_path}")
54
- else:
55
- logger.error(f"Chromium not found at: {chromium_path}")
56
-
57
- # Check if puppeteer script exists
58
- if os.path.exists('/app/puppeteer_pdf.js'):
59
- logger.info("Puppeteer script found")
60
- else:
61
- logger.error("Puppeteer script not found!")
62
-
63
- logger.info("=" * 60)
64
- logger.info("API is ready!")
65
- logger.info("=" * 60)
66
-
67
  @app.get("/")
68
  async def root():
69
- """Root endpoint - simple response for quick health check"""
70
  return {
71
  "status": "online",
72
  "service": "HTML to PDF Converter API",
73
  "version": "1.0.0",
74
  "docs": "/docs",
75
- "health": "/health"
76
  }
77
 
78
  @app.get("/health")
79
  async def health():
80
  """Health check endpoint"""
81
- return {
82
- "status": "healthy",
83
- "service": "HTML to PDF Converter API",
84
- "version": "1.0.0",
85
- "endpoints": ["/convert", "/convert-html", "/convert-base64"]
86
- }
87
 
88
  @app.get("/ui", response_class=HTMLResponse)
89
  async def ui():
@@ -148,14 +108,6 @@ async def ui():
148
  }
149
  ul { margin-left: 20px; }
150
  li { margin: 8px 0; }
151
- a { color: #667eea; text-decoration: none; font-weight: 500; }
152
- a:hover { text-decoration: underline; }
153
- .links {
154
- display: flex;
155
- gap: 15px;
156
- margin: 20px 0;
157
- flex-wrap: wrap;
158
- }
159
  .btn {
160
  display: inline-block;
161
  background: #667eea;
@@ -163,6 +115,7 @@ async def ui():
163
  padding: 12px 24px;
164
  border-radius: 6px;
165
  text-decoration: none;
 
166
  transition: all 0.3s;
167
  }
168
  .btn:hover {
@@ -182,19 +135,13 @@ async def ui():
182
  page breaks, image embedding, and multiple aspect ratios.
183
  </p>
184
 
185
- <div class="links">
186
  <a href="/docs" class="btn">📚 API Documentation</a>
187
  <a href="/health" class="btn">💚 Health Check</a>
188
  </div>
189
 
190
  <h2>📡 Endpoints</h2>
191
 
192
- <div class="endpoint">
193
- <h3>GET /health</h3>
194
- <p>Check API health status</p>
195
- <pre>curl https://YOUR-SPACE.hf.space/health</pre>
196
- </div>
197
-
198
  <div class="endpoint">
199
  <h3>POST /convert</h3>
200
  <p>Upload HTML file and convert to PDF</p>
@@ -202,56 +149,26 @@ async def ui():
202
  <ul>
203
  <li><code>html_file</code> - HTML file (required)</li>
204
  <li><code>aspect_ratio</code> - "16:9", "1:1", or "9:16" (optional)</li>
205
- <li><code>auto_detect</code> - Auto-detect aspect ratio (default: true)</li>
206
- <li><code>images</code> - Image files to embed (optional, multiple files)</li>
207
  </ul>
208
- <pre>curl -X POST https://YOUR-SPACE.hf.space/convert \\
209
- -F "html_file=@document.html" \\
210
- -F "images=@logo.png" \\
211
- -o output.pdf</pre>
212
  </div>
213
 
214
  <div class="endpoint">
215
  <h3>POST /convert-html</h3>
216
  <p>Convert HTML string to PDF</p>
217
- <p><strong>Parameters:</strong></p>
218
- <ul>
219
- <li><code>html_content</code> - HTML as string (required)</li>
220
- <li><code>aspect_ratio</code> - "16:9", "1:1", or "9:16" (optional)</li>
221
- </ul>
222
- <pre>curl -X POST https://YOUR-SPACE.hf.space/convert-html \\
223
- -F "html_content=&lt;html&gt;&lt;body&gt;&lt;h1&gt;Hello!&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;" \\
224
- -o output.pdf</pre>
225
  </div>
226
 
227
  <div class="endpoint">
228
  <h3>POST /convert-base64</h3>
229
  <p>Convert HTML to base64-encoded PDF (returns JSON)</p>
230
- <p><strong>Response:</strong></p>
231
- <pre>{
232
- "success": true,
233
- "pdf_base64": "JVBERi0xLjQK...",
234
- "aspect_ratio": "9:16",
235
- "size_bytes": 45678
236
- }</pre>
237
  </div>
238
 
239
  <h2>📐 Aspect Ratios</h2>
240
  <ul>
241
- <li><code>16:9</code> - Landscape (297mm × 210mm) - Presentations</li>
242
- <li><code>1:1</code> - Square (210mm × 210mm) - Social media</li>
243
- <li><code>9:16</code> - Portrait (210mm × 297mm) - Documents</li>
244
  </ul>
245
-
246
- <h2>📄 HTML Structure for Page Breaks</h2>
247
- <p>Use class <code>page</code> or <code>slide</code> for automatic page breaks:</p>
248
- <pre>&lt;div class="page"&gt;
249
- &lt;h1&gt;Page 1&lt;/h1&gt;
250
- &lt;/div&gt;
251
-
252
- &lt;div class="page"&gt;
253
- &lt;h1&gt;Page 2&lt;/h1&gt;
254
- &lt;/div&gt;</pre>
255
  </div>
256
  </body>
257
  </html>
@@ -319,8 +236,6 @@ def convert_to_pdf(html: str, ratio: str) -> bytes:
319
  logger.error(f"Conversion failed: {result.stderr}")
320
  raise Exception(f"PDF conversion failed: {result.stderr}")
321
 
322
- logger.info("Conversion successful")
323
-
324
  pdf_file = html_file.replace('.html', '.pdf')
325
 
326
  if not os.path.exists(pdf_file):
@@ -329,7 +244,7 @@ def convert_to_pdf(html: str, ratio: str) -> bytes:
329
  with open(pdf_file, 'rb') as f:
330
  pdf_bytes = f.read()
331
 
332
- logger.info(f"PDF size: {len(pdf_bytes)} bytes")
333
  return pdf_bytes
334
 
335
  finally:
@@ -344,13 +259,10 @@ async def convert(
344
  ):
345
  """Convert uploaded HTML file to PDF"""
346
  try:
347
- logger.info(f"Received conversion request: {html_file.filename}")
348
-
349
  html = (await html_file.read()).decode('utf-8')
350
 
351
  if auto_detect:
352
  aspect_ratio = detect_aspect_ratio(html)
353
- logger.info(f"Auto-detected aspect ratio: {aspect_ratio}")
354
  elif not aspect_ratio:
355
  aspect_ratio = "9:16"
356
 
@@ -359,7 +271,6 @@ async def convert(
359
 
360
  # Embed images if provided
361
  if images:
362
- logger.info(f"Embedding {len(images)} image(s)")
363
  for img in images:
364
  img_bytes = await img.read()
365
  b64 = base64.b64encode(img_bytes).decode()
@@ -370,7 +281,6 @@ async def convert(
370
 
371
  pdf = convert_to_pdf(html, aspect_ratio)
372
 
373
- logger.info("Returning PDF response")
374
  return Response(
375
  content=pdf,
376
  media_type="application/pdf",
@@ -381,7 +291,7 @@ async def convert(
381
  )
382
 
383
  except Exception as e:
384
- logger.error(f"Error in /convert: {str(e)}")
385
  raise HTTPException(500, str(e))
386
 
387
  @app.post("/convert-html")
@@ -392,8 +302,6 @@ async def convert_html(
392
  ):
393
  """Convert HTML string to PDF"""
394
  try:
395
- logger.info("Received HTML string conversion request")
396
-
397
  if auto_detect:
398
  aspect_ratio = detect_aspect_ratio(html_content)
399
  elif not aspect_ratio:
@@ -414,7 +322,7 @@ async def convert_html(
414
  )
415
 
416
  except Exception as e:
417
- logger.error(f"Error in /convert-html: {str(e)}")
418
  raise HTTPException(500, str(e))
419
 
420
  @app.post("/convert-base64")
@@ -425,8 +333,6 @@ async def convert_base64(
425
  ):
426
  """Convert HTML to base64-encoded PDF"""
427
  try:
428
- logger.info("Received base64 conversion request")
429
-
430
  if auto_detect:
431
  aspect_ratio = detect_aspect_ratio(html_content)
432
  elif not aspect_ratio:
@@ -446,7 +352,7 @@ async def convert_base64(
446
  })
447
 
448
  except Exception as e:
449
- logger.error(f"Error in /convert-base64: {str(e)}")
450
  raise HTTPException(500, str(e))
451
 
452
  if __name__ == "__main__":
 
10
  from typing import List, Optional
11
 
12
  # Configure logging
13
+ logging.basicConfig(level=logging.INFO)
 
 
 
14
  logger = logging.getLogger(__name__)
15
 
16
  # Create FastAPI app
 
29
  allow_headers=["*"],
30
  )
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  @app.get("/")
33
  async def root():
34
+ """Root endpoint - returns immediately for health check"""
35
  return {
36
  "status": "online",
37
  "service": "HTML to PDF Converter API",
38
  "version": "1.0.0",
39
  "docs": "/docs",
40
+ "ui": "/ui"
41
  }
42
 
43
  @app.get("/health")
44
  async def health():
45
  """Health check endpoint"""
46
+ return {"status": "healthy"}
 
 
 
 
 
47
 
48
  @app.get("/ui", response_class=HTMLResponse)
49
  async def ui():
 
108
  }
109
  ul { margin-left: 20px; }
110
  li { margin: 8px 0; }
 
 
 
 
 
 
 
 
111
  .btn {
112
  display: inline-block;
113
  background: #667eea;
 
115
  padding: 12px 24px;
116
  border-radius: 6px;
117
  text-decoration: none;
118
+ margin: 5px;
119
  transition: all 0.3s;
120
  }
121
  .btn:hover {
 
135
  page breaks, image embedding, and multiple aspect ratios.
136
  </p>
137
 
138
+ <div>
139
  <a href="/docs" class="btn">📚 API Documentation</a>
140
  <a href="/health" class="btn">💚 Health Check</a>
141
  </div>
142
 
143
  <h2>📡 Endpoints</h2>
144
 
 
 
 
 
 
 
145
  <div class="endpoint">
146
  <h3>POST /convert</h3>
147
  <p>Upload HTML file and convert to PDF</p>
 
149
  <ul>
150
  <li><code>html_file</code> - HTML file (required)</li>
151
  <li><code>aspect_ratio</code> - "16:9", "1:1", or "9:16" (optional)</li>
152
+ <li><code>images</code> - Image files to embed (optional)</li>
 
153
  </ul>
 
 
 
 
154
  </div>
155
 
156
  <div class="endpoint">
157
  <h3>POST /convert-html</h3>
158
  <p>Convert HTML string to PDF</p>
 
 
 
 
 
 
 
 
159
  </div>
160
 
161
  <div class="endpoint">
162
  <h3>POST /convert-base64</h3>
163
  <p>Convert HTML to base64-encoded PDF (returns JSON)</p>
 
 
 
 
 
 
 
164
  </div>
165
 
166
  <h2>📐 Aspect Ratios</h2>
167
  <ul>
168
+ <li><code>16:9</code> - Landscape - Presentations</li>
169
+ <li><code>1:1</code> - Square - Social media</li>
170
+ <li><code>9:16</code> - Portrait - Documents (default)</li>
171
  </ul>
 
 
 
 
 
 
 
 
 
 
172
  </div>
173
  </body>
174
  </html>
 
236
  logger.error(f"Conversion failed: {result.stderr}")
237
  raise Exception(f"PDF conversion failed: {result.stderr}")
238
 
 
 
239
  pdf_file = html_file.replace('.html', '.pdf')
240
 
241
  if not os.path.exists(pdf_file):
 
244
  with open(pdf_file, 'rb') as f:
245
  pdf_bytes = f.read()
246
 
247
+ logger.info(f"PDF generated: {len(pdf_bytes)} bytes")
248
  return pdf_bytes
249
 
250
  finally:
 
259
  ):
260
  """Convert uploaded HTML file to PDF"""
261
  try:
 
 
262
  html = (await html_file.read()).decode('utf-8')
263
 
264
  if auto_detect:
265
  aspect_ratio = detect_aspect_ratio(html)
 
266
  elif not aspect_ratio:
267
  aspect_ratio = "9:16"
268
 
 
271
 
272
  # Embed images if provided
273
  if images:
 
274
  for img in images:
275
  img_bytes = await img.read()
276
  b64 = base64.b64encode(img_bytes).decode()
 
281
 
282
  pdf = convert_to_pdf(html, aspect_ratio)
283
 
 
284
  return Response(
285
  content=pdf,
286
  media_type="application/pdf",
 
291
  )
292
 
293
  except Exception as e:
294
+ logger.error(f"Error: {str(e)}")
295
  raise HTTPException(500, str(e))
296
 
297
  @app.post("/convert-html")
 
302
  ):
303
  """Convert HTML string to PDF"""
304
  try:
 
 
305
  if auto_detect:
306
  aspect_ratio = detect_aspect_ratio(html_content)
307
  elif not aspect_ratio:
 
322
  )
323
 
324
  except Exception as e:
325
+ logger.error(f"Error: {str(e)}")
326
  raise HTTPException(500, str(e))
327
 
328
  @app.post("/convert-base64")
 
333
  ):
334
  """Convert HTML to base64-encoded PDF"""
335
  try:
 
 
336
  if auto_detect:
337
  aspect_ratio = detect_aspect_ratio(html_content)
338
  elif not aspect_ratio:
 
352
  })
353
 
354
  except Exception as e:
355
+ logger.error(f"Error: {str(e)}")
356
  raise HTTPException(500, str(e))
357
 
358
  if __name__ == "__main__":