@nanocollective/get-md 1.0.2 → 1.1.0-beta.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.
- package/LICENSE +1 -1
- package/README.md +155 -1
- package/dist/cli.js +388 -4
- package/dist/cli.js.map +1 -1
- package/dist/cli.spec.js +187 -0
- package/dist/cli.spec.js.map +1 -1
- package/dist/converters/llm-converter.d.ts +71 -0
- package/dist/converters/llm-converter.d.ts.map +1 -0
- package/dist/converters/llm-converter.js +191 -0
- package/dist/converters/llm-converter.js.map +1 -0
- package/dist/converters/llm-converter.spec.d.ts +2 -0
- package/dist/converters/llm-converter.spec.d.ts.map +1 -0
- package/dist/converters/llm-converter.spec.js +281 -0
- package/dist/converters/llm-converter.spec.js.map +1 -0
- package/dist/converters/llm-manager.d.ts +88 -0
- package/dist/converters/llm-manager.d.ts.map +1 -0
- package/dist/converters/llm-manager.js +277 -0
- package/dist/converters/llm-manager.js.map +1 -0
- package/dist/converters/llm-manager.spec.d.ts +2 -0
- package/dist/converters/llm-manager.spec.d.ts.map +1 -0
- package/dist/converters/llm-manager.spec.js +280 -0
- package/dist/converters/llm-manager.spec.js.map +1 -0
- package/dist/extractors/metadata-extractor.js +1 -1
- package/dist/extractors/metadata-extractor.js.map +1 -1
- package/dist/index.d.ts +14 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -10
- package/dist/index.js.map +1 -1
- package/dist/index.spec.js +172 -1
- package/dist/index.spec.js.map +1 -1
- package/dist/optimizers/html-cleaner.js +1 -1
- package/dist/optimizers/html-cleaner.js.map +1 -1
- package/dist/optimizers/html-cleaner.spec.js +1 -0
- package/dist/optimizers/html-cleaner.spec.js.map +1 -1
- package/dist/optimizers/llm-formatter.js +2 -2
- package/dist/optimizers/llm-formatter.js.map +1 -1
- package/dist/optimizers/structure-enhancer.js +3 -3
- package/dist/optimizers/structure-enhancer.js.map +1 -1
- package/dist/optimizers/structure-enhancer.spec.js +1 -1
- package/dist/optimizers/structure-enhancer.spec.js.map +1 -1
- package/dist/parsers/markdown-parser.d.ts +36 -0
- package/dist/parsers/markdown-parser.d.ts.map +1 -1
- package/dist/parsers/markdown-parser.js +267 -45
- package/dist/parsers/markdown-parser.js.map +1 -1
- package/dist/parsers/markdown-parser.spec.js +106 -98
- package/dist/parsers/markdown-parser.spec.js.map +1 -1
- package/dist/types.d.ts +149 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/config-loader.d.ts +62 -0
- package/dist/utils/config-loader.d.ts.map +1 -0
- package/dist/utils/config-loader.js +167 -0
- package/dist/utils/config-loader.js.map +1 -0
- package/dist/utils/config-loader.spec.d.ts +2 -0
- package/dist/utils/config-loader.spec.d.ts.map +1 -0
- package/dist/utils/config-loader.spec.js +355 -0
- package/dist/utils/config-loader.spec.js.map +1 -0
- package/dist/utils/url-fetcher.d.ts.map +1 -1
- package/dist/utils/url-fetcher.js +1 -1
- package/dist/utils/url-fetcher.js.map +1 -1
- package/dist/utils/validators.js +1 -1
- package/dist/utils/validators.js.map +1 -1
- package/package.json +25 -17
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// src/converters/llm-converter.spec.ts
|
|
2
|
+
import test from "ava";
|
|
3
|
+
import { LLMConverter, createLLMConverter } from "./llm-converter.js";
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Note on Testing Strategy
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// These tests focus on the LLMConverter's interface, configuration, and
|
|
8
|
+
// error handling without requiring an actual model file. Tests that would
|
|
9
|
+
// require loading a real ~1GB model are marked as integration tests and
|
|
10
|
+
// should be run separately with the model downloaded.
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Constructor Tests
|
|
14
|
+
// ============================================================================
|
|
15
|
+
test("LLMConverter: constructor creates instance with required options", (t) => {
|
|
16
|
+
const converter = new LLMConverter({
|
|
17
|
+
modelPath: "/path/to/model.gguf",
|
|
18
|
+
});
|
|
19
|
+
t.truthy(converter);
|
|
20
|
+
t.is(typeof converter.loadModel, "function");
|
|
21
|
+
t.is(typeof converter.convert, "function");
|
|
22
|
+
t.is(typeof converter.unload, "function");
|
|
23
|
+
t.is(typeof converter.isLoaded, "function");
|
|
24
|
+
});
|
|
25
|
+
test("LLMConverter: constructor accepts optional temperature", (t) => {
|
|
26
|
+
const converter = new LLMConverter({
|
|
27
|
+
modelPath: "/path/to/model.gguf",
|
|
28
|
+
temperature: 0.5,
|
|
29
|
+
});
|
|
30
|
+
t.truthy(converter);
|
|
31
|
+
});
|
|
32
|
+
test("LLMConverter: constructor accepts optional maxTokens", (t) => {
|
|
33
|
+
const converter = new LLMConverter({
|
|
34
|
+
modelPath: "/path/to/model.gguf",
|
|
35
|
+
maxTokens: 1000,
|
|
36
|
+
});
|
|
37
|
+
t.truthy(converter);
|
|
38
|
+
});
|
|
39
|
+
test("LLMConverter: constructor accepts optional event callback", (t) => {
|
|
40
|
+
const events = [];
|
|
41
|
+
const onEvent = (event) => {
|
|
42
|
+
events.push(event);
|
|
43
|
+
};
|
|
44
|
+
const converter = new LLMConverter({
|
|
45
|
+
modelPath: "/path/to/model.gguf",
|
|
46
|
+
onEvent,
|
|
47
|
+
});
|
|
48
|
+
t.truthy(converter);
|
|
49
|
+
});
|
|
50
|
+
test("LLMConverter: constructor accepts all options together", (t) => {
|
|
51
|
+
const converter = new LLMConverter({
|
|
52
|
+
modelPath: "/path/to/model.gguf",
|
|
53
|
+
temperature: 0.2,
|
|
54
|
+
maxTokens: 10000,
|
|
55
|
+
onEvent: () => { },
|
|
56
|
+
});
|
|
57
|
+
t.truthy(converter);
|
|
58
|
+
});
|
|
59
|
+
// ============================================================================
|
|
60
|
+
// isLoaded Tests
|
|
61
|
+
// ============================================================================
|
|
62
|
+
test("LLMConverter: isLoaded returns false before loading", (t) => {
|
|
63
|
+
const converter = new LLMConverter({
|
|
64
|
+
modelPath: "/path/to/model.gguf",
|
|
65
|
+
});
|
|
66
|
+
t.false(converter.isLoaded());
|
|
67
|
+
});
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// Error Handling Tests
|
|
70
|
+
// ============================================================================
|
|
71
|
+
test("LLMConverter: convert throws if model not loaded", async (t) => {
|
|
72
|
+
const converter = new LLMConverter({
|
|
73
|
+
modelPath: "/path/to/model.gguf",
|
|
74
|
+
});
|
|
75
|
+
await t.throwsAsync(async () => {
|
|
76
|
+
await converter.convert("<h1>Test</h1>");
|
|
77
|
+
}, { message: /Model not loaded/ });
|
|
78
|
+
});
|
|
79
|
+
test("LLMConverter: loadModel throws for non-existent model file", async (t) => {
|
|
80
|
+
const converter = new LLMConverter({
|
|
81
|
+
modelPath: "/nonexistent/path/to/model.gguf",
|
|
82
|
+
});
|
|
83
|
+
await t.throwsAsync(async () => {
|
|
84
|
+
await converter.loadModel();
|
|
85
|
+
}, { message: /Failed to load LLM model/ });
|
|
86
|
+
});
|
|
87
|
+
// ============================================================================
|
|
88
|
+
// unload Tests
|
|
89
|
+
// ============================================================================
|
|
90
|
+
test("LLMConverter: unload works even if model not loaded", async (t) => {
|
|
91
|
+
const converter = new LLMConverter({
|
|
92
|
+
modelPath: "/path/to/model.gguf",
|
|
93
|
+
});
|
|
94
|
+
// Should not throw
|
|
95
|
+
await t.notThrowsAsync(async () => {
|
|
96
|
+
await converter.unload();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
test("LLMConverter: unload can be called multiple times", async (t) => {
|
|
100
|
+
const converter = new LLMConverter({
|
|
101
|
+
modelPath: "/path/to/model.gguf",
|
|
102
|
+
});
|
|
103
|
+
await t.notThrowsAsync(async () => {
|
|
104
|
+
await converter.unload();
|
|
105
|
+
await converter.unload();
|
|
106
|
+
await converter.unload();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
// ============================================================================
|
|
110
|
+
// createLLMConverter Factory Function Tests
|
|
111
|
+
// ============================================================================
|
|
112
|
+
test("createLLMConverter: creates LLMConverter instance", (t) => {
|
|
113
|
+
const converter = createLLMConverter({
|
|
114
|
+
modelPath: "/path/to/model.gguf",
|
|
115
|
+
});
|
|
116
|
+
t.truthy(converter);
|
|
117
|
+
t.true(converter instanceof LLMConverter);
|
|
118
|
+
});
|
|
119
|
+
test("createLLMConverter: passes all options to constructor", (t) => {
|
|
120
|
+
const events = [];
|
|
121
|
+
const converter = createLLMConverter({
|
|
122
|
+
modelPath: "/path/to/model.gguf",
|
|
123
|
+
temperature: 0.3,
|
|
124
|
+
maxTokens: 5000,
|
|
125
|
+
onEvent: (event) => {
|
|
126
|
+
events.push(event);
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
t.truthy(converter);
|
|
130
|
+
t.false(converter.isLoaded());
|
|
131
|
+
});
|
|
132
|
+
// ============================================================================
|
|
133
|
+
// Event Emission Tests (Without Model)
|
|
134
|
+
// ============================================================================
|
|
135
|
+
test("LLMConverter: emits model-loading event on loadModel attempt", async (t) => {
|
|
136
|
+
const events = [];
|
|
137
|
+
const converter = new LLMConverter({
|
|
138
|
+
modelPath: "/nonexistent/model.gguf",
|
|
139
|
+
onEvent: (event) => {
|
|
140
|
+
events.push(event);
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
try {
|
|
144
|
+
await converter.loadModel();
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
// Expected to fail
|
|
148
|
+
}
|
|
149
|
+
// Should have emitted model-loading event before failing
|
|
150
|
+
t.true(events.some((e) => e.type === "model-loading"));
|
|
151
|
+
});
|
|
152
|
+
// ============================================================================
|
|
153
|
+
// Type Safety Tests
|
|
154
|
+
// ============================================================================
|
|
155
|
+
test("types: LLMConverter interface is correctly typed", (t) => {
|
|
156
|
+
// This test verifies TypeScript types at compile time
|
|
157
|
+
const converter = new LLMConverter({
|
|
158
|
+
modelPath: "/path/to/model.gguf",
|
|
159
|
+
});
|
|
160
|
+
// Verify methods exist and are functions
|
|
161
|
+
t.is(typeof converter.loadModel, "function");
|
|
162
|
+
t.is(typeof converter.convert, "function");
|
|
163
|
+
t.is(typeof converter.unload, "function");
|
|
164
|
+
t.is(typeof converter.isLoaded, "function");
|
|
165
|
+
});
|
|
166
|
+
// ============================================================================
|
|
167
|
+
// Event Type Tests
|
|
168
|
+
// ============================================================================
|
|
169
|
+
test("types: LLMEvent union covers model-loading", (t) => {
|
|
170
|
+
const event = {
|
|
171
|
+
type: "model-loading",
|
|
172
|
+
modelName: "ReaderLM-v2",
|
|
173
|
+
};
|
|
174
|
+
t.is(event.type, "model-loading");
|
|
175
|
+
});
|
|
176
|
+
test("types: LLMEvent union covers model-loaded", (t) => {
|
|
177
|
+
const event = {
|
|
178
|
+
type: "model-loaded",
|
|
179
|
+
loadTime: 1000,
|
|
180
|
+
};
|
|
181
|
+
t.is(event.type, "model-loaded");
|
|
182
|
+
t.is(event.loadTime, 1000);
|
|
183
|
+
});
|
|
184
|
+
test("types: LLMEvent union covers conversion-start", (t) => {
|
|
185
|
+
const event = {
|
|
186
|
+
type: "conversion-start",
|
|
187
|
+
inputSize: 5000,
|
|
188
|
+
};
|
|
189
|
+
t.is(event.type, "conversion-start");
|
|
190
|
+
t.is(event.inputSize, 5000);
|
|
191
|
+
});
|
|
192
|
+
test("types: LLMEvent union covers conversion-progress", (t) => {
|
|
193
|
+
const event = {
|
|
194
|
+
type: "conversion-progress",
|
|
195
|
+
tokensProcessed: 100,
|
|
196
|
+
};
|
|
197
|
+
t.is(event.type, "conversion-progress");
|
|
198
|
+
t.is(event.tokensProcessed, 100);
|
|
199
|
+
});
|
|
200
|
+
test("types: LLMEvent union covers conversion-complete", (t) => {
|
|
201
|
+
const event = {
|
|
202
|
+
type: "conversion-complete",
|
|
203
|
+
outputSize: 3000,
|
|
204
|
+
duration: 5000,
|
|
205
|
+
};
|
|
206
|
+
t.is(event.type, "conversion-complete");
|
|
207
|
+
t.is(event.outputSize, 3000);
|
|
208
|
+
t.is(event.duration, 5000);
|
|
209
|
+
});
|
|
210
|
+
test("types: LLMEvent union covers conversion-error", (t) => {
|
|
211
|
+
const event = {
|
|
212
|
+
type: "conversion-error",
|
|
213
|
+
error: new Error("Test error"),
|
|
214
|
+
};
|
|
215
|
+
t.is(event.type, "conversion-error");
|
|
216
|
+
t.is(event.error.message, "Test error");
|
|
217
|
+
});
|
|
218
|
+
// ============================================================================
|
|
219
|
+
// Edge Cases
|
|
220
|
+
// ============================================================================
|
|
221
|
+
test("LLMConverter: handles empty HTML input for convert (after model loaded error)", async (t) => {
|
|
222
|
+
const converter = new LLMConverter({
|
|
223
|
+
modelPath: "/path/to/model.gguf",
|
|
224
|
+
});
|
|
225
|
+
// Should fail because model not loaded, not because of empty input
|
|
226
|
+
await t.throwsAsync(async () => {
|
|
227
|
+
await converter.convert("");
|
|
228
|
+
}, { message: /Model not loaded/ });
|
|
229
|
+
});
|
|
230
|
+
test("LLMConverter: handles very long HTML input for convert (after model loaded error)", async (t) => {
|
|
231
|
+
const converter = new LLMConverter({
|
|
232
|
+
modelPath: "/path/to/model.gguf",
|
|
233
|
+
});
|
|
234
|
+
const longHtml = "<p>" + "x".repeat(100000) + "</p>";
|
|
235
|
+
// Should fail because model not loaded, not because of length
|
|
236
|
+
await t.throwsAsync(async () => {
|
|
237
|
+
await converter.convert(longHtml);
|
|
238
|
+
}, { message: /Model not loaded/ });
|
|
239
|
+
});
|
|
240
|
+
test("LLMConverter: temperature defaults are reasonable", (t) => {
|
|
241
|
+
// Default temperature should be low (0.1) for consistent output
|
|
242
|
+
// We can't directly test the default, but we can verify the class accepts it
|
|
243
|
+
const converter = createLLMConverter({
|
|
244
|
+
modelPath: "/path/to/model.gguf",
|
|
245
|
+
// Not specifying temperature - should use default
|
|
246
|
+
});
|
|
247
|
+
t.truthy(converter);
|
|
248
|
+
});
|
|
249
|
+
test("LLMConverter: maxTokens defaults are reasonable", (t) => {
|
|
250
|
+
// Default maxTokens should be high (512000) to handle long documents
|
|
251
|
+
// We can't directly test the default, but we can verify the class accepts it
|
|
252
|
+
const converter = createLLMConverter({
|
|
253
|
+
modelPath: "/path/to/model.gguf",
|
|
254
|
+
// Not specifying maxTokens - should use default
|
|
255
|
+
});
|
|
256
|
+
t.truthy(converter);
|
|
257
|
+
});
|
|
258
|
+
// ============================================================================
|
|
259
|
+
// Async Event Callback Tests
|
|
260
|
+
// ============================================================================
|
|
261
|
+
test("LLMConverter: async event callback is supported", async (t) => {
|
|
262
|
+
const events = [];
|
|
263
|
+
const converter = new LLMConverter({
|
|
264
|
+
modelPath: "/nonexistent/model.gguf",
|
|
265
|
+
onEvent: async (event) => {
|
|
266
|
+
// Simulate async operation
|
|
267
|
+
await new Promise((resolve) => setTimeout(resolve, 1));
|
|
268
|
+
events.push(event);
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
try {
|
|
272
|
+
await converter.loadModel();
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
// Expected to fail
|
|
276
|
+
}
|
|
277
|
+
// Give time for async callback to complete
|
|
278
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
279
|
+
t.true(events.length > 0);
|
|
280
|
+
});
|
|
281
|
+
//# sourceMappingURL=llm-converter.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-converter.spec.js","sourceRoot":"","sources":["../../src/converters/llm-converter.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { LLMDownloadOptions, LLMEventCallback, LLMModelInfo, LLMModelStatus } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* LLM Manager - handles model availability checking, downloading, and management
|
|
4
|
+
*/
|
|
5
|
+
export declare class LLMManager {
|
|
6
|
+
private modelPath;
|
|
7
|
+
private eventCallback?;
|
|
8
|
+
constructor(options?: {
|
|
9
|
+
modelPath?: string;
|
|
10
|
+
onEvent?: LLMEventCallback;
|
|
11
|
+
});
|
|
12
|
+
/**
|
|
13
|
+
* Emit an event to the callback if registered
|
|
14
|
+
*/
|
|
15
|
+
private emit;
|
|
16
|
+
/**
|
|
17
|
+
* Check if the model is available locally
|
|
18
|
+
*/
|
|
19
|
+
checkModel(): Promise<LLMModelStatus>;
|
|
20
|
+
/**
|
|
21
|
+
* Get the model path
|
|
22
|
+
*/
|
|
23
|
+
getModelPath(): string;
|
|
24
|
+
/**
|
|
25
|
+
* Download the model with progress tracking
|
|
26
|
+
*/
|
|
27
|
+
downloadModel(options?: LLMDownloadOptions): Promise<string>;
|
|
28
|
+
/**
|
|
29
|
+
* Remove the downloaded model
|
|
30
|
+
*/
|
|
31
|
+
removeModel(): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Get information about available models
|
|
34
|
+
*/
|
|
35
|
+
static getModelInfo(): LLMModelInfo;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if the LLM model is available locally
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const status = await checkLLMModel();
|
|
43
|
+
* console.log(status.available); // false
|
|
44
|
+
* console.log(status.path); // ~/.get-md/models/ReaderLM-v2-Q4_K_M.gguf
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function checkLLMModel(options?: {
|
|
48
|
+
modelPath?: string;
|
|
49
|
+
}): Promise<LLMModelStatus>;
|
|
50
|
+
/**
|
|
51
|
+
* Download the LLM model with progress tracking
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* await downloadLLMModel({
|
|
56
|
+
* onProgress: (downloaded, total, percentage) => {
|
|
57
|
+
* console.log(`Downloading: ${percentage.toFixed(1)}%`);
|
|
58
|
+
* },
|
|
59
|
+
* onComplete: (path) => {
|
|
60
|
+
* console.log(`Model ready at: ${path}`);
|
|
61
|
+
* }
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function downloadLLMModel(options?: LLMDownloadOptions): Promise<string>;
|
|
66
|
+
/**
|
|
67
|
+
* Remove the downloaded LLM model
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* await removeLLMModel();
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function removeLLMModel(options?: {
|
|
75
|
+
modelPath?: string;
|
|
76
|
+
}): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Get information about the LLM model
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* const info = getLLMModelInfo();
|
|
83
|
+
* console.log(info.recommendedModel); // "ReaderLM-v2-Q4_K_M"
|
|
84
|
+
* console.log(info.defaultPath); // ~/.get-md/models/ReaderLM-v2-Q4_K_M.gguf
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export declare function getLLMModelInfo(): LLMModelInfo;
|
|
88
|
+
//# sourceMappingURL=llm-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-manager.d.ts","sourceRoot":"","sources":["../../src/converters/llm-manager.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,cAAc,EAEf,MAAM,aAAa,CAAC;AAuErB;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAC,CAAmB;gBAE7B,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,gBAAgB,CAAA;KAAE;IAKxE;;OAEG;YACW,IAAI;IAMlB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,cAAc,CAAC;IAiC3C;;OAEG;IACH,YAAY,IAAI,MAAM;IAItB;;OAEG;IACG,aAAa,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IA0ElE;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAYlC;;OAEG;IACH,MAAM,CAAC,YAAY,IAAI,YAAY;CAOpC;AAMD;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,OAAO,CAAC,EAAE;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,cAAc,CAAC,CAG1B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,OAAO,CAAC,EAAE;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhB;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAE9C"}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
// src/converters/llm-manager.ts
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as os from "node:os";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { createModelDownloader } from "node-llama-cpp";
|
|
6
|
+
// Model configuration
|
|
7
|
+
// Using mradermacher's public mirror since jinaai's repo requires authentication
|
|
8
|
+
const MODEL_CONFIG = {
|
|
9
|
+
name: "ReaderLM-v2-Q4_K_M",
|
|
10
|
+
huggingFaceRepo: "mradermacher/ReaderLM-v2-GGUF",
|
|
11
|
+
fileName: "ReaderLM-v2.Q4_K_M.gguf",
|
|
12
|
+
size: 1120 * 1024 * 1024, // ~1.12GB in bytes
|
|
13
|
+
quantization: "Q4_K_M",
|
|
14
|
+
ramRequired: "2-4GB",
|
|
15
|
+
version: "2.0",
|
|
16
|
+
};
|
|
17
|
+
// Available model variants for future use
|
|
18
|
+
// Sizes from mradermacher/ReaderLM-v2-GGUF public mirror
|
|
19
|
+
const MODEL_VARIANTS = [
|
|
20
|
+
{
|
|
21
|
+
name: "ReaderLM-v2-Q2_K",
|
|
22
|
+
size: 753 * 1024 * 1024, // 753MB
|
|
23
|
+
quantization: "Q2_K",
|
|
24
|
+
ramRequired: "1-2GB",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: "ReaderLM-v2-Q4_K_M",
|
|
28
|
+
size: 1120 * 1024 * 1024, // 1.12GB
|
|
29
|
+
quantization: "Q4_K_M",
|
|
30
|
+
ramRequired: "2-4GB",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "ReaderLM-v2-Q8_0",
|
|
34
|
+
size: 1890 * 1024 * 1024, // 1.89GB
|
|
35
|
+
quantization: "Q8_0",
|
|
36
|
+
ramRequired: "3-5GB",
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
/**
|
|
40
|
+
* Formats bytes into a human-readable string
|
|
41
|
+
*/
|
|
42
|
+
function formatBytes(bytes) {
|
|
43
|
+
if (bytes < 1024)
|
|
44
|
+
return `${bytes}B`;
|
|
45
|
+
if (bytes < 1024 * 1024)
|
|
46
|
+
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
47
|
+
if (bytes < 1024 * 1024 * 1024)
|
|
48
|
+
return `${(bytes / (1024 * 1024)).toFixed(0)}MB`;
|
|
49
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)}GB`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Gets the default model directory path
|
|
53
|
+
* Stored in ~/.get-md/models/
|
|
54
|
+
*/
|
|
55
|
+
function getDefaultModelDir() {
|
|
56
|
+
return path.join(os.homedir(), ".get-md", "models");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Gets the default model file path
|
|
60
|
+
*/
|
|
61
|
+
function getDefaultModelPath() {
|
|
62
|
+
return path.join(getDefaultModelDir(), MODEL_CONFIG.fileName);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Ensures the model directory exists
|
|
66
|
+
*/
|
|
67
|
+
async function ensureModelDir(modelPath) {
|
|
68
|
+
const dir = path.dirname(modelPath);
|
|
69
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* LLM Manager - handles model availability checking, downloading, and management
|
|
73
|
+
*/
|
|
74
|
+
export class LLMManager {
|
|
75
|
+
modelPath;
|
|
76
|
+
eventCallback;
|
|
77
|
+
constructor(options) {
|
|
78
|
+
this.modelPath = options?.modelPath ?? getDefaultModelPath();
|
|
79
|
+
this.eventCallback = options?.onEvent;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Emit an event to the callback if registered
|
|
83
|
+
*/
|
|
84
|
+
async emit(event) {
|
|
85
|
+
if (this.eventCallback) {
|
|
86
|
+
await this.eventCallback(event);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if the model is available locally
|
|
91
|
+
*/
|
|
92
|
+
async checkModel() {
|
|
93
|
+
await this.emit({ type: "model-check", status: "checking" });
|
|
94
|
+
try {
|
|
95
|
+
const stats = await fs.promises.stat(this.modelPath);
|
|
96
|
+
if (stats.isFile() && stats.size > 0) {
|
|
97
|
+
await this.emit({
|
|
98
|
+
type: "model-check",
|
|
99
|
+
status: "found",
|
|
100
|
+
path: this.modelPath,
|
|
101
|
+
});
|
|
102
|
+
return {
|
|
103
|
+
available: true,
|
|
104
|
+
path: this.modelPath,
|
|
105
|
+
size: stats.size,
|
|
106
|
+
sizeFormatted: formatBytes(stats.size),
|
|
107
|
+
version: MODEL_CONFIG.version,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// File doesn't exist
|
|
113
|
+
}
|
|
114
|
+
await this.emit({ type: "model-check", status: "not-found" });
|
|
115
|
+
return {
|
|
116
|
+
available: false,
|
|
117
|
+
path: this.modelPath,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get the model path
|
|
122
|
+
*/
|
|
123
|
+
getModelPath() {
|
|
124
|
+
return this.modelPath;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Download the model with progress tracking
|
|
128
|
+
*/
|
|
129
|
+
async downloadModel(options) {
|
|
130
|
+
const targetPath = options?.modelPath ?? this.modelPath;
|
|
131
|
+
await ensureModelDir(targetPath);
|
|
132
|
+
await this.emit({
|
|
133
|
+
type: "download-start",
|
|
134
|
+
modelName: MODEL_CONFIG.name,
|
|
135
|
+
totalSize: MODEL_CONFIG.size,
|
|
136
|
+
});
|
|
137
|
+
try {
|
|
138
|
+
const downloader = await createModelDownloader({
|
|
139
|
+
modelUri: `hf:${MODEL_CONFIG.huggingFaceRepo}/${MODEL_CONFIG.fileName}`,
|
|
140
|
+
dirPath: path.dirname(targetPath),
|
|
141
|
+
fileName: path.basename(targetPath),
|
|
142
|
+
onProgress: (progress) => {
|
|
143
|
+
const downloaded = progress.downloadedSize;
|
|
144
|
+
const total = progress.totalSize;
|
|
145
|
+
const percentage = total > 0 ? (downloaded / total) * 100 : 0;
|
|
146
|
+
// Calculate speed if available
|
|
147
|
+
let speed;
|
|
148
|
+
if (progress.downloadedSize && progress.totalSize) {
|
|
149
|
+
// Speed calculation would need time tracking, simplified for now
|
|
150
|
+
speed = undefined;
|
|
151
|
+
}
|
|
152
|
+
// Emit unified event
|
|
153
|
+
void this.emit({
|
|
154
|
+
type: "download-progress",
|
|
155
|
+
downloaded,
|
|
156
|
+
total,
|
|
157
|
+
percentage,
|
|
158
|
+
speed,
|
|
159
|
+
});
|
|
160
|
+
// Call simplified callback if provided
|
|
161
|
+
if (options?.onProgress) {
|
|
162
|
+
options.onProgress(downloaded, total, percentage);
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
// Start the download
|
|
167
|
+
const resolvedPath = await downloader.download();
|
|
168
|
+
await this.emit({
|
|
169
|
+
type: "download-complete",
|
|
170
|
+
path: resolvedPath,
|
|
171
|
+
size: MODEL_CONFIG.size,
|
|
172
|
+
});
|
|
173
|
+
if (options?.onComplete) {
|
|
174
|
+
options.onComplete(resolvedPath);
|
|
175
|
+
}
|
|
176
|
+
return resolvedPath;
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
180
|
+
await this.emit({
|
|
181
|
+
type: "download-error",
|
|
182
|
+
error: err,
|
|
183
|
+
});
|
|
184
|
+
if (options?.onError) {
|
|
185
|
+
options.onError(err);
|
|
186
|
+
}
|
|
187
|
+
throw err;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Remove the downloaded model
|
|
192
|
+
*/
|
|
193
|
+
async removeModel() {
|
|
194
|
+
try {
|
|
195
|
+
await fs.promises.unlink(this.modelPath);
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
// Ignore if file doesn't exist
|
|
199
|
+
const err = error;
|
|
200
|
+
if (err.code !== "ENOENT") {
|
|
201
|
+
throw error;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Get information about available models
|
|
207
|
+
*/
|
|
208
|
+
static getModelInfo() {
|
|
209
|
+
return {
|
|
210
|
+
defaultPath: getDefaultModelPath(),
|
|
211
|
+
recommendedModel: MODEL_CONFIG.name,
|
|
212
|
+
availableModels: MODEL_VARIANTS,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
// ============================================================================
|
|
217
|
+
// Exported utility functions (for SDK API)
|
|
218
|
+
// ============================================================================
|
|
219
|
+
/**
|
|
220
|
+
* Check if the LLM model is available locally
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* const status = await checkLLMModel();
|
|
225
|
+
* console.log(status.available); // false
|
|
226
|
+
* console.log(status.path); // ~/.get-md/models/ReaderLM-v2-Q4_K_M.gguf
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
export async function checkLLMModel(options) {
|
|
230
|
+
const manager = new LLMManager({ modelPath: options?.modelPath });
|
|
231
|
+
return manager.checkModel();
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Download the LLM model with progress tracking
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```typescript
|
|
238
|
+
* await downloadLLMModel({
|
|
239
|
+
* onProgress: (downloaded, total, percentage) => {
|
|
240
|
+
* console.log(`Downloading: ${percentage.toFixed(1)}%`);
|
|
241
|
+
* },
|
|
242
|
+
* onComplete: (path) => {
|
|
243
|
+
* console.log(`Model ready at: ${path}`);
|
|
244
|
+
* }
|
|
245
|
+
* });
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
export async function downloadLLMModel(options) {
|
|
249
|
+
const manager = new LLMManager({ modelPath: options?.modelPath });
|
|
250
|
+
return manager.downloadModel(options);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Remove the downloaded LLM model
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```typescript
|
|
257
|
+
* await removeLLMModel();
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
export async function removeLLMModel(options) {
|
|
261
|
+
const manager = new LLMManager({ modelPath: options?.modelPath });
|
|
262
|
+
return manager.removeModel();
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Get information about the LLM model
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```typescript
|
|
269
|
+
* const info = getLLMModelInfo();
|
|
270
|
+
* console.log(info.recommendedModel); // "ReaderLM-v2-Q4_K_M"
|
|
271
|
+
* console.log(info.defaultPath); // ~/.get-md/models/ReaderLM-v2-Q4_K_M.gguf
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
export function getLLMModelInfo() {
|
|
275
|
+
return LLMManager.getModelInfo();
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=llm-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-manager.js","sourceRoot":"","sources":["../../src/converters/llm-manager.ts"],"names":[],"mappings":"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"}
|