Merge pull request #2873 from SillyTavern/nemo-tokenizer Add Mistral Nemo downloadable tokenizer
Signed| @@ -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> |
| @@ -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 | }; |
| 35 | 36 | ||
| @@ -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, lol | 48 | // 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'; | ||
| 538 | 546 | ||
| 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 | } |
| 629 | 637 | ||
| 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 | } |
| 633 | 644 | ||
| @@ -221,6 +221,7 @@ const claude_tokenizer = new WebTokenizer('src/tokenizers/claude.json'); | |||
| 221 | const llama3_tokenizer = new WebTokenizer('src/tokenizers/llama3.json'); | 221 | const llama3_tokenizer = new WebTokenizer('src/tokenizers/llama3.json'); |
| 222 | const commandTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/command-r.json', 'src/tokenizers/llama3.json'); | 222 | const commandTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/command-r.json', 'src/tokenizers/llama3.json'); |
| 223 | const qwen2Tokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/qwen2.json', 'src/tokenizers/llama3.json'); | 223 | const qwen2Tokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/qwen2.json', 'src/tokenizers/llama3.json'); |
| 224 | const nemoTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/nemo.json', 'src/tokenizers/llama3.json'); | ||
| 224 | 225 | ||
| 225 | const sentencepieceTokenizers = [ | 226 | const sentencepieceTokenizers = [ |
| 226 | 'llama', | 227 | 'llama', |
| @@ -418,6 +419,10 @@ function getTokenizerModel(requestModel) { | |||
| 418 | return 'command-r'; | 419 | return 'command-r'; |
| 419 | } | 420 | } |
| 420 | 421 | ||
| 422 | if (requestModel.includes('nemo')) { | ||
| 423 | return 'nemo'; | ||
| 424 | } | ||
| 425 | |||
| 421 | // default | 426 | // 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 | |||
| 645 | router.post('/llama3/encode', jsonParser, createWebTokenizerEncodingHandler(llama3_tokenizer)); | 650 | router.post('/llama3/encode', jsonParser, createWebTokenizerEncodingHandler(llama3_tokenizer)); |
| 646 | router.post('/qwen2/encode', jsonParser, createWebTokenizerEncodingHandler(qwen2Tokenizer)); | 651 | router.post('/qwen2/encode', jsonParser, createWebTokenizerEncodingHandler(qwen2Tokenizer)); |
| 647 | router.post('/command-r/encode', jsonParser, createWebTokenizerEncodingHandler(commandTokenizer)); | 652 | router.post('/command-r/encode', jsonParser, createWebTokenizerEncodingHandler(commandTokenizer)); |
| 653 | router.post('/nemo/encode', jsonParser, createWebTokenizerEncodingHandler(nemoTokenizer)); | ||
| 648 | router.post('/llama/decode', jsonParser, createSentencepieceDecodingHandler(spp_llama)); | 654 | router.post('/llama/decode', jsonParser, createSentencepieceDecodingHandler(spp_llama)); |
| 649 | router.post('/nerdstash/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd)); | 655 | router.post('/nerdstash/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd)); |
| 650 | router.post('/nerdstash_v2/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd_v2)); | 656 | router.post('/nerdstash_v2/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd_v2)); |
| @@ -657,6 +663,7 @@ router.post('/claude/decode', jsonParser, createWebTokenizerDecodingHandler(clau | |||
| 657 | router.post('/llama3/decode', jsonParser, createWebTokenizerDecodingHandler(llama3_tokenizer)); | 663 | router.post('/llama3/decode', jsonParser, createWebTokenizerDecodingHandler(llama3_tokenizer)); |
| 658 | router.post('/qwen2/decode', jsonParser, createWebTokenizerDecodingHandler(qwen2Tokenizer)); | 664 | router.post('/qwen2/decode', jsonParser, createWebTokenizerDecodingHandler(qwen2Tokenizer)); |
| 659 | router.post('/command-r/decode', jsonParser, createWebTokenizerDecodingHandler(commandTokenizer)); | 665 | router.post('/command-r/decode', jsonParser, createWebTokenizerDecodingHandler(commandTokenizer)); |
| 666 | router.post('/nemo/decode', jsonParser, createWebTokenizerDecodingHandler(nemoTokenizer)); | ||
| 660 | 667 | ||
| 661 | router.post('/openai/encode', jsonParser, async function (req, res) { | 668 | router.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 | } |
| 709 | 716 | ||
| 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 | } |
| 767 | 779 | ||
| 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 | } |
| 837 | 854 | ||
| 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; |