ginipick commited on
Commit
9c80bb4
Β·
verified Β·
1 Parent(s): b40c73b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -17
app.py CHANGED
@@ -228,6 +228,17 @@ function open(i){
228
  if(fb){fb.destroy();viewer.innerHTML='';}
229
 
230
  if(pages[0].path) {
 
 
 
 
 
 
 
 
 
 
 
231
  // μ„œλ²„ PDF 파일 λ‘œλ“œ
232
  fetch(`/api/pdf-content?path=${encodeURIComponent(pages[0].path)}`)
233
  .then(response => {
@@ -246,25 +257,42 @@ function open(i){
246
  console.log('PDF λ¬Έμ„œ λ‘œλ“œ μ™„λ£Œ. νŽ˜μ΄μ§€ 수:', pdf.numPages);
247
 
248
  const pdfPages = [];
 
 
249
  for(let p = 1; p <= pdf.numPages; p++) {
250
- console.log('νŽ˜μ΄μ§€ λ Œλ”λ§ 쀑:', p + '/' + pdf.numPages);
251
-
252
- const pg = await pdf.getPage(p);
253
- const vp = pg.getViewport({scale: 1});
254
- const c = document.createElement('canvas');
255
- c.width = vp.width;
256
- c.height = vp.height;
257
 
258
- await pg.render({canvasContext: c.getContext('2d'), viewport: vp}).promise;
259
- pdfPages.push({src: c.toDataURL(), thumb: c.toDataURL()});
 
 
 
 
 
 
 
 
 
 
260
  }
261
 
262
  console.log('λͺ¨λ“  νŽ˜μ΄μ§€ λ Œλ”λ§ μ™„λ£Œ:', pdfPages.length);
263
- createFlipBook(pdfPages);
 
 
 
 
 
264
  })
265
  .catch(error => {
266
  console.error('PDF 처리 쀑 였λ₯˜ λ°œμƒ:', error);
267
- alert('PDFλ₯Ό λ‘œλ“œν•˜λŠ” 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: ' + error.message);
 
 
 
 
268
  });
269
  } else {
270
  // μ—…λ‘œλ“œλœ ν”„λ‘œμ νŠΈ 보기
@@ -297,11 +325,38 @@ function createFlipBook(pages) {
297
  }
298
 
299
  /* ── λ„€λΉ„κ²Œμ΄μ…˜ ── */
300
- $id('homeBtn').onclick=()=>toggle(true);
 
 
 
 
 
 
 
 
301
  function toggle(showHome){
302
  $id('home').style.display=showHome?'block':'none';
303
  $id('viewerPage').style.display=showHome?'none':'block';
304
  $id('homeBtn').style.display=showHome?'none':'inline-block';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  }
306
 
307
  // νŽ˜μ΄μ§€ λ‘œλ“œ μ‹œ μ„œλ²„ PDF λ‘œλ“œ
@@ -351,20 +406,28 @@ async def get_pdf_content(path: str):
351
  with open(path, "rb") as pdf_file:
352
  content = pdf_file.read()
353
 
354
- # 응닡 헀더 μ„€μ • - PDF νŒŒμΌμž„μ„ λͺ…μ‹œ
 
 
 
 
 
355
  headers = {
356
  "Content-Type": "application/pdf",
357
- "Content-Disposition": f"inline; filename={pdf_path.name}"
358
  }
359
 
360
- # 파일 μ½˜ν…μΈ  λ°˜ν™˜
361
  from fastapi.responses import Response
362
- return Response(content=content, headers=headers)
363
  except Exception as e:
364
  import traceback
365
  error_details = traceback.format_exc()
366
  print(f"PDF μ½˜ν…μΈ  λ‘œλ“œ 였λ₯˜: {str(e)}\n{error_details}")
367
- return {"error": str(e)}, 500
 
 
 
368
 
369
  @app.get("/", response_class=HTMLResponse)
370
  async def root():
 
228
  if(fb){fb.destroy();viewer.innerHTML='';}
229
 
230
  if(pages[0].path) {
231
+ // λ‘œλ”© ν‘œμ‹œ
232
+ viewer.innerHTML = '<div style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center;"><div style="border:4px solid #f3f3f3;border-top:4px solid #3498db;border-radius:50%;width:50px;height:50px;margin:0 auto;animation:spin 2s linear infinite;"></div><p style="margin-top:20px;font-size:16px;">PDF λ‘œλ”© 쀑...</p></div>';
233
+
234
+ // μŠ€νƒ€μΌ μΆ”κ°€
235
+ if (!document.getElementById('loadingStyle')) {
236
+ const style = document.createElement('style');
237
+ style.id = 'loadingStyle';
238
+ style.textContent = '@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}';
239
+ document.head.appendChild(style);
240
+ }
241
+
242
  // μ„œλ²„ PDF 파일 λ‘œλ“œ
243
  fetch(`/api/pdf-content?path=${encodeURIComponent(pages[0].path)}`)
244
  .then(response => {
 
257
  console.log('PDF λ¬Έμ„œ λ‘œλ“œ μ™„λ£Œ. νŽ˜μ΄μ§€ 수:', pdf.numPages);
258
 
259
  const pdfPages = [];
260
+ const progressElement = viewer.querySelector('p');
261
+
262
  for(let p = 1; p <= pdf.numPages; p++) {
263
+ if (progressElement) {
264
+ progressElement.textContent = `PDF νŽ˜μ΄μ§€ λ‘œλ”© 쀑... (${p}/${pdf.numPages})`;
265
+ }
 
 
 
 
266
 
267
+ try {
268
+ const pg = await pdf.getPage(p);
269
+ const vp = pg.getViewport({scale: 1});
270
+ const c = document.createElement('canvas');
271
+ c.width = vp.width;
272
+ c.height = vp.height;
273
+
274
+ await pg.render({canvasContext: c.getContext('2d'), viewport: vp}).promise;
275
+ pdfPages.push({src: c.toDataURL(), thumb: c.toDataURL()});
276
+ } catch (pageError) {
277
+ console.error(`νŽ˜μ΄μ§€ ${p} λ Œλ”λ§ 였λ₯˜:`, pageError);
278
+ }
279
  }
280
 
281
  console.log('λͺ¨λ“  νŽ˜μ΄μ§€ λ Œλ”λ§ μ™„λ£Œ:', pdfPages.length);
282
+
283
+ if (pdfPages.length > 0) {
284
+ createFlipBook(pdfPages);
285
+ } else {
286
+ throw new Error('PDFμ—μ„œ νŽ˜μ΄μ§€λ₯Ό μΆ”μΆœν•  수 μ—†μŠ΅λ‹ˆλ‹€.');
287
+ }
288
  })
289
  .catch(error => {
290
  console.error('PDF 처리 쀑 였λ₯˜ λ°œμƒ:', error);
291
+ viewer.innerHTML = `<div style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center;"><p style="color:red;font-size:16px;">PDFλ₯Ό λ‘œλ“œν•˜λŠ” 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€:<br>${error.message}</p><button id="backBtn" style="margin-top:20px;padding:10px 20px;background:#0077c2;color:white;border:none;border-radius:4px;cursor:pointer;">ν™ˆμœΌλ‘œ λŒμ•„κ°€κΈ°</button></div>`;
292
+
293
+ document.getElementById('backBtn').addEventListener('click', function() {
294
+ toggle(true);
295
+ });
296
  });
297
  } else {
298
  // μ—…λ‘œλ“œλœ ν”„λ‘œμ νŠΈ 보기
 
325
  }
326
 
327
  /* ── λ„€λΉ„κ²Œμ΄μ…˜ ── */
328
+ $id('homeBtn').onclick=()=>{
329
+ if(fb) {
330
+ fb.destroy();
331
+ viewer.innerHTML = '';
332
+ fb = null;
333
+ }
334
+ toggle(true);
335
+ };
336
+
337
  function toggle(showHome){
338
  $id('home').style.display=showHome?'block':'none';
339
  $id('viewerPage').style.display=showHome?'none':'block';
340
  $id('homeBtn').style.display=showHome?'none':'inline-block';
341
+
342
+ // μΆ”κ°€: 전체 ν™”λ©΄ λͺ¨λ“œμ—μ„œ homeBtn μœ„μΉ˜ μ‘°μ •
343
+ if(!showHome) {
344
+ $id('homeBtn').style.position = 'fixed';
345
+ $id('homeBtn').style.top = '20px';
346
+ $id('homeBtn').style.left = '20px';
347
+ $id('homeBtn').style.zIndex = '1001'; // 뷰어보닀 높은 z-index
348
+ $id('homeBtn').style.fontSize = '24px'; // 크기 증가
349
+ $id('homeBtn').style.width = '48px';
350
+ $id('homeBtn').style.height = '48px';
351
+ } else {
352
+ $id('homeBtn').style.position = '';
353
+ $id('homeBtn').style.top = '';
354
+ $id('homeBtn').style.left = '';
355
+ $id('homeBtn').style.zIndex = '';
356
+ $id('homeBtn').style.fontSize = '';
357
+ $id('homeBtn').style.width = '';
358
+ $id('homeBtn').style.height = '';
359
+ }
360
  }
361
 
362
  // νŽ˜μ΄μ§€ λ‘œλ“œ μ‹œ μ„œλ²„ PDF λ‘œλ“œ
 
406
  with open(path, "rb") as pdf_file:
407
  content = pdf_file.read()
408
 
409
+ # 파일λͺ… 처리 - URL μΈμ½”λ”©μœΌλ‘œ ν•œκΈ€ λ“± 특수 문자 처리
410
+ import urllib.parse
411
+ filename = pdf_path.name
412
+ encoded_filename = urllib.parse.quote(filename)
413
+
414
+ # 응닡 헀더 μ„€μ • - RFC 6266 ν‘œμ€€ μ‚¬μš©
415
  headers = {
416
  "Content-Type": "application/pdf",
417
+ "Content-Disposition": f"inline; filename=\"{encoded_filename}\"; filename*=UTF-8''{encoded_filename}"
418
  }
419
 
420
+ # 파일 μ½˜ν…μΈ  직접 λ°˜ν™˜ (dictκ°€ μ•„λ‹Œ Response 객체)
421
  from fastapi.responses import Response
422
+ return Response(content=content, media_type="application/pdf")
423
  except Exception as e:
424
  import traceback
425
  error_details = traceback.format_exc()
426
  print(f"PDF μ½˜ν…μΈ  λ‘œλ“œ 였λ₯˜: {str(e)}\n{error_details}")
427
+
428
+ # 였λ₯˜ 응닡 λ°˜ν™˜ (JSON ν˜•μ‹)
429
+ from fastapi.responses import JSONResponse
430
+ return JSONResponse(content={"error": str(e)}, status_code=500)
431
 
432
  @app.get("/", response_class=HTMLResponse)
433
  async def root():