Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
quickjs bare-bones?
separate jamfile project, WIP
  • Loading branch information
asg017 committed Dec 20, 2024
commit fd370f43852e1345e019f8742f7829f2007e8d51
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ include llamafile/BUILD.mk
include llama.cpp/BUILD.mk
include stable-diffusion.cpp/BUILD.mk
include whisper.cpp/BUILD.mk
include jamfile/BUILD.mk

# the root package is `o//` by default
# building a package also builds its sub-packages
Expand Down
12 changes: 12 additions & 0 deletions jamfile/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
BasedOnStyle: LLVM
IndentWidth: 4
ColumnLimit: 100
---
Language: Cpp
AllowShortFunctionsOnASingleLine: false
AlignTrailingComments: false
AlignEscapedNewlines: DontAlign
AlwaysBreakTemplateDeclarations: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
---
110 changes: 110 additions & 0 deletions jamfile/BUILD.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘

PKGS += LLAMA_CPP_JAMFILE

LLAMA_CPP_JAMFILE_FILES := $(wildcard jamfile/*)
LLAMA_CPP_JAMFILE_HDRS = $(filter %.h,$(LLAMA_CPP_JAMFILE_FILES))
LLAMA_CPP_JAMFILE_SRCS_C = $(filter %.c,$(LLAMA_CPP_JAMFILE_FILES))
LLAMA_CPP_JAMFILE_SRCS_CPP = $(filter %.cpp,$(LLAMA_CPP_JAMFILE_FILES))
LLAMA_CPP_JAMFILE_SRCS = $(LLAMA_CPP_JAMFILE_SRCS_C) $(LLAMA_CPP_JAMFILE_SRCS_CPP)

LLAMA_CPP_JAMFILE_OBJS = \
$(LLAMA_CPP_JAMFILE_SRCS_C:%.c=o/$(MODE)/%.o) \
$(LLAMA_CPP_JAMFILE_SRCS_CPP:%.cpp=o/$(MODE)/%.o)


#o/$(MODE)/jamfile/jamfile.a: $(LLAMA_CPP_JAMFILE_SRCS_C)

### o/$(MODE)/jamfile/sqlite-vec.o: jamfile/sqlite-vec.c
### o/$(MODE)/jamfile/sqlite-vec.a: o/$(MODE)/jamfile/sqlite-vec.o
###
### o/$(MODE)/jamfile/sqlite-csv.o: jamfile/sqlite-csv.c
### o/$(MODE)/jamfile/sqlite-csv.a: o/$(MODE)/jamfile/sqlite-csv.o
###
###
o/$(MODE)/jamfile/quickjs-llamafile-completion.o: jamfile/quickjs-llamafile-completion.cpp
o/$(MODE)/jamfile/quickjs-llamafile-completion.a: o/$(MODE)/jamfile/quickjs-llamafile-completion.o

o/$(MODE)/jamfile/quickjs-llamafile.o: jamfile/quickjs-llamafile.c jamfile/quickjs-llamafile-completion.cpp #o/$(MODE)/jamfile/quickjs-llamafile-completion.o
o/$(MODE)/jamfile/quickjs-llamafile.a: o/$(MODE)/jamfile/quickjs-llamafile.o o/$(MODE)/jamfile/quickjs-llamafile-completion.a
###
### o/$(MODE)/jamfile/sqlite-lines.o: jamfile/sqlite-lines.c
### o/$(MODE)/jamfile/sqlite-lines.a: o/$(MODE)/jamfile/sqlite-lines.o
###
### o/$(MODE)/jamfile/sqlite-lembed.o: jamfile/sqlite-lembed.c
### o/$(MODE)/jamfile/sqlite-lembed.a: o/$(MODE)/jamfile/sqlite-lembed.o o/$(MODE)/llama.cpp/llama.cpp.a


# jamfile:assert bytecode
o/$(MODE)/jamfile/assert.gen.c: jamfile/js_builtins/assert.js o/$(mode)/third_party/quickjs/qjsc
o/$(mode)/third_party/quickjs/qjsc -m -o $@ $<
o/$(MODE)/jamfile/assert.gen.o: o/$(MODE)/jamfile/assert.gen.c

# jamfile:fmt bytecode
o/$(MODE)/jamfile/fmt.gen.c: jamfile/js_builtins/fmt.js o/$(mode)/third_party/quickjs/qjsc
o/$(mode)/third_party/quickjs/qjsc -m -o $@ $<
o/$(MODE)/jamfile/fmt.gen.o: o/$(MODE)/jamfile/fmt.gen.c

# jamfile:cli bytecode
o/$(MODE)/jamfile/cli.gen.c: jamfile/js_builtins/cli.js o/$(MODE)/third_party/quickjs/qjsc
o/$(mode)/third_party/quickjs/qjsc -m -o $@ $<
o/$(MODE)/jamfile/cli.gen.o: o/$(MODE)/jamfile/cli.gen.c

# jamfile:colors bytecode
o/$(MODE)/jamfile/colors.gen.c: jamfile/js_builtins/colors.js o/$(MODE)/third_party/quickjs/qjsc
o/$(mode)/third_party/quickjs/qjsc -m -o $@ $<
o/$(MODE)/jamfile/colors.gen.o: o/$(MODE)/jamfile/colors.gen.c

# jamfile:zod bytecode
o/$(MODE)/jamfile/zod.gen.c: jamfile/js_builtins/zod.js o/$(mode)/third_party/quickjs/qjsc
o/$(mode)/third_party/quickjs/qjsc -m -o $@ $<
o/$(MODE)/jamfile/zod.gen.o: o/$(MODE)/jamfile/zod.gen.c

# include the raw contents of the jamfile.d.ts into jamfile for the `jamfile types` command
o/$(MODE)/jamfile/jamfile-types.c: jamfile/jamfile.d.ts
xxd --include $< > $@
o/$(MODE)/jamfile/jamfile-types.o: o/$(MODE)/jamfile/jamfile-types.c

o/$(MODE)/jamfile/jamfile.a: \
o/$(MODE)/jamfile/jamfile-types.o \
o/$(MODE)/jamfile/cli.gen.o \
o/$(MODE)/jamfile/fmt.gen.o \
o/$(MODE)/jamfile/zod.gen.o \
o/$(MODE)/jamfile/assert.gen.o \
o/$(MODE)/jamfile/colors.gen.o \
o/$(MODE)/jamfile/quickjs-sqlite.o \
o/$(MODE)/jamfile/quickjs-llamafile.o \
o/$(MODE)/jamfile/quickjs-llamafile-completion.o \
o/$(MODE)/third_party/quickjs/repl.o \
o/$(MODE)/third_party/quickjs/cutils.o \
o/$(MODE)/third_party/quickjs/libbf.o \
o/$(MODE)/third_party/quickjs/quickjs.o \
o/$(MODE)/third_party/quickjs/libregexp.o \
o/$(MODE)/third_party/quickjs/libunicode.o \
o/$(MODE)/third_party/quickjs/quickjs-libc.o


o/$(MODE)/jamfile/jamfile: \
o/$(MODE)/jamfile/jamfile.a \
o/$(MODE)/jamfile/jamfile.1.asc.zip.o \
o/$(MODE)/llama.cpp/llama.cpp.a \
o/$(MODE)/third_party/sqlite/sqlite3.a \
o/$(MODE)/jamfile/quickjs-sqlite.a \
o/$(MODE)/jamfile/quickjs-llamafile.a \
o/$(MODE)/embedfile/sqlite-csv.a \
o/$(MODE)/embedfile/sqlite-vec.a \
o/$(MODE)/embedfile/sqlite-lines.a \
o/$(MODE)/embedfile/sqlite-lembed.a

$(LLAMA_CPP_JAMFILE_OBJS): private CCFLAGS += -DSQLITE_CORE

.PHONY: o/$(MODE)/jamfile
o/$(MODE)/jamfile: \
o/$(MODE)/jamfile/jamfile

$(LLAMA_CPP_JAMFILE_OBJS): llama.cpp/BUILD.mk jamfile/BUILD.mk
.PHONY: jamfile-test-js

jamfile-test-js: o/$(MODE)/jamfile/jamfile jamfile/tests/js/test.js
$< run jamfile/tests/js/test.js
6 changes: 6 additions & 0 deletions jamfile/examples/spellcheck/document.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
The first spell ceckers were "verifiers" instead of "correctors." They
offered no suggestions for incorrectly spelled words. This was helpful
for typos but it was not so helpfl for logical or phonetic errors. The
challenge the developers faced was the difficulty in offering useful
suggestions for misspelled words. This requires reducing words to a
sceletal form and applying pattern-matching algorithms.
4 changes: 4 additions & 0 deletions jamfile/examples/spellcheck/spellcheck.gbnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
root ::= good | list
good ::= "ok"
list ::= item ( "\n" item )*
item ::= "- `" [-_0-9A-Za-z]+ "` should be `" [-_0-9A-Za-z]+ "`"
36 changes: 36 additions & 0 deletions jamfile/examples/spellcheck/spellcheck.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/// <reference types="./jamfile/jamfile.d.ts"/>

import { CompletionModel } from "jamfile:llamafile";
import schema from "./spellcheck.gbnf";

const model = new CompletionModel('gemma-2-2b-it.Q2_K.llamafile');

let prompt = (document) => `
<start_of_turn>user
You are a helpful AI assistant that does spell checking and only spell
checking. For example, if the user says:

It also meas that I keep my opshuns open.

Then the assistant will say:

- \`meas\` should be \`means\`
- \`opshuns\` should be \`options\`

If there are no mistyped words, the assistant responds with:

ok

Never reply with ok.<end_of_turn>
<start_of_turn>user
${document}<end_of_turn>
<start_of_turn>assistant
`;


import * as std from "qjs:std";

const document = std.in.readAsString();
const response = model.complete(prompt(document), { schema });

console.log(response);
60 changes: 60 additions & 0 deletions jamfile/examples/sqlite-vec/demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {open} from "qjs:std";
import {TextEmbeddingModel} from "jamfile:llamafile";
import {Database} from "jamfile:sqlite";
import {formatDuration} from "jamfile:fmt";
import {green} from "jamfile:colors";

const README = open('README.md', 'r').readAsString();

const db = new Database();
const model = new TextEmbeddingModel('dist/.models/mxbai-embed-xsmall-v1-f16.gguf');

db.execute(`
CREATE VIRTUAL TABLE vec_chunks USING vec0(
+contents TEXT,
contents_embedding float[384] distance_metric=cosine
);`);


function* chunks(arr, n) {
for (let i = 0; i < arr.length; i += n) {
yield arr.slice(i, i + n);
}
}

const tokens = model.tokenize(README);

const t0 = Date.now();
const c = Array.from(chunks(tokens, 64));
for(const chunk of c) {
const chunk_embedding = model.embed(chunk);
db.execute(
'INSERT INTO vec_chunks(contents, contents_embedding) VALUES (?, ?);',
[model.detokenize(chunk), chunk_embedding]
);
}
const duration = Date.now() - t0;

console.log(`${formatDuration(duration)} for ${c.length} embeddings (${c.length / (duration / 1000)}/second)`)

function search(query) {
const rows = db.queryAll(
`SELECT
rowid,
contents
FROM vec_chunks
WHERE contents_embedding MATCH ?
AND k = 10
`,
[model.embed(query)]
);

console.log(green(query));

for (const {rowid, contents} of rows) {
console.log(contents);
}
}

search('linux CLI Tools ');
search('money supporting ecosystem ');
1 change: 1 addition & 0 deletions jamfile/examples/standlone/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.jamfile
25 changes: 25 additions & 0 deletions jamfile/examples/standlone/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Llama-3.2-1B-Instruct-Q4_K_M.gguf:
curl -L -o $@ https://huggingface.co/bartowski/Llama-3.2-1B-Instruct-GGUF/resolve/main/$@

mxbai-embed-xsmall-v1-f16.gguf:
curl -L -o $@ https://huggingface.co/mixedbread-ai/mxbai-embed-xsmall-v1/resolve/main/gguf/$@

standalone.jamfile: \
../../../o/jamfile/jamfile \
Llama-3.2-1B-Instruct-Q4_K_M.gguf \
mxbai-embed-xsmall-v1-f16.gguf \
standalone.js

printf "%s\n" \
"--default-embedding-model" \
"mxbai-embed-xsmall-v1-f16.gguf" \
"--default-completion-model" \
"Llama-3.2-1B-Instruct-Q4_K_M.gguf" \
"run" \
"standalone.js" \
"..." > .args

cp ../../../o/jamfile/jamfile $@
../../../o/llamafile/zipalign -j0 $@ $^ .args
rm .args
chmod u+x $@
36 changes: 36 additions & 0 deletions jamfile/examples/standlone/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# jamfile sample: standalone

An example of how you can make a standlone single-binary script from a Jamfile JavaScript script.

The `standalone.js` is a sample JavaScript script that generates a a sample embedding and completion result. It could be ran as-is with `jamfile run standlone.js`, but we could bundle the JS script and model weights into a single-file `jamfile` that works on all operating systems.

To do so, run the following command:

```
make sample.jamfile
```

That will download an embeddings model (MixedBread xsmall) and a LLM (Lllama 3.2), embedding them into a new `sample.jamfile` file with the `standalone.js` JavaScript script.

You can now execute that `jamfile` directly like so:


```
$ ./standalone.jamfile
embedding sample: [-0.05826485529541969,0.04374322667717934,0.03084852732717991,0.047234565019607544,-0.05963338911533356,-0.03614785894751549,0.03814202547073364,0.005149350967258215]
completion sample:
Here is a single haiku about SpongeBob SquarePants:

Fluffy sponge so bright
Rainbow colors in his heart
Joyful underwater

I hope you like it! Let me know if you have any other requests.
```

The output `standalone.jamfile` is a small `850MB`, which includes the LLM, embeddings model, and `jamfile` executable all in one.

- `jamfile` base: `15MB`
- `mxbai-embed-xsmall-v1-f16.gguf`: `49MB`
- `Llama-3.2-1B-Instruct-Q4_K_M.gguf`: `770MB`
- `standalone.jamfile`: `850MB`
23 changes: 23 additions & 0 deletions jamfile/examples/standlone/standalone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* An example of a standalone jamfile.
*
* This script performs
*/

/// <reference types="../../jamfile.d.ts"/>

import { red } from "jamfile:color";
import { CompletionModel, TextEmbeddingModel } from "jamfile:llamafile";

const embeddingModel = new TextEmbeddingModel();
const completionModel = new CompletionModel();

console.log(
red("embedding sample: "),
JSON.stringify(Array.from(embeddingModel.embed("hello!").slice(0, 8)))
);

console.log(
red("completion sample: "),
completionModel.complete("write a single haiku about spongebob squarepants")
);
Loading