mirror of
https://github.com/NomaDamas/k-skill.git
synced 2026-06-24 02:04:11 +00:00
Add korean-transit-route skill (#201)
* Add korean-transit-route skill * Apply review fixes to korean-transit-route skill - Add Done when and Failure modes sections to align with SKILL.md template - Fix Python geocode example to use with-statement for urlopen - Add korean-transit-route to README.md skill table and feature list - Add docs/features/korean-transit-route.md guide --------- Co-authored-by: Jeffrey (Dongkyu) Kim <vkehfdl1@gmail.com>
This commit is contained in:
parent
8c2f31ad59
commit
32162e4cd7
3 changed files with 203 additions and 0 deletions
|
|
@ -25,6 +25,7 @@ Claude Code, Codex, OpenCode, OpenClaw/ClawHub 등 각종 코딩 에이전트
|
|||
| 자연휴양림 빈 객실 조회 | `foresttrip-vacancy` | 공식 숲나들e 자연휴양림 예약 가능 객실 조회 자동화 (예약/결제 제외) | 필요 | [자연휴양림 빈 객실 조회 가이드](docs/features/foresttrip-vacancy.md) |
|
||||
| 카카오톡 Mac CLI | `kakaotalk-mac` | macOS에서 카카오톡 대화 조회, 검색, 메시지 전송 | 불필요 | [카카오톡 Mac CLI 가이드](docs/features/kakaotalk-mac.md) |
|
||||
| 서울 지하철 도착정보 조회 | `seoul-subway-arrival` | 서울 지하철 역 기준 실시간 도착 예정 열차 확인 | 불필요 | [서울 지하철 도착정보 가이드](docs/features/seoul-subway-arrival.md) |
|
||||
| 한국 대중교통 길찾기 | `korean-transit-route` | ODsay LIVE API + Kakao geocoding 기반 출발지→도착지 지하철+버스+도보 경로 및 환승 정보 조회 | 필요 | [한국 대중교통 길찾기 가이드](docs/features/korean-transit-route.md) |
|
||||
| 지하철 분실물 조회 | `subway-lost-property` | 지하철 역/물품명 기준 공식 LOST112 분실물 검색 조건과 유실물센터 진입점 안내 | 불필요 | [지하철 분실물 조회 가이드](docs/features/subway-lost-property.md) |
|
||||
| 긱뉴스 조회 | `geeknews-search` | GeekNews 공개 RSS/Atom 피드 기반 최신 글 목록, 검색, 상세 확인 | 불필요 | [긱뉴스 조회 가이드](docs/features/geeknews-search.md) |
|
||||
| 한국 날씨 조회 | `korea-weather` | 기상청 단기예보 기반 한국 날씨 조회 | 불필요 | [한국 날씨 조회 가이드](docs/features/korea-weather.md) |
|
||||
|
|
@ -116,6 +117,7 @@ Claude Code, Codex, OpenCode, OpenClaw/ClawHub 등 각종 코딩 에이전트
|
|||
- [자연휴양림 빈 객실 조회](docs/features/foresttrip-vacancy.md)
|
||||
- [카카오톡 Mac CLI](docs/features/kakaotalk-mac.md)
|
||||
- [서울 지하철 도착정보 조회](docs/features/seoul-subway-arrival.md)
|
||||
- [한국 대중교통 길찾기 가이드](docs/features/korean-transit-route.md)
|
||||
- [지하철 분실물 조회 가이드](docs/features/subway-lost-property.md)
|
||||
- [긱뉴스 조회 가이드](docs/features/geeknews-search.md)
|
||||
- [한국 날씨 조회 가이드](docs/features/korea-weather.md)
|
||||
|
|
|
|||
75
docs/features/korean-transit-route.md
Normal file
75
docs/features/korean-transit-route.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# 한국 대중교통 길찾기 가이드
|
||||
|
||||
## 이 기능으로 할 수 있는 일
|
||||
|
||||
- 출발지→도착지 도어투도어 대중교통 경로 조회 (지하철 + 버스 + 도보)
|
||||
- ODsay LIVE API 기반 환승 정보, 소요시간, 요금 확인
|
||||
- Kakao Local geocoding으로 주소·장소명→좌표 변환
|
||||
- 추천순 / 최소시간 / 최소환승 옵션 선택
|
||||
|
||||
## 먼저 필요한 것
|
||||
|
||||
- [공통 설정 가이드](../setup.md) 완료
|
||||
- [보안/시크릿 정책](../security-and-secrets.md) 확인
|
||||
- ODsay Server API Key 발급 및 호출 IP 화이트리스트 등록: https://lab.odsay.com
|
||||
- Kakao REST API Key 발급 (지도/로컬 서비스 활성화): https://developers.kakao.com
|
||||
|
||||
## 필요한 환경변수
|
||||
|
||||
- `ODSAY_API_KEY` — ODsay LIVE API Server 키
|
||||
- `KAKAO_REST_API_KEY` — Kakao Local REST API 키
|
||||
|
||||
두 값 모두 `~/.config/k-skill/secrets.env` 에 저장하거나 환경변수로 주입한다.
|
||||
|
||||
## 입력값
|
||||
|
||||
- 출발지 (주소, 장소명, 또는 좌표)
|
||||
- 도착지 (주소, 장소명, 또는 좌표)
|
||||
- 선택 사항: 경로 옵션 (`OPT=0` 추천순, `4` 최소시간, `5` 최소환승), `SearchPathType` (`0` 지하철+버스, `1` 지하철만, `2` 버스만)
|
||||
|
||||
## 기본 흐름
|
||||
|
||||
1. 출발지/도착지를 Kakao Local API(`address.json` → `keyword.json`)로 geocoding하여 좌표를 확보한다.
|
||||
2. ODsay `searchPubTransPathT`에 출발/도착 좌표와 옵션을 전달한다.
|
||||
3. 응답의 `result.path[]`를 3개 이내로 정리한다.
|
||||
4. 각 경로의 `subPath[]`를 `trafficType`별로 표시하며, 첫/끝 도보 구간을 반드시 포함한다.
|
||||
|
||||
## 예시
|
||||
|
||||
### 좌표 직접 입력
|
||||
|
||||
```bash
|
||||
set -a; . ~/.config/k-skill/secrets.env; set +a
|
||||
KEY=$(python3 -c "import os,urllib.parse;print(urllib.parse.quote(os.environ['ODSAY_API_KEY'],safe=''))")
|
||||
curl -s "https://api.odsay.com/v1/api/searchPubTransPathT?apiKey=${KEY}&SX=126.9706&SY=37.5559&EX=127.0276&EY=37.4979&OPT=0&SearchPathType=0"
|
||||
```
|
||||
|
||||
### 주소→좌표→경로 (Python)
|
||||
|
||||
```python
|
||||
import os, urllib.parse, urllib.request, json
|
||||
|
||||
H = {'Authorization': 'KakaoAK ' + os.environ['KAKAO_REST_API_KEY']}
|
||||
|
||||
def geocode(q):
|
||||
for ep, name in [('address', 'address_name'), ('keyword', 'place_name')]:
|
||||
url = f'https://dapi.kakao.com/v2/local/search/{ep}.json?query=' + urllib.parse.quote(q)
|
||||
req = urllib.request.Request(url, headers=H)
|
||||
with urllib.request.urlopen(req, timeout=10) as resp:
|
||||
d = json.loads(resp.read())
|
||||
if d.get('documents'):
|
||||
doc = d['documents'][0]
|
||||
return float(doc['x']), float(doc['y']), doc.get(name) or doc['address_name']
|
||||
return None
|
||||
|
||||
sx, sy, s_name = geocode('서울역')
|
||||
ex, ey, e_name = geocode('강남역')
|
||||
# 이후 ODsay searchPubTransPathT 호출
|
||||
```
|
||||
|
||||
## 주의할 점
|
||||
|
||||
- ODsay Server 키는 **호출 IP 화이트리스트 등록이 필수**이다. 등록되지 않은 IP에서는 `error` 응답이 반환된다.
|
||||
- 묣료 일일 한도는 5,000건이다. `searchPubTransPathT`와 `searchStation` 호출이 합산된다.
|
||||
- 한국 외 좌표는 지원하지 않는다.
|
||||
- 카카오맵/네이버지도 directions API는 대중교통 라우팅을 공개하지 않으므로 사용하지 말 것.
|
||||
126
korean-transit-route/SKILL.md
Normal file
126
korean-transit-route/SKILL.md
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
---
|
||||
name: korean-transit-route
|
||||
description: Korean door-to-door public transit routing (subway + bus + walking) via ODsay LIVE API with Kakao geocoding for address-to-address queries. Use when the user asks for 지하철/버스/대중교통 길찾기, 환승 경로, 소요시간, or transit directions between two places in Korea.
|
||||
license: MIT
|
||||
metadata:
|
||||
category: transit
|
||||
locale: ko-KR
|
||||
phase: v1
|
||||
---
|
||||
|
||||
# korean-transit-route
|
||||
|
||||
한국 대중교통(지하철+버스+도보) 도어투도어 길찾기 스킬. ODsay LIVE API + Kakao Local geocoding.
|
||||
|
||||
## When to use
|
||||
|
||||
- "강남에서 잠실 지하철로 어떻게 가?"
|
||||
- "서울역 → 인천공항 대중교통 경로"
|
||||
- "환승 가장 적은 경로", "최소 시간 경로"
|
||||
|
||||
## Credentials
|
||||
|
||||
- 환경변수 `ODSAY_API_KEY` 가 있으면 사용. 없으면 `~/.config/k-skill/secrets.env` 에서 로드.
|
||||
- ODsay Server 키는 호출 IP 화이트리스트 등록 필수. 발급은 https://lab.odsay.com
|
||||
|
||||
## Inputs
|
||||
|
||||
자연어 입력에서 출발/도착을 추출. 좌표가 없으면 **반드시 geocoding 먼저** (ODsay는 좌표만 받음).
|
||||
|
||||
### Geocoding (필수 선행 단계)
|
||||
|
||||
`KAKAO_REST_API_KEY` 사용. 두 엔드포인트를 순서대로 시도:
|
||||
|
||||
1. `https://dapi.kakao.com/v2/local/search/address.json?query=<주소>` — 도로명/지번 주소
|
||||
2. 결과 없으면 `https://dapi.kakao.com/v2/local/search/keyword.json?query=<장소명>` — 상호명/랜드마크
|
||||
|
||||
헤더: `Authorization: KakaoAK <KAKAO_REST_API_KEY>`. 응답 `documents[0].x`(경도), `.y`(위도) 사용.
|
||||
|
||||
```python
|
||||
import os, urllib.parse, urllib.request, json
|
||||
H={'Authorization':'KakaoAK '+os.environ['KAKAO_REST_API_KEY']}
|
||||
def geocode(q):
|
||||
for ep,name in [('address','address_name'),('keyword','place_name')]:
|
||||
url=f'https://dapi.kakao.com/v2/local/search/{ep}.json?query='+urllib.parse.quote(q)
|
||||
req=urllib.request.Request(url,headers=H)
|
||||
with urllib.request.urlopen(req,timeout=10) as resp:
|
||||
d=json.loads(resp.read())
|
||||
if d.get('documents'):
|
||||
doc=d['documents'][0]
|
||||
return float(doc['x']), float(doc['y']), doc.get(name) or doc['address_name']
|
||||
return None
|
||||
```
|
||||
|
||||
지하철역명만 정확히 알 때는 ODsay `searchStation` 도 OK 하지만, 도어투도어 결과를 원하면 **실제 출발지/도착지 좌표**를 써야 첫/끝 도보 구간이 계산됨.
|
||||
|
||||
## Core call
|
||||
|
||||
```bash
|
||||
set -a; . ~/.config/k-skill/secrets.env; set +a
|
||||
KEY=$(python3 -c "import os,urllib.parse;print(urllib.parse.quote(os.environ['ODSAY_API_KEY'],safe=''))")
|
||||
curl -s "https://api.odsay.com/v1/api/searchPubTransPathT?apiKey=${KEY}&SX=${SX}&SY=${SY}&EX=${EX}&EY=${EY}&OPT=0&SearchPathType=${TYPE}"
|
||||
```
|
||||
|
||||
Parameters:
|
||||
- `SX,SY` 출발 경도/위도, `EX,EY` 도착 경도/위도 (WGS84)
|
||||
- `OPT`: `0` 추천순(기본), `4` 최소시간, `5` 최소환승
|
||||
- `SearchPathType`: `0` 지하철+버스, `1` 지하철만, `2` 버스만
|
||||
|
||||
## Response shape
|
||||
|
||||
`result.path[]` 배열, 각 path:
|
||||
- `pathType`: 1=지하철, 2=버스, 3=지하철+버스
|
||||
- `info.totalTime`(분), `info.payment`(원), `info.subwayTransitCount`, `info.busTransitCount`, `info.totalWalk`(m), `info.firstStartStation`, `info.lastEndStation`
|
||||
- `subPath[]`: 구간별. `trafficType` 1=지하철 2=버스 3=도보. 지하철이면 `lane[0].name`, `startName`, `endName`, `passStopList.stations[]`(경유역)
|
||||
|
||||
## Recommended output (door-to-door)
|
||||
|
||||
`subPath` 의 각 구간을 `trafficType` 별로 표시. 첫/끝 도보 구간은 출발지·도착지에서 역까지 실제 도보를 의미하므로 **반드시 포함**.
|
||||
|
||||
```
|
||||
🚇 범안로95번길 32 → SKT타워
|
||||
경로 1: 54분 · 1,950원 · 환승 2회 · 도보 688m
|
||||
🚶 도보 1분
|
||||
🚌 19번 부천범박힐스테이트 → 역곡역 (9분)
|
||||
🚶 도보 2분
|
||||
🚇 1호선 역곡 → 종각 (15정거장, 35분)
|
||||
🚶 도보 7분
|
||||
```
|
||||
|
||||
3개 이내 경로 비교 권장. `OPT=4`(최소시간) / `OPT=5`(최소환승) 옵션을 사용자가 선호 표시하면 그쪽으로 호출.
|
||||
|
||||
## Done when
|
||||
|
||||
- 출발지와 도착지가 geocoding 되었거나, 좌표/역명이 명확히 확인되었다.
|
||||
- ODsay 응답에서 1개 이상 경로가 정리되었다.
|
||||
- 각 경로의 총 소요시간, 요금, 환승 횟수, 총 도보 거리가 포함되었다.
|
||||
- 첫/끝 도보 구간이 포함된 door-to-door 요약을 보여줬다.
|
||||
- upstream API 키가 응답에 노출되지 않았다.
|
||||
|
||||
## Helpers
|
||||
|
||||
좌표 모르고 역명만 아는 경우 — `searchStation` 으로 변환:
|
||||
|
||||
```bash
|
||||
curl -s "https://api.odsay.com/v1/api/searchStation?apiKey=${KEY}&stationName=강남&CID=1000"
|
||||
```
|
||||
|
||||
`CID=1000` = 수도권. 결과 `result.station[].x,y` 가 좌표.
|
||||
|
||||
## Limits
|
||||
|
||||
- 묣료 일 5,000건. `searchPubTransPathT` + `searchStation` 호출이 합산되니 한 질문당 호출 최소화.
|
||||
- 응답에 `error` 키 있으면 즉시 사용자에게 표시(ApiKey/IP 문제 진단에 유용).
|
||||
- 한국 외 좌표는 지원 안 함.
|
||||
|
||||
## Failure modes
|
||||
|
||||
- ODsay `error` 응답: `msg` 필드를 그대로 사용자에게 표시하고, ApiKey 미등록 또는 IP 화이트리스트 누락 가능성을 안내한다.
|
||||
- Kakao geocoding 결과 없음: 주소/장소명을 다시 확인하거나 더 구체적인 표현을 요청한다.
|
||||
- 좌표는 있으나 ODsay 경로 없음: 대중교통 미개통 지역, 도보 가능 거리, 또는 해상/공항 구간일 수 있다. 사용자에게 확인한다.
|
||||
- quota 초과: 일일 5,000건 한도 도달 시 추가 호출을 중단하고 사용자에게 알린다.
|
||||
|
||||
## Don'ts
|
||||
|
||||
- 카카오맵/네이버지도 directions API로 대중교통 라우팅 시도하지 말 것 (둘 다 운전·도보만 공개).
|
||||
- 키를 절대 응답에 노출하지 말 것.
|
||||
Loading…
Add table
Add a link
Reference in a new issue