OVERVIEW GPU OCR 개요

PaddleOCR PP-OCRv4 기반 OCR(Optical Character Recognition) API입니다. PNG, JPEG, PDF, TIFF, BMP 형식의 이미지에서 텍스트를 인식합니다. text 단순 텍스트와 json_structured 블록·표 구조화 출력을 지원합니다. 대용량 이미지는 Multipart 모드로 전송해 base64 오버헤드를 제거할 수 있습니다.

PaddleOCR PP-OCRv4 — 바이두(Baidu)가 개발한 산업용 OCR 엔진. DB++ 텍스트 검출 → 방향 분류 → SVTR 텍스트 인식의 3단계 파이프라인으로 동작합니다. 간판·번호판 등 자연 장면 텍스트와 서류·PDF·화면 캡처 등 문서 텍스트를 모두 인식합니다. 한국어·영어·중국어·일본어 4개 언어를 지원하며, 각 텍스트 영역의 좌표(bbox)와 신뢰도(confidence)를 함께 반환합니다. VRAM ~500MB.

⚠ OCR 태스크 활성화 필요

다른 태스크와 함께 실행하면 VRAM 부족이 발생합니다. 반드시 OCR만 단독으로 활성화하세요.

# .env
REDGX_GPU_RELAY_ENABLED=true
REDGX_GPU_OCR_ENABLED=true
# 나머지는 false
아키텍처 흐름
# 1. POST → 202 Accepted (request_id 반환)
POST /api/v1/ns/{ns}/gpu/ocr
  Content-Type: multipart/form-data  또는 application/json (image_b64)202 { "request_id": "ocr-1710000000000-a1b2c3d4" }

# 2. GET 폴링 → 완료 시 200
GET /api/v1/ns/{ns}/gpu/ocr/{request_id}
  → 202 { "status": "queued" }
  → 200 { "status": "completed", "text": "..." }

# 데이터 흐름
Client → POST /gpu/ocr (이미지 bytes) → Redis Queue → OCRWorker
  → PaddleOCR → text / blocks / tables → Redis Outbox → Client
지원 포맷 및 모델 정보
항목
OCR 엔진PaddleOCR PP-OCRv4 (DB++ Detection + SVTR Recognition)
모델 선정RTX 3060 12GB 채택 — ~500MB VRAM, 4개 언어(ko/en/zh/ja)
Scene Text(간판/번호판) + Document(서류/PDF/화면캡처) 모두 지원
지원 포맷 PNG JPEG PDF TIFF BMP (magic bytes 검증)
최대 파일 크기50 MB
출력 형식text: 순수 텍스트 / json_structured: blocks (위치+신뢰도) + tables (표 구조)
전송 모드JSON: image_b64 (base64) / Multipart: file 파트 (권장)
캐시SHA-256(모델명 + 이미지 bytes) 기반
캐시 TTL24시간 (86400초)
POST 이미지 업로드 · 기본 OCR

이미지 파일을 업로드하고 OCR 결과를 조회합니다. Multipart 모드(권장)와 JSON Base64 모드를 지원합니다. 샘플 이미지를 클릭하거나 직접 파일을 드래그하세요.

POST /api/v1/ns/{ns}/gpu/ocr
샘플 이미지: 아래 버튼으로 fixtures 폴더의 이미지를 바로 요청할 수 있습니다.
📷
파일을 드래그하거나 클릭하여 선택
PNG · JPEG · PDF · TIFF · BMP · 최대 50 MB
이미지를 선택하면 여기에 표시됩니다
curl 명령 보기

            
POST 출력 포맷 선택 — text vs json_structured

동일한 이미지를 textjson_structured 포맷으로 각각 요청하여 결과를 나란히 비교합니다. json_structured는 블록별 위치(bbox)와 신뢰도, 표 구조(rows × cols)를 함께 반환합니다.

text vs json_structured 동시 비교
json_structured 활용: 문서 파싱 자동화, 표 데이터 추출(엑셀 변환), 특정 영역 텍스트 검색 등에 활용합니다.
curl 명령 보기

            
POST 결과 캐시 테스트

동일한 이미지를 두 번 전송하면 두 번째는 GPU 추론 없이 즉시 반환됩니다. 캐시 키는 SHA-256(모델명 + 이미지 raw bytes)로 계산됩니다.

캐시 키: SHA-256(모델명 + 이미지 bytes) — output_formatlanguage는 캐시 키에 포함되지 않습니다. 동일 이미지에 포맷만 다르게 요청해도 캐시가 적중됩니다.
1회차 → 2회차 캐시 적중 확인
curl 명령 보기

            
MANAGE 결과 관리 — 조회 / 삭제 / 취소

결과는 outbox에 1시간(3600초) 보관됩니다.

GET 결과 조회
curl 명령 보기

            
DELETE 결과 삭제
curl 명령 보기

            
POST 요청 취소
큐 대기 중인 요청만 취소 가능. 처리 중이면 409 반환.
curl 명령 보기

            
POST 배치 상태 일괄 조회

여러 request_id 상태를 한 번의 API 호출로 조회합니다.

POST /gpu/ocr/batch-status
curl 명령 보기

            
ERROR 에러 케이스

OCR 전용 에러(INVALID_IMAGE_FORMAT)를 포함한 다양한 오류 상황을 테스트합니다.

REF API 레퍼런스
POST /api/v1/ns/{ns}/gpu/ocr — 요청 파라미터
Dual Transfer Mode:
JSON 모드 (Content-Type: application/json): image_b64 필드에 Base64 인코딩 이미지
Multipart 모드 (Content-Type: multipart/form-data): file 파트에 원본 이미지 bytes (권장)
필드타입기본값설명
image_b64string (JSON)필수Base64 인코딩 이미지 데이터 (JSON 모드)
filebinary (Multipart)필수이미지 파일 원본 bytes (Multipart 모드)
output_format"text" | "json_structured""text"출력 형식. json_structured는 blocks+tables 포함
languagestring | nullnull문서 언어 힌트 (en, ko, …). 지정 시 정확도 향상
modelstring | null서버 기본값PaddleOCR 모델명 (null = 서버 설정값)
POST 202 Accepted 응답
{
  "ok": true,
  "data": {
    "request_id": "ocr-1710567890123-a1b2c3d4",
    "task_type":  "ocr",
    "hint":       "text_recommended"   // 4KB 미만 업로드 시에만 포함 — JSON 모드 권장 힌트
  }
}

hint 필드는 multipart 업로드가 4KB 미만일 때만 응답에 포함됩니다 (요청은 거부되지 않음). 작은 페이로드에는 base64 JSON 모드가 효율적입니다.

GET 완료 응답 구조 (HTTP 200)
// output_format=text (기본)
{
  "ok": true,
  "data": {
    "request_id":    "ocr-1710567890123-a1b2c3d4",
    "status":        "completed",
    "text":          "Hello World\nThis is a test document.",
    "output_format": "text",
    "blocks":        null,       // text 모드 시 null
    "tables":        null,
    "page_count":    1,
    "language":      "en",
    "model":         "PaddleOCR/PP-OCRv4",
    "cached":        false,
    "elapsed_ms":    843.5
  }
}

// output_format=json_structured
{
  "data": {
    "text": "Hello World\nThis is a test...",
    "output_format": "json_structured",
    "blocks": [
      {
        "text": "Hello World",
        "confidence": 0.98,
        "bbox": { "x": 0.05, "y": 0.02, "width": 0.4, "height": 0.08 }
      }
    ],
    "tables": [
      {
        "rows": [["Name", "Age"], ["Alice", "30"]],
        "num_rows": 2, "num_cols": 2, "confidence": null
      }
    ]
  }
}
필드설명
request_id요청 ID
statuscompleted 또는 failed
text전체 인식 텍스트 (output_format 무관하게 항상 포함)
output_format실제 사용된 출력 형식
blocks텍스트 블록 목록 (json_structured 시), 각 블록에 text, confidence, bbox 포함
tables표 구조 목록 (json_structured 시), rows[행][열] = 셀 텍스트
page_count페이지 수 (PDF 시 실제 페이지 수, 이미지는 1)
language감지(또는 지정)된 언어
model실제 사용된 OCR 모델명
cached캐시 적중 여부
elapsed_ms전체 처리 시간 (ms)
curl 예시
# Multipart 모드 (권장)
curl -X POST https://localhost:1443/api/v1/ns/HRM/gpu/ocr \
  -k \
  -H "X-API-Key: <your-key>" \
  -F "[email protected]" \
  -F "output_format=json_structured" \
  -F "language=en"

# JSON 모드 (소용량)
curl -X POST https://localhost:1443/api/v1/ns/HRM/gpu/ocr \
  -k \
  -H "X-API-Key: <your-key>" \
  -H "Content-Type: application/json" \
  -d '{"image_b64":"'"$(base64 -w0 document.png)"'","output_format":"text"}'

# 결과 조회 후 자동 삭제
curl "https://localhost:1443/api/v1/ns/HRM/gpu/ocr/ocr-xxx?auto_clear=true" \
  -k -H "X-API-Key: <your-key>"
에러 코드
코드HTTP설명
INVALID_IMAGE_FORMAT400지원하지 않는 이미지 포맷 (magic bytes 검증 실패)
MISSING_IMAGE400JSON 모드: image_b64 필드 누락 또는 빈 값
MISSING_FILE400Multipart 모드: file 파트 누락
EMPTY_FILE400업로드 파일이 빈 바이트 (multipart 또는 base64 디코딩 결과 0 byte)
INVALID_MULTIPART400multipart/form-data 파싱 실패
INVALID_JSON400JSON 본문 파싱 실패
INVALID_BASE64400image_b64가 유효한 base64가 아님
UNAUTHORIZED401API Key 누락 또는 잘못됨
NAMESPACE_DENIED403Namespace 접근 권한 없음
GPU_NOT_FOUND404Request ID 없음 또는 만료 (TTL 3600s)
GPU_PAYLOAD_TOO_LARGE413이미지 파일 크기 초과 (max_file_size_mb, 기본 50 MB)
GPU_TASK_DISABLED503OCR 태스크 비활성 (REDGX_GPU_OCR_ENABLED=false)
GPU_UNAVAILABLE503CUDA 불가 또는 PaddleOCR 모델 로드 실패
GPU_QUEUE_FULL503큐 용량 초과
GPU_PROCESSING409취소 불가 — 이미 처리 중
WS /api/v1/ns/{ns}/gpu/ocr/{req_id}/wait — 결과 Push 대기

Redis Pub/Sub으로 완료 알림을 수신 후 즉시 OCR 결과를 전송합니다.

// 인증: Sec-WebSocket-Protocol 헤더로 API 키 전달 (URL 쿼리 미지원)
// 브라우저: new WebSocket(url, ["redgx_ak_crm_..."])
wss://<host>/api/v1/ns/CRM/gpu/ocr/ocr-xxx/wait?timeout=90          // timeout 기본 10, 최대 300
// 완료 — REST GET과 동일 구조
{ "ok": true, "data": { "request_id": "ocr-...", "status": "completed",
    "text": "인식된 텍스트", "output_format": "text",
    "blocks": null, "tables": null, "page_count": 1, "language": "en",
    "model": "PaddleOCR/PP-OCRv4", "cached": false, "elapsed_ms": 420.0 } }

// 실패
{ "ok": true, "data": { "request_id": "ocr-...", "status": "failed", "error": {...} } }

// 인증 실패 → HTTP 403 (upgrade 거부, accept 전 — 4001 close 프레임 미전송)
// Not Found    → { "ok": false, "error": { "code": "GPU_NOT_FOUND" } } + close(4004)
// Timeout      → { "ok": false, "error": { "code": "GPU_TIMEOUT" } }  + close(4008)