feat(harness): Upstage OCR 연동 하네스 — Document AI + 7개 워크플로우

에이전트:
- upstage-ocr-dev: Document Parse/Information Extraction/QA API 엔진
- ocr-workflow-dev: 7개 워크플로우 (계약서/납품서/청구서/감사/장애/회의록/브랜드계약)

오케스트레이터: upstage-ocr-orchestrator
- Upstage API Base URL 연동
- 현대백화점 등 브랜드 계약서 스키마 포함
- 7종 내장 추출 템플릿
- 민감 정보 자동 마스킹
- multimodal.py (온프레미스) 와 보완 관계

API 가이드: references/upstage-api-guide.md
- Document Parse/Extract/QA 요청·응답 구조
- 6개 시나리오별 추출 스키마 (계약서/납품서/청구서/보고서/회의록)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
DESKTOP-TKLFCPR\ython 2026-06-02 18:24:26 +09:00
parent b8faec44e0
commit d76caea5dd
5 changed files with 886 additions and 0 deletions

View File

@ -0,0 +1,200 @@
# ocr-workflow-dev
## 핵심 역할
Upstage OCR 결과를 **GUARDiA ITSM 워크플로우에 자동 연동**한다.
6개 시나리오 + 기업 계약서 처리를 구현하여
문서 → 자동 등록/분류/SR 생성 전 과정을 자동화한다.
## 구현 범위
### 신규 라우터: `doc_workflow.py`
```
엔드포인트:
POST /api/docflow/contract — 계약서 OCR → 조달 자동 등록
POST /api/docflow/server-spec — 서버납품서 OCR → CMDB 자동 등록
POST /api/docflow/invoice — 청구서/세금계산서 → 과금 연동
POST /api/docflow/audit-report — 감사보고서 → CSAP 자동 업데이트
POST /api/docflow/incident-report — 장애보고서 이미지 → SR 자동 생성
POST /api/docflow/meeting-minutes — 회의록 → SR/작업 자동 생성
POST /api/docflow/brand-contract — 브랜드 계약서 (현대백화점 등) 처리
GET /api/docflow/jobs — 워크플로우 작업 목록
GET /api/docflow/jobs/{id} — 작업 상세·결과
```
### 신규 라우터: `doc_template.py`
```
엔드포인트:
GET /api/doctemplate/ — 추출 템플릿 목록
POST /api/doctemplate/ — 템플릿 생성
PUT /api/doctemplate/{id} — 템플릿 수정
DELETE /api/doctemplate/{id} — 템플릿 삭제
GET /api/doctemplate/builtin — 내장 템플릿 목록
POST /api/doctemplate/apply-builtin — 내장 템플릿 적용
```
### 시나리오 구현
#### 시나리오 1: 나라장터 계약서 자동 등록
```python
async def process_contract(file_bytes, filename, api_key, tenant_id, db):
# 1. Upstage Information Extraction
schema = {
"contract_no": "계약번호",
"contract_name": "계약품명",
"supplier": "공급사명",
"supplier_biz_no": "공급사사업자번호",
"amount": "계약금액",
"start_date": "계약시작일",
"end_date": "계약종료일",
"institution": "발주기관명",
}
extracted = await extract_information(api_key, file_bytes, filename, schema)
# 2. e_procurement.py 자동 등록
if extracted.get("contract_no"):
await db.execute(insert(ProcurementRecord).values(
tenant_id=tenant_id,
contract_no=extracted["contract_no"],
contract_name=extracted["contract_name"],
supplier=extracted["supplier"],
amount=parse_amount(extracted["amount"]),
start_date=parse_date(extracted["start_date"]),
end_date=parse_date(extracted["end_date"]),
))
return extracted
```
#### 시나리오 2: 서버 납품서 → CMDB 자동 등록
```python
# 납품서에서 서버 사양 추출 → tb_server_info 자동 등록
schema = {
"hostname": "호스트명",
"model": "서버모델",
"cpu": "CPU 사양",
"memory_gb": "메모리(GB)",
"disk_tb": "스토리지(TB)",
"ip_addr": "IP주소",
"serial_no": "시리얼번호",
"warranty_until": "보증기간",
}
```
#### 시나리오 3: 브랜드 계약서 (현대백화점 등)
```python
# 일반 기업 계약서 템플릿
schema = {
"contract_title": "계약서명",
"party_a": "갑(발주사)",
"party_b": "을(수주사)",
"contract_amount": "계약금액",
"contract_period": "계약기간",
"payment_terms": "지급조건",
"effective_date": "계약일",
"contract_items": "계약품목",
"special_conditions": "특수조건",
"penalty_clause": "위약금 조항",
"contact_a": "갑 담당자",
"contact_b": "을 담당자",
}
# 추출 후 → ProcurementRecord + SR 연계 또는 별도 BrandContract 테이블
```
#### 시나리오 4: 장애보고서 이미지 → SR 자동 생성
```python
# Document Parse로 에러 내용 추출 → SRRequest 자동 생성
extracted_text = await parse_document(api_key, file_bytes, filename)
error_summary = extract_error_from_text(extracted_text["text"])
sr = SRRequest(
title=f"[장애보고서] {error_summary[:80]}",
description=extracted_text["text"][:1000],
category="INCIDENT", priority="HIGH",
status=SRStatus.OPEN,
)
```
### 내장 추출 템플릿
```python
BUILTIN_TEMPLATES = {
"narasajang_contract": {
"name": "나라장터 계약서",
"schema": {"contract_no": "계약번호", "amount": "계약금액", ...},
"workflow": "e_procurement",
},
"server_delivery": {
"name": "서버 납품 명세서",
"schema": {"hostname": "호스트명", "cpu": "CPU", "memory_gb": "메모리(GB)", ...},
"workflow": "cmdb_register",
},
"brand_contract": {
"name": "일반 기업 계약서 (현대백화점 등)",
"schema": {"party_a": "갑", "party_b": "을", "contract_amount": "계약금액", ...},
"workflow": "procurement_record",
},
"invoice": {
"name": "세금계산서/청구서",
"schema": {"invoice_no": "세금계산서번호", "supplier": "공급자", "amount": "공급가액", ...},
"workflow": "billing",
},
"incident_report": {
"name": "장애 보고서",
"schema": {"error_type": "오류유형", "affected_system": "영향 시스템", ...},
"workflow": "sr_create",
},
"csap_report": {
"name": "CSAP 점검 보고서",
"schema": {"check_item": "점검항목", "result": "점검결과", "score": "점수", ...},
"workflow": "compliance_update",
},
"meeting_minutes": {
"name": "회의록",
"schema": {"date": "회의일", "participants": "참석자", "decisions": "결정사항", "actions": "액션아이템"},
"workflow": "sr_create",
},
}
```
## DB 모델 추가
```python
class DocWorkflowJob(Base):
__tablename__ = "tb_doc_workflow_job"
id = Column(Integer, primary_key=True)
tenant_id = Column(Integer, nullable=False, index=True)
workflow_type = Column(String(50)) # contract|server_spec|invoice|...
filename = Column(String(300))
template_id = Column(Integer, nullable=True)
status = Column(String(20), default="PROCESSING")
extracted_data = Column(JSON, nullable=True)
linked_record_id = Column(Integer, nullable=True)
linked_table = Column(String(50), nullable=True)
error_message = Column(Text, nullable=True)
created_by = Column(Integer, ForeignKey("tb_user.id"))
created_at = Column(DateTime, default=func.now())
completed_at = Column(DateTime, nullable=True)
class DocTemplate(Base):
__tablename__ = "tb_doc_template"
id = Column(Integer, primary_key=True)
tenant_id = Column(Integer, nullable=False, index=True)
name = Column(String(200), nullable=False)
description = Column(Text, nullable=True)
schema_json = Column(Text, nullable=False) # 추출 스키마
workflow = Column(String(50), nullable=True) # 연동 워크플로우
is_builtin = Column(Boolean, default=False)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=func.now())
```
## 작업 원칙
1. 민감 정보(주민번호·계좌번호) 자동 마스킹 후 저장
2. 추출 실패 시 수동 검토 큐에 등록 (SR 생성)
3. 기업 계약서는 brand_contract 템플릿으로 표준화
4. 워크플로우 결과는 반드시 원본 파일과 연계 추적
## 팀 통신 프로토콜
- **수신**: orchestrator로부터 "워크플로우 구현 시작"; upstage-ocr-dev에서 API 스펙 수신
- **발신**: `_workspace/workflow_spec.md`
- **협업**: upstage-ocr-dev의 parse/extract 함수 재사용
- **보고**: 6개 시나리오 + 브랜드 계약 워크플로우 완료 보고

View File

@ -0,0 +1,108 @@
# upstage-ocr-dev
## 핵심 역할
GUARDiA ITSM에 **Upstage Document AI OCR 엔진**을 구현한다.
`workspace/guardia-itsm/routers/upstage_ocr.py`
Upstage API 연동 코어(Document Parse, Information Extraction, Document QA)를 구현한다.
## 구현 범위
### 신규 라우터: `upstage_ocr.py`
```
엔드포인트:
POST /api/ocr/config — Upstage API Key 설정 (AES-256-GCM 암호화)
GET /api/ocr/config — 설정 조회 (마스킹)
POST /api/ocr/parse — 문서 파싱 (PDF/PNG/JPG → 구조화 JSON)
POST /api/ocr/extract — 정보 추출 (Key-Value, 스키마 기반)
POST /api/ocr/qa — 문서 QA (문서 + 질문 → 답변)
POST /api/ocr/batch — 배치 처리 (다중 파일)
GET /api/ocr/history — OCR 처리 이력
GET /api/ocr/usage — API 사용량 현황
```
### Upstage API 연동
```python
UPSTAGE_BASE = "https://api.upstage.ai/v1/document-ai"
async def parse_document(api_key: str, file_bytes: bytes,
filename: str, model: str = "document-parse") -> dict:
"""
Upstage Document Parse API 호출.
반환: {pages, elements, tables, text, html, ...}
"""
async with httpx.AsyncClient(timeout=60) as client:
files = {"document": (filename, file_bytes, _mime_type(filename))}
headers = {"Authorization": f"Bearer {api_key}"}
r = await client.post(
f"{UPSTAGE_BASE}/document-digitization",
files=files, headers=headers,
data={"model": model, "ocr": "auto", "output_formats": ["text", "html", "markdown"]}
)
return r.json() if r.status_code == 200 else {"error": r.text[:200]}
async def extract_information(api_key: str, file_bytes: bytes,
filename: str, schema: dict) -> dict:
"""
Upstage Information Extraction API.
schema 예시: {"contract_no": "계약번호", "amount": "계약금액", "supplier": "공급사명"}
"""
async with httpx.AsyncClient(timeout=60) as client:
files = {"document": (filename, file_bytes, _mime_type(filename))}
headers = {"Authorization": f"Bearer {api_key}"}
r = await client.post(
f"{UPSTAGE_BASE}/information-extraction",
files=files, headers=headers,
data={"schema": json.dumps(schema, ensure_ascii=False)}
)
return r.json() if r.status_code == 200 else {"error": r.text[:200]}
```
### DB 모델
```python
class UpstageOCRConfig(Base):
__tablename__ = "tb_upstage_ocr_config"
tenant_id = Column(Integer, primary_key=True)
api_key_enc = Column(Text, nullable=False) # AES-256-GCM 암호화
model = Column(String(50), default="document-parse")
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=func.now())
class OCRHistory(Base):
__tablename__ = "tb_ocr_history"
id = Column(Integer, primary_key=True)
tenant_id = Column(Integer, nullable=False, index=True)
filename = Column(String(300), nullable=False)
file_size = Column(Integer, default=0)
ocr_type = Column(String(30)) # PARSE | EXTRACT | QA
schema_used = Column(Text, nullable=True) # 추출 스키마 JSON
result_json = Column(Text, nullable=True) # 결과 요약 (전체 아님)
linked_to = Column(String(50), nullable=True) # sr | contract | cmdb
linked_id = Column(Integer, nullable=True)
pages = Column(Integer, default=1)
tokens_used = Column(Integer, default=0)
status = Column(String(20), default="SUCCESS")
created_by = Column(Integer, ForeignKey("tb_user.id"))
created_at = Column(DateTime, default=func.now())
```
### 파일 지원 형식
- PDF (텍스트 레이어 있음/없음 모두)
- PNG, JPG, JPEG, TIFF, BMP
- 최대 파일 크기: 20MB
- 최대 페이지: 100페이지
### 보안 원칙
1. Upstage API Key는 AES-256-GCM 암호화 저장
2. 테넌트별 독립 API Key 관리
3. 민감 문서 (기밀, 개인정보): 온프레미스 `multimodal.py` 사용 권고
4. OCR 결과에서 주민번호, 계좌번호 자동 마스킹
5. API 사용량 추적 및 일일 한도 관리
## 팀 통신 프로토콜
- **수신**: orchestrator로부터 "OCR 엔진 구현 시작"
- **발신**: `_workspace/ocr_api_spec.md` (API 스펙)
- **협업**: ocr-workflow-dev에게 parse/extract 함수 인터페이스 제공
- **보고**: 완료 후 지원 문서 형식 + API 응답 구조 문서화

View File

@ -0,0 +1,245 @@
---
name: upstage-ocr-orchestrator
description: >
Upstage Document AI OCR 연동 및 GUARDiA ITSM 워크플로우 자동화 오케스트레이터.
Upstage API(Document Parse, Information Extraction, Document QA)를 연동하여
계약서·납품서·청구서·장애보고서·감사보고서 등을 자동 처리한다.
현대백화점 같은 기업 브랜드 계약서를 포함한 일반 계약서도 처리한다.
처리 결과를 ITSM 기능(조달관리·CMDB·과금·CSAP·SR)에 자동 연동한다.
다음 상황에서 반드시 사용:
(1) 'OCR', 'Upstage', '문서 파싱', '문서 자동 처리', '계약서 OCR';
(2) '납품서 CMDB 등록', '청구서 자동 파싱', '계약서 자동 등록';
(3) '현대백화점 계약', '브랜드 계약서', '일반 계약서 처리';
(4) '장애보고서 이미지 → SR', '회의록 → 액션아이템';
(5) 'CSAP 보고서 자동 업데이트', '감사 문서 처리';
(6) 다시 실행, 업데이트, 수정, 보완.
---
# Upstage OCR 연동 오케스트레이터
**실행 모드:** 에이전트 팀
- 팀 구성: upstage-ocr-dev (OCR 엔진) + ocr-workflow-dev (ITSM 연동)
- Phase 1: OCR 엔진 구현
- Phase 2: 워크플로우 구현 (병렬)
- Phase 3: DB 모델 + main.py 등록
---
## 시스템 개요
```
사용자/시스템
↓ 문서 업로드 (PDF/PNG/JPG)
upstage_ocr.py
↓ Upstage API 호출
├── Document Parse → 구조화 JSON (레이아웃/텍스트/테이블)
├── Information Extraction → Key-Value (스키마 기반)
└── Document QA → 자연어 답변
doc_workflow.py
↓ 결과 → ITSM 자동 연동
├── 계약서 → e_procurement.py (ProcurementRecord)
├── 납품서 → cmdb.py (Server 등록)
├── 청구서 → billing.py (Invoice)
├── 감사보고서 → compliance.py (CSAP 업데이트)
├── 장애보고서 → tasks.py (SR 생성)
├── 회의록 → tasks.py (SR + 작업)
└── 브랜드 계약서 → ProcurementRecord
```
---
## Phase 0: 컨텍스트 확인
```
_workspace/ 없음 → 초기 구현
있음 + OCR 엔진만 → upstage-ocr-dev 재실행
있음 + 워크플로우만 → ocr-workflow-dev 재실행
```
---
## Phase 1: OCR 엔진 구현 (upstage-ocr-dev)
### 구현 파일: `workspace/guardia-itsm/routers/upstage_ocr.py`
**핵심 구현:**
```python
UPSTAGE_BASE = "https://api.upstage.ai/v1/document-ai"
# 지원 형식
SUPPORTED_MIME = {
".pdf": "application/pdf",
".png": "image/png",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".tiff": "image/tiff",
".bmp": "image/bmp",
".heic": "image/heic",
}
# 민감 정보 마스킹 패턴
SENSITIVE_PATTERNS = [
(r'\d{6}-[1-4]\d{6}', '######-#######'), # 주민번호
(r'\d{3}-\d{2}-\d{5}', '###-##-#####'), # 사업자번호 (보존)
(r'\d{3,4}-\d{4}-\d{4}', '****-****-****'), # 전화번호 뒷자리
]
```
**엔드포인트:**
| 엔드포인트 | 설명 |
|-----------|------|
| `POST /api/ocr/config` | Upstage API Key 저장 (AES-256-GCM) |
| `GET /api/ocr/config` | 설정 조회 (키 마스킹) |
| `POST /api/ocr/parse` | 문서 파싱 → 구조화 JSON |
| `POST /api/ocr/extract` | 정보 추출 → Key-Value |
| `POST /api/ocr/qa` | 문서 QA → 자연어 답변 |
| `POST /api/ocr/batch` | 다중 파일 배치 처리 |
| `GET /api/ocr/history` | 처리 이력 |
| `GET /api/ocr/usage` | API 사용량 |
---
## Phase 2: 워크플로우 구현 (ocr-workflow-dev)
### 구현 파일 1: `workspace/guardia-itsm/routers/doc_workflow.py`
| 엔드포인트 | 워크플로우 | 연동 |
|-----------|---------|------|
| `POST /api/docflow/contract` | 나라장터 계약서 | e_procurement.py |
| `POST /api/docflow/server-spec` | 서버납품서 | cmdb.py |
| `POST /api/docflow/invoice` | 청구서/세금계산서 | billing.py |
| `POST /api/docflow/audit-report` | 감사·CSAP 보고서 | compliance.py |
| `POST /api/docflow/incident-report` | 장애보고서 이미지 | tasks.py (SR) |
| `POST /api/docflow/meeting-minutes` | 회의록 | tasks.py (SR+작업) |
| `POST /api/docflow/brand-contract` | **기업 브랜드 계약서** | ProcurementRecord |
| `GET /api/docflow/jobs` | 작업 목록 | — |
| `GET /api/docflow/jobs/{id}` | 작업 상세 | — |
#### 브랜드 계약서 처리 (현대백화점 등)
```python
BRAND_CONTRACT_SCHEMA = {
"contract_title": "계약서 제목",
"party_a": "갑(발주사/브랜드사)",
"party_b": "을(수주사/공급사)",
"contract_amount": "계약금액",
"currency": "통화",
"contract_period": "계약기간",
"effective_date": "계약일",
"expiry_date": "만료일",
"payment_terms": "지급조건",
"contract_items": "계약품목/서비스",
"royalty_rate": "수수료율/로열티",
"territory": "적용지역",
"exclusive": "독점여부",
"renewal_clause": "갱신조항",
"termination": "해지조건",
"penalty_clause": "위약금",
"contact_a": "갑 담당자",
"contact_b": "을 담당자",
"special_terms": "특약사항",
}
```
### 구현 파일 2: `workspace/guardia-itsm/routers/doc_template.py`
내장 템플릿 + 커스텀 템플릿 관리
**내장 템플릿 7종:**
1. `narasajang_contract` — 나라장터 계약서
2. `server_delivery` — 서버 납품 명세서
3. `brand_contract` — 기업 브랜드 계약서 (현대백화점 등)
4. `invoice` — 세금계산서/청구서
5. `incident_report` — 장애 보고서
6. `csap_report` — CSAP 점검 보고서
7. `meeting_minutes` — 회의록
---
## Phase 3: DB 모델 + main.py 등록
```python
# 신규 모델
class UpstageOCRConfig(Base): ... # API Key 설정
class OCRHistory(Base): ... # 처리 이력
class DocWorkflowJob(Base): ... # 워크플로우 작업
class DocTemplate(Base): ... # 추출 템플릿
# main.py 등록
from routers import upstage_ocr, doc_workflow, doc_template
app.include_router(upstage_ocr.router)
app.include_router(doc_workflow.router)
app.include_router(doc_template.router)
```
---
## ITSM 사이드바 메뉴 추가
```javascript
// index.html에 추가
{ label: '문서 AI (OCR)', icon: '📄', children: [
{ nav: 'ocr_parse', label: 'Upstage OCR 파싱' },
{ nav: 'ocr_contract', label: '계약서 자동 처리' },
{ nav: 'ocr_invoice', label: '청구서 처리' },
{ nav: 'ocr_history', label: 'OCR 처리 이력' },
{ nav: 'doc_templates', label: '추출 템플릿 관리' },
]}
```
---
## 데이터 흐름
```
_workspace/
├── ocr_api_spec.md ← upstage-ocr-dev
└── workflow_spec.md ← ocr-workflow-dev
```
---
## 에러 핸들링
| 에러 | 처리 |
|------|------|
| Upstage API Key 없음 | 설정 페이지 안내 |
| API 한도 초과 | 큐잉 후 재시도 |
| 지원 안 되는 파일 형식 | 400 오류 + 지원 형식 안내 |
| 추출 실패 (낮은 신뢰도) | 수동 검토 큐 등록 + SR 생성 |
| 민감 정보 감지 | 자동 마스킹 후 처리 |
| 파일 크기 초과 | 20MB 한도 안내 |
---
## 테스트 시나리오
**정상 흐름 (브랜드 계약서):**
1. POST /api/docflow/brand-contract + 현대백화점_계약서.pdf
2. Upstage Extract API 호출 → 계약번호, 금액, 기간 추출
3. ProcurementRecord 자동 생성
4. 응답: {"ok": true, "contract_no": "HDC-2026-001", "amount": 50000000, ...}
**정상 흐름 (장애보고서 이미지):**
1. POST /api/docflow/incident-report + 장애화면.png
2. Upstage Document Parse → 에러 텍스트 추출
3. SR 자동 생성 (category=INCIDENT, priority=HIGH)
4. 응답: {"ok": true, "sr_id": 1234}
---
## should-trigger
- "OCR 연동", "Upstage 설정", "문서 파싱"
- "계약서 자동 등록", "현대백화점 계약", "브랜드 계약서"
- "납품서 CMDB 등록", "청구서 자동 처리"
- "장애보고서 이미지 SR", "회의록 액션아이템"
- "다시 실행", "수정", "보완"
## should-NOT-trigger
- "multimodal 이미지 분석" → multimodal.py (온프레미스)
- "SR 처리" → guardia-orchestrator
- "CMDB 관리" → cmdb.py 직접

View File

@ -0,0 +1,305 @@
# Upstage Document AI API 가이드
## 기본 정보
| 항목 | 값 |
|------|-----|
| Base URL | `https://api.upstage.ai/v1/document-ai` |
| 인증 | Bearer Token (API Key) |
| 최대 파일 크기 | 20MB |
| 지원 형식 | PDF, PNG, JPG, JPEG, TIFF, BMP, HEIC |
| 최대 페이지 | 100페이지/요청 |
---
## 1. Document Parse (문서 파싱)
### 요청
```http
POST https://api.upstage.ai/v1/document-ai/document-digitization
Authorization: Bearer {API_KEY}
Content-Type: multipart/form-data
document: (파일 바이너리)
model: document-parse # 텍스트 레이어 있는 PDF
document-parse-ocr # 이미지/스캔 PDF
ocr: auto # auto: 자동 판단
output_formats: ["text", "html", "markdown"]
```
### 응답 구조
```json
{
"api": "2.0",
"model": "document-parse",
"usage": {"pages": 3, "tokens": 1200},
"content": {
"markdown": "# 계약서\n\n...",
"html": "<html>...</html>",
"text": "계약서\n\n당사는 ..."
},
"elements": [
{
"category": "paragraph", // paragraph | table | figure | header | footer
"content": {"markdown": "...", "html": "...", "text": "..."},
"coordinates": [{"x": 0.1, "y": 0.1, "w": 0.8, "h": 0.05}],
"page": 1
},
{
"category": "table",
"content": {"markdown": "| 항목 | 금액 |\n|---|---|\n...", "html": "<table>...</table>"},
"page": 2
}
],
"pages": [{"page": 1, "width": 595, "height": 842}]
}
```
---
## 2. Information Extraction (정보 추출)
### 요청
```http
POST https://api.upstage.ai/v1/document-ai/information-extraction
Authorization: Bearer {API_KEY}
Content-Type: multipart/form-data
document: (파일 바이너리)
schema: {
"contract_no": "계약번호",
"amount": "계약금액",
"supplier": "공급사명"
}
```
### 응답 구조
```json
{
"api": "2.0",
"usage": {"pages": 1, "tokens": 800},
"result": {
"contract_no": {
"value": "2026-IT-0042",
"confidence": 0.97,
"coordinates": {"x": 0.2, "y": 0.15, "page": 1}
},
"amount": {
"value": "₩50,000,000",
"confidence": 0.95,
"normalized": 50000000
},
"supplier": {
"value": "(주)지오정보기술",
"confidence": 0.98
}
}
}
```
---
## 3. Document QA (문서 질의응답)
### 요청
```http
POST https://api.upstage.ai/v1/document-ai/document-qa
Authorization: Bearer {API_KEY}
Content-Type: multipart/form-data
document: (파일 바이너리)
question: "이 계약서의 계약 기간은 언제까지인가요?"
```
### 응답
```json
{
"answer": "본 계약의 계약기간은 2026년 6월 1일부터 2027년 5월 31일까지입니다.",
"confidence": 0.93,
"source": {"page": 2, "text": "제3조 (계약기간) 본 계약의 기간은..."}
}
```
---
## 활용 시나리오별 스키마
### 나라장터 계약서
```json
{
"contract_no": "계약번호",
"contract_name": "계약품명",
"supplier": "공급사명",
"supplier_biz_no":"사업자등록번호",
"amount": "계약금액(원)",
"vat": "부가세",
"start_date": "계약시작일(YYYY-MM-DD)",
"end_date": "계약종료일(YYYY-MM-DD)",
"institution": "발주기관명",
"manager": "담당자",
"payment_terms": "납부조건"
}
```
### 서버 납품 명세서
```json
{
"hostname": "호스트명/서버명",
"manufacturer": "제조사",
"model_no": "모델번호",
"serial_no": "시리얼번호",
"cpu_model": "CPU 모델",
"cpu_cores": "CPU 코어 수",
"memory_gb": "메모리 용량(GB)",
"disk_config": "스토리지 구성",
"os": "운영체제",
"ip_addr": "IP주소",
"rack_location": "랙 위치",
"warranty_until": "보증기간 만료일",
"delivery_date": "납품일"
}
```
### 기업 브랜드 계약서 (현대백화점 등)
```json
{
"contract_title": "계약서 제목",
"party_a": "갑(브랜드사/발주사)",
"party_a_biz_no": "갑 사업자번호",
"party_b": "을(공급사/입점사)",
"party_b_biz_no": "을 사업자번호",
"contract_amount": "계약금액",
"currency": "통화(KRW/USD)",
"effective_date": "계약일",
"expiry_date": "만료일",
"auto_renewal": "자동갱신여부",
"payment_terms": "지급조건",
"contract_items": "계약품목/서비스",
"royalty_rate": "수수료율",
"territory": "적용지역/매장",
"exclusive": "독점여부",
"termination": "해지조건",
"penalty_clause": "위약금",
"special_terms": "특약사항",
"contact_a": "갑 담당자",
"contact_b": "을 담당자"
}
```
### 세금계산서/청구서
```json
{
"invoice_no": "세금계산서번호/청구번호",
"issue_date": "발행일",
"supplier_name": "공급자 상호",
"supplier_biz_no": "공급자 사업자번호",
"buyer_name": "공급받는자 상호",
"buyer_biz_no": "공급받는자 사업자번호",
"supply_amount": "공급가액",
"vat_amount": "세액",
"total_amount": "합계금액",
"items": "품목/내역",
"payment_due": "결제기한",
"bank_account": "입금계좌(마스킹)"
}
```
### 장애 보고서
```json
{
"incident_date": "발생일시",
"incident_type": "장애유형",
"affected_system": "영향 시스템",
"error_message": "오류 메시지",
"root_cause": "근본원인",
"impact_scope": "영향 범위",
"resolution": "조치사항",
"downtime_minutes": "다운타임(분)",
"reporter": "보고자"
}
```
### CSAP 점검 보고서
```json
{
"institution": "기관명",
"check_date": "점검일",
"total_items": "총 점검항목 수",
"passed_items": "적합 항목 수",
"failed_items": "부적합 항목 수",
"compliance_rate": "준수율(%)",
"major_findings": "주요 발견사항",
"recommendations": "권고사항"
}
```
### 회의록
```json
{
"meeting_date": "회의일시",
"meeting_place": "장소",
"participants": "참석자",
"agenda": "안건",
"decisions": "결정사항",
"action_items": "액션아이템(담당자/기한)",
"next_meeting": "차기 회의일"
}
```
---
## 비용 가이드 (참고)
| API | 페이지당 비용 |
|-----|------------|
| Document Parse | ~$0.01/페이지 |
| Information Extraction | ~$0.02/페이지 |
| Document QA | ~$0.02/요청 |
> 최신 요금은 https://www.upstage.ai/pricing 참조
---
## Python 구현 예시
```python
import httpx, base64, json
from pathlib import Path
async def upstage_parse(api_key: str, file_path: str) -> dict:
with open(file_path, "rb") as f:
file_bytes = f.read()
filename = Path(file_path).name
ext = Path(file_path).suffix.lower()
mime = {"pdf": "application/pdf", "png": "image/png", "jpg": "image/jpeg"}.get(ext[1:], "application/octet-stream")
async with httpx.AsyncClient(timeout=120) as client:
response = await client.post(
"https://api.upstage.ai/v1/document-ai/document-digitization",
headers={"Authorization": f"Bearer {api_key}"},
files={"document": (filename, file_bytes, mime)},
data={
"model": "document-parse-ocr",
"ocr": "auto",
"output_formats": '["text", "html", "markdown"]'
}
)
return response.json()
async def upstage_extract(api_key: str, file_path: str, schema: dict) -> dict:
with open(file_path, "rb") as f:
file_bytes = f.read()
filename = Path(file_path).name
async with httpx.AsyncClient(timeout=120) as client:
response = await client.post(
"https://api.upstage.ai/v1/document-ai/information-extraction",
headers={"Authorization": f"Bearer {api_key}"},
files={"document": (filename, file_bytes, "application/pdf")},
data={"schema": json.dumps(schema, ensure_ascii=False)}
)
return response.json()
```

View File

@ -279,6 +279,34 @@ GUARDiA ITSM (허브, :9001/:8443)
--- ---
## 하네스: Upstage OCR 연동
**목표:** Upstage Document AI API(Document Parse·Information Extraction·Document QA)를 연동하여 계약서·납품서·청구서·장애보고서·감사보고서·회의록을 자동 처리하고 ITSM 기능에 연동. 현대백화점 등 기업 브랜드 계약서 포함.
**트리거:** OCR, Upstage, 문서 파싱, 계약서 자동 처리, 현대백화점 계약, 브랜드 계약서, 납품서 CMDB 등록, 청구서 자동 처리, 장애보고서 이미지→SR 요청 시 `upstage-ocr-orchestrator` 스킬을 사용하라.
**에이전트:** upstage-ocr-dev (Document AI API 엔진) · ocr-workflow-dev (6개 워크플로우 + 브랜드 계약 연동)
**신규 라우터:** upstage_ocr.py · doc_workflow.py · doc_template.py
**지원 시나리오:**
1. 나라장터 계약서 → ProcurementRecord 자동 등록
2. 서버납품서 → CMDB 자동 등록
3. 브랜드 계약서 (현대백화점 등) → 계약 이력 관리
4. 세금계산서 → 과금 연동
5. 장애보고서 이미지 → SR 자동 생성
6. 회의록 → 액션아이템 SR 생성
7. CSAP 보고서 → 준수율 자동 업데이트
**API 가이드:** `.claude/skills/upstage-ocr-orchestrator/references/upstage-api-guide.md`
**변경 이력:**
| 날짜 | 변경 내용 | 대상 | 사유 |
|------|----------|------|------|
| 2026-06-02 | 초기 하네스 구성 | 전체 | Upstage OCR 연동 + 기업 계약서 처리 |
---
## 하네스: GUARDiA 고급 확장 ## 하네스: GUARDiA 고급 확장
**목표:** GUARDiA ITSM 현재 104개 라우터(667 엔드포인트)에서 20개 신규 라우터 추가. CMDB 자동 발견·Text-to-SQL·구성 드리프트·멀티클라우드·공공기관 특화 5개 영역 확장. 목표: 124개 라우터, ~764개 엔드포인트. **목표:** GUARDiA ITSM 현재 104개 라우터(667 엔드포인트)에서 20개 신규 라우터 추가. CMDB 자동 발견·Text-to-SQL·구성 드리프트·멀티클라우드·공공기관 특화 5개 영역 확장. 목표: 124개 라우터, ~764개 엔드포인트.