Update default model list from live API discovery and filter out TTS/music/agent models

This commit is contained in:
Chris 2026-11-01 01:43:44 -05:00
parent ca6d9b2db6
commit 454f676499
4 changed files with 31 additions and 24 deletions

View file

@ -2035,15 +2035,17 @@ function populateModelDropdown(models, selectedModel) {
const select = elements.settingsGeminiModelSelect; const select = elements.settingsGeminiModelSelect;
select.innerHTML = ''; select.innerHTML = '';
const targetModel = selectedModel || 'gemini-2.0-flash'; const targetModel = selectedModel || 'gemini-2.5-flash';
let foundTarget = false; let foundTarget = false;
models.forEach(m => { models.forEach(m => {
const opt = document.createElement('option'); const opt = document.createElement('option');
opt.value = m.id; opt.value = m.id;
opt.textContent = m.displayName || m.id; opt.textContent = m.displayName || m.id;
if (m.id === 'gemini-2.0-flash') { if (m.id === 'gemini-2.5-flash') {
opt.textContent = `${m.displayName || 'Gemini 2.0 Flash'} (Recommended)`; opt.textContent = `${m.displayName || 'Gemini 2.5 Flash'} (Stable Recommended)`;
} else if (m.id === 'gemini-3.8-flash') {
opt.textContent = `${m.displayName || 'Gemini 3.8 Flash'} (Newest Flash)`;
} }
if (m.id === targetModel) { if (m.id === targetModel) {
opt.selected = true; opt.selected = true;
@ -2073,9 +2075,10 @@ async function fetchModelsDirectFromGoogle(key) {
if (!Array.isArray(googleData.models)) { if (!Array.isArray(googleData.models)) {
throw new Error('Unexpected response format from Google API.'); throw new Error('Unexpected response format from Google API.');
} }
const excludedPatterns = /embedding|aqa|imagen|tts|lyria|banana|-image|robotics|computer-use|deep-research|antigravity|customtools/i;
const models = googleData.models const models = googleData.models
.filter(m => Array.isArray(m.supportedGenerationMethods) && m.supportedGenerationMethods.includes('generateContent')) .filter(m => Array.isArray(m.supportedGenerationMethods) && m.supportedGenerationMethods.includes('generateContent'))
.filter(m => !m.name.includes('embedding') && !m.name.includes('aqa') && !m.name.includes('imagen')) .filter(m => !excludedPatterns.test(m.name) && !excludedPatterns.test(m.displayName || ''))
.map(m => { .map(m => {
const modelId = m.name.replace(/^models\//, ''); const modelId = m.name.replace(/^models\//, '');
return { return {
@ -2090,7 +2093,7 @@ async function fetchModelsDirectFromGoogle(key) {
const bIsFlash = b.id.toLowerCase().includes('flash'); const bIsFlash = b.id.toLowerCase().includes('flash');
if (aIsFlash && !bIsFlash) return -1; if (aIsFlash && !bIsFlash) return -1;
if (!aIsFlash && bIsFlash) return 1; if (!aIsFlash && bIsFlash) return 1;
return a.id.localeCompare(b.id); return b.id.localeCompare(a.id);
}); });
return models; return models;
} }
@ -2145,7 +2148,7 @@ async function handleDiscoverModels(showNotice = true) {
} }
if (models.length > 0) { if (models.length > 0) {
const currentSelected = elements.settingsGeminiModelSelect ? elements.settingsGeminiModelSelect.value : 'gemini-2.0-flash'; const currentSelected = elements.settingsGeminiModelSelect ? elements.settingsGeminiModelSelect.value : 'gemini-2.5-flash';
populateModelDropdown(models, currentSelected); populateModelDropdown(models, currentSelected);
if (elements.modelsStatusHint) { if (elements.modelsStatusHint) {
elements.modelsStatusHint.textContent = `Discovered ${models.length} compatible models.`; elements.modelsStatusHint.textContent = `Discovered ${models.length} compatible models.`;
@ -2211,7 +2214,7 @@ async function openSettingsModal() {
} }
if (elements.settingsGeminiModelSelect) { if (elements.settingsGeminiModelSelect) {
const savedModel = settings.geminiModel || 'gemini-2.0-flash'; const savedModel = (!settings.geminiModel || settings.geminiModel === 'gemini-2.0-flash') ? 'gemini-2.5-flash' : settings.geminiModel;
let exists = false; let exists = false;
for (let i = 0; i < elements.settingsGeminiModelSelect.options.length; i++) { for (let i = 0; i < elements.settingsGeminiModelSelect.options.length; i++) {
if (elements.settingsGeminiModelSelect.options[i].value === savedModel) { if (elements.settingsGeminiModelSelect.options[i].value === savedModel) {
@ -2243,7 +2246,7 @@ async function handleSaveSettings(e) {
elements.settingsStatusMsg.style.display = 'none'; elements.settingsStatusMsg.style.display = 'none';
const key = elements.settingsGeminiKeyInput.value.trim(); const key = elements.settingsGeminiKeyInput.value.trim();
const model = elements.settingsGeminiModelSelect ? elements.settingsGeminiModelSelect.value : 'gemini-2.0-flash'; const model = elements.settingsGeminiModelSelect ? elements.settingsGeminiModelSelect.value : 'gemini-2.5-flash';
const defaultConsolidate = elements.settingsDefaultConsolidate ? elements.settingsDefaultConsolidate.checked : true; const defaultConsolidate = elements.settingsDefaultConsolidate ? elements.settingsDefaultConsolidate.checked : true;
try { try {
@ -2417,7 +2420,8 @@ async function scanRecipeFile(file) {
} }
const settings = await settingsResponse.json(); const settings = await settingsResponse.json();
const apiKey = settings.geminiApiKey ? settings.geminiApiKey.trim() : ''; const apiKey = settings.geminiApiKey ? settings.geminiApiKey.trim() : '';
const geminiModel = settings.geminiModel ? settings.geminiModel.trim() : 'gemini-2.0-flash'; const rawModel = settings.geminiModel ? settings.geminiModel.trim() : '';
const geminiModel = (!rawModel || rawModel === 'gemini-2.0-flash') ? 'gemini-2.5-flash' : rawModel;
const isPlaceholder = apiKey === 'PASTE_YOUR_GEMINI_API_KEY_HERE' || apiKey === ''; const isPlaceholder = apiKey === 'PASTE_YOUR_GEMINI_API_KEY_HERE' || apiKey === '';
if (!apiKey || isPlaceholder) { if (!apiKey || isPlaceholder) {

View file

@ -1036,9 +1036,11 @@
</button> </button>
</div> </div>
<select id="settings-gemini-model" style="width: 100%; height: 40px; border-radius: var(--border-radius-md); border: 1px solid var(--border-color); background: var(--bg-card, #1e2430); color: var(--text-main); padding-left: 12px; padding-right: 12px; font-size: 0.85rem; cursor: pointer;"> <select id="settings-gemini-model" style="width: 100%; height: 40px; border-radius: var(--border-radius-md); border: 1px solid var(--border-color); background: var(--bg-card, #1e2430); color: var(--text-main); padding-left: 12px; padding-right: 12px; font-size: 0.85rem; cursor: pointer;">
<option value="gemini-2.0-flash">Gemini 2.0 Flash (Recommended)</option> <option value="gemini-2.5-flash">Gemini 2.5 Flash (Stable Recommended)</option>
<option value="gemini-1.5-flash">Gemini 1.5 Flash</option> <option value="gemini-3.8-flash">Gemini 3.8 Flash (Newest Flash)</option>
<option value="gemini-1.5-pro">Gemini 1.5 Pro</option> <option value="gemini-flash-latest">Gemini Flash Latest</option>
<option value="gemini-2.5-pro">Gemini 2.5 Pro</option>
<option value="gemini-4-argon">Gemini 4 Argon</option>
</select> </select>
<span id="models-status-hint" style="font-size: 0.75rem; color: var(--text-muted); margin-top: 4px; display: block;">Powers both recipe photo scanning and AI text polishing.</span> <span id="models-status-hint" style="font-size: 0.75rem; color: var(--text-muted); margin-top: 4px; display: block;">Powers both recipe photo scanning and AI text polishing.</span>
</div> </div>

View file

@ -1,4 +1,4 @@
{ {
"geminiApiKey": "PASTE_YOUR_GEMINI_API_KEY_HERE", "geminiApiKey": "PASTE_YOUR_GEMINI_API_KEY_HERE",
"geminiModel": "gemini-2.0-flash" "geminiModel": "gemini-2.5-flash"
} }

View file

@ -82,7 +82,7 @@ db.prepare(`
db.prepare(` db.prepare(`
CREATE TABLE IF NOT EXISTS settings ( CREATE TABLE IF NOT EXISTS settings (
geminiApiKey TEXT DEFAULT '', geminiApiKey TEXT DEFAULT '',
geminiModel TEXT DEFAULT 'gemini-2.0-flash' geminiModel TEXT DEFAULT 'gemini-2.5-flash'
) )
`).run(); `).run();
@ -193,16 +193,16 @@ try {
db.prepare("ALTER TABLE backup_history ADD COLUMN userSummary TEXT NOT NULL DEFAULT '[]'").run(); db.prepare("ALTER TABLE backup_history ADD COLUMN userSummary TEXT NOT NULL DEFAULT '[]'").run();
} catch (e) {} } catch (e) {}
try { try {
db.prepare("ALTER TABLE settings ADD COLUMN geminiModel TEXT DEFAULT 'gemini-2.0-flash'").run(); db.prepare("ALTER TABLE settings ADD COLUMN geminiModel TEXT DEFAULT 'gemini-2.5-flash'").run();
} catch (e) {} } catch (e) {}
try { try {
db.prepare("UPDATE settings SET geminiModel = 'gemini-2.0-flash' WHERE geminiModel IS NULL OR geminiModel = ''").run(); db.prepare("UPDATE settings SET geminiModel = 'gemini-2.5-flash' WHERE geminiModel IS NULL OR geminiModel = '' OR geminiModel = 'gemini-2.0-flash'").run();
} catch (e) {} } catch (e) {}
// Initialize single settings record if empty // Initialize single settings record if empty
const settingsCount = db.prepare('SELECT COUNT(*) as count FROM settings').get().count; const settingsCount = db.prepare('SELECT COUNT(*) as count FROM settings').get().count;
if (settingsCount === 0) { if (settingsCount === 0) {
db.prepare('INSERT INTO settings (geminiApiKey, geminiModel) VALUES (?, ?)').run('', 'gemini-2.0-flash'); db.prepare('INSERT INTO settings (geminiApiKey, geminiModel) VALUES (?, ?)').run('', 'gemini-2.5-flash');
} }
// Ensure default system_admin and admin user profiles exist // Ensure default system_admin and admin user profiles exist
@ -1587,7 +1587,7 @@ app.post('/api/recipes/ai-polish', requireAuth, async (req, res) => {
const settingsRow = db.prepare('SELECT geminiApiKey, geminiModel FROM settings LIMIT 1').get(); const settingsRow = db.prepare('SELECT geminiApiKey, geminiModel FROM settings LIMIT 1').get();
const geminiKey = settingsRow?.geminiApiKey?.trim(); const geminiKey = settingsRow?.geminiApiKey?.trim();
const geminiModel = settingsRow?.geminiModel?.trim() || 'gemini-2.0-flash'; const geminiModel = settingsRow?.geminiModel?.trim() || 'gemini-2.5-flash';
const isPlaceholder = !geminiKey || geminiKey === 'PASTE_YOUR_GEMINI_API_KEY_HERE'; const isPlaceholder = !geminiKey || geminiKey === 'PASTE_YOUR_GEMINI_API_KEY_HERE';
if (isPlaceholder) { if (isPlaceholder) {
@ -1654,7 +1654,7 @@ app.get('/api/settings', requireAuth, (req, res) => {
const defaultConsolidateLists = userRow ? userRow.defaultConsolidateLists !== 0 : true; const defaultConsolidateLists = userRow ? userRow.defaultConsolidateLists !== 0 : true;
res.json({ res.json({
geminiApiKey: settings ? settings.geminiApiKey : '', geminiApiKey: settings ? settings.geminiApiKey : '',
geminiModel: (settings && settings.geminiModel) ? settings.geminiModel : 'gemini-2.0-flash', geminiModel: (settings && settings.geminiModel) ? settings.geminiModel : 'gemini-2.5-flash',
defaultConsolidateLists defaultConsolidateLists
}); });
} catch (e) { } catch (e) {
@ -1671,7 +1671,7 @@ app.post('/api/settings', requireAuth, (req, res) => {
db.prepare('UPDATE settings SET geminiApiKey = ?').run(geminiApiKey || ''); db.prepare('UPDATE settings SET geminiApiKey = ?').run(geminiApiKey || '');
} }
if (geminiModel !== undefined) { if (geminiModel !== undefined) {
db.prepare('UPDATE settings SET geminiModel = ?').run(geminiModel || 'gemini-2.0-flash'); db.prepare('UPDATE settings SET geminiModel = ?').run(geminiModel || 'gemini-2.5-flash');
} }
if (typeof defaultConsolidateLists === 'boolean') { if (typeof defaultConsolidateLists === 'boolean') {
db.prepare('UPDATE users SET defaultConsolidateLists = ? WHERE id = ?').run(defaultConsolidateLists ? 1 : 0, req.user.id); db.prepare('UPDATE users SET defaultConsolidateLists = ? WHERE id = ?').run(defaultConsolidateLists ? 1 : 0, req.user.id);
@ -1681,7 +1681,7 @@ app.post('/api/settings', requireAuth, (req, res) => {
const userRow = db.prepare('SELECT defaultConsolidateLists FROM users WHERE id = ?').get(req.user.id); const userRow = db.prepare('SELECT defaultConsolidateLists FROM users WHERE id = ?').get(req.user.id);
res.json({ res.json({
geminiApiKey: settings ? settings.geminiApiKey : '', geminiApiKey: settings ? settings.geminiApiKey : '',
geminiModel: (settings && settings.geminiModel) ? settings.geminiModel : 'gemini-2.0-flash', geminiModel: (settings && settings.geminiModel) ? settings.geminiModel : 'gemini-2.5-flash',
defaultConsolidateLists: userRow ? userRow.defaultConsolidateLists !== 0 : true defaultConsolidateLists: userRow ? userRow.defaultConsolidateLists !== 0 : true
}); });
} catch (e) { } catch (e) {
@ -1707,9 +1707,10 @@ app.post('/api/settings/discover-models', requireAuth, async (req, res) => {
}); });
if (response.data && Array.isArray(response.data.models)) { if (response.data && Array.isArray(response.data.models)) {
const excludedPatterns = /embedding|aqa|imagen|tts|lyria|banana|-image|robotics|computer-use|deep-research|antigravity|customtools/i;
const models = response.data.models const models = response.data.models
.filter(m => Array.isArray(m.supportedGenerationMethods) && m.supportedGenerationMethods.includes('generateContent')) .filter(m => Array.isArray(m.supportedGenerationMethods) && m.supportedGenerationMethods.includes('generateContent'))
.filter(m => !m.name.includes('embedding') && !m.name.includes('aqa') && !m.name.includes('imagen')) .filter(m => !excludedPatterns.test(m.name) && !excludedPatterns.test(m.displayName || ''))
.map(m => { .map(m => {
const modelId = m.name.replace(/^models\//, ''); const modelId = m.name.replace(/^models\//, '');
return { return {
@ -1719,13 +1720,13 @@ app.post('/api/settings/discover-models', requireAuth, async (req, res) => {
}; };
}); });
// Sort models: Flash models first, then by ID // Sort models: Flash models first, then Pro, then others
models.sort((a, b) => { models.sort((a, b) => {
const aIsFlash = a.id.toLowerCase().includes('flash'); const aIsFlash = a.id.toLowerCase().includes('flash');
const bIsFlash = b.id.toLowerCase().includes('flash'); const bIsFlash = b.id.toLowerCase().includes('flash');
if (aIsFlash && !bIsFlash) return -1; if (aIsFlash && !bIsFlash) return -1;
if (!aIsFlash && bIsFlash) return 1; if (!aIsFlash && bIsFlash) return 1;
return a.id.localeCompare(b.id); return b.id.localeCompare(a.id);
}); });
return res.json({ models }); return res.json({ models });