Download docs/tokenizer.js from GeorgeCodesSometimes/sprout-instruct: direct link, hf CLI and curl.
- Browser
- Download file 2.96 kB
-
https://huggingface.co/GeorgeCodesSometimes/sprout-instruct/resolve/main/docs/tokenizer.js
- Command line
-
hf download hf://GeorgeCodesSometimes/sprout-instruct/docs/tokenizer.js
-
curl -L -o tokenizer.js https://huggingface.co/GeorgeCodesSometimes/sprout-instruct/resolve/main/docs/tokenizer.js
2.96 kB
| // The same byte BPE and Unicode pre-splitting as tokenizer.py. | |
| const pattern = /'(?:[sSdDmMtT]|[lL][lL]|[vV][eE]|[rR][eE])|[^\r\n\p{L}\p{N}]?\p{L}+|\p{N}{1,3}| ?[^\p{White_Space}\p{L}\p{N}]+[\r\n]*|\p{White_Space}*[\r\n]|\p{White_Space}+(?![^\p{White_Space}])|\p{White_Space}+/gu; | |
| const specials = ["<|endoftext|>", "<|user|>", "<|assistant|>", "<|end|>"]; | |
| export function tokenizer(text) { | |
| const pairs = text.trim().split(/\r?\n/).map(line => line.split(" ").map(Number)); | |
| const ranks = new Map(); | |
| const vocab = Array.from({ length: 256 }, (_, i) => new Uint8Array([i])); | |
| for (const [a, b] of pairs) { | |
| ranks.set(`${a},${b}`, vocab.length); | |
| vocab.push(new Uint8Array([...vocab[a], ...vocab[b]])); | |
| } | |
| const special = Object.fromEntries(specials.map((s, i) => [s, vocab.length + i])); | |
| const encoder = new TextEncoder(); | |
| const split = /(<\|endoftext\|>|<\|user\|>|<\|assistant\|>|<\|end\|>)/g; | |
| function encode(text) { | |
| const result = []; | |
| for (const part of text.split(split)) { | |
| if (part in special) { | |
| result.push(special[part]); | |
| continue; | |
| } | |
| for (const match of part.matchAll(pattern)) { | |
| let ids = Array.from(encoder.encode(match[0])); | |
| while (ids.length > 1) { | |
| let rank = Infinity; | |
| let a, b; | |
| for (let i = 0; i < ids.length - 1; i++) { | |
| const value = ranks.get(`${ids[i]},${ids[i + 1]}`) ?? Infinity; | |
| if (value < rank) { rank = value; a = ids[i]; b = ids[i + 1]; } | |
| } | |
| if (!Number.isFinite(rank)) break; | |
| const merged = []; | |
| for (let i = 0; i < ids.length; i++) { | |
| if (ids[i] === a && ids[i + 1] === b) { merged.push(rank); i++; } | |
| else merged.push(ids[i]); | |
| } | |
| ids = merged; | |
| } | |
| result.push(...ids); | |
| } | |
| } | |
| return result; | |
| } | |
| return { encode, vocab, special }; | |
| } | |
| export function storyPrompt(fields) { | |
| const names = ["Summary", "Words", "Random sentence", "Features"]; | |
| if (Object.keys(fields).some(key => !names.includes(key)) || | |
| Object.values(fields).some(value => typeof value !== "string")) { | |
| throw new Error("Use the supported story fields with text values."); | |
| } | |
| if (Object.values(fields).reduce((n, value) => n + value.length, 0) > 4096) { | |
| throw new Error("Your instructions are too long. Try a shorter story idea."); | |
| } | |
| if (Object.values(fields).some(value => specials.some(s => value.includes(s)))) { | |
| throw new Error("Remove reserved tokens such as <|user|> from your instructions."); | |
| } | |
| const clean = names.map(key => [key, (fields[key] ?? "").replace(/[\p{White_Space}\u001c-\u001f]+/gu, " ").replace(/^ | $/g, "")]); | |
| const lines = clean.filter(([, value]) => value).map(([key, value]) => `${key}: ${value}`); | |
| if (!lines.length) throw new Error("Enter a story idea or a word to include."); | |
| return `<|user|>\nWrite a short story.\n${lines.join("\n")}<|end|>\n<|assistant|>\n`; | |
| } | |