diff --git a/app/static/index.html b/app/static/index.html
index db5725a..0e05168 100644
--- a/app/static/index.html
+++ b/app/static/index.html
@@ -979,6 +979,30 @@
+
+
News Summarizer
+
Takes effect on the next hourly run (:05). No container restart.
+
+
+ Nous Portal (inference-api.nousresearch.com)
+
+
+
+ set in API Keys as NOUS_API_KEY (never shown here)
+
+
+
+
+
+
+
+ —
+
+
+
+
+
+
Map Defaults
Applied to the live map on load.
@@ -1025,7 +1049,7 @@
Active sources—
Open alerts—
Tracked entities—
-
News cycle15 min
+
News cyclehourly :05
Market feedSTANDBY
@@ -1051,7 +1075,7 @@
-
15-MIN CYCLE
+
HOURLY
@@ -1181,7 +1205,7 @@ function showView(name) {
}
if (name === 'news') loadNews(false);
if (name === 'events') { loadSummary(); loadEvents(); }
- if (name === 'settings') { loadSummary(); renderSysInfo(); }
+ if (name === 'settings') { loadSummary(); renderSysInfo(); loadSettings(); }
window.scrollTo(0, 0);
}
@@ -1657,6 +1681,55 @@ function initSettings() {
}
} catch (e) {}
}
+async function loadSettings() {
+ const sel = document.getElementById('set-summary-model');
+ const now = document.getElementById('set-summary-model-now');
+ try {
+ const [setR, modR] = await Promise.all([
+ fetch(`${API}/api/settings`),
+ fetch(`${API}/api/news/models`),
+ ]);
+ const settings = setR.ok ? await setR.json() : {};
+ const catalog = modR.ok ? await modR.json() : {models: []};
+ const saved = (settings.summary_model || '').trim();
+ const ids = (catalog.models || []).map(m => m && m.id).filter(Boolean);
+ if (saved && ids.indexOf(saved) === -1) ids.unshift(saved);
+ if (sel) {
+ sel.innerHTML = ids.map(id => ``).join('');
+ if (saved) sel.value = saved;
+ }
+ if (now) now.textContent = saved || '—';
+ } catch (e) {
+ console.error('Settings load failed', e);
+ }
+}
+async function saveSummaryModel() {
+ const sel = document.getElementById('set-summary-model');
+ const flash = document.getElementById('sum-saved');
+ const now = document.getElementById('set-summary-model-now');
+ const summary_model = ((sel && sel.value) || '').trim();
+ if (!summary_model) {
+ if (flash) flash.textContent = 'Choose a model to save.';
+ return;
+ }
+ try {
+ const r = await fetch(`${API}/api/settings`, {
+ method: 'PUT',
+ headers: {'Content-Type': 'application/json'},
+ body: JSON.stringify({summary_model}),
+ });
+ const d = await r.json().catch(() => ({}));
+ if (!r.ok) {
+ if (flash) flash.textContent = (typeof d.detail === 'string' ? d.detail : 'Save failed');
+ return;
+ }
+ if (now) now.textContent = d.summary_model || summary_model;
+ if (sel && d.summary_model) sel.value = d.summary_model;
+ if (flash) flash.textContent = 'Model saved.';
+ } catch (e) {
+ if (flash) flash.textContent = 'Network error.';
+ }
+}
/* ═══════════════ MAP (NASA GIBS basemap + FIRMS + cameras + blips) ═══════
The satellite map core is production-proven — preserved verbatim. */