Skip to main content
Glama
nearby-facilities.ts8.49 kB
// 주변 편의시설 조회 Tool // 카카오맵 API를 활용한 상권 주변 편의시설 분석 // 지하철역, 버스정류장, 은행, 주차장 등 창업에 필요한 시설 정보 제공 import { kakaoApi } from "../api/kakao-api.js"; import { DATA_SOURCES, DISCLAIMERS } from "../constants.js"; import type { ApiResult, Coordinates } from "../types.js"; // 편의시설 카테고리 코드 (카카오맵) const FACILITY_CATEGORIES = { 지하철역: "SW8", 버스정류장: "BS8", // 버스정류장은 키워드 검색 사용 은행: "BK9", 주차장: "PK6", 병원: "HP8", 약국: "PM9", 편의점: "CS2", 대형마트: "MT1", 학교: "SC4", 공공기관: "PO3", } as const; // 편의시설 타입 export interface NearbyFacility { name: string; category: string; address: string; distance: string; phone?: string; } // 편의시설 분석 결과 타입 export interface NearbyFacilitiesAnalysis { location: { name: string; coordinates: Coordinates; }; radius: number; facilities: { category: string; count: number; items: NearbyFacility[]; }[]; summary: { totalCount: number; accessibility: "우수" | "양호" | "보통" | "미흡"; highlights: string[]; }; insights: string[]; } // 접근성 점수 계산 function calculateAccessibilityScore(facilities: { category: string; count: number }[]): { score: number; level: "우수" | "양호" | "보통" | "미흡"; } { let score = 0; for (const facility of facilities) { switch (facility.category) { case "지하철역": score += facility.count > 0 ? 30 : 0; // 지하철 있으면 30점 break; case "버스정류장": score += Math.min(facility.count * 5, 15); // 최대 15점 break; case "주차장": score += Math.min(facility.count * 3, 10); // 최대 10점 break; case "은행": score += facility.count > 0 ? 10 : 0; break; case "편의점": score += Math.min(facility.count * 2, 10); break; case "병원": case "약국": score += facility.count > 0 ? 5 : 0; break; default: score += facility.count > 0 ? 3 : 0; } } let level: "우수" | "양호" | "보통" | "미흡"; if (score >= 60) level = "우수"; else if (score >= 40) level = "양호"; else if (score >= 20) level = "보통"; else level = "미흡"; return { score: Math.min(score, 100), level }; } // 인사이트 생성 function generateInsights( facilities: { category: string; count: number; items: NearbyFacility[] }[], accessibilityLevel: string ): string[] { const insights: string[] = []; const subway = facilities.find((f) => f.category === "지하철역"); const bus = facilities.find((f) => f.category === "버스정류장"); const parking = facilities.find((f) => f.category === "주차장"); const bank = facilities.find((f) => f.category === "은행"); const convenience = facilities.find((f) => f.category === "편의점"); // 교통 접근성 if (subway && subway.count > 0) { const nearestSubway = subway.items[0]; insights.push(`🚇 ${nearestSubway.name}이(가) ${nearestSubway.distance}에 있어 대중교통 접근성이 우수합니다.`); } else { insights.push("🚇 반경 내 지하철역이 없습니다. 버스 노선이나 주차 편의성을 확인하세요."); } if (bus && bus.count >= 3) { insights.push(`🚌 버스정류장 ${bus.count}개로 대중교통 이용이 편리합니다.`); } // 주차 if (parking && parking.count >= 2) { insights.push(`🅿️ 주차장 ${parking.count}개로 차량 이용 고객도 편리하게 방문 가능합니다.`); } else if (!parking || parking.count === 0) { insights.push("🅿️ 주변 주차장이 부족합니다. 주차 불편 시 고객 유입에 영향이 있을 수 있습니다."); } // 금융 if (bank && bank.count >= 2) { insights.push(`🏦 은행 ${bank.count}개로 금융 업무가 편리합니다.`); } // 생활 편의 if (convenience && convenience.count >= 3) { insights.push(`🏪 편의점 ${convenience.count}개로 생활 편의시설이 밀집해 있습니다.`); } // 종합 평가 if (accessibilityLevel === "우수") { insights.push("✅ 종합 접근성이 우수하여 고객 유입에 유리한 입지입니다."); } else if (accessibilityLevel === "미흡") { insights.push("⚠️ 편의시설이 부족합니다. 목적 방문형 업종이 아니라면 입지를 재검토하세요."); } return insights; } export async function analyzeNearbyFacilities( location: string, radius: number = 500, categories?: string[] ): Promise<ApiResult<NearbyFacilitiesAnalysis>> { try { // 1. 위치 좌표 얻기 const coords = await kakaoApi.getCoordinates(location); if (!coords) { return { success: false, error: { code: "LOCATION_NOT_FOUND", message: `입력하신 위치를 찾을 수 없습니다: ${location}`, suggestion: "강남역, 홍대입구 등 구체적인 지명을 입력해주세요.", }, }; } // 2. 조회할 카테고리 결정 const targetCategories = categories && categories.length > 0 ? categories.filter((c) => c in FACILITY_CATEGORIES) : Object.keys(FACILITY_CATEGORIES); // 3. 각 카테고리별 시설 검색 const facilitiesResults: { category: string; count: number; items: NearbyFacility[] }[] = []; for (const category of targetCategories) { const categoryCode = FACILITY_CATEGORIES[category as keyof typeof FACILITY_CATEGORIES]; try { let places; // 버스정류장은 키워드 검색 사용 if (category === "버스정류장") { places = await kakaoApi.searchByKeyword("버스정류장", { x: String(coords.lng), y: String(coords.lat), radius, size: 5, sort: "distance", }); } else { places = await kakaoApi.searchByCategory(categoryCode, String(coords.lng), String(coords.lat), { radius, size: 5, }); } const items: NearbyFacility[] = places.map((place) => ({ name: place.place_name, category, address: place.road_address_name || place.address_name, distance: place.distance ? `${place.distance}m` : "거리 정보 없음", phone: place.phone || undefined, })); facilitiesResults.push({ category, count: items.length, items, }); } catch { // 개별 카테고리 검색 실패 시 빈 결과로 처리 facilitiesResults.push({ category, count: 0, items: [], }); } } // 4. 접근성 점수 계산 const { score, level } = calculateAccessibilityScore(facilitiesResults); // 5. 하이라이트 생성 const highlights: string[] = []; for (const facility of facilitiesResults) { if (facility.count > 0 && facility.items[0]) { highlights.push(`${facility.category}: ${facility.items[0].name} (${facility.items[0].distance})`); } } // 6. 인사이트 생성 const insights = generateInsights(facilitiesResults, level); // 7. 총 개수 계산 const totalCount = facilitiesResults.reduce((sum, f) => sum + f.count, 0); return { success: true, data: { location: { name: location, coordinates: coords, }, radius, facilities: facilitiesResults, summary: { totalCount, accessibility: level, highlights: highlights.slice(0, 5), }, insights, }, meta: { source: DATA_SOURCES.kakaoLocal, timestamp: new Date().toISOString(), dataNote: `반경 ${radius}m 기준. 신뢰도: 높음 (카카오맵 실시간 API). 접근성 점수: ${score}점. ${DISCLAIMERS.GENERAL}`, }, }; } catch (error) { console.error("편의시설 분석 실패:", error); return { success: false, error: { code: "ANALYSIS_FAILED", message: `편의시설 분석 중 오류가 발생했습니다: ${error instanceof Error ? error.message : "Unknown error"}`, suggestion: "잠시 후 다시 시도해주세요.", }, }; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/re171113-byte/startup-helper-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server