네이버 OCR 기능 사용법 및 React 적용

제론·2024년 7월 19일
3

Naver Cloud

목록 보기
1/1
post-thumbnail

NAVER CLOVA OCR

네이버 OCR 도입 배경

회사 프로젝트에서 네이버 OCR 기능을 활용해
사업자등록증의 정보를 추출하는 기능을 구현해야 했습니다.

구글 OCR도 있었지만 한글이기 때문에 인식률 측면에서 네이버 OCR을 쓰는 게 낫다고 판단했습니다.
또한 네이버 OCR은 특정 도메인(명함/사업자등록증/영수증 등)에 대한 템플릿을 제공해 더 정확하게 추츨합니다.

사용하면서 주의해야할 점은 요금입니다.
기본적으로 유료 서비스이기 때문에 무료 구간을 잘 확인하여 개발해야합니다.
잘못하면 개발하면서 많은 요청을 보내 과금이 될 수 있습니다.

서비스 설명

네이버 OCR은 기본적으로 특성에 따라 3가지 서비스로 나뉘어져 있습니다.

General OCR, Template OCR, Document OCR입니다.

General OCR

범용적으로 OCR을 활용할 때 사용됩니다.

사진이나 불특정 문서들의 글자를 추출합니다.

Template OCR

Template-OCR

템플릿을 사용해 특정 파일이나 문서에 적함한 OCR 적용 방법입니다.

인식 템플릿을 만들어 적용하므로 구체적인 문서의 레이아웃에 맞다면 더 정확한 분석이 가능합니다.

특정한 문서를 대상으로 할 때 유용합니다.

Document OCR

많이 사용하는 파일들을 네이버에서 이미 학습 시켜서 인식율을 높인 모델입니다.

영수증, 사업자등록증, 신용카드, 명함, 신분증 추가로 법인등기부등론, 병원비 영수증, 진단서, 병원비세부내역서 가능합니다.

저는 사업자등록증 모델을 사용했습니다.

사용법

네이버 OCR 기능은 다른 API 와는 다르게 API Gateway를 통해 사용해야 해서 절차가 더 많습니다.

자세한 사항은 CLOVA API 문서를 참고해주세요.

  1. 우선 네이버 OCR 상품 이용신청을 합니다.

상품 이용신청 해줍니다.

  • 도메인은 상품 구분 이름이라고 생각하시면 됩니다. 서비스 타입은 일반으로 합니다.

  • 상품 이용신청 시 다음과 같이 도메인이 생성된 것을 확인할 수 있습니다.

  1. API 연동
  • API Gateway 연동을 클릭합니다.

  • Secret Key 생성하고 자동연동을 클릭합니다.

  • 여기서 API Gateway 생서하신 적 없는 처음 사용하시는 분들은 API Gateway 신청합니다.

    • Services -> Application Services -> API Gateway 사용 신청
  • 자동연동 하셨다면 API Gateway에 자동으로 프로덕트가 생긴 것을 확인할 수 있습니다.(수동 연동도 가능지만 자동추천)

  1. API 요청 테스트
  • 이제 요청해봅시다. 자동연동 했던 창에서 APIGW Invoke URL을 복사하여 endpoint로 설정합니다.

  • POSTMAN에서 다음과 같이 Header와 Body를 추가합니다.

  • POSTMAN 기본 헤더에 추가로 X-OCR-SECRET을 추가해야 합니다.

    • X-OCR-SECRET은 API Gateway 연동 창 Secret Key입니다.

  • 요청 시 다음과 같이 데이터가 잘 분석되어 오는 걸 확인할 수 있습니다.

CORS 에러 해결

실제 프로젝트 환경에서 적용 시 POSTMAN에서는 잘 됐지만 host가 바뀌는 환경에서는 CORS 에러가 나는 걸 확인할 수 있습니다.

API Gateway에 추가적인 설정이 필요한데 이건 문서에 안 나와있어 직접 CLOUD Platform에 문의하여 적용했습니다.

  • API Gateway -> My Products로 이동합니다.

  • Product의 APIs를 클릭합니다.

  • Resources -> POST 메서드 클릭 -> 리소스 생성 -> CORS 활성화

  • Access-Control-Allow-Headers에 "x-ocr-secret"을 추가하고 수정합니다.

  • API 배포 버튼 클릭

프로젝트에 적용

이제 실제 프로젝트에 적용 해봅시다.

저는 Next.js 환경에서 requestOCR 함수를 만들어 적용했습니다.

const requestOCR = async (
    imageFile: FileWithPath[] | File[]
): Promise<OCRResponse | null | undefined> => {
    try {
        if (!imageFile[0]) {
            window.alert('사업자등록증을 등록해주세요.');
            return null;
        }

        const formData = new FormData();
        const message = {
            version: 'V2',
            requestId: Math.random().toString(),
            timestamp: dayjs().format('YYYYMMDDHHmmss'),
            images: [{ format: 'jpeg', name: imageFile[0].name }],
        };

        formData.append('message', JSON.stringify(message));
        formData.append('file', imageFile[0]);

        const data = await axios.post(
            process.env.NEXT_PUBLIC_NAVER_OCR_INVOKE_URL || '',
            formData,
            {
                headers: {
                    'Content-Type': 'multipart/form-data',
                    'X-OCR-SECRET': process.env.NEXT_PUBLIC_NAVER_X_OCR_SECRET,
                },
            }
        );
        return data.data;
    } catch (error) {
        console.log(error);
    }
};

export { requestOCR };

OCR 상태관리

저는 사업자등록증 Document API를 사용했고
각각 상태는 다음과 같았습니다.

  • OCR 분석에 성공한 경우

  • 사업자등록증 이미지가 아닌 경우

  • OCR 분석에 실패한 경우

세 가지 상태이다 보니 각각의 state 만들기 보다는 하나의 state를 사용했습니다.

interface ocrState {
    isPending: boolean; // OCR 분석 중
    isFileRejected: boolean; // OCR 이미지가 아닌 경우
    error: Error | null; // OCR 분석 실패
    data: OCRResponse | null; // OCR 분석 성공 시 데이터
}

Dropzone에 이미지 업로드 시 자동으로 requestOCR 함수가 실행되도록 하였습니다.

적절한 사업자등록증 이미지가 아닌 경우 판단은 ocrData?.images[0].bizLicense.result가 undefined인 것을 활용했습니다.

useEffect(() => {
        if (ocrState.data) {
            setOcrState((prevState) => ({
                ...prevState,
                isPending: false,
                error: null,
                data: null,
            }));
        }

        if (imageFile.length > 0) {
            setOcrState((prevState) => ({
                ...prevState,
                data: null,
                isFileRejected: false,
                isPending: true,
                error: null,
            }));

            requestOCR(imageFile)
                .then((ocrData) => {
                    // 사업자등록증 형식이 아닌 경우
                    if (ocrData?.images[0].bizLicense.result == undefined) {
                        setOcrState((prevState) => ({
                            ...prevState,
                            isPending: false,
                            isFileRejected: true,
                            error: {
                                message: '사업자등록증 이미지가 아닙니다.',
                                description: '올바른 사업자등록증 이미지를 업로드해주세요.',
                            },
                        }));
                    } else {
                        // OCR 분석 성공
                        setOcrState((prevState) => ({
                            ...prevState,
                            isPending: false,
                            data: ocrData,
                        }));
                    }
                })
                .catch((err) => {
                    // OCR 분석 실패
                    setOcrState((prevState) => ({
                        ...prevState,
                        isPending: false,
                        error: {
                            message: '사업자등록증 분석에 실패했습니다.',
                            description: '잠시 후 다시 시도해 주세요.',
                        },
                    }));
                })
                .finally(() => {
                    setOcrState((prevState) => ({
                        ...prevState,
                        isPending: false,
                    }));
                });
        }
    }, [imageFile]);

실제 결과물

lottie를 이용해서 추가적인 애니메이션 및 스크롤 이동도 구현해봤습니다.

감사합니다!

profile
Software Developer

0개의 댓글

관련 채용 정보