fivetech commited on
Commit
dae5ea5
路
verified 路
1 Parent(s): 60707b0

Create localmodel.mjs

Browse files
Files changed (1) hide show
  1. core/localmodel.mjs +54 -0
core/localmodel.mjs ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Modelo local MiMo en el navegador (wllama 3.5.1, WASM/CPU).
2
+ El chat de este Space no depende de ning煤n servicio externo de modelos:
3
+ el GGUF se descarga desde Hugging Face (aprox. 5,8 GB la primera vez) y se
4
+ reutiliza desde la cach茅 del navegador mientras esta se conserve. */
5
+ const WLLAMA_ESM = 'https://cdn.jsdelivr.net/npm/@wllama/wllama@3.5.1/esm/index.js';
6
+ const WLLAMA_WASM = 'https://cdn.jsdelivr.net/npm/@wllama/wllama@3.5.1/esm/wasm/wllama.wasm';
7
+ const MODEL_URL = 'https://huggingface.co/bartowski/MiMo-V2.6-Distill-Qwen-9B-GGUF/resolve/main/MiMo-V2.6-Distill-Qwen-9B-Q4_K_M.gguf';
8
+ export const APLocalModel = {
9
+ state: 'idle', // idle | downloading | ready | error
10
+ error: '',
11
+ wllama: null,
12
+ label: 'MiMo-V2.6-Distill-Qwen-9B (local en este navegador)',
13
+ async cleanupCache() {
14
+ try { const keys = await caches.keys(); for (const k of keys) await caches.delete(k); } catch (_) {}
15
+ },
16
+ async load(onProgress) {
17
+ if (this.state === 'ready' || this.state === 'downloading') return;
18
+ this.state = 'downloading'; this.error = '';
19
+ try {
20
+ const { Wllama } = await import(WLLAMA_ESM);
21
+ if (this.wllama) { try { await this.wllama.exit(); } catch (_) {} }
22
+ this.wllama = new Wllama({ default: WLLAMA_WASM }, { parallelDownloads: 5 });
23
+ const opts = {
24
+ n_gpu_layers: 0, // WASM/CPU: sin aceleraci贸n garantizada
25
+ n_ctx: 4096, n_batch: 512,
26
+ n_threads: Math.max(1, Math.min(8, navigator.hardwareConcurrency || 4)),
27
+ progressCallback: ({ loaded, total }) => { if (onProgress && total > 0) onProgress(loaded, total); },
28
+ };
29
+ try {
30
+ await this.wllama.loadModelFromUrl(MODEL_URL, opts);
31
+ } catch (first) {
32
+ // Cach茅 incompleta o corrupta: limpiar y reintentar una vez.
33
+ await this.cleanupCache();
34
+ await this.wllama.loadModelFromUrl(MODEL_URL, opts);
35
+ }
36
+ this.state = 'ready';
37
+ } catch (e) {
38
+ this.state = 'error'; this.error = String(e && e.message || e).slice(0, 200);
39
+ throw e;
40
+ }
41
+ },
42
+ async chat(messages, { maxTokens = 640, temperature = 0.2, onToken } = {}) {
43
+ if (this.state !== 'ready') throw new Error('modelo local no cargado');
44
+ const stream = await this.wllama.createChatCompletion({ messages, max_tokens: maxTokens, temperature, stream: true });
45
+ let answer = '';
46
+ for await (const chunk of stream) {
47
+ const delta = (chunk.choices && chunk.choices[0] && chunk.choices[0].delta) || {};
48
+ const tk = delta.content || '';
49
+ if (tk) { answer += tk; if (onToken) onToken(answer); }
50
+ }
51
+ return answer;
52
+ },
53
+ };
54
+ globalThis.APLocalModel = APLocalModel;