NanoGPT: Pull max context and vision capability from endpoint

5eea41d315eb1e53729c3db2383f7824ed6ce105

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

3 files changed, +40 -13Ignore whitespace
public/index.html+1 -1
@@ -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>
public/scripts/openai.js+26 -6
@@ -4570,6 +4570,27 @@ function getFireworksMaxContext(model, isUnlocked) {
4570 return max_32k;4570 return max_32k;
4571}4571}
45724572
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 */
4579function 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
4573async function onModelChange() {4594async 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 }
49014922
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 }
49134931
@@ -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 }
src/endpoints/backends/chat-completions.js+13 -6
@@ -2,6 +2,7 @@ import process from 'node:process';
2import util from 'node:util';2import util from 'node:util';
3import express from 'express';3import express from 'express';
4import fetch from 'node-fetch';4import fetch from 'node-fetch';
5import urlJoin from 'url-join';
56
6import {7import {
7 AIMLAPI_HEADERS,8 AIMLAPI_HEADERS,
@@ -1197,9 +1198,10 @@ export const router = express.Router();
1197router.post('/status', async function (request, statusResponse) {1198router.post('/status', async function (request, statusResponse) {
1198 if (!request.body) return statusResponse.sendStatus(400);1199 if (!request.body) return statusResponse.sendStatus(400);
11991200
1200 let apiUrl;1201 let apiUrl = '';
1201 let apiKey;1202 let apiKey = '';
1202 let headers;1203 let headers = {};
1204 let queryParams = {};
12031205
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 }
13081311
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,