mihailik commited on
Commit
1bb1792
·
1 Parent(s): 6b6e94a

Lighter model.

Browse files
package.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "localm",
3
- "version": "1.1.1",
4
  "description": "",
5
  "main": "chat-full.js",
6
  "scripts": {
 
1
  {
2
  "name": "localm",
3
+ "version": "1.1.2",
4
  "description": "",
5
  "main": "chat-full.js",
6
  "scripts": {
src/app/worker-connection.js CHANGED
@@ -33,7 +33,7 @@ export function workerConnection() {
33
  const msg = ev.data || {};
34
  if (msg && msg.type === 'ready') {
35
  ready = true;
36
- resolve({ worker: worker, pending, send });
37
  return;
38
  }
39
 
@@ -41,10 +41,14 @@ export function workerConnection() {
41
  const id = msg.id;
42
  const entry = pending.get(id);
43
  if (!entry) return;
44
- pending.delete(id);
45
- if (msg.type === 'response') entry.resolve(msg.result);
46
- else if (msg.type === 'error') entry.reject(new Error(msg.error));
47
- else entry.resolve(msg);
 
 
 
 
48
  }
49
  });
50
 
@@ -80,11 +84,12 @@ export function workerConnection() {
80
 
81
  /**
82
  * @param {string} promptText
83
- * @param {string} modelName
84
  */
85
  async function runPrompt(promptText, modelName) {
86
  await workerLoaded;
87
  const { send } = await workerLoaded;
88
- return send({ type: 'runPrompt', prompt: promptText, modelName });
 
89
  }
90
  }
 
33
  const msg = ev.data || {};
34
  if (msg && msg.type === 'ready') {
35
  ready = true;
36
+ resolve({ worker, pending, send });
37
  return;
38
  }
39
 
 
41
  const id = msg.id;
42
  const entry = pending.get(id);
43
  if (!entry) return;
44
+ if (msg.type === 'response') {
45
+ pending.delete(id);
46
+ entry.resolve(msg.result);
47
+ } else if (msg.type === 'error') {
48
+ pending.delete(id);
49
+ entry.reject(new Error(msg.error));
50
+ }
51
+ //else entry.resolve(msg);
52
  }
53
  });
54
 
 
84
 
85
  /**
86
  * @param {string} promptText
87
+ * @param {string} [modelName]
88
  */
89
  async function runPrompt(promptText, modelName) {
90
  await workerLoaded;
91
  const { send } = await workerLoaded;
92
+ const sendPromise = send({ type: 'runPrompt', prompt: promptText, modelName });
93
+ return sendPromise;
94
  }
95
  }
src/worker/load-model-core.js CHANGED
@@ -19,12 +19,13 @@ export async function loadModelCore({
19
  // via its own callbacks if available.
20
  const pipe = await pipeline(
21
  'text-generation',
22
- modelName,{
23
- device,
24
- progress_callback: (progress) => {
25
- if (onProgress) onProgress(progress);
26
- }
27
- });
 
28
 
29
  return pipe;
30
  }
 
19
  // via its own callbacks if available.
20
  const pipe = await pipeline(
21
  'text-generation',
22
+ modelName,
23
+ {
24
+ device,
25
+ progress_callback: (progress) => {
26
+ if (onProgress) onProgress(progress);
27
+ }
28
+ });
29
 
30
  return pipe;
31
  }
src/worker/model-cache.js CHANGED
@@ -9,9 +9,14 @@ export class ModelCache {
9
  backend = undefined;
10
 
11
  knownModels = [
12
- 'Xenova/phi-1.5',
13
  'Xenova/phi-3-mini-4k-instruct',
14
- 'Xenova/all-MiniLM-L6-v2'
 
 
 
 
 
15
  ];
16
 
17
  /**
@@ -30,20 +35,52 @@ export class ModelCache {
30
  */
31
  _loadModelAndStore({ modelName }) {
32
  if (!this.backend) this.backend = detectTransformersBackend();
33
- const modelPromise = loadModelCore({
34
- modelName,
35
- device: this.backend
36
- });
37
- this.cache.set(modelName, modelPromise);
38
- modelPromise.then(
39
- model => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  this.cache.set(modelName, model);
41
  },
42
  () => {
43
  this.cache.delete(modelName);
44
- });
45
-
46
- return modelPromise;
 
47
  }
48
 
49
  }
 
9
  backend = undefined;
10
 
11
  knownModels = [
12
+ 'Xenova/llama2.c-stories15M', // nonsense
13
  'Xenova/phi-3-mini-4k-instruct',
14
+ 'Xenova/all-MiniLM-L6-v2', // unsupported model type: bert
15
+ 'Xenova/phi-1.5', // gated
16
+ 'Qwen/Qwen2.5-3B', // cannot be loaded
17
+ 'microsoft/phi-1_5', // cannot be loaded
18
+ 'FlofloB/100k_fineweb_continued_pretraining_Qwen2.5-0.5B-Instruct_Unsloth_merged_16bit', // cannot be loaded
19
+ 'ehristoforu/coolqwen-3b-it' // cannot be loaded
20
  ];
21
 
22
  /**
 
35
  */
36
  _loadModelAndStore({ modelName }) {
37
  if (!this.backend) this.backend = detectTransformersBackend();
38
+ // Create a loader promise that will try multiple backends in order.
39
+ const loader = (async () => {
40
+ const tried = [];
41
+ // candidate order: detected backend first, then common fallbacks
42
+ let candidates = ['webgpu', 'gpu', 'wasm'];
43
+ candidates = ['gpu', 'wasm'];
44
+ candidates = candidates.slice(candidates.indexOf(this.backend || 'wasm'));
45
+
46
+ let lastErr = null;
47
+ console.log('Trying candidates ', candidates);
48
+ for (const device of candidates) {
49
+ try {
50
+ const model = await loadModelCore({
51
+ modelName,
52
+ device: /** @type {import('@huggingface/transformers').DeviceType} */ (device)
53
+ });
54
+ // on success, update backend to the working device and store model
55
+ this.backend = /** @type {import('@huggingface/transformers').DeviceType} */ (device);
56
+ this.cache.set(modelName, model);
57
+ return model;
58
+ } catch (err) {
59
+ console.log('Failed ', device, ' ', err);
60
+ tried.push({ device, error: err.stack || String(err) });
61
+ lastErr = err;
62
+ // continue to next candidate
63
+ }
64
+ }
65
+
66
+ // none succeeded
67
+ const err = new Error(`no available backend found. attempts=${JSON.stringify(tried)}; last=${String(lastErr)}`);
68
+ throw err;
69
+ })();
70
+
71
+ // store the in-progress promise so concurrent requests reuse it
72
+ this.cache.set(modelName, loader);
73
+ loader.then(
74
+ (model) => {
75
+ // on success, loader already stored the model
76
  this.cache.set(modelName, model);
77
  },
78
  () => {
79
  this.cache.delete(modelName);
80
+ }
81
+ );
82
+
83
+ return loader;
84
  }
85
 
86
  }