@jungtz/wiki-router 1.0.1 → 1.0.4

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
@@ -14,83 +14,142 @@ npm install @jungtz/wiki-router
14
14
  ## 運作流程
15
15
 
16
16
  ```
17
- 知識檔案 (JSON/MD) -> build() -> LLM 生成 Wiki (.md) -> getContext(prompt) -> LLM 路由 -> 相關上下文
17
+ 知識來源 -> build() -> LLM 生成 Wiki -> getContext(prompt) -> LLM 路由 -> 相關上下文
18
18
  ```
19
19
 
20
- 1. **build()**: 將知識庫目錄中的 JSON/Markdown 檔案送交 LLM,拆分成結構化 `.md` 維基頁面
20
+ 1. **build()**: 將知識來源 (JSON/Markdown) 送交 LLM,拆分成結構化 `.md` 維基頁面
21
21
  2. **getContext(prompt)**: 根據使用者問題,由 LLM 從 Index.md 中選擇相關檔案,回傳合併後的上下文
22
22
 
23
- ## 使用方法
23
+ 知識的「來源」與 wiki 的「儲存位置」皆透過 **adapter** 介面抽象,可使用內建檔案系統 adapter,亦可自訂 (例如 API + 資料庫),方便支援多租戶 / 多資料集場景。
24
+
25
+ ## 快速開始(檔案系統)
24
26
 
25
27
  ```js
26
28
  const { createWikiRouter } = require('@jungtz/wiki-router')
27
29
  const { createRouter } = require('@jungtz/ai-router')
28
30
 
29
- // 1. 準備 AI Router
30
31
  const router = createRouter({
31
32
  providers: {
32
- 'ollama-local': {
33
- type: 'local',
34
- baseURL: 'http://localhost:11434',
35
- },
33
+ 'ollama-local': { type: 'local', baseURL: 'http://localhost:11434' },
36
34
  },
37
35
  })
38
36
 
39
- // 2. 建立 WikiRouter
40
37
  const wiki = createWikiRouter({
41
- router, // AI Router 實例 (required)
42
- knowledgeDir: './knowledge', // 知識檔案來源目錄 (required)
43
- outputDir: './wiki-output', // Wiki 輸出目錄 (required)
44
- modelId: 'ollama-local/gemma4:31b', // Wiki 生成模型 (可選)
45
- routerModelId: 'ollama-local/gemma4:31b', // 路由選擇模型 (可選)
46
-
38
+ router,
39
+ knowledgeDir: './knowledge', // fs 來源(簡寫)
40
+ outputDir: './wiki-output', // fs 儲存(簡寫)
41
+ modelId: 'ollama-local/gemma4:31b',
47
42
  })
48
43
 
49
- // 3. 建構/更新 Wiki
50
44
  await wiki.build()
51
-
52
- // 4. 查詢相關上下文
53
45
  const ctx = await wiki.getContext('住宿有什麼規定?')
54
- console.log(ctx)
46
+ ```
47
+
48
+ ## 進階:自訂 adapter(多租戶 / API + DB)
49
+
50
+ 當知識來自 API、wiki 要存到資料庫時,傳入 `source` / `store` adapter:
51
+
52
+ ```js
53
+ const { createWikiRouter } = require('@jungtz/wiki-router')
54
+
55
+ function wikiOf(hotelId) {
56
+ return createWikiRouter({
57
+ router,
58
+ modelId: 'ollama-local/gemma4:31b',
59
+ source: {
60
+ async list() { return ['base.json'] },
61
+ async read() {
62
+ const res = await fetch(`/api/hotels/${hotelId}/knowledge`)
63
+ return { type: 'json', content: await res.text() }
64
+ },
65
+ },
66
+ store: {
67
+ async list() { return await db.wiki.list(hotelId) },
68
+ async read(filename) { return await db.wiki.read(hotelId, filename) },
69
+ async write(name, body) { await db.wiki.upsert(hotelId, name, body) },
70
+ },
71
+ })
72
+ }
73
+
74
+ const wikiA = wikiOf(4) // 旅館 A
75
+ const wikiB = wikiOf(7) // 旅館 B
55
76
  ```
56
77
 
57
78
  ## API
58
79
 
59
80
  ### `createWikiRouter(config)`
60
81
 
61
- 建立 WikiRouter 實例。
62
-
63
82
  | 參數 | 類型 | 必要 | 說明 |
64
83
  |------|------|------|------|
65
84
  | `router` | `AIProviderRouter` | ✅ | AI Router 實例 |
66
- | `knowledgeDir` | `string` | | 知識檔案來源目錄 |
67
- | `outputDir` | `string` | | Wiki 輸出目錄 |
85
+ | `source` | `Source` | | Knowledge 來源 adapter(與 `knowledgeDir` 二選一) |
86
+ | `store` | `Store` | | Wiki 儲存 adapter(與 `outputDir` 二選一) |
87
+ | `knowledgeDir` | `string` | ✱ | 簡寫:等同 `source: fsSource(dir)` |
88
+ | `outputDir` | `string` | ✱ | 簡寫:等同 `store: fsStore(dir)` |
68
89
  | `modelId` | `string` | | Wiki 生成模型,格式 `provider/model` |
69
90
  | `routerModelId` | `string` | | 路由選擇模型,預設同 `modelId` |
91
+ | `timeout` | `number` | | LLM 對話逾時毫秒數,預設 `300000` (5 分鐘) |
92
+ | `splitPrompt` | `string` | | 自訂 Split prompt |
93
+ | `mergePrompt` | `string` | | 自訂 Merge prompt |
94
+ | `routerPrompt` | `string` | | 自訂 Router prompt |
70
95
 
96
+ ✱ `source` 與 `knowledgeDir` 至少擇一;`store` 與 `outputDir` 至少擇一。
71
97
 
72
98
  ### `wiki.build()`
73
99
 
74
100
  建構或增量更新 Wiki 知識庫。回傳 `Promise<boolean>`。
75
101
 
76
- - 首次執行:為每個 JSON 檔案執行 split prompt,拆分成多個 `.md`
77
- - 後續執行:使用 merge prompt,將新內容合併到既有檔案
102
+ - 首次(`store.list()` 為空):對 JSON 來源執行 split prompt,拆分成多個 `.md`
103
+ - 後續:使用 merge prompt,將新來源合併到既有檔案
78
104
 
79
105
  ### `wiki.getContext(prompt)`
80
106
 
81
107
  根據使用者問題取得相關 Wiki 上下文。回傳 `Promise<string>`。
82
108
 
83
- - 若 Wiki 目錄為空,自動調用 `build()`
84
- - 由 LLM 根據 Index.md 選擇最相關的檔案
85
- - 回傳合併後的 Markdown 內容,無相關檔案時回傳空字串
109
+ - 若 store 為空,自動調用 `build()`
110
+ - 由 LLM 根據 `Index.md` 選擇最相關的檔案
111
+ - 回傳合併後的 Markdown 內容;無相關檔案時回傳空字串
112
+
113
+ ## Adapter 介面
114
+
115
+ ### `Source`
116
+
117
+ ```ts
118
+ interface Source {
119
+ list(): Promise<string[]> // 來源 key 清單
120
+ read(key: string): Promise<{ type: 'json' | 'markdown', content: string }>
121
+ }
122
+ ```
123
+
124
+ ### `Store`
125
+
126
+ ```ts
127
+ interface Store {
128
+ list(): Promise<string[]> // 已生成的 wiki 檔名(含 .md)
129
+ read(filename: string): Promise<string | null> // 不存在回 null
130
+ write(filename: string, content: string): Promise<void>
131
+ }
132
+ ```
133
+
134
+ ### 內建 adapter
135
+
136
+ ```js
137
+ import { fsSource, fsStore } from '@jungtz/wiki-router'
138
+
139
+ createWikiRouter({
140
+ router,
141
+ source: fsSource('./knowledge'),
142
+ store: fsStore('./wiki-output'),
143
+ })
144
+ ```
145
+
146
+ `knowledgeDir` / `outputDir` 簡寫即在內部分別包成 `fsSource` / `fsStore`。
86
147
 
87
148
  ## 子模組
88
149
 
89
150
  ### 解析器
90
151
 
91
152
  ```js
92
- const { parseWikiOutput } = require('@jungtz/wiki-router')
93
- // 或
94
153
  import { parseWikiOutput } from '@jungtz/wiki-router/parser'
95
154
 
96
155
  const files = parseWikiOutput(llmResponse)
@@ -99,22 +158,57 @@ const files = parseWikiOutput(llmResponse)
99
158
 
100
159
  ### 提示詞模板
101
160
 
161
+ 三個內建 prompt 定義於 `src/prompts/*.md`,build 時自動 inline 進 dist:
162
+
163
+ | 檔案 | 匯出名稱 | 用途 |
164
+ |------|----------|------|
165
+ | `src/prompts/split.md` | `SPLIT_PROMPT` | 將 JSON 資料拆分為多個 `.md` 檔案 |
166
+ | `src/prompts/merge.md` | `MERGE_PROMPT` | 將新內容合併到既有 Wiki 檔案 |
167
+ | `src/prompts/router.md` | `ROUTER_PROMPT` | 根據使用者問題選擇相關檔案 |
168
+
102
169
  ```js
103
170
  import { SPLIT_PROMPT, MERGE_PROMPT, ROUTER_PROMPT } from '@jungtz/wiki-router/prompts'
104
171
  ```
105
172
 
106
- ## 知識庫目錄結構
173
+ #### 自訂 Prompt
174
+
175
+ 於 `createWikiRouter` 設定中傳入 `splitPrompt` / `mergePrompt` / `routerPrompt` 字串可在 runtime 動態覆蓋;不傳則使用內建預設。
107
176
 
177
+ ```js
178
+ const wiki = createWikiRouter({
179
+ router,
180
+ knowledgeDir: './knowledge',
181
+ outputDir: './wiki-output',
182
+ mergePrompt: readFileSync('./my-custom-merge.md', 'utf-8'),
183
+ })
108
184
  ```
109
- my-project/
110
- ├── knowledge/ # 放入 JSON 或 Markdown 知識檔案
111
- │ ├── base.json
112
- │ └── faq.md
113
- ├── wiki-output/ # build() 後自動生成
114
- │ ├── Index.md
115
- │ ├── Rooms.md
116
- │ ├── Facilities.md
117
- │ └── ...
185
+
186
+ ## 範例
187
+
188
+ - `examples/basic.js` — 檔案系統用法
189
+ - `examples/multi-tenant.js` — 多租戶 (API + DB) 用法
190
+
191
+ ## 互動預覽
192
+
193
+ 內建互動式 TUI,可在終端直接問答測試 Wiki 路由效果:
194
+
195
+ ```bash
196
+ npm run preview
197
+
198
+ # 自訂路徑
199
+ npm run preview -- --knowledge ./my-knowledge --output ./my-wiki
200
+ ```
201
+
202
+ 支援指令:`:list` 查看維基頁面、`:build` 重建維基、`:files` 顯示檔案、`:quit` 離開。
203
+
204
+ ## 發布腳本
205
+
206
+ ```bash
207
+ npm run bump:patch # 版號 patch +1 並自動 git commit + tag
208
+ npm run bump:minor # 版號 minor +1
209
+ npm run bump:major # 版號 major +1
210
+ npm run push:version # 推送 commit 與 tag 至 remote
211
+ npm run release # bump:patch + push:version
118
212
  ```
119
213
 
120
214
  ## 錯誤處理