NanoGPT: Pull max context and vision capability from endpoint
| @@ -1999,7 +1999,7 @@ | |||
| 1999 | <strong data-i18n="enable_functions_desc_4">Not supported when Prompt Post-Processing with "no tools" is used!</strong> | 1999 | <strong data-i18n="enable_functions_desc_4">Not supported when Prompt Post-Processing with "no tools" is used!</strong> |
| 2000 | </div> | 2000 | </div> |
| 2001 | </div> | 2001 | </div> |
| 2002 | <div class="range-block" data-source="openai,aimlapi,openrouter,mistralai,makersuite,vertexai,claude,custom,xai,pollinations,moonshot,cohere,cometapi"> | 2002 | <div class="range-block" data-source="openai,aimlapi,openrouter,mistralai,makersuite,vertexai,claude,custom,xai,pollinations,moonshot,cohere,cometapi,nanogpt"> |
| 2003 | <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand"> | 2003 | <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand"> |
| 2004 | <input id="openai_image_inlining" type="checkbox" /> | 2004 | <input id="openai_image_inlining" type="checkbox" /> |
| 2005 | <span data-i18n="Send inline images">Send inline images</span> | 2005 | <span data-i18n="Send inline images">Send inline images</span> |
| @@ -4570,6 +4570,27 @@ function getFireworksMaxContext(model, isUnlocked) { | |||
| 4570 | return max_32k; | 4570 | return max_32k; |
| 4571 | } | 4571 | } |
| 4572 | 4572 | ||
| 4573 | /** | ||
| 4574 | * Get the maximum context size for the NanoGPT model | ||
| 4575 | * @param {string} model Model identifier | ||
| 4576 | * @param {boolean} isUnlocked Whether context limits are unlocked | ||
| 4577 | * @returns {number} Maximum context size in tokens | ||
| 4578 | */ | ||
| 4579 | function getNanoGptMaxContext(model, isUnlocked) { | ||
| 4580 | if (isUnlocked) { | ||
| 4581 | return unlocked_max; | ||
| 4582 | } | ||
| 4583 | |||
| 4584 | if (Array.isArray(model_list)) { | ||
| 4585 | const modelInfo = model_list.find(m => m.id === model); | ||
| 4586 | if (modelInfo?.context_length) { | ||
| 4587 | return modelInfo.context_length; | ||
| 4588 | } | ||
| 4589 | } | ||
| 4590 | |||
| 4591 | return max_128k; | ||
| 4592 | } | ||
| 4593 | |||
| 4573 | async function onModelChange() { | 4594 | async function onModelChange() { |
| 4574 | biasCache = undefined; | 4595 | biasCache = undefined; |
| 4575 | let value = String($(this).val() || ''); | 4596 | let value = String($(this).val() || ''); |
| @@ -4900,14 +4921,11 @@ async function onModelChange() { | |||
| 4900 | } | 4921 | } |
| 4901 | 4922 | ||
| 4902 | if (oai_settings.chat_completion_source === chat_completion_sources.NANOGPT) { | 4923 | if (oai_settings.chat_completion_source === chat_completion_sources.NANOGPT) { |
| 4903 | if (oai_settings.max_context_unlocked) { | 4924 | const maxContext = getNanoGptMaxContext(oai_settings.nanogpt_model, oai_settings.max_context_unlocked); |
| 4904 | $('#openai_max_context').attr('max', unlocked_max); | 4925 | $('#openai_max_context').attr('max', maxContext); |
| 4905 | } else { | ||
| 4906 | $('#openai_max_context').attr('max', max_128k); | ||
| 4907 | } | ||
| 4908 | |||
| 4909 | oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context); | 4926 | oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context); |
| 4910 | $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); | 4927 | $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); |
| 4928 | oai_settings.temp_openai = Math.min(oai_max_temp, oai_settings.temp_openai); | ||
| 4911 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); | 4929 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); |
| 4912 | } | 4930 | } |
| 4913 | 4931 | ||
| @@ -5504,6 +5522,8 @@ export function isImageInliningSupported() { | |||
| 5504 | return true; | 5522 | return true; |
| 5505 | case chat_completion_sources.MOONSHOT: | 5523 | case chat_completion_sources.MOONSHOT: |
| 5506 | return visionSupportedModels.some(model => oai_settings.moonshot_model.includes(model)); | 5524 | return visionSupportedModels.some(model => oai_settings.moonshot_model.includes(model)); |
| 5525 | case chat_completion_sources.NANOGPT: | ||
| 5526 | return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.nanogpt_model)?.capabilities?.vision); | ||
| 5507 | default: | 5527 | default: |
| 5508 | return false; | 5528 | return false; |
| 5509 | } | 5529 | } |
| @@ -2,6 +2,7 @@ import process from 'node:process'; | |||
| 2 | import util from 'node:util'; | 2 | import util from 'node:util'; |
| 3 | import express from 'express'; | 3 | import express from 'express'; |
| 4 | import fetch from 'node-fetch'; | 4 | import fetch from 'node-fetch'; |
| 5 | import urlJoin from 'url-join'; | ||
| 5 | 6 | ||
| 6 | import { | 7 | import { |
| 7 | AIMLAPI_HEADERS, | 8 | AIMLAPI_HEADERS, |
| @@ -1197,9 +1198,10 @@ export const router = express.Router(); | |||
| 1197 | router.post('/status', async function (request, statusResponse) { | 1198 | router.post('/status', async function (request, statusResponse) { |
| 1198 | if (!request.body) return statusResponse.sendStatus(400); | 1199 | if (!request.body) return statusResponse.sendStatus(400); |
| 1199 | 1200 | ||
| 1200 | let apiUrl; | 1201 | let apiUrl = ''; |
| 1201 | let apiKey; | 1202 | let apiKey = ''; |
| 1202 | let headers; | 1203 | let headers = {}; |
| 1204 | let queryParams = {}; | ||
| 1203 | 1205 | ||
| 1204 | if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENAI) { | 1206 | if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENAI) { |
| 1205 | apiUrl = new URL(request.body.reverse_proxy || API_OPENAI).toString(); | 1207 | apiUrl = new URL(request.body.reverse_proxy || API_OPENAI).toString(); |
| @@ -1227,12 +1229,13 @@ router.post('/status', async function (request, statusResponse) { | |||
| 1227 | apiUrl = API_NANOGPT; | 1229 | apiUrl = API_NANOGPT; |
| 1228 | apiKey = readSecret(request.user.directories, SECRET_KEYS.NANOGPT); | 1230 | apiKey = readSecret(request.user.directories, SECRET_KEYS.NANOGPT); |
| 1229 | headers = {}; | 1231 | headers = {}; |
| 1232 | queryParams = { detailed: true }; | ||
| 1230 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.DEEPSEEK) { | 1233 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.DEEPSEEK) { |
| 1231 | apiUrl = new URL(request.body.reverse_proxy || API_DEEPSEEK.replace('/beta', '')); | 1234 | apiUrl = new URL(request.body.reverse_proxy || API_DEEPSEEK.replace('/beta', '')).toString(); |
| 1232 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK); | 1235 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK); |
| 1233 | headers = {}; | 1236 | headers = {}; |
| 1234 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.XAI) { | 1237 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.XAI) { |
| 1235 | apiUrl = new URL(request.body.reverse_proxy || API_XAI); | 1238 | apiUrl = new URL(request.body.reverse_proxy || API_XAI).toString(); |
| 1236 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.XAI); | 1239 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.XAI); |
| 1237 | headers = {}; | 1240 | headers = {}; |
| 1238 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.AIMLAPI) { | 1241 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.AIMLAPI) { |
| @@ -1307,7 +1310,11 @@ router.post('/status', async function (request, statusResponse) { | |||
| 1307 | } | 1310 | } |
| 1308 | 1311 | ||
| 1309 | try { | 1312 | try { |
| 1310 | const response = await fetch(apiUrl + '/models', { | 1313 | const modelsUrl = new URL(urlJoin(apiUrl, '/models')); |
| 1314 | Object.keys(queryParams).forEach(key => { | ||
| 1315 | modelsUrl.searchParams.append(key, queryParams[key]); | ||
| 1316 | }); | ||
| 1317 | const response = await fetch(modelsUrl, { | ||
| 1311 | method: 'GET', | 1318 | method: 'GET', |
| 1312 | headers: { | 1319 | headers: { |
| 1313 | 'Authorization': 'Bearer ' + apiKey, | 1320 | 'Authorization': 'Bearer ' + apiKey, |