@degreesign/chat 0.1.3 → 0.2.0
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/README.md +38 -5
- package/dist/browser/chat.min.mjs +1 -1
- package/dist/chat.d.ts +5 -2
- package/dist/index.d.ts +2 -2
- package/dist/node/chat.node.min.js +1 -1
- package/dist/node/chat.node.min.mjs +1 -1
- package/dist/types.d.ts +14 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -85,6 +85,7 @@ import {
|
|
|
85
85
|
ChatModelId,
|
|
86
86
|
LlmRole,
|
|
87
87
|
createChat,
|
|
88
|
+
preloadModel,
|
|
88
89
|
} from "@degreesign/chat";
|
|
89
90
|
|
|
90
91
|
const messages = [
|
|
@@ -92,6 +93,9 @@ const messages = [
|
|
|
92
93
|
{ role: LlmRole.user, content: "Hello" },
|
|
93
94
|
];
|
|
94
95
|
|
|
96
|
+
// Optional: download and load the model before the first send.
|
|
97
|
+
await preloadModel({ model: ChatModelId.qwen3_vl_2b });
|
|
98
|
+
|
|
95
99
|
const cancel = createChat({
|
|
96
100
|
model: ChatModelId.qwen3_vl_2b,
|
|
97
101
|
messages,
|
|
@@ -106,8 +110,10 @@ const cancel = createChat({
|
|
|
106
110
|
cancel();
|
|
107
111
|
```
|
|
108
112
|
|
|
109
|
-
There is no promise and no controller object
|
|
110
|
-
three callbacks, and `onStatus` reports `requesting: false`
|
|
113
|
+
There is no promise and no controller object on `createChat`. Every result
|
|
114
|
+
arrives through the three callbacks, and `onStatus` reports `requesting: false`
|
|
115
|
+
when the reply ends. `preloadModel` is the one promise: it resolves once the
|
|
116
|
+
model is loaded, or `false` when it cannot load.
|
|
111
117
|
|
|
112
118
|
Attach images to a user turn with `images: [dataUrl]`. The package sends them
|
|
113
119
|
only to a model with vision support, center-crops each image to a square,
|
|
@@ -120,6 +126,7 @@ the call and appends the assistant message after the last `onResponse`.
|
|
|
120
126
|
|
|
121
127
|
```ts
|
|
122
128
|
createChat(input: ChatInput): CancelChat
|
|
129
|
+
preloadModel(input: ChatPreloadInput): Promise<boolean>
|
|
123
130
|
```
|
|
124
131
|
|
|
125
132
|
Call it once per response. A new call aborts the previous stream. When the
|
|
@@ -148,6 +155,30 @@ requested model is already loaded, no download or load happens.
|
|
|
148
155
|
|
|
149
156
|
The model stays loaded between calls until a cancel frees it.
|
|
150
157
|
|
|
158
|
+
### Preload
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
preloadModel(input: ChatPreloadInput): Promise<boolean>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Call it before the first `createChat` to download and load the model early. It
|
|
165
|
+
resolves `true` when the runtime is ready and `false` when the model is unknown,
|
|
166
|
+
unsupported or failed. A later `createChat` for the same model reuses the loaded
|
|
167
|
+
runtime, and either call joins a load already in flight.
|
|
168
|
+
|
|
169
|
+
`ChatPreloadInput` is the subset of `ChatInput` that a preload needs:
|
|
170
|
+
|
|
171
|
+
| Field | Description |
|
|
172
|
+
| ----- | ----------- |
|
|
173
|
+
| `model` | `ChatModelId` to download and load. |
|
|
174
|
+
| `limits?` | Partial `LlmLimits`; `maxThreads` applies when the model loads. |
|
|
175
|
+
| `logging?` | Whether package and engine console logs are written. Defaults to `false`. |
|
|
176
|
+
| `onStatus?` | Receives a `ChatStatusSnapshot` on every progress and state change. |
|
|
177
|
+
|
|
178
|
+
The final snapshot reports `ready: true`, `phase: LlmPhase.load` and
|
|
179
|
+
`percent: 100` on success, or an `error` with `availability: ChatStatus.offline`
|
|
180
|
+
on failure. A preload owns no cancel function; a new load replaces it.
|
|
181
|
+
|
|
151
182
|
## Status
|
|
152
183
|
|
|
153
184
|
`ChatStatusSnapshot` is the only lifecycle signal:
|
|
@@ -274,14 +305,15 @@ assembly, budgets, status state and cancellation.
|
|
|
274
305
|
|
|
275
306
|
The wllama engine needs a browser worker and wasm runtime. In Node,
|
|
276
307
|
`createChat` reports `LlmStatus.unsupported` and `ChatStatus.offline` through
|
|
277
|
-
`onStatus`, and the reply callbacks stay silent.
|
|
308
|
+
`onStatus`, and the reply callbacks stay silent. `preloadModel` resolves `false`
|
|
309
|
+
and reports the same unsupported status.
|
|
278
310
|
|
|
279
311
|
```js
|
|
280
|
-
const { createChat, ChatModelId, LlmRole } = require("@degreesign/chat");
|
|
312
|
+
const { createChat, preloadModel, ChatModelId, LlmRole } = require("@degreesign/chat");
|
|
281
313
|
```
|
|
282
314
|
|
|
283
315
|
```js
|
|
284
|
-
import { createChat, ChatModelId, LlmRole } from "@degreesign/chat";
|
|
316
|
+
import { createChat, preloadModel, ChatModelId, LlmRole } from "@degreesign/chat";
|
|
285
317
|
```
|
|
286
318
|
|
|
287
319
|
The Node entries are `dist/node/chat.node.min.js` for `require` and
|
|
@@ -326,6 +358,7 @@ const useReply = () => {
|
|
|
326
358
|
| Type | Description |
|
|
327
359
|
| ---- | ----------- |
|
|
328
360
|
| `ChatInput` | One request: model, messages, budgets, reasoning and callbacks. |
|
|
361
|
+
| `ChatPreloadInput` | Model, limits, logging and status, the subset `preloadModel` needs. |
|
|
329
362
|
| `CancelChat` | The function returned by `createChat`. |
|
|
330
363
|
| `ChatMessage` | One prompt turn, `role`, `content` and optional `images`. |
|
|
331
364
|
| `ChatStatusSnapshot` | Availability, engine status, backend, progress and request state. |
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see chat.min.mjs.LICENSE.txt */
|
|
2
|
-
var e={};const t={};function n(a){const o=t[a];if(void 0!==o)return o.exports;const r=t[a]={exports:{}};return e[a](r,r.exports,n),r.exports}var a,o,r,s,i,c;n.m=e,n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.f={},n.e=e=>{const t=[];return n.f.j(e,t),Promise.all(t)},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={924:()=>import("./engine-wllama.min.mjs")},t={792:0},a=e=>{let{__webpack_esm_ids__:a,__webpack_esm_modules__:o,__webpack_esm_runtime__:r}=e;var s,i,c=0;for(s in o)n.o(o,s)&&(n.m[s]=o[s]);for(r&&r(n);c<a.length;c++)i=a[c],n.o(t,i)&&t[i]&&t[i][0](),t[i]=0};n.f.j=(o,r)=>{let s=n.o(t,o)?t[o]:void 0;if(0!==s)if(s)r.push(s[1]);else{let n=e[o]().then(a,e=>{throw 0!==t[o]&&(t[o]=void 0),e});n=Promise.race([n,new Promise(e=>s=t[o]=[e])]),r.push(s[1]=n)}}})(),function(e){e.system="system",e.user="user",e.assistant="assistant"}(a||(a={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(o||(o={})),function(e){e[e.idle=0]="idle",e[e.downloading=1]="downloading",e[e.ready=2]="ready",e[e.error=3]="error",e[e.unsupported=4]="unsupported"}(r||(r={})),function(e){e.cpu="cpu",e.none="none"}(s||(s={})),function(e){e.download="download",e.load="load"}(i||(i={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b"}(c||(c={}));const l=[{id:c.qwen3_vl_2b,reasoning:!0,cpu:{repo:"Qwen/Qwen3-VL-2B-Thinking-GGUF",file:"Qwen3VL-2B-Thinking-Q4_K_M.gguf",mmproj:{file:"mmproj-Qwen3VL-2B-Thinking-Q8_0.gguf"}}}],d=e=>e?l.find(t=>t.id==e):void 0,g=e=>!!e.cpu.mmproj,u=new URL("./../assets/wllama/wllama.wasm",import.meta.url).href,m=new URL("./../assets/wllama/compat/wllama.wasm",import.meta.url).href,f=new URL("./../assets/wllama/compat/wllama.js",import.meta.url).href,p=288,h=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),n=await createImageBitmap(await t.blob()),a=Math.min(n.width,n.height),o=Math.floor((n.width-a)/2),r=Math.floor((n.height-a)/2),s=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const n=document.createElement("canvas");return n.width=e,n.height=t,n})(p,p),i=s?s.getContext("2d"):null;if(!s||!i||a<1)return n.close(),e;if(i.drawImage(n,o,r,a,a,0,0,p,p),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(s)){const t=await s.convertToBlob({type:"image/jpeg",quality:.85});return await(e=>new Promise(t=>{if("undefined"==typeof FileReader)return void t("");const n=new FileReader;n.onerror=()=>t(""),n.onload=()=>t(`${n.result}`),n.readAsDataURL(e)}))(t)||e}return s.toDataURL("image/jpeg",.85)}catch{return e}},w={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},y=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,x=["<|channel>thought\n","<|channel>thought","..."],k=["<channel|>","..."],v=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,b=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,_=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[...b(e),{type:"text",text:"\n"},...b(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n},T=async({model:e,logging:t,onReason:n,onText:a,start:o,stopped:r})=>{let s="",i="",c="";const l=((e,t)=>{let n="",a=!1;const o=(e,t)=>{let n=-1,a="";for(const o of t){const t=e.indexOf(o);t>=0&&(n<0||t<n)&&(n=t,a=o)}return{at:n,tag:a}},r=(e,t)=>{let n="";for(const a of t)for(let t=Math.min(e.length,a.length-1);t>n.length;t--)if(e.endsWith(a.slice(0,t))){n=e.slice(e.length-t);break}return n};return{feed:s=>{let i=n+s;for(n="";i;){if(a){const{at:t,tag:s}=o(i,k);if(t>=0){t&&e(i.slice(0,t)),i=i.slice(t+s.length),a=!1;continue}const c=r(i,k);e(i.slice(0,i.length-c.length)),n=c;break}{const{at:e,tag:s}=o(i,x);if(e>=0){e&&t(i.slice(0,e)),i=i.slice(e+s.length),i.startsWith("\n")&&(i=i.slice(1)),a=!0;continue}const c=r(i,x);t(i.slice(0,i.length-c.length)),n=c;break}}},flush:()=>{n&&(a?e(n):t(n),n="")}}})(e=>{i+=e,n(e)},e=>{s+=e,a(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],a=e?.delta,o="string"==typeof a?.reasoning_content?a.reasoning_content:"string"==typeof a?.reasoning?a.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(i+=o,n(o)),a?.content&&l.feed(a.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:s||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",s.length,i.length)),d},M=async({model:e,params:t,start:n,stopped:o})=>{const r=await(async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push(n);continue}const e=[];for(const t of n.content)e.push("image"==t.type?{type:"image",url:await h(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=w)=>{const n=t.maxContentLength,o=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=a.user||!e.images?.length)),r=[],s=[];let i=0,c=t.maxImages;for(let e=o.length-1;e>=0;e--){const l=o[e],d=("string"==typeof l.content?l.content:"").slice(0,n),g=l.role==a.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&i+d.length>t.promptCharBudget)break;i+=d.length,c-=g.length,l.role==a.system?r.unshift(d):l.role==a.assistant?s.unshift({role:"assistant",content:d}):s.unshift({role:"user",content:v(d,g)})}}for(;s.length&&"user"!=s[0].role;)s.shift();const l=[];for(const e of s){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=_(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=r.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),g})(t.messages,t.limits));return t.logging&&((e,t)=>{console.log("Local chat call",e.id,t.map(({role:e,content:t})=>({role:e,content:"****",...Array.isArray(t)?{images:t.filter(e=>"image"==e.type).length}:{}})))})(e,r),await T({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>n(r),stopped:o})};let C,L,R="",j=!1;const W=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,$=e=>{const t={wasm:u,compatWasm:m,compatWorker:f};return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},q=e=>{const t=e=>(...t)=>{j&&("string"==typeof t[0]&&t[0].includes("ggml_webgpu: Failed to get an adapter")||e(...t))};return{...e,log:t(e.log),warn:t(e.warn),error:t(e.error)}},B=async()=>{if(C)return C;const e=await n.e(924).then(()=>n(577)),t=L||$(),a=new e.Wllama({default:t.wasm},{logger:q(e.LoggerWithoutDebug)});return L||(L=t,R=W(t)),a.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),C=a,a},I=async()=>{const e=C;C=void 0;try{await(e?.exit())}catch{}},P=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),O=e=>[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]],U=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,A=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),n=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!n.includes(";base64"))return await(await fetch(e)).arrayBuffer();const a=atob(e.slice(t+1)),o=new Uint8Array(a.length);for(let e=0;e<a.length;e++)o[e]=a.charCodeAt(e);return o.buffer},F=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){"system"==n.role?t.push({role:"system",content:n.content}):"assistant"==n.role?t.push({role:"assistant",content:n.content}):t.push({role:"user",content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await A(t.url)});t.push({role:"user",content:e})}return t},E=async(e,t,n)=>{if(j=!0===n.logging,e.isModelLoaded())return await M({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if((e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)))(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await F(a),...(o=n.limits,r=n.reasoning,{stream:!0,temperature:.7,max_tokens:r?o.maxReasoningTokens:o.maxReplyTokens}),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}});var o,r}})},Q={backend:s.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{j=!0===o;const c=$(r),l=W(c);C&&l!=R&&await I(),L=c,R=l;const d=(g="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,u=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(g||4)-1)),u)));var g,u;const m=await B(),f=U(e.cpu.repo,e.cpu.file),p=e.cpu.mmproj?.file,h=p?U(e.cpu.repo,p):"";if(a?.aborted)throw await I(),new Error("Cancelled");if(p){const t=await m.cacheManager.list(),n=t.some(t=>P(t,e.cpu.file)),a=t.some(e=>P(e,p));n&&!a&&await m.cacheManager.deleteMany(t=>P(t,e.cpu.file))}try{await m.loadModelFromUrl(h?{url:f,mmprojUrl:h}:f,{n_ctx:8192,n_threads:d,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!0,signal:a,progressCallback:({loaded:e,total:t})=>{const a=t?e/t:0;n(a,a>=1?i.load:i.download)}})}catch(e){throw await I(),e}if(a?.aborted)throw await I(),new Error("Cancelled");if(!m.getLoadedContextInfo().n_ctx)throw await I(),new Error("Failed to create model context");return{model:e,backend:s.cpu,contextSize:8192,chat:t=>E(m,e,t),unload:async()=>{if(C==m)await I();else try{await m.exit()}catch{}}}},cached:async e=>{try{const t=await B(),n=await t.cacheManager.list();return O(e).every(e=>n.some(t=>P(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await B();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{const t=await B();await t.cacheManager.deleteMany(t=>O(e).some(e=>P(t,e)))}catch{}},purge:async()=>{try{const e=await B();await e.cacheManager.clear()}catch{}}},S=((e={})=>{const t=e.engines?.cpu||Q;let n,a,o,c,d,g,u,m=s.none,f=r.idle,p=0,h={percent:0,phase:i.download};const w=()=>e.backend||("undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?s.none:s.cpu),y=async()=>{await t.purge()},x=(e,t)=>{h={percent:Math.max(0,Math.min(1,e)),phase:t||i.download},g?.(h.percent,h.phase)},k=e=>{f=e},v=()=>f==r.ready&&!!n&&!!a;return{load:async({model:e,limits:u,assets:f,logging:b,onProgress:_})=>{if(v()&&a?.id==e.id)return!0;if(o&&c==e.id)return g=_,_(h.percent,h.phase),await o;o&&(g=void 0,d?.abort(),await o.catch(()=>!1)),g=_;const T=++p,M=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const o=w();if(T!=p)return!1;if(o==s.none)return k(r.unsupported),!1;if(await(async e=>{if(a&&a.id!=e.id){const e=a,o=n;n=void 0,a=void 0,await(o?.unload()),await t.remove(e)}if(await t.hasCache())for(const n of l)n.id!=e.id&&await t.remove(n)})(e),T!=p)return!1;const c=await t.cached(e);if(T!=p)return!1;if(!c&&await(async()=>{try{if("undefined"==typeof navigator)return!1;if(!navigator.storage?.estimate)return!1;const{quota:e=0,usage:t=0}=await navigator.storage.estimate();return!!e&&t>=e}catch{return!1}})()&&await y(),T!=p)return!1;k(r.downloading),x(0,i.download),c&&x(1,i.load);const g=new AbortController;d=g;try{const s=await t.startLLM({model:e,limits:u,logging:b,signal:g.signal,assets:f,onProgress:(e,t)=>{T==p&&x(e,t)}});return T!=p||g.signal.aborted?(await s.unload(),!1):(n=s,a=e,m=o,k(r.ready),x(1,i.load),!0)}catch(e){return T!=p||(n=void 0,a=void 0,b&&console.log("Local model failed",e),(e=>["quota","no space","disk full","ns_error_dom_quota_reached"].some(t=>`${e?.name||""} ${e?.message||`${e}`}`.toLowerCase().includes(t)))(e)&&await y(),k(r.error)),!1}finally{d==g&&(d=void 0)}})().finally(()=>{o==M&&(o=void 0,c=void 0)});return o=M,c=e.id,await M},chat:async e=>{if(!v()||!n)return;for(;u;)await u.catch(()=>{});if(!v()||!n)return;const t=n.chat(e);u=t;try{return await t}finally{u==t&&(u=void 0)}},unload:async()=>{p++,d?.abort(),d=void 0,c=void 0;const e=n;n=void 0,a=void 0,k(r.idle),await(e?.unload())},cancelLoad:()=>{p++,d?.abort(),d=void 0,c=void 0,f==r.downloading&&k(r.idle)},ready:v,loading:()=>!v()&&f==r.downloading,status:()=>f,backend:()=>m,model:()=>a}})(),D=(e=>{let t,n=0;const s=t=>{const n=e.status(),a=e.backend(),s=d(t.input.model),i={availability:n==r.ready?o.online:n==r.error||n==r.unsupported?o.offline:o.away,status:n,backend:a,supportsImages:!!s&&g(s),ready:e.ready(),loading:e.loading(),requesting:t.requesting,phase:t.phase,percent:t.percent,...t.error?{error:t.error}:{}};t.input.onStatus?.(i)},c=async t=>{const{input:o}=t,r=!0===o.logging,c=d(o.model),l=o.messages.some(e=>e.role!=a.system&&"string"==typeof e.content&&!!e.content.trim()),u=o.messages.some(e=>e.role==a.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),m=l||u;if(!c)return t.error="Unknown model",void s(t);if(!m)return void s(t);if(u&&!l&&!g(c))return t.error="Model does not accept images",void s(t);const f=((e={})=>{const t=w;return{maxReplyTokens:y(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:y(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:y(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:y(e.maxImages,t.maxImages,0),maxContentLength:y(e.maxContentLength,t.maxContentLength,1),promptCharBudget:y(e.promptCharBudget,t.promptCharBudget,1),maxThreads:y(e.maxThreads,t.maxThreads,1)}})(o.limits),p=await e.load({model:c,limits:f,logging:r,onProgress:(e,a)=>{t.token==n&&(t.percent=Math.round(100*e),t.phase=a,s(t))}}).catch(e=>(t.token==n&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=n)return;if(!p)return t.cancelled||t.error||(t.error="Model not ready"),void s(t);const h=g(c),x=u&&!h?o.messages.map(({images:e,...t})=>t):o.messages;if(u&&!h&&!l)return t.error="Model does not accept images",void s(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=i.load,s(t);let k,v="",b="";try{k=await e.chat({messages:x,limits:f,reasoning:!0===o.reasoning,logging:r,onReason:e=>{t.token!=n||t.cancelled||(v+=e,o.onThinking?.(v))},onText:e=>{t.token!=n||t.cancelled||(b+=e,o.onResponse?.(b))},signal:t.controller.signal})}catch(e){if(t.token!=n)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void s(t)}t.token==n&&(t.requesting=!1,k||t.cancelled||(t.error="No reply"),s(t))};return a=>{t?.controller.abort();const o={token:++n,input:a,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?i.load:i.download,requesting:!1,cancelled:!1};return t=o,s(o),c(o),()=>(t=>{t.token==n&&(t.cancelled=!0,t.controller.abort(),e.status()!=r.ready?(e.cancelLoad(),s(t)):e.unload().then(()=>s(t)))})(o)}})(S);export{c as ChatModelId,o as ChatStatus,s as LlmBackend,i as LlmPhase,a as LlmRole,r as LlmStatus,D as createChat};
|
|
2
|
+
var e={};const t={};function n(a){const o=t[a];if(void 0!==o)return o.exports;const r=t[a]={exports:{}};return e[a](r,r.exports,n),r.exports}var a,o,r,s,i,c;n.m=e,n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.f={},n.e=e=>{const t=[];return n.f.j(e,t),Promise.all(t)},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={924:()=>import("./engine-wllama.min.mjs")},t={792:0},a=e=>{let{__webpack_esm_ids__:a,__webpack_esm_modules__:o,__webpack_esm_runtime__:r}=e;var s,i,c=0;for(s in o)n.o(o,s)&&(n.m[s]=o[s]);for(r&&r(n);c<a.length;c++)i=a[c],n.o(t,i)&&t[i]&&t[i][0](),t[i]=0};n.f.j=(o,r)=>{let s=n.o(t,o)?t[o]:void 0;if(0!==s)if(s)r.push(s[1]);else{let n=e[o]().then(a,e=>{throw 0!==t[o]&&(t[o]=void 0),e});n=Promise.race([n,new Promise(e=>s=t[o]=[e])]),r.push(s[1]=n)}}})(),function(e){e.system="system",e.user="user",e.assistant="assistant"}(a||(a={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(o||(o={})),function(e){e[e.idle=0]="idle",e[e.downloading=1]="downloading",e[e.ready=2]="ready",e[e.error=3]="error",e[e.unsupported=4]="unsupported"}(r||(r={})),function(e){e.cpu="cpu",e.none="none"}(s||(s={})),function(e){e.download="download",e.load="load"}(i||(i={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b"}(c||(c={}));const l=[{id:c.qwen3_vl_2b,reasoning:!0,cpu:{repo:"Qwen/Qwen3-VL-2B-Thinking-GGUF",file:"Qwen3VL-2B-Thinking-Q4_K_M.gguf",mmproj:{file:"mmproj-Qwen3VL-2B-Thinking-Q8_0.gguf"}}}],d=e=>e?l.find(t=>t.id==e):void 0,g=e=>!!e.cpu.mmproj,u=new URL("./../assets/wllama/wllama.wasm",import.meta.url).href,m=new URL("./../assets/wllama/compat/wllama.wasm",import.meta.url).href,p=new URL("./../assets/wllama/compat/wllama.js",import.meta.url).href,f=288,h=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),n=await createImageBitmap(await t.blob()),a=Math.min(n.width,n.height),o=Math.floor((n.width-a)/2),r=Math.floor((n.height-a)/2),s=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const n=document.createElement("canvas");return n.width=e,n.height=t,n})(f,f),i=s?s.getContext("2d"):null;if(!s||!i||a<1)return n.close(),e;if(i.drawImage(n,o,r,a,a,0,0,f,f),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(s)){const t=await s.convertToBlob({type:"image/jpeg",quality:.85});return await(e=>new Promise(t=>{if("undefined"==typeof FileReader)return void t("");const n=new FileReader;n.onerror=()=>t(""),n.onload=()=>t(`${n.result}`),n.readAsDataURL(e)}))(t)||e}return s.toDataURL("image/jpeg",.85)}catch{return e}},w={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},y=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,x=(e={})=>{const t=w;return{maxReplyTokens:y(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:y(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:y(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:y(e.maxImages,t.maxImages,0),maxContentLength:y(e.maxContentLength,t.maxContentLength,1),promptCharBudget:y(e.promptCharBudget,t.promptCharBudget,1),maxThreads:y(e.maxThreads,t.maxThreads,1)}},k=["<|channel>thought\n","<|channel>thought","..."],v=["<channel|>","..."],b=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,_=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,M=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[..._(e),{type:"text",text:"\n"},..._(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n},T=async({model:e,logging:t,onReason:n,onText:a,start:o,stopped:r})=>{let s="",i="",c="";const l=((e,t)=>{let n="",a=!1;const o=(e,t)=>{let n=-1,a="";for(const o of t){const t=e.indexOf(o);t>=0&&(n<0||t<n)&&(n=t,a=o)}return{at:n,tag:a}},r=(e,t)=>{let n="";for(const a of t)for(let t=Math.min(e.length,a.length-1);t>n.length;t--)if(e.endsWith(a.slice(0,t))){n=e.slice(e.length-t);break}return n};return{feed:s=>{let i=n+s;for(n="";i;){if(a){const{at:t,tag:s}=o(i,v);if(t>=0){t&&e(i.slice(0,t)),i=i.slice(t+s.length),a=!1;continue}const c=r(i,v);e(i.slice(0,i.length-c.length)),n=c;break}{const{at:e,tag:s}=o(i,k);if(e>=0){e&&t(i.slice(0,e)),i=i.slice(e+s.length),i.startsWith("\n")&&(i=i.slice(1)),a=!0;continue}const c=r(i,k);t(i.slice(0,i.length-c.length)),n=c;break}}},flush:()=>{n&&(a?e(n):t(n),n="")}}})(e=>{i+=e,n(e)},e=>{s+=e,a(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],a=e?.delta,o="string"==typeof a?.reasoning_content?a.reasoning_content:"string"==typeof a?.reasoning?a.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(i+=o,n(o)),a?.content&&l.feed(a.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:s||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",s.length,i.length)),d},C=async({model:e,params:t,start:n,stopped:o})=>{const r=await(async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push(n);continue}const e=[];for(const t of n.content)e.push("image"==t.type?{type:"image",url:await h(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=w)=>{const n=t.maxContentLength,o=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=a.user||!e.images?.length)),r=[],s=[];let i=0,c=t.maxImages;for(let e=o.length-1;e>=0;e--){const l=o[e],d=("string"==typeof l.content?l.content:"").slice(0,n),g=l.role==a.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&i+d.length>t.promptCharBudget)break;i+=d.length,c-=g.length,l.role==a.system?r.unshift(d):l.role==a.assistant?s.unshift({role:"assistant",content:d}):s.unshift({role:"user",content:b(d,g)})}}for(;s.length&&"user"!=s[0].role;)s.shift();const l=[];for(const e of s){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=M(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=r.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),g})(t.messages,t.limits));return t.logging&&((e,t)=>{console.log("Local chat call",e.id,t.map(({role:e,content:t})=>({role:e,content:"****",...Array.isArray(t)?{images:t.filter(e=>"image"==e.type).length}:{}})))})(e,r),await T({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>n(r),stopped:o})};let L,R,j="",W=!1;const $=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,q=e=>{const t={wasm:u,compatWasm:m,compatWorker:p};return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},B=e=>{const t=e=>(...t)=>{W&&("string"==typeof t[0]&&t[0].includes("ggml_webgpu: Failed to get an adapter")||e(...t))};return{...e,log:t(e.log),warn:t(e.warn),error:t(e.error)}},P=async()=>{if(L)return L;const e=await n.e(924).then(()=>n(577)),t=R||q(),a=new e.Wllama({default:t.wasm},{logger:B(e.LoggerWithoutDebug)});return R||(R=t,j=$(t)),a.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),L=a,a},I=async()=>{const e=L;L=void 0;try{await(e?.exit())}catch{}},U=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),O=e=>[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]],A=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,F=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),n=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!n.includes(";base64"))return await(await fetch(e)).arrayBuffer();const a=atob(e.slice(t+1)),o=new Uint8Array(a.length);for(let e=0;e<a.length;e++)o[e]=a.charCodeAt(e);return o.buffer},E=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){"system"==n.role?t.push({role:"system",content:n.content}):"assistant"==n.role?t.push({role:"assistant",content:n.content}):t.push({role:"user",content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await F(t.url)});t.push({role:"user",content:e})}return t},Q=async(e,t,n)=>{if(W=!0===n.logging,e.isModelLoaded())return await C({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if((e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)))(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await E(a),...(o=n.limits,r=n.reasoning,{stream:!0,temperature:.7,max_tokens:r?o.maxReasoningTokens:o.maxReplyTokens}),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}});var o,r}})},S={backend:s.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{W=!0===o;const c=q(r),l=$(c);L&&l!=j&&await I(),R=c,j=l;const d=(g="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,u=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(g||4)-1)),u)));var g,u;const m=await P(),p=A(e.cpu.repo,e.cpu.file),f=e.cpu.mmproj?.file,h=f?A(e.cpu.repo,f):"";if(a?.aborted)throw await I(),new Error("Cancelled");if(f){const t=await m.cacheManager.list(),n=t.some(t=>U(t,e.cpu.file)),a=t.some(e=>U(e,f));n&&!a&&await m.cacheManager.deleteMany(t=>U(t,e.cpu.file))}try{await m.loadModelFromUrl(h?{url:p,mmprojUrl:h}:p,{n_ctx:8192,n_threads:d,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!0,signal:a,progressCallback:({loaded:e,total:t})=>{const a=t?e/t:0;n(a,a>=1?i.load:i.download)}})}catch(e){throw await I(),e}if(a?.aborted)throw await I(),new Error("Cancelled");if(!m.getLoadedContextInfo().n_ctx)throw await I(),new Error("Failed to create model context");return{model:e,backend:s.cpu,contextSize:8192,chat:t=>Q(m,e,t),unload:async()=>{if(L==m)await I();else try{await m.exit()}catch{}}}},cached:async e=>{try{const t=await P(),n=await t.cacheManager.list();return O(e).every(e=>n.some(t=>U(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await P();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{const t=await P();await t.cacheManager.deleteMany(t=>O(e).some(e=>U(t,e)))}catch{}},purge:async()=>{try{const e=await P();await e.cacheManager.clear()}catch{}}},D=((e={})=>{const t=e.engines?.cpu||S;let n,a,o,c,d,g,u,m=s.none,p=r.idle,f=0,h={percent:0,phase:i.download};const w=()=>e.backend||("undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?s.none:s.cpu),y=async()=>{await t.purge()},x=(e,t)=>{h={percent:Math.max(0,Math.min(1,e)),phase:t||i.download},g?.(h.percent,h.phase)},k=e=>{p=e},v=()=>p==r.ready&&!!n&&!!a;return{load:async({model:e,limits:u,assets:p,logging:b,onProgress:_})=>{if(v()&&a?.id==e.id)return!0;if(o&&c==e.id)return g=_,_(h.percent,h.phase),await o;o&&(g=void 0,d?.abort(),await o.catch(()=>!1)),g=_;const M=++f,T=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const o=w();if(M!=f)return!1;if(o==s.none)return k(r.unsupported),!1;if(await(async e=>{if(a&&a.id!=e.id){const e=a,o=n;n=void 0,a=void 0,await(o?.unload()),await t.remove(e)}if(await t.hasCache())for(const n of l)n.id!=e.id&&await t.remove(n)})(e),M!=f)return!1;const c=await t.cached(e);if(M!=f)return!1;if(!c&&await(async()=>{try{if("undefined"==typeof navigator)return!1;if(!navigator.storage?.estimate)return!1;const{quota:e=0,usage:t=0}=await navigator.storage.estimate();return!!e&&t>=e}catch{return!1}})()&&await y(),M!=f)return!1;k(r.downloading),x(0,i.download),c&&x(1,i.load);const g=new AbortController;d=g;try{const s=await t.startLLM({model:e,limits:u,logging:b,signal:g.signal,assets:p,onProgress:(e,t)=>{M==f&&x(e,t)}});return M!=f||g.signal.aborted?(await s.unload(),!1):(n=s,a=e,m=o,k(r.ready),x(1,i.load),!0)}catch(e){return M!=f||(n=void 0,a=void 0,b&&console.log("Local model failed",e),(e=>["quota","no space","disk full","ns_error_dom_quota_reached"].some(t=>`${e?.name||""} ${e?.message||`${e}`}`.toLowerCase().includes(t)))(e)&&await y(),k(r.error)),!1}finally{d==g&&(d=void 0)}})().finally(()=>{o==T&&(o=void 0,c=void 0)});return o=T,c=e.id,await T},chat:async e=>{if(!v()||!n)return;for(;u;)await u.catch(()=>{});if(!v()||!n)return;const t=n.chat(e);u=t;try{return await t}finally{u==t&&(u=void 0)}},unload:async()=>{f++,d?.abort(),d=void 0,c=void 0;const e=n;n=void 0,a=void 0,k(r.idle),await(e?.unload())},cancelLoad:()=>{f++,d?.abort(),d=void 0,c=void 0,p==r.downloading&&k(r.idle)},ready:v,loading:()=>!v()&&p==r.downloading,status:()=>p,backend:()=>m,model:()=>a}})(),V=(e,t,n)=>{const a=e.status(),s=d(t);return{availability:a==r.ready?o.online:a==r.error||a==r.unsupported?o.offline:o.away,status:a,backend:e.backend(),supportsImages:!!s&&g(s),ready:e.ready(),loading:e.loading(),requesting:n.requesting,phase:n.phase,percent:n.percent,...n.error?{error:n.error}:{}}},G=(e=>{let t,n=0;const o=t=>t.input.onStatus?.(V(e,t.input.model,t));return s=>{t?.controller.abort();const c={token:++n,input:s,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?i.load:i.download,requesting:!1,cancelled:!1};return t=c,o(c),(async t=>{const{input:r}=t,s=!0===r.logging,c=d(r.model),l=r.messages.some(e=>e.role!=a.system&&"string"==typeof e.content&&!!e.content.trim()),u=r.messages.some(e=>e.role==a.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),m=l||u;if(!c)return t.error="Unknown model",void o(t);if(!m)return void o(t);if(u&&!l&&!g(c))return t.error="Model does not accept images",void o(t);const p=x(r.limits),f=await e.load({model:c,limits:p,logging:s,onProgress:(e,a)=>{t.token==n&&(t.percent=Math.round(100*e),t.phase=a,o(t))}}).catch(e=>(t.token==n&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=n)return;if(!f)return t.cancelled||t.error||(t.error="Model not ready"),void o(t);const h=g(c),w=u&&!h?r.messages.map(({images:e,...t})=>t):r.messages;if(u&&!h&&!l)return t.error="Model does not accept images",void o(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=i.load,o(t);let y,k="",v="";try{y=await e.chat({messages:w,limits:p,reasoning:!0===r.reasoning,logging:s,onReason:e=>{t.token!=n||t.cancelled||(k+=e,r.onThinking?.(k))},onText:e=>{t.token!=n||t.cancelled||(v+=e,r.onResponse?.(v))},signal:t.controller.signal})}catch(e){if(t.token!=n)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void o(t)}t.token==n&&(t.requesting=!1,y||t.cancelled||(t.error="No reply"),o(t))})(c),()=>(t=>{t.token==n&&(t.cancelled=!0,t.controller.abort(),e.status()!=r.ready?(e.cancelLoad(),o(t)):e.unload().then(()=>o(t)))})(c)}})(D),N=(z=D,async e=>{const t=d(e.model),n=t=>e.onStatus?.(V(z,e.model,t));if(!t)return n({requesting:!1,phase:i.download,percent:0,error:"Unknown model"}),!1;let a,o=0,r=i.download;const s=z.ready()&&z.model()?.id==t.id;return await z.load({model:t,limits:x(e.limits),logging:!0===e.logging,onProgress:(e,t)=>{o=Math.round(100*e),r=t,n({requesting:!1,phase:r,percent:o})}}).catch(e=>(a=`${e?.message||`${e}`}`,!1))?(s&&n({requesting:!1,phase:i.load,percent:100}),!0):(n({requesting:!1,phase:r,percent:o,error:a||"Model not ready"}),!1)});var z;export{c as ChatModelId,o as ChatStatus,s as LlmBackend,i as LlmPhase,a as LlmRole,r as LlmStatus,G as createChat,N as preloadModel};
|
package/dist/chat.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import type { CancelChat, ChatInput, Runtime } from './types';
|
|
1
|
+
import type { CancelChat, ChatInput, ChatPreloadInput, Runtime } from './types';
|
|
2
2
|
/** Build a one-shot chat function over one runtime */
|
|
3
3
|
declare const createChatOn: (service: Runtime) => ((input: ChatInput) => CancelChat);
|
|
4
|
+
/** Build a model preload over one runtime */
|
|
5
|
+
declare const createPreloadOn: (service: Runtime) => (input: ChatPreloadInput) => Promise<boolean>;
|
|
4
6
|
declare const createChat: (input: ChatInput) => CancelChat;
|
|
5
|
-
|
|
7
|
+
declare const preloadModel: (input: ChatPreloadInput) => Promise<boolean>;
|
|
8
|
+
export { createChat, createChatOn, createPreloadOn, preloadModel };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { createChat } from './chat';
|
|
1
|
+
export { createChat, preloadModel } from './chat';
|
|
2
2
|
export { LlmRole, ChatStatus, LlmStatus, LlmBackend, LlmPhase, ChatModelId, } from './enums';
|
|
3
|
-
export type { ChatMessage, LlmLimits, ChatStatusSnapshot, ChatInput, CancelChat, WllamaAssets, } from './types';
|
|
3
|
+
export type { ChatMessage, LlmLimits, ChatStatusSnapshot, ChatInput, ChatPreloadInput, CancelChat, WllamaAssets, } from './types';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see chat.node.min.js.LICENSE.txt */
|
|
2
|
-
(()=>{"use strict";var e={};const t={};function n(a){const o=t[a];if(void 0!==o)return o.exports;const r=t[a]={exports:{}};return e[a](r,r.exports,n),r.exports}n.m=e,n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.f={},n.e=e=>{const t=[];return n.f.require(e,t),Promise.all(t)},n.u=e=>"engine-wllama.node.min.js",n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={792:1};n.f.require=(t,a)=>{if(!e[t]){const a=require("./"+n.u(t));e[t]||(t=>{const a=t.modules,o=t.ids,r=t.runtime;for(var s in a)n.o(a,s)&&(n.m[s]=a[s]);r&&r(n);for(var i=0;i<o.length;i++)e[o[i]]=1})(a)}}})();let a={};var o,r,s,i,c,l;n.r(a),n.d(a,{ChatModelId:()=>l,ChatStatus:()=>r,LlmBackend:()=>i,LlmPhase:()=>c,LlmRole:()=>o,LlmStatus:()=>s,createChat:()=>D}),function(e){e.system="system",e.user="user",e.assistant="assistant"}(o||(o={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(r||(r={})),function(e){e[e.idle=0]="idle",e[e.downloading=1]="downloading",e[e.ready=2]="ready",e[e.error=3]="error",e[e.unsupported=4]="unsupported"}(s||(s={})),function(e){e.cpu="cpu",e.none="none"}(i||(i={})),function(e){e.download="download",e.load="load"}(c||(c={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b"}(l||(l={}));const d=[{id:l.qwen3_vl_2b,reasoning:!0,cpu:{repo:"Qwen/Qwen3-VL-2B-Thinking-GGUF",file:"Qwen3VL-2B-Thinking-Q4_K_M.gguf",mmproj:{file:"mmproj-Qwen3VL-2B-Thinking-Q8_0.gguf"}}}],g=e=>e?d.find(t=>t.id==e):void 0,u=e=>!!e.cpu.mmproj,m=require("node:path"),f=()=>{return e=(0,m.join)(__dirname,"../assets/wllama"),{wasm:(0,m.join)(e,"wllama.wasm"),compatWasm:(0,m.join)(e,"compat/wllama.wasm"),compatWorker:(0,m.join)(e,"compat/wllama.js")};var e},p=288,h=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),n=await createImageBitmap(await t.blob()),a=Math.min(n.width,n.height),o=Math.floor((n.width-a)/2),r=Math.floor((n.height-a)/2),s=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const n=document.createElement("canvas");return n.width=e,n.height=t,n})(p,p),i=s?s.getContext("2d"):null;if(!s||!i||a<1)return n.close(),e;if(i.drawImage(n,o,r,a,a,0,0,p,p),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(s)){const t=await s.convertToBlob({type:"image/jpeg",quality:.85});return await(e=>new Promise(t=>{if("undefined"==typeof FileReader)return void t("");const n=new FileReader;n.onerror=()=>t(""),n.onload=()=>t(`${n.result}`),n.readAsDataURL(e)}))(t)||e}return s.toDataURL("image/jpeg",.85)}catch{return e}},y={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},w=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,x=["<|channel>thought\n","<|channel>thought","..."],v=["<channel|>","..."],k=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,b=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,T=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[...b(e),{type:"text",text:"\n"},...b(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n},M=async({model:e,logging:t,onReason:n,onText:a,start:o,stopped:r})=>{let s="",i="",c="";const l=((e,t)=>{let n="",a=!1;const o=(e,t)=>{let n=-1,a="";for(const o of t){const t=e.indexOf(o);t>=0&&(n<0||t<n)&&(n=t,a=o)}return{at:n,tag:a}},r=(e,t)=>{let n="";for(const a of t)for(let t=Math.min(e.length,a.length-1);t>n.length;t--)if(e.endsWith(a.slice(0,t))){n=e.slice(e.length-t);break}return n};return{feed:s=>{let i=n+s;for(n="";i;){if(a){const{at:t,tag:s}=o(i,v);if(t>=0){t&&e(i.slice(0,t)),i=i.slice(t+s.length),a=!1;continue}const c=r(i,v);e(i.slice(0,i.length-c.length)),n=c;break}{const{at:e,tag:s}=o(i,x);if(e>=0){e&&t(i.slice(0,e)),i=i.slice(e+s.length),i.startsWith("\n")&&(i=i.slice(1)),a=!0;continue}const c=r(i,x);t(i.slice(0,i.length-c.length)),n=c;break}}},flush:()=>{n&&(a?e(n):t(n),n="")}}})(e=>{i+=e,n(e)},e=>{s+=e,a(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],a=e?.delta,o="string"==typeof a?.reasoning_content?a.reasoning_content:"string"==typeof a?.reasoning?a.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(i+=o,n(o)),a?.content&&l.feed(a.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:s||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",s.length,i.length)),d},C=async({model:e,params:t,start:n,stopped:a})=>{const r=await(async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push(n);continue}const e=[];for(const t of n.content)e.push("image"==t.type?{type:"image",url:await h(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=y)=>{const n=t.maxContentLength,a=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=o.user||!e.images?.length)),r=[],s=[];let i=0,c=t.maxImages;for(let e=a.length-1;e>=0;e--){const l=a[e],d=("string"==typeof l.content?l.content:"").slice(0,n),g=l.role==o.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&i+d.length>t.promptCharBudget)break;i+=d.length,c-=g.length,l.role==o.system?r.unshift(d):l.role==o.assistant?s.unshift({role:"assistant",content:d}):s.unshift({role:"user",content:k(d,g)})}}for(;s.length&&"user"!=s[0].role;)s.shift();const l=[];for(const e of s){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=T(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=r.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),g})(t.messages,t.limits));return t.logging&&((e,t)=>{console.log("Local chat call",e.id,t.map(({role:e,content:t})=>({role:e,content:"****",...Array.isArray(t)?{images:t.filter(e=>"image"==e.type).length}:{}})))})(e,r),await M({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>n(r),stopped:a})};let _,L,j="",R=!1;const W=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,q=e=>{const t=f();return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},$=e=>{const t=e=>(...t)=>{R&&("string"==typeof t[0]&&t[0].includes("ggml_webgpu: Failed to get an adapter")||e(...t))};return{...e,log:t(e.log),warn:t(e.warn),error:t(e.error)}},B=async()=>{if(_)return _;const e=await n.e(924).then(()=>n(577)),t=L||q(),a=new e.Wllama({default:t.wasm},{logger:$(e.LoggerWithoutDebug)});return L||(L=t,j=W(t)),a.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),_=a,a},I=async()=>{const e=_;_=void 0;try{await(e?.exit())}catch{}},O=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),P=e=>[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]],A=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,U=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),n=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!n.includes(";base64"))return await(await fetch(e)).arrayBuffer();const a=atob(e.slice(t+1)),o=new Uint8Array(a.length);for(let e=0;e<a.length;e++)o[e]=a.charCodeAt(e);return o.buffer},F=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){"system"==n.role?t.push({role:"system",content:n.content}):"assistant"==n.role?t.push({role:"assistant",content:n.content}):t.push({role:"user",content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await U(t.url)});t.push({role:"user",content:e})}return t},S=async(e,t,n)=>{if(R=!0===n.logging,e.isModelLoaded())return await C({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if((e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)))(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await F(a),...(o=n.limits,r=n.reasoning,{stream:!0,temperature:.7,max_tokens:r?o.maxReasoningTokens:o.maxReplyTokens}),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}});var o,r}})},E={backend:i.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{R=!0===o;const s=q(r),l=W(s);_&&l!=j&&await I(),L=s,j=l;const d=(g="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,u=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(g||4)-1)),u)));var g,u;const m=await B(),f=A(e.cpu.repo,e.cpu.file),p=e.cpu.mmproj?.file,h=p?A(e.cpu.repo,p):"";if(a?.aborted)throw await I(),new Error("Cancelled");if(p){const t=await m.cacheManager.list(),n=t.some(t=>O(t,e.cpu.file)),a=t.some(e=>O(e,p));n&&!a&&await m.cacheManager.deleteMany(t=>O(t,e.cpu.file))}try{await m.loadModelFromUrl(h?{url:f,mmprojUrl:h}:f,{n_ctx:8192,n_threads:d,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!0,signal:a,progressCallback:({loaded:e,total:t})=>{const a=t?e/t:0;n(a,a>=1?c.load:c.download)}})}catch(e){throw await I(),e}if(a?.aborted)throw await I(),new Error("Cancelled");if(!m.getLoadedContextInfo().n_ctx)throw await I(),new Error("Failed to create model context");return{model:e,backend:i.cpu,contextSize:8192,chat:t=>S(m,e,t),unload:async()=>{if(_==m)await I();else try{await m.exit()}catch{}}}},cached:async e=>{try{const t=await B(),n=await t.cacheManager.list();return P(e).every(e=>n.some(t=>O(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await B();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{const t=await B();await t.cacheManager.deleteMany(t=>P(e).some(e=>O(t,e)))}catch{}},purge:async()=>{try{const e=await B();await e.cacheManager.clear()}catch{}}},Q=((e={})=>{const t=e.engines?.cpu||E;let n,a,o,r,l,g,u,m=i.none,f=s.idle,p=0,h={percent:0,phase:c.download};const y=()=>e.backend||("undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?i.none:i.cpu),w=async()=>{await t.purge()},x=(e,t)=>{h={percent:Math.max(0,Math.min(1,e)),phase:t||c.download},g?.(h.percent,h.phase)},v=e=>{f=e},k=()=>f==s.ready&&!!n&&!!a;return{load:async({model:e,limits:u,assets:f,logging:b,onProgress:T})=>{if(k()&&a?.id==e.id)return!0;if(o&&r==e.id)return g=T,T(h.percent,h.phase),await o;o&&(g=void 0,l?.abort(),await o.catch(()=>!1)),g=T;const M=++p,C=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const o=y();if(M!=p)return!1;if(o==i.none)return v(s.unsupported),!1;if(await(async e=>{if(a&&a.id!=e.id){const e=a,o=n;n=void 0,a=void 0,await(o?.unload()),await t.remove(e)}if(await t.hasCache())for(const n of d)n.id!=e.id&&await t.remove(n)})(e),M!=p)return!1;const r=await t.cached(e);if(M!=p)return!1;if(!r&&await(async()=>{try{if("undefined"==typeof navigator)return!1;if(!navigator.storage?.estimate)return!1;const{quota:e=0,usage:t=0}=await navigator.storage.estimate();return!!e&&t>=e}catch{return!1}})()&&await w(),M!=p)return!1;v(s.downloading),x(0,c.download),r&&x(1,c.load);const g=new AbortController;l=g;try{const r=await t.startLLM({model:e,limits:u,logging:b,signal:g.signal,assets:f,onProgress:(e,t)=>{M==p&&x(e,t)}});return M!=p||g.signal.aborted?(await r.unload(),!1):(n=r,a=e,m=o,v(s.ready),x(1,c.load),!0)}catch(e){return M!=p||(n=void 0,a=void 0,b&&console.log("Local model failed",e),(e=>["quota","no space","disk full","ns_error_dom_quota_reached"].some(t=>`${e?.name||""} ${e?.message||`${e}`}`.toLowerCase().includes(t)))(e)&&await w(),v(s.error)),!1}finally{l==g&&(l=void 0)}})().finally(()=>{o==C&&(o=void 0,r=void 0)});return o=C,r=e.id,await C},chat:async e=>{if(!k()||!n)return;for(;u;)await u.catch(()=>{});if(!k()||!n)return;const t=n.chat(e);u=t;try{return await t}finally{u==t&&(u=void 0)}},unload:async()=>{p++,l?.abort(),l=void 0,r=void 0;const e=n;n=void 0,a=void 0,v(s.idle),await(e?.unload())},cancelLoad:()=>{p++,l?.abort(),l=void 0,r=void 0,f==s.downloading&&v(s.idle)},ready:k,loading:()=>!k()&&f==s.downloading,status:()=>f,backend:()=>m,model:()=>a}})(),D=(e=>{let t,n=0;const a=t=>{const n=e.status(),a=e.backend(),o=g(t.input.model),i={availability:n==s.ready?r.online:n==s.error||n==s.unsupported?r.offline:r.away,status:n,backend:a,supportsImages:!!o&&u(o),ready:e.ready(),loading:e.loading(),requesting:t.requesting,phase:t.phase,percent:t.percent,...t.error?{error:t.error}:{}};t.input.onStatus?.(i)},i=async t=>{const{input:r}=t,s=!0===r.logging,i=g(r.model),l=r.messages.some(e=>e.role!=o.system&&"string"==typeof e.content&&!!e.content.trim()),d=r.messages.some(e=>e.role==o.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),m=l||d;if(!i)return t.error="Unknown model",void a(t);if(!m)return void a(t);if(d&&!l&&!u(i))return t.error="Model does not accept images",void a(t);const f=((e={})=>{const t=y;return{maxReplyTokens:w(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:w(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:w(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:w(e.maxImages,t.maxImages,0),maxContentLength:w(e.maxContentLength,t.maxContentLength,1),promptCharBudget:w(e.promptCharBudget,t.promptCharBudget,1),maxThreads:w(e.maxThreads,t.maxThreads,1)}})(r.limits),p=await e.load({model:i,limits:f,logging:s,onProgress:(e,o)=>{t.token==n&&(t.percent=Math.round(100*e),t.phase=o,a(t))}}).catch(e=>(t.token==n&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=n)return;if(!p)return t.cancelled||t.error||(t.error="Model not ready"),void a(t);const h=u(i),x=d&&!h?r.messages.map(({images:e,...t})=>t):r.messages;if(d&&!h&&!l)return t.error="Model does not accept images",void a(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=c.load,a(t);let v,k="",b="";try{v=await e.chat({messages:x,limits:f,reasoning:!0===r.reasoning,logging:s,onReason:e=>{t.token!=n||t.cancelled||(k+=e,r.onThinking?.(k))},onText:e=>{t.token!=n||t.cancelled||(b+=e,r.onResponse?.(b))},signal:t.controller.signal})}catch(e){if(t.token!=n)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void a(t)}t.token==n&&(t.requesting=!1,v||t.cancelled||(t.error="No reply"),a(t))};return o=>{t?.controller.abort();const r={token:++n,input:o,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?c.load:c.download,requesting:!1,cancelled:!1};return t=r,a(r),i(r),()=>(t=>{t.token==n&&(t.cancelled=!0,t.controller.abort(),e.status()!=s.ready?(e.cancelLoad(),a(t)):e.unload().then(()=>a(t)))})(r)}})(Q);module.exports=a})();
|
|
2
|
+
(()=>{"use strict";var e={};const t={};function n(a){const o=t[a];if(void 0!==o)return o.exports;const r=t[a]={exports:{}};return e[a](r,r.exports,n),r.exports}n.m=e,n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.f={},n.e=e=>{const t=[];return n.f.require(e,t),Promise.all(t)},n.u=e=>"engine-wllama.node.min.js",n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={792:1};n.f.require=(t,a)=>{if(!e[t]){const a=require("./"+n.u(t));e[t]||(t=>{const a=t.modules,o=t.ids,r=t.runtime;for(var s in a)n.o(a,s)&&(n.m[s]=a[s]);r&&r(n);for(var i=0;i<o.length;i++)e[o[i]]=1})(a)}}})();let a={};var o,r,s,i,c,l;n.r(a),n.d(a,{ChatModelId:()=>l,ChatStatus:()=>r,LlmBackend:()=>i,LlmPhase:()=>c,LlmRole:()=>o,LlmStatus:()=>s,createChat:()=>G,preloadModel:()=>N}),function(e){e.system="system",e.user="user",e.assistant="assistant"}(o||(o={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(r||(r={})),function(e){e[e.idle=0]="idle",e[e.downloading=1]="downloading",e[e.ready=2]="ready",e[e.error=3]="error",e[e.unsupported=4]="unsupported"}(s||(s={})),function(e){e.cpu="cpu",e.none="none"}(i||(i={})),function(e){e.download="download",e.load="load"}(c||(c={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b"}(l||(l={}));const d=[{id:l.qwen3_vl_2b,reasoning:!0,cpu:{repo:"Qwen/Qwen3-VL-2B-Thinking-GGUF",file:"Qwen3VL-2B-Thinking-Q4_K_M.gguf",mmproj:{file:"mmproj-Qwen3VL-2B-Thinking-Q8_0.gguf"}}}],g=e=>e?d.find(t=>t.id==e):void 0,u=e=>!!e.cpu.mmproj,m=require("node:path"),p=()=>{return e=(0,m.join)(__dirname,"../assets/wllama"),{wasm:(0,m.join)(e,"wllama.wasm"),compatWasm:(0,m.join)(e,"compat/wllama.wasm"),compatWorker:(0,m.join)(e,"compat/wllama.js")};var e},f=288,h=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),n=await createImageBitmap(await t.blob()),a=Math.min(n.width,n.height),o=Math.floor((n.width-a)/2),r=Math.floor((n.height-a)/2),s=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const n=document.createElement("canvas");return n.width=e,n.height=t,n})(f,f),i=s?s.getContext("2d"):null;if(!s||!i||a<1)return n.close(),e;if(i.drawImage(n,o,r,a,a,0,0,f,f),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(s)){const t=await s.convertToBlob({type:"image/jpeg",quality:.85});return await(e=>new Promise(t=>{if("undefined"==typeof FileReader)return void t("");const n=new FileReader;n.onerror=()=>t(""),n.onload=()=>t(`${n.result}`),n.readAsDataURL(e)}))(t)||e}return s.toDataURL("image/jpeg",.85)}catch{return e}},y={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},w=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,x=(e={})=>{const t=y;return{maxReplyTokens:w(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:w(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:w(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:w(e.maxImages,t.maxImages,0),maxContentLength:w(e.maxContentLength,t.maxContentLength,1),promptCharBudget:w(e.promptCharBudget,t.promptCharBudget,1),maxThreads:w(e.maxThreads,t.maxThreads,1)}},v=["<|channel>thought\n","<|channel>thought","..."],k=["<channel|>","..."],b=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,M=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,T=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[...M(e),{type:"text",text:"\n"},...M(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n},C=async({model:e,logging:t,onReason:n,onText:a,start:o,stopped:r})=>{let s="",i="",c="";const l=((e,t)=>{let n="",a=!1;const o=(e,t)=>{let n=-1,a="";for(const o of t){const t=e.indexOf(o);t>=0&&(n<0||t<n)&&(n=t,a=o)}return{at:n,tag:a}},r=(e,t)=>{let n="";for(const a of t)for(let t=Math.min(e.length,a.length-1);t>n.length;t--)if(e.endsWith(a.slice(0,t))){n=e.slice(e.length-t);break}return n};return{feed:s=>{let i=n+s;for(n="";i;){if(a){const{at:t,tag:s}=o(i,k);if(t>=0){t&&e(i.slice(0,t)),i=i.slice(t+s.length),a=!1;continue}const c=r(i,k);e(i.slice(0,i.length-c.length)),n=c;break}{const{at:e,tag:s}=o(i,v);if(e>=0){e&&t(i.slice(0,e)),i=i.slice(e+s.length),i.startsWith("\n")&&(i=i.slice(1)),a=!0;continue}const c=r(i,v);t(i.slice(0,i.length-c.length)),n=c;break}}},flush:()=>{n&&(a?e(n):t(n),n="")}}})(e=>{i+=e,n(e)},e=>{s+=e,a(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],a=e?.delta,o="string"==typeof a?.reasoning_content?a.reasoning_content:"string"==typeof a?.reasoning?a.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(i+=o,n(o)),a?.content&&l.feed(a.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:s||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",s.length,i.length)),d},_=async({model:e,params:t,start:n,stopped:a})=>{const r=await(async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push(n);continue}const e=[];for(const t of n.content)e.push("image"==t.type?{type:"image",url:await h(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=y)=>{const n=t.maxContentLength,a=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=o.user||!e.images?.length)),r=[],s=[];let i=0,c=t.maxImages;for(let e=a.length-1;e>=0;e--){const l=a[e],d=("string"==typeof l.content?l.content:"").slice(0,n),g=l.role==o.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&i+d.length>t.promptCharBudget)break;i+=d.length,c-=g.length,l.role==o.system?r.unshift(d):l.role==o.assistant?s.unshift({role:"assistant",content:d}):s.unshift({role:"user",content:b(d,g)})}}for(;s.length&&"user"!=s[0].role;)s.shift();const l=[];for(const e of s){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=T(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=r.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),g})(t.messages,t.limits));return t.logging&&((e,t)=>{console.log("Local chat call",e.id,t.map(({role:e,content:t})=>({role:e,content:"****",...Array.isArray(t)?{images:t.filter(e=>"image"==e.type).length}:{}})))})(e,r),await C({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>n(r),stopped:a})};let L,j,q="",R=!1;const W=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,$=e=>{const t=p();return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},B=e=>{const t=e=>(...t)=>{R&&("string"==typeof t[0]&&t[0].includes("ggml_webgpu: Failed to get an adapter")||e(...t))};return{...e,log:t(e.log),warn:t(e.warn),error:t(e.error)}},I=async()=>{if(L)return L;const e=await n.e(924).then(()=>n(577)),t=j||$(),a=new e.Wllama({default:t.wasm},{logger:B(e.LoggerWithoutDebug)});return j||(j=t,q=W(t)),a.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),L=a,a},P=async()=>{const e=L;L=void 0;try{await(e?.exit())}catch{}},O=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),A=e=>[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]],U=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,S=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),n=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!n.includes(";base64"))return await(await fetch(e)).arrayBuffer();const a=atob(e.slice(t+1)),o=new Uint8Array(a.length);for(let e=0;e<a.length;e++)o[e]=a.charCodeAt(e);return o.buffer},F=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){"system"==n.role?t.push({role:"system",content:n.content}):"assistant"==n.role?t.push({role:"assistant",content:n.content}):t.push({role:"user",content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await S(t.url)});t.push({role:"user",content:e})}return t},E=async(e,t,n)=>{if(R=!0===n.logging,e.isModelLoaded())return await _({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if((e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)))(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await F(a),...(o=n.limits,r=n.reasoning,{stream:!0,temperature:.7,max_tokens:r?o.maxReasoningTokens:o.maxReplyTokens}),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}});var o,r}})},Q={backend:i.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{R=!0===o;const s=$(r),l=W(s);L&&l!=q&&await P(),j=s,q=l;const d=(g="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,u=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(g||4)-1)),u)));var g,u;const m=await I(),p=U(e.cpu.repo,e.cpu.file),f=e.cpu.mmproj?.file,h=f?U(e.cpu.repo,f):"";if(a?.aborted)throw await P(),new Error("Cancelled");if(f){const t=await m.cacheManager.list(),n=t.some(t=>O(t,e.cpu.file)),a=t.some(e=>O(e,f));n&&!a&&await m.cacheManager.deleteMany(t=>O(t,e.cpu.file))}try{await m.loadModelFromUrl(h?{url:p,mmprojUrl:h}:p,{n_ctx:8192,n_threads:d,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!0,signal:a,progressCallback:({loaded:e,total:t})=>{const a=t?e/t:0;n(a,a>=1?c.load:c.download)}})}catch(e){throw await P(),e}if(a?.aborted)throw await P(),new Error("Cancelled");if(!m.getLoadedContextInfo().n_ctx)throw await P(),new Error("Failed to create model context");return{model:e,backend:i.cpu,contextSize:8192,chat:t=>E(m,e,t),unload:async()=>{if(L==m)await P();else try{await m.exit()}catch{}}}},cached:async e=>{try{const t=await I(),n=await t.cacheManager.list();return A(e).every(e=>n.some(t=>O(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await I();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{const t=await I();await t.cacheManager.deleteMany(t=>A(e).some(e=>O(t,e)))}catch{}},purge:async()=>{try{const e=await I();await e.cacheManager.clear()}catch{}}},D=((e={})=>{const t=e.engines?.cpu||Q;let n,a,o,r,l,g,u,m=i.none,p=s.idle,f=0,h={percent:0,phase:c.download};const y=()=>e.backend||("undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?i.none:i.cpu),w=async()=>{await t.purge()},x=(e,t)=>{h={percent:Math.max(0,Math.min(1,e)),phase:t||c.download},g?.(h.percent,h.phase)},v=e=>{p=e},k=()=>p==s.ready&&!!n&&!!a;return{load:async({model:e,limits:u,assets:p,logging:b,onProgress:M})=>{if(k()&&a?.id==e.id)return!0;if(o&&r==e.id)return g=M,M(h.percent,h.phase),await o;o&&(g=void 0,l?.abort(),await o.catch(()=>!1)),g=M;const T=++f,C=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const o=y();if(T!=f)return!1;if(o==i.none)return v(s.unsupported),!1;if(await(async e=>{if(a&&a.id!=e.id){const e=a,o=n;n=void 0,a=void 0,await(o?.unload()),await t.remove(e)}if(await t.hasCache())for(const n of d)n.id!=e.id&&await t.remove(n)})(e),T!=f)return!1;const r=await t.cached(e);if(T!=f)return!1;if(!r&&await(async()=>{try{if("undefined"==typeof navigator)return!1;if(!navigator.storage?.estimate)return!1;const{quota:e=0,usage:t=0}=await navigator.storage.estimate();return!!e&&t>=e}catch{return!1}})()&&await w(),T!=f)return!1;v(s.downloading),x(0,c.download),r&&x(1,c.load);const g=new AbortController;l=g;try{const r=await t.startLLM({model:e,limits:u,logging:b,signal:g.signal,assets:p,onProgress:(e,t)=>{T==f&&x(e,t)}});return T!=f||g.signal.aborted?(await r.unload(),!1):(n=r,a=e,m=o,v(s.ready),x(1,c.load),!0)}catch(e){return T!=f||(n=void 0,a=void 0,b&&console.log("Local model failed",e),(e=>["quota","no space","disk full","ns_error_dom_quota_reached"].some(t=>`${e?.name||""} ${e?.message||`${e}`}`.toLowerCase().includes(t)))(e)&&await w(),v(s.error)),!1}finally{l==g&&(l=void 0)}})().finally(()=>{o==C&&(o=void 0,r=void 0)});return o=C,r=e.id,await C},chat:async e=>{if(!k()||!n)return;for(;u;)await u.catch(()=>{});if(!k()||!n)return;const t=n.chat(e);u=t;try{return await t}finally{u==t&&(u=void 0)}},unload:async()=>{f++,l?.abort(),l=void 0,r=void 0;const e=n;n=void 0,a=void 0,v(s.idle),await(e?.unload())},cancelLoad:()=>{f++,l?.abort(),l=void 0,r=void 0,p==s.downloading&&v(s.idle)},ready:k,loading:()=>!k()&&p==s.downloading,status:()=>p,backend:()=>m,model:()=>a}})(),V=(e,t,n)=>{const a=e.status(),o=g(t);return{availability:a==s.ready?r.online:a==s.error||a==s.unsupported?r.offline:r.away,status:a,backend:e.backend(),supportsImages:!!o&&u(o),ready:e.ready(),loading:e.loading(),requesting:n.requesting,phase:n.phase,percent:n.percent,...n.error?{error:n.error}:{}}},G=(e=>{let t,n=0;const a=t=>t.input.onStatus?.(V(e,t.input.model,t));return r=>{t?.controller.abort();const i={token:++n,input:r,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?c.load:c.download,requesting:!1,cancelled:!1};return t=i,a(i),(async t=>{const{input:r}=t,s=!0===r.logging,i=g(r.model),l=r.messages.some(e=>e.role!=o.system&&"string"==typeof e.content&&!!e.content.trim()),d=r.messages.some(e=>e.role==o.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),m=l||d;if(!i)return t.error="Unknown model",void a(t);if(!m)return void a(t);if(d&&!l&&!u(i))return t.error="Model does not accept images",void a(t);const p=x(r.limits),f=await e.load({model:i,limits:p,logging:s,onProgress:(e,o)=>{t.token==n&&(t.percent=Math.round(100*e),t.phase=o,a(t))}}).catch(e=>(t.token==n&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=n)return;if(!f)return t.cancelled||t.error||(t.error="Model not ready"),void a(t);const h=u(i),y=d&&!h?r.messages.map(({images:e,...t})=>t):r.messages;if(d&&!h&&!l)return t.error="Model does not accept images",void a(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=c.load,a(t);let w,v="",k="";try{w=await e.chat({messages:y,limits:p,reasoning:!0===r.reasoning,logging:s,onReason:e=>{t.token!=n||t.cancelled||(v+=e,r.onThinking?.(v))},onText:e=>{t.token!=n||t.cancelled||(k+=e,r.onResponse?.(k))},signal:t.controller.signal})}catch(e){if(t.token!=n)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void a(t)}t.token==n&&(t.requesting=!1,w||t.cancelled||(t.error="No reply"),a(t))})(i),()=>(t=>{t.token==n&&(t.cancelled=!0,t.controller.abort(),e.status()!=s.ready?(e.cancelLoad(),a(t)):e.unload().then(()=>a(t)))})(i)}})(D),N=(z=D,async e=>{const t=g(e.model),n=t=>e.onStatus?.(V(z,e.model,t));if(!t)return n({requesting:!1,phase:c.download,percent:0,error:"Unknown model"}),!1;let a,o=0,r=c.download;const s=z.ready()&&z.model()?.id==t.id;return await z.load({model:t,limits:x(e.limits),logging:!0===e.logging,onProgress:(e,t)=>{o=Math.round(100*e),r=t,n({requesting:!1,phase:r,percent:o})}}).catch(e=>(a=`${e?.message||`${e}`}`,!1))?(s&&n({requesting:!1,phase:c.load,percent:100}),!0):(n({requesting:!1,phase:r,percent:o,error:a||"Model not ready"}),!1)});var z;module.exports=a})();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see chat.node.min.mjs.LICENSE.txt */
|
|
2
|
-
import{dirname as e,join as t}from"node:path";import{fileURLToPath as n}from"node:url";var a={};const o={};function r(e){const t=o[e];if(void 0!==t)return t.exports;const n=o[e]={exports:{}};return a[e](n,n.exports,r),n.exports}var s,i,c,l,d,g;r.m=a,r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.f={},r.e=e=>{const t=[];return r.f.j(e,t),Promise.all(t)},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={924:()=>import("./engine-wllama.node.min.mjs")},t={792:0},n=e=>{let{__webpack_esm_ids__:n,__webpack_esm_modules__:a,__webpack_esm_runtime__:o}=e;var s,i,c=0;for(s in a)r.o(a,s)&&(r.m[s]=a[s]);for(o&&o(r);c<n.length;c++)i=n[c],r.o(t,i)&&t[i]&&t[i][0](),t[i]=0};r.f.j=(a,o)=>{let s=r.o(t,a)?t[a]:void 0;if(0!==s)if(s)o.push(s[1]);else{let r=e[a]().then(n,e=>{throw 0!==t[a]&&(t[a]=void 0),e});r=Promise.race([r,new Promise(e=>s=t[a]=[e])]),o.push(s[1]=r)}}})(),function(e){e.system="system",e.user="user",e.assistant="assistant"}(s||(s={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(i||(i={})),function(e){e[e.idle=0]="idle",e[e.downloading=1]="downloading",e[e.ready=2]="ready",e[e.error=3]="error",e[e.unsupported=4]="unsupported"}(c||(c={})),function(e){e.cpu="cpu",e.none="none"}(l||(l={})),function(e){e.download="download",e.load="load"}(d||(d={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b"}(g||(g={}));const u=[{id:g.qwen3_vl_2b,reasoning:!0,cpu:{repo:"Qwen/Qwen3-VL-2B-Thinking-GGUF",file:"Qwen3VL-2B-Thinking-Q4_K_M.gguf",mmproj:{file:"mmproj-Qwen3VL-2B-Thinking-Q8_0.gguf"}}}],m=e=>e?u.find(t=>t.id==e):void 0,f=e=>!!e.cpu.mmproj,p=()=>{return a=t(e(n("file:///media/x/store/code/DegreeSign/ds_chat/src/assets/nodeEsm.js")),"../assets/wllama"),{wasm:t(a,"wllama.wasm"),compatWasm:t(a,"compat/wllama.wasm"),compatWorker:t(a,"compat/wllama.js")};var a},h=288,w=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),n=await createImageBitmap(await t.blob()),a=Math.min(n.width,n.height),o=Math.floor((n.width-a)/2),r=Math.floor((n.height-a)/2),s=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const n=document.createElement("canvas");return n.width=e,n.height=t,n})(h,h),i=s?s.getContext("2d"):null;if(!s||!i||a<1)return n.close(),e;if(i.drawImage(n,o,r,a,a,0,0,h,h),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(s)){const t=await s.convertToBlob({type:"image/jpeg",quality:.85});return await(e=>new Promise(t=>{if("undefined"==typeof FileReader)return void t("");const n=new FileReader;n.onerror=()=>t(""),n.onload=()=>t(`${n.result}`),n.readAsDataURL(e)}))(t)||e}return s.toDataURL("image/jpeg",.85)}catch{return e}},y={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},x=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,k=["<|channel>thought\n","<|channel>thought","..."],v=["<channel|>","..."],b=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,_=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,T=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[..._(e),{type:"text",text:"\n"},..._(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n},M=async({model:e,logging:t,onReason:n,onText:a,start:o,stopped:r})=>{let s="",i="",c="";const l=((e,t)=>{let n="",a=!1;const o=(e,t)=>{let n=-1,a="";for(const o of t){const t=e.indexOf(o);t>=0&&(n<0||t<n)&&(n=t,a=o)}return{at:n,tag:a}},r=(e,t)=>{let n="";for(const a of t)for(let t=Math.min(e.length,a.length-1);t>n.length;t--)if(e.endsWith(a.slice(0,t))){n=e.slice(e.length-t);break}return n};return{feed:s=>{let i=n+s;for(n="";i;){if(a){const{at:t,tag:s}=o(i,v);if(t>=0){t&&e(i.slice(0,t)),i=i.slice(t+s.length),a=!1;continue}const c=r(i,v);e(i.slice(0,i.length-c.length)),n=c;break}{const{at:e,tag:s}=o(i,k);if(e>=0){e&&t(i.slice(0,e)),i=i.slice(e+s.length),i.startsWith("\n")&&(i=i.slice(1)),a=!0;continue}const c=r(i,k);t(i.slice(0,i.length-c.length)),n=c;break}}},flush:()=>{n&&(a?e(n):t(n),n="")}}})(e=>{i+=e,n(e)},e=>{s+=e,a(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],a=e?.delta,o="string"==typeof a?.reasoning_content?a.reasoning_content:"string"==typeof a?.reasoning?a.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(i+=o,n(o)),a?.content&&l.feed(a.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:s||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",s.length,i.length)),d},C=async({model:e,params:t,start:n,stopped:a})=>{const o=await(async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push(n);continue}const e=[];for(const t of n.content)e.push("image"==t.type?{type:"image",url:await w(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=y)=>{const n=t.maxContentLength,a=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=s.user||!e.images?.length)),o=[],r=[];let i=0,c=t.maxImages;for(let e=a.length-1;e>=0;e--){const l=a[e],d=("string"==typeof l.content?l.content:"").slice(0,n),g=l.role==s.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&i+d.length>t.promptCharBudget)break;i+=d.length,c-=g.length,l.role==s.system?o.unshift(d):l.role==s.assistant?r.unshift({role:"assistant",content:d}):r.unshift({role:"user",content:b(d,g)})}}for(;r.length&&"user"!=r[0].role;)r.shift();const l=[];for(const e of r){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=T(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=o.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),g})(t.messages,t.limits));return t.logging&&((e,t)=>{console.log("Local chat call",e.id,t.map(({role:e,content:t})=>({role:e,content:"****",...Array.isArray(t)?{images:t.filter(e=>"image"==e.type).length}:{}})))})(e,o),await M({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>n(o),stopped:a})};let L,j,R="",W=!1;const $=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,q=e=>{const t=p();return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},B=e=>{const t=e=>(...t)=>{W&&("string"==typeof t[0]&&t[0].includes("ggml_webgpu: Failed to get an adapter")||e(...t))};return{...e,log:t(e.log),warn:t(e.warn),error:t(e.error)}},P=async()=>{if(L)return L;const e=await r.e(924).then(()=>r(577)),t=j||q(),n=new e.Wllama({default:t.wasm},{logger:B(e.LoggerWithoutDebug)});return j||(j=t,R=$(t)),n.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),L=n,n},I=async()=>{const e=L;L=void 0;try{await(e?.exit())}catch{}},O=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),A=e=>[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]],U=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,E=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),n=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!n.includes(";base64"))return await(await fetch(e)).arrayBuffer();const a=atob(e.slice(t+1)),o=new Uint8Array(a.length);for(let e=0;e<a.length;e++)o[e]=a.charCodeAt(e);return o.buffer},F=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){"system"==n.role?t.push({role:"system",content:n.content}):"assistant"==n.role?t.push({role:"assistant",content:n.content}):t.push({role:"user",content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await E(t.url)});t.push({role:"user",content:e})}return t},Q=async(e,t,n)=>{if(W=!0===n.logging,e.isModelLoaded())return await C({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if((e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)))(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await F(a),...(o=n.limits,r=n.reasoning,{stream:!0,temperature:.7,max_tokens:r?o.maxReasoningTokens:o.maxReplyTokens}),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}});var o,r}})},S={backend:l.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{W=!0===o;const s=q(r),i=$(s);L&&i!=R&&await I(),j=s,R=i;const c=(g="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,u=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(g||4)-1)),u)));var g,u;const m=await P(),f=U(e.cpu.repo,e.cpu.file),p=e.cpu.mmproj?.file,h=p?U(e.cpu.repo,p):"";if(a?.aborted)throw await I(),new Error("Cancelled");if(p){const t=await m.cacheManager.list(),n=t.some(t=>O(t,e.cpu.file)),a=t.some(e=>O(e,p));n&&!a&&await m.cacheManager.deleteMany(t=>O(t,e.cpu.file))}try{await m.loadModelFromUrl(h?{url:f,mmprojUrl:h}:f,{n_ctx:8192,n_threads:c,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!0,signal:a,progressCallback:({loaded:e,total:t})=>{const a=t?e/t:0;n(a,a>=1?d.load:d.download)}})}catch(e){throw await I(),e}if(a?.aborted)throw await I(),new Error("Cancelled");if(!m.getLoadedContextInfo().n_ctx)throw await I(),new Error("Failed to create model context");return{model:e,backend:l.cpu,contextSize:8192,chat:t=>Q(m,e,t),unload:async()=>{if(L==m)await I();else try{await m.exit()}catch{}}}},cached:async e=>{try{const t=await P(),n=await t.cacheManager.list();return A(e).every(e=>n.some(t=>O(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await P();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{const t=await P();await t.cacheManager.deleteMany(t=>A(e).some(e=>O(t,e)))}catch{}},purge:async()=>{try{const e=await P();await e.cacheManager.clear()}catch{}}},D=((e={})=>{const t=e.engines?.cpu||S;let n,a,o,r,s,i,g,m=l.none,f=c.idle,p=0,h={percent:0,phase:d.download};const w=()=>e.backend||("undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?l.none:l.cpu),y=async()=>{await t.purge()},x=(e,t)=>{h={percent:Math.max(0,Math.min(1,e)),phase:t||d.download},i?.(h.percent,h.phase)},k=e=>{f=e},v=()=>f==c.ready&&!!n&&!!a;return{load:async({model:e,limits:g,assets:f,logging:b,onProgress:_})=>{if(v()&&a?.id==e.id)return!0;if(o&&r==e.id)return i=_,_(h.percent,h.phase),await o;o&&(i=void 0,s?.abort(),await o.catch(()=>!1)),i=_;const T=++p,M=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const o=w();if(T!=p)return!1;if(o==l.none)return k(c.unsupported),!1;if(await(async e=>{if(a&&a.id!=e.id){const e=a,o=n;n=void 0,a=void 0,await(o?.unload()),await t.remove(e)}if(await t.hasCache())for(const n of u)n.id!=e.id&&await t.remove(n)})(e),T!=p)return!1;const r=await t.cached(e);if(T!=p)return!1;if(!r&&await(async()=>{try{if("undefined"==typeof navigator)return!1;if(!navigator.storage?.estimate)return!1;const{quota:e=0,usage:t=0}=await navigator.storage.estimate();return!!e&&t>=e}catch{return!1}})()&&await y(),T!=p)return!1;k(c.downloading),x(0,d.download),r&&x(1,d.load);const i=new AbortController;s=i;try{const r=await t.startLLM({model:e,limits:g,logging:b,signal:i.signal,assets:f,onProgress:(e,t)=>{T==p&&x(e,t)}});return T!=p||i.signal.aborted?(await r.unload(),!1):(n=r,a=e,m=o,k(c.ready),x(1,d.load),!0)}catch(e){return T!=p||(n=void 0,a=void 0,b&&console.log("Local model failed",e),(e=>["quota","no space","disk full","ns_error_dom_quota_reached"].some(t=>`${e?.name||""} ${e?.message||`${e}`}`.toLowerCase().includes(t)))(e)&&await y(),k(c.error)),!1}finally{s==i&&(s=void 0)}})().finally(()=>{o==M&&(o=void 0,r=void 0)});return o=M,r=e.id,await M},chat:async e=>{if(!v()||!n)return;for(;g;)await g.catch(()=>{});if(!v()||!n)return;const t=n.chat(e);g=t;try{return await t}finally{g==t&&(g=void 0)}},unload:async()=>{p++,s?.abort(),s=void 0,r=void 0;const e=n;n=void 0,a=void 0,k(c.idle),await(e?.unload())},cancelLoad:()=>{p++,s?.abort(),s=void 0,r=void 0,f==c.downloading&&k(c.idle)},ready:v,loading:()=>!v()&&f==c.downloading,status:()=>f,backend:()=>m,model:()=>a}})(),V=(e=>{let t,n=0;const a=t=>{const n=e.status(),a=e.backend(),o=m(t.input.model),r={availability:n==c.ready?i.online:n==c.error||n==c.unsupported?i.offline:i.away,status:n,backend:a,supportsImages:!!o&&f(o),ready:e.ready(),loading:e.loading(),requesting:t.requesting,phase:t.phase,percent:t.percent,...t.error?{error:t.error}:{}};t.input.onStatus?.(r)},o=async t=>{const{input:o}=t,r=!0===o.logging,i=m(o.model),c=o.messages.some(e=>e.role!=s.system&&"string"==typeof e.content&&!!e.content.trim()),l=o.messages.some(e=>e.role==s.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),g=c||l;if(!i)return t.error="Unknown model",void a(t);if(!g)return void a(t);if(l&&!c&&!f(i))return t.error="Model does not accept images",void a(t);const u=((e={})=>{const t=y;return{maxReplyTokens:x(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:x(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:x(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:x(e.maxImages,t.maxImages,0),maxContentLength:x(e.maxContentLength,t.maxContentLength,1),promptCharBudget:x(e.promptCharBudget,t.promptCharBudget,1),maxThreads:x(e.maxThreads,t.maxThreads,1)}})(o.limits),p=await e.load({model:i,limits:u,logging:r,onProgress:(e,o)=>{t.token==n&&(t.percent=Math.round(100*e),t.phase=o,a(t))}}).catch(e=>(t.token==n&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=n)return;if(!p)return t.cancelled||t.error||(t.error="Model not ready"),void a(t);const h=f(i),w=l&&!h?o.messages.map(({images:e,...t})=>t):o.messages;if(l&&!h&&!c)return t.error="Model does not accept images",void a(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=d.load,a(t);let k,v="",b="";try{k=await e.chat({messages:w,limits:u,reasoning:!0===o.reasoning,logging:r,onReason:e=>{t.token!=n||t.cancelled||(v+=e,o.onThinking?.(v))},onText:e=>{t.token!=n||t.cancelled||(b+=e,o.onResponse?.(b))},signal:t.controller.signal})}catch(e){if(t.token!=n)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void a(t)}t.token==n&&(t.requesting=!1,k||t.cancelled||(t.error="No reply"),a(t))};return r=>{t?.controller.abort();const s={token:++n,input:r,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?d.load:d.download,requesting:!1,cancelled:!1};return t=s,a(s),o(s),()=>(t=>{t.token==n&&(t.cancelled=!0,t.controller.abort(),e.status()!=c.ready?(e.cancelLoad(),a(t)):e.unload().then(()=>a(t)))})(s)}})(D);export{g as ChatModelId,i as ChatStatus,l as LlmBackend,d as LlmPhase,s as LlmRole,c as LlmStatus,V as createChat};
|
|
2
|
+
import{dirname as e,join as t}from"node:path";import{fileURLToPath as n}from"node:url";var a={};const o={};function r(e){const t=o[e];if(void 0!==t)return t.exports;const n=o[e]={exports:{}};return a[e](n,n.exports,r),n.exports}var s,i,c,l,d,g;r.m=a,r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.f={},r.e=e=>{const t=[];return r.f.j(e,t),Promise.all(t)},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={924:()=>import("./engine-wllama.node.min.mjs")},t={792:0},n=e=>{let{__webpack_esm_ids__:n,__webpack_esm_modules__:a,__webpack_esm_runtime__:o}=e;var s,i,c=0;for(s in a)r.o(a,s)&&(r.m[s]=a[s]);for(o&&o(r);c<n.length;c++)i=n[c],r.o(t,i)&&t[i]&&t[i][0](),t[i]=0};r.f.j=(a,o)=>{let s=r.o(t,a)?t[a]:void 0;if(0!==s)if(s)o.push(s[1]);else{let r=e[a]().then(n,e=>{throw 0!==t[a]&&(t[a]=void 0),e});r=Promise.race([r,new Promise(e=>s=t[a]=[e])]),o.push(s[1]=r)}}})(),function(e){e.system="system",e.user="user",e.assistant="assistant"}(s||(s={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(i||(i={})),function(e){e[e.idle=0]="idle",e[e.downloading=1]="downloading",e[e.ready=2]="ready",e[e.error=3]="error",e[e.unsupported=4]="unsupported"}(c||(c={})),function(e){e.cpu="cpu",e.none="none"}(l||(l={})),function(e){e.download="download",e.load="load"}(d||(d={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b"}(g||(g={}));const u=[{id:g.qwen3_vl_2b,reasoning:!0,cpu:{repo:"Qwen/Qwen3-VL-2B-Thinking-GGUF",file:"Qwen3VL-2B-Thinking-Q4_K_M.gguf",mmproj:{file:"mmproj-Qwen3VL-2B-Thinking-Q8_0.gguf"}}}],m=e=>e?u.find(t=>t.id==e):void 0,p=e=>!!e.cpu.mmproj,f=()=>{return a=t(e(n("file:///media/x/store/code/DegreeSign/ds_chat/src/assets/nodeEsm.js")),"../assets/wllama"),{wasm:t(a,"wllama.wasm"),compatWasm:t(a,"compat/wllama.wasm"),compatWorker:t(a,"compat/wllama.js")};var a},h=288,w=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),n=await createImageBitmap(await t.blob()),a=Math.min(n.width,n.height),o=Math.floor((n.width-a)/2),r=Math.floor((n.height-a)/2),s=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const n=document.createElement("canvas");return n.width=e,n.height=t,n})(h,h),i=s?s.getContext("2d"):null;if(!s||!i||a<1)return n.close(),e;if(i.drawImage(n,o,r,a,a,0,0,h,h),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(s)){const t=await s.convertToBlob({type:"image/jpeg",quality:.85});return await(e=>new Promise(t=>{if("undefined"==typeof FileReader)return void t("");const n=new FileReader;n.onerror=()=>t(""),n.onload=()=>t(`${n.result}`),n.readAsDataURL(e)}))(t)||e}return s.toDataURL("image/jpeg",.85)}catch{return e}},y={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},x=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,k=(e={})=>{const t=y;return{maxReplyTokens:x(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:x(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:x(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:x(e.maxImages,t.maxImages,0),maxContentLength:x(e.maxContentLength,t.maxContentLength,1),promptCharBudget:x(e.promptCharBudget,t.promptCharBudget,1),maxThreads:x(e.maxThreads,t.maxThreads,1)}},v=["<|channel>thought\n","<|channel>thought","..."],b=["<channel|>","..."],_=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,T=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,M=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[...T(e),{type:"text",text:"\n"},...T(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n},C=async({model:e,logging:t,onReason:n,onText:a,start:o,stopped:r})=>{let s="",i="",c="";const l=((e,t)=>{let n="",a=!1;const o=(e,t)=>{let n=-1,a="";for(const o of t){const t=e.indexOf(o);t>=0&&(n<0||t<n)&&(n=t,a=o)}return{at:n,tag:a}},r=(e,t)=>{let n="";for(const a of t)for(let t=Math.min(e.length,a.length-1);t>n.length;t--)if(e.endsWith(a.slice(0,t))){n=e.slice(e.length-t);break}return n};return{feed:s=>{let i=n+s;for(n="";i;){if(a){const{at:t,tag:s}=o(i,b);if(t>=0){t&&e(i.slice(0,t)),i=i.slice(t+s.length),a=!1;continue}const c=r(i,b);e(i.slice(0,i.length-c.length)),n=c;break}{const{at:e,tag:s}=o(i,v);if(e>=0){e&&t(i.slice(0,e)),i=i.slice(e+s.length),i.startsWith("\n")&&(i=i.slice(1)),a=!0;continue}const c=r(i,v);t(i.slice(0,i.length-c.length)),n=c;break}}},flush:()=>{n&&(a?e(n):t(n),n="")}}})(e=>{i+=e,n(e)},e=>{s+=e,a(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],a=e?.delta,o="string"==typeof a?.reasoning_content?a.reasoning_content:"string"==typeof a?.reasoning?a.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(i+=o,n(o)),a?.content&&l.feed(a.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:s||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",s.length,i.length)),d},L=async({model:e,params:t,start:n,stopped:a})=>{const o=await(async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push(n);continue}const e=[];for(const t of n.content)e.push("image"==t.type?{type:"image",url:await w(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=y)=>{const n=t.maxContentLength,a=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=s.user||!e.images?.length)),o=[],r=[];let i=0,c=t.maxImages;for(let e=a.length-1;e>=0;e--){const l=a[e],d=("string"==typeof l.content?l.content:"").slice(0,n),g=l.role==s.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&i+d.length>t.promptCharBudget)break;i+=d.length,c-=g.length,l.role==s.system?o.unshift(d):l.role==s.assistant?r.unshift({role:"assistant",content:d}):r.unshift({role:"user",content:_(d,g)})}}for(;r.length&&"user"!=r[0].role;)r.shift();const l=[];for(const e of r){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=M(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=o.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),g})(t.messages,t.limits));return t.logging&&((e,t)=>{console.log("Local chat call",e.id,t.map(({role:e,content:t})=>({role:e,content:"****",...Array.isArray(t)?{images:t.filter(e=>"image"==e.type).length}:{}})))})(e,o),await C({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>n(o),stopped:a})};let j,R,W="",$=!1;const q=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,P=e=>{const t=f();return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},B=e=>{const t=e=>(...t)=>{$&&("string"==typeof t[0]&&t[0].includes("ggml_webgpu: Failed to get an adapter")||e(...t))};return{...e,log:t(e.log),warn:t(e.warn),error:t(e.error)}},I=async()=>{if(j)return j;const e=await r.e(924).then(()=>r(577)),t=R||P(),n=new e.Wllama({default:t.wasm},{logger:B(e.LoggerWithoutDebug)});return R||(R=t,W=q(t)),n.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),j=n,n},O=async()=>{const e=j;j=void 0;try{await(e?.exit())}catch{}},A=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),U=e=>[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]],E=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,F=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),n=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!n.includes(";base64"))return await(await fetch(e)).arrayBuffer();const a=atob(e.slice(t+1)),o=new Uint8Array(a.length);for(let e=0;e<a.length;e++)o[e]=a.charCodeAt(e);return o.buffer},S=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){"system"==n.role?t.push({role:"system",content:n.content}):"assistant"==n.role?t.push({role:"assistant",content:n.content}):t.push({role:"user",content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await F(t.url)});t.push({role:"user",content:e})}return t},Q=async(e,t,n)=>{if($=!0===n.logging,e.isModelLoaded())return await L({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if((e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)))(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await S(a),...(o=n.limits,r=n.reasoning,{stream:!0,temperature:.7,max_tokens:r?o.maxReasoningTokens:o.maxReplyTokens}),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}});var o,r}})},D={backend:l.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{$=!0===o;const s=P(r),i=q(s);j&&i!=W&&await O(),R=s,W=i;const c=(g="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,u=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(g||4)-1)),u)));var g,u;const m=await I(),p=E(e.cpu.repo,e.cpu.file),f=e.cpu.mmproj?.file,h=f?E(e.cpu.repo,f):"";if(a?.aborted)throw await O(),new Error("Cancelled");if(f){const t=await m.cacheManager.list(),n=t.some(t=>A(t,e.cpu.file)),a=t.some(e=>A(e,f));n&&!a&&await m.cacheManager.deleteMany(t=>A(t,e.cpu.file))}try{await m.loadModelFromUrl(h?{url:p,mmprojUrl:h}:p,{n_ctx:8192,n_threads:c,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!0,signal:a,progressCallback:({loaded:e,total:t})=>{const a=t?e/t:0;n(a,a>=1?d.load:d.download)}})}catch(e){throw await O(),e}if(a?.aborted)throw await O(),new Error("Cancelled");if(!m.getLoadedContextInfo().n_ctx)throw await O(),new Error("Failed to create model context");return{model:e,backend:l.cpu,contextSize:8192,chat:t=>Q(m,e,t),unload:async()=>{if(j==m)await O();else try{await m.exit()}catch{}}}},cached:async e=>{try{const t=await I(),n=await t.cacheManager.list();return U(e).every(e=>n.some(t=>A(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await I();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{const t=await I();await t.cacheManager.deleteMany(t=>U(e).some(e=>A(t,e)))}catch{}},purge:async()=>{try{const e=await I();await e.cacheManager.clear()}catch{}}},V=((e={})=>{const t=e.engines?.cpu||D;let n,a,o,r,s,i,g,m=l.none,p=c.idle,f=0,h={percent:0,phase:d.download};const w=()=>e.backend||("undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?l.none:l.cpu),y=async()=>{await t.purge()},x=(e,t)=>{h={percent:Math.max(0,Math.min(1,e)),phase:t||d.download},i?.(h.percent,h.phase)},k=e=>{p=e},v=()=>p==c.ready&&!!n&&!!a;return{load:async({model:e,limits:g,assets:p,logging:b,onProgress:_})=>{if(v()&&a?.id==e.id)return!0;if(o&&r==e.id)return i=_,_(h.percent,h.phase),await o;o&&(i=void 0,s?.abort(),await o.catch(()=>!1)),i=_;const T=++f,M=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const o=w();if(T!=f)return!1;if(o==l.none)return k(c.unsupported),!1;if(await(async e=>{if(a&&a.id!=e.id){const e=a,o=n;n=void 0,a=void 0,await(o?.unload()),await t.remove(e)}if(await t.hasCache())for(const n of u)n.id!=e.id&&await t.remove(n)})(e),T!=f)return!1;const r=await t.cached(e);if(T!=f)return!1;if(!r&&await(async()=>{try{if("undefined"==typeof navigator)return!1;if(!navigator.storage?.estimate)return!1;const{quota:e=0,usage:t=0}=await navigator.storage.estimate();return!!e&&t>=e}catch{return!1}})()&&await y(),T!=f)return!1;k(c.downloading),x(0,d.download),r&&x(1,d.load);const i=new AbortController;s=i;try{const r=await t.startLLM({model:e,limits:g,logging:b,signal:i.signal,assets:p,onProgress:(e,t)=>{T==f&&x(e,t)}});return T!=f||i.signal.aborted?(await r.unload(),!1):(n=r,a=e,m=o,k(c.ready),x(1,d.load),!0)}catch(e){return T!=f||(n=void 0,a=void 0,b&&console.log("Local model failed",e),(e=>["quota","no space","disk full","ns_error_dom_quota_reached"].some(t=>`${e?.name||""} ${e?.message||`${e}`}`.toLowerCase().includes(t)))(e)&&await y(),k(c.error)),!1}finally{s==i&&(s=void 0)}})().finally(()=>{o==M&&(o=void 0,r=void 0)});return o=M,r=e.id,await M},chat:async e=>{if(!v()||!n)return;for(;g;)await g.catch(()=>{});if(!v()||!n)return;const t=n.chat(e);g=t;try{return await t}finally{g==t&&(g=void 0)}},unload:async()=>{f++,s?.abort(),s=void 0,r=void 0;const e=n;n=void 0,a=void 0,k(c.idle),await(e?.unload())},cancelLoad:()=>{f++,s?.abort(),s=void 0,r=void 0,p==c.downloading&&k(c.idle)},ready:v,loading:()=>!v()&&p==c.downloading,status:()=>p,backend:()=>m,model:()=>a}})(),G=(e,t,n)=>{const a=e.status(),o=m(t);return{availability:a==c.ready?i.online:a==c.error||a==c.unsupported?i.offline:i.away,status:a,backend:e.backend(),supportsImages:!!o&&p(o),ready:e.ready(),loading:e.loading(),requesting:n.requesting,phase:n.phase,percent:n.percent,...n.error?{error:n.error}:{}}},N=(e=>{let t,n=0;const a=t=>t.input.onStatus?.(G(e,t.input.model,t));return o=>{t?.controller.abort();const r={token:++n,input:o,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?d.load:d.download,requesting:!1,cancelled:!1};return t=r,a(r),(async t=>{const{input:o}=t,r=!0===o.logging,i=m(o.model),c=o.messages.some(e=>e.role!=s.system&&"string"==typeof e.content&&!!e.content.trim()),l=o.messages.some(e=>e.role==s.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),g=c||l;if(!i)return t.error="Unknown model",void a(t);if(!g)return void a(t);if(l&&!c&&!p(i))return t.error="Model does not accept images",void a(t);const u=k(o.limits),f=await e.load({model:i,limits:u,logging:r,onProgress:(e,o)=>{t.token==n&&(t.percent=Math.round(100*e),t.phase=o,a(t))}}).catch(e=>(t.token==n&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=n)return;if(!f)return t.cancelled||t.error||(t.error="Model not ready"),void a(t);const h=p(i),w=l&&!h?o.messages.map(({images:e,...t})=>t):o.messages;if(l&&!h&&!c)return t.error="Model does not accept images",void a(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=d.load,a(t);let y,x="",v="";try{y=await e.chat({messages:w,limits:u,reasoning:!0===o.reasoning,logging:r,onReason:e=>{t.token!=n||t.cancelled||(x+=e,o.onThinking?.(x))},onText:e=>{t.token!=n||t.cancelled||(v+=e,o.onResponse?.(v))},signal:t.controller.signal})}catch(e){if(t.token!=n)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void a(t)}t.token==n&&(t.requesting=!1,y||t.cancelled||(t.error="No reply"),a(t))})(r),()=>(t=>{t.token==n&&(t.cancelled=!0,t.controller.abort(),e.status()!=c.ready?(e.cancelLoad(),a(t)):e.unload().then(()=>a(t)))})(r)}})(V),z=(K=V,async e=>{const t=m(e.model),n=t=>e.onStatus?.(G(K,e.model,t));if(!t)return n({requesting:!1,phase:d.download,percent:0,error:"Unknown model"}),!1;let a,o=0,r=d.download;const s=K.ready()&&K.model()?.id==t.id;return await K.load({model:t,limits:k(e.limits),logging:!0===e.logging,onProgress:(e,t)=>{o=Math.round(100*e),r=t,n({requesting:!1,phase:r,percent:o})}}).catch(e=>(a=`${e?.message||`${e}`}`,!1))?(s&&n({requesting:!1,phase:d.load,percent:100}),!0):(n({requesting:!1,phase:r,percent:o,error:a||"Model not ready"}),!1)});var K;export{g as ChatModelId,i as ChatStatus,l as LlmBackend,d as LlmPhase,s as LlmRole,c as LlmStatus,N as createChat,z as preloadModel};
|
package/dist/types.d.ts
CHANGED
|
@@ -76,6 +76,8 @@ interface ChatInput {
|
|
|
76
76
|
/** Model and request state, reported on every change */
|
|
77
77
|
onStatus?: (snapshot: ChatStatusSnapshot) => void;
|
|
78
78
|
}
|
|
79
|
+
/** Model preload request, a subset of ChatInput */
|
|
80
|
+
type ChatPreloadInput = Pick<ChatInput, `model` | `limits` | `logging` | `onStatus`>;
|
|
79
81
|
/** Stop the current request, its model load, or free the loaded model */
|
|
80
82
|
type CancelChat = () => void;
|
|
81
83
|
/** wllama wasm assets used by the CPU engine */
|
|
@@ -87,16 +89,22 @@ interface WllamaAssets {
|
|
|
87
89
|
/** URL of the wllama compat worker script */
|
|
88
90
|
compatWorker: string;
|
|
89
91
|
}
|
|
92
|
+
/** Request state that builds one status snapshot */
|
|
93
|
+
interface ChatState {
|
|
94
|
+
/** Whether a reply is streaming right now */
|
|
95
|
+
requesting: boolean;
|
|
96
|
+
phase: LlmPhase;
|
|
97
|
+
/** Download or load progress, 0..100 */
|
|
98
|
+
percent: number;
|
|
99
|
+
/** Last request error, cleared when a reply starts */
|
|
100
|
+
error?: string;
|
|
101
|
+
}
|
|
90
102
|
/** One live chat request */
|
|
91
|
-
interface ActiveCall {
|
|
103
|
+
interface ActiveCall extends ChatState {
|
|
92
104
|
token: number;
|
|
93
105
|
input: ChatInput;
|
|
94
106
|
controller: AbortController;
|
|
95
|
-
percent: number;
|
|
96
|
-
phase: LlmPhase;
|
|
97
|
-
requesting: boolean;
|
|
98
107
|
cancelled: boolean;
|
|
99
|
-
error?: string;
|
|
100
108
|
}
|
|
101
109
|
/** Engine and backend overrides used by tests */
|
|
102
110
|
interface RuntimeDeps {
|
|
@@ -267,4 +275,4 @@ interface EngineRunParams {
|
|
|
267
275
|
/** Whether the caller stopped the generation */
|
|
268
276
|
stopped: () => boolean;
|
|
269
277
|
}
|
|
270
|
-
export type { ChatMessage, ChatModel, LlmLimits, ChatStatusSnapshot, ChatInput, CancelChat, WllamaAssets, ActiveCall, RuntimeDeps, RuntimeLoadParams, RuntimeChatParams, Runtime, EngineChatParams, StartLlmParams, LlmRuntime, LlmEngine, EngineMessage, EngineContentPart, WllamaContentPart, WllamaMessage, EngineDelta, EngineChunk, StreamReplyParams, EngineRunParams, };
|
|
278
|
+
export type { ChatMessage, ChatModel, LlmLimits, ChatStatusSnapshot, ChatInput, ChatPreloadInput, ChatState, CancelChat, WllamaAssets, ActiveCall, RuntimeDeps, RuntimeLoadParams, RuntimeChatParams, Runtime, EngineChatParams, StartLlmParams, LlmRuntime, LlmEngine, EngineMessage, EngineContentPart, WllamaContentPart, WllamaMessage, EngineDelta, EngineChunk, StreamReplyParams, EngineRunParams, };
|
package/package.json
CHANGED