Skip to content

Commit 453c162

Browse files
authored
feat: split gguf files support (#214)
* feat: split gguf files support * feat: `pull` command * feat: `stopOnAbortSignal` and `customStopTriggers` on `LlamaChat` and `LlamaChatSession` * feat: `checkTensors` parameter on `loadModel` * feat: improve Electron support * fix: more efficient max context size finding algorithm * fix: make embedding-only models work correctly * fix: perform context shift on the correct token index on generation * fix: make context loading work for all models on Electron * refactor: simplify `LlamaText` implementation * docs: update simple usage
1 parent ef501f9 commit 453c162

File tree

60 files changed

+9161
-6508
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+9161
-6508
lines changed

.vitepress/config.ts

Lines changed: 75 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import {defineConfig, DefaultTheme} from "vitepress";
1+
import {DefaultTheme, defineConfig} from "vitepress";
22
import path from "path";
33
import fs from "fs-extra";
44
import {fileURLToPath} from "url";
5+
import {transformerTwoslash} from "@shikijs/vitepress-twoslash";
6+
import ts from "typescript";
57
import typedocSidebar from "../docs/api/typedoc-sidebar.json"; // if this import fails, run `npm run docs:generateTypedoc`
68
import envVar from "env-var";
79
import process from "process";
@@ -126,6 +128,29 @@ export default defineConfig({
126128
{rel: "canonical", href: canonicalUrl}
127129
])
128130
},
131+
markdown: {
132+
codeTransformers: [
133+
transformerTwoslash({
134+
// explicitTrigger: false,
135+
twoslashOptions: {
136+
compilerOptions: {
137+
...(await fs.readJSON(path.join(__dirname, "..", "tsconfig.json"))).compilerOptions,
138+
moduleResolution: undefined,
139+
paths: {
140+
"node-llama-cpp": [path.resolve(__dirname, "..", "src", "index.ts")]
141+
},
142+
typeRoots: [
143+
path.resolve(__dirname, "..", "node_modules"),
144+
path.resolve(__dirname, "..", "node_modules", "@types")
145+
],
146+
module: ts.ModuleKind.ES2022,
147+
target: ts.ScriptTarget.ES2022
148+
},
149+
tsModule: ts
150+
}
151+
})
152+
]
153+
},
129154
themeConfig: {
130155
editLink: {
131156
pattern: "https://github.com/withcatai/node-llama-cpp/edit/master/docs/:path"
@@ -196,6 +221,7 @@ export default defineConfig({
196221
collapsed: true,
197222
link: "/",
198223
items: [
224+
{text: "Pull", link: "/pull"},
199225
{text: "Chat", link: "/chat"},
200226
{text: "Download", link: "/download"},
201227
{text: "Complete", link: "/complete"},
@@ -216,6 +242,7 @@ export default defineConfig({
216242
}]
217243
},
218244
socialLinks: [
245+
{icon: "npm", link: "https://www.npmjs.com/package/node-llama-cpp"},
219246
{icon: "github", link: "https://github.com/withcatai/node-llama-cpp"}
220247
]
221248
}
@@ -257,8 +284,6 @@ function getApiReferenceSidebar(): typeof typedocSidebar {
257284
return item;
258285

259286
case "Variables":
260-
item.text = "Enums";
261-
262287
if (item.collapsed)
263288
item.collapsed = false;
264289

@@ -271,6 +296,7 @@ function getApiReferenceSidebar(): typeof typedocSidebar {
271296
}
272297

273298
function orderApiReferenceSidebar(sidebar: typeof typedocSidebar): typeof typedocSidebar {
299+
applyOverrides(sidebar);
274300
orderClasses(sidebar);
275301
orderTypes(sidebar);
276302
orderFunctions(sidebar);
@@ -280,6 +306,23 @@ function orderApiReferenceSidebar(sidebar: typeof typedocSidebar): typeof typedo
280306
return sidebar;
281307
}
282308

309+
function applyOverrides(sidebar: typeof typedocSidebar) {
310+
const functions = sidebar.find((item) => item.text === "Functions");
311+
312+
const llamaTextFunction = functions?.items?.find((item) => item.text === "LlamaText");
313+
if (llamaTextFunction != null) {
314+
delete (llamaTextFunction as {link?: string}).link;
315+
}
316+
317+
const classes = sidebar.find((item) => item.text === "Classes");
318+
if (classes != null && classes.items instanceof Array && !classes.items.some((item) => item.text === "LlamaText")) {
319+
classes.items.push({
320+
text: "LlamaText",
321+
link: "/api/classes/LlamaText.md"
322+
});
323+
}
324+
}
325+
283326
function orderClasses(sidebar: typeof typedocSidebar) {
284327
const baseChatWrapper = "ChatWrapper";
285328
const chatWrapperItems: DefaultTheme.SidebarItem[] = [];
@@ -322,21 +365,36 @@ function orderClasses(sidebar: typeof typedocSidebar) {
322365
{moveToEndIfGrouped: false}
323366
)
324367

325-
const LlamaTextGroup = {
326-
text: "LlamaText",
327-
collapsed: true,
328-
items: []
329-
};
330-
(classes.items as DefaultTheme.SidebarItem[]).push(LlamaTextGroup);
331-
const LlamaTextGroupItemsOrder = ["SpecialTokensText", "SpecialToken"];
368+
let LlamaTextGroup = classes.items.find((item) => item.text === "LlamaText") as {
369+
text: string,
370+
collapsed?: boolean,
371+
items?: []
372+
} | undefined;
373+
if (LlamaTextGroup == null) {
374+
LlamaTextGroup = {
375+
text: "LlamaText",
376+
collapsed: true,
377+
items: []
378+
};
379+
(classes.items as DefaultTheme.SidebarItem[]).push(LlamaTextGroup);
380+
}
332381

333-
groupItems(
334-
classes.items,
335-
(item) => item === LlamaTextGroup,
336-
(item) => item.text != null && LlamaTextGroupItemsOrder.includes(item.text),
337-
{moveToEndIfGrouped: false}
338-
)
339-
sortItemsInOrder(LlamaTextGroup.items, LlamaTextGroupItemsOrder);
382+
if (LlamaTextGroup != null) {
383+
LlamaTextGroup.collapsed = true;
384+
385+
if (LlamaTextGroup.items == null)
386+
LlamaTextGroup.items = [];
387+
388+
const LlamaTextGroupItemsOrder = ["SpecialTokensText", "SpecialToken"];
389+
390+
groupItems(
391+
classes.items,
392+
(item) => item === LlamaTextGroup,
393+
(item) => item.text != null && LlamaTextGroupItemsOrder.includes(item.text),
394+
{moveToEndIfGrouped: false}
395+
)
396+
sortItemsInOrder(LlamaTextGroup.items, LlamaTextGroupItemsOrder);
397+
}
340398

341399
sortItemsInOrder(chatWrapperItems, chatWrappersOrder);
342400
}

.vitepress/theme/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
import {h} from "vue";
22
import Theme from "vitepress/theme";
3+
import TwoslashFloatingVue from "@shikijs/vitepress-twoslash/client";
4+
import "@shikijs/vitepress-twoslash/style.css";
35
import "./style.css";
46

7+
import type {EnhanceAppContext} from "vitepress";
8+
59
export default {
610
extends: Theme,
711
Layout: () => {
812
return h(Theme.Layout, null, {});
913
},
10-
enhanceApp({app, router, siteData}) {}
14+
enhanceApp({app, router, siteData}: EnhanceAppContext) {
15+
// @ts-ignore
16+
app.use(TwoslashFloatingVue);
17+
}
1118
};

.vitepress/theme/style.css

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,52 @@
4040
}
4141
}
4242

43+
.VPNavBar .divider-line:after {
44+
display: block;
45+
position: absolute;
46+
width: 100%;
47+
height: 32px;
48+
background: linear-gradient(var(--vp-c-bg), transparent 70%);
49+
content: "";
50+
transition: opacity 0.5s;
51+
opacity: 0;
52+
pointer-events: none;
53+
}
54+
55+
.VPNavBar:not(.home) .divider-line[class] {
56+
background-color: transparent;
57+
}
58+
.VPNavBar:not(.home) .divider-line:after {
59+
opacity: 1;
60+
}
61+
62+
@media (min-width: 960px) {
63+
.VPNavBar:not(.home.top) .divider-line[class] {
64+
background-color: transparent;
65+
}
66+
.VPNavBar:not(.home.top) .divider-line:after {
67+
opacity: 1;
68+
}
69+
70+
.VPNavBar:not(.has-sidebar):not(.home.top) .divider[class] {
71+
background-color: transparent;
72+
}
73+
}
74+
75+
.VPLocalNav[class] {
76+
border-bottom: none;
77+
}
78+
.VPLocalNav[class]:after {
79+
display: block;
80+
position: absolute;
81+
width: 100%;
82+
height: 32px;
83+
background: linear-gradient(var(--vp-c-bg), transparent 70%);
84+
content: "";
85+
transition: opacity 0.5s;
86+
pointer-events: none;
87+
}
88+
4389
.main-badges>p {
4490
display: flex;
4591
flex-direction: row;

.vitepress/utils/buildHtmlTable.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export function buildHtmlTable(header: string[], rows: string[][]) {
1414
}
1515

1616
if (rows.length > 0) {
17-
res += "" + "<tbody>\n";
17+
res += "" + '<tbody style="white-space: pre-wrap">\n';
1818

1919
for (const row of rows) {
2020
res += "" + "" + "<tr>\n";

.vitepress/utils/getCommandHtmlDoc.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ function renderOptionsGroupOptionsTable(options: {name: string, option: Options}
213213
const hasDefaultDescription = option.defaultDescription != null && option.defaultDescription.trim().length > 0;
214214
if (option.default != null || hasDefaultDescription) {
215215
if (hasDefaultDescription && option.defaultDescription != null)
216-
optionDescription.push(`<span style="opacity: 0.72">(${htmlEscape("default: ")}${htmlEscape(option.defaultDescription.trim())})</span>`);
216+
optionDescription.push(`<span style="opacity: 0.72">(${htmlEscape("default: ")}${htmlEscapeWithCodeMarkdown(option.defaultDescription.trim())})</span>`);
217217
else
218218
optionDescription.push(`<span style="opacity: 0.72">(${htmlEscape("default: ")}<code>${htmlEscape(option.default)}</code>)</span>`);
219219
}

README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,18 @@ To disable this behavior set the environment variable `NODE_LLAMA_CPP_SKIP_DOWNL
4747
```typescript
4848
import {fileURLToPath} from "url";
4949
import path from "path";
50-
import {LlamaModel, LlamaContext, LlamaChatSession} from "node-llama-cpp";
50+
import {getLlama, LlamaChatSession} from "node-llama-cpp";
5151

5252
const __dirname = path.dirname(fileURLToPath(import.meta.url));
5353

54-
const model = new LlamaModel({
55-
modelPath: path.join(__dirname, "models", "codellama-13b.Q3_K_M.gguf")
54+
const llama = await getLlama();
55+
const model = await llama.loadModel({
56+
modelPath: path.join(__dirname, "models", "dolphin-2.1-mistral-7b.Q4_K_M.gguf")
57+
});
58+
const context = await model.createContext();
59+
const session = new LlamaChatSession({
60+
contextSequence: context.getSequence()
5661
});
57-
const context = new LlamaContext({model});
58-
const session = new LlamaChatSession({context});
5962

6063

6164
const q1 = "Hi there, how are you?";

docs/guide/cli/cli.data.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {CommandModule} from "yargs";
22
import {getCommandHtmlDoc} from "../../../.vitepress/utils/getCommandHtmlDoc.js";
3+
import {PullCommand} from "../../../src/cli/commands/PullCommand.js";
34
import {BuildCommand} from "../../../src/cli/commands/BuildCommand.js";
45
import {ChatCommand} from "../../../src/cli/commands/ChatCommand.js";
56
import {CompleteCommand} from "../../../src/cli/commands/CompleteCommand.js";
@@ -23,6 +24,7 @@ export default {
2324

2425
return {
2526
index: buildIndexTable([
27+
["pull", PullCommand],
2628
["chat", ChatCommand],
2729
["complete", CompleteCommand],
2830
["infill", InfillCommand],
@@ -32,6 +34,7 @@ export default {
3234
["clear", ClearCommand]
3335
]),
3436

37+
pull: await getCommandHtmlDoc(PullCommand),
3538
chat: await getCommandHtmlDoc(ChatCommand),
3639
complete: await getCommandHtmlDoc(CompleteCommand),
3740
infill: await getCommandHtmlDoc(InfillCommand),

docs/guide/cli/pull.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
outline: deep
3+
---
4+
# `pull` command
5+
6+
<script setup lang="ts">
7+
import {data as docs} from "./cli.data.js";
8+
const commandDoc = docs.pull;
9+
</script>
10+
11+
{{commandDoc.description}}
12+
13+
## Usage
14+
```shell-vue
15+
{{commandDoc.usage}}
16+
```
17+
<div v-html="commandDoc.options"></div>

docs/guide/index.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
outline: deep
33
---
4-
# Getting started
4+
# Getting started
55

66
## Installation
77
Inside of your node.js project directory, run this command:
@@ -53,15 +53,18 @@ npx --no node-llama-cpp chat --wrapper llamaChat --model <path-to-a-model-file-o
5353
```typescript
5454
import {fileURLToPath} from "url";
5555
import path from "path";
56-
import {LlamaModel, LlamaContext, LlamaChatSession} from "node-llama-cpp";
56+
import {getLlama, LlamaChatSession} from "node-llama-cpp";
5757

5858
const __dirname = path.dirname(fileURLToPath(import.meta.url));
5959

60-
const model = new LlamaModel({
61-
modelPath: path.join(__dirname, "models", "codellama-13b.Q3_K_M.gguf")
60+
const llama = await getLlama();
61+
const model = await llama.loadModel({
62+
modelPath: path.join(__dirname, "models", "dolphin-2.1-mistral-7b.Q4_K_M.gguf")
63+
});
64+
const context = await model.createContext();
65+
const session = new LlamaChatSession({
66+
contextSequence: context.getSequence()
6267
});
63-
const context = new LlamaContext({model});
64-
const session = new LlamaChatSession({context});
6568

6669

6770
const q1 = "Hi there, how are you?";

llama/addon.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,10 @@ class AddonModel : public Napi::ObjectWrap<AddonModel> {
289289
model_params.use_mlock = options.Get("useMlock").As<Napi::Boolean>().Value();
290290
}
291291

292+
if (options.Has("checkTensors")) {
293+
model_params.check_tensors = options.Get("checkTensors").As<Napi::Boolean>().Value();
294+
}
295+
292296
if (options.Has("onLoadProgress")) {
293297
auto onLoadProgressJSCallback = options.Get("onLoadProgress").As<Napi::Function>();
294298
if (onLoadProgressJSCallback.IsFunction()) {
@@ -1483,6 +1487,11 @@ class AddonContextSampleTokenWorker : public Napi::AsyncWorker {
14831487
llama_token new_token_id = 0;
14841488

14851489
// Select the best prediction.
1490+
if (llama_get_logits(ctx->ctx) == nullptr) {
1491+
SetError("This model does not support token generation");
1492+
return;
1493+
}
1494+
14861495
auto logits = llama_get_logits_ith(ctx->ctx, batchLogitIndex);
14871496
auto n_vocab = llama_n_vocab(ctx->model->model);
14881497

@@ -1701,13 +1710,15 @@ static void addonLlamaCppLogCallback(ggml_log_level level, const char* text, voi
17011710
}
17021711
}
17031712

1704-
if (level == 2) {
1705-
fputs(text, stderr);
1706-
fflush(stderr);
1707-
} else {
1708-
fputs(text, stdout);
1709-
fflush(stdout);
1710-
}
1713+
if (text != nullptr) {
1714+
if (level == 2) {
1715+
fputs(text, stderr);
1716+
fflush(stderr);
1717+
} else {
1718+
fputs(text, stdout);
1719+
fflush(stdout);
1720+
}
1721+
}
17111722
}
17121723

17131724
Napi::Value setLogger(const Napi::CallbackInfo& info) {

0 commit comments

Comments
 (0)