SlideWise: AI Agent로 구현한 대학생 맞춤 시험 대비 플랫폼

현서·2026년 2월 1일
post-thumbnail

Upstage AI Ambassador 2기 과제 - AI Agent 프로젝트 소개


📚 목차

  1. 문제 정의: 대학생의 시험 준비 현실
  2. 해결 방안: SlideWise 소개
  3. 핵심 기술: Two-Pass AI 분석 시스템
  4. 핵심 기술: Upstage API 활용
  5. 기능 소개: 3-Tab 분석 패널
  6. 기능 소개: AI 챗봇 & 퀴즈 시스템
  7. 기술 스택 & 아키텍처
  8. 기대효과 & 교육 콘텐츠 확장 가능성
  9. 개발 과정의 도전과 해결
  10. 마치며

1. 문제 정의: 대학생의 시험 준비 현실

1.1. 시험 기간의 현실

"중간고사 2주 전, 자료구조 슬라이드 150장..."

대학생이라면 누구나 겪는 상황입니다. 시험 기간이 다가오면:

📄 슬라이드 150장
+ 교수님 판서 캡처 30장
+ 강의 녹화본 3시간 분량
+ 내 필기 20페이지
───────────────────────────────────────
= 어디서부터 봐야 할까? 😰

저는 개발자로서, "AI로 이 문제를 해결할 수 없을까?" 라는 생각에서 SlideWise를 시작했습니다.

1.2. 기존 도구의 한계

처음엔 ChatGPT에 PDF를 올려봤습니다.

나: [50페이지 PDF 업로드] "이거 요약해줘"
GPT: "이 문서는 자료구조에 대한 내용으로,
      스택, 큐, 트리 등을 다룹니다..."

문제점:

  • 페이지별로 하나씩 올려야 하는 번거로움
  • 전체 맥락을 파악하지 못함
  • 시험에 뭐가 나올지, "중요한 부분"이 어딘지 모름

Google의 NotebookLM도 써봤습니다. PDF 자동 분석, 퀴즈 생성, 팟캐스트까지 정말 강력한 도구입니다. 하지만 대학생 시험 준비 관점에서 보면 아쉬운 점이 있었습니다:

기능NotebookLM대학생이 필요한 것
타겟범용 (직장인, 연구자)시험 준비에 특화
분석 단위전체 요약슬라이드별 상세 분석
퀴즈일반 문제시험 유형별 (객관식/서술형/코딩)
시험 범위전체 문서시험 범위만 선택 가능
교수 강조점기본 OCR손글씨 필기/강조 추출

1.3. 핵심 Pain Point 정리

  1. 슬라이드 복붙 노가다: 50장 슬라이드를 AI에 1장씩 넣는 건 비현실적
  2. 맥락 없는 분석: 각 슬라이드를 독립적으로 보면 전체 흐름을 놓침
  3. 시험 유형 무시: 객관식과 서술형은 공부 방법이 다름
  4. 일방적 요약: 질문하고 싶을 때 다시 AI에 물어봐야 함

결론: 기존 도구들은 훌륭하지만, 대학생 시험 준비에 특화되지 않았습니다.


2. 해결 방안: SlideWise 소개

2.1. 핵심 컨셉

"AI에 슬라이드 1장씩 넣었을 때의 디테일을, 단 한 번의 업로드로"

SlideWise는 PDF 강의 슬라이드를 업로드하면 AI가 자동으로:

  • 전체 맥락을 파악하고
  • 각 슬라이드를 심층 분석하며
  • 시험 유형에 맞춘 학습 전략을 제공합니다.

2.2. 차별화 포인트

1️⃣ 시험 유형별 맞춤 분석

대학 시험은 크게 4가지 유형이 있고, 각 유형마다 공부 방법이 다릅니다:

시험 유형특징학습 전략
객관식4지선다, OX오답 선지 함정 파악, 정확한 정의 암기
서술형단답형, 논술답안 구조화, 필수 키워드 포함
코딩알고리즘 구현시간복잡도, Edge case 체크
혼합형다양한 유형유형별 전략 병행

예시: "해시 함수 설계 원리" 슬라이드

객관식 시험일 때:

🎯 오답 선지 함정
❌ "해시 함수는 중복을 허용하지 않는다"
   → 충돌은 발생할 수 있음! (함정)

🔑 정의 정확도
"충돌 최소화" vs "충돌 제거"
→ "최소화"가 정확한 표현

서술형 시험일 때:

📝 예상 문제
Q. 해시 함수 설계 시 고려해야 할 3가지 원리를 설명하시오.

✍️ 답안 작성 구조 (20점 만점)
[1단계 - 2점] 서론: 해시 함수의 정의
[2단계 - 12점] 3가지 원리 각 4점
[3단계 - 3점] 구체적 예시
[4단계 - 3점] 결론

🔑 필수 키워드 (안 쓰면 감점!)
✓ "충돌 최소화"
✓ "균일 분포"
✓ "시간복잡도 O(1)"

2️⃣ Two-Pass 분석 (자동 + 온디맨드)

기존 AI 도구: "전체 요약 한 번"
SlideWise: "전체 맥락 파악 → 슬라이드별 심층 분석"

Phase 1 (자동): PDF 업로드 시 즉시 실행
├── 전체 요약 (200-300자)
├── 토픽 그룹핑 (3-7개)
├── 중요 개념 추출 (10-20개)
└── 학습 전략 제안

Phase 2 (온디맨드): 사용자가 슬라이드 선택 시 실행
├── 핵심 개념 설명 (300-500자)
├── 다이어그램 요소별 해석
├── 구체적 예시 3개
├── 자주 하는 실수 2-3개
├── 시험 대비 전략
├── 연습 문제 2개
└── 빠른 복습 카드 3-5개

이 구조의 장점:

  • 빠른 첫 화면: Phase 1은 약 30초 내 완료
  • 필요한 것만 분석: 모든 슬라이드를 분석하지 않아 효율적
  • 캐싱: 한 번 분석한 슬라이드는 재사용

3️⃣ 실시간 AI 튜터 챗봇

슬라이드를 보다가 궁금한 점이 생기면 바로 질문할 수 있습니다.

👤 사용자: "해시 충돌 해결 방법 중 체이닝과 오픈 어드레싱의 차이가 뭐야?"

🤖 AI 튜터: "현재 보고 계신 슬라이드 11의 내용을 기반으로 설명드릴게요.

**체이닝 (Chaining)**
- 같은 버킷에 연결 리스트로 저장
- 장점: 삭제가 간단
- 단점: 추가 메모리 필요

**오픈 어드레싱 (Open Addressing)**
- 다른 빈 버킷을 찾아 저장
- 장점: 메모리 효율적
- 단점: 클러스터링 발생 가능

📌 시험 Tip: 서술형에서 둘의 '장단점 비교' 자주 출제됩니다!"

3. 핵심 기술: Two-Pass AI 분석 시스템

3.1. 왜 Two-Pass인가?

일반적인 AI 분석 방식은 전체 문서를 한 번에 요약하는 One-Pass입니다.

// ❌ One-Pass 방식 - 표면적 분석
const analysis = await solar.chat({
  prompt: "이 150페이지 슬라이드 전부 분석해줘"
})
// 결과: "이 강의는 자료구조를 다룹니다..." (너무 추상적)

One-Pass의 문제점:

  • 각 슬라이드의 디테일 부족
  • "시험에 뭐가 나올까?"에 답하지 못함
  • ChatGPT와 다를 바 없음

SlideWise는 Two-Pass 방식을 채택했습니다:

┌─────────────────────────────────────────────────────┐
│  Phase 1: 전체 맥락 파악 (1회 API 호출)              │
│  ├── 모든 슬라이드 텍스트를 한 번에 분석             │
│  ├── 과목 전체 흐름 이해                            │
│  ├── 토픽별 그룹핑                                  │
│  └── slideContents 저장 (Phase 2에서 사용)          │
└─────────────────────────────────────────────────────┘
                        ↓
┌─────────────────────────────────────────────────────┐
│  Phase 2: 슬라이드별 심층 분석 (N회 API 호출)        │
│  ├── 사용자가 특정 슬라이드 선택 시 실행             │
│  ├── Phase 1의 맥락 정보 참조                       │
│  ├── 300-500자 상세 설명                           │
│  ├── 시험 유형별 맞춤 전략                          │
│  └── 분석 결과 캐싱 (재요청 시 즉시 반환)            │
└─────────────────────────────────────────────────────┘

3.2. Phase 1: 전체 맥락 파악

Phase 1은 PDF 업로드 즉시 자동으로 실행됩니다.

// app/api/analyze/route.ts (간략화)
async function processPhase1(analysisId: string, filePath: string, examType: string, subject: string) {
  // 1. Upstage Document Parse로 PDF 텍스트 추출
  const parseResult = await parseDocument(filePath)
  const slideContents = parseResult.elements.map(e => e.text)

  // 2. Solar Pro로 전체 맥락 분석
  const overviewPrompt = `
    과목: ${subject}
    시험 유형: ${examType}
    전체 슬라이드: ${slideContents.length}장

    [슬라이드 내용]
    ${slideContents.map((s, i) => `[${i+1}] ${s}`).join('\n')}

    다음을 JSON으로 분석:
    1. overallSummary: 전체 요약 (200-300자)
    2. topics: 토픽 그룹핑 (3-7개)
    3. importantConcepts: 핵심 개념 (10-20개)
    4. studyStrategy: 학습 전략
  `

  const overview = await callSolarAPI(overviewPrompt)

  // 3. 결과 저장 (slideContents 포함 - Phase 2에서 사용)
  await supabase.from('analyses').update({
    analysis_result: {
      ...overview,
      slideContents,  // Phase 2에서 개별 슬라이드 텍스트 사용
      detailedSlideAnalyses: []
    },
    status: 'completed'
  })
}

Phase 1 결과 예시:

{
  "overallSummary": "이 강의는 자료구조의 핵심인 해시 테이블을 다룹니다. 해시 함수 설계 원리부터 충돌 해결 방법, 실제 구현까지 단계적으로 학습합니다.",
  "topics": [
    { "title": "해시 함수 기초", "slideNumbers": [1, 2, 3, 4], "examWeight": "중" },
    { "title": "해시 함수 설계", "slideNumbers": [5, 6, 7, 8, 9, 10, 11], "examWeight": "상" },
    { "title": "충돌 해결", "slideNumbers": [12, 13, 14, 15], "examWeight": "상" }
  ],
  "importantConcepts": [
    { "concept": "해시 함수", "importance": "★★★", "examLikelihood": "상" },
    { "concept": "충돌(Collision)", "importance": "★★★", "examLikelihood": "상" },
    { "concept": "체이닝", "importance": "★★", "examLikelihood": "중" }
  ],
  "slideContents": ["슬라이드1 텍스트...", "슬라이드2 텍스트...", ...]
}

3.3. Phase 2: 슬라이드별 심층 분석 (온디맨드)

Phase 2는 사용자가 특정 슬라이드의 "분석하기" 버튼을 클릭할 때만 실행됩니다.

[UI 스크린샷 삽입 위치 - 분석하기 버튼]

슬라이드 선택 후 "이 슬라이드 분석하기" 버튼을 클릭하는 화면

// app/api/analyze/slide/route.ts (간략화)
export async function POST(request: Request) {
  const { analysisId, slideNumber } = await request.json()

  // 1. 이미 분석된 슬라이드인지 확인 (캐싱)
  const existing = analysisResult.detailedSlideAnalyses?.find(
    d => d.slideNumber === slideNumber
  )
  if (existing?.conceptExplanation) {
    return NextResponse.json({ slideAnalysis: existing, cached: true })
  }

  // 2. Phase 1에서 저장한 슬라이드 텍스트 가져오기
  const slideContent = analysisResult.slideContents[slideNumber - 1]

  // 3. 심층 분석 실행
  const slideAnalysis = await analyzeSlideInDepth(
    slideNumber,
    slideContent,
    subject,
    examType,
    analysisResult  // Phase 1 맥락 정보 참조
  )

  // 4. 결과 저장
  await saveSlideAnalysis(analysisId, slideAnalysis)

  return NextResponse.json({ slideAnalysis, cached: false })
}

3.4. Phase 2 프롬프트 설계

Phase 2의 핵심은 시험 유형별 맞춤 프롬프트입니다.

// 시험 유형별 프롬프트 분기
function getExamTypeSpecificPrompt(examType: string): string {
  switch (examType) {
    case 'mcq':  // 객관식
      return `
        - 오답 선지로 자주 나오는 개념들
        - 정확히 알아야 할 키워드
        - "A와 B의 차이를 묻는 문제 대비"
      `
    case 'essay':  // 서술형
      return `
        - 답안 작성 구조 (정의 → 설명 → 예시)
        - 반드시 포함해야 할 키워드
        - 예상 배점 (정의 5점, 설명 10점, 예시 5점)
        - 모범 답안 예시 (200자 내외)
      `
    case 'coding':  // 코딩
      return `
        - 구현 시 주의사항
        - 시간복잡도/공간복잡도 분석
        - Edge case 체크리스트
        - 핵심 코드 스니펫
      `
    default:  // 혼합형
      return `
        - 객관식으로 나올 확률과 대비 방법
        - 서술형으로 나올 확률과 대비 방법
      `
  }
}

Phase 2 결과 예시 (슬라이드 11: 해시 함수 설계 원리):

{
  "slideNumber": 11,
  "title": "해시 함수 설계 원리",

  "conceptExplanation": "해시 함수 설계의 핵심은 '충돌 최소화'입니다. 좋은 해시 함수는 입력값을 테이블 전체에 균일하게 분포시켜야 합니다. 예를 들어, 학번을 해시 키로 사용할 때 단순히 앞 두 자리(입학년도)만 사용하면 같은 학번대 학생들이 모두 같은 버킷에 몰립니다. 대신 전체 학번을 사용하고, 테이블 크기 M을 소수로 선택하면 분포가 균일해집니다...",

  "examples": [
    {
      "title": "나쁜 해시 함수 예시",
      "content": "M=10일 때, h(k) = k mod 10. 키가 20, 30, 40이면 모두 버킷 0에 저장됨 → 충돌 다발",
      "code": "function badHash(key) { return key % 10; }"
    },
    {
      "title": "좋은 해시 함수 예시",
      "content": "M=7(소수)일 때, h(k) = k mod 7. 키 15→1, 22→1, 30→2로 분산됨",
      "code": "function goodHash(key) { return key % 7; }"
    }
  ],

  "commonMistakes": [
    "❌ '해시 함수는 충돌이 없다' → 충돌은 발생할 수 있으며, 최소화가 목표",
    "❌ 'M은 아무 수나 가능하다' → M은 소수를 권장 (균일 분포)"
  ],

  "examAnalysis": {
    "likelihood": "상",
    "questionTypes": ["정의 묻기", "좋은/나쁜 해시 함수 비교", "M 선택 이유"],
    "answerStructure": "1) 해시 함수 정의 (3점)\n2) 3가지 설계 원리 (9점)\n3) 구체적 예시 (3점)",
    "keyTerms": [
      { "term": "충돌 최소화", "definition": "다른 키가 같은 버킷에 매핑되는 것을 줄임", "mustInclude": true },
      { "term": "균일 분포", "definition": "모든 버킷에 키가 고르게 분산", "mustInclude": true }
    ],
    "modelAnswer": "해시 함수는 키를 해시 테이블의 인덱스로 변환하는 함수이다. 좋은 해시 함수의 조건은 첫째 충돌 최소화, 둘째 균일 분포, 셋째 O(1) 시간복잡도이다. 예를 들어 M=7(소수)일 때 h(k)=k mod 7은 키를 고르게 분산시킨다."
  },

  "practiceQuestions": [
    {
      "question": "해시 테이블 크기 M을 소수로 선택하는 이유를 설명하시오.",
      "answer": "소수를 사용하면 키가 테이블 전체에 균일하게 분포되어 충돌이 감소한다.",
      "explanation": "M이 2의 거듭제곱이면 하위 비트만 사용되어 패턴이 생기고, 소수면 모든 비트가 활용됨",
      "difficulty": "중급"
    }
  ],

  "quickReviewCards": [
    { "front": "좋은 해시 함수의 3가지 조건은?", "back": "충돌 최소화, 균일 분포, O(1) 시간복잡도" },
    { "front": "M을 소수로 선택하는 이유는?", "back": "균일 분포를 위해" }
  ]
}

4. 핵심 기술: Upstage API 활용

SlideWise는 Upstage의 두 가지 핵심 API를 활용합니다.

4.1. Document Parse: PDF에서 텍스트 추출

PDF를 분석하려면 먼저 텍스트를 추출해야 합니다. Upstage Document Parse API는 단순 텍스트뿐 아니라 손글씨 필기까지 인식합니다.

[슬라이드 이미지 예시]
┌─────────────────────────────────────┐
│  해시 함수 설계 원리                  │  ← 인쇄체
│  • 충돌 최소화                       │  ← 인쇄체
│                                     │
│  M은 소수로! ★★★                    │  ← 손글씨 필기
│  시험 꼭 나옴                        │  ← 손글씨 필기
└─────────────────────────────────────┘

코드 예시:

// lib/upstage.ts
export async function parseDocument(filePath: string) {
  const formData = new FormData()
  formData.append('document', file)

  const response = await fetch(
    'https://api.upstage.ai/v1/document-digitization',
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.UPSTAGE_API_KEY}`
      },
      body: formData
    }
  )

  return response.json()
  // 결과: { elements: [{ text: "해시 함수 설계 원리...", page: 1 }, ...] }
}

일반 PDF 파서 vs Upstage Document Parse:

기능일반 PDF 파서Upstage Document Parse
인쇄체
손글씨 필기
강조 표시 (★, 밑줄)
표/다이어그램 구조부분 지원

왜 중요한가?: 대학 강의에서 교수님의 손글씨 필기나 강조 표시는 종종 시험에 나올 핵심 내용을 담고 있습니다. 이를 놓치면 중요한 정보를 잃게 됩니다.

4.2. Solar Pro: 한국어 최적화 LLM

분석에는 Upstage의 Solar Pro 모델을 사용합니다.

// Solar Pro API 호출
const response = await fetch(
  'https://api.upstage.ai/v1/solar/chat/completions',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.UPSTAGE_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      model: 'solar-pro',
      messages: [
        { role: 'system', content: systemPrompt },
        { role: 'user', content: userPrompt }
      ],
      response_format: { type: 'json_object' },  // JSON 응답 보장
      temperature: 0.4  // 일관성 있는 응답
    })
  }
)

Solar Pro를 선택한 이유:

항목설명
한국어 이해도대학 전공 용어, 한국어 문맥 파악이 정확
JSON 안정성response_format: { type: 'json_object' } 지원으로 파싱 오류 최소화
속도슬라이드 1개당 약 2-3초
비용 효율고품질 대비 경제적

4.3. Upstage API 통합 아키텍처

┌──────────────────────────────────────────────────────────┐
│                    SlideWise                              │
└──────────────────────────────────────────────────────────┘
                           │
           ┌───────────────┴───────────────┐
           ▼                               ▼
┌─────────────────────┐         ┌─────────────────────┐
│  Document Parse API │         │    Solar Pro API    │
│  (PDF 텍스트 추출)   │         │    (AI 분석/챗봇)    │
├─────────────────────┤         ├─────────────────────┤
│ • OCR 기반 추출      │         │ • Phase 1: 전체 분석 │
│ • 손글씨 인식        │         │ • Phase 2: 상세 분석 │
│ • 페이지별 분리      │         │ • 챗봇 응답         │
│ • 표/다이어그램 구조  │         │ • 퀴즈 생성/채점    │
└─────────────────────┘         └─────────────────────┘

5. 기능 소개: 3-Tab 분석 패널

분석 결과는 3개 탭으로 구조화되어 목적에 맞게 학습할 수 있습니다.

5.1. 📖 개념 설명 탭

목적: 슬라이드 내용을 완전히 이해하기

섹션내용
핵심 개념300-500자 상세 설명, 왜 중요한지, 실생활 비유
다이어그램 해석그림/수식의 각 요소 설명
구체적 예시실제 숫자/코드로 3가지 예시
자주 하는 실수학생들이 흔히 틀리는 포인트
관련 개념다른 슬라이드와의 연결

5.2. 📝 시험 대비 탭

목적: 시험에서 고득점 받기

섹션내용
출제 확률상/중/하로 표시
예상 문제 유형"정의 묻기", "비교 문제" 등
답안 작성 구조점수 배분까지 포함된 가이드
필수 키워드답안에 반드시 포함할 용어
오답 패턴학생들이 자주 쓰는 잘못된 답
모범 답안150-200자 예시 답안


5.3. 🎯 연습 탭

목적: 실전 연습

섹션내용
연습 문제2개 (난이도 표시, 정답/해설 포함)
빠른 복습 카드플래시카드 3-5개
퀴즈 생성원하는 문제 수/유형으로 퀴즈 생성


6. 기능 소개: AI 챗봇 & 퀴즈 시스템

6.1. 슬라이드 기반 AI 챗봇

슬라이드를 보다가 궁금한 점이 생기면 바로 질문할 수 있습니다.

특징:

  • 현재 보고 있는 슬라이드 맥락 자동 포함
  • 이전 대화 히스토리 유지
  • 마크다운 렌더링 (코드 블록, 표 등)
// 챗봇 API 호출
const response = await fetch('/api/chat/ask', {
  method: 'POST',
  body: JSON.stringify({
    analysisId,
    message: "체이닝과 오픈 어드레싱 차이점이 뭐야?",
    slideContext: currentSlide  // 현재 슬라이드 번호
  })
})

6.2. 자동 퀴즈 생성 & AI 채점

분석된 슬라이드를 기반으로 맞춤형 퀴즈를 생성합니다.


퀴즈 유형:

  • 객관식 (4지선다)
  • 서술형 (AI가 채점 및 피드백)
  • 혼합형
// 퀴즈 생성
const quiz = await fetch('/api/quiz/generate', {
  method: 'POST',
  body: JSON.stringify({
    analysisId,
    quizType: 'mcq',      // 객관식
    questionCount: 5       // 5문제
  })
})

// 퀴즈 제출 및 채점
const result = await fetch('/api/quiz/submit', {
  method: 'POST',
  body: JSON.stringify({
    quizId,
    answers: userAnswers
  })
})
// 결과: { score: 80, feedback: [...], wrongAnswers: [...] }

퀴즈가 분석 내용을 반영하는 방법:

Phase 2에서 분석된 detailedSlideAnalyses의 내용을 퀴즈 생성 프롬프트에 포함시킵니다:

// app/api/quiz/generate/route.ts
const detailedAnalyses = analysisResult?.detailedSlideAnalyses || []
const slideDetails = detailedAnalyses.map((slide) => `
슬라이드 ${slide.slideNumber}: ${slide.title}
- 핵심 개념: ${slide.conceptExplanation}
- 예시: ${slide.examples?.map(e => e.content).join(', ')}
- 핵심 용어: ${slide.examAnalysis?.keyTerms?.map(k => k.term).join(', ')}
`).join('\n')

const context = `
과목 요약: ${overallSummary}
주요 토픽: ${topicTitles}
중요 개념: ${conceptList}

슬라이드별 상세 내용:
${slideDetails}
`

7. 기술 스택 & 아키텍처

7.1. 전체 아키텍처

┌─────────────────────────────────────────────────────────────┐
│                     Frontend (Next.js 15)                    │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐ │
│  │  Upload  │ → │ Analysis │ → │   Quiz   │   │  Chat    │ │
│  └──────────┘   └──────────┘   └──────────┘   └──────────┘ │
└─────────────────────────┬───────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────────┐
│              Backend (Next.js API Routes)                    │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  /api/analyze      → Phase 1 전체 분석              │   │
│  │  /api/analyze/slide → Phase 2 슬라이드별 분석        │   │
│  │  /api/chat/ask     → AI 챗봇 응답                   │   │
│  │  /api/quiz/generate → 퀴즈 생성                     │   │
│  │  /api/quiz/submit  → 퀴즈 채점                      │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────┬───────────────────────────────────┘
                          │
          ┌───────────────┼───────────────┐
          ▼               ▼               ▼
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│   Upstage    │  │   Supabase   │  │    Vercel    │
│  APIs        │  │              │  │              │
├──────────────┤  ├──────────────┤  ├──────────────┤
│ • Doc Parse  │  │ • PostgreSQL │  │ • 호스팅     │
│ • Solar Pro  │  │ • Auth       │  │ • Serverless │
│              │  │ • Storage    │  │ • Edge       │
└──────────────┘  └──────────────┘  └──────────────┘

7.2. 기술 스택 상세

영역기술버전용도
FrameworkNext.js15.xApp Router, API Routes
UIReact19.x컴포넌트 기반 UI
LanguageTypeScript5.x타입 안정성
StylingTailwind CSS4.x유틸리티 기반 스타일링
Componentsshadcn/ui-Radix UI 기반 컴포넌트
StateTanStack Query5.x서버 상태 관리
Formreact-hook-form + Zod-폼 상태 + 검증
DatabaseSupabase (PostgreSQL)-DB + Auth + Storage
AIUpstage APIs-Doc Parse + Solar Pro
DeployVercel-Serverless 배포

7.3. React 19의 새로운 기능 활용

Next.js 15부터 params가 Promise로 변경되었습니다. React 19의 use() hook을 활용합니다:

// ✅ React 19 방식
import { use } from 'react'

export default function AnalysisPage({
  params
}: {
  params: Promise<{ id: string }>
}) {
  const { id } = use(params)  // Promise를 동기적으로 unwrap
  // ...
}

7.4. Vercel Serverless 최적화

Vercel의 무료 티어는 함수 실행 시간이 10초로 제한됩니다. 이를 해결하기 위해:

  1. maxDuration 설정 (Pro 플랜):
// app/api/analyze/route.ts
export const maxDuration = 60  // 60초까지 허용
  1. Phase 분리: Phase 2를 온디맨드로 분리하여 각 호출의 실행 시간 단축

8. 기대효과 & 교육 콘텐츠 확장 가능성

8.1. 기대효과

학생 관점

효과설명
학습 시간 단축150장 슬라이드를 1장씩 읽는 대신, AI가 핵심만 추출
맞춤형 학습시험 유형(객관식/서술형)에 맞는 전략 제공
실전 대비예상 문제, 모범 답안으로 실전 연습
24시간 과외AI 챗봇으로 언제든 질문 가능

정량적 목표

📊 목표 지표
├── 시험 준비 시간: 기존 대비 50% 단축
├── 핵심 개념 파악률: 90% 이상
├── 사용자 만족도: 4.5/5.0 이상
└── 재사용률: 70% 이상

8.2. 교육 콘텐츠 확장 가능성

SlideWise의 Two-Pass 분석 시스템은 다양한 교육 시나리오로 확장 가능합니다:

1️⃣ 자격증 시험 대비

[확장 예시: 정보처리기사]
├── 기출문제 패턴 분석
├── 출제 빈도 기반 학습 우선순위
├── 오답 노트 자동 생성
└── 합격 예측 점수 제공

2️⃣ 기업 교육/연수

[확장 예시: 신입사원 교육]
├── 사내 매뉴얼 분석
├── 직무별 핵심 내용 추출
├── 이해도 테스트 자동 생성
└── 학습 진도 대시보드

3️⃣ 언어 학습

[확장 예시: TOEIC/TOEFL]
├── 지문 난이도 분석
├── 핵심 어휘 추출
├── 문제 유형별 전략
└── 약점 집중 학습

4️⃣ K-12 교육

[확장 예시: 수능 대비]
├── 교과서 단원별 분석
├── 수능 기출 연계 분석
├── 오개념 교정
└── 등급 예측

8.3. 기술적 확장 가능성

기능설명필요 기술
강의 영상 분석YouTube 강의 자막 분석STT, 영상 처리
필기 인식 강화손글씨 노트 직접 업로드OCR 고도화
협업 학습스터디 그룹 공유 기능실시간 동기화
학습 분석개인화된 학습 패턴 분석ML/Analytics

9. 개발 과정의 도전과 해결

9.1. Vercel Serverless 타임아웃 문제

문제: Vercel 무료 티어의 함수 실행 시간 제한 (10초)

증상: 슬라이드가 많은 PDF 분석 시 타임아웃 발생

해결: Two-Pass 아키텍처로 분리

Before (One-Pass):
├── 모든 슬라이드 한 번에 분석
├── 150장 × 3초 = 450초 → 타임아웃!
└── ❌ 실패

After (Two-Pass):
├── Phase 1: 전체 요약만 (30초 이내)
├── Phase 2: 사용자가 선택한 슬라이드만 (10초 이내)
└── ✅ 성공

9.2. React Error #31 (Object Rendered as Child)

문제: commonMistakes 배열에 문자열과 객체가 혼재

증상: React 렌더링 오류

해결: 타입 정규화

// 렌더링 시 타입 체크
{commonMistakes.map((mistake, i) => (
  <li key={i}>
    {typeof mistake === 'string'
      ? mistake
      : (mistake as any)?.pattern || JSON.stringify(mistake)}
  </li>
))}

9.3. 분석 버튼이 안 보이는 문제

문제: 슬라이드 선택 시 "분석하기" 버튼이 표시되지 않음

원인: 조건부 렌더링 분기 오류

해결: 분기 로직 수정

// Before (잘못된 분기)
{activeSlide ? (
  <Summary />  // 버튼 없음
) : hasDetailedAnalysis ? (
  <FullContent />
) : (
  <AnalyzeButton />
)}

// After (수정)
{hasDetailedAnalysis ? (
  <FullContent />
) : (
  <AnalyzeButton />  // 분석 안 된 슬라이드면 버튼 표시
)}

9.4. 마크다운 렌더링 이슈

문제: **텍스트**를 형태로 한글이 붙으면 파싱 실패

// ❌ 파싱 안 됨
"**해시 함수**는 중요합니다"

// ✅ 파싱 됨
"**해시 함수** 는 중요합니다"

해결: 전처리 함수 적용

function preprocessMarkdown(text: string): string {
  return text
    .replace(/\*\*([^*]+)\*\*([가-힣a-zA-Z])/g, '**$1** $2')
    .replace(/`([^`]+)`([가-힣a-zA-Z])/g, '`$1` $2')
}

10. 마치며

10.1. 프로젝트 요약

항목내용
문제 정의대학생 시험 준비 시 슬라이드 분석의 비효율성
해결 방안Two-Pass AI 분석 + 시험 유형별 맞춤 전략
핵심 기술Upstage Document Parse + Solar Pro, Next.js 15
기대효과학습 시간 50% 단축, 맞춤형 시험 대비

10.2. 배운 점

  1. 사용자 중심 설계: "대학생 시험 준비"라는 명확한 타겟이 모든 기능 결정의 기준
  2. 품질 vs 속도 트레이드오프: Two-Pass는 느리지만, 사용자가 원하는 퀄리티 제공
  3. API 선택의 중요성: 한국어 특화 Solar Pro + 강력한 OCR의 조합이 핵심
  4. Serverless 제약 극복: 아키텍처 설계로 타임아웃 문제 해결

10.3. 향후 계획

  • 강의 녹화 영상 자막 자동 분석
  • 기출문제 데이터베이스 연동
  • 스터디 그룹 협업 기능
  • 모바일 앱 (React Native)
  • B2B 확장 (대학 제휴)

📎 링크


🙏 감사의 말


Upstage AI Ambassador 2기 과제로 제작되었습니다.

Made with ❤️ by @hseo1o2

profile
LLM부터 풀스택까지, 만들면서 기록합니다

0개의 댓글