Project Report

PDF Evidence AI

PDF를 업로드하면 AI가 근거 쪽수와 함께 질문에 답하는 문서 분석 어시스턴트

Next.js 16 Gemini 2.5 Flash PDF.js 4 NeonDB (PostgreSQL) NextAuth v4 TypeScript

시스템 구성

브라우저 (인증 필요) └─ Google OAuth → NextAuth JWT 세션 → 로그인 후 진입 │ ├─ chat/page.tsx PDF 업로드 (드래그&드롭·클릭) └─ chat/[id]/page.tsx 채팅 + PDF 뷰어 ├─ Sidebar (접이식) 채팅방 목록 탭 / 페이지 목록 탭 ├─ PdfViewer.tsx PDF.js 캔버스 (줌 제어·드래그 패닝) └─ react-markdown 마크다운·LaTeX(KaTeX)·표 스트리밍 렌더링 API Routes (Next.js Server, Node.js) ├─ POST /api/analyze-pdf (maxDuration=90s) │ ├─ 인증 확인 (NextAuth getServerSession) │ ├─ PDF 파싱 → pdf.ts (pdfjs-dist, 텍스트 추출·청킹) │ ├─ Gemini File API 업로드 → ai.ts │ ├─ 전 페이지 AI 요약 생성 → generatePageSummaries() │ └─ DB 저장: pdf_sessions + pdf_pages │ ├─ POST /api/ask (maxDuration=120s, SSE 스트리밍) │ ├─ BM25 유사도 청크 랭킹 → pdf.ts │ ├─ Gemini 스트리밍 질의 → answerWithPdfContext() │ ├─ SSE 청크 전송 (chunk/meta/done/error 이벤트) │ └─ DB 저장: chat_messages │ ├─ GET /api/sessions 사용자 채팅방 목록 조회 └─ GET /api/sessions/[id] 세션 상세 (PDF 바이너리·페이지 목록) 스토리지 ├─ NeonDB (PostgreSQL) users · pdf_sessions · pdf_pages · chat_messages └─ pdfEvidenceStore 서버 인메모리 Map (NeonDB 캐시, 재시작 시 DB에서 재로드)

구현 현황

🔐 Google 소셜 로그인

완료

NextAuth v4 + Google OAuth. JWT 세션 전략. 비로그인 시 로그인 페이지로 리다이렉트. 첫 로그인 시 DB에 사용자 자동 생성(upsert).

💾 NeonDB 영구 저장

완료

PostgreSQL(NeonDB)에 사용자·세션·PDF 바이너리·페이지 요약·대화 기록 저장. 서버 재시작 후에도 이전 채팅방 복원.

📄 PDF 업로드 & 분석

완료

드래그&드롭·클릭 업로드. 4.5MB 이하 PDF 처리. pdfjs-dist 텍스트·레이아웃 추출 및 BM25 청킹. Gemini File API 멀티모달 업로드.

🤖 AI 페이지 요약

완료

PDF 업로드 직후 Gemini가 전 페이지를 1~2문장으로 요약. 사이드바 페이지 목록 탭에 raw 텍스트 대신 표시. DB에 영구 저장.

⚡ AI 답변 스트리밍 (SSE)

완료

Server-Sent Events로 Gemini 응답 토큰을 실시간 스트리밍. chunk·meta·done·error 이벤트 타입. 첫 토큰 약 0.3~1초 내 표시.

💬 근거 기반 질의응답

완료

질문 시 관련 청크 랭킹 → Gemini 멀티모달 응답 → 근거 카드(쪽수·종류·인용·이유) 생성. 근거 카드 클릭 시 PDF 해당 페이지로 이동.

🗂️ 접이식 통합 사이드바

완료

좌측 사이드바에 채팅방 탭페이지 목록 탭 통합. 접기/펼치기 토글로 52px ↔ 전체 폭 전환. 아이콘만 모드 지원.

🔍 PDF 뷰어 줌 & 패닝

완료

− / + 버튼으로 25%씩 확대·축소 (0.5×~4×, 기본 150%). 좌클릭 드래그로 PDF 뷰어 내 자유 패닝. Pointer Events API로 안정적 구현.

🖼️ PDF.js 캔버스 뷰어

완료

iframe 대신 PDF.js 캔버스 렌더링. 빠른 페이지 전환도 이전 렌더 자동 취소. 디바이스 픽셀비(DPR) 반영으로 고해상도 출력.

📐 수식 렌더링 (KaTeX)

완료

인라인 $...$·블록 $$...$$ LaTeX 수식을 KaTeX로 오류 없이 렌더링.

📊 마크다운 + 표

완료

GFM 마크다운(표·굵기·목록·코드블록). AI 답변이 자동으로 서식 있는 HTML로 렌더링. 스트리밍 중에도 실시간 파싱.

🌐 웹 검색 보강

완료

PDF 정보가 부족하면 Google Search grounding으로 최신 정보 보강. 질문창 하단 토글로 ON/OFF.

📐 고정 뷰포트 레이아웃

완료

100쪽 이상 PDF도 전체 페이지 스크롤 없음. 채팅·PDF 뷰어·사이드바 각 패널이 독립 스크롤. 1fr + 520px 그리드.

🗂️ 페이지 목록 자동 포커스

완료

근거 카드 클릭·AI 응답 수신 시 사이드바 페이지 목록이 해당 쪽으로 부드럽게 스크롤.

NeonDB 스키마 (PostgreSQL)

테이블 주요 컬럼 역할
users id, email, name, image, created_at Google OAuth 사용자. 로그인마다 upsert.
pdf_sessions id, user_id, filename, page_count, total_characters, gemini_file_uri, pdf_data(bytea) 업로드된 PDF 세션. PDF 바이너리 저장 → 재방문 시 뷰어 복원.
pdf_pages session_id, page_number, text, preview, char_count, ai_summary 페이지별 추출 텍스트 + AI 요약. 사이드바 페이지 목록 데이터 소스.
chat_messages id, session_id, role, content, evidence_json, created_at 대화 기록. 채팅방 재진입 시 이전 대화 복원. 근거 카드 JSON 포함.

추가·보완 로드맵

🔍 페이지 목록 검색

우선순위 높음

100쪽 이상 문서에서 원하는 페이지를 찾기 어려움. 검색창 하나로 AI 요약 내용을 실시간 필터링.

구현 비용 낮음 프론트 상태 searchQuery 추가 후 pages.filter()로 필터링. 서버 변경 불필요.

📋 대화 내보내기

우선순위 중간

질문·답변·근거 목록을 마크다운으로 변환해 클립보드 복사. 논문 리뷰·공부 노트에 즉시 붙여넣기 가능.

🖼️ 페이지 썸네일

아이디어

사이드바 페이지 목록에 텍스트 요약 대신 미니 캔버스 썸네일. 시각적으로 풍부하지만 렌더링 비용이 높아 가상 스크롤 구현 필요.

🔑 키보드 단축키

아이디어

← → 화살표로 페이지 이동, Ctrl+K로 질문창 포커스, Ctrl+Enter로 질문 전송.

📷 스캔 PDF OCR

아이디어

텍스트가 없는 스캔 PDF는 현재 분석 불가. Gemini Vision으로 이미지 페이지 직접 분석하거나 Tesseract.js OCR 적용 가능.

현재 AI 응답 속도·품질 문제와 개선 방법

스트리밍 전환 완료 /api/ask가 SSE(Server-Sent Events)로 Gemini 응답을 실시간 스트리밍. 첫 토큰 0.3~1초 내 표시.
문제 원인 개선 방법 난이도
웹 검색 사용 시 추가 2~5초 PDF 답변 완료 후 순차적으로 웹 검색 2차 호출 두 호출 병렬화 또는 웹 검색을 같은 호출에 통합 중간
100쪽 PDF 요약에 20~40초 단일 호출이지만 응답 JSON이 매우 큼 배치(30쪽씩) 병렬 호출, 또는 요약 비동기 생성 중간
수식·표 누락 또는 부정확 텍스트 추출 시 수식·표 구조 손실 Gemini Vision(geminiFileUri) 직접 참조로 원본 이미지 기반 응답 낮음
근거 카드가 실제와 다른 쪽 참조 청크 랭킹 후 Gemini가 쪽 번호 재추론 evidence.page를 청크 출처로 고정하는 후처리 강화 낮음

모델 선택 가이드

모델 속도 품질 비용 추천 용도
gemini-2.5-flash
현재 사용 중
빠름 우수 저렴 일반 문서 분석, 빠른 응답이 중요한 경우
gemini-2.5-pro 보통 최고 비쌈 논문·법률·수식이 복잡한 기술 문서. 긴 추론 필요 시
gemini-2.0-flash 매우 빠름 양호 가장 저렴 페이지 요약 생성, 단순 Q&A에 활용하고 복잡 질문은 2.5-flash로 라우팅

프롬프트 최적화 체크리스트

배포 환경 및 제약 사항

Vercel Hobby 플랜 제약 함수 실행 최대 10초. /api/analyze-pdf(maxDuration=90s)와 /api/ask(maxDuration=120s)는 Pro 플랜 이상 필요. Body 크기 제한 4.5MB → 업로드 파일 크기를 4.5MB로 제한한 이유.
플랫폼 무료 한도 적합성 비고
Railway
추천
월 $5 크레딧 제공 최적 Node.js 영구 실행, 타임아웃 제한 없음, 환경변수 UI 편리
Vercel Pro 월 $20 유료 필요 함수 실행 5분, Edge Network CDN, 가장 편리한 Next.js 배포
Fly.io 소형 VM 3개 무료 가능 Docker 기반, 타임아웃 없음, 설정 약간 복잡
Koyeb Nano 인스턴스 2개 무료 가능 GitHub 연동 배포, 타임아웃 없음, EU 리전 중심
GitHub Pages 무제한 (정적만) 정적 전용 이 리포트 HTML 같은 정적 파일 배포에 최적
💡
Railway 배포 방법 요약 GitHub 저장소 연결 → New Project → Deploy from GitHub → 환경변수 설정(DATABASE_URL, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, NEXTAUTH_SECRET, NEXTAUTH_URL, GOOGLE_AI_API_KEY) → 자동 빌드·배포. Node.js 서버로 실행되어 장시간 API 함수에 제한 없음.

사용 기술 전체 목록

Frontend

  • Next.js 16.2 (App Router, webpack)
  • React 19.2
  • TypeScript 6.0
  • NextAuth v4 (Google OAuth, JWT)
  • PDF.js 4.10 — 캔버스 렌더링, DPR 대응
  • react-markdown + remark-gfm
  • remark-math + rehype-katex (수식)
  • Lucide React (아이콘)
  • CSS Custom Properties (디자인 시스템)
  • Pointer Events API (PDF 드래그 패닝)

Backend / DB / AI

  • Next.js API Routes (Node.js 20)
  • NeonDB @neondatabase/serverless (PostgreSQL)
  • @google/genai 2.1 — Gemini SDK
  • Gemini 2.5 Flash (질의응답·요약)
  • Gemini File API (PDF 멀티모달)
  • Google Search grounding
  • SSE (Server-Sent Events) 스트리밍
  • pdfjs-dist (서버 텍스트 추출)
  • BM25 청크 랭킹 (인메모리)