mirror of
https://github.com/NomaDamas/k-skill.git
synced 2026-06-24 02:04:11 +00:00
fix(startup-support): remove fabricated detail data
This commit is contained in:
parent
9b2e0957f2
commit
cff6b29ff9
7 changed files with 165 additions and 199 deletions
|
|
@ -85,7 +85,7 @@ Claude Code, Codex, OpenCode, OpenClaw/ClawHub 등 각종 코딩 에이전트
|
|||
| ~~근처 블루리본 맛집~~ ⚠️ 지원 중단 | ~~`blue-ribbon-nearby`~~ | ~~현재 위치 기준 근처 블루리본 선정 맛집 조회~~ | ~~불필요~~ | ~~[근처 블루리본 맛집 가이드](docs/features/blue-ribbon-nearby.md)~~ |
|
||||
| 근처 술집 조회 | `kakao-bar-nearby` | 현재 위치 기준 영업 상태·메뉴·좌석·전화번호가 포함된 근처 술집 조회 | 불필요 | [근처 술집 조회 가이드](docs/features/kakao-bar-nearby.md) |
|
||||
| 우편번호 검색 | `zipcode-search` | 주소 키워드로 우편번호 + 공식 영문주소 조회 | 불필요 | [우편번호 검색 가이드](docs/features/zipcode-search.md) |
|
||||
| startup-support | Search Korean government startup support programs, grants, and subsidies for startups, SMEs, and entrepreneurs. Use when users ask about 창업 지원, 스타트업 지원금, 중소기업 지원, 정부 지원사업. | No login | [docs/features/startup-support.md](https://github.com/k-skill/k-skill/blob/main/docs/features/startup-support.md) |
|
||||
| 창업 지원사업 조회 | `startup-support` | 정부·지자체 스타트업 지원사업 목록 조회 (상세 조회는 원본 공고 링크로 확인) | 불필요 | [창업 지원사업 조회 가이드](docs/features/startup-support.md) |
|
||||
| 다이소 상품 조회 | `daiso-product-search` | 다이소 매장별 상품 픽업 가능 여부 확인 (정확한 매장별 재고 수량은 다이소몰 보안 정책으로 2026-05-05 부터 차단됨) | 불필요 | [다이소 상품 조회 가이드](docs/features/daiso-product-search.md) |
|
||||
| 강남언니 병원 조회 | `gangnamunni-clinic-search` | 강남언니 공개 검색 페이지에서 성형외과·피부과 병원 후보, 평점, 리뷰 수, 지원 언어, 공개 링크 조회 | 불필요 | [강남언니 병원 조회 가이드](docs/features/gangnamunni-clinic-search.md) |
|
||||
| 마켓컬리 상품 조회 | `market-kurly-search` | 마켓컬리 상품 검색, 현재 가격, 할인 여부, 품절 여부 조회 | 불필요 | [마켓컬리 상품 조회 가이드](docs/features/market-kurly-search.md) |
|
||||
|
|
|
|||
|
|
@ -43,10 +43,7 @@
|
|||
|
||||
#### k-skill-proxy 라우트
|
||||
|
||||
- `GET /v1/startup-support/list`: 지원사업 목록 조회
|
||||
- `GET /v1/startup-support/detail/:program_id`: 특정 지원사업 상세 정보
|
||||
- `GET /v1/startup-support/region/:region`: 특정 지역 지원사업 조회
|
||||
- `GET /v1/startup-support/deadline`: 임박 마감 지원사업
|
||||
공공데이터포털 K-Startup OpenAPI는 별도 `kstartup-search` 스킬과 `k-skill-proxy`의 `/v1/kstartup/*` 라우트가 담당합니다. `startup-support` helper는 지역별 공개 API 목록을 조회하고, 상세 정보는 결과의 공식 `url` 로 확인합니다.
|
||||
|
||||
#### Python 스크립트
|
||||
|
||||
|
|
@ -63,8 +60,7 @@ keyword_programs = search_startup_support(keyword='청년')
|
|||
# 마감 임박 검색
|
||||
deadline_programs = search_startup_support(deadline_only=True)
|
||||
|
||||
# 상세 정보 조회
|
||||
detail = get_startup_program_detail('test_001')
|
||||
# 상세 정보는 목록 결과의 공식 url로 확인
|
||||
```
|
||||
|
||||
## 데이터 소스
|
||||
|
|
@ -72,7 +68,7 @@ detail = get_startup_program_detail('test_001')
|
|||
### 1. 공공데이터포털
|
||||
- **기관**: 중소벤처기업부
|
||||
- **API**: 스타트업 지원사업 정보
|
||||
- **인증**: API 키 필요 (DATA_GO_KR_API_KEY)
|
||||
- **인증**: hosted/self-host proxy 운영 서버에서 API 키 주입
|
||||
|
||||
### 2. 지자체별 사이트
|
||||
- **서울시**: https://seoulstartup.go.kr
|
||||
|
|
|
|||
|
|
@ -428,9 +428,7 @@ node scripts/korean_character_count.js --text $'첫 줄\n둘째 줄🙂' --profi
|
|||
startup-support 스킬은 다음과 같은 환경이 필요합니다:
|
||||
|
||||
#### 환경 변수
|
||||
```bash
|
||||
export DATA_GO_KR_API_KEY="your_api_key_here"
|
||||
```
|
||||
기본 사용자는 별도 API 키가 필요 없습니다. `DATA_GO_KR_API_KEY` 는 hosted/self-host `k-skill-proxy` 운영자가 서버에 설정하는 값입니다.
|
||||
|
||||
#### 의존성
|
||||
- Python 3.7+
|
||||
|
|
|
|||
|
|
@ -89,10 +89,9 @@ KSKILL_PROXY_BASE_URL=
|
|||
### startup-support
|
||||
|
||||
#### API 키 관리
|
||||
- **환경 변수**: `DATA_GO_KR_API_KEY`
|
||||
- **용도**: 공공데이터포털 API 인증
|
||||
- **보안**: 절대 코드에 하드코딩하지 않음
|
||||
- **관리**: 환경 변수 또는 시크릿 매니저를 통해 관리
|
||||
- 기본 사용자는 `DATA_GO_KR_API_KEY` 를 설정하지 않습니다.
|
||||
- `DATA_GO_KR_API_KEY` 는 hosted/self-host `k-skill-proxy` 운영자가 서버에 설정하는 upstream 키입니다.
|
||||
- 로컬에서 직접 공공데이터포털 API를 호출하는 실험 경로에서만 사용자 환경에 임시로 둘 수 있습니다.
|
||||
|
||||
#### 데이터 보안
|
||||
- **데이터 소스**: 공공기관 공식 API만 사용
|
||||
|
|
|
|||
|
|
@ -65,12 +65,7 @@ metadata:
|
|||
|
||||
### Proxy Integration
|
||||
|
||||
API 요청은 `k-skill-proxy`의 `/v1/startup-support/*` 라우트로 중계되며, 다음과 같은 엔드포인트를 사용:
|
||||
|
||||
- `/v1/startup-support/list` - 지원사업 목록 조회
|
||||
- `/v1/startup-support/detail/<program_id>` - 특정 지원사업 상세 정보
|
||||
- `/v1/startup-support/region/<region>` - 특정 지역 지원사업 조회
|
||||
- `/v1/startup-support/deadline` - 임박 마감 지원사업
|
||||
공공데이터포털 K-Startup OpenAPI는 `kstartup-search` 스킬과 `k-skill-proxy`의 `/v1/kstartup/*` 라우트가 담당한다. 이 스킬의 helper는 지역별 공개 API 목록을 조회하고, 상세 정보는 결과의 공식 `url` 로 확인한다.
|
||||
|
||||
## Output format
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ class StartupSupportAPI:
|
|||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
def search_programs(self, region: str = '전국', keyword: str = None,
|
||||
support_type: str = None, deadline_only: bool = False) -> List[Dict]:
|
||||
def search_programs(self, region: str = '전국', keyword: Optional[str] = None,
|
||||
support_type: Optional[str] = None, deadline_only: bool = False) -> List[Dict]:
|
||||
"""
|
||||
지원사업 검색
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ class StartupSupportAPI:
|
|||
|
||||
return programs
|
||||
|
||||
def _search_data_go_kr(self, region: str, keyword: str, support_type: str) -> List[Dict]:
|
||||
def _search_data_go_kr(self, region: str, keyword: Optional[str], support_type: Optional[str]) -> List[Dict]:
|
||||
"""공공데이터포털 API로 검색"""
|
||||
programs = []
|
||||
|
||||
|
|
@ -105,7 +105,7 @@ class StartupSupportAPI:
|
|||
|
||||
return programs
|
||||
|
||||
def _search_by_region(self, region: str, keyword: str, support_type: str) -> List[Dict]:
|
||||
def _search_by_region(self, region: str, keyword: Optional[str], support_type: Optional[str]) -> List[Dict]:
|
||||
"""지자체별 API로 검색"""
|
||||
programs = []
|
||||
|
||||
|
|
@ -133,9 +133,11 @@ class StartupSupportAPI:
|
|||
}
|
||||
}
|
||||
|
||||
# 해당 지역 API 호출
|
||||
if region in region_apis:
|
||||
api_info = region_apis[region]
|
||||
target_regions = list(region_apis) if region == '전국' else [region]
|
||||
for target_region in target_regions:
|
||||
if target_region not in region_apis:
|
||||
continue
|
||||
api_info = region_apis[target_region]
|
||||
|
||||
try:
|
||||
params = {}
|
||||
|
|
@ -153,12 +155,12 @@ class StartupSupportAPI:
|
|||
# 실제 API 응답 구조에 따라 데이터 추출
|
||||
if 'programs' in data:
|
||||
for item in data['programs']:
|
||||
program = self._parse_program_from_region_api(item, region)
|
||||
program = self._parse_program_from_region_api(item, target_region)
|
||||
if program:
|
||||
programs.append(program)
|
||||
|
||||
except Exception as e:
|
||||
print(f"{region} API 오류: {e}")
|
||||
print(f"{target_region} API 오류: {e}")
|
||||
|
||||
return programs
|
||||
|
||||
|
|
@ -275,74 +277,14 @@ class StartupSupportAPI:
|
|||
|
||||
def _get_data_go_kr_detail(self, program_id: str) -> Optional[Dict]:
|
||||
"""공공데이터포털 상세 정보 조회"""
|
||||
# 실 구현에서는 program_id를 사용해 상세 API 호출
|
||||
return {
|
||||
'id': program_id,
|
||||
'title': '상세 정보 조회 예시',
|
||||
'organization': '중소벤처기업부',
|
||||
'region': '전국',
|
||||
'support_type': '보조금',
|
||||
'amount': '최대 1억원',
|
||||
'deadline': '2024-12-31',
|
||||
'target': '중소기업 창업자',
|
||||
'requirements': [
|
||||
'사업자등록증',
|
||||
'사업계획서',
|
||||
'재무제표',
|
||||
'창업자 신분증'
|
||||
],
|
||||
'application_process': [
|
||||
'온라인 신청서 작성',
|
||||
'서류 제출',
|
||||
'서류 심사',
|
||||
'현장 면접',
|
||||
'결공고'
|
||||
],
|
||||
'contact': {
|
||||
'phone': '02-1234-5678',
|
||||
'email': 'support@smbs.or.kr',
|
||||
'address': '서울시 강남구 테헤란로 123'
|
||||
},
|
||||
'url': 'https://www.data.go.kr/program/detail',
|
||||
'source': '공공데이터포털',
|
||||
'last_updated': datetime.now().strftime('%Y-%m-%d')
|
||||
}
|
||||
return None
|
||||
|
||||
def _get_region_detail(self, program_id: str) -> Optional[Dict]:
|
||||
"""지자체 상세 정보 조회"""
|
||||
# 실 구현에서는 program_id를 사용해 상세 API 호출
|
||||
return {
|
||||
'id': program_id,
|
||||
'title': '지자체 상세 정보 조회 예시',
|
||||
'organization': '서울시 창업진흥원',
|
||||
'region': '서울특별시',
|
||||
'support_type': '보조금',
|
||||
'amount': '최대 5천만원',
|
||||
'deadline': '2024-12-31',
|
||||
'target': '서울시 내 스타트업',
|
||||
'requirements': [
|
||||
'사업자등록증',
|
||||
'사업계획서',
|
||||
'재무제표'
|
||||
],
|
||||
'application_process': [
|
||||
'온라인 신청서 작성',
|
||||
'서류 제출',
|
||||
'서류 심사',
|
||||
'결공고'
|
||||
],
|
||||
'contact': {
|
||||
'phone': '02-1234-5678',
|
||||
'email': 'startup@seoul.go.kr',
|
||||
'address': '서울시 강남구 테헤란로 123'
|
||||
},
|
||||
'url': 'https://seoulstartup.go.kr/program/detail',
|
||||
'source': '서울시 창업진흥원',
|
||||
'last_updated': datetime.now().strftime('%Y-%m-%d')
|
||||
}
|
||||
return None
|
||||
|
||||
def search_startup_support(region: str = '전국', keyword: str = None,
|
||||
support_type: str = None, deadline_only: bool = False) -> List[Dict]:
|
||||
def search_startup_support(region: str = '전국', keyword: Optional[str] = None,
|
||||
support_type: Optional[str] = None, deadline_only: bool = False) -> List[Dict]:
|
||||
"""
|
||||
스타트업 지원사업 검색 함수
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from datetime import datetime, timedelta
|
|||
|
||||
# 현재 디렉토리에서 모듈 임포트
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from startup_support import search_startup_support, get_startup_program_detail
|
||||
from startup_support import search_startup_support, get_startup_program_detail, StartupSupportAPI
|
||||
|
||||
class TestStartupSupport(unittest.TestCase):
|
||||
"""스타트업 지원사업 API 테스트"""
|
||||
|
|
@ -64,6 +64,44 @@ class TestStartupSupport(unittest.TestCase):
|
|||
self.assertEqual(result[0]['title'], '경기도 MVP 지원사업')
|
||||
self.assertEqual(result[1]['title'], '서울시 청년 스타트업 창업 지원금')
|
||||
|
||||
@patch('startup_support.requests.get')
|
||||
def test_nationwide_search_aggregates_configured_regions_without_api_key(self, mock_get):
|
||||
payloads = {
|
||||
'https://seoulstartup.go.kr/api/program/list': {
|
||||
'programs': [{
|
||||
'id': 'seoul_1',
|
||||
'title': '서울 창업 지원',
|
||||
'deadline': '2026-06-03',
|
||||
}]
|
||||
},
|
||||
'https://g-startup.kr/api/support/list': {
|
||||
'programs': [{
|
||||
'id': 'gyeonggi_1',
|
||||
'title': '경기 창업 지원',
|
||||
'deadline': '2026-06-04',
|
||||
}]
|
||||
},
|
||||
}
|
||||
|
||||
def fake_get(url, **_):
|
||||
response = MagicMock()
|
||||
response.status_code = 200
|
||||
response.json.return_value = payloads.get(url, {'programs': []})
|
||||
return response
|
||||
|
||||
mock_get.side_effect = fake_get
|
||||
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
result = search_startup_support(region='전국')
|
||||
|
||||
titles = {program['title'] for program in result}
|
||||
self.assertIn('서울 창업 지원', titles)
|
||||
self.assertIn('경기 창업 지원', titles)
|
||||
|
||||
def test_builtin_detail_lookup_does_not_return_fabricated_sample_data(self):
|
||||
self.assertIsNone(get_startup_program_detail('data_gov_missing'))
|
||||
self.assertIsNone(get_startup_program_detail('서울_missing'))
|
||||
|
||||
@patch('startup_support.StartupSupportAPI._search_data_go_kr')
|
||||
@patch('startup_support.StartupSupportAPI._search_by_region')
|
||||
def test_search_programs_seoul_only(self, mock_region_search, mock_data_go_kr_search):
|
||||
|
|
@ -139,8 +177,6 @@ class TestStartupSupport(unittest.TestCase):
|
|||
|
||||
def test_parse_program_from_data_go_kr(self):
|
||||
"""공공데이터포털 데이터 파싱 테스트"""
|
||||
from startup_support import StartupSupportAPI
|
||||
|
||||
api = StartupSupportAPI()
|
||||
|
||||
# 테스트 데이터
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue