Skip to main content
Glama
commercial-area.ts5.68 kB
// 상권 분석 Tool // 카카오맵 API를 활용한 상권 분석 import { kakaoApi } from "../api/kakao-api.js"; import { SATURATION_LEVELS, DATA_SOURCES } from "../constants.js"; import type { ApiResult, CommercialAreaData } from "../types.js"; // 포화도 레벨 계산 function getSaturationLevel(score: number): string { if (score >= SATURATION_LEVELS.SATURATED.min) return SATURATION_LEVELS.SATURATED.label; if (score >= SATURATION_LEVELS.HIGH.min) return SATURATION_LEVELS.HIGH.label; if (score >= SATURATION_LEVELS.MEDIUM.min) return SATURATION_LEVELS.MEDIUM.label; return SATURATION_LEVELS.LOW.label; } // 상권 유형 추정 function estimateAreaType(categoryBreakdown: Record<string, number>): string { const total = Object.values(categoryBreakdown).reduce((a, b) => a + b, 0); if (total > 50) return "발달상권"; if (categoryBreakdown["음식점"] > 20) return "먹자골목"; if (categoryBreakdown["카페"] > 10) return "카페거리"; if (total < 20) return "골목상권"; return "일반상권"; } // 상권 특성 분석 function analyzeCharacteristics( categoryBreakdown: Record<string, number>, location: string ): string[] { const characteristics: string[] = []; const total = Object.values(categoryBreakdown).reduce((a, b) => a + b, 0); if (total > 40) characteristics.push("유동인구 많음"); if (categoryBreakdown["카페"] > 8) characteristics.push("카페 밀집지역"); if (categoryBreakdown["음식점"] > 15) characteristics.push("음식점 밀집지역"); if (categoryBreakdown["편의점"] > 3) characteristics.push("편의시설 양호"); // 지역명 기반 추정 if (location.includes("역")) characteristics.push("역세권"); if (location.includes("대학") || location.includes("학교")) characteristics.push("학생 상권"); if (characteristics.length === 0) { characteristics.push("조용한 주거지역"); } return characteristics; } // 추천 메시지 생성 function generateRecommendation( businessType: string, saturationScore: number, _sameCategoryCount: number ): string { if (saturationScore >= 80) { return `${businessType} 포화도가 ${saturationScore}%로 매우 높습니다. 차별화 전략이 필수이며, 인근 다른 지역도 검토해보세요.`; } if (saturationScore >= 60) { return `${businessType} 포화도가 ${saturationScore}%로 높은 편입니다. 경쟁이 있지만 차별화된 컨셉으로 진입 가능합니다.`; } if (saturationScore >= 40) { return `${businessType} 포화도가 ${saturationScore}%로 적정 수준입니다. 진입 여지가 있습니다.`; } return `${businessType} 포화도가 ${saturationScore}%로 낮습니다. 새로운 ${businessType} 창업에 좋은 입지입니다.`; } // 포화도 점수 계산 (업종별 기준) function calculateSaturationScore( businessType: string, sameCategoryCount: number, _totalStores: number ): number { // 업종별 적정 개수 기준 (반경 500m 기준) const optimalCounts: Record<string, number> = { 카페: 10, 음식점: 20, 편의점: 5, 미용실: 8, default: 10, }; const optimal = optimalCounts[businessType] || optimalCounts.default; const ratio = (sameCategoryCount / optimal) * 100; return Math.min(100, Math.round(ratio)); } export async function analyzeCommercialArea( location: string, businessType: string, radius: number = 500 ): Promise<ApiResult<CommercialAreaData>> { try { // 1. 위치 좌표 얻기 const coords = await kakaoApi.getCoordinates(location); if (!coords) { return { success: false, error: { code: "LOCATION_NOT_FOUND", message: `입력하신 위치를 찾을 수 없습니다: ${location}`, suggestion: "강남역, 홍대입구 등 구체적인 지명을 입력해주세요.", }, }; } // 2. 업종별 업체 수 조회 const categoryBreakdown = await kakaoApi.countByCategories( String(coords.lng), String(coords.lat), radius ); // 3. 해당 업종 업체 검색 const competitors = await kakaoApi.findCompetitors( businessType, location, radius, 15 ); const sameCategoryCount = competitors.length; // 4. 분석 결과 계산 const totalStores = Object.values(categoryBreakdown).reduce((a, b) => a + b, 0); const saturationScore = calculateSaturationScore(businessType, sameCategoryCount, totalStores); const areaType = estimateAreaType(categoryBreakdown); const characteristics = analyzeCharacteristics(categoryBreakdown, location); const recommendation = generateRecommendation(businessType, saturationScore, sameCategoryCount); return { success: true, data: { location: { name: location, address: location, coordinates: coords, }, areaType, characteristics, density: { totalStores, categoryBreakdown, sameCategoryCount, saturationLevel: getSaturationLevel(saturationScore), saturationScore, }, recommendation, }, meta: { source: DATA_SOURCES.kakaoLocal, timestamp: new Date().toISOString(), }, }; } catch (error) { console.error("상권 분석 실패:", error); return { success: false, error: { code: "ANALYSIS_FAILED", message: `상권 분석 중 오류가 발생했습니다: ${error instanceof Error ? error.message : "Unknown error"}`, suggestion: "잠시 후 다시 시도해주세요.", }, }; } }

Implementation Reference

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