deepseek reasoner

Closes #3322
This commit is contained in:
Cohee
2025-01-20 23:31:40 +02:00
parent d87b925488
commit d7bb92be54
5 changed files with 77 additions and 22 deletions

View File

@ -1977,12 +1977,12 @@
</span> </span>
</div> </div>
</div> </div>
<div class="range-block" data-source="makersuite"> <div class="range-block" data-source="makersuite,deepseek">
<label for="openai_show_thoughts" class="checkbox_label widthFreeExpand"> <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand">
<input id="openai_show_thoughts" type="checkbox" /> <input id="openai_show_thoughts" type="checkbox" />
<span> <span>
<span data-i18n="Show model thoughts">Show model thoughts</span> <span data-i18n="Show model thoughts">Show model thoughts</span>
<i class="opacity50p fa-solid fa-circle-info" title="Gemini 2.0 Thinking"></i> <i class="opacity50p fa-solid fa-circle-info" title="Gemini 2.0 Thinking / DeepSeek Reasoner"></i>
</span> </span>
</label> </label>
<div class="toggle-description justifyLeft marginBot5"> <div class="toggle-description justifyLeft marginBot5">
@ -3209,6 +3209,7 @@
<select id="model_deepseek_select"> <select id="model_deepseek_select">
<option value="deepseek-chat">deepseek-chat</option> <option value="deepseek-chat">deepseek-chat</option>
<option value="deepseek-coder">deepseek-coder</option> <option value="deepseek-coder">deepseek-coder</option>
<option value="deepseek-reasoner">deepseek-reasoner</option>
</select> </select>
</div> </div>
</div> </div>

View File

@ -5655,20 +5655,31 @@ function extractMessageFromData(data) {
return data; return data;
} }
switch (main_api) { function getTextContext() {
case 'kobold': switch (main_api) {
return data.results[0].text; case 'kobold':
case 'koboldhorde': return data.results[0].text;
return data.text; case 'koboldhorde':
case 'textgenerationwebui': return data.text;
return data.choices?.[0]?.text ?? data.content ?? data.response ?? ''; case 'textgenerationwebui':
case 'novel': return data.choices?.[0]?.text ?? data.content ?? data.response ?? '';
return data.output; case 'novel':
case 'openai': return data.output;
return data?.choices?.[0]?.message?.content ?? data?.choices?.[0]?.text ?? data?.text ?? data?.message?.content?.[0]?.text ?? data?.message?.tool_plan ?? ''; case 'openai':
default: return data?.choices?.[0]?.message?.content ?? data?.choices?.[0]?.text ?? data?.text ?? data?.message?.content?.[0]?.text ?? data?.message?.tool_plan ?? '';
return ''; default:
return '';
}
} }
const content = getTextContext();
if (main_api === 'openai' && oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK && oai_settings.show_thoughts) {
const thoughts = data?.choices?.[0]?.message?.reasoning_content ?? '';
return [thoughts, content].filter(x => x).join('\n\n');
}
return content;
} }
/** /**

View File

@ -2030,6 +2030,16 @@ async function sendOpenAIRequest(type, messages, signal) {
// https://api-docs.deepseek.com/api/create-chat-completion // https://api-docs.deepseek.com/api/create-chat-completion
if (isDeepSeek) { if (isDeepSeek) {
generate_data.top_p = generate_data.top_p || Number.EPSILON; generate_data.top_p = generate_data.top_p || Number.EPSILON;
if (generate_data.model.endsWith('-reasoner')) {
delete generate_data.top_p;
delete generate_data.temperature;
delete generate_data.frequency_penalty;
delete generate_data.presence_penalty;
delete generate_data.top_logprobs;
delete generate_data.logprobs;
delete generate_data.logit_bias;
}
} }
if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano) && oai_settings.seed >= 0) { if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano) && oai_settings.seed >= 0) {
@ -2085,6 +2095,7 @@ async function sendOpenAIRequest(type, messages, signal) {
let text = ''; let text = '';
const swipes = []; const swipes = [];
const toolCalls = []; const toolCalls = [];
const state = {};
while (true) { while (true) {
const { done, value } = await reader.read(); const { done, value } = await reader.read();
if (done) return; if (done) return;
@ -2095,9 +2106,9 @@ async function sendOpenAIRequest(type, messages, signal) {
if (Array.isArray(parsed?.choices) && parsed?.choices?.[0]?.index > 0) { if (Array.isArray(parsed?.choices) && parsed?.choices?.[0]?.index > 0) {
const swipeIndex = parsed.choices[0].index - 1; const swipeIndex = parsed.choices[0].index - 1;
swipes[swipeIndex] = (swipes[swipeIndex] || '') + getStreamingReply(parsed); swipes[swipeIndex] = (swipes[swipeIndex] || '') + getStreamingReply(parsed, state);
} else { } else {
text += getStreamingReply(parsed); text += getStreamingReply(parsed, state);
} }
ToolManager.parseToolCalls(toolCalls, parsed); ToolManager.parseToolCalls(toolCalls, parsed);
@ -2129,14 +2140,27 @@ async function sendOpenAIRequest(type, messages, signal) {
} }
} }
function getStreamingReply(data) { /**
* Extracts the reply from the response data from a chat completions-like source
* @param {object} data Response data from the chat completions-like source
* @param {object} state Additional state to keep track of
* @returns {string} The reply extracted from the response data
*/
function getStreamingReply(data, state) {
if (oai_settings.chat_completion_source === chat_completion_sources.CLAUDE) { if (oai_settings.chat_completion_source === chat_completion_sources.CLAUDE) {
return data?.delta?.text || ''; return data?.delta?.text || '';
} else if (oai_settings.chat_completion_source === chat_completion_sources.MAKERSUITE) { } else if (oai_settings.chat_completion_source === chat_completion_sources.MAKERSUITE) {
return data?.candidates?.[0]?.content?.parts?.filter(x => oai_settings.show_thoughts || !x.thought)?.map(x => x.text)?.filter(x => x)?.join('\n\n') || ''; return data?.candidates?.[0]?.content?.parts?.filter(x => oai_settings.show_thoughts || !x.thought)?.map(x => x.text)?.filter(x => x)?.join('\n\n') || '';
} else if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) { } else if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) {
return data?.delta?.message?.content?.text || data?.delta?.message?.tool_plan || ''; return data?.delta?.message?.content?.text || data?.delta?.message?.tool_plan || '';
} else { } else if (oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK) {
const hadThoughts = state.hadThoughts;
const thoughts = data.choices?.filter(x => oai_settings.show_thoughts || !x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content || '';
const content = data.choices?.[0]?.delta?.content || '';
state.hadThoughts = !!thoughts;
const separator = hadThoughts && !thoughts ? '\n\n' : '';
return [thoughts, separator, content].filter(x => x).join('\n\n');
} else {
return data.choices?.[0]?.delta?.content ?? data.choices?.[0]?.message?.content ?? data.choices?.[0]?.text ?? ''; return data.choices?.[0]?.delta?.content ?? data.choices?.[0]?.message?.content ?? data.choices?.[0]?.text ?? '';
} }
} }
@ -4488,7 +4512,7 @@ async function onModelChange() {
if (oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK) { if (oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK) {
if (oai_settings.max_context_unlocked) { if (oai_settings.max_context_unlocked) {
$('#openai_max_context').attr('max', unlocked_max); $('#openai_max_context').attr('max', unlocked_max);
} else if (oai_settings.deepseek_model == 'deepseek-chat') { } else if (['deepseek-reasoner', 'deepseek-chat'].includes(oai_settings.deepseek_model)) {
$('#openai_max_context').attr('max', max_64k); $('#openai_max_context').attr('max', max_64k);
} else if (oai_settings.deepseek_model == 'deepseek-coder') { } else if (oai_settings.deepseek_model == 'deepseek-coder') {
$('#openai_max_context').attr('max', max_16k); $('#openai_max_context').attr('max', max_16k);

View File

@ -220,6 +220,21 @@ async function* parseStreamData(json) {
} }
return; return;
} }
else if (typeof json.choices[0].delta.reasoning_content === 'string' && json.choices[0].delta.reasoning_content.length > 0) {
for (let j = 0; j < json.choices[0].delta.reasoning_content.length; j++) {
const str = json.choices[0].delta.reasoning_content[j];
const isLastSymbol = j === json.choices[0].delta.reasoning_content.length - 1;
const choiceClone = structuredClone(json.choices[0]);
choiceClone.delta.reasoning_content = str;
choiceClone.delta.content = isLastSymbol ? choiceClone.delta.content : '';
const choices = [choiceClone];
yield {
data: { ...json, choices },
chunk: str,
};
}
return;
}
else if (typeof json.choices[0].delta.content === 'string' && json.choices[0].delta.content.length > 0) { else if (typeof json.choices[0].delta.content === 'string' && json.choices[0].delta.content.length > 0) {
for (let j = 0; j < json.choices[0].delta.content.length; j++) { for (let j = 0; j < json.choices[0].delta.content.length; j++) {
const str = json.choices[0].delta.content[j]; const str = json.choices[0].delta.content[j];

View File

@ -61,6 +61,7 @@ const API_DEEPSEEK = 'https://api.deepseek.com/beta';
* @returns * @returns
*/ */
function postProcessPrompt(messages, type, names) { function postProcessPrompt(messages, type, names) {
const addAssistantPrefix = x => x.length && (x[x.length - 1].role !== 'assistant' || (x[x.length - 1].prefix = true)) ? x : x;
switch (type) { switch (type) {
case 'merge': case 'merge':
case 'claude': case 'claude':
@ -70,7 +71,9 @@ function postProcessPrompt(messages, type, names) {
case 'strict': case 'strict':
return mergeMessages(messages, names, true, true); return mergeMessages(messages, names, true, true);
case 'deepseek': case 'deepseek':
return (x => x.length && (x[x.length - 1].role !== 'assistant' || (x[x.length - 1].prefix = true)) ? x : x)(mergeMessages(messages, names, true, false)); return addAssistantPrefix(mergeMessages(messages, names, true, false));
case 'deepseek-reasoner':
return addAssistantPrefix(mergeMessages(messages, names, true, true));
default: default:
return messages; return messages;
} }
@ -965,7 +968,8 @@ router.post('/generate', jsonParser, function (request, response) {
bodyParams['logprobs'] = true; bodyParams['logprobs'] = true;
} }
request.body.messages = postProcessPrompt(request.body.messages, 'deepseek', getPromptNames(request)); const postProcessType = String(request.body.model).endsWith('-reasoner') ? 'deepseek-reasoner' : 'deepseek';
request.body.messages = postProcessPrompt(request.body.messages, postProcessType, getPromptNames(request));
} else { } else {
console.log('This chat completion source is not supported yet.'); console.log('This chat completion source is not supported yet.');
return response.status(400).send({ error: true }); return response.status(400).send({ error: true });