저는 학교 기록을 검증하려고 직접 PDF를 열어 정보를 옮겨 적다가 손목이 남아나지 않았습니다. 그래서 Next.js API Route에서 CLOVA OCR API를 호출해 텍스트를 자동으로 추출하는 파이프라인을 만들었습니다. PDF를 페이지별로 쪼개고, 안전한 동시성으로 요청을 보내는 부분이 핵심이었어요.
pdf-lib으로 페이지를 하나씩 잘라 Base64로 인코딩해 CLOVA OCR에 보냅니다.images 배열에 담아 순차적으로 API를 호출하고, 최대 4개씩만 병렬로 처리합니다.inferText를 모아 한 번에 반환해 후속 로직이 쉽게 활용할 수 있도록 했습니다.PDFDocument.load로 업로드된 PDF를 읽고, copyPages로 한 페이지씩 새 PDF를 만들어 Base64로 변환했습니다. pageLimit 파라미터를 받아 최대 처리 페이지 수도 제어했습니다.
각 페이지/이미지마다 { format, name, data } 구조를 만들고, CLOVA API에 lang: 'ko', resultType: 'string'을 지정했습니다. X-OCR-SECRET 헤더와 ocrInvokeUrl은 환경 변수에서 가져옵니다.
import { PDFDocument } from 'pdf-lib';
interface OcrImagePayload {
format: 'pdf' | 'jpg' | 'png';
name: string;
data: string; // Base64
}
export async function splitPdfIntoImages(
pdfBytes: ArrayBuffer,
pageLimit = 1,
): Promise<OcrImagePayload[]> {
const pdfDoc = await PDFDocument.load(pdfBytes);
const totalPages = pdfDoc.getPageCount();
const limit = Math.min(Math.max(pageLimit, 1), totalPages);
const payloads: OcrImagePayload[] = [];
for (let pageIndex = 0; pageIndex < limit; pageIndex += 1) {
const singlePagePdf = await PDFDocument.create();
const [page] = await singlePagePdf.copyPages(pdfDoc, [pageIndex]);
singlePagePdf.addPage(page);
const base64Data = Buffer.from(await singlePagePdf.save()).toString('base64');
payloads.push({
format: 'pdf',
name: `page_${pageIndex + 1}`,
data: base64Data,
});
}
return payloads;
}
const ocrRequestBody = {
images: [{ format: 'pdf', name: `page_${pageIndex}`, data: base64Data }],
lang: 'ko',
requestId: `ocr_${Date.now()}_${pageIndex}`,
resultType: 'string',
timestamp: Date.now(),
version: 'V1',
};
const response = await fetch(process.env.OCR_INVOKE_URL!, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-OCR-SECRET': process.env.X_OCR_SECRET!,
},
body: JSON.stringify(ocrRequestBody),
});
processImagesInBatches가 4개씩 슬라이스로 끊어 비동기로 호출합니다. Promise.allSettled로 실패한 요청은 빈 배열로 대체하고, 성공한 요청에서 inferText를 추출해 결과 배열에 넣었습니다.
pageLimit 기본값을 1로 두고, 필요할 때만 클라이언트에서 늘리도록 했습니다.이제 사용자가 학력 증빙 파일을 올리면 몇 초 내에 OCR 결과가 돌아옵니다. 운영자가 수동으로 입력하던 시간을 줄였고, 실패한 페이지만 골라 다시 시도할 수 있게 로그도 남겼습니다. 다음 목표는 OCR 결과를 정규식으로 파싱해 자동 검증 비율을 높이는 것입니다.
여러분은 문서 OCR을 어떻게 처리하고 계신가요? 다른 서비스나 최적화 팁이 있다면 꼭 알려주세요.