DeepSeek Closes #3233
| @@ -682,7 +682,7 @@ | ||
| 682 | 682 | </span> |
| 683 | 683 | </div> |
| 684 | 684 | </div> |
| 685 | 685 | <div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek"> |
| 686 | 686 | <div class="range-block-title" data-i18n="Temperature"> |
| 687 | 687 | Temperature |
| 688 | 688 | </div> |
| @@ -695,7 +695,7 @@ | ||
| 695 | 695 | </div> |
| 696 | 696 | </div> |
| 697 | 697 | </div> |
| 698 | 698 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek"> |
| 699 | 699 | <div class="range-block-title" data-i18n="Frequency Penalty"> |
| 700 | 700 | Frequency Penalty |
| 701 | 701 | </div> |
| @@ -708,7 +708,7 @@ | ||
| 708 | 708 | </div> |
| 709 | 709 | </div> |
| 710 | 710 | </div> |
| 711 | 711 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek"> |
| 712 | 712 | <div class="range-block-title" data-i18n="Presence Penalty"> |
| 713 | 713 | Presence Penalty |
| 714 | 714 | </div> |
| @@ -734,7 +734,7 @@ | ||
| 734 | 734 | </div> |
| 735 | 735 | </div> |
| 736 | 736 | </div> |
| 737 | 737 | <div class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek"> |
| 738 | 738 | <div class="range-block-title" data-i18n="Top P"> |
| 739 | 739 | Top P |
| 740 | 740 | </div> |
| @@ -2679,6 +2679,7 @@ | ||
| 2679 | 2679 | <option value="blockentropy">Block Entropy</option> |
| 2680 | 2680 | <option value="claude">Claude</option> |
| 2681 | 2681 | <option value="cohere">Cohere</option> |
| 2682 | + <option value="deepseek">DeepSeek</option> | |
| 2682 | 2683 | <option value="groq">Groq</option> |
| 2683 | 2684 | <option value="makersuite">Google AI Studio</option> |
| 2684 | 2685 | <option value="mistralai">MistralAI</option> |
| @@ -3192,6 +3193,23 @@ | ||
| 3192 | 3193 | </select> |
| 3193 | 3194 | </div> |
| 3194 | 3195 | </div> |
| 3196 | + <div id="deepseek_form" data-source="deepseek"> | |
| 3197 | + <h4 data-i18n="DeepSeek API Key">DeepSeek API Key</h4> | |
| 3198 | + <div class="flex-container"> | |
| 3199 | + <input id="api_key_deepseek" name="api_key_deepseek" class="text_pole flex1" value="" type="text" autocomplete="off"> | |
| 3200 | + <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_nanogpt"></div> | |
| 3201 | + </div> | |
| 3202 | + <div data-for="api_key_deepseek" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | |
| 3203 | + For privacy reasons, your API key will be hidden after you reload the page. | |
| 3204 | + </div> | |
| 3205 | + <div> | |
| 3206 | + <h4 data-i18n="DeepSeek Model">DeepSeek Model</h4> | |
| 3207 | + <select id="model_deepseek_select"> | |
| 3208 | + <option value="deepseek-chat">deepseek-chat</option> | |
| 3209 | + <option value="deepseek-coder">deepseek-coder</option> | |
| 3210 | + </select> | |
| 3211 | + </div> | |
| 3212 | + </div> | |
| 3195 | 3213 | <div id="perplexity_form" data-source="perplexity"> |
| 3196 | 3214 | <h4 data-i18n="Perplexity API Key">Perplexity API Key</h4> |
| 3197 | 3215 | <div class="flex-container"> |
| @@ -3762,6 +3780,7 @@ | ||
| 3762 | 3780 | <option value="17">Mistral Nemo</option> |
| 3763 | 3781 | <option value="8">Yi</option> |
| 3764 | 3782 | <option value="11">Claude 1/2</option> |
| 3783 | + <option value="18">DeepSeek V3</option> | |
| 3765 | 3784 | <option value="6">API (WebUI / koboldcpp)</option> |
| 3766 | 3785 | </select> |
| 3767 | 3786 | </div> |
| @@ -390,6 +390,7 @@ function RA_autoconnect(PrevApi) { | ||
| 390 | 390 | || (secret_state[SECRET_KEYS.ZEROONEAI] && oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI) |
| 391 | 391 | || (secret_state[SECRET_KEYS.BLOCKENTROPY] && oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY) |
| 392 | 392 | || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) |
| 393 | + || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) | |
| 393 | 394 | || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) |
| 394 | 395 | ) { |
| 395 | 396 | $('#api_button_openai').trigger('click'); |
| @@ -183,6 +183,7 @@ export const chat_completion_sources = { | ||
| 183 | 183 | ZEROONEAI: '01ai', |
| 184 | 184 | BLOCKENTROPY: 'blockentropy', |
| 185 | 185 | NANOGPT: 'nanogpt', |
| 186 | + DEEPSEEK: 'deepseek', | |
| 186 | 187 | }; |
| 187 | 188 | |
| 188 | 189 | const character_names_behavior = { |
| @@ -261,6 +262,7 @@ const default_settings = { | ||
| 261 | 262 | nanogpt_model: 'gpt-4o-mini', |
| 262 | 263 | zerooneai_model: 'yi-large', |
| 263 | 264 | blockentropy_model: 'be-70b-base-llama3.1', |
| 265 | + deepseek_model: 'deepseek-chat', | |
| 264 | 266 | custom_model: '', |
| 265 | 267 | custom_url: '', |
| 266 | 268 | custom_include_body: '', |
| @@ -339,6 +341,7 @@ const oai_settings = { | ||
| 339 | 341 | nanogpt_model: 'gpt-4o-mini', |
| 340 | 342 | zerooneai_model: 'yi-large', |
| 341 | 343 | blockentropy_model: 'be-70b-base-llama3.1', |
| 344 | + deepseek_model: 'deepseek-chat', | |
| 342 | 345 | custom_model: '', |
| 343 | 346 | custom_url: '', |
| 344 | 347 | custom_include_body: '', |
| @@ -1523,6 +1526,8 @@ function getChatCompletionModel() { | ||
| 1523 | 1526 | return oai_settings.blockentropy_model; |
| 1524 | 1527 | case chat_completion_sources.NANOGPT: |
| 1525 | 1528 | return oai_settings.nanogpt_model; |
| 1529 | + case chat_completion_sources.DEEPSEEK: | |
| 1530 | + return oai_settings.deepseek_model; | |
| 1526 | 1531 | default: |
| 1527 | 1532 | throw new Error(`Unknown chat completion source: ${oai_settings.chat_completion_source}`); |
| 1528 | 1533 | } |
| @@ -1698,6 +1703,24 @@ function saveModelList(data) { | ||
| 1698 | 1703 | |
| 1699 | 1704 | $('#model_nanogpt_select').val(oai_settings.nanogpt_model).trigger('change'); |
| 1700 | 1705 | } |
| 1706 | + | |
| 1707 | + if (oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) { | |
| 1708 | + $('#model_deepseek_select').empty(); | |
| 1709 | + model_list.forEach((model) => { | |
| 1710 | + $('#model_deepseek_select').append( | |
| 1711 | + $('<option>', { | |
| 1712 | + value: model.id, | |
| 1713 | + text: model.id, | |
| 1714 | + })); | |
| 1715 | + }); | |
| 1716 | + | |
| 1717 | + const selectedModel = model_list.find(model => model.id === oai_settings.deepseek_model); | |
| 1718 | + if (model_list.length > 0 && (!selectedModel || !oai_settings.deepseek_model)) { | |
| 1719 | + oai_settings.deepseek_model = model_list[0].id; | |
| 1720 | + } | |
| 1721 | + | |
| 1722 | + $('#model_deepseek_select').val(oai_settings.deepseek_model).trigger('change'); | |
| 1723 | + } | |
| 1701 | 1724 | } |
| 1702 | 1725 | |
| 1703 | 1726 | function appendOpenRouterOptions(model_list, groupModels = false, sort = false) { |
| @@ -1838,6 +1861,7 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 1838 | 1861 | const isGroq = oai_settings.chat_completion_source == chat_completion_sources.GROQ; |
| 1839 | 1862 | const is01AI = oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI; |
| 1840 | 1863 | const isNano = oai_settings.chat_completion_source == chat_completion_sources.NANOGPT; |
| 1864 | + const isDeepSeek = oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK; | |
| 1841 | 1865 | const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model); |
| 1842 | 1866 | const isQuiet = type === 'quiet'; |
| 1843 | 1867 | const isImpersonate = type === 'impersonate'; |
| @@ -1902,7 +1926,7 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 1902 | 1926 | } |
| 1903 | 1927 | |
| 1904 | 1928 | // Add logprobs request (currently OpenAI only, max 5 on their side) |
| 1905 | 1929 | if (useLogprobs && (isOAI || isCustom || isDeepSeek)) { |
| 1906 | 1930 | generate_data['logprobs'] = 5; |
| 1907 | 1931 | } |
| 1908 | 1932 | |
| @@ -2000,6 +2024,11 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 2000 | 2024 | delete generate_data.stop; |
| 2001 | 2025 | } |
| 2002 | 2026 | |
| 2027 | + // https://api-docs.deepseek.com/api/create-chat-completion | |
| 2028 | + if (isDeepSeek) { | |
| 2029 | + generate_data.top_p = generate_data.top_p || Number.EPSILON; | |
| 2030 | + } | |
| 2031 | + | |
| 2003 | 2032 | if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano) && oai_settings.seed >= 0) { |
| 2004 | 2033 | generate_data['seed'] = oai_settings.seed; |
| 2005 | 2034 | } |
| @@ -2122,6 +2151,7 @@ function parseChatCompletionLogprobs(data) { | ||
| 2122 | 2151 | |
| 2123 | 2152 | switch (oai_settings.chat_completion_source) { |
| 2124 | 2153 | case chat_completion_sources.OPENAI: |
| 2154 | + case chat_completion_sources.DEEPSEEK: | |
| 2125 | 2155 | case chat_completion_sources.CUSTOM: |
| 2126 | 2156 | if (!data.choices?.length) { |
| 2127 | 2157 | return null; |
| @@ -3041,6 +3071,7 @@ function loadOpenAISettings(data, settings) { | ||
| 3041 | 3071 | oai_settings.perplexity_model = settings.perplexity_model ?? default_settings.perplexity_model; |
| 3042 | 3072 | oai_settings.groq_model = settings.groq_model ?? default_settings.groq_model; |
| 3043 | 3073 | oai_settings.nanogpt_model = settings.nanogpt_model ?? default_settings.nanogpt_model; |
| 3074 | + oai_settings.deepseek_model = settings.deepseek_model ?? default_settings.deepseek_model; | |
| 3044 | 3075 | oai_settings.blockentropy_model = settings.blockentropy_model ?? default_settings.blockentropy_model; |
| 3045 | 3076 | oai_settings.zerooneai_model = settings.zerooneai_model ?? default_settings.zerooneai_model; |
| 3046 | 3077 | oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model; |
| @@ -3122,6 +3153,8 @@ function loadOpenAISettings(data, settings) { | ||
| 3122 | 3153 | $(`#model_groq_select option[value="${oai_settings.groq_model}"`).attr('selected', true); |
| 3123 | 3154 | $('#model_nanogpt_select').val(oai_settings.nanogpt_model); |
| 3124 | 3155 | $(`#model_nanogpt_select option[value="${oai_settings.nanogpt_model}"`).attr('selected', true); |
| 3156 | + $('#model_deepseek_select').val(oai_settings.deepseek_model); | |
| 3157 | + $(`#model_deepseek_select option[value="${oai_settings.deepseek_model}"`).prop('selected', true); | |
| 3125 | 3158 | $('#model_01ai_select').val(oai_settings.zerooneai_model); |
| 3126 | 3159 | $('#model_blockentropy_select').val(oai_settings.blockentropy_model); |
| 3127 | 3160 | $('#custom_model_id').val(oai_settings.custom_model); |
| @@ -3861,6 +3894,7 @@ function onSettingsPresetChange() { | ||
| 3861 | 3894 | perplexity_model: ['#model_perplexity_select', 'perplexity_model', false], |
| 3862 | 3895 | groq_model: ['#model_groq_select', 'groq_model', false], |
| 3863 | 3896 | nanogpt_model: ['#model_nanogpt_select', 'nanogpt_model', false], |
| 3897 | + deepseek_model: ['#model_deepseek_select', 'deepseek_model', false], | |
| 3864 | 3898 | zerooneai_model: ['#model_01ai_select', 'zerooneai_model', false], |
| 3865 | 3899 | blockentropy_model: ['#model_blockentropy_select', 'blockentropy_model', false], |
| 3866 | 3900 | custom_model: ['#custom_model_id', 'custom_model', false], |
| @@ -4120,6 +4154,16 @@ async function onModelChange() { | ||
| 4120 | 4154 | oai_settings.nanogpt_model = value; |
| 4121 | 4155 | } |
| 4122 | 4156 | |
| 4157 | + if ($(this).is('#model_deepseek_select')) { | |
| 4158 | + if (!value) { | |
| 4159 | + console.debug('Null DeepSeek model selected. Ignoring.'); | |
| 4160 | + return; | |
| 4161 | + } | |
| 4162 | + | |
| 4163 | + console.log('DeepSeek model changed to', value); | |
| 4164 | + oai_settings.deepseek_model = value; | |
| 4165 | + } | |
| 4166 | + | |
| 4123 | 4167 | if (value && $(this).is('#model_01ai_select')) { |
| 4124 | 4168 | console.log('01.AI model changed to', value); |
| 4125 | 4169 | oai_settings.zerooneai_model = value; |
| @@ -4436,6 +4480,22 @@ async function onModelChange() { | ||
| 4436 | 4480 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); |
| 4437 | 4481 | } |
| 4438 | 4482 | |
| 4483 | + if (oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK) { | |
| 4484 | + if (oai_settings.max_context_unlocked) { | |
| 4485 | + $('#openai_max_context').attr('max', unlocked_max); | |
| 4486 | + } else if (oai_settings.deepseek_model == 'deepseek-chat') { | |
| 4487 | + $('#openai_max_context').attr('max', max_64k); | |
| 4488 | + } else if (oai_settings.deepseek_model == 'deepseek-coder') { | |
| 4489 | + $('#openai_max_context').attr('max', max_16k); | |
| 4490 | + } else { | |
| 4491 | + $('#openai_max_context').attr('max', max_64k); | |
| 4492 | + } | |
| 4493 | + | |
| 4494 | + oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context); | |
| 4495 | + $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); | |
| 4496 | + $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); | |
| 4497 | + } | |
| 4498 | + | |
| 4439 | 4499 | if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) { |
| 4440 | 4500 | oai_settings.pres_pen_openai = Math.min(Math.max(0, oai_settings.pres_pen_openai), 1); |
| 4441 | 4501 | $('#pres_pen_openai').attr('max', 1).attr('min', 0).val(oai_settings.pres_pen_openai).trigger('input'); |
| @@ -4653,6 +4713,19 @@ async function onConnectButtonClick(e) { | ||
| 4653 | 4713 | } |
| 4654 | 4714 | } |
| 4655 | 4715 | |
| 4716 | + if (oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) { | |
| 4717 | + const api_key_deepseek = String($('#api_key_deepseek').val()).trim(); | |
| 4718 | + | |
| 4719 | + if (api_key_deepseek.length) { | |
| 4720 | + await writeSecret(SECRET_KEYS.DEEPSEEK, api_key_deepseek); | |
| 4721 | + } | |
| 4722 | + | |
| 4723 | + if (!secret_state[SECRET_KEYS.DEEPSEEK]) { | |
| 4724 | + console.log('No secret key saved for DeepSeek'); | |
| 4725 | + return; | |
| 4726 | + } | |
| 4727 | + } | |
| 4728 | + | |
| 4656 | 4729 | if (oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI) { |
| 4657 | 4730 | const api_key_01ai = String($('#api_key_01ai').val()).trim(); |
| 4658 | 4731 | |
| @@ -4734,6 +4807,9 @@ function toggleChatCompletionForms() { | ||
| 4734 | 4807 | else if (oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY) { |
| 4735 | 4808 | $('#model_blockentropy_select').trigger('change'); |
| 4736 | 4809 | } |
| 4810 | + else if (oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) { | |
| 4811 | + $('#model_deepseek_select').trigger('change'); | |
| 4812 | + } | |
| 4737 | 4813 | $('[data-source]').each(function () { |
| 4738 | 4814 | const validSources = $(this).data('source').split(','); |
| 4739 | 4815 | $(this).toggle(validSources.includes(oai_settings.chat_completion_source)); |
| @@ -5447,6 +5523,7 @@ export function initOpenAI() { | ||
| 5447 | 5523 | $('#model_perplexity_select').on('change', onModelChange); |
| 5448 | 5524 | $('#model_groq_select').on('change', onModelChange); |
| 5449 | 5525 | $('#model_nanogpt_select').on('change', onModelChange); |
| 5526 | + $('#model_deepseek_select').on('change', onModelChange); | |
| 5450 | 5527 | $('#model_01ai_select').on('change', onModelChange); |
| 5451 | 5528 | $('#model_blockentropy_select').on('change', onModelChange); |
| 5452 | 5529 | $('#model_custom_select').on('change', onModelChange); |
| @@ -39,6 +39,7 @@ export const SECRET_KEYS = { | ||
| 39 | 39 | TAVILY: 'api_key_tavily', |
| 40 | 40 | BFL: 'api_key_bfl', |
| 41 | 41 | GENERIC: 'api_key_generic', |
| 42 | + DEEPSEEK: 'api_key_deepseek', | |
| 42 | 43 | }; |
| 43 | 44 | |
| 44 | 45 | const INPUT_MAP = { |
| @@ -73,6 +74,7 @@ const INPUT_MAP = { | ||
| 73 | 74 | [SECRET_KEYS.BLOCKENTROPY]: '#api_key_blockentropy', |
| 74 | 75 | [SECRET_KEYS.NANOGPT]: '#api_key_nanogpt', |
| 75 | 76 | [SECRET_KEYS.GENERIC]: '#api_key_generic', |
| 77 | + [SECRET_KEYS.DEEPSEEK]: '#api_key_deepseek', | |
| 76 | 78 | }; |
| 77 | 79 | |
| 78 | 80 | async function clearSecret() { |
| @@ -3815,6 +3815,7 @@ function getModelOptions(quiet) { | ||
| 3815 | 3815 | { id: 'model_nanogpt_select', api: 'openai', type: chat_completion_sources.NANOGPT }, |
| 3816 | 3816 | { id: 'model_01ai_select', api: 'openai', type: chat_completion_sources.ZEROONEAI }, |
| 3817 | 3817 | { id: 'model_blockentropy_select', api: 'openai', type: chat_completion_sources.BLOCKENTROPY }, |
| 3818 | + { id: 'model_deepseek_select', api: 'openai', type: chat_completion_sources.DEEPSEEK }, | |
| 3818 | 3819 | { id: 'model_novel_select', api: 'novel', type: null }, |
| 3819 | 3820 | { id: 'horde_model', api: 'koboldhorde', type: null }, |
| 3820 | 3821 | ]; |
| @@ -31,6 +31,7 @@ export const tokenizers = { | ||
| 31 | 31 | QWEN2: 15, |
| 32 | 32 | COMMAND_R: 16, |
| 33 | 33 | NEMO: 17, |
| 34 | + DEEPSEEK: 18, | |
| 34 | 35 | BEST_MATCH: 99, |
| 35 | 36 | MANUAL_SELECTION: 411, |
| 36 | 37 | }; |
| @@ -46,6 +47,7 @@ export const ENCODE_TOKENIZERS = [ | ||
| 46 | 47 | tokenizers.QWEN2, |
| 47 | 48 | tokenizers.COMMAND_R, |
| 48 | 49 | tokenizers.NEMO, |
| 50 | + tokenizers.DEEPSEEK, | |
| 49 | 51 | // uncomment when NovelAI releases Kayra and Clio weights, lol |
| 50 | 52 | //tokenizers.NERD, |
| 51 | 53 | //tokenizers.NERD2, |
| @@ -133,6 +135,11 @@ const TOKENIZER_URLS = { | ||
| 133 | 135 | decode: '/api/tokenizers/nemo/decode', |
| 134 | 136 | count: '/api/tokenizers/nemo/encode', |
| 135 | 137 | }, |
| 138 | + [tokenizers.DEEPSEEK]: { | |
| 139 | + encode: '/api/tokenizers/deepseek/encode', | |
| 140 | + decode: '/api/tokenizers/deepseek/decode', | |
| 141 | + count: '/api/tokenizers/deepseek/encode', | |
| 142 | + }, | |
| 136 | 143 | [tokenizers.API_TEXTGENERATIONWEBUI]: { |
| 137 | 144 | encode: '/api/tokenizers/remote/textgenerationwebui/encode', |
| 138 | 145 | count: '/api/tokenizers/remote/textgenerationwebui/encode', |
| @@ -551,12 +558,17 @@ export function getTokenizerModel() { | ||
| 551 | 558 | const qwen2Tokenizer = 'qwen2'; |
| 552 | 559 | const commandRTokenizer = 'command-r'; |
| 553 | 560 | const nemoTokenizer = 'nemo'; |
| 561 | + const deepseekTokenizer = 'deepseek'; | |
| 554 | 562 | |
| 555 | 563 | // Assuming no one would use it for different models.. right? |
| 556 | 564 | if (oai_settings.chat_completion_source == chat_completion_sources.SCALE) { |
| 557 | 565 | return gpt4Tokenizer; |
| 558 | 566 | } |
| 559 | 567 | |
| 568 | + if (oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) { | |
| 569 | + return deepseekTokenizer; | |
| 570 | + } | |
| 571 | + | |
| 560 | 572 | // Select correct tokenizer for WindowAI proxies |
| 561 | 573 | if (oai_settings.chat_completion_source == chat_completion_sources.WINDOWAI && oai_settings.windowai_model) { |
| 562 | 574 | if (oai_settings.windowai_model.includes('gpt-4')) { |
| @@ -619,6 +631,9 @@ export function getTokenizerModel() { | ||
| 619 | 631 | else if (oai_settings.openrouter_model.includes('jamba')) { |
| 620 | 632 | return jambaTokenizer; |
| 621 | 633 | } |
| 634 | + else if (oai_settings.openrouter_model.includes('deepseek')) { | |
| 635 | + return deepseekTokenizer; | |
| 636 | + } | |
| 622 | 637 | } |
| 623 | 638 | |
| 624 | 639 | if (oai_settings.chat_completion_source == chat_completion_sources.COHERE) { |
| @@ -175,6 +175,7 @@ export const CHAT_COMPLETION_SOURCES = { | ||
| 175 | 175 | ZEROONEAI: '01ai', |
| 176 | 176 | BLOCKENTROPY: 'blockentropy', |
| 177 | 177 | NANOGPT: 'nanogpt', |
| 178 | + DEEPSEEK: 'deepseek', | |
| 178 | 179 | }; |
| 179 | 180 | |
| 180 | 181 | /** |
| @@ -51,6 +51,7 @@ const API_01AI = 'https://api.01.ai/v1'; | ||
| 51 | 51 | const API_BLOCKENTROPY = 'https://api.blockentropy.ai/v1'; |
| 52 | 52 | const API_AI21 = 'https://api.ai21.com/studio/v1'; |
| 53 | 53 | const API_NANOGPT = 'https://nano-gpt.com/api/v1'; |
| 54 | +const API_DEEPSEEK = 'https://api.deepseek.com/beta'; | |
| 54 | 55 | |
| 55 | 56 | /** |
| 56 | 57 | * Applies a post-processing step to the generated messages. |
| @@ -66,6 +67,8 @@ function postProcessPrompt(messages, type, names) { | ||
| 66 | 67 | return mergeMessages(messages, names, false); |
| 67 | 68 | case 'strict': |
| 68 | 69 | return mergeMessages(messages, names, true); |
| 70 | + case 'deepseek': | |
| 71 | + return (x => x[x.length - 1].role !== 'assistant' || (x[x.length - 1].prefix = true) ? x : x)([...mergeMessages(messages, names, true)]); | |
| 69 | 72 | default: |
| 70 | 73 | return messages; |
| 71 | 74 | } |
| @@ -668,6 +671,10 @@ router.post('/status', jsonParser, async function (request, response_getstatus_o | ||
| 668 | 671 | api_url = API_NANOGPT; |
| 669 | 672 | api_key_openai = readSecret(request.user.directories, SECRET_KEYS.NANOGPT); |
| 670 | 673 | headers = {}; |
| 674 | + } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.DEEPSEEK) { | |
| 675 | + api_url = API_DEEPSEEK; | |
| 676 | + api_key_openai = readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK); | |
| 677 | + headers = {}; | |
| 671 | 678 | } else { |
| 672 | 679 | console.log('This chat completion source is not supported yet.'); |
| 673 | 680 | return response_getstatus_openai.status(400).send({ error: true }); |
| @@ -939,6 +946,18 @@ router.post('/generate', jsonParser, function (request, response) { | ||
| 939 | 946 | apiKey = readSecret(request.user.directories, SECRET_KEYS.BLOCKENTROPY); |
| 940 | 947 | headers = {}; |
| 941 | 948 | bodyParams = {}; |
| 949 | + } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.DEEPSEEK) { | |
| 950 | + apiUrl = API_DEEPSEEK; | |
| 951 | + apiKey = readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK); | |
| 952 | + headers = {}; | |
| 953 | + bodyParams = {}; | |
| 954 | + | |
| 955 | + if (request.body.logprobs > 0) { | |
| 956 | + bodyParams['top_logprobs'] = request.body.logprobs; | |
| 957 | + bodyParams['logprobs'] = true; | |
| 958 | + } | |
| 959 | + | |
| 960 | + request.body.messages = postProcessPrompt(request.body.messages, 'deepseek', getPromptNames(request)); | |
| 942 | 961 | } else { |
| 943 | 962 | console.log('This chat completion source is not supported yet.'); |
| 944 | 963 | return response.status(400).send({ error: true }); |
| @@ -51,6 +51,7 @@ export const SECRET_KEYS = { | ||
| 51 | 51 | NANOGPT: 'api_key_nanogpt', |
| 52 | 52 | BFL: 'api_key_bfl', |
| 53 | 53 | GENERIC: 'api_key_generic', |
| 54 | + DEEPSEEK: 'api_key_deepseek', | |
| 54 | 55 | }; |
| 55 | 56 | |
| 56 | 57 | // These are the keys that are safe to expose, even if allowKeysExposure is false |
| @@ -226,6 +226,7 @@ const llama3_tokenizer = new WebTokenizer('src/tokenizers/llama3.json'); | ||
| 226 | 226 | const commandTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/command-r.json', 'src/tokenizers/llama3.json'); |
| 227 | 227 | const qwen2Tokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/qwen2.json', 'src/tokenizers/llama3.json'); |
| 228 | 228 | const nemoTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/nemo.json', 'src/tokenizers/llama3.json'); |
| 229 | +const deepseekTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/deepseek.json', 'src/tokenizers/llama3.json'); | |
| 229 | 230 | |
| 230 | 231 | export const sentencepieceTokenizers = [ |
| 231 | 232 | 'llama', |
| @@ -407,6 +408,10 @@ export function getTokenizerModel(requestModel) { | ||
| 407 | 408 | return 'yi'; |
| 408 | 409 | } |
| 409 | 410 | |
| 411 | + if (requestModel.includes('deepseek')) { | |
| 412 | + return 'deepseek'; | |
| 413 | + } | |
| 414 | + | |
| 410 | 415 | if (requestModel.includes('gemma') || requestModel.includes('gemini')) { |
| 411 | 416 | return 'gemma'; |
| 412 | 417 | } |
| @@ -655,6 +660,7 @@ router.post('/llama3/encode', jsonParser, createWebTokenizerEncodingHandler(llam | ||
| 655 | 660 | router.post('/qwen2/encode', jsonParser, createWebTokenizerEncodingHandler(qwen2Tokenizer)); |
| 656 | 661 | router.post('/command-r/encode', jsonParser, createWebTokenizerEncodingHandler(commandTokenizer)); |
| 657 | 662 | router.post('/nemo/encode', jsonParser, createWebTokenizerEncodingHandler(nemoTokenizer)); |
| 663 | +router.post('/deepseek/encode', jsonParser, createWebTokenizerEncodingHandler(deepseekTokenizer)); | |
| 658 | 664 | router.post('/llama/decode', jsonParser, createSentencepieceDecodingHandler(spp_llama)); |
| 659 | 665 | router.post('/nerdstash/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd)); |
| 660 | 666 | router.post('/nerdstash_v2/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd_v2)); |
| @@ -668,6 +674,7 @@ router.post('/llama3/decode', jsonParser, createWebTokenizerDecodingHandler(llam | ||
| 668 | 674 | router.post('/qwen2/decode', jsonParser, createWebTokenizerDecodingHandler(qwen2Tokenizer)); |
| 669 | 675 | router.post('/command-r/decode', jsonParser, createWebTokenizerDecodingHandler(commandTokenizer)); |
| 670 | 676 | router.post('/nemo/decode', jsonParser, createWebTokenizerDecodingHandler(nemoTokenizer)); |
| 677 | +router.post('/deepseek/decode', jsonParser, createWebTokenizerDecodingHandler(deepseekTokenizer)); | |
| 671 | 678 | |
| 672 | 679 | router.post('/openai/encode', jsonParser, async function (req, res) { |
| 673 | 680 | try { |
| @@ -723,6 +730,11 @@ router.post('/openai/encode', jsonParser, async function (req, res) { | ||
| 723 | 730 | return handler(req, res); |
| 724 | 731 | } |
| 725 | 732 | |
| 733 | + if (queryModel.includes('deepseek')) { | |
| 734 | + const handler = createWebTokenizerEncodingHandler(deepseekTokenizer); | |
| 735 | + return handler(req, res); | |
| 736 | + } | |
| 737 | + | |
| 726 | 738 | const model = getTokenizerModel(queryModel); |
| 727 | 739 | const handler = createTiktokenEncodingHandler(model); |
| 728 | 740 | return handler(req, res); |
| @@ -786,6 +798,11 @@ router.post('/openai/decode', jsonParser, async function (req, res) { | ||
| 786 | 798 | return handler(req, res); |
| 787 | 799 | } |
| 788 | 800 | |
| 801 | + if (queryModel.includes('deepseek')) { | |
| 802 | + const handler = createWebTokenizerDecodingHandler(deepseekTokenizer); | |
| 803 | + return handler(req, res); | |
| 804 | + } | |
| 805 | + | |
| 789 | 806 | const model = getTokenizerModel(queryModel); |
| 790 | 807 | const handler = createTiktokenDecodingHandler(model); |
| 791 | 808 | return handler(req, res); |
| @@ -863,6 +880,13 @@ router.post('/openai/count', jsonParser, async function (req, res) { | ||
| 863 | 880 | return res.send({ 'token_count': num_tokens }); |
| 864 | 881 | } |
| 865 | 882 | |
| 883 | + if (model === 'deepseek') { | |
| 884 | + const instance = await deepseekTokenizer.get(); | |
| 885 | + if (!instance) throw new Error('Failed to load the DeepSeek tokenizer'); | |
| 886 | + num_tokens = countWebTokenizerTokens(instance, req.body); | |
| 887 | + return res.send({ 'token_count': num_tokens }); | |
| 888 | + } | |
| 889 | + | |
| 866 | 890 | const tokensPerName = queryModel.includes('gpt-3.5-turbo-0301') ? -1 : 1; |
| 867 | 891 | const tokensPerMessage = queryModel.includes('gpt-3.5-turbo-0301') ? 4 : 3; |
| 868 | 892 | const tokensPadding = 3; |