llm-tuner 0.4.2 → 0.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llm-tuner",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "Detects your hardware and finds the fastest configuration to run local LLMs with LM Studio or Ollama.",
5
5
  "keywords": [
6
6
  "llm",
@@ -27,13 +27,28 @@ async function hasSystemdService() {
27
27
  return r.code === 0;
28
28
  }
29
29
 
30
+ /** Extracts OLLAMA_MODELS from the systemd service environment if configured. */
31
+ async function systemdModelsDir() {
32
+ if (PLATFORM !== 'linux') return null;
33
+ try {
34
+ const r = await run('systemctl', ['show', 'ollama.service', '--property=Environment']);
35
+ if (r.code === 0) {
36
+ const match = r.stdout.match(/OLLAMA_MODELS=(?:"([^"]+)"|([^\s]+))/);
37
+ return match ? (match[1] || match[2]) : null;
38
+ }
39
+ } catch { /* next */ }
40
+ return null;
41
+ }
42
+
30
43
  /** Where the models live (needed to start a private benchmark server). */
31
44
  async function modelsDir() {
32
- if (process.env.OLLAMA_MODELS) return process.env.OLLAMA_MODELS;
33
- const candidates = [path.join(homeDir(), '.ollama', 'models')];
34
- if (PLATFORM === 'linux') candidates.unshift('/usr/share/ollama/.ollama/models', '/var/lib/ollama/.ollama/models');
45
+ const candidates = [process.env.OLLAMA_MODELS, await systemdModelsDir(), path.join(homeDir(), '.ollama', 'models')].filter(Boolean);
46
+ if (PLATFORM === 'linux') candidates.push('/usr/share/ollama/.ollama/models', '/var/lib/ollama/.ollama/models');
35
47
  for (const c of candidates) {
36
- try { await fs.access(path.join(c, 'manifests'), fs.constants.R_OK); return c; } catch { /* next */ }
48
+ try {
49
+ await fs.access(path.join(c, 'manifests'), fs.constants.R_OK | fs.constants.W_OK);
50
+ return c;
51
+ } catch { /* next */ }
37
52
  }
38
53
  return null;
39
54
  }
@@ -206,12 +221,16 @@ export const ollama = {
206
221
  * attention can change per candidate without touching the user's server.
207
222
  */
208
223
  async benchmark(ctx, model, candidate, opts) {
209
- const dir = ctx.detection.modelsDir;
210
- if (!dir || !ctx.detection.bin) {
211
- // Can't read the models: measure on the main server (its KV type/FA stay as configured).
224
+ const fallbackMainServer = async () => {
212
225
  const res = await runApiBenchmark({ kind: 'ollama', baseUrl: ctx.detection.apiUrl, model: model.key, ollamaOptions: this.requestOptions(candidate), ...opts });
213
226
  await this.unloadAll(ctx.detection.apiUrl);
214
227
  return { ...res, noteCode: 'bench.mainServerNote' };
228
+ };
229
+
230
+ const dir = ctx.detection.modelsDir;
231
+ if (!dir || !ctx.detection.bin) {
232
+ // Can't read/write the models: measure on the main server (its KV type/FA stay as configured).
233
+ return fallbackMainServer();
215
234
  }
216
235
  const port = await freePort();
217
236
  const url = `http://127.0.0.1:${port}`;
@@ -223,7 +242,7 @@ export const ollama = {
223
242
  if ((await fetchJson(`${url}/api/version`, { timeout: 1000 }))?.ok) { up = true; break; }
224
243
  await sleep(500);
225
244
  }
226
- if (!up) return benchError('bench.ollamaTestServerFailed', { detail: proc.lines.slice(-2).join(' | ') });
245
+ if (!up) return fallbackMainServer();
227
246
  const res = await runApiBenchmark({ kind: 'ollama', baseUrl: url, model: model.key, ollamaOptions: this.requestOptions(candidate), ...opts });
228
247
  // How much really landed on GPU (Ollama may silently fall back to CPU).
229
248
  const ps = await fetchJson(`${url}/api/ps`);