DeepSeek Closes #3233

4c7d160d41872e73e5ded5a2a600a618f8097392

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

10 files changed, +165 -5Ignore whitespace
public/index.html+23 -4
@@ -682,7 +682,7 @@
682 </span>682 </span>
683 </div>683 </div>
684 </div>684 </div>
685 <div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt">685 <div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek">
686 <div class="range-block-title" data-i18n="Temperature">686 <div class="range-block-title" data-i18n="Temperature">
687 Temperature687 Temperature
688 </div>688 </div>
@@ -695,7 +695,7 @@
695 </div>695 </div>
696 </div>696 </div>
697 </div>697 </div>
698 <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt">698 <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek">
699 <div class="range-block-title" data-i18n="Frequency Penalty">699 <div class="range-block-title" data-i18n="Frequency Penalty">
700 Frequency Penalty700 Frequency Penalty
701 </div>701 </div>
@@ -708,7 +708,7 @@
708 </div>708 </div>
709 </div>709 </div>
710 </div>710 </div>
711 <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt">711 <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek">
712 <div class="range-block-title" data-i18n="Presence Penalty">712 <div class="range-block-title" data-i18n="Presence Penalty">
713 Presence Penalty713 Presence Penalty
714 </div>714 </div>
@@ -734,7 +734,7 @@
734 </div>734 </div>
735 </div>735 </div>
736 </div>736 </div>
737 <div class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt">737 <div class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek">
738 <div class="range-block-title" data-i18n="Top P">738 <div class="range-block-title" data-i18n="Top P">
739 Top P739 Top P
740 </div>740 </div>
@@ -2679,6 +2679,7 @@
2679 <option value="blockentropy">Block Entropy</option>2679 <option value="blockentropy">Block Entropy</option>
2680 <option value="claude">Claude</option>2680 <option value="claude">Claude</option>
2681 <option value="cohere">Cohere</option>2681 <option value="cohere">Cohere</option>
2682 <option value="deepseek">DeepSeek</option>
2682 <option value="groq">Groq</option>2683 <option value="groq">Groq</option>
2683 <option value="makersuite">Google AI Studio</option>2684 <option value="makersuite">Google AI Studio</option>
2684 <option value="mistralai">MistralAI</option>2685 <option value="mistralai">MistralAI</option>
@@ -3192,6 +3193,23 @@
3192 </select>3193 </select>
3193 </div>3194 </div>
3194 </div>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 <div id="perplexity_form" data-source="perplexity">3213 <div id="perplexity_form" data-source="perplexity">
3196 <h4 data-i18n="Perplexity API Key">Perplexity API Key</h4>3214 <h4 data-i18n="Perplexity API Key">Perplexity API Key</h4>
3197 <div class="flex-container">3215 <div class="flex-container">
@@ -3762,6 +3780,7 @@
3762 <option value="17">Mistral Nemo</option>3780 <option value="17">Mistral Nemo</option>
3763 <option value="8">Yi</option>3781 <option value="8">Yi</option>
3764 <option value="11">Claude 1/2</option>3782 <option value="11">Claude 1/2</option>
3783 <option value="18">DeepSeek V3</option>
3765 <option value="6">API (WebUI / koboldcpp)</option>3784 <option value="6">API (WebUI / koboldcpp)</option>
3766 </select>3785 </select>
3767 </div>3786 </div>
public/scripts/RossAscends-mods.js+1 -0
@@ -390,6 +390,7 @@ function RA_autoconnect(PrevApi) {
390 || (secret_state[SECRET_KEYS.ZEROONEAI] && oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI)390 || (secret_state[SECRET_KEYS.ZEROONEAI] && oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI)
391 || (secret_state[SECRET_KEYS.BLOCKENTROPY] && oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY)391 || (secret_state[SECRET_KEYS.BLOCKENTROPY] && oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY)
392 || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT)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 || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM)394 || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM)
394 ) {395 ) {
395 $('#api_button_openai').trigger('click');396 $('#api_button_openai').trigger('click');
public/scripts/openai.js+78 -1
@@ -183,6 +183,7 @@ export const chat_completion_sources = {
183 ZEROONEAI: '01ai',183 ZEROONEAI: '01ai',
184 BLOCKENTROPY: 'blockentropy',184 BLOCKENTROPY: 'blockentropy',
185 NANOGPT: 'nanogpt',185 NANOGPT: 'nanogpt',
186 DEEPSEEK: 'deepseek',
186};187};
187188
188const character_names_behavior = {189const character_names_behavior = {
@@ -261,6 +262,7 @@ const default_settings = {
261 nanogpt_model: 'gpt-4o-mini',262 nanogpt_model: 'gpt-4o-mini',
262 zerooneai_model: 'yi-large',263 zerooneai_model: 'yi-large',
263 blockentropy_model: 'be-70b-base-llama3.1',264 blockentropy_model: 'be-70b-base-llama3.1',
265 deepseek_model: 'deepseek-chat',
264 custom_model: '',266 custom_model: '',
265 custom_url: '',267 custom_url: '',
266 custom_include_body: '',268 custom_include_body: '',
@@ -339,6 +341,7 @@ const oai_settings = {
339 nanogpt_model: 'gpt-4o-mini',341 nanogpt_model: 'gpt-4o-mini',
340 zerooneai_model: 'yi-large',342 zerooneai_model: 'yi-large',
341 blockentropy_model: 'be-70b-base-llama3.1',343 blockentropy_model: 'be-70b-base-llama3.1',
344 deepseek_model: 'deepseek-chat',
342 custom_model: '',345 custom_model: '',
343 custom_url: '',346 custom_url: '',
344 custom_include_body: '',347 custom_include_body: '',
@@ -1523,6 +1526,8 @@ function getChatCompletionModel() {
1523 return oai_settings.blockentropy_model;1526 return oai_settings.blockentropy_model;
1524 case chat_completion_sources.NANOGPT:1527 case chat_completion_sources.NANOGPT:
1525 return oai_settings.nanogpt_model;1528 return oai_settings.nanogpt_model;
1529 case chat_completion_sources.DEEPSEEK:
1530 return oai_settings.deepseek_model;
1526 default:1531 default:
1527 throw new Error(`Unknown chat completion source: ${oai_settings.chat_completion_source}`);1532 throw new Error(`Unknown chat completion source: ${oai_settings.chat_completion_source}`);
1528 }1533 }
@@ -1698,6 +1703,24 @@ function saveModelList(data) {
16981703
1699 $('#model_nanogpt_select').val(oai_settings.nanogpt_model).trigger('change');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}
17021725
1703function appendOpenRouterOptions(model_list, groupModels = false, sort = false) {1726function appendOpenRouterOptions(model_list, groupModels = false, sort = false) {
@@ -1838,6 +1861,7 @@ async function sendOpenAIRequest(type, messages, signal) {
1838 const isGroq = oai_settings.chat_completion_source == chat_completion_sources.GROQ;1861 const isGroq = oai_settings.chat_completion_source == chat_completion_sources.GROQ;
1839 const is01AI = oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI;1862 const is01AI = oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI;
1840 const isNano = oai_settings.chat_completion_source == chat_completion_sources.NANOGPT;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 const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model);1865 const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model);
1842 const isQuiet = type === 'quiet';1866 const isQuiet = type === 'quiet';
1843 const isImpersonate = type === 'impersonate';1867 const isImpersonate = type === 'impersonate';
@@ -1902,7 +1926,7 @@ async function sendOpenAIRequest(type, messages, signal) {
1902 }1926 }
19031927
1904 // Add logprobs request (currently OpenAI only, max 5 on their side)1928 // Add logprobs request (currently OpenAI only, max 5 on their side)
1905 if (useLogprobs && (isOAI || isCustom)) {1929 if (useLogprobs && (isOAI || isCustom || isDeepSeek)) {
1906 generate_data['logprobs'] = 5;1930 generate_data['logprobs'] = 5;
1907 }1931 }
19081932
@@ -2000,6 +2024,11 @@ async function sendOpenAIRequest(type, messages, signal) {
2000 delete generate_data.stop;2024 delete generate_data.stop;
2001 }2025 }
20022026
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 if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano) && oai_settings.seed >= 0) {2032 if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano) && oai_settings.seed >= 0) {
2004 generate_data['seed'] = oai_settings.seed;2033 generate_data['seed'] = oai_settings.seed;
2005 }2034 }
@@ -2122,6 +2151,7 @@ function parseChatCompletionLogprobs(data) {
21222151
2123 switch (oai_settings.chat_completion_source) {2152 switch (oai_settings.chat_completion_source) {
2124 case chat_completion_sources.OPENAI:2153 case chat_completion_sources.OPENAI:
2154 case chat_completion_sources.DEEPSEEK:
2125 case chat_completion_sources.CUSTOM:2155 case chat_completion_sources.CUSTOM:
2126 if (!data.choices?.length) {2156 if (!data.choices?.length) {
2127 return null;2157 return null;
@@ -3041,6 +3071,7 @@ function loadOpenAISettings(data, settings) {
3041 oai_settings.perplexity_model = settings.perplexity_model ?? default_settings.perplexity_model;3071 oai_settings.perplexity_model = settings.perplexity_model ?? default_settings.perplexity_model;
3042 oai_settings.groq_model = settings.groq_model ?? default_settings.groq_model;3072 oai_settings.groq_model = settings.groq_model ?? default_settings.groq_model;
3043 oai_settings.nanogpt_model = settings.nanogpt_model ?? default_settings.nanogpt_model;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 oai_settings.blockentropy_model = settings.blockentropy_model ?? default_settings.blockentropy_model;3075 oai_settings.blockentropy_model = settings.blockentropy_model ?? default_settings.blockentropy_model;
3045 oai_settings.zerooneai_model = settings.zerooneai_model ?? default_settings.zerooneai_model;3076 oai_settings.zerooneai_model = settings.zerooneai_model ?? default_settings.zerooneai_model;
3046 oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model;3077 oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model;
@@ -3122,6 +3153,8 @@ function loadOpenAISettings(data, settings) {
3122 $(`#model_groq_select option[value="${oai_settings.groq_model}"`).attr('selected', true);3153 $(`#model_groq_select option[value="${oai_settings.groq_model}"`).attr('selected', true);
3123 $('#model_nanogpt_select').val(oai_settings.nanogpt_model);3154 $('#model_nanogpt_select').val(oai_settings.nanogpt_model);
3124 $(`#model_nanogpt_select option[value="${oai_settings.nanogpt_model}"`).attr('selected', true);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 $('#model_01ai_select').val(oai_settings.zerooneai_model);3158 $('#model_01ai_select').val(oai_settings.zerooneai_model);
3126 $('#model_blockentropy_select').val(oai_settings.blockentropy_model);3159 $('#model_blockentropy_select').val(oai_settings.blockentropy_model);
3127 $('#custom_model_id').val(oai_settings.custom_model);3160 $('#custom_model_id').val(oai_settings.custom_model);
@@ -3861,6 +3894,7 @@ function onSettingsPresetChange() {
3861 perplexity_model: ['#model_perplexity_select', 'perplexity_model', false],3894 perplexity_model: ['#model_perplexity_select', 'perplexity_model', false],
3862 groq_model: ['#model_groq_select', 'groq_model', false],3895 groq_model: ['#model_groq_select', 'groq_model', false],
3863 nanogpt_model: ['#model_nanogpt_select', 'nanogpt_model', false],3896 nanogpt_model: ['#model_nanogpt_select', 'nanogpt_model', false],
3897 deepseek_model: ['#model_deepseek_select', 'deepseek_model', false],
3864 zerooneai_model: ['#model_01ai_select', 'zerooneai_model', false],3898 zerooneai_model: ['#model_01ai_select', 'zerooneai_model', false],
3865 blockentropy_model: ['#model_blockentropy_select', 'blockentropy_model', false],3899 blockentropy_model: ['#model_blockentropy_select', 'blockentropy_model', false],
3866 custom_model: ['#custom_model_id', 'custom_model', false],3900 custom_model: ['#custom_model_id', 'custom_model', false],
@@ -4120,6 +4154,16 @@ async function onModelChange() {
4120 oai_settings.nanogpt_model = value;4154 oai_settings.nanogpt_model = value;
4121 }4155 }
41224156
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 if (value && $(this).is('#model_01ai_select')) {4167 if (value && $(this).is('#model_01ai_select')) {
4124 console.log('01.AI model changed to', value);4168 console.log('01.AI model changed to', value);
4125 oai_settings.zerooneai_model = value;4169 oai_settings.zerooneai_model = value;
@@ -4436,6 +4480,22 @@ async function onModelChange() {
4436 $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');4480 $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');
4437 }4481 }
44384482
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 if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) {4499 if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) {
4440 oai_settings.pres_pen_openai = Math.min(Math.max(0, oai_settings.pres_pen_openai), 1);4500 oai_settings.pres_pen_openai = Math.min(Math.max(0, oai_settings.pres_pen_openai), 1);
4441 $('#pres_pen_openai').attr('max', 1).attr('min', 0).val(oai_settings.pres_pen_openai).trigger('input');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 }
46554715
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 if (oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI) {4729 if (oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI) {
4657 const api_key_01ai = String($('#api_key_01ai').val()).trim();4730 const api_key_01ai = String($('#api_key_01ai').val()).trim();
46584731
@@ -4734,6 +4807,9 @@ function toggleChatCompletionForms() {
4734 else if (oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY) {4807 else if (oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY) {
4735 $('#model_blockentropy_select').trigger('change');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 $('[data-source]').each(function () {4813 $('[data-source]').each(function () {
4738 const validSources = $(this).data('source').split(',');4814 const validSources = $(this).data('source').split(',');
4739 $(this).toggle(validSources.includes(oai_settings.chat_completion_source));4815 $(this).toggle(validSources.includes(oai_settings.chat_completion_source));
@@ -5447,6 +5523,7 @@ export function initOpenAI() {
5447 $('#model_perplexity_select').on('change', onModelChange);5523 $('#model_perplexity_select').on('change', onModelChange);
5448 $('#model_groq_select').on('change', onModelChange);5524 $('#model_groq_select').on('change', onModelChange);
5449 $('#model_nanogpt_select').on('change', onModelChange);5525 $('#model_nanogpt_select').on('change', onModelChange);
5526 $('#model_deepseek_select').on('change', onModelChange);
5450 $('#model_01ai_select').on('change', onModelChange);5527 $('#model_01ai_select').on('change', onModelChange);
5451 $('#model_blockentropy_select').on('change', onModelChange);5528 $('#model_blockentropy_select').on('change', onModelChange);
5452 $('#model_custom_select').on('change', onModelChange);5529 $('#model_custom_select').on('change', onModelChange);
public/scripts/secrets.js+2 -0
@@ -39,6 +39,7 @@ export const SECRET_KEYS = {
39 TAVILY: 'api_key_tavily',39 TAVILY: 'api_key_tavily',
40 BFL: 'api_key_bfl',40 BFL: 'api_key_bfl',
41 GENERIC: 'api_key_generic',41 GENERIC: 'api_key_generic',
42 DEEPSEEK: 'api_key_deepseek',
42};43};
4344
44const INPUT_MAP = {45const INPUT_MAP = {
@@ -73,6 +74,7 @@ const INPUT_MAP = {
73 [SECRET_KEYS.BLOCKENTROPY]: '#api_key_blockentropy',74 [SECRET_KEYS.BLOCKENTROPY]: '#api_key_blockentropy',
74 [SECRET_KEYS.NANOGPT]: '#api_key_nanogpt',75 [SECRET_KEYS.NANOGPT]: '#api_key_nanogpt',
75 [SECRET_KEYS.GENERIC]: '#api_key_generic',76 [SECRET_KEYS.GENERIC]: '#api_key_generic',
77 [SECRET_KEYS.DEEPSEEK]: '#api_key_deepseek',
76};78};
7779
78async function clearSecret() {80async function clearSecret() {
public/scripts/slash-commands.js+1 -0
@@ -3815,6 +3815,7 @@ function getModelOptions(quiet) {
3815 { id: 'model_nanogpt_select', api: 'openai', type: chat_completion_sources.NANOGPT },3815 { id: 'model_nanogpt_select', api: 'openai', type: chat_completion_sources.NANOGPT },
3816 { id: 'model_01ai_select', api: 'openai', type: chat_completion_sources.ZEROONEAI },3816 { id: 'model_01ai_select', api: 'openai', type: chat_completion_sources.ZEROONEAI },
3817 { id: 'model_blockentropy_select', api: 'openai', type: chat_completion_sources.BLOCKENTROPY },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 { id: 'model_novel_select', api: 'novel', type: null },3819 { id: 'model_novel_select', api: 'novel', type: null },
3819 { id: 'horde_model', api: 'koboldhorde', type: null },3820 { id: 'horde_model', api: 'koboldhorde', type: null },
3820 ];3821 ];
public/scripts/tokenizers.js+15 -0
@@ -31,6 +31,7 @@ export const tokenizers = {
31 QWEN2: 15,31 QWEN2: 15,
32 COMMAND_R: 16,32 COMMAND_R: 16,
33 NEMO: 17,33 NEMO: 17,
34 DEEPSEEK: 18,
34 BEST_MATCH: 99,35 BEST_MATCH: 99,
35 MANUAL_SELECTION: 411,36 MANUAL_SELECTION: 411,
36};37};
@@ -46,6 +47,7 @@ export const ENCODE_TOKENIZERS = [
46 tokenizers.QWEN2,47 tokenizers.QWEN2,
47 tokenizers.COMMAND_R,48 tokenizers.COMMAND_R,
48 tokenizers.NEMO,49 tokenizers.NEMO,
50 tokenizers.DEEPSEEK,
49 // uncomment when NovelAI releases Kayra and Clio weights, lol51 // uncomment when NovelAI releases Kayra and Clio weights, lol
50 //tokenizers.NERD,52 //tokenizers.NERD,
51 //tokenizers.NERD2,53 //tokenizers.NERD2,
@@ -133,6 +135,11 @@ const TOKENIZER_URLS = {
133 decode: '/api/tokenizers/nemo/decode',135 decode: '/api/tokenizers/nemo/decode',
134 count: '/api/tokenizers/nemo/encode',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 [tokenizers.API_TEXTGENERATIONWEBUI]: {143 [tokenizers.API_TEXTGENERATIONWEBUI]: {
137 encode: '/api/tokenizers/remote/textgenerationwebui/encode',144 encode: '/api/tokenizers/remote/textgenerationwebui/encode',
138 count: '/api/tokenizers/remote/textgenerationwebui/encode',145 count: '/api/tokenizers/remote/textgenerationwebui/encode',
@@ -551,12 +558,17 @@ export function getTokenizerModel() {
551 const qwen2Tokenizer = 'qwen2';558 const qwen2Tokenizer = 'qwen2';
552 const commandRTokenizer = 'command-r';559 const commandRTokenizer = 'command-r';
553 const nemoTokenizer = 'nemo';560 const nemoTokenizer = 'nemo';
561 const deepseekTokenizer = 'deepseek';
554562
555 // Assuming no one would use it for different models.. right?563 // Assuming no one would use it for different models.. right?
556 if (oai_settings.chat_completion_source == chat_completion_sources.SCALE) {564 if (oai_settings.chat_completion_source == chat_completion_sources.SCALE) {
557 return gpt4Tokenizer;565 return gpt4Tokenizer;
558 }566 }
559567
568 if (oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) {
569 return deepseekTokenizer;
570 }
571
560 // Select correct tokenizer for WindowAI proxies572 // Select correct tokenizer for WindowAI proxies
561 if (oai_settings.chat_completion_source == chat_completion_sources.WINDOWAI && oai_settings.windowai_model) {573 if (oai_settings.chat_completion_source == chat_completion_sources.WINDOWAI && oai_settings.windowai_model) {
562 if (oai_settings.windowai_model.includes('gpt-4')) {574 if (oai_settings.windowai_model.includes('gpt-4')) {
@@ -619,6 +631,9 @@ export function getTokenizerModel() {
619 else if (oai_settings.openrouter_model.includes('jamba')) {631 else if (oai_settings.openrouter_model.includes('jamba')) {
620 return jambaTokenizer;632 return jambaTokenizer;
621 }633 }
634 else if (oai_settings.openrouter_model.includes('deepseek')) {
635 return deepseekTokenizer;
636 }
622 }637 }
623638
624 if (oai_settings.chat_completion_source == chat_completion_sources.COHERE) {639 if (oai_settings.chat_completion_source == chat_completion_sources.COHERE) {
src/constants.js+1 -0
@@ -175,6 +175,7 @@ export const CHAT_COMPLETION_SOURCES = {
175 ZEROONEAI: '01ai',175 ZEROONEAI: '01ai',
176 BLOCKENTROPY: 'blockentropy',176 BLOCKENTROPY: 'blockentropy',
177 NANOGPT: 'nanogpt',177 NANOGPT: 'nanogpt',
178 DEEPSEEK: 'deepseek',
178};179};
179180
180/**181/**
src/endpoints/backends/chat-completions.js+19 -0
@@ -51,6 +51,7 @@ const API_01AI = 'https://api.01.ai/v1';
51const API_BLOCKENTROPY = 'https://api.blockentropy.ai/v1';51const API_BLOCKENTROPY = 'https://api.blockentropy.ai/v1';
52const API_AI21 = 'https://api.ai21.com/studio/v1';52const API_AI21 = 'https://api.ai21.com/studio/v1';
53const API_NANOGPT = 'https://nano-gpt.com/api/v1';53const API_NANOGPT = 'https://nano-gpt.com/api/v1';
54const API_DEEPSEEK = 'https://api.deepseek.com/beta';
5455
55/**56/**
56 * Applies a post-processing step to the generated messages.57 * Applies a post-processing step to the generated messages.
@@ -66,6 +67,8 @@ function postProcessPrompt(messages, type, names) {
66 return mergeMessages(messages, names, false);67 return mergeMessages(messages, names, false);
67 case 'strict':68 case 'strict':
68 return mergeMessages(messages, names, true);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 default:72 default:
70 return messages;73 return messages;
71 }74 }
@@ -668,6 +671,10 @@ router.post('/status', jsonParser, async function (request, response_getstatus_o
668 api_url = API_NANOGPT;671 api_url = API_NANOGPT;
669 api_key_openai = readSecret(request.user.directories, SECRET_KEYS.NANOGPT);672 api_key_openai = readSecret(request.user.directories, SECRET_KEYS.NANOGPT);
670 headers = {};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 } else {678 } else {
672 console.log('This chat completion source is not supported yet.');679 console.log('This chat completion source is not supported yet.');
673 return response_getstatus_openai.status(400).send({ error: true });680 return response_getstatus_openai.status(400).send({ error: true });
@@ -939,6 +946,18 @@ router.post('/generate', jsonParser, function (request, response) {
939 apiKey = readSecret(request.user.directories, SECRET_KEYS.BLOCKENTROPY);946 apiKey = readSecret(request.user.directories, SECRET_KEYS.BLOCKENTROPY);
940 headers = {};947 headers = {};
941 bodyParams = {};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 } else {961 } else {
943 console.log('This chat completion source is not supported yet.');962 console.log('This chat completion source is not supported yet.');
944 return response.status(400).send({ error: true });963 return response.status(400).send({ error: true });
src/endpoints/secrets.js+1 -0
@@ -51,6 +51,7 @@ export const SECRET_KEYS = {
51 NANOGPT: 'api_key_nanogpt',51 NANOGPT: 'api_key_nanogpt',
52 BFL: 'api_key_bfl',52 BFL: 'api_key_bfl',
53 GENERIC: 'api_key_generic',53 GENERIC: 'api_key_generic',
54 DEEPSEEK: 'api_key_deepseek',
54};55};
5556
56// These are the keys that are safe to expose, even if allowKeysExposure is false57// These are the keys that are safe to expose, even if allowKeysExposure is false
src/endpoints/tokenizers.js+24 -0
@@ -226,6 +226,7 @@ const llama3_tokenizer = new WebTokenizer('src/tokenizers/llama3.json');
226const commandTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/command-r.json', 'src/tokenizers/llama3.json');226const commandTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/command-r.json', 'src/tokenizers/llama3.json');
227const qwen2Tokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/qwen2.json', 'src/tokenizers/llama3.json');227const qwen2Tokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/qwen2.json', 'src/tokenizers/llama3.json');
228const nemoTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/nemo.json', 'src/tokenizers/llama3.json');228const nemoTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/nemo.json', 'src/tokenizers/llama3.json');
229const deepseekTokenizer = new WebTokenizer('https://github.com/SillyTavern/SillyTavern-Tokenizers/raw/main/deepseek.json', 'src/tokenizers/llama3.json');
229230
230export const sentencepieceTokenizers = [231export const sentencepieceTokenizers = [
231 'llama',232 'llama',
@@ -407,6 +408,10 @@ export function getTokenizerModel(requestModel) {
407 return 'yi';408 return 'yi';
408 }409 }
409410
411 if (requestModel.includes('deepseek')) {
412 return 'deepseek';
413 }
414
410 if (requestModel.includes('gemma') || requestModel.includes('gemini')) {415 if (requestModel.includes('gemma') || requestModel.includes('gemini')) {
411 return 'gemma';416 return 'gemma';
412 }417 }
@@ -655,6 +660,7 @@ router.post('/llama3/encode', jsonParser, createWebTokenizerEncodingHandler(llam
655router.post('/qwen2/encode', jsonParser, createWebTokenizerEncodingHandler(qwen2Tokenizer));660router.post('/qwen2/encode', jsonParser, createWebTokenizerEncodingHandler(qwen2Tokenizer));
656router.post('/command-r/encode', jsonParser, createWebTokenizerEncodingHandler(commandTokenizer));661router.post('/command-r/encode', jsonParser, createWebTokenizerEncodingHandler(commandTokenizer));
657router.post('/nemo/encode', jsonParser, createWebTokenizerEncodingHandler(nemoTokenizer));662router.post('/nemo/encode', jsonParser, createWebTokenizerEncodingHandler(nemoTokenizer));
663router.post('/deepseek/encode', jsonParser, createWebTokenizerEncodingHandler(deepseekTokenizer));
658router.post('/llama/decode', jsonParser, createSentencepieceDecodingHandler(spp_llama));664router.post('/llama/decode', jsonParser, createSentencepieceDecodingHandler(spp_llama));
659router.post('/nerdstash/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd));665router.post('/nerdstash/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd));
660router.post('/nerdstash_v2/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd_v2));666router.post('/nerdstash_v2/decode', jsonParser, createSentencepieceDecodingHandler(spp_nerd_v2));
@@ -668,6 +674,7 @@ router.post('/llama3/decode', jsonParser, createWebTokenizerDecodingHandler(llam
668router.post('/qwen2/decode', jsonParser, createWebTokenizerDecodingHandler(qwen2Tokenizer));674router.post('/qwen2/decode', jsonParser, createWebTokenizerDecodingHandler(qwen2Tokenizer));
669router.post('/command-r/decode', jsonParser, createWebTokenizerDecodingHandler(commandTokenizer));675router.post('/command-r/decode', jsonParser, createWebTokenizerDecodingHandler(commandTokenizer));
670router.post('/nemo/decode', jsonParser, createWebTokenizerDecodingHandler(nemoTokenizer));676router.post('/nemo/decode', jsonParser, createWebTokenizerDecodingHandler(nemoTokenizer));
677router.post('/deepseek/decode', jsonParser, createWebTokenizerDecodingHandler(deepseekTokenizer));
671678
672router.post('/openai/encode', jsonParser, async function (req, res) {679router.post('/openai/encode', jsonParser, async function (req, res) {
673 try {680 try {
@@ -723,6 +730,11 @@ router.post('/openai/encode', jsonParser, async function (req, res) {
723 return handler(req, res);730 return handler(req, res);
724 }731 }
725732
733 if (queryModel.includes('deepseek')) {
734 const handler = createWebTokenizerEncodingHandler(deepseekTokenizer);
735 return handler(req, res);
736 }
737
726 const model = getTokenizerModel(queryModel);738 const model = getTokenizerModel(queryModel);
727 const handler = createTiktokenEncodingHandler(model);739 const handler = createTiktokenEncodingHandler(model);
728 return handler(req, res);740 return handler(req, res);
@@ -786,6 +798,11 @@ router.post('/openai/decode', jsonParser, async function (req, res) {
786 return handler(req, res);798 return handler(req, res);
787 }799 }
788800
801 if (queryModel.includes('deepseek')) {
802 const handler = createWebTokenizerDecodingHandler(deepseekTokenizer);
803 return handler(req, res);
804 }
805
789 const model = getTokenizerModel(queryModel);806 const model = getTokenizerModel(queryModel);
790 const handler = createTiktokenDecodingHandler(model);807 const handler = createTiktokenDecodingHandler(model);
791 return handler(req, res);808 return handler(req, res);
@@ -863,6 +880,13 @@ router.post('/openai/count', jsonParser, async function (req, res) {
863 return res.send({ 'token_count': num_tokens });880 return res.send({ 'token_count': num_tokens });
864 }881 }
865882
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 const tokensPerName = queryModel.includes('gpt-3.5-turbo-0301') ? -1 : 1;890 const tokensPerName = queryModel.includes('gpt-3.5-turbo-0301') ? -1 : 1;
867 const tokensPerMessage = queryModel.includes('gpt-3.5-turbo-0301') ? 4 : 3;891 const tokensPerMessage = queryModel.includes('gpt-3.5-turbo-0301') ? 4 : 3;
868 const tokensPadding = 3;892 const tokensPadding = 3;