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) {
|
async function handleDiscoverModels(showNotice = true) {
|
||||||
const key = elements.settingsGeminiKeyInput ? elements.settingsGeminiKeyInput.value.trim() : '';
|
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) {
|
if (elements.modelsStatusHint) {
|
||||||
elements.modelsStatusHint.textContent = 'Discovering available models from Google API...';
|
elements.modelsStatusHint.textContent = 'Discovering available models from Google API...';
|
||||||
elements.modelsStatusHint.style.color = 'var(--primary)';
|
elements.modelsStatusHint.style.color = 'var(--primary)';
|
||||||
|
|
@ -2072,25 +2113,42 @@ async function handleDiscoverModels(showNotice = true) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/settings/discover-models', {
|
let models = [];
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
...getAuthHeaders()
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ apiKey: key })
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await res.json();
|
// 1. Attempt backend endpoint first
|
||||||
if (!res.ok) {
|
try {
|
||||||
throw new Error(data.error || 'Failed to discover models.');
|
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';
|
const currentSelected = elements.settingsGeminiModelSelect ? elements.settingsGeminiModelSelect.value : 'gemini-2.0-flash';
|
||||||
populateModelDropdown(data.models, currentSelected);
|
populateModelDropdown(models, currentSelected);
|
||||||
if (elements.modelsStatusHint) {
|
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)';
|
elements.modelsStatusHint.style.color = 'var(--text-muted)';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue