It actually works (in Firefox)
Browse files- LOCAL_MODELS_README.md +17 -0
- docs/0-goal.md +53 -0
- models/google/gemma-2b/resolve/main +1 -0
- package-lock.json +236 -236
- package.json +4 -4
- src/worker/curated-model-list.json +9 -7
- src/worker/load-model-core.js +138 -12
- src/worker/model-cache.js +229 -4
LOCAL_MODELS_README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Put downloaded Hugging Face model repo files in the `models` folder so the dev server can serve them locally.
|
| 2 |
+
|
| 3 |
+
For Gemma (example):
|
| 4 |
+
|
| 5 |
+
1. Create directory: `models/google/gemma-2b/resolve/main/`
|
| 6 |
+
2. Download and place files into that directory as they would appear on HF, e.g.:
|
| 7 |
+
- config.json
|
| 8 |
+
- tokenizer.json
|
| 9 |
+
- tokenizer_config.json
|
| 10 |
+
- pytorch_model.bin (or converted files)
|
| 11 |
+
- any other weights/tokenizer files
|
| 12 |
+
|
| 13 |
+
The app expects to fetch assets at paths like:
|
| 14 |
+
|
| 15 |
+
http://127.0.0.1:8812/models/google/gemma-2b/resolve/main/config.json
|
| 16 |
+
|
| 17 |
+
After placing files, reload the app and select the local Gemma entry from the slash menu. If files are present, the loader should be able to read config and proceed; if not present you'll get 404s for the missing files.
|
docs/0-goal.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# LocalM: Project Goals & Architectural Decisions
|
| 2 |
+
|
| 3 |
+
This document outlines the problem statement, goals, and key architectural and technical policies for the `localm` project, synthesized from the project's structure and planning documents.
|
| 4 |
+
|
| 5 |
+
## 1. Problem Statement
|
| 6 |
+
|
| 7 |
+
The core challenge is to build a web application that can **run large language models (LLMs) for text generation directly in the browser**. This presents three primary technical hurdles:
|
| 8 |
+
|
| 9 |
+
1. **Model Compatibility**: Many models available on public hubs (like Hugging Face) are not designed for text generation (e.g., encoder-only models like BERT). Attempting to load these with a generation pipeline leads to runtime errors and a poor user experience.
|
| 10 |
+
2. **UI Responsiveness**: Model discovery, loading, and inference are resource-intensive operations that can easily block the browser's main thread, causing the UI to freeze and become unresponsive.
|
| 11 |
+
3. **Backend Optimization**: Multiple technologies exist for running models in the browser (e.g., Transformers.js, WebLLM), each with different performance characteristics and model support. The application needs an efficient strategy to use the best available backend for any given situation.
|
| 12 |
+
|
| 13 |
+
## 2. Core Goals
|
| 14 |
+
|
| 15 |
+
To address the problem, the project is guided by the following goals:
|
| 16 |
+
|
| 17 |
+
1. **Robust Model Loading**: Implement a reliable system to filter models and ensure only generation-capable architectures are loaded, thereby preventing runtime failures.
|
| 18 |
+
2. **Responsive User Experience**: Guarantee a fluid UI by offloading all heavy computation (model discovery, loading, inference) to a background web worker.
|
| 19 |
+
3. **Optimized Inference Performance**: Integrate multiple backends with an "optimistic fallback" strategy: attempt to use the most performant backend first (WebLLM), and seamlessly fall back to the more broadly compatible one (Transformers.js) if it fails.
|
| 20 |
+
4. **Simple & Maintainable Architecture**: Prioritize simplicity and pragmatism. Avoid premature or unnecessary abstractions in favor of clear, minimal, and maintainable code that is easy to debug and evolve.
|
| 21 |
+
|
| 22 |
+
## 3. Architectural & Technical Policies
|
| 23 |
+
|
| 24 |
+
The project adheres to several key implementation decisions that form its architectural foundation.
|
| 25 |
+
|
| 26 |
+
### a. Worker-First Architecture
|
| 27 |
+
|
| 28 |
+
All computationally expensive tasks are delegated to a dedicated Web Worker (`src/worker/boot-worker.js`). The main UI thread remains lightweight and communicates with the worker via a dedicated connection manager (`src/app/worker-connection.js`). This is the fundamental policy for ensuring UI responsiveness.
|
| 29 |
+
|
| 30 |
+
### b. Two-Phase Model Discovery & Filtering
|
| 31 |
+
|
| 32 |
+
A robust, multi-step process, executed entirely within the worker, is used to identify suitable chat models.
|
| 33 |
+
|
| 34 |
+
1. **Phase 1: Heuristic Pre-filtering**: The worker first fetches a large list of model candidates from Hugging Face and applies a fast, network-free filter to eliminate obviously unsuitable models based on their metadata (e.g., `pipeline_tag`, name patterns).
|
| 35 |
+
2. **Phase 2: Config-Based Classification**: For the remaining candidates, the worker fetches each model's `config.json` file. It uses the `model_type` and `architectures` fields within this file to definitively classify the model as either generation-capable (`gen`), `encoder`, or `unknown`. This is the authoritative step for ensuring compatibility.
|
| 36 |
+
|
| 37 |
+
This entire process is implemented as a modern `async` generator (`src/worker/actions/list-chat-models.js`), which streams progress back to the UI for an incremental and responsive experience.
|
| 38 |
+
|
| 39 |
+
### c. Inline, Dual-Backend Integration
|
| 40 |
+
|
| 41 |
+
To achieve the best performance, the application integrates both WebLLM and Transformers.js using a simple, inline strategy.
|
| 42 |
+
|
| 43 |
+
- **Policy**: Optimistic Fallback.
|
| 44 |
+
- **Implementation**:
|
| 45 |
+
1. When a model is requested, the application first attempts to load it using the high-performance **WebLLM** engine.
|
| 46 |
+
2. If the WebLLM load fails for any reason (e.g., unsupported model, runtime error), the failure is logged, and the system **automatically falls back** to loading the model with the more universally compatible **Transformers.js** library.
|
| 47 |
+
3. At inference time, a simple, inline check (`if`/`else`) determines which engine is backing the loaded model and routes the request accordingly.
|
| 48 |
+
|
| 49 |
+
This approach was deliberately chosen over more complex architectural patterns (like registries, adapters, or orchestrators) to minimize complexity and maintenance overhead, in alignment with the goal of architectural simplicity.
|
| 50 |
+
|
| 51 |
+
### d. Minimal & Pragmatic Code Style
|
| 52 |
+
|
| 53 |
+
The project favors modern, concise, and readable JavaScript. It avoids complex abstractions where simple conditionals suffice and prefers clear, self-contained logic that is easy to test and debug. Exceptions are handled explicitly to either trigger a fallback or provide clear diagnostic information.
|
models/google/gemma-2b/resolve/main
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
Subproject commit 9b0cfec892e2bc2afd938c98eabe4e4a7b1e0ca1
|
package-lock.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
| 1 |
{
|
| 2 |
"name": "localm",
|
| 3 |
-
"version": "1.
|
| 4 |
"lockfileVersion": 3,
|
| 5 |
"requires": true,
|
| 6 |
"packages": {
|
| 7 |
"": {
|
| 8 |
"name": "localm",
|
| 9 |
-
"version": "1.
|
| 10 |
"license": "ISC",
|
| 11 |
"dependencies": {
|
| 12 |
-
"@huggingface/transformers": "
|
| 13 |
-
"@milkdown/crepe": "
|
| 14 |
-
"@mlc-ai/web-llm": "
|
| 15 |
-
"esbuild": "
|
| 16 |
}
|
| 17 |
},
|
| 18 |
"node_modules/@babel/helper-string-parser": {
|
|
@@ -34,12 +34,12 @@
|
|
| 34 |
}
|
| 35 |
},
|
| 36 |
"node_modules/@babel/parser": {
|
| 37 |
-
"version": "7.28.
|
| 38 |
-
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.
|
| 39 |
-
"integrity": "sha512-
|
| 40 |
"license": "MIT",
|
| 41 |
"dependencies": {
|
| 42 |
-
"@babel/types": "^7.28.
|
| 43 |
},
|
| 44 |
"bin": {
|
| 45 |
"parser": "bin/babel-parser.js"
|
|
@@ -49,9 +49,9 @@
|
|
| 49 |
}
|
| 50 |
},
|
| 51 |
"node_modules/@babel/types": {
|
| 52 |
-
"version": "7.28.
|
| 53 |
-
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.
|
| 54 |
-
"integrity": "sha512-
|
| 55 |
"license": "MIT",
|
| 56 |
"dependencies": {
|
| 57 |
"@babel/helper-string-parser": "^7.27.1",
|
|
@@ -62,9 +62,9 @@
|
|
| 62 |
}
|
| 63 |
},
|
| 64 |
"node_modules/@codemirror/autocomplete": {
|
| 65 |
-
"version": "6.18.
|
| 66 |
-
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.
|
| 67 |
-
"integrity": "sha512-
|
| 68 |
"license": "MIT",
|
| 69 |
"dependencies": {
|
| 70 |
"@codemirror/language": "^6.0.0",
|
|
@@ -136,9 +136,9 @@
|
|
| 136 |
}
|
| 137 |
},
|
| 138 |
"node_modules/@codemirror/lang-html": {
|
| 139 |
-
"version": "6.4.
|
| 140 |
-
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.
|
| 141 |
-
"integrity": "sha512-
|
| 142 |
"license": "MIT",
|
| 143 |
"dependencies": {
|
| 144 |
"@codemirror/autocomplete": "^6.0.0",
|
|
@@ -446,9 +446,9 @@
|
|
| 446 |
}
|
| 447 |
},
|
| 448 |
"node_modules/@codemirror/view": {
|
| 449 |
-
"version": "6.38.
|
| 450 |
-
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.
|
| 451 |
-
"integrity": "sha512-
|
| 452 |
"license": "MIT",
|
| 453 |
"dependencies": {
|
| 454 |
"@codemirror/state": "^6.5.0",
|
|
@@ -458,9 +458,9 @@
|
|
| 458 |
}
|
| 459 |
},
|
| 460 |
"node_modules/@emnapi/runtime": {
|
| 461 |
-
"version": "1.
|
| 462 |
-
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.
|
| 463 |
-
"integrity": "sha512
|
| 464 |
"license": "MIT",
|
| 465 |
"optional": true,
|
| 466 |
"dependencies": {
|
|
@@ -893,9 +893,9 @@
|
|
| 893 |
}
|
| 894 |
},
|
| 895 |
"node_modules/@floating-ui/dom": {
|
| 896 |
-
"version": "1.7.
|
| 897 |
-
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.
|
| 898 |
-
"integrity": "sha512-
|
| 899 |
"license": "MIT",
|
| 900 |
"dependencies": {
|
| 901 |
"@floating-ui/core": "^1.7.3",
|
|
@@ -918,9 +918,9 @@
|
|
| 918 |
}
|
| 919 |
},
|
| 920 |
"node_modules/@huggingface/transformers": {
|
| 921 |
-
"version": "3.7.
|
| 922 |
-
"resolved": "https://registry.npmjs.org/@huggingface/transformers/-/transformers-3.7.
|
| 923 |
-
"integrity": "sha512-
|
| 924 |
"license": "Apache-2.0",
|
| 925 |
"dependencies": {
|
| 926 |
"@huggingface/jinja": "^0.5.1",
|
|
@@ -1436,9 +1436,9 @@
|
|
| 1436 |
}
|
| 1437 |
},
|
| 1438 |
"node_modules/@lezer/javascript": {
|
| 1439 |
-
"version": "1.5.
|
| 1440 |
-
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.
|
| 1441 |
-
"integrity": "sha512-
|
| 1442 |
"license": "MIT",
|
| 1443 |
"dependencies": {
|
| 1444 |
"@lezer/common": "^1.2.0",
|
|
@@ -1549,21 +1549,21 @@
|
|
| 1549 |
"license": "MIT"
|
| 1550 |
},
|
| 1551 |
"node_modules/@milkdown/components": {
|
| 1552 |
-
"version": "7.15.
|
| 1553 |
-
"resolved": "https://registry.npmjs.org/@milkdown/components/-/components-7.15.
|
| 1554 |
-
"integrity": "sha512-
|
| 1555 |
"license": "MIT",
|
| 1556 |
"dependencies": {
|
| 1557 |
"@floating-ui/dom": "^1.5.1",
|
| 1558 |
-
"@milkdown/core": "7.15.
|
| 1559 |
-
"@milkdown/ctx": "7.15.
|
| 1560 |
-
"@milkdown/exception": "7.15.
|
| 1561 |
-
"@milkdown/plugin-tooltip": "7.15.
|
| 1562 |
-
"@milkdown/preset-commonmark": "7.15.
|
| 1563 |
-
"@milkdown/preset-gfm": "7.15.
|
| 1564 |
-
"@milkdown/prose": "7.15.
|
| 1565 |
-
"@milkdown/transformer": "7.15.
|
| 1566 |
-
"@milkdown/utils": "7.15.
|
| 1567 |
"@types/lodash-es": "^4.17.12",
|
| 1568 |
"clsx": "^2.0.0",
|
| 1569 |
"dompurify": "^3.2.5",
|
|
@@ -1571,7 +1571,7 @@
|
|
| 1571 |
"nanoid": "^5.0.9",
|
| 1572 |
"tslib": "^2.8.1",
|
| 1573 |
"unist-util-visit": "^5.0.0",
|
| 1574 |
-
"vue": "
|
| 1575 |
},
|
| 1576 |
"peerDependencies": {
|
| 1577 |
"@codemirror/language": "^6",
|
|
@@ -1580,15 +1580,15 @@
|
|
| 1580 |
}
|
| 1581 |
},
|
| 1582 |
"node_modules/@milkdown/core": {
|
| 1583 |
-
"version": "7.15.
|
| 1584 |
-
"resolved": "https://registry.npmjs.org/@milkdown/core/-/core-7.15.
|
| 1585 |
-
"integrity": "sha512
|
| 1586 |
"license": "MIT",
|
| 1587 |
"dependencies": {
|
| 1588 |
-
"@milkdown/ctx": "7.15.
|
| 1589 |
-
"@milkdown/exception": "7.15.
|
| 1590 |
-
"@milkdown/prose": "7.15.
|
| 1591 |
-
"@milkdown/transformer": "7.15.
|
| 1592 |
"remark-parse": "^11.0.0",
|
| 1593 |
"remark-stringify": "^11.0.0",
|
| 1594 |
"tslib": "^2.8.1",
|
|
@@ -1596,9 +1596,9 @@
|
|
| 1596 |
}
|
| 1597 |
},
|
| 1598 |
"node_modules/@milkdown/crepe": {
|
| 1599 |
-
"version": "7.15.
|
| 1600 |
-
"resolved": "https://registry.npmjs.org/@milkdown/crepe/-/crepe-7.15.
|
| 1601 |
-
"integrity": "sha512-
|
| 1602 |
"license": "MIT",
|
| 1603 |
"dependencies": {
|
| 1604 |
"@codemirror/commands": "^6.2.4",
|
|
@@ -1608,7 +1608,7 @@
|
|
| 1608 |
"@codemirror/theme-one-dark": "^6.1.2",
|
| 1609 |
"@codemirror/view": "^6.16.0",
|
| 1610 |
"@floating-ui/dom": "^1.5.1",
|
| 1611 |
-
"@milkdown/kit": "7.15.
|
| 1612 |
"@types/lodash-es": "^4.17.12",
|
| 1613 |
"clsx": "^2.0.0",
|
| 1614 |
"codemirror": "^6.0.1",
|
|
@@ -1619,212 +1619,212 @@
|
|
| 1619 |
"remark-math": "^6.0.0",
|
| 1620 |
"tslib": "^2.8.1",
|
| 1621 |
"unist-util-visit": "^5.0.0",
|
| 1622 |
-
"vue": "
|
| 1623 |
}
|
| 1624 |
},
|
| 1625 |
"node_modules/@milkdown/ctx": {
|
| 1626 |
-
"version": "7.15.
|
| 1627 |
-
"resolved": "https://registry.npmjs.org/@milkdown/ctx/-/ctx-7.15.
|
| 1628 |
-
"integrity": "sha512-
|
| 1629 |
"license": "MIT",
|
| 1630 |
"dependencies": {
|
| 1631 |
-
"@milkdown/exception": "7.15.
|
| 1632 |
"tslib": "^2.8.1"
|
| 1633 |
}
|
| 1634 |
},
|
| 1635 |
"node_modules/@milkdown/exception": {
|
| 1636 |
-
"version": "7.15.
|
| 1637 |
-
"resolved": "https://registry.npmjs.org/@milkdown/exception/-/exception-7.15.
|
| 1638 |
-
"integrity": "sha512-
|
| 1639 |
"license": "MIT",
|
| 1640 |
"dependencies": {
|
| 1641 |
"tslib": "^2.8.1"
|
| 1642 |
}
|
| 1643 |
},
|
| 1644 |
"node_modules/@milkdown/kit": {
|
| 1645 |
-
"version": "7.15.
|
| 1646 |
-
"resolved": "https://registry.npmjs.org/@milkdown/kit/-/kit-7.15.
|
| 1647 |
-
"integrity": "sha512-
|
| 1648 |
-
"license": "MIT",
|
| 1649 |
-
"dependencies": {
|
| 1650 |
-
"@milkdown/components": "7.15.
|
| 1651 |
-
"@milkdown/core": "7.15.
|
| 1652 |
-
"@milkdown/ctx": "7.15.
|
| 1653 |
-
"@milkdown/plugin-block": "7.15.
|
| 1654 |
-
"@milkdown/plugin-clipboard": "7.15.
|
| 1655 |
-
"@milkdown/plugin-cursor": "7.15.
|
| 1656 |
-
"@milkdown/plugin-history": "7.15.
|
| 1657 |
-
"@milkdown/plugin-indent": "7.15.
|
| 1658 |
-
"@milkdown/plugin-listener": "7.15.
|
| 1659 |
-
"@milkdown/plugin-slash": "7.15.
|
| 1660 |
-
"@milkdown/plugin-tooltip": "7.15.
|
| 1661 |
-
"@milkdown/plugin-trailing": "7.15.
|
| 1662 |
-
"@milkdown/plugin-upload": "7.15.
|
| 1663 |
-
"@milkdown/preset-commonmark": "7.15.
|
| 1664 |
-
"@milkdown/preset-gfm": "7.15.
|
| 1665 |
-
"@milkdown/prose": "7.15.
|
| 1666 |
-
"@milkdown/transformer": "7.15.
|
| 1667 |
-
"@milkdown/utils": "7.15.
|
| 1668 |
"tslib": "^2.8.1"
|
| 1669 |
}
|
| 1670 |
},
|
| 1671 |
"node_modules/@milkdown/plugin-block": {
|
| 1672 |
-
"version": "7.15.
|
| 1673 |
-
"resolved": "https://registry.npmjs.org/@milkdown/plugin-block/-/plugin-block-7.15.
|
| 1674 |
-
"integrity": "sha512-
|
| 1675 |
"license": "MIT",
|
| 1676 |
"dependencies": {
|
| 1677 |
"@floating-ui/dom": "^1.5.1",
|
| 1678 |
-
"@milkdown/core": "7.15.
|
| 1679 |
-
"@milkdown/ctx": "7.15.
|
| 1680 |
-
"@milkdown/exception": "7.15.
|
| 1681 |
-
"@milkdown/prose": "7.15.
|
| 1682 |
-
"@milkdown/utils": "7.15.
|
| 1683 |
"@types/lodash-es": "^4.17.12",
|
| 1684 |
"lodash-es": "^4.17.21",
|
| 1685 |
"tslib": "^2.8.1"
|
| 1686 |
}
|
| 1687 |
},
|
| 1688 |
"node_modules/@milkdown/plugin-clipboard": {
|
| 1689 |
-
"version": "7.15.
|
| 1690 |
-
"resolved": "https://registry.npmjs.org/@milkdown/plugin-clipboard/-/plugin-clipboard-7.15.
|
| 1691 |
-
"integrity": "sha512-
|
| 1692 |
"license": "MIT",
|
| 1693 |
"dependencies": {
|
| 1694 |
-
"@milkdown/core": "7.15.
|
| 1695 |
-
"@milkdown/ctx": "7.15.
|
| 1696 |
-
"@milkdown/prose": "7.15.
|
| 1697 |
-
"@milkdown/utils": "7.15.
|
| 1698 |
"tslib": "^2.8.1"
|
| 1699 |
}
|
| 1700 |
},
|
| 1701 |
"node_modules/@milkdown/plugin-cursor": {
|
| 1702 |
-
"version": "7.15.
|
| 1703 |
-
"resolved": "https://registry.npmjs.org/@milkdown/plugin-cursor/-/plugin-cursor-7.15.
|
| 1704 |
-
"integrity": "sha512-
|
| 1705 |
"license": "MIT",
|
| 1706 |
"dependencies": {
|
| 1707 |
-
"@milkdown/core": "7.15.
|
| 1708 |
-
"@milkdown/ctx": "7.15.
|
| 1709 |
-
"@milkdown/prose": "7.15.
|
| 1710 |
-
"@milkdown/utils": "7.15.
|
| 1711 |
"tslib": "^2.8.1"
|
| 1712 |
}
|
| 1713 |
},
|
| 1714 |
"node_modules/@milkdown/plugin-history": {
|
| 1715 |
-
"version": "7.15.
|
| 1716 |
-
"resolved": "https://registry.npmjs.org/@milkdown/plugin-history/-/plugin-history-7.15.
|
| 1717 |
-
"integrity": "sha512-
|
| 1718 |
"license": "MIT",
|
| 1719 |
"dependencies": {
|
| 1720 |
-
"@milkdown/core": "7.15.
|
| 1721 |
-
"@milkdown/ctx": "7.15.
|
| 1722 |
-
"@milkdown/prose": "7.15.
|
| 1723 |
-
"@milkdown/utils": "7.15.
|
| 1724 |
"tslib": "^2.8.1"
|
| 1725 |
}
|
| 1726 |
},
|
| 1727 |
"node_modules/@milkdown/plugin-indent": {
|
| 1728 |
-
"version": "7.15.
|
| 1729 |
-
"resolved": "https://registry.npmjs.org/@milkdown/plugin-indent/-/plugin-indent-7.15.
|
| 1730 |
-
"integrity": "sha512-
|
| 1731 |
"license": "MIT",
|
| 1732 |
"dependencies": {
|
| 1733 |
-
"@milkdown/core": "7.15.
|
| 1734 |
-
"@milkdown/ctx": "7.15.
|
| 1735 |
-
"@milkdown/prose": "7.15.
|
| 1736 |
-
"@milkdown/utils": "7.15.
|
| 1737 |
"tslib": "^2.8.1"
|
| 1738 |
}
|
| 1739 |
},
|
| 1740 |
"node_modules/@milkdown/plugin-listener": {
|
| 1741 |
-
"version": "7.15.
|
| 1742 |
-
"resolved": "https://registry.npmjs.org/@milkdown/plugin-listener/-/plugin-listener-7.15.
|
| 1743 |
-
"integrity": "sha512-
|
| 1744 |
"license": "MIT",
|
| 1745 |
"dependencies": {
|
| 1746 |
-
"@milkdown/core": "7.15.
|
| 1747 |
-
"@milkdown/ctx": "7.15.
|
| 1748 |
-
"@milkdown/prose": "7.15.
|
| 1749 |
-
"@milkdown/utils": "7.15.
|
| 1750 |
"@types/lodash-es": "^4.17.12",
|
| 1751 |
"lodash-es": "^4.17.21",
|
| 1752 |
"tslib": "^2.8.1"
|
| 1753 |
}
|
| 1754 |
},
|
| 1755 |
"node_modules/@milkdown/plugin-slash": {
|
| 1756 |
-
"version": "7.15.
|
| 1757 |
-
"resolved": "https://registry.npmjs.org/@milkdown/plugin-slash/-/plugin-slash-7.15.
|
| 1758 |
-
"integrity": "sha512-
|
| 1759 |
"license": "MIT",
|
| 1760 |
"dependencies": {
|
| 1761 |
"@floating-ui/dom": "^1.5.1",
|
| 1762 |
-
"@milkdown/core": "7.15.
|
| 1763 |
-
"@milkdown/ctx": "7.15.
|
| 1764 |
-
"@milkdown/exception": "7.15.
|
| 1765 |
-
"@milkdown/prose": "7.15.
|
| 1766 |
-
"@milkdown/utils": "7.15.
|
| 1767 |
"@types/lodash-es": "^4.17.12",
|
| 1768 |
"lodash-es": "^4.17.21",
|
| 1769 |
"tslib": "^2.8.1"
|
| 1770 |
}
|
| 1771 |
},
|
| 1772 |
"node_modules/@milkdown/plugin-tooltip": {
|
| 1773 |
-
"version": "7.15.
|
| 1774 |
-
"resolved": "https://registry.npmjs.org/@milkdown/plugin-tooltip/-/plugin-tooltip-7.15.
|
| 1775 |
-
"integrity": "sha512-
|
| 1776 |
"license": "MIT",
|
| 1777 |
"dependencies": {
|
| 1778 |
"@floating-ui/dom": "^1.5.1",
|
| 1779 |
-
"@milkdown/core": "7.15.
|
| 1780 |
-
"@milkdown/ctx": "7.15.
|
| 1781 |
-
"@milkdown/exception": "7.15.
|
| 1782 |
-
"@milkdown/prose": "7.15.
|
| 1783 |
-
"@milkdown/utils": "7.15.
|
| 1784 |
"@types/lodash-es": "^4.17.12",
|
| 1785 |
"lodash-es": "^4.17.21",
|
| 1786 |
"tslib": "^2.8.1"
|
| 1787 |
}
|
| 1788 |
},
|
| 1789 |
"node_modules/@milkdown/plugin-trailing": {
|
| 1790 |
-
"version": "7.15.
|
| 1791 |
-
"resolved": "https://registry.npmjs.org/@milkdown/plugin-trailing/-/plugin-trailing-7.15.
|
| 1792 |
-
"integrity": "sha512-
|
| 1793 |
"license": "MIT",
|
| 1794 |
"dependencies": {
|
| 1795 |
-
"@milkdown/core": "7.15.
|
| 1796 |
-
"@milkdown/ctx": "7.15.
|
| 1797 |
-
"@milkdown/prose": "7.15.
|
| 1798 |
-
"@milkdown/utils": "7.15.
|
| 1799 |
"tslib": "^2.8.1"
|
| 1800 |
}
|
| 1801 |
},
|
| 1802 |
"node_modules/@milkdown/plugin-upload": {
|
| 1803 |
-
"version": "7.15.
|
| 1804 |
-
"resolved": "https://registry.npmjs.org/@milkdown/plugin-upload/-/plugin-upload-7.15.
|
| 1805 |
-
"integrity": "sha512-
|
| 1806 |
"license": "MIT",
|
| 1807 |
"dependencies": {
|
| 1808 |
-
"@milkdown/core": "7.15.
|
| 1809 |
-
"@milkdown/ctx": "7.15.
|
| 1810 |
-
"@milkdown/exception": "7.15.
|
| 1811 |
-
"@milkdown/prose": "7.15.
|
| 1812 |
-
"@milkdown/utils": "7.15.
|
| 1813 |
"tslib": "^2.8.1"
|
| 1814 |
}
|
| 1815 |
},
|
| 1816 |
"node_modules/@milkdown/preset-commonmark": {
|
| 1817 |
-
"version": "7.15.
|
| 1818 |
-
"resolved": "https://registry.npmjs.org/@milkdown/preset-commonmark/-/preset-commonmark-7.15.
|
| 1819 |
-
"integrity": "sha512-
|
| 1820 |
"license": "MIT",
|
| 1821 |
"dependencies": {
|
| 1822 |
-
"@milkdown/core": "7.15.
|
| 1823 |
-
"@milkdown/ctx": "7.15.
|
| 1824 |
-
"@milkdown/exception": "7.15.
|
| 1825 |
-
"@milkdown/prose": "7.15.
|
| 1826 |
-
"@milkdown/transformer": "7.15.
|
| 1827 |
-
"@milkdown/utils": "7.15.
|
| 1828 |
"remark-inline-links": "^7.0.0",
|
| 1829 |
"tslib": "^2.8.1",
|
| 1830 |
"unist-util-visit": "^5.0.0",
|
|
@@ -1832,30 +1832,30 @@
|
|
| 1832 |
}
|
| 1833 |
},
|
| 1834 |
"node_modules/@milkdown/preset-gfm": {
|
| 1835 |
-
"version": "7.15.
|
| 1836 |
-
"resolved": "https://registry.npmjs.org/@milkdown/preset-gfm/-/preset-gfm-7.15.
|
| 1837 |
-
"integrity": "sha512-
|
| 1838 |
-
"license": "MIT",
|
| 1839 |
-
"dependencies": {
|
| 1840 |
-
"@milkdown/core": "7.15.
|
| 1841 |
-
"@milkdown/ctx": "7.15.
|
| 1842 |
-
"@milkdown/exception": "7.15.
|
| 1843 |
-
"@milkdown/preset-commonmark": "7.15.
|
| 1844 |
-
"@milkdown/prose": "7.15.
|
| 1845 |
-
"@milkdown/transformer": "7.15.
|
| 1846 |
-
"@milkdown/utils": "7.15.
|
| 1847 |
"prosemirror-safari-ime-span": "^1.0.1",
|
| 1848 |
"remark-gfm": "^4.0.1",
|
| 1849 |
"tslib": "^2.8.1"
|
| 1850 |
}
|
| 1851 |
},
|
| 1852 |
"node_modules/@milkdown/prose": {
|
| 1853 |
-
"version": "7.15.
|
| 1854 |
-
"resolved": "https://registry.npmjs.org/@milkdown/prose/-/prose-7.15.
|
| 1855 |
-
"integrity": "sha512-
|
| 1856 |
"license": "MIT",
|
| 1857 |
"dependencies": {
|
| 1858 |
-
"@milkdown/exception": "7.15.
|
| 1859 |
"prosemirror-changeset": "^2.2.1",
|
| 1860 |
"prosemirror-commands": "^1.6.2",
|
| 1861 |
"prosemirror-dropcursor": "^1.8.1",
|
|
@@ -1873,13 +1873,13 @@
|
|
| 1873 |
}
|
| 1874 |
},
|
| 1875 |
"node_modules/@milkdown/transformer": {
|
| 1876 |
-
"version": "7.15.
|
| 1877 |
-
"resolved": "https://registry.npmjs.org/@milkdown/transformer/-/transformer-7.15.
|
| 1878 |
-
"integrity": "sha512-
|
| 1879 |
"license": "MIT",
|
| 1880 |
"dependencies": {
|
| 1881 |
-
"@milkdown/exception": "7.15.
|
| 1882 |
-
"@milkdown/prose": "7.15.
|
| 1883 |
"remark": "^15.0.1",
|
| 1884 |
"remark-parse": "^11.0.0",
|
| 1885 |
"remark-stringify": "^11.0.0",
|
|
@@ -1888,16 +1888,16 @@
|
|
| 1888 |
}
|
| 1889 |
},
|
| 1890 |
"node_modules/@milkdown/utils": {
|
| 1891 |
-
"version": "7.15.
|
| 1892 |
-
"resolved": "https://registry.npmjs.org/@milkdown/utils/-/utils-7.15.
|
| 1893 |
-
"integrity": "sha512
|
| 1894 |
"license": "MIT",
|
| 1895 |
"dependencies": {
|
| 1896 |
-
"@milkdown/core": "7.15.
|
| 1897 |
-
"@milkdown/ctx": "7.15.
|
| 1898 |
-
"@milkdown/exception": "7.15.
|
| 1899 |
-
"@milkdown/prose": "7.15.
|
| 1900 |
-
"@milkdown/transformer": "7.15.
|
| 1901 |
"nanoid": "^5.0.9",
|
| 1902 |
"tslib": "^2.8.1"
|
| 1903 |
}
|
|
@@ -2030,9 +2030,9 @@
|
|
| 2030 |
"license": "MIT"
|
| 2031 |
},
|
| 2032 |
"node_modules/@types/node": {
|
| 2033 |
-
"version": "24.3.
|
| 2034 |
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.
|
| 2035 |
-
"integrity": "sha512-
|
| 2036 |
"license": "MIT",
|
| 2037 |
"dependencies": {
|
| 2038 |
"undici-types": "~7.10.0"
|
|
@@ -2471,12 +2471,12 @@
|
|
| 2471 |
}
|
| 2472 |
},
|
| 2473 |
"node_modules/escape-string-regexp": {
|
| 2474 |
-
"version": "
|
| 2475 |
-
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-
|
| 2476 |
-
"integrity": "sha512
|
| 2477 |
"license": "MIT",
|
| 2478 |
"engines": {
|
| 2479 |
-
"node": ">=
|
| 2480 |
},
|
| 2481 |
"funding": {
|
| 2482 |
"url": "https://github.com/sponsors/sindresorhus"
|
|
@@ -2564,9 +2564,9 @@
|
|
| 2564 |
}
|
| 2565 |
},
|
| 2566 |
"node_modules/is-arrayish": {
|
| 2567 |
-
"version": "0.3.
|
| 2568 |
-
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.
|
| 2569 |
-
"integrity": "sha512-
|
| 2570 |
"license": "MIT"
|
| 2571 |
},
|
| 2572 |
"node_modules/is-plain-obj": {
|
|
@@ -2639,12 +2639,12 @@
|
|
| 2639 |
}
|
| 2640 |
},
|
| 2641 |
"node_modules/magic-string": {
|
| 2642 |
-
"version": "0.30.
|
| 2643 |
-
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.
|
| 2644 |
-
"integrity": "sha512-
|
| 2645 |
"license": "MIT",
|
| 2646 |
"dependencies": {
|
| 2647 |
-
"@jridgewell/sourcemap-codec": "^1.5.
|
| 2648 |
}
|
| 2649 |
},
|
| 2650 |
"node_modules/markdown-table": {
|
|
@@ -2669,18 +2669,6 @@
|
|
| 2669 |
"node": ">=10"
|
| 2670 |
}
|
| 2671 |
},
|
| 2672 |
-
"node_modules/matcher/node_modules/escape-string-regexp": {
|
| 2673 |
-
"version": "4.0.0",
|
| 2674 |
-
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
| 2675 |
-
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
| 2676 |
-
"license": "MIT",
|
| 2677 |
-
"engines": {
|
| 2678 |
-
"node": ">=10"
|
| 2679 |
-
},
|
| 2680 |
-
"funding": {
|
| 2681 |
-
"url": "https://github.com/sponsors/sindresorhus"
|
| 2682 |
-
}
|
| 2683 |
-
},
|
| 2684 |
"node_modules/mdast-util-definitions": {
|
| 2685 |
"version": "6.0.0",
|
| 2686 |
"resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz",
|
|
@@ -2712,6 +2700,18 @@
|
|
| 2712 |
"url": "https://opencollective.com/unified"
|
| 2713 |
}
|
| 2714 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2715 |
"node_modules/mdast-util-from-markdown": {
|
| 2716 |
"version": "2.0.2",
|
| 2717 |
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz",
|
|
@@ -3782,9 +3782,9 @@
|
|
| 3782 |
}
|
| 3783 |
},
|
| 3784 |
"node_modules/prosemirror-tables": {
|
| 3785 |
-
"version": "1.
|
| 3786 |
-
"resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.
|
| 3787 |
-
"integrity": "sha512-
|
| 3788 |
"license": "MIT",
|
| 3789 |
"dependencies": {
|
| 3790 |
"prosemirror-keymap": "^1.2.2",
|
|
@@ -3804,9 +3804,9 @@
|
|
| 3804 |
}
|
| 3805 |
},
|
| 3806 |
"node_modules/prosemirror-view": {
|
| 3807 |
-
"version": "1.
|
| 3808 |
-
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.
|
| 3809 |
-
"integrity": "sha512-
|
| 3810 |
"license": "MIT",
|
| 3811 |
"dependencies": {
|
| 3812 |
"prosemirror-model": "^1.20.0",
|
|
@@ -4058,9 +4058,9 @@
|
|
| 4058 |
}
|
| 4059 |
},
|
| 4060 |
"node_modules/simple-swizzle": {
|
| 4061 |
-
"version": "0.2.
|
| 4062 |
-
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.
|
| 4063 |
-
"integrity": "sha512-
|
| 4064 |
"license": "MIT",
|
| 4065 |
"dependencies": {
|
| 4066 |
"is-arrayish": "^0.3.1"
|
|
|
|
| 1 |
{
|
| 2 |
"name": "localm",
|
| 3 |
+
"version": "1.2.12",
|
| 4 |
"lockfileVersion": 3,
|
| 5 |
"requires": true,
|
| 6 |
"packages": {
|
| 7 |
"": {
|
| 8 |
"name": "localm",
|
| 9 |
+
"version": "1.2.12",
|
| 10 |
"license": "ISC",
|
| 11 |
"dependencies": {
|
| 12 |
+
"@huggingface/transformers": "*",
|
| 13 |
+
"@milkdown/crepe": "*",
|
| 14 |
+
"@mlc-ai/web-llm": "*",
|
| 15 |
+
"esbuild": "*"
|
| 16 |
}
|
| 17 |
},
|
| 18 |
"node_modules/@babel/helper-string-parser": {
|
|
|
|
| 34 |
}
|
| 35 |
},
|
| 36 |
"node_modules/@babel/parser": {
|
| 37 |
+
"version": "7.28.4",
|
| 38 |
+
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
|
| 39 |
+
"integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
|
| 40 |
"license": "MIT",
|
| 41 |
"dependencies": {
|
| 42 |
+
"@babel/types": "^7.28.4"
|
| 43 |
},
|
| 44 |
"bin": {
|
| 45 |
"parser": "bin/babel-parser.js"
|
|
|
|
| 49 |
}
|
| 50 |
},
|
| 51 |
"node_modules/@babel/types": {
|
| 52 |
+
"version": "7.28.4",
|
| 53 |
+
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
|
| 54 |
+
"integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
|
| 55 |
"license": "MIT",
|
| 56 |
"dependencies": {
|
| 57 |
"@babel/helper-string-parser": "^7.27.1",
|
|
|
|
| 62 |
}
|
| 63 |
},
|
| 64 |
"node_modules/@codemirror/autocomplete": {
|
| 65 |
+
"version": "6.18.7",
|
| 66 |
+
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.7.tgz",
|
| 67 |
+
"integrity": "sha512-8EzdeIoWPJDsMBwz3zdzwXnUpCzMiCyz5/A3FIPpriaclFCGDkAzK13sMcnsu5rowqiyeQN2Vs2TsOcoDPZirQ==",
|
| 68 |
"license": "MIT",
|
| 69 |
"dependencies": {
|
| 70 |
"@codemirror/language": "^6.0.0",
|
|
|
|
| 136 |
}
|
| 137 |
},
|
| 138 |
"node_modules/@codemirror/lang-html": {
|
| 139 |
+
"version": "6.4.10",
|
| 140 |
+
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.10.tgz",
|
| 141 |
+
"integrity": "sha512-h/SceTVsN5r+WE+TVP2g3KDvNoSzbSrtZXCKo4vkKdbfT5t4otuVgngGdFukOO/rwRD2++pCxoh6xD4TEVMkQA==",
|
| 142 |
"license": "MIT",
|
| 143 |
"dependencies": {
|
| 144 |
"@codemirror/autocomplete": "^6.0.0",
|
|
|
|
| 446 |
}
|
| 447 |
},
|
| 448 |
"node_modules/@codemirror/view": {
|
| 449 |
+
"version": "6.38.2",
|
| 450 |
+
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.2.tgz",
|
| 451 |
+
"integrity": "sha512-bTWAJxL6EOFLPzTx+O5P5xAO3gTqpatQ2b/ARQ8itfU/v2LlpS3pH2fkL0A3E/Fx8Y2St2KES7ZEV0sHTsSW/A==",
|
| 452 |
"license": "MIT",
|
| 453 |
"dependencies": {
|
| 454 |
"@codemirror/state": "^6.5.0",
|
|
|
|
| 458 |
}
|
| 459 |
},
|
| 460 |
"node_modules/@emnapi/runtime": {
|
| 461 |
+
"version": "1.5.0",
|
| 462 |
+
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz",
|
| 463 |
+
"integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==",
|
| 464 |
"license": "MIT",
|
| 465 |
"optional": true,
|
| 466 |
"dependencies": {
|
|
|
|
| 893 |
}
|
| 894 |
},
|
| 895 |
"node_modules/@floating-ui/dom": {
|
| 896 |
+
"version": "1.7.4",
|
| 897 |
+
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz",
|
| 898 |
+
"integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
|
| 899 |
"license": "MIT",
|
| 900 |
"dependencies": {
|
| 901 |
"@floating-ui/core": "^1.7.3",
|
|
|
|
| 918 |
}
|
| 919 |
},
|
| 920 |
"node_modules/@huggingface/transformers": {
|
| 921 |
+
"version": "3.7.3",
|
| 922 |
+
"resolved": "https://registry.npmjs.org/@huggingface/transformers/-/transformers-3.7.3.tgz",
|
| 923 |
+
"integrity": "sha512-on3Y4Pn9oK/OqNKygojnAn6RePtOVlIZbMFwnP6Q8q9p6UiYPp5IDR08KWN0FSic5fBbrZvF+vVH67vNXBqZvA==",
|
| 924 |
"license": "Apache-2.0",
|
| 925 |
"dependencies": {
|
| 926 |
"@huggingface/jinja": "^0.5.1",
|
|
|
|
| 1436 |
}
|
| 1437 |
},
|
| 1438 |
"node_modules/@lezer/javascript": {
|
| 1439 |
+
"version": "1.5.3",
|
| 1440 |
+
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.3.tgz",
|
| 1441 |
+
"integrity": "sha512-jexmlKq5NpGiB7t+0QkyhSXRgaiab5YisHIQW9C7EcU19KSUsDguZe9WY+rmRDg34nXoNH2LQ4SxpC+aJUchSQ==",
|
| 1442 |
"license": "MIT",
|
| 1443 |
"dependencies": {
|
| 1444 |
"@lezer/common": "^1.2.0",
|
|
|
|
| 1549 |
"license": "MIT"
|
| 1550 |
},
|
| 1551 |
"node_modules/@milkdown/components": {
|
| 1552 |
+
"version": "7.15.5",
|
| 1553 |
+
"resolved": "https://registry.npmjs.org/@milkdown/components/-/components-7.15.5.tgz",
|
| 1554 |
+
"integrity": "sha512-amSlgjpp5gFKzcEUHMT6mrRGr89krlRMUo+L8MhmWBys1Wu+ZGAj5f2C2pTQncW9yVGAudquVqF+nV57aRTaoA==",
|
| 1555 |
"license": "MIT",
|
| 1556 |
"dependencies": {
|
| 1557 |
"@floating-ui/dom": "^1.5.1",
|
| 1558 |
+
"@milkdown/core": "7.15.5",
|
| 1559 |
+
"@milkdown/ctx": "7.15.5",
|
| 1560 |
+
"@milkdown/exception": "7.15.5",
|
| 1561 |
+
"@milkdown/plugin-tooltip": "7.15.5",
|
| 1562 |
+
"@milkdown/preset-commonmark": "7.15.5",
|
| 1563 |
+
"@milkdown/preset-gfm": "7.15.5",
|
| 1564 |
+
"@milkdown/prose": "7.15.5",
|
| 1565 |
+
"@milkdown/transformer": "7.15.5",
|
| 1566 |
+
"@milkdown/utils": "7.15.5",
|
| 1567 |
"@types/lodash-es": "^4.17.12",
|
| 1568 |
"clsx": "^2.0.0",
|
| 1569 |
"dompurify": "^3.2.5",
|
|
|
|
| 1571 |
"nanoid": "^5.0.9",
|
| 1572 |
"tslib": "^2.8.1",
|
| 1573 |
"unist-util-visit": "^5.0.0",
|
| 1574 |
+
"vue": "3.5.18"
|
| 1575 |
},
|
| 1576 |
"peerDependencies": {
|
| 1577 |
"@codemirror/language": "^6",
|
|
|
|
| 1580 |
}
|
| 1581 |
},
|
| 1582 |
"node_modules/@milkdown/core": {
|
| 1583 |
+
"version": "7.15.5",
|
| 1584 |
+
"resolved": "https://registry.npmjs.org/@milkdown/core/-/core-7.15.5.tgz",
|
| 1585 |
+
"integrity": "sha512-Pd5M/97pg2mvK+msGVG2oUFJycSDqk9RiH1D2MIaoeNDatdpDVjMv3kucBr8g6hMUsSYjlmhvMLPSZqm4EBB0A==",
|
| 1586 |
"license": "MIT",
|
| 1587 |
"dependencies": {
|
| 1588 |
+
"@milkdown/ctx": "7.15.5",
|
| 1589 |
+
"@milkdown/exception": "7.15.5",
|
| 1590 |
+
"@milkdown/prose": "7.15.5",
|
| 1591 |
+
"@milkdown/transformer": "7.15.5",
|
| 1592 |
"remark-parse": "^11.0.0",
|
| 1593 |
"remark-stringify": "^11.0.0",
|
| 1594 |
"tslib": "^2.8.1",
|
|
|
|
| 1596 |
}
|
| 1597 |
},
|
| 1598 |
"node_modules/@milkdown/crepe": {
|
| 1599 |
+
"version": "7.15.5",
|
| 1600 |
+
"resolved": "https://registry.npmjs.org/@milkdown/crepe/-/crepe-7.15.5.tgz",
|
| 1601 |
+
"integrity": "sha512-DTSC8Grgy4Sugze08HTsaEa1jSsU8azgzgH4f6OSg8VTVnx/mjFJz14b4Vtfc8LZbUZy0hdZM8n9Pp3Tu0nq4w==",
|
| 1602 |
"license": "MIT",
|
| 1603 |
"dependencies": {
|
| 1604 |
"@codemirror/commands": "^6.2.4",
|
|
|
|
| 1608 |
"@codemirror/theme-one-dark": "^6.1.2",
|
| 1609 |
"@codemirror/view": "^6.16.0",
|
| 1610 |
"@floating-ui/dom": "^1.5.1",
|
| 1611 |
+
"@milkdown/kit": "7.15.5",
|
| 1612 |
"@types/lodash-es": "^4.17.12",
|
| 1613 |
"clsx": "^2.0.0",
|
| 1614 |
"codemirror": "^6.0.1",
|
|
|
|
| 1619 |
"remark-math": "^6.0.0",
|
| 1620 |
"tslib": "^2.8.1",
|
| 1621 |
"unist-util-visit": "^5.0.0",
|
| 1622 |
+
"vue": "3.5.18"
|
| 1623 |
}
|
| 1624 |
},
|
| 1625 |
"node_modules/@milkdown/ctx": {
|
| 1626 |
+
"version": "7.15.5",
|
| 1627 |
+
"resolved": "https://registry.npmjs.org/@milkdown/ctx/-/ctx-7.15.5.tgz",
|
| 1628 |
+
"integrity": "sha512-XLNOLUYIwL/h5i8wkQbVBZELKUEa9ySLjn+5zAfomJXIWEdLs3LnXRweGF8kH0dEoKSEKcNHz+myGZO8SHPI6w==",
|
| 1629 |
"license": "MIT",
|
| 1630 |
"dependencies": {
|
| 1631 |
+
"@milkdown/exception": "7.15.5",
|
| 1632 |
"tslib": "^2.8.1"
|
| 1633 |
}
|
| 1634 |
},
|
| 1635 |
"node_modules/@milkdown/exception": {
|
| 1636 |
+
"version": "7.15.5",
|
| 1637 |
+
"resolved": "https://registry.npmjs.org/@milkdown/exception/-/exception-7.15.5.tgz",
|
| 1638 |
+
"integrity": "sha512-ZU1EpM3CaklfnHlMLqoR0mVdpL6lNPz3mlOTcgOlUZGB7EOvZQlFKvsdV53hisZSo6/RfgPHBukeJdO9Wq1Jjw==",
|
| 1639 |
"license": "MIT",
|
| 1640 |
"dependencies": {
|
| 1641 |
"tslib": "^2.8.1"
|
| 1642 |
}
|
| 1643 |
},
|
| 1644 |
"node_modules/@milkdown/kit": {
|
| 1645 |
+
"version": "7.15.5",
|
| 1646 |
+
"resolved": "https://registry.npmjs.org/@milkdown/kit/-/kit-7.15.5.tgz",
|
| 1647 |
+
"integrity": "sha512-JEfBJ5lVhVNTaHYgKVfg3ztgd7O0lvgi3Kxox71VEVXa7crV3+HBr5wKkJSQrfwBm5Gr0Vk2KWj+jdPrEVtF1A==",
|
| 1648 |
+
"license": "MIT",
|
| 1649 |
+
"dependencies": {
|
| 1650 |
+
"@milkdown/components": "7.15.5",
|
| 1651 |
+
"@milkdown/core": "7.15.5",
|
| 1652 |
+
"@milkdown/ctx": "7.15.5",
|
| 1653 |
+
"@milkdown/plugin-block": "7.15.5",
|
| 1654 |
+
"@milkdown/plugin-clipboard": "7.15.5",
|
| 1655 |
+
"@milkdown/plugin-cursor": "7.15.5",
|
| 1656 |
+
"@milkdown/plugin-history": "7.15.5",
|
| 1657 |
+
"@milkdown/plugin-indent": "7.15.5",
|
| 1658 |
+
"@milkdown/plugin-listener": "7.15.5",
|
| 1659 |
+
"@milkdown/plugin-slash": "7.15.5",
|
| 1660 |
+
"@milkdown/plugin-tooltip": "7.15.5",
|
| 1661 |
+
"@milkdown/plugin-trailing": "7.15.5",
|
| 1662 |
+
"@milkdown/plugin-upload": "7.15.5",
|
| 1663 |
+
"@milkdown/preset-commonmark": "7.15.5",
|
| 1664 |
+
"@milkdown/preset-gfm": "7.15.5",
|
| 1665 |
+
"@milkdown/prose": "7.15.5",
|
| 1666 |
+
"@milkdown/transformer": "7.15.5",
|
| 1667 |
+
"@milkdown/utils": "7.15.5",
|
| 1668 |
"tslib": "^2.8.1"
|
| 1669 |
}
|
| 1670 |
},
|
| 1671 |
"node_modules/@milkdown/plugin-block": {
|
| 1672 |
+
"version": "7.15.5",
|
| 1673 |
+
"resolved": "https://registry.npmjs.org/@milkdown/plugin-block/-/plugin-block-7.15.5.tgz",
|
| 1674 |
+
"integrity": "sha512-g1nCWhtvCsJhDDMTk06M/jUb1M6CitGeNYAWrCj5oXV8Er8+9F5s2U1/kyAbYzjp29nC09IKSNjCsrZrpvI1Qw==",
|
| 1675 |
"license": "MIT",
|
| 1676 |
"dependencies": {
|
| 1677 |
"@floating-ui/dom": "^1.5.1",
|
| 1678 |
+
"@milkdown/core": "7.15.5",
|
| 1679 |
+
"@milkdown/ctx": "7.15.5",
|
| 1680 |
+
"@milkdown/exception": "7.15.5",
|
| 1681 |
+
"@milkdown/prose": "7.15.5",
|
| 1682 |
+
"@milkdown/utils": "7.15.5",
|
| 1683 |
"@types/lodash-es": "^4.17.12",
|
| 1684 |
"lodash-es": "^4.17.21",
|
| 1685 |
"tslib": "^2.8.1"
|
| 1686 |
}
|
| 1687 |
},
|
| 1688 |
"node_modules/@milkdown/plugin-clipboard": {
|
| 1689 |
+
"version": "7.15.5",
|
| 1690 |
+
"resolved": "https://registry.npmjs.org/@milkdown/plugin-clipboard/-/plugin-clipboard-7.15.5.tgz",
|
| 1691 |
+
"integrity": "sha512-QU83bqyeThpEayDN3vKV+/7j9GtNdlSQLboElNG8ZIVp+4nFOetlNQOwJQQxv6h7j+69dnxAM7ePZ7DqnkCiDw==",
|
| 1692 |
"license": "MIT",
|
| 1693 |
"dependencies": {
|
| 1694 |
+
"@milkdown/core": "7.15.5",
|
| 1695 |
+
"@milkdown/ctx": "7.15.5",
|
| 1696 |
+
"@milkdown/prose": "7.15.5",
|
| 1697 |
+
"@milkdown/utils": "7.15.5",
|
| 1698 |
"tslib": "^2.8.1"
|
| 1699 |
}
|
| 1700 |
},
|
| 1701 |
"node_modules/@milkdown/plugin-cursor": {
|
| 1702 |
+
"version": "7.15.5",
|
| 1703 |
+
"resolved": "https://registry.npmjs.org/@milkdown/plugin-cursor/-/plugin-cursor-7.15.5.tgz",
|
| 1704 |
+
"integrity": "sha512-vtUUr+9ckv7TrSHE7P0sfna7pe0UnFIGmoj1yLh6l6WXGU48h9EBTJQfmXn+oZNgjhrW5Q4gEIvQqBftbbYtMQ==",
|
| 1705 |
"license": "MIT",
|
| 1706 |
"dependencies": {
|
| 1707 |
+
"@milkdown/core": "7.15.5",
|
| 1708 |
+
"@milkdown/ctx": "7.15.5",
|
| 1709 |
+
"@milkdown/prose": "7.15.5",
|
| 1710 |
+
"@milkdown/utils": "7.15.5",
|
| 1711 |
"tslib": "^2.8.1"
|
| 1712 |
}
|
| 1713 |
},
|
| 1714 |
"node_modules/@milkdown/plugin-history": {
|
| 1715 |
+
"version": "7.15.5",
|
| 1716 |
+
"resolved": "https://registry.npmjs.org/@milkdown/plugin-history/-/plugin-history-7.15.5.tgz",
|
| 1717 |
+
"integrity": "sha512-KigeDAUv1/VR8oRv3lIKBZIxF5s9mMCydf6BoWoc1SMFShm5ei/wEVEvex0+wlhn/BC/4xwh3K2fmNQyx6jNBw==",
|
| 1718 |
"license": "MIT",
|
| 1719 |
"dependencies": {
|
| 1720 |
+
"@milkdown/core": "7.15.5",
|
| 1721 |
+
"@milkdown/ctx": "7.15.5",
|
| 1722 |
+
"@milkdown/prose": "7.15.5",
|
| 1723 |
+
"@milkdown/utils": "7.15.5",
|
| 1724 |
"tslib": "^2.8.1"
|
| 1725 |
}
|
| 1726 |
},
|
| 1727 |
"node_modules/@milkdown/plugin-indent": {
|
| 1728 |
+
"version": "7.15.5",
|
| 1729 |
+
"resolved": "https://registry.npmjs.org/@milkdown/plugin-indent/-/plugin-indent-7.15.5.tgz",
|
| 1730 |
+
"integrity": "sha512-ikkcsY33YQ/AsYVVktmujssa7G2m7AeTUydBiCoreIWdGtyqv/ofoIpJSwxowILQ2Y/6ITo7T+YRuFFyBGPcgw==",
|
| 1731 |
"license": "MIT",
|
| 1732 |
"dependencies": {
|
| 1733 |
+
"@milkdown/core": "7.15.5",
|
| 1734 |
+
"@milkdown/ctx": "7.15.5",
|
| 1735 |
+
"@milkdown/prose": "7.15.5",
|
| 1736 |
+
"@milkdown/utils": "7.15.5",
|
| 1737 |
"tslib": "^2.8.1"
|
| 1738 |
}
|
| 1739 |
},
|
| 1740 |
"node_modules/@milkdown/plugin-listener": {
|
| 1741 |
+
"version": "7.15.5",
|
| 1742 |
+
"resolved": "https://registry.npmjs.org/@milkdown/plugin-listener/-/plugin-listener-7.15.5.tgz",
|
| 1743 |
+
"integrity": "sha512-ZGohvWL9zCKKnlgJEeiM6vBVlVvns4tEoCvM9R4IhAgD3ku/c24hK1ZRUMjtPz5yIiBW6EX6fhV+fdwjLvmIwg==",
|
| 1744 |
"license": "MIT",
|
| 1745 |
"dependencies": {
|
| 1746 |
+
"@milkdown/core": "7.15.5",
|
| 1747 |
+
"@milkdown/ctx": "7.15.5",
|
| 1748 |
+
"@milkdown/prose": "7.15.5",
|
| 1749 |
+
"@milkdown/utils": "7.15.5",
|
| 1750 |
"@types/lodash-es": "^4.17.12",
|
| 1751 |
"lodash-es": "^4.17.21",
|
| 1752 |
"tslib": "^2.8.1"
|
| 1753 |
}
|
| 1754 |
},
|
| 1755 |
"node_modules/@milkdown/plugin-slash": {
|
| 1756 |
+
"version": "7.15.5",
|
| 1757 |
+
"resolved": "https://registry.npmjs.org/@milkdown/plugin-slash/-/plugin-slash-7.15.5.tgz",
|
| 1758 |
+
"integrity": "sha512-iSgLz2kGVdkm5LvBjgPSPxm4xik2h5x7UlLheMbeOdK2eB5clBxJfRdrn05Xx2ZJKKworNFXcqB6as873BMxOA==",
|
| 1759 |
"license": "MIT",
|
| 1760 |
"dependencies": {
|
| 1761 |
"@floating-ui/dom": "^1.5.1",
|
| 1762 |
+
"@milkdown/core": "7.15.5",
|
| 1763 |
+
"@milkdown/ctx": "7.15.5",
|
| 1764 |
+
"@milkdown/exception": "7.15.5",
|
| 1765 |
+
"@milkdown/prose": "7.15.5",
|
| 1766 |
+
"@milkdown/utils": "7.15.5",
|
| 1767 |
"@types/lodash-es": "^4.17.12",
|
| 1768 |
"lodash-es": "^4.17.21",
|
| 1769 |
"tslib": "^2.8.1"
|
| 1770 |
}
|
| 1771 |
},
|
| 1772 |
"node_modules/@milkdown/plugin-tooltip": {
|
| 1773 |
+
"version": "7.15.5",
|
| 1774 |
+
"resolved": "https://registry.npmjs.org/@milkdown/plugin-tooltip/-/plugin-tooltip-7.15.5.tgz",
|
| 1775 |
+
"integrity": "sha512-TTnub8P1mc2r0dbd1X3IsLRn5lME8hazUeAaAIUlh7iId2hbR/XtzFwYZI1q3XzWG/9YQbjI1g4wxFvqZHEcqw==",
|
| 1776 |
"license": "MIT",
|
| 1777 |
"dependencies": {
|
| 1778 |
"@floating-ui/dom": "^1.5.1",
|
| 1779 |
+
"@milkdown/core": "7.15.5",
|
| 1780 |
+
"@milkdown/ctx": "7.15.5",
|
| 1781 |
+
"@milkdown/exception": "7.15.5",
|
| 1782 |
+
"@milkdown/prose": "7.15.5",
|
| 1783 |
+
"@milkdown/utils": "7.15.5",
|
| 1784 |
"@types/lodash-es": "^4.17.12",
|
| 1785 |
"lodash-es": "^4.17.21",
|
| 1786 |
"tslib": "^2.8.1"
|
| 1787 |
}
|
| 1788 |
},
|
| 1789 |
"node_modules/@milkdown/plugin-trailing": {
|
| 1790 |
+
"version": "7.15.5",
|
| 1791 |
+
"resolved": "https://registry.npmjs.org/@milkdown/plugin-trailing/-/plugin-trailing-7.15.5.tgz",
|
| 1792 |
+
"integrity": "sha512-iysHkwvOPweRut48hw6c3o1ScCTtI+Dn7lrL087peYD14afG/PfGg1mw48xwePWu5iPkTbtDpbt9OoSs7t+XRA==",
|
| 1793 |
"license": "MIT",
|
| 1794 |
"dependencies": {
|
| 1795 |
+
"@milkdown/core": "7.15.5",
|
| 1796 |
+
"@milkdown/ctx": "7.15.5",
|
| 1797 |
+
"@milkdown/prose": "7.15.5",
|
| 1798 |
+
"@milkdown/utils": "7.15.5",
|
| 1799 |
"tslib": "^2.8.1"
|
| 1800 |
}
|
| 1801 |
},
|
| 1802 |
"node_modules/@milkdown/plugin-upload": {
|
| 1803 |
+
"version": "7.15.5",
|
| 1804 |
+
"resolved": "https://registry.npmjs.org/@milkdown/plugin-upload/-/plugin-upload-7.15.5.tgz",
|
| 1805 |
+
"integrity": "sha512-rGgLGzEhpcxEYEVgNz0uwLEOqdotWroxkm/Ci96IrXp/uYVjjHFM2VuaoFTmhqs4gsVp5h2TT87n4QHMvnQKSQ==",
|
| 1806 |
"license": "MIT",
|
| 1807 |
"dependencies": {
|
| 1808 |
+
"@milkdown/core": "7.15.5",
|
| 1809 |
+
"@milkdown/ctx": "7.15.5",
|
| 1810 |
+
"@milkdown/exception": "7.15.5",
|
| 1811 |
+
"@milkdown/prose": "7.15.5",
|
| 1812 |
+
"@milkdown/utils": "7.15.5",
|
| 1813 |
"tslib": "^2.8.1"
|
| 1814 |
}
|
| 1815 |
},
|
| 1816 |
"node_modules/@milkdown/preset-commonmark": {
|
| 1817 |
+
"version": "7.15.5",
|
| 1818 |
+
"resolved": "https://registry.npmjs.org/@milkdown/preset-commonmark/-/preset-commonmark-7.15.5.tgz",
|
| 1819 |
+
"integrity": "sha512-fE5zWdBE9QpRphR+OmdmIG28SyaGb7wQ4kz4UG696Yz9P3uxjFRYf0IKJJq8nydbhlKAEXPnmzzCKQqWa6gUIQ==",
|
| 1820 |
"license": "MIT",
|
| 1821 |
"dependencies": {
|
| 1822 |
+
"@milkdown/core": "7.15.5",
|
| 1823 |
+
"@milkdown/ctx": "7.15.5",
|
| 1824 |
+
"@milkdown/exception": "7.15.5",
|
| 1825 |
+
"@milkdown/prose": "7.15.5",
|
| 1826 |
+
"@milkdown/transformer": "7.15.5",
|
| 1827 |
+
"@milkdown/utils": "7.15.5",
|
| 1828 |
"remark-inline-links": "^7.0.0",
|
| 1829 |
"tslib": "^2.8.1",
|
| 1830 |
"unist-util-visit": "^5.0.0",
|
|
|
|
| 1832 |
}
|
| 1833 |
},
|
| 1834 |
"node_modules/@milkdown/preset-gfm": {
|
| 1835 |
+
"version": "7.15.5",
|
| 1836 |
+
"resolved": "https://registry.npmjs.org/@milkdown/preset-gfm/-/preset-gfm-7.15.5.tgz",
|
| 1837 |
+
"integrity": "sha512-6uZJT11C/mN7FEu1g7U8Q6E8gWmQlBj3c0XkkLpSMxQEVGGLeJr6gMC1tWLbN933mlUMU+VvyaZ4TuEfyTMz4g==",
|
| 1838 |
+
"license": "MIT",
|
| 1839 |
+
"dependencies": {
|
| 1840 |
+
"@milkdown/core": "7.15.5",
|
| 1841 |
+
"@milkdown/ctx": "7.15.5",
|
| 1842 |
+
"@milkdown/exception": "7.15.5",
|
| 1843 |
+
"@milkdown/preset-commonmark": "7.15.5",
|
| 1844 |
+
"@milkdown/prose": "7.15.5",
|
| 1845 |
+
"@milkdown/transformer": "7.15.5",
|
| 1846 |
+
"@milkdown/utils": "7.15.5",
|
| 1847 |
"prosemirror-safari-ime-span": "^1.0.1",
|
| 1848 |
"remark-gfm": "^4.0.1",
|
| 1849 |
"tslib": "^2.8.1"
|
| 1850 |
}
|
| 1851 |
},
|
| 1852 |
"node_modules/@milkdown/prose": {
|
| 1853 |
+
"version": "7.15.5",
|
| 1854 |
+
"resolved": "https://registry.npmjs.org/@milkdown/prose/-/prose-7.15.5.tgz",
|
| 1855 |
+
"integrity": "sha512-1R6EIAp1ACKr1QtE+d1smZ5gIsPi6IgW0K7cngyC3JDxnNafbeVVQNpGQTkfzr0QJCHUVvPilaQ6A26inDHBhg==",
|
| 1856 |
"license": "MIT",
|
| 1857 |
"dependencies": {
|
| 1858 |
+
"@milkdown/exception": "7.15.5",
|
| 1859 |
"prosemirror-changeset": "^2.2.1",
|
| 1860 |
"prosemirror-commands": "^1.6.2",
|
| 1861 |
"prosemirror-dropcursor": "^1.8.1",
|
|
|
|
| 1873 |
}
|
| 1874 |
},
|
| 1875 |
"node_modules/@milkdown/transformer": {
|
| 1876 |
+
"version": "7.15.5",
|
| 1877 |
+
"resolved": "https://registry.npmjs.org/@milkdown/transformer/-/transformer-7.15.5.tgz",
|
| 1878 |
+
"integrity": "sha512-mO2kNqBwyI9Z6PTRwSiXev1zL0XkNy7kDcHBak+RFlnLxhWAgNRQHU9DREGFGT9mLm7jmH41e1esDrR+ttrALg==",
|
| 1879 |
"license": "MIT",
|
| 1880 |
"dependencies": {
|
| 1881 |
+
"@milkdown/exception": "7.15.5",
|
| 1882 |
+
"@milkdown/prose": "7.15.5",
|
| 1883 |
"remark": "^15.0.1",
|
| 1884 |
"remark-parse": "^11.0.0",
|
| 1885 |
"remark-stringify": "^11.0.0",
|
|
|
|
| 1888 |
}
|
| 1889 |
},
|
| 1890 |
"node_modules/@milkdown/utils": {
|
| 1891 |
+
"version": "7.15.5",
|
| 1892 |
+
"resolved": "https://registry.npmjs.org/@milkdown/utils/-/utils-7.15.5.tgz",
|
| 1893 |
+
"integrity": "sha512-/B5DBD9H8lPkY7jCiUEEJJUaTSrLKzLsjK5so+JxgmPJZ1E4gJjOUGnQtgzMhYZxd1Az7+vFc3XKgLY/WAzqKg==",
|
| 1894 |
"license": "MIT",
|
| 1895 |
"dependencies": {
|
| 1896 |
+
"@milkdown/core": "7.15.5",
|
| 1897 |
+
"@milkdown/ctx": "7.15.5",
|
| 1898 |
+
"@milkdown/exception": "7.15.5",
|
| 1899 |
+
"@milkdown/prose": "7.15.5",
|
| 1900 |
+
"@milkdown/transformer": "7.15.5",
|
| 1901 |
"nanoid": "^5.0.9",
|
| 1902 |
"tslib": "^2.8.1"
|
| 1903 |
}
|
|
|
|
| 2030 |
"license": "MIT"
|
| 2031 |
},
|
| 2032 |
"node_modules/@types/node": {
|
| 2033 |
+
"version": "24.3.3",
|
| 2034 |
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.3.tgz",
|
| 2035 |
+
"integrity": "sha512-GKBNHjoNw3Kra1Qg5UXttsY5kiWMEfoHq2TmXb+b1rcm6N7B3wTrFYIf/oSZ1xNQ+hVVijgLkiDZh7jRRsh+Gw==",
|
| 2036 |
"license": "MIT",
|
| 2037 |
"dependencies": {
|
| 2038 |
"undici-types": "~7.10.0"
|
|
|
|
| 2471 |
}
|
| 2472 |
},
|
| 2473 |
"node_modules/escape-string-regexp": {
|
| 2474 |
+
"version": "4.0.0",
|
| 2475 |
+
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
| 2476 |
+
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
| 2477 |
"license": "MIT",
|
| 2478 |
"engines": {
|
| 2479 |
+
"node": ">=10"
|
| 2480 |
},
|
| 2481 |
"funding": {
|
| 2482 |
"url": "https://github.com/sponsors/sindresorhus"
|
|
|
|
| 2564 |
}
|
| 2565 |
},
|
| 2566 |
"node_modules/is-arrayish": {
|
| 2567 |
+
"version": "0.3.4",
|
| 2568 |
+
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
|
| 2569 |
+
"integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
|
| 2570 |
"license": "MIT"
|
| 2571 |
},
|
| 2572 |
"node_modules/is-plain-obj": {
|
|
|
|
| 2639 |
}
|
| 2640 |
},
|
| 2641 |
"node_modules/magic-string": {
|
| 2642 |
+
"version": "0.30.19",
|
| 2643 |
+
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
|
| 2644 |
+
"integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
|
| 2645 |
"license": "MIT",
|
| 2646 |
"dependencies": {
|
| 2647 |
+
"@jridgewell/sourcemap-codec": "^1.5.5"
|
| 2648 |
}
|
| 2649 |
},
|
| 2650 |
"node_modules/markdown-table": {
|
|
|
|
| 2669 |
"node": ">=10"
|
| 2670 |
}
|
| 2671 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2672 |
"node_modules/mdast-util-definitions": {
|
| 2673 |
"version": "6.0.0",
|
| 2674 |
"resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz",
|
|
|
|
| 2700 |
"url": "https://opencollective.com/unified"
|
| 2701 |
}
|
| 2702 |
},
|
| 2703 |
+
"node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": {
|
| 2704 |
+
"version": "5.0.0",
|
| 2705 |
+
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
|
| 2706 |
+
"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
|
| 2707 |
+
"license": "MIT",
|
| 2708 |
+
"engines": {
|
| 2709 |
+
"node": ">=12"
|
| 2710 |
+
},
|
| 2711 |
+
"funding": {
|
| 2712 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 2713 |
+
}
|
| 2714 |
+
},
|
| 2715 |
"node_modules/mdast-util-from-markdown": {
|
| 2716 |
"version": "2.0.2",
|
| 2717 |
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz",
|
|
|
|
| 3782 |
}
|
| 3783 |
},
|
| 3784 |
"node_modules/prosemirror-tables": {
|
| 3785 |
+
"version": "1.8.1",
|
| 3786 |
+
"resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.1.tgz",
|
| 3787 |
+
"integrity": "sha512-DAgDoUYHCcc6tOGpLVPSU1k84kCUWTWnfWX3UDy2Delv4ryH0KqTD6RBI6k4yi9j9I8gl3j8MkPpRD/vWPZbug==",
|
| 3788 |
"license": "MIT",
|
| 3789 |
"dependencies": {
|
| 3790 |
"prosemirror-keymap": "^1.2.2",
|
|
|
|
| 3804 |
}
|
| 3805 |
},
|
| 3806 |
"node_modules/prosemirror-view": {
|
| 3807 |
+
"version": "1.41.0",
|
| 3808 |
+
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.0.tgz",
|
| 3809 |
+
"integrity": "sha512-FatMIIl0vRHMcNc3sPy3cMw5MMyWuO1nWQxqvYpJvXAruucGvmQ2tyyjT2/Lbok77T9a/qZqBVCq4sj43V2ihw==",
|
| 3810 |
"license": "MIT",
|
| 3811 |
"dependencies": {
|
| 3812 |
"prosemirror-model": "^1.20.0",
|
|
|
|
| 4058 |
}
|
| 4059 |
},
|
| 4060 |
"node_modules/simple-swizzle": {
|
| 4061 |
+
"version": "0.2.4",
|
| 4062 |
+
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
|
| 4063 |
+
"integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
|
| 4064 |
"license": "MIT",
|
| 4065 |
"dependencies": {
|
| 4066 |
"is-arrayish": "^0.3.1"
|
package.json
CHANGED
|
@@ -20,9 +20,9 @@
|
|
| 20 |
},
|
| 21 |
"homepage": "https://github.com/oyin-bo/localm#readme",
|
| 22 |
"dependencies": {
|
| 23 |
-
"@huggingface/transformers": "
|
| 24 |
-
"@milkdown/crepe": "
|
| 25 |
-
"@mlc-ai/web-llm": "
|
| 26 |
-
"esbuild": "
|
| 27 |
}
|
| 28 |
}
|
|
|
|
| 20 |
},
|
| 21 |
"homepage": "https://github.com/oyin-bo/localm#readme",
|
| 22 |
"dependencies": {
|
| 23 |
+
"@huggingface/transformers": "*",
|
| 24 |
+
"@milkdown/crepe": "*",
|
| 25 |
+
"@mlc-ai/web-llm": "*",
|
| 26 |
+
"esbuild": "*"
|
| 27 |
}
|
| 28 |
}
|
src/worker/curated-model-list.json
CHANGED
|
@@ -13,17 +13,19 @@
|
|
| 13 |
"isTransformersJsReady": true
|
| 14 |
},
|
| 15 |
{
|
| 16 |
-
"id": "
|
| 17 |
-
"name": "Gemma
|
| 18 |
"model_type": "gemma",
|
| 19 |
"architectures": ["gemma"],
|
| 20 |
"classification": "gen",
|
| 21 |
-
"confidence": "
|
| 22 |
-
"size_hint": "
|
| 23 |
-
"fetchStatus": "
|
| 24 |
"hasTokenizer": true,
|
| 25 |
-
"hasOnnxModel":
|
| 26 |
-
"isTransformersJsReady":
|
|
|
|
|
|
|
| 27 |
},
|
| 28 |
{
|
| 29 |
"id": "Xenova/llama2.c-stories15M",
|
|
|
|
| 13 |
"isTransformersJsReady": true
|
| 14 |
},
|
| 15 |
{
|
| 16 |
+
"id": "/models/google/gemma-2b/resolve/main",
|
| 17 |
+
"name": "Gemma 2B (local /models/google/gemma-2b/resolve/main)",
|
| 18 |
"model_type": "gemma",
|
| 19 |
"architectures": ["gemma"],
|
| 20 |
"classification": "gen",
|
| 21 |
+
"confidence": "medium",
|
| 22 |
+
"size_hint": "~2GB",
|
| 23 |
+
"fetchStatus": "pending-local",
|
| 24 |
"hasTokenizer": true,
|
| 25 |
+
"hasOnnxModel": false,
|
| 26 |
+
"isTransformersJsReady": false,
|
| 27 |
+
"requiresAuth": false,
|
| 28 |
+
"info": { "local_url": "/models/google/gemma-2b/resolve/main", "notes": "Place downloaded HF-style repo under ./models/google/gemma-2b so files resolve at /models/google/gemma-2b/resolve/main/..." }
|
| 29 |
},
|
| 30 |
{
|
| 31 |
"id": "Xenova/llama2.c-stories15M",
|
src/worker/load-model-core.js
CHANGED
|
@@ -14,18 +14,144 @@ export async function loadModelCore({
|
|
| 14 |
device,
|
| 15 |
onProgress
|
| 16 |
}) {
|
| 17 |
-
//
|
| 18 |
-
//
|
| 19 |
-
//
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
}
|
| 28 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
}
|
|
|
|
| 14 |
device,
|
| 15 |
onProgress
|
| 16 |
}) {
|
| 17 |
+
// Heuristic: when modelName points at a local-served path (starts with '/' or 'http'),
|
| 18 |
+
// probe a few candidate base URLs to find where config/tokenizer actually live.
|
| 19 |
+
// This helps when assets are under `/resolve/main/` or at the repo root.
|
| 20 |
+
async function exists(url) {
|
| 21 |
+
try {
|
| 22 |
+
const r = await fetch(url, { method: 'HEAD' });
|
| 23 |
+
return r.ok;
|
| 24 |
+
} catch (e) {
|
| 25 |
+
return false;
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
let chosenModelName = modelName;
|
| 30 |
+
try {
|
| 31 |
+
// Treat both '/models/owner/model' and 'models/owner/model' as local-hosted
|
| 32 |
+
// mirrors so we probe and later install a fetch-rewrite. Also accept http(s) URLs.
|
| 33 |
+
const isLocalLike = (/^\/?models\//).test(modelName) || /^https?:\/\//.test(modelName);
|
| 34 |
+
if (isLocalLike) {
|
| 35 |
+
const candidates = [];
|
| 36 |
+
// as-provided
|
| 37 |
+
candidates.push(modelName.replace(/\/$/, ''));
|
| 38 |
+
// if modelName doesn't end with resolve/main, try adding it
|
| 39 |
+
if (!/\/resolve\/main\/?$/.test(modelName)) {
|
| 40 |
+
candidates.push(modelName.replace(/\/$/, '') + '/resolve/main');
|
| 41 |
+
}
|
| 42 |
+
// try parent directory (strip /resolve/main)
|
| 43 |
+
candidates.push(modelName.replace(/\/resolve\/main\/?$/, '').replace(/\/$/, ''));
|
| 44 |
+
|
| 45 |
+
// Deduplicate while preserving order
|
| 46 |
+
const seen = new Set();
|
| 47 |
+
const uniq = candidates.filter(c => { if (seen.has(c)) return false; seen.add(c); return true; });
|
| 48 |
+
|
| 49 |
+
for (const base of uniq) {
|
| 50 |
+
const cfg = (base.endsWith('/')) ? base + 'config.json' : base + '/config.json';
|
| 51 |
+
const tokJson = (base.endsWith('/')) ? base + 'tokenizer.json' : base + '/tokenizer.json';
|
| 52 |
+
const tokModel = (base.endsWith('/')) ? base + 'tokenizer.model' : base + '/tokenizer.model';
|
| 53 |
+
const tokCfg = (base.endsWith('/')) ? base + 'tokenizer_config.json' : base + '/tokenizer_config.json';
|
| 54 |
+
// Probe both config and tokenizer (tokenizer may be large but HEAD is cheap)
|
| 55 |
+
const hasCfg = await exists(cfg);
|
| 56 |
+
// Accept either Hugging Face tokenizer.json or SentencePiece tokenizer.model + tokenizer_config.json
|
| 57 |
+
const hasTokJson = await exists(tokJson);
|
| 58 |
+
const hasTokModel = await exists(tokModel);
|
| 59 |
+
const hasTokCfg = await exists(tokCfg);
|
| 60 |
+
const hasTok = hasTokJson || (hasTokModel && hasTokCfg);
|
| 61 |
+
console.log('Probing model base', base, 'config:', hasCfg, 'tokenizer.json:', hasTokJson, 'tokenizer.model+config:', hasTokModel && hasTokCfg);
|
| 62 |
+
if (hasCfg && hasTok) {
|
| 63 |
+
chosenModelName = base.replace(/\/$/, '');
|
| 64 |
+
break;
|
| 65 |
+
}
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
} catch (e) {
|
| 69 |
+
console.log('Local model probing failed: ', String(e));
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
// transformers.js expects a Hugging Face-style model id like 'owner/model'.
|
| 73 |
+
// If the user provided a local path (e.g. '/models/owner/model/resolve/main'),
|
| 74 |
+
// derive owner/model and pass that to pipeline, but install a fetch wrapper
|
| 75 |
+
// that rewrites requests to huggingface.co/<owner>/<model>/resolve/main/... -> local dev server files.
|
| 76 |
+
let pipelineModelId = chosenModelName;
|
| 77 |
+
let rewriteOwner = null;
|
| 78 |
+
let rewriteModel = null;
|
| 79 |
+
try {
|
| 80 |
+
// Accept both '/models/owner/model' and 'models/owner/model' forms.
|
| 81 |
+
if (typeof chosenModelName === 'string' && (/^\/?models\//).test(chosenModelName)) {
|
| 82 |
+
// Expected form: [/]<models>/<owner>/<model>[/resolve/main]
|
| 83 |
+
const m = chosenModelName.match(/^\/?models\/([^\/]+)\/([^\/]+)(?:\/resolve\/main)?\/?$/);
|
| 84 |
+
if (m) {
|
| 85 |
+
rewriteOwner = m[1];
|
| 86 |
+
rewriteModel = m[2];
|
| 87 |
+
pipelineModelId = `${rewriteOwner}/${rewriteModel}`;
|
| 88 |
}
|
| 89 |
+
}
|
| 90 |
+
} catch (e) {
|
| 91 |
+
console.log('Failed to derive owner/model from local path:', String(e));
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
console.log('Creating pipeline for', pipelineModelId, 'device', device);
|
| 95 |
+
// Temporary fetch wrapper: if transformers.js tries to download files from
|
| 96 |
+
// https://huggingface.co/<owner>/<model>/resolve/main/<file>
|
| 97 |
+
// rewrite those requests to the local dev server path we probed earlier.
|
| 98 |
+
const origFetch = (typeof globalThis !== 'undefined' && globalThis.fetch) ? globalThis.fetch : null;
|
| 99 |
+
let wrapped = false;
|
| 100 |
+
if (origFetch && rewriteOwner && rewriteModel) {
|
| 101 |
+
try {
|
| 102 |
+
const localBase = pipelineModelId && typeof chosenModelName === 'string' ?
|
| 103 |
+
(chosenModelName.replace(/\/$/, '') + '/') : null;
|
| 104 |
+
globalThis.fetch = async function(input, init) {
|
| 105 |
+
try {
|
| 106 |
+
let urlStr = '';
|
| 107 |
+
if (typeof input === 'string') urlStr = input;
|
| 108 |
+
else if (input instanceof Request) urlStr = input.url;
|
| 109 |
+
else {
|
| 110 |
+
// cast to any to avoid TS complaining about unknown input shapes
|
| 111 |
+
try {
|
| 112 |
+
const anyInput = /** @type {any} */ (input);
|
| 113 |
+
if (anyInput && anyInput.url) urlStr = String(anyInput.url);
|
| 114 |
+
} catch (e) {}
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
// Match HF model asset URLs like https://huggingface.co/<owner>/<model>/resolve/main/<file>
|
| 118 |
+
const hfMatch = urlStr.match(new RegExp('^https?:\\/\\/huggingface\\.co\\/' + rewriteOwner + '\\/' + rewriteModel + '\\/(?:resolve\\/main\\/)?(.*)$'));
|
| 119 |
+
if (hfMatch && localBase) {
|
| 120 |
+
const filePath = hfMatch[1];
|
| 121 |
+
const localUrl = localBase + filePath;
|
| 122 |
+
return origFetch.call(this, localUrl, init);
|
| 123 |
+
}
|
| 124 |
+
} catch (e) {
|
| 125 |
+
// fall through to default
|
| 126 |
+
}
|
| 127 |
+
return origFetch.call(this, input, init);
|
| 128 |
+
};
|
| 129 |
+
wrapped = true;
|
| 130 |
+
} catch (e) {
|
| 131 |
+
console.log('Could not install fetch wrapper:', String(e));
|
| 132 |
+
}
|
| 133 |
+
}
|
| 134 |
|
| 135 |
+
try {
|
| 136 |
+
const pipe = await pipeline(
|
| 137 |
+
'text-generation',
|
| 138 |
+
pipelineModelId,
|
| 139 |
+
{
|
| 140 |
+
device,
|
| 141 |
+
progress_callback: (progress) => {
|
| 142 |
+
if (onProgress) onProgress(progress);
|
| 143 |
+
}
|
| 144 |
+
});
|
| 145 |
+
|
| 146 |
+
return pipe;
|
| 147 |
+
} finally {
|
| 148 |
+
// restore original fetch
|
| 149 |
+
try {
|
| 150 |
+
if (wrapped && origFetch) {
|
| 151 |
+
globalThis.fetch = origFetch;
|
| 152 |
+
}
|
| 153 |
+
} catch (e) {
|
| 154 |
+
// ignore
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
}
|
src/worker/model-cache.js
CHANGED
|
@@ -84,10 +84,235 @@ export class ModelCache {
|
|
| 84 |
// Try WebLLM first if probe suggests it's possible
|
| 85 |
if (probe.possible) {
|
| 86 |
try {
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
});
|
| 92 |
|
| 93 |
// Quick end-to-end validation: run a very small prompt to ensure the
|
|
|
|
| 84 |
// Try WebLLM first if probe suggests it's possible
|
| 85 |
if (probe.possible) {
|
| 86 |
try {
|
| 87 |
+
// Derive a sensible WebLLM model id (prefer owner/model when supplied)
|
| 88 |
+
let webLLMId = modelName;
|
| 89 |
+
try {
|
| 90 |
+
// Accept both '/models/owner/model' and 'models/owner/model' forms.
|
| 91 |
+
if (typeof modelName === 'string' && (/^\/?models\//).test(modelName)) {
|
| 92 |
+
const m = modelName.match(/^\/?models\/([^\/]+)\/([^\/]+)(?:\/resolve\/main)?\/?$/);
|
| 93 |
+
if (m) webLLMId = `${m[1]}/${m[2]}`;
|
| 94 |
+
else webLLMId = String(modelName).replace(/^\//, '');
|
| 95 |
+
} else if (typeof modelName === 'string' && modelName.includes('/')) {
|
| 96 |
+
// use as-is owner/model
|
| 97 |
+
webLLMId = modelName;
|
| 98 |
+
} else {
|
| 99 |
+
webLLMId = String(modelName).split('/').pop() || String(modelName);
|
| 100 |
+
}
|
| 101 |
+
} catch (e) {
|
| 102 |
+
webLLMId = String(modelName).split('/').pop() || String(modelName);
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
console.log(`Loading ${webLLMId} via WebLLM...`);
|
| 106 |
+
|
| 107 |
+
// The web-llm engine looks up the provided model id in appConfig.model_list.
|
| 108 |
+
// Many prebuilt entries use short model_ids like "gemma-2b-it-q4f16_1-MLC" rather than
|
| 109 |
+
// owner/model (google/gemma-2b). To increase the chance of a match, when we detect a
|
| 110 |
+
// local Gemma path choose a known prebuilt Gemma model_id and use it as the engine id.
|
| 111 |
+
let engineRequestedId = webLLMId;
|
| 112 |
+
|
| 113 |
+
// Prepare an appConfig that includes a mapping for this model id
|
| 114 |
+
// so WebLLM can locate the local safetensors files served by the dev server.
|
| 115 |
+
const baseAppConfig = webllm.prebuiltAppConfig ? JSON.parse(JSON.stringify(webllm.prebuiltAppConfig)) : {};
|
| 116 |
+
try {
|
| 117 |
+
// Ensure model_list is an array (prebuiltAppConfig uses an array)
|
| 118 |
+
if (!baseAppConfig.model_list) baseAppConfig.model_list = [];
|
| 119 |
+
// If the prebuilt appConfig already contains a gemma entry, prefer
|
| 120 |
+
// that exact model_id so our engineRequestedId matches what the
|
| 121 |
+
// runtime expects. This helps avoid mismatches from similar ids.
|
| 122 |
+
try {
|
| 123 |
+
if (Array.isArray(baseAppConfig.model_list)) {
|
| 124 |
+
const gemmaEntry = baseAppConfig.model_list.find(e => e && typeof e.model_id === 'string' && /gemma/i.test(e.model_id));
|
| 125 |
+
if (gemmaEntry && gemmaEntry.model_id) {
|
| 126 |
+
engineRequestedId = gemmaEntry.model_id;
|
| 127 |
+
}
|
| 128 |
+
}
|
| 129 |
+
} catch (e) {
|
| 130 |
+
// ignore
|
| 131 |
+
}
|
| 132 |
+
// Helper to push a model_list entry if it doesn't already exist
|
| 133 |
+
const pushModelListEntry = (entry) => {
|
| 134 |
+
try {
|
| 135 |
+
if (!Array.isArray(baseAppConfig.model_list)) baseAppConfig.model_list = [];
|
| 136 |
+
const exists = baseAppConfig.model_list.find(e => e && (e.model_id === entry.model_id || e.model === entry.model));
|
| 137 |
+
if (!exists) {
|
| 138 |
+
// put injected entries at the front so engine lookup sees them first
|
| 139 |
+
baseAppConfig.model_list.unshift(entry);
|
| 140 |
+
}
|
| 141 |
+
} catch (e) {
|
| 142 |
+
// ignore
|
| 143 |
+
}
|
| 144 |
+
};
|
| 145 |
+
|
| 146 |
+
// If modelName is a local-served path, derive its HTTP base
|
| 147 |
+
if (typeof modelName === 'string' && modelName.startsWith('/models/')) {
|
| 148 |
+
const origin = (typeof self !== 'undefined' && self.location && self.location.origin) ? self.location.origin : (typeof location !== 'undefined' ? location.origin : '');
|
| 149 |
+
// Ensure we build a stable absolute URL for the local model base.
|
| 150 |
+
// If modelName is a path like '/models/owner/model/resolve/main' keep the
|
| 151 |
+
// leading slash; if it's missing, add it. Avoid using new URL with a
|
| 152 |
+
// relative path that can append to the current document path and
|
| 153 |
+
// produce duplicated segments (e.g. '/models/models/...').
|
| 154 |
+
const cleaned = modelName.replace(/\/$/, '');
|
| 155 |
+
const withLeading = cleaned.startsWith('/') ? cleaned : '/' + cleaned.replace(/^\/*/, '');
|
| 156 |
+
const localBase = origin ? origin.replace(/\/$/, '') + withLeading : withLeading;
|
| 157 |
+
// Create entries to mirror the prebuilt Gemma manifest exactly and
|
| 158 |
+
// also point a local copy at our dev-server URLs. This increases
|
| 159 |
+
// the chance the engine will find and accept the model record.
|
| 160 |
+
if (/gemma-2b/i.test(localBase)) {
|
| 161 |
+
engineRequestedId = 'gemma-2b-it-q4f16_1-MLC';
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
// Verbatim-style prebuilt gemma entry (same shape as webllm.prebuiltAppConfig)
|
| 165 |
+
const prebuiltGemmaEntry = {
|
| 166 |
+
model: 'https://huggingface.co/mlc-ai/gemma-2-2b-it-q4f16_1-MLC',
|
| 167 |
+
model_id: 'gemma-2-2b-it-q4f16_1-MLC',
|
| 168 |
+
model_lib: 'https://raw.githubusercontent.com/mlc-ai/binary-mlc-llm-libs/main/web-llm-models/v0_2_48/gemma-2-2b-it-q4f16_1-ctx4k_cs1k-webgpu.wasm',
|
| 169 |
+
vram_required_MB: 1895.3,
|
| 170 |
+
low_resource_required: false,
|
| 171 |
+
buffer_size_required_bytes: 262144000,
|
| 172 |
+
required_features: ['shader-f16'],
|
| 173 |
+
overrides: { context_window_size: 4096 }
|
| 174 |
+
};
|
| 175 |
+
|
| 176 |
+
pushModelListEntry(prebuiltGemmaEntry);
|
| 177 |
+
|
| 178 |
+
// Local copy that points to our served files and uses the short id
|
| 179 |
+
const localGemmaEntry = {
|
| 180 |
+
model: localBase,
|
| 181 |
+
model_id: engineRequestedId || prebuiltGemmaEntry.model_id,
|
| 182 |
+
model_lib: prebuiltGemmaEntry.model_lib,
|
| 183 |
+
model_type: 0,
|
| 184 |
+
vram_required_MB: prebuiltGemmaEntry.vram_required_MB,
|
| 185 |
+
buffer_size_required_bytes: prebuiltGemmaEntry.buffer_size_required_bytes,
|
| 186 |
+
low_resource_required: prebuiltGemmaEntry.low_resource_required,
|
| 187 |
+
required_features: prebuiltGemmaEntry.required_features,
|
| 188 |
+
overrides: prebuiltGemmaEntry.overrides,
|
| 189 |
+
weights: [localBase + '/model.safetensors'],
|
| 190 |
+
tokenizer: localBase + '/tokenizer.model',
|
| 191 |
+
tokenizer_config: localBase + '/tokenizer_config.json',
|
| 192 |
+
config: localBase + '/config.json',
|
| 193 |
+
format: 'safetensors',
|
| 194 |
+
dtype: 'fp16'
|
| 195 |
+
};
|
| 196 |
+
|
| 197 |
+
pushModelListEntry(localGemmaEntry);
|
| 198 |
+
|
| 199 |
+
// Also create a variant keyed by the owner/model string so engines
|
| 200 |
+
// that look up that id will match; the files still point locally.
|
| 201 |
+
const localGemmaOwnerKey = Object.assign({}, localGemmaEntry, { model_id: webLLMId });
|
| 202 |
+
pushModelListEntry(localGemmaOwnerKey);
|
| 203 |
+
|
| 204 |
+
// Some engine lookups are picky: they may compare against the
|
| 205 |
+
// model field or expect a record whose `model` value equals the
|
| 206 |
+
// requested id. Add a minimal mapping that uses the owner/model
|
| 207 |
+
// string as both `model` and `model_id` to maximize matching
|
| 208 |
+
// possibilities.
|
| 209 |
+
try {
|
| 210 |
+
pushModelListEntry({
|
| 211 |
+
model: webLLMId,
|
| 212 |
+
model_id: webLLMId,
|
| 213 |
+
model_lib: prebuiltGemmaEntry.model_lib,
|
| 214 |
+
model_type: 0,
|
| 215 |
+
vram_required_MB: prebuiltGemmaEntry.vram_required_MB,
|
| 216 |
+
buffer_size_required_bytes: prebuiltGemmaEntry.buffer_size_required_bytes,
|
| 217 |
+
low_resource_required: prebuiltGemmaEntry.low_resource_required,
|
| 218 |
+
required_features: prebuiltGemmaEntry.required_features,
|
| 219 |
+
overrides: prebuiltGemmaEntry.overrides,
|
| 220 |
+
weights: [localBase + '/model.safetensors'],
|
| 221 |
+
tokenizer: localBase + '/tokenizer.model',
|
| 222 |
+
tokenizer_config: localBase + '/tokenizer_config.json',
|
| 223 |
+
config: localBase + '/config.json',
|
| 224 |
+
format: 'safetensors',
|
| 225 |
+
dtype: 'fp16'
|
| 226 |
+
});
|
| 227 |
+
} catch (e) {
|
| 228 |
+
// ignore
|
| 229 |
+
}
|
| 230 |
+
} else if (typeof modelName === 'string' && modelName.includes('/')) {
|
| 231 |
+
// If modelName looks like owner/model (or 'models/owner/model') and we also have a local mirror
|
| 232 |
+
// under /models, attempt to point at that mirror (best-effort). Normalize accidental
|
| 233 |
+
// leading 'models' segments to avoid constructing '/models/models/...'.
|
| 234 |
+
const parts = modelName.split('/').filter(p => p !== '');
|
| 235 |
+
let owner = parts[0], model = parts[1];
|
| 236 |
+
// If someone passed 'models/owner/model/...' shift the window
|
| 237 |
+
if (owner === 'models' && parts.length >= 3) {
|
| 238 |
+
owner = parts[1];
|
| 239 |
+
model = parts[2];
|
| 240 |
+
}
|
| 241 |
+
const origin = (typeof self !== 'undefined' && self.location && self.location.origin) ? self.location.origin : (typeof location !== 'undefined' ? location.origin : '');
|
| 242 |
+
const probeLocal = origin ? `${origin}/models/${owner}/${model}/resolve/main` : `/models/${owner}/${model}/resolve/main`;
|
| 243 |
+
// If owner/model style was provided, also prefer a prebuilt gemma id when appropriate
|
| 244 |
+
if (/gemma-2b/i.test(probeLocal)) {
|
| 245 |
+
engineRequestedId = 'gemma-2b-it-q4f16_1-MLC';
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
pushModelListEntry({
|
| 249 |
+
model: probeLocal,
|
| 250 |
+
model_id: engineRequestedId,
|
| 251 |
+
model_lib: 'https://raw.githubusercontent.com/mlc-ai/binary-mlc-llm-libs/main/web-llm-models/v0_2_48/gemma-2-2b-it-q4f16_1-ctx4k_cs1k-webgpu.wasm',
|
| 252 |
+
model_type: 0,
|
| 253 |
+
vram_required_MB: 1895.3,
|
| 254 |
+
buffer_size_required_bytes: 262144000,
|
| 255 |
+
low_resource_required: false,
|
| 256 |
+
required_features: ['shader-f16'],
|
| 257 |
+
overrides: { context_window_size: 4096 },
|
| 258 |
+
weights: [probeLocal + '/model.safetensors'],
|
| 259 |
+
tokenizer: probeLocal + '/tokenizer.model',
|
| 260 |
+
tokenizer_config: probeLocal + '/tokenizer_config.json',
|
| 261 |
+
config: probeLocal + '/config.json',
|
| 262 |
+
format: 'safetensors',
|
| 263 |
+
dtype: 'fp16'
|
| 264 |
+
});
|
| 265 |
+
// Also insert an entry that uses the owner/model string as model_id
|
| 266 |
+
// to handle engines that match against that id.
|
| 267 |
+
pushModelListEntry({
|
| 268 |
+
model: probeLocal,
|
| 269 |
+
model_id: webLLMId,
|
| 270 |
+
model_lib: 'https://raw.githubusercontent.com/mlc-ai/binary-mlc-llm-libs/main/web-llm-models/v0_2_48/gemma-2-2b-it-q4f16_1-ctx4k_cs1k-webgpu.wasm',
|
| 271 |
+
model_type: 0,
|
| 272 |
+
vram_required_MB: 1895.3,
|
| 273 |
+
buffer_size_required_bytes: 262144000,
|
| 274 |
+
low_resource_required: false,
|
| 275 |
+
required_features: ['shader-f16'],
|
| 276 |
+
overrides: { context_window_size: 4096 },
|
| 277 |
+
weights: [probeLocal + '/model.safetensors'],
|
| 278 |
+
tokenizer: probeLocal + '/tokenizer.model',
|
| 279 |
+
tokenizer_config: probeLocal + '/tokenizer_config.json',
|
| 280 |
+
config: probeLocal + '/config.json',
|
| 281 |
+
format: 'safetensors',
|
| 282 |
+
dtype: 'fp16'
|
| 283 |
+
});
|
| 284 |
+
}
|
| 285 |
+
} catch (e) {
|
| 286 |
+
console.log('Failed to prepare WebLLM appConfig override:', String(e));
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
// Debug: print what appConfig we are passing so we can diagnose
|
| 290 |
+
// why CreateMLCEngine may not find the model record.
|
| 291 |
+
try {
|
| 292 |
+
console.log('WebLLM appConfig for', webLLMId, JSON.stringify(baseAppConfig, null, 2));
|
| 293 |
+
try {
|
| 294 |
+
// Also print a concise list of model_ids/models present to help
|
| 295 |
+
// quickly spot mismatches between the requested id and available
|
| 296 |
+
// entries.
|
| 297 |
+
const mappings = (Array.isArray(baseAppConfig.model_list) ? baseAppConfig.model_list : []).map(e => ({ model: e.model, model_id: e.model_id }));
|
| 298 |
+
console.log('WebLLM appConfig mappings:', JSON.stringify(mappings, null, 2));
|
| 299 |
+
} catch (e) {}
|
| 300 |
+
} catch (e) {
|
| 301 |
+
console.log('WebLLM appConfig (unserializable)');
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
// Debug: print which id we will request so we can correlate with the
|
| 305 |
+
// engine error message about missing model records.
|
| 306 |
+
try {
|
| 307 |
+
console.log('Requesting CreateMLCEngine with engineRequestedId=', engineRequestedId, ' webLLMId=', webLLMId);
|
| 308 |
+
} catch (e) {}
|
| 309 |
+
|
| 310 |
+
// Try requesting the engine with the requested model id (which may be a
|
| 311 |
+
// prebuilt short id like 'gemma-2b-it-q4f16_1-MLC'). The engine matches
|
| 312 |
+
// against appConfig.model_list entries using the model_id field, so we
|
| 313 |
+
// pass engineRequestedId when available to improve matching.
|
| 314 |
+
const engine = await webllm.CreateMLCEngine(engineRequestedId || webLLMId, {
|
| 315 |
+
appConfig: baseAppConfig
|
| 316 |
});
|
| 317 |
|
| 318 |
// Quick end-to-end validation: run a very small prompt to ensure the
|