mirror of
https://gitlab.com/Zer0interrupt/recipe-manager.git
synced 2026-11-01 23:24:11 -05:00
Add direct Google API fallback for model discovery and graceful non-JSON handling
This commit is contained in:
parent
423334db4d
commit
ca6d9b2db6
1 changed files with 72 additions and 14 deletions
|
|
@ -2061,8 +2061,49 @@ function populateModelDropdown(models, selectedModel) {
|
|||
}
|
||||
}
|
||||
|
||||
async function fetchModelsDirectFromGoogle(key) {
|
||||
if (!key || key === 'PASTE_YOUR_GEMINI_API_KEY_HERE') {
|
||||
throw new Error('Please enter a valid Gemini API key first.');
|
||||
}
|
||||
const googleRes = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${key}`);
|
||||
const googleData = await googleRes.json().catch(() => ({}));
|
||||
if (!googleRes.ok) {
|
||||
throw new Error(googleData.error?.message || `Google API returned status ${googleRes.status}`);
|
||||
}
|
||||
if (!Array.isArray(googleData.models)) {
|
||||
throw new Error('Unexpected response format from Google API.');
|
||||
}
|
||||
const models = googleData.models
|
||||
.filter(m => Array.isArray(m.supportedGenerationMethods) && m.supportedGenerationMethods.includes('generateContent'))
|
||||
.filter(m => !m.name.includes('embedding') && !m.name.includes('aqa') && !m.name.includes('imagen'))
|
||||
.map(m => {
|
||||
const modelId = m.name.replace(/^models\//, '');
|
||||
return {
|
||||
id: modelId,
|
||||
displayName: m.displayName || modelId,
|
||||
description: m.description || ''
|
||||
};
|
||||
});
|
||||
|
||||
models.sort((a, b) => {
|
||||
const aIsFlash = a.id.toLowerCase().includes('flash');
|
||||
const bIsFlash = b.id.toLowerCase().includes('flash');
|
||||
if (aIsFlash && !bIsFlash) return -1;
|
||||
if (!aIsFlash && bIsFlash) return 1;
|
||||
return a.id.localeCompare(b.id);
|
||||
});
|
||||
return models;
|
||||
}
|
||||
|
||||
async function handleDiscoverModels(showNotice = true) {
|
||||
const key = elements.settingsGeminiKeyInput ? elements.settingsGeminiKeyInput.value.trim() : '';
|
||||
if (!key || key === 'PASTE_YOUR_GEMINI_API_KEY_HERE') {
|
||||
if (showNotice) {
|
||||
alert('Please enter your Google Gemini API key first.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (elements.modelsStatusHint) {
|
||||
elements.modelsStatusHint.textContent = 'Discovering available models from Google API...';
|
||||
elements.modelsStatusHint.style.color = 'var(--primary)';
|
||||
|
|
@ -2072,25 +2113,42 @@ async function handleDiscoverModels(showNotice = true) {
|
|||
}
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/settings/discover-models', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...getAuthHeaders()
|
||||
},
|
||||
body: JSON.stringify({ apiKey: key })
|
||||
});
|
||||
let models = [];
|
||||
|
||||
const data = await res.json();
|
||||
if (!res.ok) {
|
||||
throw new Error(data.error || 'Failed to discover models.');
|
||||
// 1. Attempt backend endpoint first
|
||||
try {
|
||||
const res = await fetch('/api/settings/discover-models', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...getAuthHeaders()
|
||||
},
|
||||
body: JSON.stringify({ apiKey: key })
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const text = await res.text();
|
||||
try {
|
||||
const data = JSON.parse(text);
|
||||
if (Array.isArray(data.models)) {
|
||||
models = data.models;
|
||||
}
|
||||
} catch (parseErr) {}
|
||||
}
|
||||
} catch (serverErr) {
|
||||
// Backend may not have route if server hasn't restarted yet
|
||||
}
|
||||
|
||||
if (data.models && data.models.length > 0) {
|
||||
// 2. Fallback to direct client-side call to Google API if backend returned HTML / 404
|
||||
if (models.length === 0) {
|
||||
models = await fetchModelsDirectFromGoogle(key);
|
||||
}
|
||||
|
||||
if (models.length > 0) {
|
||||
const currentSelected = elements.settingsGeminiModelSelect ? elements.settingsGeminiModelSelect.value : 'gemini-2.0-flash';
|
||||
populateModelDropdown(data.models, currentSelected);
|
||||
populateModelDropdown(models, currentSelected);
|
||||
if (elements.modelsStatusHint) {
|
||||
elements.modelsStatusHint.textContent = `Discovered ${data.models.length} compatible models.`;
|
||||
elements.modelsStatusHint.textContent = `Discovered ${models.length} compatible models.`;
|
||||
elements.modelsStatusHint.style.color = 'var(--text-muted)';
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in a new issue