EDI 수량·금액 자동정리
EDI·처방전 사진을 올리면 약품별 수량·처방량·단가·금액을 표로 정리해 드립니다. 숫자를 하나하나 옮겨 적고 계산이 맞는지 검산하던 일을 대신하고, 다시 확인이 필요한 항목만 콕 집어 알려 줍니다.
바로 실행
이미지를 올려 바로 실행해 결과를 확인하세요. (비로그인은 하루 실행 횟수 제한)
이미지를 자동으로 정렬·보정한 뒤 표를 읽어, 약품별 수량·일수·총처방량·단가·총금액을 추출합니다. 값은 이미지에서 읽어낸 원본이며, 계산·기준가 대조는 검증에만 씁니다. 약가코드가 비표준(대학병원 자체코드 등)이어도 약품명은 제공되고 라인별 needsReview로 확인 여부를 표시합니다.
엔드포인트
POST https://marketapi.nadoo.ai/api/v1/hira-extract/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": 500, "free": false },
"balanceKrw": 49700
}예시 (cURL)
curl -X POST https://marketapi.nadoo.ai/api/v1/hira-extract/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/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/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 | 처리 실패(과금분 자동 환불) |
