From 496d13b8b001e3edc38b43acca6d39a4a31197b3 Mon Sep 17 00:00:00 2001 From: Sirius DevOps Date: Thu, 27 Aug 2026 23:43:36 -0400 Subject: [PATCH] feat: critical news pins on the osint map --- app/static/index.html | 69 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/app/static/index.html b/app/static/index.html index e3f987b..db4fb01 100644 --- a/app/static/index.html +++ b/app/static/index.html @@ -264,6 +264,7 @@ .hud-chip .c.fires { background: #fb923c; box-shadow: 0 0 6px #fb923c; } .hud-chip .c.cams { background: #4ade80; box-shadow: 0 0 6px #4ade80; } .hud-chip .c.blips { background: var(--magenta); box-shadow: 0 0 6px var(--magenta); } + .hud-chip .c.news { background: var(--magenta); box-shadow: 0 0 6px var(--magenta); border-radius: 1px; transform: rotate(45deg); } .hud-chip.off { opacity: 0.4; } #dvr-bar { position: absolute; left: 50%; bottom: 12px; transform: translateX(-50%); @@ -319,6 +320,7 @@ .lp-dot.fires { background: #fb923c; box-shadow: 0 0 7px #fb923c; } .lp-dot.cams { background: #4ade80; box-shadow: 0 0 7px #4ade80; } .lp-dot.blips { background: var(--magenta); box-shadow: 0 0 7px var(--magenta); } + .lp-dot.news { background: var(--magenta); box-shadow: 0 0 7px var(--magenta); border-radius: 1px; transform: rotate(45deg); } .lp-dot.weather { background: var(--amber); box-shadow: 0 0 7px var(--amber); } .lp-dot.flights { background: #7dd3fc; box-shadow: 0 0 7px #7dd3fc; } .lp-dot.vessels { background: #2dd4bf; box-shadow: 0 0 7px #2dd4bf; } @@ -724,6 +726,13 @@
Geolocated events from the ingest pipeline. Color = source type.
+
+
+ + 0 +
+
LLM-estimated locations from the hourly brief. Pins only for critical/high.
+
@@ -804,6 +813,7 @@
FIRMS
CAMS
BLIPS
+
NEWS
@@ -1204,6 +1214,7 @@ function showView(name) { if (firesOn) loadFires(); if (camsOn) loadCams(); if (blipsOn) loadBlips(); + if (newsOn) loadNewsPins(); } } if (name === 'news') loadNews(false); @@ -1762,6 +1773,7 @@ async function saveSummaryModel() { let map = null, mapLayer = null, mapInitStarted = false; let firesHeat = null, camsGroup = null, firesOn = false, camsOn = false; let blipsGroup = null, blipsOn = false, blipsSince = '24h'; +let newsGroup = null, newsOn = false, newsReq = 0; let firesOpacity = 0.65, firesColor = 'brightness', firesSince = '24h'; let camsOpacity = 1.0, baseOpacity = 1.0; let camReq = 0, fireReq = 0, blipReq = 0; // stale-response guards (rapid zoom races) @@ -1954,6 +1966,7 @@ async function initMap() { if (firesOn) loadFires(); if (camsOn) loadCams(); if (blipsOn) loadBlips(); + if (newsOn) loadNewsPins(); refreshLiveOverlays(); sendLiveViewport(); }, 500); @@ -1965,6 +1978,7 @@ async function initMap() { firesOn = document.getElementById('lp-fires-on').checked; camsOn = document.getElementById('lp-cams-on').checked; blipsOn = document.getElementById('lp-blips-on').checked; + newsOn = document.getElementById('lp-news-on').checked; firesSince = document.getElementById('lp-fires-since').value; blipsSince = document.getElementById('lp-blips-since').value; radarOn = document.getElementById('lp-radar-on').checked; @@ -1979,6 +1993,7 @@ async function initMap() { if (firesOn) loadFires(); if (camsOn) loadCams(); if (blipsOn) loadBlips(); + if (newsOn) loadNewsPins(); refreshLiveOverlays(); connectLiveWs(); } catch(e) { @@ -2001,8 +2016,9 @@ function syncHud() { set('fires', firesOn ? (hudFiresCount) : '—', firesOn); set('cams', camsOn ? (hudCamsCount) : '—', camsOn); set('blips', blipsOn ? (hudBlipsCount) : '—', blipsOn); + set('news', newsOn ? (hudNewsCount) : '—', newsOn); } -let hudFiresCount = null, hudCamsCount = null, hudBlipsCount = null; +let hudFiresCount = null, hudCamsCount = null, hudBlipsCount = null, hudNewsCount = null; function setMapAttribution(text) { if (!map) return; @@ -2417,6 +2433,57 @@ async function loadBlips() { } } +/* ── CRITICAL NEWS (LLM-estimated locations, critical/high only) ── */ +async function toggleNewsPins() { + newsOn = document.getElementById('lp-news-on').checked; + if (newsOn) { + await loadNewsPins(); + return; + } + newsReq++; + if (newsGroup && map) { map.removeLayer(newsGroup); newsGroup = null; } + hudNewsCount = null; + const countEl = document.getElementById('lp-news-count'); + if (countEl) countEl.textContent = '0'; + syncHud(); +} +async function loadNewsPins() { + if (!map) return; + const req = ++newsReq; + try { + const url = `${API}/api/news/map?bbox=${currentBBox()}&limit=200`; + const r = await overlayFetch(url); + const data = await r.json(); + if (req !== newsReq) return; // superseded by a newer pan/zoom + const items = Array.isArray(data) ? data : []; + if (newsGroup) map.removeLayer(newsGroup); + const col = '#ff2e97'; + const pins = items.filter(it => Number.isFinite(Number(it.lat)) && Number.isFinite(Number(it.lon))); + newsGroup = L.layerGroup(pins.map(it => { + const icon = L.divIcon({ + className: '', + html: ``, + iconSize: [14, 14], iconAnchor: [7, 7], + }); + return L.marker([it.lat, it.lon], { icon }) + .bindPopup(`
` + + `
◈ ${esc(it.importance || '')}${it.category ? ' · ' + esc(it.category) : ''}
` + + `${esc(it.headline || '')}` + + `
${esc(it.location_name || '')}
` + + (it.url ? `source ↗` : '') + + `
`); + })); + newsGroup.addTo(map); + document.getElementById('lp-news-count').textContent = pins.length.toLocaleString(); + hudNewsCount = pins.length; + syncHud(); + } catch(e) { + if (isAbort(e)) return; + document.getElementById('map-hint').textContent = `News pins load failed: ${e.message || e}`; + console.error('News pins load failed', e); + } +} + /* ── Live overlays (radar / alerts / WFIGS / aircraft / trains / AIS / NHC) ── */ function refreshLiveOverlays() { if (!map) return;