| 1168 | 1221 | $('#siliconflow_vectorsModel').toggle(settings.source === 'siliconflow'); |
| 1169 | 1222 | $('#workers_ai_vectorsModel').toggle(settings.source === 'workers_ai'); |
| 1170 | 1223 | $('#vector_altEndpointUrl').toggle(vectorApiRequiresUrl.includes(settings.source)); |
| 1171 | 1224 | switchif (settings.source === 'webllm') { |
| 1172 | | - case 'webllm': |
| 1225 | + loadWebLlmModels(); |
| 1173 | | - loadWebLlmModels(); |
| 1226 | + } else if (settings.source in remoteEmbeddingEndpoints) { |
| 1174 | | - break; |
| 1227 | + loadRemoteEmbeddingModels(settings.source); |
| 1175 | | - case 'electronhub': |
| 1176 | | - loadElectronHubModels(); |
| 1177 | | - break; |
| 1178 | | - case 'openrouter': |
| 1179 | | - loadOpenRouterModels(); |
| 1180 | | - break; |
| 1181 | | - case 'chutes': |
| 1182 | | - loadChutesModels(); |
| 1183 | | - break; |
| 1184 | | - case 'nanogpt': |
| 1185 | | - loadNanoGPTModels(); |
| 1186 | | - break; |
| 1187 | | - case 'siliconflow': |
| 1188 | | - loadSiliconFlowModels(); |
| 1189 | | - break; |
| 1190 | | - case 'workers_ai': |
| 1191 | | - loadWorkersAIModels(); |
| 1192 | | - break; |
| 1193 | 1228 | } |
| 1194 | 1229 | } |
| 1195 | 1230 | |
| 1196 | | -async function loadChutesModels() { |
| 1231 | +/** |
| 1197 | | - try { |
| 1232 | + * Loads models from a remote embedding endpoint and populates the corresponding select element. |
| 1198 | | - const response = await fetch('/api/openai/chutes/models/embedding', { |
| 1233 | + * @param {string} source - The source key matching a remoteEmbeddingEndpoints entry |
| 1199 | | - method: 'POST', |
| 1234 | + */ |
| 1200 | | - headers: getRequestHeaders({ omitContentType: true }), |
| 1235 | +async function loadRemoteEmbeddingModels(source) { |
| 1201 | | - }); |
| 1236 | + const config = remoteEmbeddingEndpoints[source]; |
| 1202 | 1237 | if (!response.okconfig) { |
| 1203 | | - throw new Error(`HTTP ${response.status}`); |
| 1238 | + return; |
| 1204 | | - } |
| 1205 | | - /** @type {Array<any>} */ |
| 1206 | | - const data = await response.json(); |
| 1207 | | - const models = Array.isArray(data) ? data : []; |
| 1208 | | - populateChutesModelSelect(models); |
| 1209 | | - } catch (err) { |
| 1210 | | - console.warn('Chutes models fetch failed', err); |
| 1211 | | - populateChutesModelSelect([]); |
| 1212 | 1239 | } |
| 1213 | | -} |
| 1214 | 1240 | |
| 1215 | | -function populateChutesModelSelect(models) { |
| 1241 | + const { url, settingsKey, selectId, getBody, filter } = config; |
| 1216 | 1242 | const selectvalueProperty = $(config.valueProperty || '#vectors_chutes_modelid'); |
| 1217 | | - select.empty(); |
| 1243 | + const textProperty = config.textProperty; |
| 1218 | | - for (const m of models) { |
| 1219 | | - const option = document.createElement('option'); |
| 1220 | | - option.value = m.slug; |
| 1221 | | - option.text = m.name; |
| 1222 | | - select.append(option); |
| 1223 | | - } |
| 1224 | | - if (!settings.chutes_model && models.length) { |
| 1225 | | - settings.chutes_model = models[0].slug; |
| 1226 | | - } |
| 1227 | | - $('#vectors_chutes_model').val(settings.chutes_model); |
| 1228 | | -} |
| 1229 | 1244 | |
| 1230 | | -async function loadNanoGPTModels() { |
| 1245 | + /** |
| 1231 | | - try { |
| 1246 | + * Populates the select element with the given models. |
| 1232 | | - const response = await fetch('/api/openai/nanogpt/models/embedding', { |
| 1247 | + * @param {any[]} models - Array of model objects |
| 1233 | | - method: 'POST', |
| 1248 | + */ |
| 1234 | | - headers: getRequestHeaders({ omitContentType: true }), |
| 1249 | + function populateSelect(models) { |
| 1235 | | - }); |
| 1250 | + const select = $(`#${selectId}`); |
| 1236 | | - if (!response.ok) { |
| 1251 | + select.empty(); |
| 1237 | | - throw new Error(`HTTP ${response.status}`); |
| 1252 | + for (const m of models) { |
| 1253 | + const option = document.createElement('option'); |
| 1254 | + option.value = m[valueProperty]; |
| 1255 | + option.text = textProperty ? (m[textProperty] || m[valueProperty]) : m[valueProperty]; |
| 1256 | + select.append(option); |
| 1238 | 1257 | } |
| 1239 | | - /** @type {Array<any>} */ |
| 1258 | + if (!settings[settingsKey] && models.length) { |
| 1240 | | - const data = await response.json(); |
| 1259 | + settings[settingsKey] = models[0][valueProperty]; |
| 1241 | | - const models = Array.isArray(data) ? data : []; |
| 1260 | + Object.assign(extension_settings.vectors, settings); |
| 1242 | 1261 | populateNanoGPTModelSelect saveSettingsDebounced(models); |
| 1243 | | - } catch (err) { |
| 1244 | | - console.warn('NanoGPT models fetch failed', err); |
| 1245 | | - populateNanoGPTModelSelect([]); |
| 1246 | | - } |
| 1247 | | -} |
| 1248 | | - |
| 1249 | | -function populateNanoGPTModelSelect(models) { |
| 1250 | | - const select = $('#vectors_nanogpt_model'); |
| 1251 | | - select.empty(); |
| 1252 | | - for (const m of models) { |
| 1253 | | - const option = document.createElement('option'); |
| 1254 | | - option.value = m.id; |
| 1255 | | - option.text = m.name || m.id; |
| 1256 | | - select.append(option); |
| 1257 | | - } |
| 1258 | | - if (!settings.nanogpt_model && models.length) { |
| 1259 | | - settings.nanogpt_model = models[0].id; |
| 1260 | | - } |
| 1261 | | - $('#vectors_nanogpt_model').val(settings.nanogpt_model); |
| 1262 | | -} |
| 1263 | | - |
| 1264 | | -async function loadElectronHubModels() { |
| 1265 | | - try { |
| 1266 | | - const response = await fetch('/api/openai/electronhub/models', { |
| 1267 | | - method: 'POST', |
| 1268 | | - headers: getRequestHeaders({ omitContentType: true }), |
| 1269 | | - }); |
| 1270 | | - if (!response.ok) { |
| 1271 | | - throw new Error(`HTTP ${response.status}`); |
| 1272 | 1262 | } |
| 1273 | | - /** @type {Array<any>} */ |
| 1263 | + select.val(settings[settingsKey]); |
| 1274 | | - const data = await response.json(); |
| 1275 | | - // filter by embeddings endpoint |
| 1276 | | - const models = Array.isArray(data) ? data.filter(m => Array.isArray(m?.endpoints) && m.endpoints.includes('/v1/embeddings')) : []; |
| 1277 | | - populateElectronHubModelSelect(models); |
| 1278 | | - } catch (err) { |
| 1279 | | - console.warn('Electron Hub models fetch failed', err); |
| 1280 | | - populateElectronHubModelSelect([]); |
| 1281 | | - } |
| 1282 | | -} |
| 1283 | | - |
| 1284 | | -/** |
| 1285 | | - * Populates the Electron Hub model select element. |
| 1286 | | - * @param {{ id: string, name: string }[]} models Electron Hub models |
| 1287 | | - */ |
| 1288 | | -function populateElectronHubModelSelect(models) { |
| 1289 | | - const select = $('#vectors_electronhub_model'); |
| 1290 | | - select.empty(); |
| 1291 | | - for (const m of models) { |
| 1292 | | - const option = document.createElement('option'); |
| 1293 | | - option.value = m.id; |
| 1294 | | - option.text = m.name || m.id; |
| 1295 | | - select.append(option); |
| 1296 | | - } |
| 1297 | | - if (!settings.electronhub_model && models.length) { |
| 1298 | | - settings.electronhub_model = models[0].id; |
| 1299 | 1264 | } |
| 1300 | | - $('#vectors_electronhub_model').val(settings.electronhub_model); |
| 1301 | | -} |
| 1302 | 1265 | |
| 1303 | | -async function loadOpenRouterModels() { |
| 1304 | 1266 | try { |
| 1305 | | - const response = await fetch('/api/openrouter/models/embedding', { |
| 1267 | + const body = typeof getBody === 'function' ? getBody() : {}; |
| 1306 | | - method: 'POST', |
| 1307 | | - headers: getRequestHeaders({ omitContentType: true }), |
| 1308 | | - }); |
| 1309 | | - if (!response.ok) { |
| 1310 | | - throw new Error(`HTTP ${response.status}`); |
| 1311 | | - } |
| 1312 | | - /** @type {Array<any>} */ |
| 1313 | | - const data = await response.json(); |
| 1314 | | - const models = Array.isArray(data) ? data : []; |
| 1315 | | - populateOpenRouterModelSelect(models); |
| 1316 | | - } catch (err) { |
| 1317 | | - console.warn('OpenRouter models fetch failed', err); |
| 1318 | | - populateOpenRouterModelSelect([]); |
| 1319 | | - } |
| 1320 | | -} |
| 1321 | | - |
| 1322 | | -/** |
| 1323 | | - * Populates the OpenRouter model select element. |
| 1324 | | - * @param {{ id: string, name: string }[]} models OpenRouter models |
| 1325 | | - */ |
| 1326 | | -function populateOpenRouterModelSelect(models) { |
| 1327 | | - const select = $('#vectors_openrouter_model'); |
| 1328 | | - select.empty(); |
| 1329 | | - for (const m of models) { |
| 1330 | | - const option = document.createElement('option'); |
| 1331 | | - option.value = m.id; |
| 1332 | | - option.text = m.name || m.id; |
| 1333 | | - select.append(option); |
| 1334 | | - } |
| 1335 | | - if (!settings.openrouter_model && models.length) { |
| 1336 | | - settings.openrouter_model = models[0].id; |
| 1337 | | - } |
| 1338 | | - $('#vectors_openrouter_model').val(settings.openrouter_model); |
| 1339 | | -} |
| 1340 | 1268 | |
| 1341 | | -async function loadSiliconFlowModels() { |
| 1269 | + /** @type {RequestInit} */ |
| 1342 | | - try { |
| 1270 | + const fetchOptions = { |
| 1343 | | - const response = await fetch('/api/openai/siliconflow/models/embedding', { |
| 1344 | 1271 | method: 'POST', |
| 1345 | 1272 | headers: getRequestHeaders(), |
| 1346 | 1273 | body: JSON.stringify(body || {}), |
| 1347 | | - siliconflow_endpoint: oai_settings.siliconflow_endpoint, |
| 1274 | + }; |
| 1348 | | - }), |
| 1349 | | - }); |
| 1350 | 1275 | |
| 1276 | + const response = await fetch(url, fetchOptions); |
| 1351 | 1277 | if (!response.ok) { |
| 1352 | 1278 | throw new Error(`HTTP ${response.status}`); |
| 1353 | 1279 | } |
| 1354 | 1280 | |
| 1355 | 1281 | /** @type {Array<any>} */ |
| 1356 | 1282 | const data = await response.json(); |
| 1357 | 1283 | constlet models = Array.isArray(data) ? data : []; |
| 1358 | | - populateSiliconFlowModelSelect(models); |
| 1284 | + if (filter) { |
| 1359 | | - } catch (err) { |
| 1285 | + models = filter(models); |
| 1360 | | - console.warn('SiliconFlow models fetch failed', err); |
| 1361 | | - populateSiliconFlowModelSelect([]); |
| 1362 | | - } |
| 1363 | | -} |
| 1364 | | - |
| 1365 | | -function populateSiliconFlowModelSelect(models) { |
| 1366 | | - const select = $('#vectors_siliconflow_model'); |
| 1367 | | - select.empty(); |
| 1368 | | - for (const m of models) { |
| 1369 | | - const option = document.createElement('option'); |
| 1370 | | - option.value = m.id; |
| 1371 | | - option.text = m.id; |
| 1372 | | - select.append(option); |
| 1373 | | - } |
| 1374 | | - if (!settings.siliconflow_model && models.length) { |
| 1375 | | - settings.siliconflow_model = models[0].id; |
| 1376 | | - } |
| 1377 | | - $('#vectors_siliconflow_model').val(settings.siliconflow_model); |
| 1378 | | -} |
| 1379 | | - |
| 1380 | | -async function loadWorkersAIModels() { |
| 1381 | | - try { |
| 1382 | | - const response = await fetch('/api/openai/workers-ai/models/embedding', { |
| 1383 | | - method: 'POST', |
| 1384 | | - headers: getRequestHeaders(), |
| 1385 | | - body: JSON.stringify({ |
| 1386 | | - workers_ai_account_id: oai_settings.workers_ai_account_id, |
| 1387 | | - }), |
| 1388 | | - }); |
| 1389 | | - if (!response.ok) { |
| 1390 | | - throw new Error(`HTTP ${response.status}`); |
| 1391 | 1286 | } |
| 1392 | | - /** @type {Array<any>} */ |
| 1393 | | - const data = await response.json(); |
| 1394 | | - const models = Array.isArray(data) ? data : []; |
| 1395 | | - populateWorkersAIModelSelect(models); |
| 1396 | | - } catch (err) { |
| 1397 | | - console.warn('Workers AI models fetch failed', err); |
| 1398 | | - populateWorkersAIModelSelect([]); |
| 1399 | | - } |
| 1400 | | -} |
| 1401 | 1287 | |
| 1402 | | -function populateWorkersAIModelSelect(models) { |
| 1288 | + populateSelect(models); |
| 1403 | | - const select = $('#vectors_workers_ai_model'); |
| 1289 | + } catch (err) { |
| 1404 | | - select.empty(); |
| 1290 | + console.warn(`${source} models fetch failed`, err); |
| 1405 | | - for (const m of models) { |
| 1291 | + populateSelect([]); |
| 1406 | | - const option = document.createElement('option'); |
| 1407 | | - option.value = m.id; |
| 1408 | | - option.text = m.id; |
| 1409 | | - select.append(option); |
| 1410 | | - } |
| 1411 | | - if (!settings.workers_ai_model && models.length) { |
| 1412 | | - settings.workers_ai_model = models[0].id; |
| 1413 | | - Object.assign(extension_settings.vectors, settings); |
| 1414 | | - saveSettingsDebounced(); |
| 1415 | 1292 | } |
| 1416 | | - $('#vectors_workers_ai_model').val(settings.workers_ai_model); |
| 1417 | 1293 | } |
| 1418 | 1294 | |
| 1419 | 1295 | /** |