Add Mistral Nemo downloadable tokenizer

a782dcec336cabe2695b3661ee98cb945aacb55a

Cohee <18619528+Cohee1207@users.noreply.github.com>

3 files changed, +37 -1Showing whitespace changes
public/index.html+2 -1
@@ -3339,7 +3339,8 @@
3339 <option value="16">Command-R</option>3339 <option value="16">Command-R</option>
3340 <option value="4">NerdStash (NovelAI Clio)</option>3340 <option value="4">NerdStash (NovelAI Clio)</option>
3341 <option value="5">NerdStash v2 (NovelAI Kayra)</option>3341 <option value="5">NerdStash v2 (NovelAI Kayra)</option>
3342 <option value="7">Mistral</option>3342 <option value="7">Mistral V1</option>
3343 <option value="17">Mistral Nemo</option>
3343 <option value="8">Yi</option>3344 <option value="8">Yi</option>
3344 <option value="11">Claude 1/2</option>3345 <option value="11">Claude 1/2</option>
3345 <option value="6">API (WebUI / koboldcpp)</option>3346 <option value="6">API (WebUI / koboldcpp)</option>
public/scripts/tokenizers.js+11 -0
@@ -30,6 +30,7 @@ export const tokenizers = {
30 JAMBA: 14,30 JAMBA: 14,
31 QWEN2: 15,31 QWEN2: 15,
32 COMMAND_R: 16,32 COMMAND_R: 16,
33 NEMO: 17,
33 BEST_MATCH: 99,34 BEST_MATCH: 99,
34};35};
3536
@@ -43,6 +44,7 @@ export const ENCODE_TOKENIZERS = [
43 tokenizers.JAMBA,44 tokenizers.JAMBA,
44 tokenizers.QWEN2,45 tokenizers.QWEN2,
45 tokenizers.COMMAND_R,46 tokenizers.COMMAND_R,
47 tokenizers.NEMO,
46 // uncomment when NovelAI releases Kayra and Clio weights, lol48 // uncomment when NovelAI releases Kayra and Clio weights, lol
47 //tokenizers.NERD,49 //tokenizers.NERD,
48 //tokenizers.NERD2,50 //tokenizers.NERD2,
@@ -121,6 +123,11 @@ const TOKENIZER_URLS = {
121 decode: '/api/tokenizers/command-r/decode',123 decode: '/api/tokenizers/command-r/decode',
122 count: '/api/tokenizers/command-r/encode',124 count: '/api/tokenizers/command-r/encode',
123 },125 },
126 [tokenizers.NEMO]: {
127 encode: '/api/tokenizers/nemo/encode',
128 decode: '/api/tokenizers/nemo/decode',
129 count: '/api/tokenizers/nemo/encode',
130 },
124 [tokenizers.API_TEXTGENERATIONWEBUI]: {131 [tokenizers.API_TEXTGENERATIONWEBUI]: {
125 encode: '/api/tokenizers/remote/textgenerationwebui/encode',132 encode: '/api/tokenizers/remote/textgenerationwebui/encode',
126 count: '/api/tokenizers/remote/textgenerationwebui/encode',133 count: '/api/tokenizers/remote/textgenerationwebui/encode',
@@ -535,6 +542,7 @@ export function getTokenizerModel() {
535 const jambaTokenizer = 'jamba';542 const jambaTokenizer = 'jamba';
536 const qwen2Tokenizer = 'qwen2';543 const qwen2Tokenizer = 'qwen2';
537 const commandRTokenizer = 'command-r';544 const commandRTokenizer = 'command-r';
545 const nemoTokenizer = 'nemo';
538546
539 // Assuming no one would use it for different models.. right?547 // Assuming no one would use it for different models.. right?
540 if (oai_settings.chat_completion_source == chat_completion_sources.SCALE) {548 if (oai_settings.chat_completion_source == chat_completion_sources.SCALE) {
@@ -628,6 +636,9 @@ export function getTokenizerModel() {
628 }636 }
629637
630 if (oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI) {638 if (oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI) {
639 if (oai_settings.mistralai_model.includes('nemo') || oai_settings.mistralai_model.includes('pixtral')) {
640 return nemoTokenizer;
641 }
631 return mistralTokenizer;642 return mistralTokenizer;
632 }643 }
633644
src/endpoints/tokenizers.js+24 -0
@@ -221,6 +221,7 @@ const claude_tokenizer = new WebTokenizer('src/tokenizers/claude.json');
221const llama3_tokenizer = new WebTokenizer('src/tokenizers/llama3.json');221const llama3_tokenizer = new WebTokenizer('src/tokenizers/llama3.json');
222const commandTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/command-r.json', 'src/tokenizers/llama3.json');222const commandTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/command-r.json', 'src/tokenizers/llama3.json');
223const qwen2Tokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/qwen2.json', 'src/tokenizers/llama3.json');223const qwen2Tokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/qwen2.json', 'src/tokenizers/llama3.json');
224const nemoTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/nemo.json', 'src/tokenizers/llama3.json');
224225
225const sentencepieceTokenizers = [226const sentencepieceTokenizers = [
226 'llama',227 'llama',
@@ -418,6 +419,10 @@ function getTokenizerModel(requestModel) {
418 return 'command-r';419 return 'command-r';
419 }420 }
420421
422 if (requestModel.includes('nemo')) {
423 return 'nemo';
424 }
425
421 // default426 // default
422 return 'gpt-3.5-turbo';427 return 'gpt-3.5-turbo';
423}428}
@@ -645,6 +650,7 @@ router.post('/claude/encode', jsonParser, createWebTokenizerEncodingHandler(clau
645router.post('/llama3/encode', jsonParser, createWebTokenizerEncodingHandler(llama3_tokenizer));650router.post('/llama3/encode', jsonParser, createWebTokenizerEncodingHandler(llama3_tokenizer));
646router.post('/qwen2/encode', jsonParser, createWebTokenizerEncodingHandler(qwen2Tokenizer));651router.post('/qwen2/encode', jsonParser, createWebTokenizerEncodingHandler(qwen2Tokenizer));
647router.post('/command-r/encode', jsonParser, createWebTokenizerEncodingHandler(commandTokenizer));652router.post('/command-r/encode', jsonParser, createWebTokenizerEncodingHandler(commandTokenizer));
653router.post('/nemo/encode', jsonParser, createWebTokenizerEncodingHandler(nemoTokenizer));
648router.post('/llama/decode', jsonParser, createSentencepieceDecodingHandler(spp_llama));654router.post('/llama/decode', jsonParser, createSentencepieceDecodingHandler(spp_llama));
649router.post('/nerdstash/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd));655router.post('/nerdstash/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd));
650router.post('/nerdstash_v2/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd_v2));656router.post('/nerdstash_v2/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd_v2));
@@ -657,6 +663,7 @@ router.post('/claude/decode', jsonParser, createWebTokenizerDecodingHandler(clau
657router.post('/llama3/decode', jsonParser, createWebTokenizerDecodingHandler(llama3_tokenizer));663router.post('/llama3/decode', jsonParser, createWebTokenizerDecodingHandler(llama3_tokenizer));
658router.post('/qwen2/decode', jsonParser, createWebTokenizerDecodingHandler(qwen2Tokenizer));664router.post('/qwen2/decode', jsonParser, createWebTokenizerDecodingHandler(qwen2Tokenizer));
659router.post('/command-r/decode', jsonParser, createWebTokenizerDecodingHandler(commandTokenizer));665router.post('/command-r/decode', jsonParser, createWebTokenizerDecodingHandler(commandTokenizer));
666router.post('/nemo/decode', jsonParser, createWebTokenizerDecodingHandler(nemoTokenizer));
660667
661router.post('/openai/encode', jsonParser, async function (req, res) {668router.post('/openai/encode', jsonParser, async function (req, res) {
662 try {669 try {
@@ -707,6 +714,11 @@ router.post('/openai/encode', jsonParser, async function (req, res) {
707 return handler(req, res);714 return handler(req, res);
708 }715 }
709716
717 if (queryModel.includes('nemo')) {
718 const handler = createWebTokenizerEncodingHandler(nemoTokenizer);
719 return handler(req, res);
720 }
721
710 const model = getTokenizerModel(queryModel);722 const model = getTokenizerModel(queryModel);
711 const handler = createTiktokenEncodingHandler(model);723 const handler = createTiktokenEncodingHandler(model);
712 return handler(req, res);724 return handler(req, res);
@@ -765,6 +777,11 @@ router.post('/openai/decode', jsonParser, async function (req, res) {
765 return handler(req, res);777 return handler(req, res);
766 }778 }
767779
780 if (queryModel.includes('nemo')) {
781 const handler = createWebTokenizerDecodingHandler(nemoTokenizer);
782 return handler(req, res);
783 }
784
768 const model = getTokenizerModel(queryModel);785 const model = getTokenizerModel(queryModel);
769 const handler = createTiktokenDecodingHandler(model);786 const handler = createTiktokenDecodingHandler(model);
770 return handler(req, res);787 return handler(req, res);
@@ -835,6 +852,13 @@ router.post('/openai/count', jsonParser, async function (req, res) {
835 return res.send({ 'token_count': num_tokens });852 return res.send({ 'token_count': num_tokens });
836 }853 }
837854
855 if (model === 'nemo') {
856 const instance = await nemoTokenizer.get();
857 if (!instance) throw new Error('Failed to load the Nemo tokenizer');
858 num_tokens = countWebTokenizerTokens(instance, req.body);
859 return res.send({ 'token_count': num_tokens });
860 }
861
838 const tokensPerName = queryModel.includes('gpt-3.5-turbo-0301') ? -1 : 1;862 const tokensPerName = queryModel.includes('gpt-3.5-turbo-0301') ? -1 : 1;
839 const tokensPerMessage = queryModel.includes('gpt-3.5-turbo-0301') ? 4 : 3;863 const tokensPerMessage = queryModel.includes('gpt-3.5-turbo-0301') ? 4 : 3;
840 const tokensPadding = 3;864 const tokensPadding = 3;