chattercatcher 0.1.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.
@@ -0,0 +1,402 @@
1
+ # 技术架构
2
+
3
+ ## 总体架构
4
+
5
+ ```mermaid
6
+ flowchart TD
7
+ A["飞书/Lark 群"] --> B["本地 Gateway"]
8
+ B --> C["消息接收器"]
9
+ C --> D["SQLite 原始存储"]
10
+ C --> E["媒体下载器"]
11
+ E --> F["本地文件库"]
12
+ D --> G["解析与切块"]
13
+ F --> G
14
+ G --> H["Embedding Worker"]
15
+ H --> I["向量库"]
16
+ G --> J["SQLite FTS 索引"]
17
+ G --> K["事实抽取器"]
18
+ K --> L["事实与版本"]
19
+
20
+ A --> M["@机器人提问"]
21
+ M --> N["查询路由"]
22
+ N --> O["混合检索器"]
23
+ O --> P["冲突处理器"]
24
+ P --> Q["LLM 答案生成器"]
25
+ Q --> A
26
+
27
+ R["CLI"] --> S["配置与运行时"]
28
+ T["本地 Web UI"] --> S
29
+ T --> D
30
+ T --> I
31
+ T --> L
32
+ ```
33
+
34
+ ## 运行时
35
+
36
+ - Node.js 20+。
37
+ - TypeScript。
38
+ - npm 全局包。
39
+ - 本地优先运行。
40
+
41
+ ## 推荐技术栈
42
+
43
+ ### CLI
44
+
45
+ - `commander`:命令结构。
46
+ - `@inquirer/prompts`:交互式 setup/settings。
47
+ - `pino`:日志。
48
+
49
+ ### Gateway 和 API
50
+
51
+ - `fastify`:本地 HTTP API 和 Web UI 后端。
52
+ - `@larksuiteoapi/node-sdk`:飞书/Lark API 和长连接能力。
53
+
54
+ ### Web UI
55
+
56
+ - React。
57
+ - Vite。
58
+ - TanStack Query。
59
+ - TanStack Router。
60
+ - Tailwind CSS。
61
+ - Radix UI 或 shadcn/ui。
62
+
63
+ ### 存储
64
+
65
+ - SQLite:元数据、原始消息、任务、配置、事实。
66
+ - Drizzle ORM:schema 和 migration。
67
+ - SQLite FTS5:关键词检索。
68
+ - LanceDB 或其他本地嵌入式向量库:embedding 检索。
69
+
70
+ SQLite 不能作为完整 RAG 的唯一后端。它只负责结构化元数据和关键词召回;语义召回必须走向量库 adapter。MVP 默认优先本地向量库,首选 LanceDB,保留 Qdrant/Chroma adapter 扩展空间。
71
+
72
+ ### LLM 和 Embedding
73
+
74
+ - OpenAI-compatible chat completions API。
75
+ - OpenAI-compatible embeddings API。
76
+ - 可配置 base URL、API key、模型名和向量维度。
77
+ - `doctor` 必须验证 provider 兼容性。
78
+
79
+ ### 解析器
80
+
81
+ - PDF:`pdf-parse` 或 `unpdf`。
82
+ - DOCX:`mammoth`。
83
+ - XLSX:`xlsx`。
84
+ - PPTX:先解压 XML 提取,之后再接专用 parser。
85
+ - HTML/链接:`cheerio` 加 readability。
86
+ - OCR:可配置路径,使用 Tesseract.js 或基于视觉模型的 OCR。
87
+ - 音频:先支持可配置的 OpenAI-compatible transcription,之后支持本地 Whisper。
88
+
89
+ ## 本地数据布局
90
+
91
+ 默认:
92
+
93
+ ```text
94
+ ~/.chattercatcher/
95
+ config.json
96
+ secrets.json
97
+ data/
98
+ chattercatcher.db
99
+ exports/
100
+ files/
101
+ thumbnails/
102
+ transcripts/
103
+ vector/
104
+ logs/
105
+ cache/
106
+ ```
107
+
108
+ `config.json` 存普通配置。
109
+
110
+ `secrets.json` 存敏感值:
111
+
112
+ - 飞书 App Secret。
113
+ - LLM API Key。
114
+ - embedding API Key,若和 LLM 分开。
115
+
116
+ ## 核心数据模型
117
+
118
+ ### chats
119
+
120
+ ```text
121
+ id
122
+ platform
123
+ platform_chat_id
124
+ name
125
+ created_at
126
+ updated_at
127
+ ```
128
+
129
+ ### messages
130
+
131
+ ```text
132
+ id
133
+ platform
134
+ platform_message_id
135
+ chat_id
136
+ sender_id
137
+ sender_name
138
+ message_type
139
+ text
140
+ raw_payload_json
141
+ sent_at
142
+ received_at
143
+ created_at
144
+ ```
145
+
146
+ ### files
147
+
148
+ ```text
149
+ id
150
+ message_id
151
+ platform_file_key
152
+ file_name
153
+ mime_type
154
+ local_path
155
+ sha256
156
+ size_bytes
157
+ parse_status
158
+ created_at
159
+ updated_at
160
+ ```
161
+
162
+ ### chunks
163
+
164
+ ```text
165
+ id
166
+ source_type
167
+ source_id
168
+ chunk_index
169
+ text
170
+ metadata_json
171
+ created_at
172
+ ```
173
+
174
+ ### embeddings
175
+
176
+ ```text
177
+ id
178
+ chunk_id
179
+ provider
180
+ model
181
+ dimension
182
+ vector_ref
183
+ created_at
184
+ ```
185
+
186
+ ### facts
187
+
188
+ ```text
189
+ id
190
+ subject
191
+ predicate
192
+ value
193
+ confidence
194
+ status
195
+ source_chunk_id
196
+ supersedes_fact_id
197
+ valid_from
198
+ created_at
199
+ ```
200
+
201
+ ### qa_logs
202
+
203
+ ```text
204
+ id
205
+ chat_id
206
+ question_message_id
207
+ question
208
+ answer
209
+ citations_json
210
+ retrieval_debug_json
211
+ created_at
212
+ ```
213
+
214
+ ### jobs
215
+
216
+ ```text
217
+ id
218
+ type
219
+ status
220
+ payload_json
221
+ attempts
222
+ last_error
223
+ created_at
224
+ updated_at
225
+ ```
226
+
227
+ ## RAG 设计
228
+
229
+ RAG 是强制架构路径,不能被 prompt 堆叠替代。
230
+
231
+ 检索流程:
232
+
233
+ 1. 问题改写和意图识别。
234
+ 2. 对 chunk 做向量检索,默认接本地向量库 adapter。
235
+ 3. 通过 SQLite FTS5 做关键词检索。
236
+ 4. 按群、时间、发送人、来源类型做元数据过滤。
237
+ 5. 引入时间权重和来源权重重排。
238
+ 6. 进入事实级冲突处理。
239
+ 7. LLM 只基于最终证据块生成答案和引用。
240
+
241
+ 答案生成器只能接收压缩后的证据块,不能接收无限制原始聊天历史。
242
+
243
+ ## 冲突处理
244
+
245
+ 冲突处理不能简单“最新消息赢”。
246
+
247
+ 必须检查:
248
+
249
+ - 主体相同或高度相似。
250
+ - 谓词相同。
251
+ - 新来源时间更晚。
252
+ - 存在更新语义,例如:
253
+ - 改到。
254
+ - 更新为。
255
+ - 最终定。
256
+ - 以这个为准。
257
+ - 不是之前那个。
258
+ - 有足够置信度认为消息陈述的是事实,而不是建议。
259
+
260
+ 状态:
261
+
262
+ - `active`:当前最可信事实。
263
+ - `superseded`:被较新确认事实取代的旧事实。
264
+ - `ambiguous`:相关证据,但不覆盖 active 事实。
265
+
266
+ ## 飞书/Lark Gateway
267
+
268
+ MVP 采用本地 Gateway 模式:
269
+
270
+ - 用户创建飞书/Lark 自建应用。
271
+ - 用户启用机器人能力。
272
+ - 用户配置 App ID 和 App Secret。
273
+ - 用户启用长连接事件订阅。
274
+ - ChatterCatcher 从本机打开长连接。
275
+ - 传入消息事件被归一化为内部 message。
276
+ - 回复通过飞书/Lark Bot API 发送。
277
+
278
+ 实现上使用 `@larksuiteoapi/node-sdk` 的 `WSClient` 和 `EventDispatcher`:
279
+
280
+ ```text
281
+ WSClient 长连接 -> EventDispatcher im.message.receive_v1 -> GatewayIngestor -> SQLite/LanceDB RAG
282
+ ```
283
+
284
+ Gateway 层只负责接收和归一化事件,不直接参与 RAG 答案生成,避免平台细节污染知识库和检索层。
285
+
286
+ 当消息命中 `@ChatterCatcher` 时,Gateway 会在入库后触发问答流程,但检索时必须排除本次提问消息,避免把问题本身当作证据。回复链路为:
287
+
288
+ ```text
289
+ @消息 -> 入库 -> 排除当前消息 -> 混合检索 -> askWithRag -> 飞书 message.create 回复群聊
290
+ ```
291
+
292
+ 必需事件:
293
+
294
+ ```text
295
+ im.message.receive_v1
296
+ ```
297
+
298
+ 必需行为:
299
+
300
+ - 群聊默认需要 `@机器人` 才回答。
301
+ - 除非配置禁用,否则所有消息仍会被捕获。
302
+ - 私聊可以后续支持。
303
+
304
+ ## 配置
305
+
306
+ 配置必须能从这些入口编辑:
307
+
308
+ - `chattercatcher setup`
309
+ - `chattercatcher settings`
310
+ - 本地 Web UI
311
+
312
+ 关键字段:
313
+
314
+ ```json
315
+ {
316
+ "feishu": {
317
+ "domain": "feishu",
318
+ "appId": "",
319
+ "groupPolicy": "open",
320
+ "requireMention": true
321
+ },
322
+ "llm": {
323
+ "baseUrl": "",
324
+ "model": ""
325
+ },
326
+ "embedding": {
327
+ "baseUrl": "",
328
+ "model": "",
329
+ "dimension": null
330
+ },
331
+ "storage": {
332
+ "dataDir": "~/.chattercatcher/data"
333
+ },
334
+ "web": {
335
+ "host": "127.0.0.1",
336
+ "port": 3878
337
+ }
338
+ }
339
+ ```
340
+
341
+ secrets 不得存入该文件。
342
+
343
+ ## 运维命令
344
+
345
+ ```bash
346
+ chattercatcher setup
347
+ chattercatcher settings
348
+ chattercatcher doctor
349
+ chattercatcher gateway start
350
+ chattercatcher gateway status
351
+ chattercatcher gateway stop
352
+ chattercatcher gateway restart
353
+ chattercatcher logs --follow
354
+ chattercatcher logs --lines 200 --file gateway.log
355
+ chattercatcher index rebuild
356
+ chattercatcher process messages
357
+ chattercatcher export --out ./backup.json
358
+ chattercatcher restore ./backup.json --replace
359
+ chattercatcher data delete message <messageId> --yes
360
+ chattercatcher data delete file <messageId> --yes
361
+ chattercatcher data delete chat <chatId> --yes
362
+ chattercatcher web start
363
+ ```
364
+
365
+ `gateway start` 以前台进程运行,并在 `~/.chattercatcher/gateway.pid` 写入运行记录。`gateway stop` 读取该 PID 文件发送停止信号;如果 PID 已过期,会清理陈旧记录。后台服务安装仍属于 M3 的 service 能力。
366
+
367
+ `restore` 默认合并导入导出文件中的 chats、messages、message_chunks 和 file_jobs,并重建 SQLite FTS。只有显式传入 `--replace` 时才会先清空当前本地知识库;恢复后如果使用 LanceDB 语义检索,需要运行 `index rebuild` 重建向量。
368
+
369
+ `data delete` 删除 SQLite 知识库记录、关联 chunks、SQLite FTS 条目和文件解析任务。删除文件知识源时,只会清理位于 `storage.dataDir` 内的本地保存文件,不会删除外部源文件。删除后如果使用 LanceDB 语义检索,需要运行 `index rebuild` 清理向量侧残留。
370
+
371
+ `process messages` 立即运行消息索引处理。SQLite FTS 在消息入库时已经即时更新;该命令主要用于立刻把消息 chunks 写入 LanceDB 向量索引,等价于手动触发原本可由定时任务承担的处理动作。Web UI 首页的“立即处理”按钮调用同一条 API。
372
+
373
+ ## 测试策略
374
+
375
+ 分层测试:
376
+
377
+ - 纯逻辑单测:
378
+ - 配置校验。
379
+ - 消息归一化。
380
+ - 切块。
381
+ - 冲突处理。
382
+ - 引用格式。
383
+ - 集成测试:
384
+ - SQLite migration。
385
+ - 向量库 adapter。
386
+ - 索引任务。
387
+ - mock 飞书事件。
388
+ - mock OpenAI-compatible provider。
389
+ - UI 测试:
390
+ - settings 页面。
391
+ - history 页面。
392
+ - 文件库。
393
+ - 问答日志。
394
+
395
+ 手工 smoke test:
396
+
397
+ - 全新 setup。
398
+ - Gateway start。
399
+ - 消息捕获。
400
+ - `@机器人` 触发回答。
401
+ - 重建索引。
402
+ - Web UI 检查。
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "chattercatcher",
3
+ "version": "0.1.0",
4
+ "description": "本地优先的飞书/Lark 家庭群知识库机器人",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "homepage": "https://github.com/FlashingChen2024/chattercatcher#readme",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/FlashingChen2024/chattercatcher.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/FlashingChen2024/chattercatcher/issues"
15
+ },
16
+ "bin": {
17
+ "chattercatcher": "dist/cli.js"
18
+ },
19
+ "files": [
20
+ "assets",
21
+ "dist",
22
+ "docs",
23
+ "README.md",
24
+ "AGENTS.md"
25
+ ],
26
+ "directories": {
27
+ "doc": "docs"
28
+ },
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "dev": "tsx src/cli.ts",
32
+ "lint": "tsc --noEmit",
33
+ "typecheck": "tsc --noEmit",
34
+ "test": "vitest run"
35
+ },
36
+ "keywords": [
37
+ "feishu",
38
+ "lark",
39
+ "rag",
40
+ "local-first",
41
+ "knowledge-base"
42
+ ],
43
+ "author": "FlashingChen2024",
44
+ "license": "MIT",
45
+ "dependencies": {
46
+ "@inquirer/prompts": "^8.4.2",
47
+ "@lancedb/lancedb": "^0.27.2",
48
+ "@larksuiteoapi/node-sdk": "^1.62.0",
49
+ "better-sqlite3": "^12.9.0",
50
+ "commander": "^14.0.3",
51
+ "fastify": "^5.8.5",
52
+ "mammoth": "^1.12.0",
53
+ "pdf-parse": "^2.4.5",
54
+ "pino": "^10.3.1",
55
+ "zod": "^4.3.6"
56
+ },
57
+ "devDependencies": {
58
+ "@types/better-sqlite3": "^7.6.13",
59
+ "@types/node": "^25.6.0",
60
+ "@types/yazl": "^3.3.1",
61
+ "tsup": "^8.5.1",
62
+ "tsx": "^4.21.0",
63
+ "typescript": "^6.0.3",
64
+ "vitest": "^4.1.5",
65
+ "yazl": "^3.3.1"
66
+ }
67
+ }