Added sources
Browse files- app/dashboard.py +56 -0
- app/intel_panel.py +12 -1
app/dashboard.py
CHANGED
|
@@ -325,6 +325,62 @@ def build_dashboard() -> pn.Column:
|
|
| 325 |
sizing_mode="stretch_width",
|
| 326 |
),
|
| 327 |
region_grid,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 328 |
pn.Spacer(),
|
| 329 |
|
| 330 |
sizing_mode="stretch_height",
|
|
|
|
| 325 |
sizing_mode="stretch_width",
|
| 326 |
),
|
| 327 |
region_grid,
|
| 328 |
+
_divider(),
|
| 329 |
+
|
| 330 |
+
pn.Card(
|
| 331 |
+
pn.pane.HTML(
|
| 332 |
+
f"""
|
| 333 |
+
<table style="width:100%;border-collapse:collapse;
|
| 334 |
+
font-family:'Courier New',monospace;font-size:11px;color:#94a3b8;">
|
| 335 |
+
<tbody>
|
| 336 |
+
<tr><td style="padding:4px 4px 4px 0;color:#e2e8f0;">GDELT</td>
|
| 337 |
+
<td style="padding:4px 0;">Conflict & news events</td></tr>
|
| 338 |
+
<tr><td style="padding:4px 4px 4px 0;color:#e2e8f0;">NASA FIRMS</td>
|
| 339 |
+
<td style="padding:4px 0;">Satellite fire hotspots</td></tr>
|
| 340 |
+
<tr><td style="padding:4px 4px 4px 0;color:#e2e8f0;">OpenSky</td>
|
| 341 |
+
<td style="padding:4px 0;">Live flight tracking</td></tr>
|
| 342 |
+
<tr><td style="padding:4px 4px 4px 0;color:#e2e8f0;">NOAA</td>
|
| 343 |
+
<td style="padding:4px 0;">Weather alerts</td></tr>
|
| 344 |
+
<tr><td style="padding:4px 4px 4px 0;color:#e2e8f0;">AIS Stream</td>
|
| 345 |
+
<td style="padding:4px 0;">Maritime tracking</td></tr>
|
| 346 |
+
<tr><td style="padding:4px 4px 4px 0;color:#e2e8f0;">USGS</td>
|
| 347 |
+
<td style="padding:4px 0;">Seismic events</td></tr>
|
| 348 |
+
<tr><td style="padding:4px 4px 4px 0;color:#e2e8f0;">AlienVault OTX</td>
|
| 349 |
+
<td style="padding:4px 0;">Cyber threats</td></tr>
|
| 350 |
+
<tr><td style="padding:4px 4px 4px 0;color:#e2e8f0;">Yahoo Finance</td>
|
| 351 |
+
<td style="padding:4px 0;">Commodities & stocks</td></tr>
|
| 352 |
+
<tr><td style="padding:4px 4px 4px 0;color:#e2e8f0;">ExchangeRate.host</td>
|
| 353 |
+
<td style="padding:4px 0;">Live FX rates</td></tr>
|
| 354 |
+
<tr><td style="padding:4px 4px 4px 0;color:#e2e8f0;">Google News RSS</td>
|
| 355 |
+
<td style="padding:4px 0;">Regional headlines</td></tr>
|
| 356 |
+
<tr><td style="padding:4px 4px 4px 0;color:#e2e8f0;">Gemini</td>
|
| 357 |
+
<td style="padding:4px 0;">AI Explorer LLM</td></tr>
|
| 358 |
+
</tbody>
|
| 359 |
+
</table>
|
| 360 |
+
<div style="margin-top:8px;font-size:10px;color:#475569;font-family:'Courier New',monospace;">
|
| 361 |
+
All free & open — no paid subscriptions.
|
| 362 |
+
</div>
|
| 363 |
+
""",
|
| 364 |
+
sizing_mode="stretch_width",
|
| 365 |
+
),
|
| 366 |
+
title="About Data",
|
| 367 |
+
collapsed=True,
|
| 368 |
+
sizing_mode="stretch_width",
|
| 369 |
+
styles={"background": _PANEL_BG},
|
| 370 |
+
header_color=_ACCENT,
|
| 371 |
+
stylesheets=[f"""
|
| 372 |
+
:host .card-header {{
|
| 373 |
+
background: {_PANEL_BG};
|
| 374 |
+
border-bottom: 1px solid {_BORDER};
|
| 375 |
+
font-family: 'Courier New', monospace;
|
| 376 |
+
font-size: 11px;
|
| 377 |
+
font-weight: bold;
|
| 378 |
+
letter-spacing: 1px;
|
| 379 |
+
text-transform: uppercase;
|
| 380 |
+
padding: 6px 10px;
|
| 381 |
+
}}
|
| 382 |
+
"""],
|
| 383 |
+
),
|
| 384 |
pn.Spacer(),
|
| 385 |
|
| 386 |
sizing_mode="stretch_height",
|
app/intel_panel.py
CHANGED
|
@@ -144,6 +144,7 @@ def build_currency_tab() -> pn.Column:
|
|
| 144 |
try:
|
| 145 |
codes = FX_REGION_GROUPS.get(region, [])
|
| 146 |
fx = load_fx_live(codes).sort_values("change_pct")
|
|
|
|
| 147 |
clim = max(abs(float(fx["change_pct"].min())),
|
| 148 |
abs(float(fx["change_pct"].max())), 0.01)
|
| 149 |
h = max(260, len(codes) * 32)
|
|
@@ -152,7 +153,9 @@ def build_currency_tab() -> pn.Column:
|
|
| 152 |
c="change_pct", cmap="RdYlGn",
|
| 153 |
clim=(-clim, clim), colorbar=False,
|
| 154 |
xlim=(-clim, clim),
|
| 155 |
-
|
|
|
|
|
|
|
| 156 |
responsive=True, height=h, grid=True, fontscale=0.9,
|
| 157 |
)
|
| 158 |
return pn.pane.HoloViews(chart, sizing_mode="stretch_both", min_height=h)
|
|
@@ -172,6 +175,14 @@ def build_currency_tab() -> pn.Column:
|
|
| 172 |
),
|
| 173 |
styles={"padding": "0 16px 12px"},
|
| 174 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
pn.panel(live_pane, sizing_mode="stretch_both"),
|
| 176 |
sizing_mode="stretch_both",
|
| 177 |
styles={"background": _BG},
|
|
|
|
| 144 |
try:
|
| 145 |
codes = FX_REGION_GROUPS.get(region, [])
|
| 146 |
fx = load_fx_live(codes).sort_values("change_pct")
|
| 147 |
+
fx["Change (%)"] = fx["change_pct"].map(lambda x: f"{x:+.3f}%")
|
| 148 |
clim = max(abs(float(fx["change_pct"].min())),
|
| 149 |
abs(float(fx["change_pct"].max())), 0.01)
|
| 150 |
h = max(260, len(codes) * 32)
|
|
|
|
| 153 |
c="change_pct", cmap="RdYlGn",
|
| 154 |
clim=(-clim, clim), colorbar=False,
|
| 155 |
xlim=(-clim, clim),
|
| 156 |
+
hover_cols=["Change (%)"],
|
| 157 |
+
xlabel="1-day % change vs USD",
|
| 158 |
+
ylabel="",
|
| 159 |
responsive=True, height=h, grid=True, fontscale=0.9,
|
| 160 |
)
|
| 161 |
return pn.pane.HoloViews(chart, sizing_mode="stretch_both", min_height=h)
|
|
|
|
| 175 |
),
|
| 176 |
styles={"padding": "0 16px 12px"},
|
| 177 |
),
|
| 178 |
+
pn.pane.HTML(
|
| 179 |
+
f'<div style="font-size:11px;color:{_MUTED};font-family:\'Courier New\',monospace;'
|
| 180 |
+
f'padding:0 16px 8px;">'
|
| 181 |
+
f'🟢 positive = USD strengthened (local currency weakened) · '
|
| 182 |
+
f'🔴 negative = USD weakened (local currency strengthened)'
|
| 183 |
+
f'</div>',
|
| 184 |
+
sizing_mode="stretch_width",
|
| 185 |
+
),
|
| 186 |
pn.panel(live_pane, sizing_mode="stretch_both"),
|
| 187 |
sizing_mode="stretch_both",
|
| 188 |
styles={"background": _BG},
|