@pheem49/mint 1.5.5 → 1.6.1

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 (222) hide show
  1. package/.codex +0 -0
  2. package/.github/FUNDING.yml +2 -0
  3. package/.github/workflows/ci.yml +45 -0
  4. package/.github/workflows/release.yml +79 -0
  5. package/Cargo.lock +5792 -0
  6. package/Cargo.toml +32 -0
  7. package/README.md +387 -353
  8. package/assets/icon.png +0 -0
  9. package/bin/mint +0 -0
  10. package/crates/mint-cli/Cargo.toml +23 -0
  11. package/crates/mint-cli/src/agent.rs +851 -0
  12. package/crates/mint-cli/src/gmail.rs +216 -0
  13. package/crates/mint-cli/src/image.rs +142 -0
  14. package/crates/mint-cli/src/main.rs +2837 -0
  15. package/crates/mint-cli/src/mcp.rs +63 -0
  16. package/crates/mint-cli/src/onboard.rs +1149 -0
  17. package/crates/mint-cli/src/setup.rs +390 -0
  18. package/crates/mint-cli/src/skills.rs +8 -0
  19. package/crates/mint-cli/src/updater.rs +279 -0
  20. package/crates/mint-core/Cargo.toml +22 -0
  21. package/crates/mint-core/src/agent_loop.rs +94 -0
  22. package/crates/mint-core/src/api_server.rs +991 -0
  23. package/crates/mint-core/src/channels.rs +248 -0
  24. package/crates/mint-core/src/chat.rs +895 -0
  25. package/crates/mint-core/src/code_tools.rs +729 -0
  26. package/crates/mint-core/src/config.rs +368 -0
  27. package/crates/mint-core/src/files.rs +159 -0
  28. package/crates/mint-core/src/knowledge.rs +541 -0
  29. package/crates/mint-core/src/lib.rs +84 -0
  30. package/crates/mint-core/src/mcp.rs +273 -0
  31. package/crates/mint-core/src/memory.rs +673 -0
  32. package/crates/mint-core/src/orchestration.rs +2157 -0
  33. package/crates/mint-core/src/pictures.rs +314 -0
  34. package/crates/mint-core/src/plugins.rs +727 -0
  35. package/crates/mint-core/src/safety.rs +416 -0
  36. package/crates/mint-core/src/semantic.rs +254 -0
  37. package/crates/mint-core/src/shell.rs +317 -0
  38. package/crates/mint-core/src/skills.rs +71 -0
  39. package/crates/mint-core/src/symbols.rs +157 -0
  40. package/crates/mint-core/src/tasks.rs +308 -0
  41. package/crates/mint-core/src/tts.rs +92 -0
  42. package/crates/mint-core/src/weather.rs +93 -0
  43. package/crates/mint-core/src/web_search.rs +200 -0
  44. package/crates/mint-core/src/workflows.rs +81 -0
  45. package/crates/mint-core/tests/mcp_stdio.rs +45 -0
  46. package/crates/mint-core/tests/memory_persistence.rs +172 -0
  47. package/crates/mint-core/tests/pictures_storage.rs +14 -0
  48. package/crates/mint-core/tests/task_lifecycle.rs +87 -0
  49. package/package.json +35 -99
  50. package/src/bin/index.js +16 -0
  51. package/src/renderer/index-web.html +17 -0
  52. package/src/renderer/index.html +17 -0
  53. package/src/renderer/public/Live2DCubismCore.js +9 -0
  54. package/src/renderer/public/assets/icon.png +0 -0
  55. package/src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.model3.json +36 -0
  56. package/src/renderer/src/App.tsx +33 -0
  57. package/src/renderer/src/calculator.ts +47 -0
  58. package/src/renderer/src/components/ChatPanel.tsx +1598 -0
  59. package/src/renderer/src/components/DashboardSidebar.tsx +358 -0
  60. package/src/renderer/src/components/Live2DStage.tsx +374 -0
  61. package/src/renderer/src/components/MintDashboard.tsx +950 -0
  62. package/src/renderer/src/components/ModelPanel.tsx +154 -0
  63. package/src/renderer/src/components/PicturesLibrary.tsx +46 -0
  64. package/src/renderer/src/components/ProactiveGlow.tsx +19 -0
  65. package/src/renderer/src/components/ScreenPicker.tsx +579 -0
  66. package/src/renderer/src/components/SettingsWindow.tsx +1467 -0
  67. package/src/renderer/src/components/SpotlightWindow.tsx +280 -0
  68. package/src/renderer/src/components/WidgetWindow.tsx +36 -0
  69. package/src/renderer/src/components/WorkspacePanel.tsx +268 -0
  70. package/src/{UI → renderer/src/css}/settings.css +69 -16
  71. package/src/renderer/src/css/spotlight.css +113 -0
  72. package/src/renderer/src/css/styles.css +3722 -0
  73. package/src/renderer/src/css/widget.css +185 -0
  74. package/src/renderer/src/env.d.ts +116 -0
  75. package/src/renderer/src/index.css +379 -0
  76. package/src/renderer/src/main.tsx +13 -0
  77. package/src/renderer/src/tauri.ts +996 -0
  78. package/src/renderer/src-web/App.tsx +25 -0
  79. package/src/renderer/src-web/calculator.ts +47 -0
  80. package/src/renderer/src-web/components/ChatPanel.tsx +1662 -0
  81. package/src/renderer/src-web/components/DashboardSidebar.tsx +242 -0
  82. package/src/renderer/src-web/components/MintDashboard.tsx +763 -0
  83. package/src/renderer/src-web/components/PicturesLibrary.tsx +73 -0
  84. package/src/renderer/src-web/components/SettingsWindow.tsx +1500 -0
  85. package/src/renderer/src-web/css/settings.css +1100 -0
  86. package/src/{UI → renderer/src-web/css}/spotlight.css +4 -4
  87. package/src/{UI → renderer/src-web/css}/styles.css +1055 -159
  88. package/src/{UI → renderer/src-web/css}/widget.css +2 -2
  89. package/src/renderer/src-web/env.d.ts +107 -0
  90. package/src/renderer/src-web/index.css +379 -0
  91. package/src/renderer/src-web/main.tsx +13 -0
  92. package/src/renderer/src-web/tauri.ts +983 -0
  93. package/tsconfig.json +30 -0
  94. package/vite.config.ts +33 -0
  95. package/vite.config.web.ts +51 -0
  96. package/GUIDE_TH.md +0 -125
  97. package/assets/Agent_Mint.png +0 -0
  98. package/assets/CLI_Screen.png +0 -0
  99. package/assets/Settings.png +0 -0
  100. package/benchmark_ai.js +0 -71
  101. package/install.ps1 +0 -64
  102. package/install.sh +0 -54
  103. package/main.js +0 -139
  104. package/mint-cli-logic.js +0 -3
  105. package/mint-cli.js +0 -410
  106. package/models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.model3.json +0 -47
  107. package/models/Shiroko_Model/Shiroko//342/232/241/351/253/230/344/272/256/342/232/241/344/275/277/347/224/250/346/225/231/347/250/213/344/270/216/346/263/250/346/204/217/344/272/213/351/241/271.txt +0 -23
  108. package/preload-picker.js +0 -11
  109. package/preload-settings.js +0 -11
  110. package/preload.js +0 -41
  111. package/scripts/install_linux_desktop_entry.js +0 -48
  112. package/src/AI_Brain/Gemini_API.js +0 -813
  113. package/src/AI_Brain/agent_orchestrator.js +0 -73
  114. package/src/AI_Brain/autonomous_brain.js +0 -179
  115. package/src/AI_Brain/behavior_memory.js +0 -135
  116. package/src/AI_Brain/headless_agent.js +0 -143
  117. package/src/AI_Brain/knowledge_base.js +0 -349
  118. package/src/AI_Brain/memory_store.js +0 -662
  119. package/src/AI_Brain/proactive_engine.js +0 -172
  120. package/src/AI_Brain/provider_adapter.js +0 -365
  121. package/src/Automation_Layer/browser_automation.js +0 -149
  122. package/src/Automation_Layer/file_operations.js +0 -286
  123. package/src/Automation_Layer/open_app.js +0 -85
  124. package/src/Automation_Layer/open_website.js +0 -38
  125. package/src/CLI/approval_handler.js +0 -47
  126. package/src/CLI/chat_router.js +0 -247
  127. package/src/CLI/chat_ui.js +0 -1159
  128. package/src/CLI/cli_colors.js +0 -115
  129. package/src/CLI/cli_formatters.js +0 -94
  130. package/src/CLI/code_agent.js +0 -1667
  131. package/src/CLI/code_session_memory.js +0 -62
  132. package/src/CLI/gmail_auth.js +0 -210
  133. package/src/CLI/image_input.js +0 -90
  134. package/src/CLI/intent_detectors.js +0 -181
  135. package/src/CLI/interactive_chat.js +0 -658
  136. package/src/CLI/list_features.js +0 -64
  137. package/src/CLI/onboarding.js +0 -416
  138. package/src/CLI/repo_summarizer.js +0 -282
  139. package/src/CLI/semantic_code_search.js +0 -312
  140. package/src/CLI/skill_manager.js +0 -41
  141. package/src/CLI/slash_command_handler.js +0 -418
  142. package/src/CLI/symbol_indexer.js +0 -231
  143. package/src/CLI/updater.js +0 -230
  144. package/src/CLI/workspace_manager.js +0 -90
  145. package/src/Channels/brave_search_bridge.js +0 -35
  146. package/src/Channels/discord_bridge.js +0 -66
  147. package/src/Channels/google_search_bridge.js +0 -38
  148. package/src/Channels/line_bridge.js +0 -60
  149. package/src/Channels/slack_bridge.js +0 -48
  150. package/src/Channels/telegram_bridge.js +0 -41
  151. package/src/Channels/whatsapp_bridge.js +0 -57
  152. package/src/Command_Parser/parser.js +0 -45
  153. package/src/Plugins/dev_tools.js +0 -41
  154. package/src/Plugins/discord.js +0 -20
  155. package/src/Plugins/docker.js +0 -47
  156. package/src/Plugins/gmail.js +0 -251
  157. package/src/Plugins/google_calendar.js +0 -252
  158. package/src/Plugins/mcp_manager.js +0 -95
  159. package/src/Plugins/notion.js +0 -256
  160. package/src/Plugins/obsidian.js +0 -54
  161. package/src/Plugins/plugin_manager.js +0 -81
  162. package/src/Plugins/spotify.js +0 -173
  163. package/src/Plugins/system_metrics.js +0 -31
  164. package/src/Plugins/system_monitor.js +0 -72
  165. package/src/System/action_executor.js +0 -178
  166. package/src/System/bridge_manager.js +0 -76
  167. package/src/System/chat_history_manager.js +0 -83
  168. package/src/System/config_manager.js +0 -194
  169. package/src/System/custom_workflows.js +0 -163
  170. package/src/System/daemon_manager.js +0 -67
  171. package/src/System/google_tts_urls.js +0 -51
  172. package/src/System/granular_automation.js +0 -157
  173. package/src/System/ipc_handlers.js +0 -332
  174. package/src/System/notifications.js +0 -23
  175. package/src/System/optional_require.js +0 -23
  176. package/src/System/picture_store.js +0 -109
  177. package/src/System/proactive_loop.js +0 -153
  178. package/src/System/safety_manager.js +0 -273
  179. package/src/System/sandbox_runner.js +0 -182
  180. package/src/System/screen_capture.js +0 -175
  181. package/src/System/smart_context.js +0 -227
  182. package/src/System/system_automation.js +0 -162
  183. package/src/System/system_events.js +0 -79
  184. package/src/System/system_info.js +0 -125
  185. package/src/System/task_manager.js +0 -222
  186. package/src/System/tool_registry.js +0 -293
  187. package/src/System/window_manager.js +0 -220
  188. package/src/UI/floating.css +0 -80
  189. package/src/UI/floating.html +0 -17
  190. package/src/UI/floating.js +0 -67
  191. package/src/UI/live2d_manager.js +0 -600
  192. package/src/UI/preload-floating.js +0 -7
  193. package/src/UI/preload-spotlight.js +0 -11
  194. package/src/UI/preload-widget.js +0 -5
  195. package/src/UI/proactive-glow.html +0 -42
  196. package/src/UI/renderer.js +0 -2127
  197. package/src/UI/screenPicker.html +0 -214
  198. package/src/UI/screenPicker.js +0 -262
  199. package/src/UI/settings.html +0 -577
  200. package/src/UI/settings.js +0 -770
  201. package/src/UI/spotlight.html +0 -23
  202. package/src/UI/spotlight.js +0 -185
  203. package/src/UI/widget.html +0 -29
  204. package/src/UI/widget.js +0 -10
  205. /package/{models → src/renderer/public/models}/Shiroko_Model/Shiroko/Shiroko_Core/72d86db84cfa9730b894c241fd24c0db.png +0 -0
  206. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//345/233/264/350/243/231.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/apron.exp3.json} +0 -0
  207. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//347/214/253/345/222/252/346/273/244/351/225/234.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/catfilter.exp3.json} +0 -0
  208. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//347/202/271/344/270/200/344/270/213.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/click.exp3.json} +0 -0
  209. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//345/221/206/347/214/253.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/dazed.exp3.json} +0 -0
  210. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//345/221/206/347/214/253/347/234/274/347/217/240/346/221/207/346/231/203.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/dazedeyes.exp3.json} +0 -0
  211. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//347/234/274/351/225/234.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/glasses.exp3.json} +0 -0
  212. /package/{models → src/renderer/public/models}/Shiroko_Model/Shiroko/Shiroko_Core/items_pinned_to_model.json +0 -0
  213. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//346/213/277/347/254/224.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/pen.exp3.json} +0 -0
  214. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//346/213/215/347/205/247.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/photo.exp3.json} +0 -0
  215. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_00.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_00.png} +0 -0
  216. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_01.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_01.png} +0 -0
  217. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_02.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_02.png} +0 -0
  218. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_03.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_03.png} +0 -0
  219. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.cdi3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.cdi3.json} +0 -0
  220. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.moc3" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.moc3} +0 -0
  221. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.physics3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.physics3.json} +0 -0
  222. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.vtube.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.vtube.json} +0 -0
@@ -1,349 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const os = require('os');
4
- const crypto = require('crypto');
5
- const { GoogleGenAI } = require('@google/genai');
6
- const pdf = require('pdf-parse');
7
- const mammoth = require('mammoth');
8
- const readXlsxFile = require('read-excel-file/node');
9
- const { readConfig } = require('../System/config_manager');
10
-
11
- // Handle electron dependency safely
12
- let app;
13
- try {
14
- const electron = require('electron');
15
- app = electron.app;
16
- } catch (e) {
17
- app = null;
18
- }
19
-
20
- let ai = null;
21
- let activeApiKey = '';
22
- let DatabaseSync = null;
23
-
24
- function resolveApiKey() {
25
- let settingsKey = '';
26
- try {
27
- const cfg = readConfig();
28
- settingsKey = (cfg.apiKey || '').trim();
29
- } catch (e) {
30
- settingsKey = '';
31
- }
32
- const selectedKey = settingsKey || process.env.GEMINI_API_KEY || '';
33
- activeApiKey = selectedKey;
34
- return selectedKey;
35
- }
36
-
37
- function getAiClient() {
38
- const key = resolveApiKey();
39
- if (!ai || activeApiKey !== key) {
40
- ai = new GoogleGenAI({ apiKey: key });
41
- }
42
- return ai;
43
- }
44
-
45
- function getDbPath() {
46
- const fileName = 'mint-knowledge.sqlite';
47
- const configDir = path.join(os.homedir(), '.config', 'mint');
48
- const dbPath = path.join(configDir, fileName);
49
-
50
- if (!fs.existsSync(configDir)) {
51
- fs.mkdirSync(configDir, { recursive: true });
52
- }
53
-
54
- // Migration Logic
55
- if (!fs.existsSync(dbPath)) {
56
- const electronDb = app && app.getPath ? path.join(app.getPath('userData'), fileName) : null;
57
- const legacyDb = path.join(os.homedir(), '.mint', fileName);
58
-
59
- if (electronDb && fs.existsSync(electronDb)) {
60
- try {
61
- fs.copyFileSync(electronDb, dbPath);
62
- console.log('[RAG] Migrated database from Electron userData');
63
- } catch (e) { console.error('[RAG] Migration from Electron failed:', e); }
64
- } else if (fs.existsSync(legacyDb)) {
65
- try {
66
- fs.copyFileSync(legacyDb, dbPath);
67
- console.log('[RAG] Migrated database from ~/.mint');
68
- } catch (e) { console.error('[RAG] Migration from ~/.mint failed:', e); }
69
- }
70
- }
71
-
72
- return dbPath;
73
- }
74
-
75
- function getDatabaseSync() {
76
- if (!DatabaseSync) {
77
- ({ DatabaseSync } = require('node:sqlite'));
78
- }
79
- return DatabaseSync;
80
- }
81
-
82
- // Initialize Database
83
- let dbInstance = null;
84
- function getDb() {
85
- if (dbInstance) return dbInstance;
86
- const dbPath = getDbPath();
87
- const Database = getDatabaseSync();
88
- dbInstance = new Database(dbPath);
89
-
90
- // Enable WAL mode for better concurrency
91
- dbInstance.exec('PRAGMA journal_mode = WAL;');
92
- dbInstance.exec('PRAGMA synchronous = NORMAL;');
93
-
94
- // Create Tables
95
- dbInstance.exec(`
96
- -- Shared knowledge tables
97
- CREATE TABLE IF NOT EXISTS sources (
98
- id INTEGER PRIMARY KEY AUTOINCREMENT,
99
- path TEXT UNIQUE,
100
- name TEXT,
101
- hash TEXT,
102
- last_indexed DATETIME DEFAULT CURRENT_TIMESTAMP
103
- );
104
- CREATE TABLE IF NOT EXISTS chunks (
105
- id INTEGER PRIMARY KEY AUTOINCREMENT,
106
- source_id INTEGER,
107
- text TEXT,
108
- embedding BLOB,
109
- FOREIGN KEY(source_id) REFERENCES sources(id) ON DELETE CASCADE
110
- );
111
- CREATE INDEX IF NOT EXISTS idx_chunks_source ON chunks(source_id);
112
-
113
- -- Shared memory tables (ensuring consistency)
114
- CREATE TABLE IF NOT EXISTS user_profile (
115
- key TEXT PRIMARY KEY,
116
- value TEXT,
117
- updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
118
- );
119
- CREATE TABLE IF NOT EXISTS session_memories (
120
- id INTEGER PRIMARY KEY AUTOINCREMENT,
121
- summary TEXT NOT NULL,
122
- tags TEXT DEFAULT '',
123
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP
124
- );
125
- CREATE TABLE IF NOT EXISTS usage_patterns (
126
- pattern TEXT PRIMARY KEY,
127
- count INTEGER DEFAULT 1,
128
- last_used DATETIME DEFAULT CURRENT_TIMESTAMP
129
- );
130
- CREATE TABLE IF NOT EXISTS response_cache (
131
- query_hash TEXT PRIMARY KEY,
132
- response TEXT NOT NULL,
133
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP
134
- );
135
- `);
136
- return dbInstance;
137
- }
138
-
139
- async function generateEmbedding(text) {
140
- const client = getAiClient();
141
- const response = await client.models.embedContent({
142
- model: 'gemini-embedding-001',
143
- contents: text,
144
- });
145
- return response.embeddings[0].values;
146
- }
147
-
148
-
149
- function cosineSimilarity(vecA, vecB) {
150
- let dotProduct = 0, normA = 0, normB = 0;
151
- for (let i = 0; i < vecA.length; i++) {
152
- dotProduct += vecA[i] * vecB[i];
153
- normA += vecA[i] * vecA[i];
154
- normB += vecB[i] * vecB[i];
155
- }
156
- return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
157
- }
158
-
159
- function getFileHash(filePath) {
160
- const content = fs.readFileSync(filePath);
161
- return crypto.createHash('md5').update(content).digest('hex');
162
- }
163
-
164
- function chunkText(text, maxChars = 1000, overlap = 200) {
165
- const chunks = [];
166
- let current = 0;
167
- while (current < text.length) {
168
- chunks.push(text.slice(current, current + maxChars));
169
- current += (maxChars - overlap);
170
- if (current >= text.length) break;
171
- }
172
- return chunks;
173
- }
174
-
175
- async function indexFile(filePath) {
176
- try {
177
- if (!fs.existsSync(filePath)) return `ไม่พบไฟล์: ${filePath}`;
178
- const stats = fs.statSync(filePath);
179
- if (stats.isDirectory()) return await indexFolder(filePath);
180
- if (stats.size > 10 * 1024 * 1024) return `ไฟล์ใหญ่เกินไป (> 10MB): ${filePath}`;
181
-
182
- const hash = getFileHash(filePath);
183
- const db = getDb();
184
-
185
- // Check if already indexed and unchanged
186
- const checkStmt = db.prepare("SELECT id, hash FROM sources WHERE path = ?");
187
- const existing = checkStmt.get(filePath);
188
-
189
- if (existing && existing.hash === hash) {
190
- return `⏩ ${path.basename(filePath)} ไม่มีการเปลี่ยนแปลง (ข้ามการอ่าน)`;
191
- }
192
-
193
- console.log(`[RAG] Indexing ${filePath}...`);
194
- let content = '';
195
- const ext = path.extname(filePath).toLowerCase();
196
-
197
- // Extraction logic
198
- if (ext === '.pdf') {
199
- const data = await pdf(fs.readFileSync(filePath));
200
- content = data.text;
201
- } else if (ext === '.docx') {
202
- const res = await mammoth.extractRawText({ path: filePath });
203
- content = res.value;
204
- } else if (ext === '.xlsx') {
205
- const sheets = await readXlsxFile(filePath);
206
- content = sheets
207
- .map(({ sheet, data }) => [
208
- `Sheet: ${sheet}`,
209
- ...data.map(row => row.map(value => value == null ? '' : String(value)).join(','))
210
- ].join('\n'))
211
- .join('\n');
212
- } else {
213
- content = fs.readFileSync(filePath, 'utf8');
214
- }
215
-
216
- if (!content.trim()) return `⚠️ ไฟล์ไม่มีข้อความ: ${filePath}`;
217
-
218
- // Begin transaction
219
- db.exec("BEGIN TRANSACTION");
220
- try {
221
- if (existing) {
222
- db.prepare("DELETE FROM chunks WHERE source_id = ?").run(existing.id);
223
- db.prepare("UPDATE sources SET hash = ?, last_indexed = CURRENT_TIMESTAMP WHERE id = ?").run(hash, existing.id);
224
- } else {
225
- db.prepare("INSERT INTO sources (path, name, hash) VALUES (?, ?, ?)").run(filePath, path.basename(filePath), hash);
226
- }
227
-
228
- const sourceId = existing ? existing.id : db.prepare("SELECT last_insert_rowid() as id").get().id;
229
- const chunks = chunkText(content);
230
-
231
- const insertChunk = db.prepare("INSERT INTO chunks (source_id, text, embedding) VALUES (?, ?, ?)");
232
- for (const chunk of chunks) {
233
- const embedding = await generateEmbedding(chunk);
234
- const embeddingBlob = Buffer.from(new Float32Array(embedding).buffer);
235
- insertChunk.run(sourceId, chunk, embeddingBlob);
236
- }
237
- db.exec("COMMIT");
238
- return `✅ Successfully indexed ${path.basename(filePath)} (${chunks.length} chunks)`;
239
- } catch (e) {
240
- db.exec("ROLLBACK");
241
- throw e;
242
- }
243
- } catch (err) {
244
- console.error('[RAG] Error:', err);
245
- return `❌ Failed to index: ${err.message}`;
246
- }
247
- }
248
-
249
- /**
250
- * Recursively gets all files in a directory asynchronously
251
- */
252
- async function getAllFiles(dirPath, arrayOfFiles = []) {
253
- const files = await fs.promises.readdir(dirPath, { withFileTypes: true });
254
-
255
- for (const file of files) {
256
- const fullPath = path.join(dirPath, file.name);
257
- if (file.isDirectory()) {
258
- await getAllFiles(fullPath, arrayOfFiles);
259
- } else {
260
- arrayOfFiles.push(fullPath);
261
- }
262
- }
263
- return arrayOfFiles;
264
- }
265
-
266
- async function indexFolder(folderPath) {
267
- console.log(`[RAG] Indexing folder: ${folderPath}`);
268
- const files = await getAllFiles(folderPath);
269
- console.log(`[RAG] Found ${files.length} files to check.`);
270
-
271
- // Process in small batches to avoid blocking
272
- const BATCH_SIZE = 5;
273
- let indexedCount = 0;
274
- let skippedCount = 0;
275
-
276
- for (let i = 0; i < files.length; i += BATCH_SIZE) {
277
- const batch = files.slice(i, i + BATCH_SIZE);
278
- await Promise.all(batch.map(async (file) => {
279
- const res = await indexFile(file);
280
- if (res && res.startsWith('✅')) indexedCount++;
281
- else skippedCount++;
282
- }));
283
- }
284
-
285
- console.log(`[RAG] Indexing complete. ${indexedCount} new/updated, ${skippedCount} skipped.`);
286
- return `📂 Folder indexing complete: ${indexedCount} learned, ${skippedCount} skipped.`;
287
- }
288
-
289
- async function searchKnowledge(query, topK = 3) {
290
- const startTime = Date.now();
291
- const db = getDb();
292
- const MAX_CHUNKS_TO_SEARCH = 2000; // Limit search to keep it fast
293
-
294
- const countRes = db.prepare("SELECT COUNT(*) as count FROM chunks").get();
295
- if (!countRes || countRes.count === 0) return null;
296
-
297
- try {
298
- const queryVector = await generateEmbedding(query);
299
- const queryTyped = new Float32Array(queryVector);
300
- const results = [];
301
-
302
- // Search most recent or top chunks first, but limit the total scan
303
- const stmt = db.prepare("SELECT text, embedding, source_id FROM chunks LIMIT ?");
304
- let processed = 0;
305
-
306
- for (const c of stmt.iterate(MAX_CHUNKS_TO_SEARCH)) {
307
- if (!c.embedding) continue;
308
- processed++;
309
-
310
- const chunkVector = new Float32Array(c.embedding.buffer, c.embedding.byteOffset, c.embedding.byteLength / 4);
311
-
312
- let dotProduct = 0, normA = 0, normB = 0;
313
- for (let i = 0; i < queryTyped.length; i++) {
314
- const a = queryTyped[i];
315
- const b = chunkVector[i];
316
- dotProduct += a * b;
317
- normA += a * a;
318
- normB += b * b;
319
- }
320
- const score = dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
321
-
322
- if (score > 0.65) {
323
- results.push({ text: c.text, score, source_id: c.source_id });
324
- }
325
- }
326
-
327
- if (results.length > 0) {
328
- results.sort((a, b) => b.score - a.score);
329
- const top = results.slice(0, topK);
330
-
331
- const sourceIds = [...new Set(top.map(t => t.source_id))];
332
- const sources = db.prepare(`SELECT id, name FROM sources WHERE id IN (${sourceIds.join(',')})`).all();
333
- const sourceMap = Object.fromEntries(sources.map(s => [s.id, s.name]));
334
-
335
- console.log(`[RAG] Search took ${Date.now() - startTime}ms for ${processed} chunks.`);
336
- return top.map(t => ({
337
- text: t.text,
338
- source: sourceMap[t.source_id],
339
- score: t.score
340
- }));
341
- }
342
- } catch (e) {
343
- console.error("[RAG] Search Error:", e);
344
- }
345
- return null;
346
- }
347
-
348
-
349
- module.exports = { indexFile, indexFolder, searchKnowledge };