Skill: sw326/hira-hospital (version 3.2.0)

--- name: hira-hospital description: HIRA hospital information search API version: 3.2.0 author: chumjibot created: 2026-02-10 updated: 2026-02-19 tags: [hospital, medical, korea, openapi, data.go.kr] connectors: [~~hospital, ~~search, ~~notify] --- # Hospital Info Skill HIRA (Health Insurance Review & Assessment Service) hospital search + detail lookup. ## Overview | Service | ID | Endpoint | Purpose | |---------|-----|----------|---------| | Hospital Info | 15001698 | `hospInfoServicev2` | Hospital list search | | Detail Info | 15001699 | `MadmDtlInfoService2.7` | Departments, hours, transport | | Key | Value | |-----|-------| | Auth | `~/.config/data-go-kr/api_key` | | Base URL | `https://apis.data.go.kr/B551182/` | | Legal basis | National Health Insurance Act §43 | ## Scripts ``` scripts/ ├── hospital_search.sh → Search hospitals (name/region/type/dept) └── hospital_detail.sh → Hospital detail (parallel API calls) ``` ## Workflow ### Step 1: Parse search criteria - "근처 이비인후과" → region + department search - "서울대병원 진료시간" → specific hospital detail - ~~search to supplement hospital name/location ### Step 2: Search hospitals - `hospital_search.sh [criteria]` ### Step 3: Detail lookup (if needed) - `hospital_detail.sh [institution_code]` ### Step 4: Structured response ## Output Template ```markdown ## 🏥 [Query] Hospital Results | Hospital | Type | Address | Phone | Departments | |----------|------|---------|-------|-------------| ### [Hospital Name] Detail (on request) - 📍 Address: ... - ☎️ Phone: ... - 🕐 Hours: ... - 🚗 Transport: ... ``` ## Connectors | Placeholder | Purpose | Current Tool | |-------------|---------|-------------| | `~~hospital` | Hospital API | HIRA data.go.kr | | `~~search` | Name/location supplement | Brave Search | | `~~notify` | Alerts | Telegram | ## Intent Router | Intent | Trigger Examples | Strategy | |--------|-----------------|----------| | Quick Search | "근처 이비인후과", "강남 피부과", "소아과 찾아줘" | `hospital_search.sh` → 지역+진료과목 검색 → 목록 | | Detail Lookup | "이 병원 정보 자세히", "진료시간 알려줘", "주차 되나?" | `hospital_detail.sh` → 진료시간, 교통, 진료과목 상세 | **Routing logic:** 검색/찾기/추천 → Quick Search, 특정 병원 + 상세/시간/교통 → Detail Lookup ## Cross-Skill Integration | Trigger | Target Skill | Integration | |---------|-------------|-------------| | 병원 검색 결과 보충 | `web_search` (Brave) | 병원 리뷰·평판·홈페이지 보충 검색 | | 외출 시 참고 | `kma-weather` | 비/추위 예보 시 "따뜻하게 입고 가세요" 팁 | --- *Cowork architecture v3.2 — 🦞 chumjibot (2026-02-19)* ## 🔧 Setup (공공데이터 포털 API) 1. [data.go.kr](https://www.data.go.kr) 회원가입 2. 로그인 → 마이페이지 → **일반 인증키(Decoding)** 복사 3. API 키 저장: ```bash mkdir -p ~/.config/data-go-kr echo "YOUR_API_KEY" > ~/.config/data-go-kr/api_key ``` 4. 아래 서비스 **활용신청** 후 사용 (자동승인) - [심평원 병원 정보](https://www.data.go.kr/data/15001698/openapi.do) (15001698)

path: scripts/hospital.sh
content: #!/bin/bash
# 건강보험심사평가원 병원정보 조회 스크립트

set -euo pipefail

# API 키 읽기
API_KEY=$(cat ~/.config/data-go-kr/api_key 2>/dev/null || echo "")
if [ -z "$API_KEY" ]; then
    echo '{"error": "API key not found at ~/.config/data-go-kr/api_key"}' >&2
    exit 1
fi

# 파라미터
SIDO_CD="${1:-110000}"  # 시도코드 (기본: 서울)
HOSP_TYPE="${2:-병원}"  # 병원 종류
PAGE_NO="${3:-1}"
NUM_OF_ROWS="${4:-100}"

# API 호출
URL="https://apis.data.go.kr/B551182/hospInfoServicev2/getHospBasisList"

# 디버그 정보
echo "시도: $SIDO_CD | 종별: $HOSP_TYPE" >&2

# 요청 실행
RESPONSE=$(curl -s -G "$URL" \
    --data-urlencode "serviceKey=$API_KEY" \
    --data "sidoCd=$SIDO_CD" \
    --data "pageNo=$PAGE_NO" \
    --data "numOfRows=$NUM_OF_ROWS")

# XML을 JSON으로 변환
if command -v python3 &> /dev/null; then
    echo "$RESPONSE" | python3 -c "
import sys
import json
import xml.etree.ElementTree as ET

try:
    xml_str = sys.stdin.read()
    root = ET.fromstring(xml_str)
    
    # 헤더 파싱
    header = {}
    header_elem = root.find('.//header')
    if header_elem:
        for child in header_elem:
            header[child.tag] = child.text
    
    # 바디 파싱
    body = {}
    body_elem = root.find('.//body')
    if body_elem:
        for child in body_elem:
            if child.tag != 'items':
                body[child.tag] = child.text
    
    # 아이템 파싱
    items = []
    items_elem = root.find('.//items')
    if items_elem:
        for item in items_elem.findall('item'):
            item_dict = {}
            for child in item:
                item_dict[child.tag] = child.text
            # 종별 필터링
            if '$HOSP_TYPE' == '병원' or item_dict.get('clCdNm', '').find('$HOSP_TYPE') >= 0:
                items.append(item_dict)
    
    result = {
        'response': {
            'header': header,
            'body': {
                **body,
                'items': items
            }
        }
    }
    
    print(json.dumps(result, ensure_ascii=False, indent=2))
except Exception as e:
    print(json.dumps({'error': str(e), 'raw': xml_str[:500]}, ensure_ascii=False, indent=2))
"
else
    # python3 없으면 XML 그대로 출력
    echo "$RESPONSE"
fi


path: scripts/hospital_detail.sh
content: #!/bin/bash
# 병원 상세정보 통합 조회 스크립트 (curl 기반, 병렬 호출)
# 사용법: ./hospital_detail.sh <ykiho> [항목]
# 항목: all(기본), subject, detail, transport, nursing, equipment, specialist
# 예시: ./hospital_detail.sh "JDQ4MTg4MSM1..." all

set -euo pipefail

YKIHO="${1:-}"
ITEMS="${2:-all}"

if [ -z "$YKIHO" ]; then
    echo '{"error": "Usage: hospital_detail.sh <ykiho> [all|subject|detail|transport|nursing|equipment|specialist]"}' >&2
    exit 1
fi

API_KEY=$(cat ~/.config/data-go-kr/api_key)
BASE="https://apis.data.go.kr/B551182/MadmDtlInfoService2.7"
TMPDIR=$(mktemp -d)
trap "rm -rf $TMPDIR" EXIT

# 엔드포인트 매핑
declare -A EP_MAP=(
    [subject]="getDgsbjtInfo2.7"
    [detail]="getDtlInfo2.7"
    [specialist]="getSpcSbjtSdrInfo2.7"
    [transport]="getTrnsprtInfo2.7"
    [equipment]="getEqpInfo2.7"
    [nursing]="getNursigGrdInfo2.7"
)

if [ "$ITEMS" = "all" ]; then
    SELECTED="subject detail specialist transport equipment nursing"
else
    SELECTED=$(echo "$ITEMS" | tr ',' ' ')
fi

# 병렬로 curl 호출
for key in $SELECTED; do
    ep="${EP_MAP[$key]:-}"
    [ -z "$ep" ] && continue
    curl -s --max-time 20 -G "${BASE}/${ep}" \
        --data-urlencode "serviceKey=${API_KEY}" \
        --data-urlencode "ykiho=${YKIHO}" \
        --data "_type=json" \
        --data "numOfRows=100" \
        -o "${TMPDIR}/${key}.json" &
done
wait

# 결과 합치기
python3 - "$YKIHO" "$TMPDIR" $SELECTED << 'PYEOF'
import json, sys, os, glob

ykiho = sys.argv[1]
tmpdir = sys.argv[2]
selected = sys.argv[3:]

label_map = {
    'subject': '진료과목',
    'detail': '세부정보',
    'specialist': '전문의',
    'transport': '교통',
    'equipment': '시설장비',
    'nursing': '간호등급',
}

result = {'ykiho': ykiho}

for key in selected:
    label = label_map.get(key, key)
    fpath = os.path.join(tmpdir, f'{key}.json')
    if not os.path.exists(fpath):
        result[label] = {'error': 'no_response'}
        continue
    try:
        with open(fpath) as f:
            data = json.load(f)
        body = data.get('response', {}).get('body', {})
        items = body.get('items', {})
        if isinstance(items, dict):
            il = items.get('item', [])
            if isinstance(il, dict):
                il = [il]
        elif isinstance(items, str) and items == '':
            il = []
        else:
            il = []
        result[label] = il
    except Exception as e:
        result[label] = {'error': str(e)}

print(json.dumps(result, ensure_ascii=False, indent=2))
PYEOF


path: scripts/hospital_search.sh
content: #!/bin/bash
# 병원 통합 검색 스크립트 (이름/지역/종별/진료과목)
# 사용법:
#   ./hospital_search.sh --name "서울대" 
#   ./hospital_search.sh --sido 110000 --type 01
#   ./hospital_search.sh --sido 410000 --name "용인"
#   ./hospital_search.sh --dgsbjtCd 01    (진료과목코드: 01=내과)

set -euo pipefail

API_KEY=$(cat ~/.config/data-go-kr/api_key 2>/dev/null || echo "")
if [ -z "$API_KEY" ]; then
    echo '{"error": "API key not found"}' >&2
    exit 1
fi

# 기본값
SIDO_CD=""
SGGU_CD=""
HOSP_NAME=""
CL_CD=""
DGSBJ_CD=""
PAGE_NO="1"
NUM_OF_ROWS="20"

# 파라미터 파싱
while [[ $# -gt 0 ]]; do
    case "$1" in
        --sido)    SIDO_CD="$2"; shift 2 ;;
        --sggu)    SGGU_CD="$2"; shift 2 ;;
        --name)    HOSP_NAME="$2"; shift 2 ;;
        --type)    CL_CD="$2"; shift 2 ;;
        --dgsbjtCd) DGSBJ_CD="$2"; shift 2 ;;
        --page)    PAGE_NO="$2"; shift 2 ;;
        --rows)    NUM_OF_ROWS="$2"; shift 2 ;;
        *) shift ;;
    esac
done

URL="https://apis.data.go.kr/B551182/hospInfoServicev2/getHospBasisList"

# 동적 파라미터 구성
PARAMS="serviceKey=${API_KEY}&pageNo=${PAGE_NO}&numOfRows=${NUM_OF_ROWS}&_type=json"
[ -n "$SIDO_CD" ] && PARAMS="${PARAMS}&sidoCd=${SIDO_CD}"
[ -n "$SGGU_CD" ] && PARAMS="${PARAMS}&sgguCd=${SGGU_CD}"
[ -n "$CL_CD" ] && PARAMS="${PARAMS}&clCd=${CL_CD}"
[ -n "$DGSBJ_CD" ] && PARAMS="${PARAMS}&dgsbjtCd=${DGSBJ_CD}"

# yadmNm은 URL 인코딩 필요
if [ -n "$HOSP_NAME" ]; then
    ENCODED_NAME=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${HOSP_NAME}'))")
    PARAMS="${PARAMS}&yadmNm=${ENCODED_NAME}"
fi

RESPONSE=$(curl -s "${URL}?${PARAMS}")

echo "$RESPONSE" | python3 -c "
import sys, json

try:
    data = json.load(sys.stdin)
    body = data.get('response', {}).get('body', {})
    items = body.get('items', {})
    
    if isinstance(items, dict):
        item_list = items.get('item', [])
        if isinstance(item_list, dict):
            item_list = [item_list]
    elif isinstance(items, str) and items == '':
        item_list = []
    else:
        item_list = []
    
    # 간결한 출력
    hospitals = []
    for h in item_list:
        hospitals.append({
            'name': h.get('yadmNm', ''),
            'ykiho': h.get('ykiho', ''),
            'type': h.get('clCdNm', ''),
            'addr': h.get('addr', ''),
            'tel': h.get('telno', ''),
            'url': h.get('hospUrl', ''),
            'doctors': h.get('drTotCnt', ''),
            'lon': h.get('XPos', ''),
            'lat': h.get('YPos', ''),
        })
    
    result = {
        'totalCount': body.get('totalCount', 0),
        'page': body.get('pageNo', 1),
        'hospitals': hospitals
    }
    print(json.dumps(result, ensure_ascii=False, indent=2))
except Exception as e:
    raw = sys.stdin.read() if hasattr(sys.stdin, 'read') else ''
    print(json.dumps({'error': str(e)}, ensure_ascii=False, indent=2))
"


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: suspicious | SkillSpector: suspicious (HIGH)