korean-stats-mcp 1.4.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +24 -7
  2. package/dist/api/client.d.ts +6 -1
  3. package/dist/api/client.d.ts.map +1 -1
  4. package/dist/api/client.js +52 -33
  5. package/dist/api/client.js.map +1 -1
  6. package/dist/config/index.d.ts.map +1 -1
  7. package/dist/config/index.js +4 -4
  8. package/dist/config/index.js.map +1 -1
  9. package/dist/data/districtFileMap.d.ts +65 -0
  10. package/dist/data/districtFileMap.d.ts.map +1 -0
  11. package/dist/data/districtFileMap.js +518 -0
  12. package/dist/data/districtFileMap.js.map +1 -0
  13. package/dist/server-http.js +4 -4
  14. package/dist/server.js +2 -2
  15. package/dist/server.js.map +1 -1
  16. package/dist/tools/fetchKosisExcel.d.ts +2 -2
  17. package/dist/tools/fetchKosisExcel.d.ts.map +1 -1
  18. package/dist/tools/fetchKosisExcel.js +29 -3
  19. package/dist/tools/fetchKosisExcel.js.map +1 -1
  20. package/dist/tools/quickStats.d.ts.map +1 -1
  21. package/dist/tools/quickStats.js +200 -0
  22. package/dist/tools/quickStats.js.map +1 -1
  23. package/dist/utils/districtKosisCodes.d.ts +33 -0
  24. package/dist/utils/districtKosisCodes.d.ts.map +1 -0
  25. package/dist/utils/districtKosisCodes.js +223 -0
  26. package/dist/utils/districtKosisCodes.js.map +1 -0
  27. package/dist/utils/regions.d.ts +2 -0
  28. package/dist/utils/regions.d.ts.map +1 -1
  29. package/dist/utils/regions.js +30 -1
  30. package/dist/utils/regions.js.map +1 -1
  31. package/package.json +2 -2
  32. package/dist/tools/getRecommendedStats.d.ts +0 -41
  33. package/dist/tools/getRecommendedStats.d.ts.map +0 -1
  34. package/dist/tools/getRecommendedStats.js +0 -251
  35. package/dist/tools/getRecommendedStats.js.map +0 -1
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  ---
12
12
 
13
- ## v1.4 — 자연어 약어·오타·공백 정규화 + 체인 도구
13
+ ## v1.6자치구·시군 230+ 정밀 라우팅 + 자연어 정규화 + 체인 도구
14
14
 
15
15
  **LLM이 통계청 수치를 학습 시점으로 답하는 문제를 끝낸다.** 매 질문마다 KOSIS 공식 DB를 직접 조회.
16
16
 
@@ -56,7 +56,7 @@
56
56
  "제주 인구" → 664,792명
57
57
  ```
58
58
 
59
- 자치구·시군 230+개도 인식합니다. KOSIS OpenAPI는 광역시도 단위까지만 지원하므로, 자치구 입력 **소속 광역시도로 자동 fallback** + 자치구 단위 정밀 조회 경로(`fetch_kosis_excel`) 안내가 함께 나옵니다. 동명 자치구(`중구`, `남구` 등)는 광역시 컨텍스트가 같이 있으면 정확히 disambiguate.
59
+ 전국 230+ 자치구·시군도 **정밀 라우팅**합니다. `광진구 인구`, `해운대구 고용률`, `수원시 사망률`처럼 자치구를 입력하면 KOSIS 자치구 단위 통계표(14종)로 직접 조회해 정확한 수치를 돌려줍니다 — 인구·출산·고령인구·의사수·아파트/전세가격·고용률·취업자·실업률·사망자수·사망률·혼인(건수·율)·이혼(건수·율). 자치구 통계연보(`.xlsx`) 있으면 그쪽을 우선 쓰고, 없으면 KOSIS OpenAPI 자치구 코드로 라우팅합니다. 매핑이 없거나 KOSIS가 자치구 데이터를 미수록한 경우에만 소속 광역시도로 fallback + 안내합니다. 동명 자치구(`중구`, `남구` 등)는 광역시 컨텍스트가 같이 있으면 정확히 disambiguate.
60
60
 
61
61
  ### 시계열 추세 + 자연어 기간 추출
62
62
 
@@ -141,7 +141,7 @@ Claude Desktop / Cursor / Windsurf 설정 파일에 추가.
141
141
 
142
142
  ### 방법 3: 로컬 설치 (오프라인 가능)
143
143
 
144
- **사전 준비:** [Node.js](https://nodejs.org) 20 이상.
144
+ **사전 준비:** [Node.js](https://nodejs.org) 20 이상 · [KOSIS OpenAPI 키](https://kosis.kr/openapi/) (무료 발급).
145
145
 
146
146
  ```bash
147
147
  git clone https://github.com/chrisryugj/korean-stats-mcp.git
@@ -150,14 +150,15 @@ pnpm install
150
150
  pnpm run build
151
151
  ```
152
152
 
153
- AI 앱 설정:
153
+ AI 앱 설정 (`KOSIS_API_KEY`에 발급받은 키 입력):
154
154
 
155
155
  ```json
156
156
  {
157
157
  "mcpServers": {
158
158
  "korean-stats": {
159
159
  "command": "node",
160
- "args": ["/absolute/path/korean-stats-mcp/dist/index.js"]
160
+ "args": ["/absolute/path/korean-stats-mcp/dist/index.js"],
161
+ "env": { "KOSIS_API_KEY": "발급받은_키" }
161
162
  }
162
163
  }
163
164
  }
@@ -221,13 +222,29 @@ GDP, 국내총생산, 경제성장률, GDP성장률, 물가, 소비자물가,
221
222
  ## 지역 라우팅
222
223
 
223
224
  - **17개 광역시도** — 서울, 부산, 대구, 인천, 광주, 대전, 울산, 세종, 경기, 강원, 충북, 충남, 전북, 전남, 경북, 경남, 제주 (풀네임·약칭 모두 인식)
224
- - **자치구·시군 230+**자동으로 소속 광역시도로 fallback + 자치구 단위 정밀 조회 경로 안내
225
+ - **자치구·시군 230+ 정밀 라우팅** 자치구 통계연보(`.xlsx`) 또는 KOSIS 자치구 단위 통계표(14종)로 직접 조회. 커버 분야: 인구·출산·고령인구·의사수·아파트/전세가격·고용률·취업자·실업률·사망자수·사망률·혼인·이혼
226
+ - **fallback** — 매핑이 없거나 KOSIS가 자치구 데이터를 미수록한 경우에만 소속 광역시도로 대체 + 안내
225
227
  - **동명 자치구 disambiguate** — `중구`, `남구`, `동구` 등은 광역시 컨텍스트가 같이 있으면 정확히 매칭
226
228
 
227
229
  ---
228
230
 
229
231
  ## 변경 이력
230
232
 
233
+ <details>
234
+ <summary>v1.6 — 자치구 고용·인구동태 정밀 라우팅 확장</summary>
235
+
236
+ **자치구 단위 OpenAPI 라우팅 14개 분야로 확장**
237
+ - 고용 — `DT_1ES3A03_A01S` (고용률·취업자, objL2 연령 코드)
238
+ - 실업 — `DT_1ES3A01S` (실업률·실업자·경제활동인구)
239
+ - 인구동태 — `INH_1B82A01`(사망자수) · `INH_1B80A18`(사망률) · `INH_1B83A35`(혼인건수) · `INH_1B85033`(이혼건수) · `INH_1B8000I_01`(조이혼율) · `INH_1B8000I_02`(조혼인율)
240
+ - `getDistrictKscdCodeFor` — UP_ITM_ID 없는 메타(고용 통계표) 대응: "서울 광진구" 결합형 / "수원시" 단일형 직접 인덱스 + 동명 시군(고성군) ambiguous 처리
241
+ - `DistrictOpenApiRoute` — `objL2`(보조 분류) · `districtObjLevel`/`extraObjL1`(자치구 코드 objLevel swap) 옵션 추가
242
+ - 통계연보(`.xlsx`) value 추출 실패 시 OpenAPI 라우팅으로 fall-through
243
+ - KOSIS 자치구 데이터 미수록(`-`) 시 광역 fallback로 degrade
244
+ - 시뮬레이션 108 케이스 100% 통과 (전국 자치구 정밀값)
245
+
246
+ </details>
247
+
231
248
  <details>
232
249
  <summary>v1.4 — 자연어 정규화 + 체인 도구 + 통폐합</summary>
233
250
 
@@ -279,7 +296,7 @@ GDP, 국내총생산, 경제성장률, GDP성장률, 물가, 소비자물가,
279
296
  ## 주요 특징
280
297
 
281
298
  - **91개 키워드 + 100+ 자연어 별칭** — 줄임말·률/율 오타·공백 변형 자동 정규화
282
- - **17개 시도 + 자치구·시군 230+**자치구는 광역시도로 자동 fallback + 정밀 조회 경로 안내
299
+ - **17개 시도 + 자치구·시군 230+ 정밀 라우팅** 자치구 통계연보(`.xlsx`) 또는 KOSIS 자치구 단위 통계표(14종)로 직접 조회, 미수록 시에만 광역 fallback
283
300
  - **체인 도구 3종** — 단일 지역 13지표 한장 브리핑, N지역×M지표 매트릭스(전국 17개 동시), 7개 정책 영역 시계열
284
301
  - **자연어 기간 추출** — "민선 4기", "임기 4년차", "작년 대비", "역대" 자동 환산
285
302
  - **장래추계 안내** — 노령화지수 등 추계 데이터는 `isProjection: true` + "추계" 명시 안내
@@ -15,7 +15,12 @@ export declare class KosisClient {
15
15
  private apiKey;
16
16
  constructor(apiKey?: string);
17
17
  /**
18
- * API 요청 실행
18
+ * API 요청 실행 (timeout 15s + 3회 재시도 + 지수 백오프)
19
+ *
20
+ * - Fly Singapore → KOSIS Korea cold path 일시 abort 대응
21
+ * - KOSIS 응답 에러(err/errMsg 필드)는 영구 실패 → 즉시 throw, retry 안 함
22
+ * - HTTP 4xx도 영구 실패 → 즉시 throw
23
+ * - 네트워크 오류·타임아웃·5xx만 retry (800ms / 1600ms 백오프)
19
24
  */
20
25
  private request;
21
26
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAIjB,MAAM,YAAY,CAAC;AAEpB,cAAM,aAAc,SAAQ,KAAK;IAEtB,IAAI,EAAE,MAAM;IAEZ,aAAa,CAAC,EAAE,KAAK;gBAFrB,IAAI,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACR,aAAa,CAAC,EAAE,KAAK,YAAA;CAK/B;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,CAAC,EAAE,MAAM;IAK3B;;OAEG;YACW,OAAO;IAyErB;;OAEG;IACG,iBAAiB,CACrB,IAAI,EAAE,MAAM,EACZ,YAAY,GAAE,MAAW,GACxB,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAWhC;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE;QAC9B,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAUjC;;;OAGG;IACG,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACvB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,GACA,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAW9B;;OAEG;IACG,oBAAoB,CACxB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IASpC;;;;;OAKG;IACG,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,QAAgB,GAClE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CAQrC;AAKD,wBAAgB,cAAc,IAAI,WAAW,CAK5C;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAIjB,MAAM,YAAY,CAAC;AAEpB,cAAM,aAAc,SAAQ,KAAK;IAEtB,IAAI,EAAE,MAAM;IAEZ,aAAa,CAAC,EAAE,KAAK;gBAFrB,IAAI,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACR,aAAa,CAAC,EAAE,KAAK,YAAA;CAK/B;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,CAAC,EAAE,MAAM;IAK3B;;;;;;;OAOG;YACW,OAAO;IAsFrB;;OAEG;IACG,iBAAiB,CACrB,IAAI,EAAE,MAAM,EACZ,YAAY,GAAE,MAAW,GACxB,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAWhC;;OAEG;IACG,iBAAiB,CAAC,MAAM,EAAE;QAC9B,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAUjC;;;OAGG;IACG,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACvB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,GACA,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAW9B;;OAEG;IACG,oBAAoB,CACxB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IASpC;;;;;OAKG;IACG,YAAY,CAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,QAAgB,GAClE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CAQrC;AAKD,wBAAgB,cAAc,IAAI,WAAW,CAK5C;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -23,10 +23,14 @@ export class KosisClient {
23
23
  this.apiKey = apiKey || config.kosis.apiKey;
24
24
  }
25
25
  /**
26
- * API 요청 실행
26
+ * API 요청 실행 (timeout 15s + 3회 재시도 + 지수 백오프)
27
+ *
28
+ * - Fly Singapore → KOSIS Korea cold path 일시 abort 대응
29
+ * - KOSIS 응답 에러(err/errMsg 필드)는 영구 실패 → 즉시 throw, retry 안 함
30
+ * - HTTP 4xx도 영구 실패 → 즉시 throw
31
+ * - 네트워크 오류·타임아웃·5xx만 retry (800ms / 1600ms 백오프)
27
32
  */
28
33
  async request(endpoint, params) {
29
- // undefined 값 제거 및 문자열 변환
30
34
  const cleanParams = {};
31
35
  for (const [key, value] of Object.entries(params)) {
32
36
  if (value !== undefined) {
@@ -38,42 +42,57 @@ export class KosisClient {
38
42
  cleanParams.jsonVD = 'Y';
39
43
  const url = new URL(this.baseUrl + endpoint);
40
44
  url.search = new URLSearchParams(cleanParams).toString();
41
- // 8초 타임아웃 (Vercel maxDuration 15초 내에 여유 확보)
42
- const controller = new AbortController();
43
- const timeoutId = setTimeout(() => controller.abort(), 8000);
44
- try {
45
- const response = await fetch(url.toString(), {
46
- signal: controller.signal,
47
- });
48
- if (!response.ok) {
49
- throw new KosisApiError('HTTP_ERROR', `HTTP ${response.status}: ${response.statusText}`);
50
- }
51
- const data = await response.json();
52
- // 에러 응답 처리
53
- if (data.err || data.errMsg) {
54
- throw new KosisApiError(data.err || 'API_ERROR', data.errMsg || '알 수 없는 API 오류');
55
- }
56
- // 결과가 배열이 아닌 경우 빈 배열 반환
57
- if (!Array.isArray(data)) {
58
- if (data.result && Array.isArray(data.result)) {
59
- return data.result;
45
+ const requestUrl = url.toString();
46
+ const TIMEOUT_MS = 15000;
47
+ const MAX_ATTEMPTS = 3;
48
+ for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
49
+ const controller = new AbortController();
50
+ const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
51
+ let isRetryable = false;
52
+ try {
53
+ const response = await fetch(requestUrl, {
54
+ signal: controller.signal,
55
+ });
56
+ if (!response.ok) {
57
+ // 5xx는 일시적 retry, 4xx는 영구 실패
58
+ isRetryable = response.status >= 500;
59
+ throw new KosisApiError('HTTP_ERROR', `HTTP ${response.status}: ${response.statusText}`);
60
+ }
61
+ const data = (await response.json());
62
+ // KOSIS 응답 에러 — 영구 실패
63
+ if (data.err || data.errMsg) {
64
+ throw new KosisApiError(data.err || 'API_ERROR', data.errMsg || '알 수 없는 API 오류');
65
+ }
66
+ if (!Array.isArray(data)) {
67
+ if (data.result && Array.isArray(data.result)) {
68
+ return data.result;
69
+ }
70
+ return [];
60
71
  }
61
- return [];
72
+ return data;
62
73
  }
63
- return data;
64
- }
65
- catch (error) {
66
- if (error instanceof KosisApiError) {
67
- throw error;
74
+ catch (error) {
75
+ // KOSIS 응답 에러는 즉시 throw (retry 무의미)
76
+ if (error instanceof KosisApiError && !isRetryable) {
77
+ throw error;
78
+ }
79
+ // 네트워크/timeout/5xx — retry 가능
80
+ if (attempt === MAX_ATTEMPTS - 1) {
81
+ if (error instanceof DOMException && error.name === 'AbortError') {
82
+ throw new KosisApiError('TIMEOUT', `KOSIS API 응답 시간 초과 (${TIMEOUT_MS / 1000}초, ${MAX_ATTEMPTS}회 시도). 잠시 후 다시 시도해주세요.`);
83
+ }
84
+ if (error instanceof KosisApiError)
85
+ throw error;
86
+ throw new KosisApiError('NETWORK_ERROR', '네트워크 오류가 발생했습니다.', error);
87
+ }
88
+ await new Promise((r) => setTimeout(r, 800 * (attempt + 1)));
68
89
  }
69
- if (error instanceof DOMException && error.name === 'AbortError') {
70
- throw new KosisApiError('TIMEOUT', 'KOSIS API 응답 시간 초과 (8초). 잠시 후 다시 시도해주세요.');
90
+ finally {
91
+ clearTimeout(timeoutId);
71
92
  }
72
- throw new KosisApiError('NETWORK_ERROR', '네트워크 오류가 발생했습니다.', error);
73
- }
74
- finally {
75
- clearTimeout(timeoutId);
76
93
  }
94
+ // 도달 불가 (위 loop에서 모두 return 또는 throw)
95
+ throw new KosisApiError('UNEXPECTED', '요청 처리 중 예기치 못한 종료');
77
96
  }
78
97
  /**
79
98
  * 통계목록 조회
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAU5C,MAAM,aAAc,SAAQ,KAAK;IAEtB;IAEA;IAHT,YACS,IAAY,EACnB,OAAe,EACR,aAAqB;QAE5B,KAAK,CAAC,OAAO,CAAC,CAAC;QAJR,SAAI,GAAJ,IAAI,CAAQ;QAEZ,kBAAa,GAAb,aAAa,CAAQ;QAG5B,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,WAAW;IACd,OAAO,CAAS;IAChB,MAAM,CAAS;IAEvB,YAAY,MAAe;QACzB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;QACpC,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;IAC9C,CAAC;IAED;;;;;;;OAOG;IACK,KAAK,CAAC,OAAO,CACnB,QAAgB,EAChB,MAAmD;QAEnD,MAAM,WAAW,GAA2B,EAAE,CAAC;QAC/C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,WAAW,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;QACD,WAAW,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QACjC,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC;QAC5B,WAAW,CAAC,MAAM,GAAG,GAAG,CAAC;QAEzB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,CAAC;QAC7C,GAAG,CAAC,MAAM,GAAG,IAAI,eAAe,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC;QACzD,MAAM,UAAU,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;QAElC,MAAM,UAAU,GAAG,KAAK,CAAC;QACzB,MAAM,YAAY,GAAG,CAAC,CAAC;QAEvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,YAAY,EAAE,OAAO,EAAE,EAAE,CAAC;YACxD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,UAAU,CAAC,CAAC;YACnE,IAAI,WAAW,GAAG,KAAK,CAAC;YACxB,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,UAAU,EAAE;oBACvC,MAAM,EAAE,UAAU,CAAC,MAAM;iBAC1B,CAAC,CAAC;gBAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;oBACjB,+BAA+B;oBAC/B,WAAW,GAAG,QAAQ,CAAC,MAAM,IAAI,GAAG,CAAC;oBACrC,MAAM,IAAI,aAAa,CACrB,YAAY,EACZ,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAClD,CAAC;gBACJ,CAAC;gBAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA4B,CAAC;gBAEhE,sBAAsB;gBACtB,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;oBAC5B,MAAM,IAAI,aAAa,CACpB,IAAI,CAAC,GAAc,IAAI,WAAW,EAClC,IAAI,CAAC,MAAiB,IAAI,eAAe,CAC3C,CAAC;gBACJ,CAAC;gBAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;oBACzB,IAAI,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC9C,OAAO,IAAI,CAAC,MAAa,CAAC;oBAC5B,CAAC;oBACD,OAAO,EAAE,CAAC;gBACZ,CAAC;gBAED,OAAO,IAAW,CAAC;YACrB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,oCAAoC;gBACpC,IAAI,KAAK,YAAY,aAAa,IAAI,CAAC,WAAW,EAAE,CAAC;oBACnD,MAAM,KAAK,CAAC;gBACd,CAAC;gBACD,8BAA8B;gBAC9B,IAAI,OAAO,KAAK,YAAY,GAAG,CAAC,EAAE,CAAC;oBACjC,IAAI,KAAK,YAAY,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;wBACjE,MAAM,IAAI,aAAa,CACrB,SAAS,EACT,uBAAuB,UAAU,GAAG,IAAI,MAAM,YAAY,wBAAwB,CACnF,CAAC;oBACJ,CAAC;oBACD,IAAI,KAAK,YAAY,aAAa;wBAAE,MAAM,KAAK,CAAC;oBAChD,MAAM,IAAI,aAAa,CACrB,eAAe,EACf,kBAAkB,EAClB,KAAc,CACf,CAAC;gBACJ,CAAC;gBACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/D,CAAC;oBAAS,CAAC;gBACT,YAAY,CAAC,SAAS,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QACD,sCAAsC;QACtC,MAAM,IAAI,aAAa,CAAC,YAAY,EAAE,mBAAmB,CAAC,CAAC;IAC7D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CACrB,IAAY,EACZ,eAAuB,EAAE;QAEzB,OAAO,IAAI,CAAC,OAAO,CACjB,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,cAAc,EACrC;YACE,MAAM,EAAE,SAAS;YACjB,IAAI;YACJ,YAAY;SACb,CACF,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAC,MAYvB;QACC,OAAO,IAAI,CAAC,OAAO,CACjB,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,aAAa,EACpC;YACE,MAAM,EAAE,SAAS;YACjB,GAAG,MAAM;SACV,CACF,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,gBAAgB,CACpB,QAAgB,EAChB,OAKC;QAED,OAAO,IAAI,CAAC,OAAO,CACjB,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,gBAAgB,EACvC;YACE,MAAM,EAAE,SAAS;YACjB,QAAQ;YACR,GAAG,OAAO;SACX,CACF,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,oBAAoB,CACxB,KAAa,EACb,KAAa;QAEb,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,YAAY,EAAE;YACvD,MAAM,EAAE,SAAS;YACjB,IAAI,EAAE,KAAK;YACX,KAAK;YACL,KAAK;SACN,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,YAAY,CAChB,KAAa,EACb,KAAa,EACb,WAA8D,KAAK;QAEnE,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,cAAc,EAAE;YACzD,MAAM,EAAE,SAAS;YACjB,IAAI,EAAE,QAAQ;YACd,KAAK;YACL,KAAK;SACN,CAAC,CAAC;IACL,CAAC;CACF;AAED,WAAW;AACX,IAAI,cAAc,GAAuB,IAAI,CAAC;AAE9C,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,cAAc,GAAG,IAAI,WAAW,EAAE,CAAC;IACrC,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAKvB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiDT,CAAC;AAGX,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,MAAM,CAAC,SAAS,CAAC;AACrD,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,MAAM,CAAC,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAEvB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiDT,CAAC;AAGX,wBAAgB,cAAc,IAAI,IAAI,CAMrC;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,MAAM,CAAC,SAAS,CAAC;AACrD,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,MAAM,CAAC,WAAW,CAAC"}
@@ -1,10 +1,8 @@
1
1
  import 'dotenv/config';
2
- // 우선순위: 환경변수 KOSIS_API_KEY > 내장 키 (배포 환경 친화)
3
- const DEFAULT_KOSIS_KEY = 'YThiNDdhYjYyMWZlMDA5NWI5NGI0Y2E0OWRiNjZiYTY=';
4
2
  export const config = {
5
3
  // KOSIS API 설정
6
4
  kosis: {
7
- apiKey: process.env.KOSIS_API_KEY || DEFAULT_KOSIS_KEY,
5
+ apiKey: process.env.KOSIS_API_KEY || '',
8
6
  baseUrl: 'https://kosis.kr/openapi',
9
7
  endpoints: {
10
8
  statisticsList: '/statisticsList.do',
@@ -49,6 +47,8 @@ export const config = {
49
47
  };
50
48
  // 설정 유효성 검사
51
49
  export function validateConfig() {
52
- // 기본 API 키가 내장되어 있어 별도 검사 불필요
50
+ if (!config.kosis.apiKey) {
51
+ throw new Error('KOSIS_API_KEY 환경변수가 설정되지 않았습니다. https://kosis.kr/openapi/ 에서 무료 발급 후 .env 또는 환경변수로 지정하세요.');
52
+ }
53
53
  }
54
54
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAEvB,6CAA6C;AAC7C,MAAM,iBAAiB,GAAG,8CAA8C,CAAC;AAEzE,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,eAAe;IACf,KAAK,EAAE;QACL,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,iBAAiB;QACtD,OAAO,EAAE,0BAA0B;QACnC,SAAS,EAAE;YACT,cAAc,EAAE,oBAAoB;YACpC,cAAc,EAAE,oBAAoB;YACpC,aAAa,EAAE,mCAAmC;YAClD,gBAAgB,EAAE,sBAAsB;YACxC,YAAY,EAAE,kBAAkB;SACjC;KACF;IAED,QAAQ;IACR,KAAK,EAAE;QACL,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,GAAG,EAAE,EAAE,CAAC;QAC1D,OAAO,EAAE,IAAI;KACd;IAED,QAAQ;IACR,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;IAEzC,qBAAqB;IACrB,SAAS,EAAE;QACT,SAAS,EAAE,UAAU;QACrB,SAAS,EAAE,UAAU;QACrB,WAAW,EAAE,aAAa;QAC1B,WAAW,EAAE,aAAa;QAC1B,eAAe,EAAE,mBAAmB;QACpC,eAAe,EAAE,UAAU;QAC3B,aAAa,EAAE,QAAQ;QACvB,SAAS,EAAE,MAAM;QACjB,SAAS,EAAE,MAAM;QACjB,YAAY,EAAE,OAAO;QACrB,YAAY,EAAE,OAAO;QACrB,SAAS,EAAE,UAAU;KACb;IAEV,QAAQ;IACR,WAAW,EAAE;QACX,CAAC,EAAE,GAAG;QACN,CAAC,EAAE,GAAG;QACN,CAAC,EAAE,IAAI;QACP,CAAC,EAAE,IAAI;QACP,CAAC,EAAE,GAAG;QACN,CAAC,EAAE,YAAY;QACf,EAAE,EAAE,KAAK;KACD;CACF,CAAC;AAEX,YAAY;AACZ,MAAM,UAAU,cAAc;IAC5B,8BAA8B;AAChC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAEvB,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,eAAe;IACf,KAAK,EAAE;QACL,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE;QACvC,OAAO,EAAE,0BAA0B;QACnC,SAAS,EAAE;YACT,cAAc,EAAE,oBAAoB;YACpC,cAAc,EAAE,oBAAoB;YACpC,aAAa,EAAE,mCAAmC;YAClD,gBAAgB,EAAE,sBAAsB;YACxC,YAAY,EAAE,kBAAkB;SACjC;KACF;IAED,QAAQ;IACR,KAAK,EAAE;QACL,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,GAAG,EAAE,EAAE,CAAC;QAC1D,OAAO,EAAE,IAAI;KACd;IAED,QAAQ;IACR,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;IAEzC,qBAAqB;IACrB,SAAS,EAAE;QACT,SAAS,EAAE,UAAU;QACrB,SAAS,EAAE,UAAU;QACrB,WAAW,EAAE,aAAa;QAC1B,WAAW,EAAE,aAAa;QAC1B,eAAe,EAAE,mBAAmB;QACpC,eAAe,EAAE,UAAU;QAC3B,aAAa,EAAE,QAAQ;QACvB,SAAS,EAAE,MAAM;QACjB,SAAS,EAAE,MAAM;QACjB,YAAY,EAAE,OAAO;QACrB,YAAY,EAAE,OAAO;QACrB,SAAS,EAAE,UAAU;KACb;IAEV,QAAQ;IACR,WAAW,EAAE;QACX,CAAC,EAAE,GAAG;QACN,CAAC,EAAE,GAAG;QACN,CAAC,EAAE,IAAI;QACP,CAAC,EAAE,IAAI;QACP,CAAC,EAAE,GAAG;QACN,CAAC,EAAE,YAAY;QACf,EAAE,EAAE,KAAK;KACD;CACF,CAAC;AAEX,YAAY;AACZ,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,2FAA2F,CAC5F,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * 자치구 통계연보 파일 매핑 (KOSIS file 통계표)
3
+ *
4
+ * 자치구청 발행 통계연보(DT_<orgId>001_FILE<year>)는 14개 분야 .xlsx 파일로 구성.
5
+ * 정식 키워드(QUICK_STATS_PARAMS의 키 또는 KEYWORD_ALIASES 정규화 결과) →
6
+ * 해당 분야 file_sn(1~14) 매핑.
7
+ *
8
+ * 광진구 기준 14개 파일 구조:
9
+ * 1: Ⅱ.토지/기후 · 2: Ⅲ.인구 · 3: Ⅳ.노동/사업체 · 4: Ⅴ.농림/제조
10
+ * 5: Ⅵ.가스/상하수도 · 6: Ⅶ.유통/금융/무역수지 · 7: Ⅷ.주택/건설
11
+ * 8: Ⅸ.교통/관광 · 9: Ⅹ.보건 · 10: XI.사회보장 · 11: XII.환경
12
+ * 12: XIII.교육/문화 · 13: XIV.재정 · 14: XV.공공행정/사법
13
+ *
14
+ * P0 범위: 인구·노동·주거·보건 4분야만 매핑. 나머지는 P2에서 자치구별 검증 후 확장.
15
+ */
16
+ /**
17
+ * 자치구 단위 KOSIS OpenAPI 라우팅 매핑 (키워드 → 테이블·항목 코드)
18
+ *
19
+ * fetchKosisExcel(.xlsx 자치구 통계연보)이 미제공/PDF인 자치구에서도 자치구 정밀값을 보장.
20
+ * objL1은 런타임에 `getDistrictKscdCodeFor(orgId, tblId, districtName)` 으로 동적 lookup.
21
+ *
22
+ * 정확도 — KOSIS getMeta로 자치구 OBJ_ID=A 자치구별 ITM_ID 추출 후 호출. 라이브 검증 완료:
23
+ * - DT_1B040A3 광진구(11215) → 331,029명 ✓
24
+ * - DT_1B81A23 합계출산율 — 자치구별 코드 보유
25
+ */
26
+ export interface DistrictOpenApiRoute {
27
+ orgId: string;
28
+ tblId: string;
29
+ itmId: string;
30
+ prdSe: 'Y' | 'Q' | 'M';
31
+ /** 자연어 응답 description (예: '주민등록 총인구', '합계출산율') */
32
+ description: string;
33
+ /** 단위 (예: '명', '%') — 응답에서 자동 부착 */
34
+ unit: string;
35
+ /** 자치구 객체 OBJ_ID (KOSIS 테이블마다 다름: 'A'/'SGG'/'region'/'C1'/'S' 등). 'auto'면 후보 순회 */
36
+ objId?: string;
37
+ /** 보조 분류 코드 (예: DT_1ES3A03_A01S 연령 YRE — '000'=계, '060'=15-64세) */
38
+ objL2?: string;
39
+ /**
40
+ * 자치구 코드가 들어가는 objLevel. 기본 1 — objL1=districtCode.
41
+ * 일부 KOSIS 테이블(예: INH_1B80A18 사망률 — OBJ_ID 순서 SBB/S)은 자치구가 objL2.
42
+ * 2로 지정하면 objL1=extraObjL1(고정값), objL2=districtCode.
43
+ */
44
+ districtObjLevel?: 1 | 2;
45
+ /** districtObjLevel=2일 때 objL1에 들어가는 고정값 (예: SBB=계=='0'). */
46
+ extraObjL1?: string;
47
+ /** 통계청 장래추계 데이터 — 미래연도 실측 아닌 추계 안내 */
48
+ isProjection?: boolean;
49
+ }
50
+ export declare const DISTRICT_OPENAPI_ROUTES: Record<string, DistrictOpenApiRoute>;
51
+ export declare const DISTRICT_KEYWORD_TO_FILESN: Record<string, number>;
52
+ /**
53
+ * markdown에서 키워드 관련 핵심 행과 추정 value/unit 추출
54
+ *
55
+ * - highlightLines: 키워드 매칭 행 + 인접 행 (최대 50줄, 표 헤더·단위 정보 포함)
56
+ * - value/unit: 첫 매칭 행에서 "숫자+단위" 1차 시도, 실패 시 콤마 큰 수 2차 시도
57
+ *
58
+ * 매칭 패턴 없거나 value 추출 실패 시 value=null. answer는 markdown만 노출로 degrade.
59
+ */
60
+ export declare function extractDistrictHighlight(markdown: string, keyword: string): {
61
+ value: string | null;
62
+ unit: string | null;
63
+ highlightLines: string[];
64
+ };
65
+ //# sourceMappingURL=districtFileMap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"districtFileMap.d.ts","sourceRoot":"","sources":["../../src/data/districtFileMap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IACvB,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACzB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAoExE,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAgE7D,CAAC;AA0VF;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd;IACD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,CA8DA"}