(라이트)EDI 수량·금액 자동정리
EDI·처방전 사진을 올리면 약품별 수량·처방량·단가·금액을 표로 정리해 드립니다 — 저비용·고속 라이트 버전입니다. 깨끗한 단일 표에 최적화했으며, 표가 불완전하면 자동 보정 없이 '확인 필요'로 표시합니다. 최고 정확도(자동 재추출·보정)가 필요하면 상위 버전(EDI 수량·금액 자동정리)을 사용하세요.
바로 실행
이미지를 올려 바로 실행해 결과를 확인하세요. (비로그인은 하루 실행 횟수 제한)
이미지를 자동으로 정렬·보정한 뒤 표를 읽어, 약품별 수량·일수·총처방량·단가·총금액을 추출합니다. 값은 이미지에서 읽어낸 원본이며, 계산·기준가 대조는 검증에만 씁니다. 약가코드가 비표준(대학병원 자체코드 등)이어도 약품명은 제공되고 라인별 needsReview로 확인 여부를 표시합니다.
엔드포인트
POST https://marketapi.nadoo.ai/api/v1/hira-extract-lite/extract인증
| 헤더 | 타입 | 필수 | 설명 |
|---|---|---|---|
x-api-key | string | 필수 | 대시보드 발급 API 키 (pk_live_…) |
Content-Type | string | 필수 | application/json |
Idempotency-Key | string | 선택 | 재시도 이중 과금 방지 (권장: UUID). 재시도 시 같은 키 + 같은 본문이면 재처리 없이 최초 결과를 반환하고, 같은 키로 다른 본문을 보내면 422. 키를 안 보내면 매 요청이 별건 처리됨. |
요청 본문 (JSON)
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
image | string | 택1 | base64 인코딩 이미지 |
imageUrl | string(uri) | 택1 | 이미지 https URL (서버 다운로드) |
templateId | string | 선택 | 특정 프롬프트 템플릿 버전으로 추출 (미지정 시 활성 최신본) |
응답 200 OK
| 필드 | 타입 | 설명 |
|---|---|---|
requestId | string | 요청 식별자 |
documentType | string | drug_table=약품표. 아니면 business_registration/receipt/other 등 표 없음 사유 |
foundTable | boolean | 약품 표 검출 여부 |
items | object[] | 약품 라인아이템 (아래 스키마) |
items[].drugCode | string | null | 약가코드 — 보이는 그대로(9자리 아닐 수 있음) |
items[].drugName | string | null | 약품명 (코드 비표준이어도 제공) |
items[].quantity | number | null | 수량(처방횟수·환자수 포함) |
items[].days | number | null | 일수(투약일수) |
items[].prescribedQty | number | null | 총처방량(총사용량/총투여량) |
items[].unitPrice | number | null | 단가 |
items[].totalAmount | number | null | 총금액 |
items[].codeInMaster | boolean | 약가 마스터 조회 성공 여부 |
items[].suggestedDrugCode | string | null | 코드 미조회 시 약품명 매칭으로 추정한 약가코드(교정 제안). drugCode(OCR 원본)를 대체하지 않고 status도 올리지 않음. 오독·절단·원내코드 복구용 |
items[].priceCheck | string | 단가 검증 — current(현재가 일치)/historical(과거가·단가변동)/mismatch/none |
items[].status | string | GREEN(정상)/YELLOW(확인 권장)/RED(오류·확인 필요) |
items[].needsReview | boolean | 사람 확인 필요 여부 |
items[].review | string[] | 확인 사유 |
summary | object | items(행수)·needsReview(확인필요 수)·byStatus(green/yellow/red)·completeExtraction(합계 대조 전체추출 여부) |
geometry.rotation | number | 적용된 총 회전각(0/90/180/270), 반시계 방향 — 서비스 보정과 표 검출기 자체 보정을 합산한 값. 0=보정 없음. source→oriented 를 재현하려면 반시계로 이 각도만큼 회전 |
geometry.source / geometry.oriented | object | 업로드 원본 / 회전 보정 후 크기 { width, height } |
geometry.crop | object | null | 표 크롭 영역. 크롭본이 정본일 때만 채워지고, 크롭 실패·원본 재추출 시 null |
geometry.crop.corners | object[] | 회전 보정본 기준 꼭짓점 4개 { x, y } — 시계방향 좌상·우상·우하·좌하 |
geometry.crop.sourceCorners | object[] | 업로드 원본 기준 꼭짓점 4개(역회전 적용). 회전 없으면 corners와 동일 |
geometry.crop.box / sourceBox | object | 같은 영역의 { x, y, width, height } 표현 |
geometry.crop.normalized | object | 회전 보정본 기준 0~1 비율 좌표(해상도 무관) |
geometry.crop.score | number | null | 표 검출 신뢰도 |
meta | object | 진단(참고) — imageReadable·imageIssues[]·rotationApplied·cropped·droppedSummaryRows·template. 외부 처리에 불필요하면 무시 가능 |
cost.krw / cost.free | number / boolean | 과금액 / 무료 처리 여부 |
balanceKrw | number | 처리 후 잔액 |
응답 예시
{
"requestId": "3f9a1c2e-...",
"documentType": "drug_table",
"foundTable": true,
"items": [
{ "drugCode": "658106350", "drugName": "OO정",
"quantity": 83, "days": null, "prescribedQty": 2355,
"unitPrice": 312, "totalAmount": 734760,
"codeInMaster": true, "priceCheck": "current",
"status": "GREEN", "needsReview": false, "review": [] }
],
"summary": { "items": 4, "needsReview": 0,
"byStatus": { "green": 4, "yellow": 0, "red": 0 },
"completeExtraction": true },
"geometry": {
"rotation": 90,
"source": { "width": 3024, "height": 4032 },
"oriented": { "width": 4032, "height": 3024 },
"crop": {
"score": 0.93,
"corners": [{"x":210,"y":340},{"x":3820,"y":340},{"x":3820,"y":2660},{"x":210,"y":2660}],
"box": { "x": 210, "y": 340, "width": 3610, "height": 2320 },
"sourceCorners": [{"x":340,"y":212},{"x":2660,"y":212},{"x":2660,"y":3822},{"x":340,"y":3822}],
"sourceBox": { "x": 340, "y": 212, "width": 2320, "height": 3610 },
"normalized": { "x": 0.052, "y": 0.112, "width": 0.895, "height": 0.767 }
}
},
"meta": { "imageReadable": true, "imageIssues": [],
"rotationApplied": 0, "cropped": true, "droppedSummaryRows": 1,
"template": { "key": "edi-extract", "version": 3 } },
"cost": { "krw": 200, "free": false },
"balanceKrw": 49700
}예시 (cURL)
curl -X POST https://marketapi.nadoo.ai/api/v1/hira-extract-lite/extract \
-H "x-api-key: pk_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"imageUrl":"https://.../edi.jpg"}'대용량 업로드 (presigned, 권장)
base64는 요청 크기 한계(본문 25MB·원본 ~18MB, 초과 시 413 payload_too_large)가 있어, 대용량·대량은 presigned 업로드가 안정적입니다(용량 무제한 — 이미지를 GCS로 직접 PUT). ① 업로드 URL 발급 → ② 이미지 PUT → ③ imageUrl로 추출.
# 1) 업로드 URL 발급
curl -X POST https://marketapi.nadoo.ai/api/v1/uploads \
-H "x-api-key: pk_live_xxxxxxxx" -H "Content-Type: application/json" \
-d '{"contentType":"image/jpeg"}'
# → { "uploadUrl": "https://storage.googleapis.com/...(PUT)", "imageUrl": "https://...(read)", "expiresIn": 3600 }
# 2) 이미지 업로드(PUT) — Content-Type 일치
curl -X PUT "<uploadUrl>" -H "Content-Type: image/jpeg" --data-binary @edi.jpg
# 3) 추출 — imageUrl 로 전달(base64 불필요)
curl -X POST https://marketapi.nadoo.ai/api/v1/hira-extract-lite/extract -H "x-api-key: pk_live_xxxxxxxx" -H "Content-Type: application/json" \
-d '{"imageUrl":"<imageUrl>"}'대량 비동기 (수천 장)
이미지 배열을 접수하고 { jobId }를 즉시 반환합니다(백그라운드 처리). GET /api/v1/jobs/{jobId}로 진행률·신호등 집계·항목별 상태를 폴링합니다. 대량은 imageUrls 권장.
curl -X POST https://marketapi.nadoo.ai/api/v1/hira-extract-lite/extract-batch-async \
-H "x-api-key: pk_live_xxxxxxxx" -H "Content-Type: application/json" \
-d '{"imageUrls":["https://.../a.jpg","https://.../b.jpg"], "templateId":"..."}'
# → { "jobId": "...", "status": "queued", "pollUrl": "/api/v1/jobs/..." }폴링 · 결과 조회
GET /api/v1/jobs/{jobId} 는 기본적으로 경량 응답(항목별 itemCount·foundTable·byStatus·extractionId)을 반환합니다. 수천 장 배치에서 폴링마다 전체 items를 싣지 않기 위함입니다. 실제 약품 라인아이템은 아래 두 방법으로 가져옵니다.
| 방법 | 설명 |
|---|---|
GET /api/v1/jobs/{jobId}?items=1 | 폴링 응답의 각 항목에 items(단건 /extract와 동일 스키마)를 병합해 반환. 소·중량 배치에 편리. |
GET /api/v1/extractions/{extractionId} | 항목별 extractionId로 개별 추출 상세를 단건 조회(items·summary). 대량 배치에서 필요한 항목만 골라 받을 때. |
# 1) 진행률 폴링(경량)
curl https://marketapi.nadoo.ai/api/v1/jobs/<jobId> -H "x-api-key: pk_live_xxxxxxxx"
# → { status, done, total, ok, trafficLights,
# results: [ { index, status, itemCount, foundTable, byStatus, extractionId } ] }
# 2) 폴링에 items 포함
curl "https://marketapi.nadoo.ai/api/v1/jobs/<jobId>?items=1" -H "x-api-key: pk_live_xxxxxxxx"
# → results[].items 에 약품 라인아이템(단건 /extract 와 동일 스키마) 포함
# 3) 개별 항목 상세(extractionId 로 온디맨드)
curl https://marketapi.nadoo.ai/api/v1/extractions/<extractionId> -H "x-api-key: pk_live_xxxxxxxx"
# → { extractionId, documentType, foundTable, items: [...], summary: {...} }참고: 대량 추출은 비동기(extract-batch-async)만 제공합니다. 동기 extract-batch는 없습니다(단건 /extract를 병렬 호출하거나 비동기 배치를 사용하세요).
에러 응답
| HTTP | error | 의미 |
|---|---|---|
| 401 | invalid_key | API 키 누락/무효 |
| 402 | insufficient_credit | 무료 소진 + 잔액 부족 |
| 400 | no_image / bad_json | 이미지 또는 JSON 본문 오류 |
| 413 | payload_too_large | 요청 본문 25MB 초과 → presigned 업로드 사용 |
| 502 | processor_error | 처리 실패(과금분 자동 환불) |
