ginipick commited on
Commit
1ea68f5
·
verified ·
1 Parent(s): 285f7e3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -36
app.py CHANGED
@@ -70,17 +70,21 @@ def save_pdf_metadata():
70
  logger.error(f"메타데이터 저장 오류: {e}")
71
 
72
  # PDF ID 생성 (파일명 + 타임스탬프 기반)
 
73
  def generate_pdf_id(filename: str) -> str:
74
  # 파일명에서 확장자 제거
75
  base_name = os.path.splitext(filename)[0]
76
- # URL 안전 문자열로 변환
77
- safe_name = urllib.parse.quote(base_name, safe='')
 
78
  # 타임스탬프 추가로 고유성 보장
79
  timestamp = int(time.time())
80
  # 짧은 임의 문자열 추가
81
  random_suffix = uuid.uuid4().hex[:6]
82
  return f"{safe_name}_{timestamp}_{random_suffix}"
83
 
 
 
84
  # PDF 파일 목록 가져오기 (메인 디렉토리용)
85
  def get_pdf_files():
86
  pdf_files = []
@@ -297,15 +301,21 @@ async def cache_pdf(pdf_path: str):
297
  pdf_cache[pdf_name]["error"] = str(e)
298
 
299
  # PDF ID로 PDF 경로 찾기
 
300
  def get_pdf_path_by_id(pdf_id: str) -> str:
 
 
 
301
  if pdf_id in pdf_metadata:
302
  path = pdf_metadata[pdf_id]
303
  # 파일 존재 확인
304
  if os.path.exists(path):
305
  return path
306
 
307
- # 영구 저장소에서 파일명으로 찾기
308
  filename = os.path.basename(path)
 
 
309
  perm_path = PERMANENT_PDF_DIR / filename
310
  if perm_path.exists():
311
  # 메타데이터 업데이트
@@ -313,7 +323,7 @@ def get_pdf_path_by_id(pdf_id: str) -> str:
313
  save_pdf_metadata()
314
  return str(perm_path)
315
 
316
- # 메인 디렉토리에서 파일명으로 찾기
317
  main_path = PDF_DIR / filename
318
  if main_path.exists():
319
  # 메타데이터 업데이트
@@ -321,6 +331,34 @@ def get_pdf_path_by_id(pdf_id: str) -> str:
321
  save_pdf_metadata()
322
  return str(main_path)
323
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
  return None
325
 
326
  # 시작 시 모든 PDF 파일 캐싱
@@ -378,6 +416,28 @@ async def init_cache_all_pdfs():
378
  # 백그라운드 작업 시작 함수
379
  @app.on_event("startup")
380
  async def startup_event():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  # 백그라운드 태스크로 캐싱 실행
382
  asyncio.create_task(init_cache_all_pdfs())
383
 
@@ -685,6 +745,22 @@ async def unfeature_pdf(path: str):
685
  async def view_pdf_by_id(pdf_id: str):
686
  # PDF ID 유효한지 확인
687
  pdf_path = get_pdf_path_by_id(pdf_id)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
688
  if not pdf_path:
689
  return HTMLResponse(
690
  content=f"<html><body><h1>PDF를 찾을 수 없습니다</h1><p>ID: {pdf_id}</p><a href='/'>홈으로 돌아가기</a></body></html>",
@@ -1591,38 +1667,47 @@ HTML = """
1591
  showError("PDF 업로드 중 오류가 발생했습니다.");
1592
  }
1593
  }
1594
-
1595
- function addCard(i, thumb, title, isCached = false, pdfId = null) {
1596
- const d = document.createElement('div');
1597
- d.className = 'card fade-in';
1598
- d.onclick = () => open(i);
1599
-
1600
- // PDF ID가 있으면 데이터 속성으로 저장
1601
- if (pdfId) {
1602
- d.dataset.pdfId = pdfId;
1603
- }
1604
-
1605
- // 제목 처리
1606
- const displayTitle = title ?
1607
- (title.length > 15 ? title.substring(0, 15) + '...' : title) :
1608
- '프로젝트 ' + (i+1);
1609
-
1610
- // 캐시 상태 뱃지 추가
1611
- const cachedBadge = isCached ?
1612
- '<div class="cached-status">캐시됨</div>' : '';
1613
-
1614
- d.innerHTML = `
1615
- <div class="card-inner">
1616
- ${cachedBadge}
1617
- <img src="${thumb}" alt="${displayTitle}" loading="lazy">
1618
- <p title="${title || '프로젝트 ' + (i+1)}">${displayTitle}</p>
1619
- </div>
1620
- `;
1621
- grid.appendChild(d);
1622
-
1623
- // 프로젝트가 있으면 '프로젝트 없음' 메시지 숨기기
1624
- $id('noProjects').style.display = 'none';
1625
- }
 
 
 
 
 
 
 
 
 
1626
 
1627
  /* ── 프로젝트 저장 ── */
1628
  function save(pages, title, isCached = false, pdfId = null) {
 
70
  logger.error(f"메타데이터 저장 오류: {e}")
71
 
72
  # PDF ID 생성 (파일명 + 타임스탬프 기반)
73
+ # PDF ID 생성 (파일명 + 타임스탬프 기반) - 더 단순하고 안전한 방식으로 변경
74
  def generate_pdf_id(filename: str) -> str:
75
  # 파일명에서 확장자 제거
76
  base_name = os.path.splitext(filename)[0]
77
+ # 안전한 문자열로 변환 (URL 인코딩 대신 직접 변환)
78
+ import re
79
+ safe_name = re.sub(r'[^\w\-_]', '_', base_name.replace(" ", "_"))
80
  # 타임스탬프 추가로 고유성 보장
81
  timestamp = int(time.time())
82
  # 짧은 임의 문자열 추가
83
  random_suffix = uuid.uuid4().hex[:6]
84
  return f"{safe_name}_{timestamp}_{random_suffix}"
85
 
86
+
87
+
88
  # PDF 파일 목록 가져오기 (메인 디렉토리용)
89
  def get_pdf_files():
90
  pdf_files = []
 
301
  pdf_cache[pdf_name]["error"] = str(e)
302
 
303
  # PDF ID로 PDF 경로 찾기
304
+ # PDF ID로 PDF 경로 찾기 (개선된 검색 로직)
305
  def get_pdf_path_by_id(pdf_id: str) -> str:
306
+ logger.info(f"PDF ID로 파일 조회: {pdf_id}")
307
+
308
+ # 1. 메타데이터에서 직접 ID로 검색
309
  if pdf_id in pdf_metadata:
310
  path = pdf_metadata[pdf_id]
311
  # 파일 존재 확인
312
  if os.path.exists(path):
313
  return path
314
 
315
+ # 파일이 이동했을 수 있으므로 파일명으로 검색
316
  filename = os.path.basename(path)
317
+
318
+ # 영구 저장소에서 검색
319
  perm_path = PERMANENT_PDF_DIR / filename
320
  if perm_path.exists():
321
  # 메타데이터 업데이트
 
323
  save_pdf_metadata()
324
  return str(perm_path)
325
 
326
+ # 메인 디렉토리에서 검색
327
  main_path = PDF_DIR / filename
328
  if main_path.exists():
329
  # 메타데이터 업데이트
 
331
  save_pdf_metadata()
332
  return str(main_path)
333
 
334
+ # 2. 파일명 부분만 추출하여 모든 PDF 파일 검색
335
+ try:
336
+ # ID 형식: filename_timestamp_random
337
+ # 파일명 부분만 추출
338
+ name_part = pdf_id.split('_')[0] if '_' in pdf_id else pdf_id
339
+
340
+ # 모든 PDF 파일 검색
341
+ for file_path in get_pdf_files() + get_permanent_pdf_files():
342
+ # 파일명이 ID의 시작 부분과 일치하면
343
+ file_basename = os.path.basename(file_path)
344
+ if file_basename.startswith(name_part) or file_path.stem.startswith(name_part):
345
+ # ID 매핑 업데이트
346
+ pdf_metadata[pdf_id] = str(file_path)
347
+ save_pdf_metadata()
348
+ return str(file_path)
349
+ except Exception as e:
350
+ logger.error(f"파일명 검색 중 오류: {e}")
351
+
352
+ # 3. 모든 PDF 파일에 대해 메타데이터 확인
353
+ for pid, path in pdf_metadata.items():
354
+ if os.path.exists(path):
355
+ file_basename = os.path.basename(path)
356
+ # 유사한 파일명을 가진 경우
357
+ if pdf_id in pid or pid in pdf_id:
358
+ pdf_metadata[pdf_id] = path
359
+ save_pdf_metadata()
360
+ return path
361
+
362
  return None
363
 
364
  # 시작 시 모든 PDF 파일 캐싱
 
416
  # 백그라운드 작업 시작 함수
417
  @app.on_event("startup")
418
  async def startup_event():
419
+ # PDF 메타데이터 로드
420
+ load_pdf_metadata()
421
+
422
+ # 누락된 PDF 파일에 대한 메타데이터 생성
423
+ for pdf_file in get_pdf_files() + get_permanent_pdf_files():
424
+ found = False
425
+ for pid, path in pdf_metadata.items():
426
+ if os.path.basename(path) == pdf_file.name:
427
+ found = True
428
+ # 경로 업데이트
429
+ if not os.path.exists(path):
430
+ pdf_metadata[pid] = str(pdf_file)
431
+ break
432
+
433
+ if not found:
434
+ # 새 ID 생성 및 메타데이터에 추가
435
+ pdf_id = generate_pdf_id(pdf_file.name)
436
+ pdf_metadata[pdf_id] = str(pdf_file)
437
+
438
+ # 변경사항 저장
439
+ save_pdf_metadata()
440
+
441
  # 백그라운드 태스크로 캐싱 실행
442
  asyncio.create_task(init_cache_all_pdfs())
443
 
 
745
  async def view_pdf_by_id(pdf_id: str):
746
  # PDF ID 유효한지 확인
747
  pdf_path = get_pdf_path_by_id(pdf_id)
748
+
749
+ if not pdf_path:
750
+ # 일단 모든 PDF 메타데이터를 다시 로드하고 재시도
751
+ load_pdf_metadata()
752
+ pdf_path = get_pdf_path_by_id(pdf_id)
753
+
754
+ if not pdf_path:
755
+ # 모든 PDF 파일을 직접 스캔��여 유사한 이름 찾기
756
+ for file_path in get_pdf_files() + get_permanent_pdf_files():
757
+ name_part = pdf_id.split('_')[0] if '_' in pdf_id else pdf_id
758
+ if file_path.stem.startswith(name_part):
759
+ pdf_metadata[pdf_id] = str(file_path)
760
+ save_pdf_metadata()
761
+ pdf_path = str(file_path)
762
+ break
763
+
764
  if not pdf_path:
765
  return HTMLResponse(
766
  content=f"<html><body><h1>PDF를 찾을 수 없습니다</h1><p>ID: {pdf_id}</p><a href='/'>홈으로 돌아가기</a></body></html>",
 
1667
  showError("PDF 업로드 중 오류가 발생했습니다.");
1668
  }
1669
  }
1670
+
1671
+ function addCard(i, thumb, title, isCached = false, pdfId = null) {
1672
+ const d = document.createElement('div');
1673
+ d.className = 'card fade-in';
1674
+ d.onclick = () => open(i);
1675
+
1676
+ // PDF ID가 있으면 데이터 속성으로 저장
1677
+ if (pdfId) {
1678
+ d.dataset.pdfId = pdfId;
1679
+ }
1680
+
1681
+ // 제목 처리
1682
+ const displayTitle = title ?
1683
+ (title.length > 15 ? title.substring(0, 15) + '...' : title) :
1684
+ '프로젝트 ' + (i+1);
1685
+
1686
+ // 캐시 상태 뱃지 추가
1687
+ const cachedBadge = isCached ?
1688
+ '<div class="cached-status">캐시됨</div>' : '';
1689
+
1690
+ // 바로가기 링크 추가 (PDF ID가 있는 경우에만)
1691
+ const linkHtml = pdfId ?
1692
+ `<div style="position: absolute; bottom: 55px; left: 50%; transform: translateX(-50%); z-index:5;">
1693
+ <a href="/view/${pdfId}" target="_blank" style="color:#4a6ee0; font-size:11px;">바로가기 링크</a>
1694
+ </div>` : '';
1695
+
1696
+ d.innerHTML = `
1697
+ <div class="card-inner">
1698
+ ${cachedBadge}
1699
+ <img src="${thumb}" alt="${displayTitle}" loading="lazy">
1700
+ ${linkHtml}
1701
+ <p title="${title || '프로젝트 ' + (i+1)}">${displayTitle}</p>
1702
+ </div>
1703
+ `;
1704
+ grid.appendChild(d);
1705
+
1706
+ // 프로젝트가 있으면 '프로젝트 없음' 메시지 숨기기
1707
+ $id('noProjects').style.display = 'none';
1708
+ }
1709
+
1710
+
1711
 
1712
  /* ── 프로젝트 저장 ── */
1713
  function save(pages, title, isCached = false, pdfId = null) {