👉 주요 OCR서비스 / 라이브러리 비교👉 OPENAI api 실제 사용 비교🔹 계획🔹 OpenAIService 구현🔹 요청이 캐시되는 원리👉 model: gpt-4o-mini👉 model: gpt-4o👉 비용을 조금더 아낄 수 있는 방법?🔹 url로 요청👉 결론
👉 주요 OCR서비스 / 라이브러리 비교
네이버 클로바 요금
구분 | 서비스 | 기본요금 | 기본 제공 구간 | 추가 과금기준 | 추가요금 |
영수증 | Standard 플랜 | 월 180,000원 | 3,000건 | 추가 호출 횟수당 | 건당 80원 |
영수증 | Advanced 플랜 | 월 580,000원 | 15,000건 | 추가 호출 횟수당 | 건당 50원 |
사업자등록증 | Standard 플랜 | 월 180,000원 | 3,000건 | 추가 호출 횟수당 | 건당 80원 |
사업자등록증 | Advanced 플랜 | 월 580,000원 | 15,000건 | 추가 호출 횟수당 | 건당 50원 |
✅ 높은 정확도
⛔️ 커스터 마이징 안됨
⛔️ 비싼거 같음
⛔️ 절차가 복잡함
openai 요금
구분 | 요금 체계 | 토큰 사용량 | 한달 사용량 | 건당 요금 |
gpt-4o-mini | - 요청 토큰 요금
$0.150 / 1M input tokens
- 반환 토큰 요금
$0.600 / 1M output tokens | - 사업자 등록증
$토큰 사용량 : 대략 37,000 tokens
- 영수증
$토큰 사용량 : 대략 17,000 tokens | 건당 과금이지만
네이버 기본 요금제 사용량과 비교시 :
3,000 건
사업자등록증 : 월 24,000원
영수증 : 월 12,000원 | 사업자등록증 : 건당 8원
영수증 : 건당 4원 |
gpt-4o | - 요청 토큰 요금
$2.50 / 1M input tokens
- 반환 토큰 요금
$10.00 / 1M output tokens | - 사업자 등록증
$토큰 사용량 : 대략 1,450 tokens
- 영수증
$토큰 사용량 : 대략 1,040 tokens | 건당 과금이지만
네이버 기본 요금제 사용량과 비교시 :
3,000 건
사업자등록증 : 월 15,750원
영수증 : 월 10,920원 | 사업자등록증 : 건당 5원
영수증 : 건당 4원 |
✅ 4o 모델은 정확도 좋음 - 4o모델은 요청 최적화 작업이란게 있어서 요청 토큰 갯수가 되게 적음
✅ 프롬프트 커스터마이징이 되어서 정확도 발전 시킬수 있음, fine tuning 옵션도 제공함
✅ 절차가 간편함
✅ 반환 데이터 형태도 커스터 마이징 가능 (기본주소 + 상세주소 형태 커스터마이징 가능)
✅ 서버에 먼저 업로드하고 링크로 요청하면 요청 토큰이 1400개에서 1070개로 줄어듬, 3분의 1가량 요금을 줄일 수 있다는 뜻
tesseract OCR
✅ 무료
✅ 지속적인 업데이트 확인됨
⛔️ 정확도 다소 떨어짐
⛔️ 커스터마이징 어려움
⛔️ 학습 모델이 아님
paddle OCR
✅ 무료
✅ 정확도는 tesseract보다 약간 좋음
⛔️ 최신 라이브러리 업데이트가 3년전
⛔️ 커스터마이징 많이 어려움
⛔️ 학습 모델이 아님
👉 OPENAI api 실제 사용 비교
🔹 계획
1. 캐시에 관한 공식 문서 확인 2. 사업자등록증에서 원하는 데이터를 추출하는 기능으로 테스트 3. 이미지 또는 pdf 파일을 base64변환해서 api 요청 4. 4o / 4o-mini 모델 토큰과 비용 계산 5. 최적화 방법 (결론)
🔹 OpenAIService 구현
import 'dart:convert'; import 'dart:typed_data'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:http/http.dart' as http; import 'package:logger/logger.dart'; import 'package:image/image.dart' as img; class OpenAIService { Future<String> extractTextFromImage(Uint8List imageBytes) async { final image = img.decodeImage(imageBytes); final resizedImage = img.copyResize(image!, width: 1000); // 이미지의 크기 조절로 토큰 수를 조절 할 수 있다. final compressedImageBytes = Uint8List.fromList( img.encodeJpg(resizedImage, quality: 100)); // 이미지 품질 조절로 토큰 수를 조절 할 수 있다. final base64Image = base64Encode(compressedImageBytes); final response = await http.post( Uri.parse('https://api.openai.com/v1/chat/completions'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ${dotenv.env['OPENAI_API_KEY']}', }, body: jsonEncode({ 'model': 'gpt-4o', 'messages': [ { 'role': 'user', 'content': [ { 'type': 'text', 'text': '너는 뛰어난 세무사야. 이 이미지는 사업자 등록증이고, 여기서 사업자 등록번호, 개업연월일, 사업장 주소, 상호명(법인명,단체명)을 추출해서 json으로만 반환해야해.\n너가 채워야 할 필드는 bizNum, openDate, baseAddress, detailAddress, bizName에 매칭해서 한글로 반환해야해.\n그리고 보통 주소는 기본주소와 상세주소로 나누어 지는데, 주소가 --서울특별시 종로구 종로 6, 5층 스타필드 빌리지(서린동, 광화문우체국)-- 이런식으로 되어있으면 \n기본주소는 --서울특별시 종로구 종로 6--이고 상세주소는 --5층 스타필드 빌리지(서린동, 광화문우체국)-- 이런식으로 나누어져야해 \n그리고 모든 주소는 한국에서 실존하는 지역명이어야 해' }, { 'type': 'image_url', 'image_url': {'url': 'data:image/jpeg;base64,$base64Image'} } ], 'detail': 'high', } ], }), ); if (response.statusCode == 200) { final data = jsonDecode(utf8.decode(response.bodyBytes)); Logger().i('Full Response: ${jsonEncode(data)}'); final totalTokens = data['usage']['total_tokens']; Logger().i('Total tokens: $totalTokens'); Logger().i(data['choices'][0]['message']['content']); return data['choices'][0]['message']['content']; } else { throw Exception('Failed to extract text: ${response.body}'); } } }
- pdf파일이나 이미지를 변환해
Uint8List
타입을 매개변수로openai-service
를 요청하는 과정이다.
- 요청당 128000 토큰을 넘기면 에러가 발생한다.


- 그래서 그냥 이미지를 base64로 변환해서 요청하면 1회 최대 토큰수를 초과하는 경우가 많기 때문에, 이미지 사이즈를 줄이기로 했다.

- 이미지 url로 요청을 할 수도 있다 (주석처리된 부분), 이 경우 base64로 요청하는 것보다 조금 더 저렴하다. 이 부분도 확인해보자.
- 위와 같은 조건으로 비교를 해보았다.
🔹 요청이 캐시되는 원리
요청 구조

캐시를 활용하기 위해서는
- gpt에게 요청할 때 시작하는 첫 부분을 다른 요청과 동일하게 만들면 캐시가 작동한다.
- 예를들어 gpt 역할 설정같은 첫 부분을 완전 똑같이 요청하면 캐시가 작동하여 비용을 낮출 수 있다.
요청이 작동 되는 원리

- 요청을 받으면 요청의 앞 부분이 일치하는 요청이 있는 지 조회한다.
- 만약에 요청을 찾게되면, 그 요청의 응답속도를 현저히 낮출 수 있으며, 요금도 줄일 수 있다.
- 캐시는 보통 5~10분 보관되지만, 사용량이 낮은 시간대에서는 한 시간동안 보관할 수 있다.
캐싱 조건

- 토큰 수가 1024 이하인 경우에는 캐시가 작동한지 않는다, 특히
cached_tokens
부분이 0을 표시하게 된다.
- 그리고 만약 1024개를 초과하는 경우에는 캐시가 적용되는 부분은 128토큰씩 증가한다.
- 예를 들어 1500토큰수의 요청을 했다면 그 아래 128토큰수 증가단위인 1408토큰 까지 캐시적용된다.
캐시가 적용되는 데이터

- 여러가지가 있지만 이 블로그에서 중요한 내용은 이미지가 캐시가 되는것인가이다.
base64
로 된이미지
나링크
, 그리고 여러개의 파일까지 캐시가 된다
👉 model: gpt-4o-mini
요청 형태
'model': 'gpt-4o-mini', 'messages': [ { 'role': 'user', 'content': [ { 'type': 'text', 'text': '너는 뛰어난 세무사야. 이 이미지는 사업자 등록증이고, 여기서 사업자 등록번호, 개업연월일, 사업장 주소, 상호명(법인명,단체명)을 추출해서 json으로만 반환해야해.\n너가 채워야 할 필드는 businessNumber, startDate, baseAddress, detailAddress, businessName에 매칭해서 한글로 반환해야해.\n그리고 보통 주소는 기본주소와 상세주소로 나누어 지는데, 주소가 --서울특별시 종로구 종로 6, 5층 스타필드 빌리지(서린동, 광화문우체국)-- 이런식으로 되어있으면 \n baseAddress는 --서울특별시 종로구 종로 6--이고 detailAddress는 --5층 스타필드 빌리지(서린동, 광화문우체국)-- 이런식으로 나누어져야해 \n그리고 모든 주소는 한국에서 실존하는 지역명이어야 해' }, { 'type': 'image_url', 'image_url': {'url': 'data:image/jpeg;base64,$base64Image'} } ], 'detail': 'high', } ],
텍스트 추출의 정확도를 높이기 위해서
‘detail’: ‘high’
로 high-resolution 적용
- pdf 파일을 base64로 변환해서 요청
- 이미지 사이즈 width: 1000 설정
- 이미지 품질 quality: 100 설정
응답 형태

- 총 사용한 토큰 : 37,153개
- 정확도 : 오탈자 3개 발견
- 캐시된 토큰 수 : 0개
비용 계산

- 건당 요청 비용 : 0.0056 USD
- 적용 환율 : 1400 원 (약간 비싸게)
- 건당 비용 : 0.00562USD×1,400KRW/USD=7.861KRW,
대략 8원
- 네이버 월요금제 3000건 이랑 비교시 : 월 24,000원
👉 model: gpt-4o
요청 형태
'model': 'gpt-4o', 'messages': [ { 'role': 'user', 'content': [ { 'type': 'text', 'text': '너는 뛰어난 세무사야. 이 이미지는 사업자 등록증이고, 여기서 사업자 등록번호, 개업연월일, 사업장 주소, 상호명(법인명,단체명)을 추출해서 json으로만 반환해야해.\n너가 채워야 할 필드는 bizNum, openDate, baseAddress, detailAddress, bizName에 매칭해서 한글로 반환해야해.\n그리고 보통 주소는 기본주소와 상세주소로 나누어 지는데, 주소가 --서울특별시 종로구 종로 6, 5층 스타필드 빌리지(서린동, 광화문우체국)-- 이런식으로 되어있으면 \n기본주소는 --서울특별시 종로구 종로 6--이고 상세주소는 --5층 스타필드 빌리지(서린동, 광화문우체국)-- 이런식으로 나누어져야해 \n그리고 모든 주소는 한국에서 실존하는 지역명이어야 해' }, { 'type': 'image_url', 'image_url': {'url': 'data:image/jpeg;base64,$base64Image'} } ], 'detail': 'high', } ],
- 이 요청은 다음날에 진행되었기 때문에 캐시는 적용이 안되었을 것이다. 캐시없이 원요금을 비교하기 위해서!

- pdf 파일을 base64로 변환해서 요청
- 이미지 사이즈 width: 1000 설정
- 이미지 품질 quality: 100 설정
응답 형태

- 총 사용한 토큰 : 1,423개
- 정확도 : 오탈자 0개 발견
- 캐시된 토큰 수 : 0개
비용 계산

- 건당 요청 비용 : 0.0043 USD
- 적용 환율 : 1400 원 (약간 비싸게)
- 건당 비용 : 0.00427USD×1,400KRW/USD=5.978KRW,
대략 6원
- 네이버 월요금제 3000건 이랑 비교시 : 월 18,000원
👉 비용을 조금더 아낄 수 있는 방법?
🔹 url로 요청
'model': 'gpt-4o', 'messages': [ { 'role': 'user', 'content': [ { 'type': 'text', 'text': '?너는 뛰어난 세무사야. 이 이미지는 사업자 등록증이고, 여기서 사업자 등록번호, 개업연월일, 사업장 주소, 상호명(법인명,단체명)을 추출해서 json으로만 반환해야해.\n너가 채워야 할 필드는 bizNum, openDate, baseAddress, detailAddress, bizName에 매칭해서 한글로 반환해야해.\n그리고 보통 주소는 기본주소와 상세주소로 나누어 지는데, 주소가 --서울특별시 종로구 종로 6, 5층 스타필드 빌리지(서린동, 광화문우체국)-- 이런식으로 되어있으면 \n기본주소는 --서울특별시 종로구 종로 6--이고 상세주소는 --5층 스타필드 빌리지(서린동, 광화문우체국)-- 이런식으로 나누어져야해 \n그리고 모든 주소는 한국에서 실존하는 지역명이어야 해' }, { 'type': 'image_url', 'image_url': { 'url': 'https://ims365.co.kr/file_data/ims365s/2020/09/23/584537f7305734571cbaf170666715cc.jpg' }, } ], 'detail': 'high', }, ],
- 요청 원문이 비슷하기 때문에, 제일 앞에
?
를 붙여 변경하였다. 이렇게 하면 캐시 적용이 안된다.
- 인터넷에 공개된 사업자 등록증 사진 링크로 테스트 해보자.
응답형태

- 총 사용한 토큰 : 1,073개
- 정확도 : 오탈자 0개 발견
- 캐시된 토큰 수 : 0개
비용계산

- 건당 요청 비용 : 0.0033 USD
- 적용 환율 : 1400 원 (약간 비싸게)
- 건당 비용 : 0.00332USD×1,400KRW/USD=4.648KRW,
대략 5원
- 네이버 월요금제 3000건 이랑 비교시 : 월 15,000원
👉 결론
정확하게 왜 그런지는 알 수 없지만, 4o모델로 요청을 하면 토큰 수가 작게 계산이 되었다. 4o모델이 요청을 최적화한다고 gpt가 이야기 했지만, 다른 tokenizer 방식을 쓰는 건가 싶기도 하다. 캐시토큰도 0으로 찍히니 캐시때문은 아닌 것 같다.
그래서 정확도 높은 최고 효율을 내기 위해서는, 요청전 사업자 등록증을 스토리지 서버에 업로드를 먼저 진행하고 링크로 요청하면 1400개 정도로 요청되던 것이 1000개정도로 요청이 된다. 총 비용을 조금 더 절약 할 수 있다.
그리고 요청 링크는 변경하되 본문을 변경하지 않고 그대로 사용하며, 5~10분 이내에 재요청이 들어온다면 매 요청당 1024 토큰을 더 아낄수 있게 된다. ( 내 생각에는 완벽히 일치하는 구간이 1024토큰이 되어야 되지 않을 까 생각한다. 그렇게 따지면 현재 링크 방식은 응답토큰이 85개라서 정확히 일치하는 본문 구간이 1024토큰이 되지 않아 캐시가 적용이 되지 않을 것이라 생각한다. )
결론을 이렇게 내보겠다.
- gpt-4o 모델 사용
- 요청 본문을 정확히 일치 시켜야된다. (최소 1024 토큰 구간까지는)
- 파일 변환 방식도 괜찮고, 링크로 요청한다면 요청 본문을 좀 늘리는 것도 괜찮을 것 같다.