kakaotalk-chat-analyzer 0.16.1 → 0.16.3

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.
package/README.md CHANGED
@@ -2,33 +2,30 @@
2
2
 
3
3
  # KakaoTalk Chat Analyzer
4
4
 
5
- ### 카카오톡 CSV 보내기 → 익명 집계 리포트선택적 임시 공유 · 한 번에 끝내는 CLI
5
+ ### 카카오톡 CSV 보내기 → 터미널 브라우저 리포트 링크
6
6
 
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-22c55e?style=flat-square)](./LICENSE)
8
8
  [![Node.js](https://img.shields.io/badge/node-%3E%3D22-3b82f6?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org/)
9
9
  [![GitHub Pages](https://img.shields.io/badge/docs-GitHub%20Pages-8b5cf6?style=flat-square&logo=github)](https://claudianus.github.io/kakaotalk-chat-analyzer/)
10
10
  [![npm · kcachat](https://img.shields.io/npm/v/kcachat?label=npm%20kcachat&color=cb3837&logo=npm&style=flat-square)](https://www.npmjs.com/package/kcachat)
11
- [![npm · 본체](https://img.shields.io/npm/v/kakaotalk-chat-analyzer?label=npm%20본체&color=cb3837&logo=npm&style=flat-square)](https://www.npmjs.com/package/kakaotalk-chat-analyzer)
12
11
 
13
- [**랜딩 (GitHub Pages)**](https://claudianus.github.io/kakaotalk-chat-analyzer/) · [**소스 코드**](https://github.com/claudianus/kakaotalk-chat-analyzer) · [**이슈**](https://github.com/claudianus/kakaotalk-chat-analyzer/issues)
14
-
15
- 카카오톡 **CSV 보내기** → 터미널 **한 줄** → 브라우저에서 읽는 Wrapped·차트 리포트 링크.
12
+ [**랜딩 (GitHub Pages)**](https://claudianus.github.io/kakaotalk-chat-analyzer/) · [**소스**](https://github.com/claudianus/kakaotalk-chat-analyzer) · [**이슈**](https://github.com/claudianus/kakaotalk-chat-analyzer/issues)
16
13
 
17
14
  ```bash
18
15
  npx kcachat@latest
19
16
  ```
20
17
 
21
- [Node.js 22+](https://nodejs.org/) · CSV 생략 `KCA_CSV_DIR` 기본 폴더(Win: `Documents\카카오톡 받은 파일`, macOS: Downloads) · `--local` ([빠른 시작](#빠른-시작))
18
+ [Node.js 22+](https://nodejs.org/) · 설치 없이 `npx` · CSV 경로 생략 가능 · [`--local`](#업로드-없이-내-pc에만)
22
19
 
23
20
  <table>
24
21
  <tr>
25
- <td align="center" width="33%"><strong>Wrapped</strong><br><img src="docs/assets/demo/wrapped.png" alt="Wrapped 요약과 활동 그리드" width="100%" /></td>
26
- <td align="center" width="33%"><strong>차트</strong><br><img src="docs/assets/demo/charts.png" alt="워드클라우드와 시간대 차트" width="100%" /></td>
27
- <td align="center" width="33%"><strong>키워드</strong><br><img src="docs/assets/demo/keywords.png" alt="키워드 순위 표" width="100%" /></td>
22
+ <td align="center" width="33%"><strong>Wrapped</strong><br><img src="docs/assets/demo/wrapped.png" alt="Wrapped 요약" width="100%" /></td>
23
+ <td align="center" width="33%"><strong>차트</strong><br><img src="docs/assets/demo/charts-viz.png" alt="차트" width="100%" /></td>
24
+ <td align="center" width="33%"><strong>키워드</strong><br><img src="docs/assets/demo/keywords.png" alt="키워드" width="100%" /></td>
28
25
  </tr>
29
26
  </table>
30
27
 
31
- <p><sub>미리보기는 테스트 fixture 리포트 캡처입니다. UI 변경 <code>npm run docs:capture-demo</code>로 갱신.</sub></p>
28
+ <p><sub><a href="https://claudianus.github.io/kakaotalk-chat-analyzer/#demo">리포트 미리보기 전체</a> (12장 · 탭하면 크게 보기)</sub></p>
32
29
 
33
30
  </div>
34
31
 
@@ -36,318 +33,219 @@ npx kcachat@latest
36
33
 
37
34
  ## 목차
38
35
 
39
- - [왜 이 프로젝트인가요?](#왜-이-프로젝트인가요)
40
- - [핵심 기능](#핵심-기능)
41
- - [대용량·속도](#대용량속도)
42
- - [리포트 UX](#리포트-ux)
43
- - [카카오톡에서 CSV 보내기](#카카오톡에서-csv-보내기)
44
- - [빠른 시작](#빠른-시작)
45
- - [생성되는 리포트](#생성되는-리포트)
46
- - [프라이버시 기본값](#프라이버시-기본값)
47
- - [아키텍처 한눈에](#아키텍처-한눈에)
48
- - [개발](#개발)
49
- - [문서 사이트 (GitHub Pages)](#문서-사이트-github-pages)
50
- - [기여하기](#기여하기)
36
+ **처음 쓰는 분**
51
37
 
52
- ---
38
+ - [3분 안에 시작하기](#3분-안에-시작하기)
39
+ - [리포트에서 볼 수 있는 것](#리포트에서-볼-수-있는-것)
40
+ - [개인정보·공유 전에](#개인정보공유-전에)
41
+ - [자주 묻는 질문](#자주-묻는-질문)
53
42
 
54
- ## 프로젝트인가요?
43
+ **더 쓰고 싶을 때**
55
44
 
56
- 카카오톡 대화를 **CSV로 보낸 뒤**, 팀·친구·커뮤니티에 **재미있는 통계**를 공유하고 싶을 때가 있습니다.
57
- 그런데 원문 그대로 올리기엔 **개인정보·민감 URL** 리스크가 큽니다.
45
+ - [옵션·고급](#옵션고급)
46
+ - [최근 업데이트](#최근-업데이트)
58
47
 
59
- **`kca`(KakaoTalk Chat Analyzer)**는 메시지 본문을 **리포트 파일에 저장하지 않고**, 집계 통계만 담은 **단일 `index.html`**을 생성합니다. 몇 개월·수십만 줄 규모도 **파일 전체를 RAM에 올리지 않는 스트리밍 집계**로 처리하고, 리포트는 **한글 프리미엄 UI**(채팅방 이름·히트맵·오전/오후 리듬·인사이트 카드)로 바로 읽을 수 있습니다. 기본은 참여자 **부분 마스킹**, 필요 시 **가입 없이** BrewPage 등에 올려 링크로 공유합니다.
48
+ **개발자**
60
49
 
61
- > 이 도구는 카카오 공식 제품이 아닙니다. 보낸 CSV 형식 변경에 따라 파싱이 깨질 수 있으니, 중요한 데이터는 항상 백업하세요.
50
+ - [개발·기여](#개발기여)
51
+ - [문서 사이트 (GitHub Pages)](#문서-사이트-github-pages)
62
52
 
63
53
  ---
64
54
 
65
- ## 핵심 기능
55
+ ## 3분 안에 시작하기
66
56
 
67
- | 영역 | 설명 |
68
- |------|------|
69
- | **인코딩** | UTF-8 BOM, UTF-8, CP949/EUC-KR 등 보내기 인코딩 자동 감지 |
70
- | **파싱** | `Date,User,Message` 헤더 기반 CSV + 멀티라인 메시지 처리 |
71
- | **리포트** | Wrapped·**ECharts**·**주제 맵**(c-TF-IDF)·**Kiwi+BM25** 키워드 120개·잔디·인사이트 등 **집계 전용** 시각화 |
72
- | **성능** | 줄 단위 스트림 파싱 · 단일 패스 집계 · 3MB+ Worker · 진행률 **기본 ON** (`--no-progress`로 끔) |
73
- | **배포** | BrewPage(기본) / TempFile / Cloudflare 등 **TTL 기반** 임시 호스팅 · iframe 공유 링크 안전 처리 |
74
- | **npx** | 짧은 별칭 **[`kcachat`](https://www.npmjs.com/package/kcachat)** 또는 본체 **`kakaotalk-chat-analyzer`** |
75
- | **프라이버시** | 원문 미포함, 참여자 **부분 마스킹 표시명**(기본), URL은 **도메인**만 집계 |
57
+ ### 1. 카카오톡에서 CSV 보내기
76
58
 
77
- ---
59
+ 1. PC 카카오톡에서 채팅방 열기
60
+ 2. **더보기(≡)** → **대화 보내기** → **CSV 보내기**
78
61
 
79
- ## 대용량·속도
62
+ 파일명은 보통 `KakaoTalk_Chat_…` 형태입니다. **원문이 들어 있는 파일**이므로 다른 사람에게 보내기 전에 내용을 확인하세요.
80
63
 
81
- 카카오 보내기 CSV는 **일반 표 CSV가 아니라** “날짜 + 이어지는 본문” 형식입니다. `kca`는 이 형식에 맞춘 **전용 스트림 파서**로 읽고, 메시지마다 통계만 누적한 뒤 **본문은 즉시 버립니다**.
64
+ ### 2. 터미널에서 실행
82
65
 
83
- | 설계 | 효과 |
84
- |------|------|
85
- | **스트리밍 파싱** | 파일 전체를 문자열/배열로 펼치지 않음 |
86
- | **단일 패스 집계** | `Map`·히스토그램·온라인 통계(간격 P90 등)만 유지 |
87
- | **Worker (≥3MB)** | 대용량일 때 메인 스레드 멈춤 완화 |
88
- | **키워드** | **Kiwi** 한국어 형태소(+방별·glossary userWords) + **BM25**·PMI + **한국어 방 자동 시맨틱**(다국어 임베딩) |
89
- | **kcachat@latest** | 실행 시 `kakaotalk-chat-analyzer@latest` 본체를 받아 최신 CLI 사용 |
66
+ [Node.js 22+](https://nodejs.org/)가 설치되어 있어야 합니다.
90
67
 
91
- 로컬 벤치(합성 20만 메시지, 집계만): **약 0.4초대** 환경·디스크·실제 대화 밀도에 따라 달라집니다.
68
+ **공유 링크까지 (기본)** 저장 폴더에서 **가장 최근** CSV를 자동으로 고릅니다:
92
69
 
93
70
  ```bash
94
- # 진행률은 기본으로 stderr에 표시 (집계 → Kiwi 준비 → 키워드·주제). 끄려면:
95
- npx kcachat@latest "./KakaoTalk_Chat_....csv" --no-progress
96
-
97
- # 한국어 방은 시맨틱 키워드가 기본 ON (multilingual-e5-small, 끄려면 --no-semantic-keywords)
98
- # 영어 위주 방에서 강제: --semantic-keywords
99
- # 이전 MiniLM: KCA_SEMANTIC_MODEL=Xenova/paraphrase-multilingual-MiniLM-L12-v2
100
-
101
- # 단계별 ms (Worker 끔)
102
- npx kcachat@latest "./KakaoTalk_Chat_....csv" --profile --no-worker
103
-
104
- # 개발용 벤치
105
- npm run bench:stream -- 100000
71
+ npx kcachat@latest
106
72
  ```
107
73
 
108
- > 외부 DB(DuckDB ) 없이 **Node.js만**으로 동작합니다. 의존성·설치 부담을 줄이기 위한 선택입니다.
109
-
110
- ---
111
-
112
- ## 리포트 UX
74
+ **내 PC에만 저장** (인터넷 업로드 없음):
113
75
 
114
- 생성되는 `index.html`은 **브라우저만** 있으면 열리는 단일 파일입니다. (인터랙티브 차트는 CDN으로 ECharts를 불러옵니다.)
76
+ ```bash
77
+ npx kcachat@latest --local
78
+ ```
115
79
 
116
- - **⓪ Wrapped · 스토리**: 카드형 한 장면 요약, **페르소나·챕터**, **활동 기간/연간 그리드**(짧은 기간은 「활동 기간 그리드」), **이벤트 스파인**, 방 프로필·타임라인
117
- - **빠른 이동**: Wrapped · 페르소나 · 연간 그리드 · 숫자 요약 · 하이라이트 · 주제 맵 · 인터랙티브 차트 · 용어 설명
118
- - **혁신 레이어**: **dyad**(누가 누구에게 답하는가)·기간 비교·내러티브·브러시 기간 탐색
119
- - **인터랙티브 차트**: 워드클라우드, 시간대·**요일 7색**·월별, **대화 테마 · c-TF-IDF**, **키워드 순위 목록**(인라인 막대·전체 120개)
120
- - **숫자·인사이트**: 지니·리듬 점수·응답 간격(초/분)·하이라이트·시스템 알림 분리
121
- - **키워드**: **Kiwi** + **BM25/PMI** + 한국어 방 **자동 시맨틱**(e5-small), 오픈채팅·잡음어 필터
122
- - **참여자**: 말풍선 맵 + 마스킹 닉네임 + 랭킹 테이블
123
- - **생성 메타 (0.13.3+)**: 사이드 카드 **생성 도구**(`kca` 버전), 접기 **리포트 정보**, `#kca-provenance` JSON — BrewPage 링크로 **어떤 kca로 만들었는지** 확인 가능
124
- - **BrewPage**: iframe 섹션 점프·외부 링크 안전 처리
125
- - **테마**: 라이트 / 다크 / 시스템 · **OLED glass** 비주얼
80
+ | OS | 자동으로 찾는 폴더 |
81
+ |----|-------------------|
82
+ | **Windows** | `문서\카카오톡 받은 파일` (없으면 `문서\카카오톡` → `다운로드`) |
83
+ | **Mac** | `다운로드` (Downloads) |
126
84
 
127
- 원문 메시지·전체 URL은 HTML에 넣지 않습니다(BrewPage 5MiB 한도 고려). **이미 올린 링크는 재업로드해야** UI·버전 메타가 바뀝니다.
85
+ 다른 폴더를 쓰려면: `KCA_CSV_DIR=~/Desktop npx kcachat@latest`
128
86
 
129
- ### 최근
87
+ ### 3. 링크 열기
130
88
 
131
- | 버전 | 요약 |
132
- |------|------|
133
- | **0.16.1** | Windows 기본 CSV 경로 `Documents\카카오톡 받은 파일` 자동 탐색 |
134
- | **0.16.0** | **최신 CSV 자동**(`npx kcachat`·`latest --list/--pick`)·진행률 추정·30분 세션 gap·topicModel provenance·Facts/Wrapped DOM 정렬 |
135
- | **0.15.0** | Trust UX(조건부 네비·참여자 카드)·키워드 RRF·burst MAD·Kiwi 1×CSV read·오픈채팅 인사이트·임베딩 주제 옵션 |
136
- | **0.13.8** | burst 활동일 스케일·대용량 gap exact quantile·주제맵 PMI/약한 edge·벤치 **추정** UI·회귀 fixture |
137
- | **0.13.7** | **BM25** 키워드·**담화어** 통합 lexicon·주제맵 discourse 게이트·시맨틱 k-means++/coherence·타임라인 meme **peakDate** |
138
- | **0.13.6** | 활동 그리드 일별 셀·dyad 전체 숫자·주제맵 품질·키워드 요약 펼침·샵검색 집계·시스템 테마 |
139
- | **0.13.5** | 키워드 **순위 목록** 통합(ECharts 막대+표 → 인라인 막대 표) · ② 요약 상위 12·접기 기본 |
140
- | **0.13.4** | Worker 분석 시 provenance **`kiwiAvailable`** 정확 표시 (`kiwiAvailableAtAnalysis`) |
141
- | **0.13.3** | HTML **provenance**: `kca` 버전·`#kca-provenance` JSON·**리포트 정보** `<details>`·`kcachat` → `KCA_INVOKER` |
142
- | **0.13.2** | 키워드 막대 insideLeft·상위 3색, **활동 기간 그리드**(compact), 주제 테마/기간 분리, dyad visualMap |
143
- | **0.13.1** | 생성 시각·소요, 이벤트 스파인, 히트맵/참여 pie, 주제맵·키워드 UX |
144
- | **0.13.0** | dyad·타임라인·내러티브·기간 탐색(혁신 레이어) |
145
- | **0.12.0** | OLED glassmorphism 리포트 비주얼 |
146
- | **0.11.2** | lazy charts·Playwright `report:screenshots` |
147
- | **0.11.1** | ECharts 반응형 grid·모바일 말풍선·`npm run report:viewport` |
148
- | **0.11.0** | 반응형 6레이어·ResizeObserver·스크롤 리빌 |
149
- | **0.10.x** | Open Props CSS 번들·테마 대비·Pretendard ([Releases](https://github.com/claudianus/kakaotalk-chat-analyzer/releases)에서 0.10.0–0.10.2) |
150
- | **0.9.x** | e5-small 시맨틱 기본·스크롤 스파이 네비 ([Releases](https://github.com/claudianus/kakaotalk-chat-analyzer/releases)) |
151
- | **0.3–0.8** | Kiwi·BM25·주제 맵·한국어 시맨틱·스트림 2단계 등 — [Releases](https://github.com/claudianus/kakaotalk-chat-analyzer/releases) 참고 |
89
+ 터미널에 나온 **URL**을 브라우저에서 열면 Wrapped·차트·키워드가 있는 리포트를 볼 수 있습니다.
152
90
 
153
- ---
91
+ - **최초 1회**는 한국어 분석 모델 다운로드로 **1~3분** 걸릴 수 있습니다.
92
+ - 이미 올린 예전 링크는 **다시 실행·업로드**해야 UI가 바뀝니다.
154
93
 
155
- ## 카카오톡에서 CSV 보내기
94
+ ### 파일을 직접 고르고 싶을 때
156
95
 
157
- 1. 카카오톡에서 분석할 **채팅방**을 엽니다.
158
- 2. 우측 상단 **더보기(≡)** **대화 보내기** → **CSV 보내기**로 파일을 저장합니다. (파일명은 보통 `KakaoTalk_Chat_…` 형태입니다.)
159
- 3. 아래 [빠른 시작](#빠른-시작)의 `npx` 명령에 **저장한 파일 경로**를 넣어 실행합니다.
96
+ ```bash
97
+ npx kcachat@latest latest --list # 후보 목록
98
+ npx kcachat@latest latest --pick 1 # 번째로 최근 파일
99
+ npx kcachat@latest "C:\경로\KakaoTalk_Chat_....csv"
100
+ ```
160
101
 
161
- > iOS/Android 버전에 따라 메뉴 문구가 조금 다를 있습니다. **메시지 원문이 포함된 CSV**이므로, 공유·업로드 전에 항상 내용을 확인하세요.
102
+ > 카카오 **공식 앱이 아닙니다.** 보내기 CSV 형식이 바뀌면 동작이 깨질 있으니 중요한 대화는 백업해 두세요.
162
103
 
163
104
  ---
164
105
 
165
- ## 빠른 시작
166
-
167
- ### 요구 사항
106
+ ## 리포트에서 볼 수 있는 것
168
107
 
169
- - [Node.js](https://nodejs.org/) **22 이상**
108
+ 브라우저만 있으면 되는 **단일 HTML**입니다. **대화 원문은 파일에 넣지 않습니다.**
170
109
 
171
- ### npx (추천)
110
+ | 구역 | 내용 |
111
+ |------|------|
112
+ | **Wrapped** | 한 장면 요약, 활동 달력, 페르소나·하이라이트 |
113
+ | **차트** | 워드클라우드, 요일·시간대, 주제 맵 |
114
+ | **키워드** | 상위 단어 순위 (한국어 형태소 + 통계) |
115
+ | **참여자** | 말풍선·랭킹 (이름은 **일부만** 보이게 마스킹) |
116
+ | **테마** | 라이트 / 다크 / 시스템 |
172
117
 
173
- **짧은 패키지명 [`kcachat`](https://www.npmjs.com/package/kcachat)** 으로 본체(`kakaotalk-chat-analyzer`)와 똑같이 실행할 있습니다.
118
+ 공유 링크(BrewPage ) 열어도 되고, `--local`로 만든 `index.html`을 더블클릭해도 됩니다.
174
119
 
175
- | 상황 | 대략 소요 (M1급, 참고) |
176
- |------|------------------------|
177
- | 최초 `npx` + Kiwi 모델 | 1~3분 (1회) |
178
- | 2천 건 · `--local` · 시맨틱 끔 | 수 초 |
179
- | 9만 건 · Kiwi ON · 시맨틱 ON | 수십 초~2분 |
120
+ ---
180
121
 
181
- **로컬에만** (`--local`: HTML만 만들고 기본 BrewPage 업로드는 생략. 출력 기본 `.tmp/kca-report`, `-o ./report`로 변경):
122
+ ## 개인정보·공유 전에
182
123
 
183
- ```bash
184
- npx kcachat@latest --local
185
- # 또는 경로 지정: npx kcachat@latest "./KakaoTalk_Chat_....csv" --local
186
- ```
124
+ - 메시지 **본문은 리포트 HTML에 저장하지 않습니다** (집계에만 사용).
125
+ - 참여자 이름은 기본적으로 **앞·뒤만 남기고 가운데 마스킹**합니다.
126
+ - URL은 **도메인**만 집계합니다.
127
+ - 그래도 **키워드·통계**만으로 방 분위기가 드러날 수 있습니다. 링크를 보내기 전에 한 번 훑어 보세요.
128
+ - `--local`을 쓰면 기본적으로 **외부 업로드 없이** 내 PC에만 저장합니다.
187
129
 
188
- **리포트 생성 후 기본 호스트(BrewPage)로 업로드** (CSV 생략 시 **KCA_CSV_DIR** 또는 OS 기본 폴더에서 최신 `KakaoTalk*.csv` 자동 선택):
130
+ ---
189
131
 
190
- | OS | 기본 폴더 |
191
- |----|-----------|
192
- | Windows | `%USERPROFILE%\Documents\카카오톡 받은 파일` |
193
- | macOS 등 | `~/Downloads` |
132
+ ## 자주 묻는 질문
194
133
 
195
- ```bash
196
- npx kcachat@latest
197
- npx kcachat@latest latest --list # 후보 10개 목록
198
- npx kcachat@latest latest --pick 1 # 두 번째로 최근 파일
199
- KCA_CSV_DIR=~/Desktop npx kcachat@latest
200
- ```
134
+ **Q. Node.js가 없어요.**
135
+ [nodejs.org](https://nodejs.org/)에서 LTS(22+) 설치 후 터미널을 다시 엽니다.
201
136
 
202
- > **버전:** `kcachat@latest`는 본체 `kakaotalk-chat-analyzer@latest`를 매 실행 받습니다. 고정하려면 `npx kakaotalk-chat-analyzer@0.13.4`. 리포트 사이드 카드·`grep kca-provenance`로 실제 생성 버전을 확인하세요. 오프라인은 `kcachat … --bundled`. ([kcachat README](kcachat/README.md))
137
+ **Q. CSV를 찾는다고 해요.**
138
+ → 위 [OS별 폴더](#2-터미널에서-한-줄-실행)에 파일이 있는지 확인하거나, 경로를 직접 넣으세요.
203
139
 
204
- CSV와 같은 폴더에 **`.kca-glossary.txt`**(한 줄에 단어)를 두면 Kiwi 사용자 사전에 자동 반영됩니다.
140
+ **Q. 실행이 너무 느려요.**
141
+ → Kiwi 한국어 모델을 **처음 한 번** 받는 중입니다. 이후에는 훨씬 빨라집니다.
205
142
 
206
- 전체 이름으로 실행해도 동일합니다:
143
+ **Q. 친구에게 링크만내면 되나요?**
144
+ → 네. 다만 통계·키워드가 방 성격을 드러낼 수 있으니 공유 범위는 스스로 판단하세요.
207
145
 
208
- ```bash
209
- npx kakaotalk-chat-analyzer@latest "./KakaoTalk_Chat_....csv" --local
210
- ```
146
+ **Q. 예전에 만든 링크 UI가 옛날이에요.**
147
+ 링크는 업로드 당시 HTML이 고정됩니다. CSV로 **다시 실행**해 새 링크를 받으세요.
211
148
 
212
- GitHub 소스에서 직접:
149
+ **Q. `kcachat`와 `kakaotalk-chat-analyzer` 차이?**
150
+ → 같은 프로그램입니다. `kcachat`는 짧은 `npx` 이름입니다.
213
151
 
214
- ```bash
215
- npx github:claudianus/kakaotalk-chat-analyzer "./KakaoTalk_Chat_....csv" --local
216
- ```
217
-
218
- ### 로컬 클론 개발
219
-
220
- ```bash
221
- git clone https://github.com/claudianus/kakaotalk-chat-analyzer.git
222
- cd kakaotalk-chat-analyzer
223
- npm install
224
- npm run build
225
- npm test
226
- ```
152
+ ---
227
153
 
228
- ### CLI 요약
154
+ ## 옵션·고급
229
155
 
230
- 기본 동작은 **서브커맨드 없이** `<csv>` 한 개만 주면 됩니다.
156
+ <details>
157
+ <summary><strong>CLI 전체 옵션 (펼치기)</strong></summary>
231
158
 
232
159
  ```bash
233
160
  # 기본: HTML 생성 후 BrewPage 업로드
234
161
  kca ./KakaoTalk_Chat_....csv
235
162
 
236
163
  # 업로드 없이 로컬만
237
- kca ./KakaoTalk_Chat_....csv --local -o ./report
164
+ kca ./chat.csv --local -o ./report
238
165
 
239
166
  # 업로드 생략(드라이런)
240
- kca ./KakaoTalk_Chat_....csv --dry-run
167
+ kca ./chat.csv --dry-run
241
168
 
242
- # TempFile 호스트
169
+ # 다른 호스트
243
170
  kca ./chat.csv --host tempfile --ttl 30
244
171
 
245
- # 보내기 구조 점검(원문 출력 없음, 스트리밍)
246
- kca inspect ./KakaoTalk_Chat_....csv
172
+ # 보내기 구조 점검(원문 출력 없음)
173
+ kca inspect ./chat.csv
247
174
 
248
- # 진행률 끄기(CI·스크립트) / 단계별 ms 프로파일
175
+ # 진행률 끄기 / 프로파일
249
176
  kca ./chat.csv --no-progress
250
177
  kca ./chat.csv --profile --no-worker
251
178
 
252
- # YYYY-MM-DD 이후만 집계
179
+ # 날짜 필터
253
180
  kca ./chat.csv --since 2025-01-01
254
181
 
255
182
  kca --help
256
183
  ```
257
184
 
258
- 업로드가 실패해도 **로컬 `index.html`은 남습니다**.
259
-
260
- ---
261
-
262
- ## 생성되는 리포트
185
+ 업로드가 실패해도 **로컬 `index.html`은 남습니다.**
263
186
 
264
- - **단일 `index.html`**: CSS·차트·안내 문구가 **한 파일에 포함**되어 오프라인에서도 동작합니다.
265
- - **원문 미저장**: 메시지 본문은 통계 계산에만 사용되며 HTML에 남기지 않습니다.
266
- - **provenance (CLI)**: `kca` 버전·분석 옵션·HTML 크기·생성 소요가 **생성 도구** / **리포트 정보** / `#kca-provenance`에 기록됩니다.
267
- - **재업로드 안내**: 예전 BrewPage 링크는 생성 시점 HTML이 고정됩니다. UI·버그 수정 후에는 **다시 업로드**해야 반영됩니다.
268
- - 자세한 화면 구성은 [리포트 UX](#리포트-ux)를 참고하세요.
187
+ </details>
269
188
 
270
- ---
271
-
272
- ## 프라이버시 기본값
189
+ <details>
190
+ <summary><strong>성능·키워드·벤치 (개발·파워유저)</strong></summary>
273
191
 
274
- - 기본(`public-masked`)은 참여자 이름을 **앞·뒤 글자만 남기고 가운데 마스킹**합니다(동명이의 충돌 시 `·2`처럼 구분자가 붙을 수 있음). 완전 별칭(`User 001`)은 `--privacy public-anonymous` 로 선택할 수 있습니다.
275
- - 메시지 텍스트는 **통계 계산에만** 사용되며, **생성된 HTML에 원문이 쓰이지 않습니다**.
276
- - URL에서 **도메인**만 집계하고, 전체 URL 문자열은 리포트에 보존하지 않습니다.
277
- - BrewPage **owner 토큰**은 로컬에 저장되어, 이후 링크 관리·삭제에 활용할 있습니다.
192
+ - **스트리밍 파싱**: 대용량 CSV도 RAM에 통째로 올리지 않음
193
+ - **진행률**: 기본 ON (`--no-progress`로 끔)
194
+ - **시맨틱 키워드**: 한국어 기본 ON (`--no-semantic-keywords`로 끔)
195
+ - CSV **`.kca-glossary.txt`**(한 줄에 단어) Kiwi 사용자 사전 반영
278
196
 
279
197
  ```bash
280
- # 저장된 owner 토큰 삭제
281
- kca token clear --host brewpage --ns kakao-chat-report
198
+ npx kcachat@latest "./chat.csv" --profile --no-worker
199
+ npm run bench:stream -- 100000 # 저장소 클론 후
282
200
  ```
283
201
 
284
- ---
202
+ </details>
285
203
 
286
- ## 아키텍처 한눈에
287
-
288
- ```
289
- CSV 파일 (스트림 read)
290
- → 인코딩 샘플(512KB) + 줄 단위 Kakao 파서
291
- → ReportAggregator (단일 패스 · 메시지 본문 비보관)
292
- ├─ [≥3MB] Worker 스레드 (선택)
293
- └─ Gap/키워드 온라인 통계
294
- → report.ts (단일 HTML, 다크/라이트)
295
- → [선택] providers → BrewPage / TempFile / Cloudflare
296
- ```
297
-
298
- `kcachat`는 npm에서 **짧은 이름**으로 위 파이프라인을 실행하는 래퍼입니다.
299
-
300
- ---
204
+ **버전 고정:** `npx kakaotalk-chat-analyzer@0.16.1` · 최신은 `kcachat@latest`가 매번 본체를 받습니다. 리포트 사이드 카드·`#kca-provenance`로 실제 생성 버전을 확인할 수 있습니다.
301
205
 
302
- ## 개발
206
+ **로컬 개발:**
303
207
 
304
208
  ```bash
305
- npm install
306
- npm run build # sync-version CSS 번들 tsc
307
- npm test
209
+ git clone https://github.com/claudianus/kakaotalk-chat-analyzer.git
210
+ cd kakaotalk-chat-analyzer && npm install && npm run build && npm test
308
211
  ```
309
212
 
310
- 유용한 스크립트: `npm run report:qa` · `report:qa:serve` · `report:screenshots` · `docs:capture-demo` · `keyword:audit` · `bench:stream` · Pages pill `node scripts/sync-docs-version.mjs`
311
-
312
213
  ---
313
214
 
314
- ## 문서 사이트 (GitHub Pages)
315
-
316
- ### Kiwi 모델·환경 변수
317
-
318
- - **최초 실행** 시 GitHub에서 Kiwi 한국어 모델을 **무료**로 받아 `~/.cache/kakaotalk-chat-analyzer/kiwi-base/`에 둡니다.
319
- - **`KCA_NO_KIWI=1`**: 형태소 없이 휴리스틱만(빠름, 품질↓).
320
- - **진행률**: 기본으로 stderr에 `대화 분석 42% (…)` 표시. 끄려면 `--no-progress`.
321
- - **키워드 비교**: `npm run keyword:diff -- ./KakaoTalk_Chat_....csv 30`
322
- - LGPL 고지: [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)
215
+ ## 최근 업데이트
323
216
 
324
- 랜딩([`docs/index.html`](docs/index.html))은 **업로드 명령**·**리포트 데모 스크린샷**·짧은 팁만 담은 단일 HTML입니다. 상세 옵션은 이 README를 봅니다. `main`에 `docs/` 변경을 푸시하면 **GitHub Actions**가 Pages를 배포합니다.
217
+ | 버전 | 요약 |
218
+ |------|------|
219
+ | **0.16.3** | 기본 **품질 우선** 프로필(메인 스레드·시맨틱 샘플 확대·RRF 완화·임베딩 주제). 가속은 `--worker` / `--fast` |
220
+ | **0.16.1** | Windows 기본 CSV 폴더 `문서\카카오톡 받은 파일` |
221
+ | **0.16.0** | 경로 생략·`latest --list/--pick`·진행률 추정·세션 gap |
222
+ | **0.15.0** | 모바일 참여자 카드·키워드 RRF·오픈채팅 인사이트 |
223
+ | **0.13.8** | burst·주제맵·벤치 UI |
224
+ | **0.13.3** | 리포트에 `kca` 버전(provenance) 표시 |
325
225
 
326
- - **공개 URL:** [https://claudianus.github.io/kakaotalk-chat-analyzer/](https://claudianus.github.io/kakaotalk-chat-analyzer/)
327
- - **워크플로:** [`.github/workflows/pages.yml`](.github/workflows/pages.yml)
226
+ 이전 버전: [Releases](https://github.com/claudianus/kakaotalk-chat-analyzer/releases)
328
227
 
329
- ### 저장소를 새로 쓸 때 (Pages 켜기)
228
+ ---
330
229
 
331
- 1. GitHub **Settings → Pages**
332
- 2. **Build and deployment → Source:** **GitHub Actions** 선택
333
- 3. `main`에 푸시하면 **Deploy GitHub Pages** 워크플로가 `docs/`를 게시합니다. (최초 1회는 Actions 탭에서 권한/환경 승인이 필요할 수 있습니다.)
230
+ ## 개발·기여
334
231
 
335
- ---
232
+ ```bash
233
+ npm install && npm run build && npm test
234
+ ```
336
235
 
337
- ## 기여하기
236
+ 유용한 스크립트: `report:qa` · `report:screenshots` · `docs:capture-demo` · `bench:stream`
338
237
 
339
- 이슈·PR·아이디어 모두 환영합니다. 변경 전에는 이슈에서 방향을 먼저 짧게 나누면 리뷰가 빨라집니다.
238
+ 이슈·PR 환영합니다. 민감한 CSV·토큰은 이슈에 첨부하지 마세요.
340
239
 
341
- 1. Fork브랜치 생성
342
- 2. `npm test` 통과
343
- 3. PR 설명에 **동기(왜)** 와 **테스트 방법**을 적어 주세요.
240
+ **아키텍처 (요약):** CSV 스트림 집계(본문 비보관) → 단일 HTML → [선택] BrewPage 등 업로드.
344
241
 
345
242
  ---
346
243
 
347
- ## 보안
244
+ ## 문서 사이트 (GitHub Pages)
348
245
 
349
- 민감한 CSV나 토큰이 포함된 스크린샷은 **이슈/PR에 첨부하지 마세요**.
350
- 취약점으로 보이는 내용은 비공개 채널(예: GitHub Security Advisories)로 알려 주시면 감사하겠습니다.
246
+ - **공개 URL:** [https://claudianus.github.io/kakaotalk-chat-analyzer/](https://claudianus.github.io/kakaotalk-chat-analyzer/)
247
+ - [`docs/index.html`](docs/index.html) 시작 명령·OS별 폴더·짧은
248
+ - `main`에 `docs/` 푸시 시 Actions가 배포 · pill 버전: `node scripts/sync-docs-version.mjs`
351
249
 
352
250
  ---
353
251
 
@@ -355,12 +253,8 @@ npm test
355
253
 
356
254
  [MIT License](./LICENSE)
357
255
 
358
- ---
359
-
360
256
  <div align="center">
361
257
 
362
258
  **Made with care for safer chat analytics** · [@claudianus](https://github.com/claudianus)
363
259
 
364
- ⭐ 이 프로젝트가 도움이 되었다면 스타 한 번 부탁드립니다.
365
-
366
260
  </div>
@@ -8,7 +8,11 @@ export interface FinalizeSourceMeta {
8
8
  export interface FinalizeOptions {
9
9
  usedSemanticKeywords?: boolean;
10
10
  koreanPrimary?: boolean;
11
+ useEmbeddingTopics?: boolean;
12
+ semanticSupplementRrfWeight?: number;
11
13
  }
14
+ /** 시맨틱 supplement messageHits 상한 — RRF 독점 방지 */
15
+ export declare function semanticSupplementHitCap(corpusMessages: number): number;
12
16
  export interface AggregatorOptions {
13
17
  /** 시맨틱 키워드용 메시지 샘플 수집 */
14
18
  semanticSamples?: boolean;
@@ -89,7 +93,7 @@ export declare class ReportAggregator {
89
93
  label: string;
90
94
  messageHits: number;
91
95
  score?: number;
92
- }[]): void;
96
+ }[], corpusMessages: number): void;
93
97
  consume(record: ChatRecord, opts?: {
94
98
  keywordsOnly?: boolean;
95
99
  skipKeywords?: boolean;
@@ -10,6 +10,7 @@ import { buildTopicStopwords } from "./topic-stopwords.js";
10
10
  import { MessageReservoir } from "./message-reservoir.js";
11
11
  import { semanticReservoirCap, semanticSampleCap, subsampleSemanticMessages } from "./semantic-policy.js";
12
12
  import { mergeKeywordRankings } from "./keyword-merge.js";
13
+ import { isNoiseKeyword } from "./keyword-quality.js";
13
14
  import { formatCompactNumber, formatReplyGapMinutes } from "./report-util.js";
14
15
  import { KeywordCounter } from "./keyword-counter.js";
15
16
  import { RepeatPhraseCounter } from "./repeat-phrase-counter.js";
@@ -47,6 +48,10 @@ const EMOJI_RE = /\p{Extended_Pictographic}/u;
47
48
  const LAUGH_RE = /(?:ㅋ{2,}|ㅎ{2,}|ㅠ+|ㅜ+|ㅇㅇ|ㅋㅋ|ㅎㅎ|ㅋㅎ|ㅎㅋ)/;
48
49
  const LINK_HINT_RE = /https?:\/\/|www\./i;
49
50
  const HAS_TOKEN_CHAR_RE = /[가-힣A-Za-z]/;
51
+ /** 시맨틱 supplement messageHits 상한 — RRF 독점 방지 */
52
+ export function semanticSupplementHitCap(corpusMessages) {
53
+ return Math.min(24, 4 + Math.floor(Math.sqrt(Math.max(corpusMessages, 1))));
54
+ }
50
55
  export class ReportAggregator {
51
56
  filePath;
52
57
  privacy;
@@ -156,14 +161,17 @@ export class ReportAggregator {
156
161
  if (this.semanticReservoir && messageLength >= 12)
157
162
  this.semanticReservoir.push(msg);
158
163
  }
159
- applySemanticKeywordBoost(items) {
160
- this.semanticThemeCandidates = items.map((item) => ({
164
+ applySemanticKeywordBoost(items, corpusMessages) {
165
+ const hitCap = semanticSupplementHitCap(corpusMessages);
166
+ const valid = items.filter((item) => !isNoiseKeyword(item.label));
167
+ this.semanticThemeCandidates = valid.map((item) => ({
161
168
  label: item.label,
162
169
  messageHits: item.messageHits,
163
170
  score: item.score ?? item.messageHits,
164
171
  }));
165
- for (const item of items) {
166
- this.keywordSupplement.addHits(item.label, Math.max(2, item.messageHits));
172
+ for (const item of valid) {
173
+ const hits = Math.max(2, Math.min(item.messageHits, hitCap));
174
+ this.keywordSupplement.addHits(item.label, hits);
167
175
  }
168
176
  }
169
177
  consume(record, opts) {
@@ -445,9 +453,9 @@ export class ReportAggregator {
445
453
  limit: keywordLimit,
446
454
  minDocFreq: adaptiveMinCount(total, finalizeOpts?.koreanPrimary !== false),
447
455
  });
448
- const keywords = mergeKeywordRankings(wordRankItems, this.keywordSupplement, keywordLimit);
456
+ const keywords = mergeKeywordRankings(wordRankItems, this.keywordSupplement, keywordLimit, finalizeOpts?.semanticSupplementRrfWeight ?? 0.5);
449
457
  let topics = this.topicMap.buildTopics(total, buildTopicStopwords());
450
- if (process.env.KCA_EMBEDDING_TOPICS === "1" && this.semanticThemeCandidates.length > 0) {
458
+ if (finalizeOpts?.useEmbeddingTopics && this.semanticThemeCandidates.length > 0) {
451
459
  topics = mergeEmbeddingThemes(topics, this.semanticThemeCandidates, total);
452
460
  }
453
461
  const burstDetectionMethod = resolveBurstDetectionMethod();