Add NanoGPT embeddings support for Vector Storage (#5150)
* Initial plan * Add NanoGPT embeddings support for Vector Storage Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com> * Fix models loading --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Cohee1207 <18619528+Cohee1207@users.noreply.github.com>
This commit is contained in:
@@ -71,6 +71,7 @@ const settings = {
|
||||
webllm_model: '',
|
||||
google_model: 'text-embedding-005',
|
||||
chutes_model: 'chutes-qwen-qwen3-embedding-8b',
|
||||
nanogpt_model: 'text-embedding-3-small',
|
||||
summarize: false,
|
||||
summarize_sent: false,
|
||||
summary_source: 'main',
|
||||
@@ -834,6 +835,9 @@ function getVectorsRequestBody(args = {}) {
|
||||
case 'chutes':
|
||||
body.model = extension_settings.vectors.chutes_model;
|
||||
break;
|
||||
case 'nanogpt':
|
||||
body.model = extension_settings.vectors.nanogpt_model;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -919,6 +923,7 @@ function throwIfSourceInvalid() {
|
||||
if (settings.source === 'openai' && !secret_state[SECRET_KEYS.OPENAI] ||
|
||||
settings.source === 'electronhub' && !secret_state[SECRET_KEYS.ELECTRONHUB] ||
|
||||
settings.source === 'chutes' && !secret_state[SECRET_KEYS.CHUTES] ||
|
||||
settings.source === 'nanogpt' && !secret_state[SECRET_KEYS.NANOGPT] ||
|
||||
settings.source === 'openrouter' && !secret_state[SECRET_KEYS.OPENROUTER] ||
|
||||
settings.source === 'palm' && !secret_state[SECRET_KEYS.MAKERSUITE] ||
|
||||
settings.source === 'vertexai' && !secret_state[SECRET_KEYS.VERTEXAI] && !secret_state[SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT] ||
|
||||
@@ -1134,6 +1139,7 @@ function toggleSettings() {
|
||||
$('#openai_vectorsModel').toggle(settings.source === 'openai');
|
||||
$('#electronhub_vectorsModel').toggle(settings.source === 'electronhub');
|
||||
$('#chutes_vectorsModel').toggle(settings.source === 'chutes');
|
||||
$('#nanogpt_vectorsModel').toggle(settings.source === 'nanogpt');
|
||||
$('#openrouter_vectorsModel').toggle(settings.source === 'openrouter');
|
||||
$('#cohere_vectorsModel').toggle(settings.source === 'cohere');
|
||||
$('#ollama_vectorsModel').toggle(settings.source === 'ollama');
|
||||
@@ -1157,6 +1163,9 @@ function toggleSettings() {
|
||||
case 'chutes':
|
||||
loadChutesModels();
|
||||
break;
|
||||
case 'nanogpt':
|
||||
loadNanoGPTModels();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1194,6 +1203,40 @@ function populateChutesModelSelect(models) {
|
||||
$('#vectors_chutes_model').val(settings.chutes_model);
|
||||
}
|
||||
|
||||
async function loadNanoGPTModels() {
|
||||
try {
|
||||
const response = await fetch('/api/openai/nanogpt/models/embedding', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders({ omitContentType: true }),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
/** @type {Array<any>} */
|
||||
const data = await response.json();
|
||||
const models = Array.isArray(data) ? data : [];
|
||||
populateNanoGPTModelSelect(models);
|
||||
} catch (err) {
|
||||
console.warn('NanoGPT models fetch failed', err);
|
||||
populateNanoGPTModelSelect([]);
|
||||
}
|
||||
}
|
||||
|
||||
function populateNanoGPTModelSelect(models) {
|
||||
const select = $('#vectors_nanogpt_model');
|
||||
select.empty();
|
||||
for (const m of models) {
|
||||
const option = document.createElement('option');
|
||||
option.value = m.id;
|
||||
option.text = m.name || m.id;
|
||||
select.append(option);
|
||||
}
|
||||
if (!settings.nanogpt_model && models.length) {
|
||||
settings.nanogpt_model = models[0].id;
|
||||
}
|
||||
$('#vectors_nanogpt_model').val(settings.nanogpt_model);
|
||||
}
|
||||
|
||||
async function loadElectronHubModels() {
|
||||
try {
|
||||
const response = await fetch('/api/openai/electronhub/models', {
|
||||
@@ -1679,6 +1722,11 @@ jQuery(async () => {
|
||||
Object.assign(extension_settings.vectors, settings);
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
$('#vectors_nanogpt_model').val(settings.nanogpt_model).on('change', () => {
|
||||
settings.nanogpt_model = String($('#vectors_nanogpt_model').val());
|
||||
Object.assign(extension_settings.vectors, settings);
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
$('#vectors_openrouter_model').val(settings.openrouter_model).on('change', () => {
|
||||
settings.openrouter_model = String($('#vectors_openrouter_model').val());
|
||||
Object.assign(extension_settings.vectors, settings);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<option value="llamacpp">llama.cpp</option>
|
||||
<option value="transformers" data-i18n="Local (Transformers)">Local (Transformers)</option>
|
||||
<option value="mistral">MistralAI</option>
|
||||
<option value="nanogpt">NanoGPT</option>
|
||||
<option value="nomicai">NomicAI</option>
|
||||
<option value="ollama">Ollama</option>
|
||||
<option value="openai">OpenAI</option>
|
||||
@@ -38,6 +39,15 @@
|
||||
Hint: Set your Chutes API key in API Connections.
|
||||
</i>
|
||||
</div>
|
||||
<div class="flex-container flexFlowColumn" id="nanogpt_vectorsModel">
|
||||
<label for="vectors_nanogpt_model" data-i18n="Vectorization Model">
|
||||
Vectorization Model
|
||||
</label>
|
||||
<select id="vectors_nanogpt_model" class="text_pole"></select>
|
||||
<i data-i18n="Hint: Set your NanoGPT API key in API Connections.">
|
||||
Hint: Set your NanoGPT API key in API Connections.
|
||||
</i>
|
||||
</div>
|
||||
<div class="flex-container flexFlowColumn" id="electronhub_vectorsModel">
|
||||
<label for="vectors_electronhub_model" data-i18n="Vectorization Model">
|
||||
Vectorization Model
|
||||
|
||||
@@ -493,6 +493,43 @@ router.post('/chutes/models/embedding', async (request, response) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/nanogpt/models/embedding', async (request, response) => {
|
||||
try {
|
||||
const key = readSecret(request.user.directories, SECRET_KEYS.NANOGPT);
|
||||
|
||||
if (!key) {
|
||||
console.warn('No NanoGPT key found');
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const result = await fetch('https://nano-gpt.com/api/v1/embedding-models', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${key}`,
|
||||
'Accept-Encoding': 'identity',
|
||||
},
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
const text = await result.text();
|
||||
console.warn('NanoGPT embedding models request failed', result.statusText, text);
|
||||
return response.status(500).send(text);
|
||||
}
|
||||
|
||||
/** @type {any} */
|
||||
const data = await result.json();
|
||||
|
||||
if (!Array.isArray(data?.data)) {
|
||||
console.warn('NanoGPT embedding models response invalid', data);
|
||||
return response.sendStatus(500);
|
||||
}
|
||||
return response.json(data.data);
|
||||
} catch (error) {
|
||||
console.error('NanoGPT embedding models fetch failed', error);
|
||||
response.sendStatus(500);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/generate-image', async (request, response) => {
|
||||
try {
|
||||
const key = readSecret(request.user.directories, SECRET_KEYS.OPENAI);
|
||||
|
||||
@@ -37,6 +37,7 @@ const SOURCES = [
|
||||
'electronhub',
|
||||
'openrouter',
|
||||
'chutes',
|
||||
'nanogpt',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -82,6 +83,8 @@ async function getVector(source, sourceSettings, text, isQuery, directories) {
|
||||
return sourceSettings.embeddings[text];
|
||||
case 'chutes':
|
||||
return getOpenAIVector(text, source, directories, sourceSettings.model);
|
||||
case 'nanogpt':
|
||||
return getOpenAIVector(text, source, directories, sourceSettings.model);
|
||||
}
|
||||
|
||||
throw new Error(`Unknown vector source ${source}`);
|
||||
@@ -150,6 +153,9 @@ async function getBatchVector(source, sourceSettings, texts, isQuery, directorie
|
||||
case 'chutes':
|
||||
results.push(...await getOpenAIBatchVector(batch, source, directories, sourceSettings.model));
|
||||
break;
|
||||
case 'nanogpt':
|
||||
results.push(...await getOpenAIBatchVector(batch, source, directories, sourceSettings.model));
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown vector source ${source}`);
|
||||
}
|
||||
@@ -238,6 +244,10 @@ function getSourceSettings(source, request) {
|
||||
return {
|
||||
model: String(request.body.model || 'chutes-qwen-qwen3-embedding-8b'),
|
||||
};
|
||||
case 'nanogpt':
|
||||
return {
|
||||
model: String(request.body.model || 'text-embedding-3-small'),
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -47,6 +47,13 @@ const SOURCES = {
|
||||
body.model = null;
|
||||
},
|
||||
},
|
||||
'nanogpt': {
|
||||
secretKey: SECRET_KEYS.NANOGPT,
|
||||
url: 'https://nano-gpt.com/api/v1',
|
||||
model: 'text-embedding-3-small',
|
||||
headers: {},
|
||||
processBody: () => {},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user