Add LightGBM daily high forecasting pipeline

This commit is contained in:
2569718930@qq.com
2026-03-29 23:29:17 +08:00
parent 4a2db4727b
commit 0cc4f4f0d3
25 changed files with 3038 additions and 82 deletions
+33 -3
View File
@@ -4,7 +4,7 @@ import { startTransition, useEffect, useMemo, useState } from "react";
import clsx from "clsx";
import { useDashboardStore } from "@/hooks/useDashboardStore";
import { useI18n } from "@/hooks/useI18n";
import { CityListItem } from "@/lib/dashboard-types";
import { CityListItem, DeviationMonitor } from "@/lib/dashboard-types";
type RiskGroupKey = "high" | "medium" | "low" | "other";
@@ -50,7 +50,7 @@ function normalizeExpandedGroups(
export function CitySidebar() {
const store = useDashboardStore();
const { t } = useI18n();
const { locale, t } = useI18n();
const selectedCity = store.selectedCity;
const riskOrder = { high: 0, medium: 1, low: 2, other: 3 };
const [expandedGroups, setExpandedGroups] = useState<
@@ -114,6 +114,16 @@ export function CitySidebar() {
} catch {}
}, [expandedGroups]);
const formatDeviationText = (monitor?: DeviationMonitor | null) => {
if (!monitor?.available) return "";
const label =
locale === "en-US" ? monitor.label_en : monitor.label_zh;
const trendLabel =
locale === "en-US" ? monitor.trend_label_en : monitor.trend_label_zh;
if (!label) return "";
return trendLabel ? `${label} · ${trendLabel}` : label;
};
const groupMeta: Array<{ key: RiskGroupKey; label: string }> = [
{ key: "high", label: t("sidebar.group.high") },
{ key: "medium", label: t("sidebar.group.medium") },
@@ -172,6 +182,9 @@ export function CitySidebar() {
temp: `${snapshot.current.temp}${tempSymbol}`,
})
: t("common.na");
const deviationText = formatDeviationText(
snapshot?.deviation_monitor,
);
const peakTempText =
detail?.current?.max_so_far != null &&
detail.current.max_temp_time
@@ -182,6 +195,11 @@ export function CitySidebar() {
: detail?.current?.max_temp_time
? t("sidebar.peakAt", { time: detail.current.max_temp_time })
: "";
const deviationDirection =
snapshot?.deviation_monitor?.direction || "normal";
const deviationSeverity =
snapshot?.deviation_monitor?.severity || "normal";
const secondaryText = deviationText || peakTempText;
return (
<button
@@ -211,7 +229,19 @@ export function CitySidebar() {
<span className="city-local-time">
{snapshot?.local_time ? `🕒 ${snapshot.local_time}` : ""}
</span>
<span className="city-max-info">{peakTempText}</span>
<span
className={clsx(
"city-max-info",
deviationText && "city-deviation-info",
deviationText &&
`city-deviation-${deviationDirection}`,
deviationText &&
deviationSeverity === "strong" &&
"strong",
)}
>
{secondaryText}
</span>
</div>
</button>
);
@@ -488,6 +488,30 @@
font-weight: 500;
}
.root :global(.city-item .city-deviation-info) {
font-weight: 600;
}
.root :global(.city-item .city-deviation-cold) {
color: #38bdf8;
}
.root :global(.city-item .city-deviation-hot) {
color: #f59e0b;
}
.root :global(.city-item .city-deviation-normal) {
color: #22d3ee;
}
.root :global(.city-item .city-deviation-info.strong) {
text-shadow: 0 0 10px rgba(56, 189, 248, 0.18);
}
.root :global(.city-item .city-deviation-hot.strong) {
text-shadow: 0 0 10px rgba(245, 158, 11, 0.24);
}
.root :global(.city-item .risk-dot) {
width: 10px;
height: 10px;
+1
View File
@@ -74,6 +74,7 @@ export function toCitySummary(detail: CityDetail): CitySummary {
deb: {
prediction: detail.deb?.prediction,
},
deviation_monitor: detail.deviation_monitor,
risk: {
level: detail.risk?.level,
warning: detail.risk?.warning,
+102 -34
View File
@@ -58,40 +58,6 @@ const CITY_SPECIFIC_SOURCES: Record<string, OfficialSourceLink[]> = {
kind: "metar",
},
],
"shek kong": [
{
label: "香港天文台",
href: "https://www.hko.gov.hk/en/index.html",
kind: "agency",
},
{
label: "HKO 区域天气数据",
href: "https://data.weather.gov.hk/weatherAPI/hko_data/regional-weather/latest_1min_temperature.csv",
kind: "agency",
},
{
label: "VHSK Timeseries",
href: "https://www.weather.gov/wrh/timeseries?site=VHSK",
kind: "metar",
},
],
"lau fau shan": [
{
label: "香港天文台",
href: "https://www.hko.gov.hk/en/index.html",
kind: "agency",
},
{
label: "HKO 区域天气数据",
href: "https://data.weather.gov.hk/weatherAPI/hko_data/regional-weather/latest_1min_temperature.csv",
kind: "agency",
},
{
label: "HKO 实时读数页",
href: "https://www.hko.gov.hk/textonly/v2/forecast/text_readings_e.htm",
kind: "agency",
},
],
taipei: [
{
label: "NOAA RCTP Timeseries",
@@ -150,6 +116,108 @@ const CITY_SPECIFIC_SOURCES: Record<string, OfficialSourceLink[]> = {
kind: "metar",
},
],
"los angeles": [
{
label: "NWS Los Angeles/Oxnard",
href: "https://www.weather.gov/lox/",
kind: "agency",
},
{
label: "LAX Airport",
href: "https://www.flylax.com/",
kind: "airport",
},
{
label: "KLAX METAR",
href: "https://aviationweather.gov/data/metar/?id=KLAX&decoded=1&taf=1",
kind: "metar",
},
],
"san francisco": [
{
label: "NWS San Francisco Bay Area",
href: "https://www.weather.gov/mtr/",
kind: "agency",
},
{
label: "SFO Airport",
href: "https://www.flysfo.com/",
kind: "airport",
},
{
label: "KSFO METAR",
href: "https://aviationweather.gov/data/metar/?id=KSFO&decoded=1&taf=1",
kind: "metar",
},
],
aurora: [
{
label: "NWS Denver/Boulder",
href: "https://www.weather.gov/bou/",
kind: "agency",
},
{
label: "Buckley Space Force Base",
href: "https://www.buckley.spaceforce.mil/",
kind: "airport",
},
{
label: "KBKF METAR",
href: "https://aviationweather.gov/data/metar/?id=KBKF&decoded=1&taf=1",
kind: "metar",
},
],
austin: [
{
label: "NWS Austin/San Antonio",
href: "https://www.weather.gov/ewx/",
kind: "agency",
},
{
label: "Austin-Bergstrom Airport",
href: "https://www.austintexas.gov/airport",
kind: "airport",
},
{
label: "KAUS METAR",
href: "https://aviationweather.gov/data/metar/?id=KAUS&decoded=1&taf=1",
kind: "metar",
},
],
houston: [
{
label: "NWS Houston/Galveston",
href: "https://www.weather.gov/hgx/",
kind: "agency",
},
{
label: "William P. Hobby Airport",
href: "https://www.fly2houston.com/hobby",
kind: "airport",
},
{
label: "KHOU METAR",
href: "https://aviationweather.gov/data/metar/?id=KHOU&decoded=1&taf=1",
kind: "metar",
},
],
"mexico city": [
{
label: "SMN",
href: "https://smn.conagua.gob.mx/",
kind: "agency",
},
{
label: "AICM",
href: "https://www.aicm.com.mx/",
kind: "airport",
},
{
label: "MMMX METAR",
href: "https://aviationweather.gov/data/metar/?id=MMMX&decoded=1&taf=1",
kind: "metar",
},
],
ankara: [
{
label: "MGM",
+15
View File
@@ -162,6 +162,7 @@ export interface CitySummary {
deb?: {
prediction?: number | null;
};
deviation_monitor?: DeviationMonitor;
risk?: {
level?: RiskLevel;
warning?: string | null;
@@ -169,6 +170,19 @@ export interface CitySummary {
updated_at?: string | null;
}
export interface DeviationMonitor {
available?: boolean;
current_delta?: number | null;
reference_temp?: number | null;
direction?: "normal" | "cold" | "hot" | string;
severity?: "normal" | "light" | "strong" | string;
trend?: "stable" | "expanding" | "contracting" | string;
label_zh?: string | null;
label_en?: string | null;
trend_label_zh?: string | null;
trend_label_en?: string | null;
}
export interface HourlySeries {
times?: string[];
temps?: Array<number | null>;
@@ -301,6 +315,7 @@ export interface CityDetail {
forecast?: ForecastData;
multi_model?: Record<string, number | null>;
deb?: DebForecast;
deviation_monitor?: DeviationMonitor;
probabilities?: {
mu?: number | null;
distribution?: ProbabilityBucket[];
+1
View File
@@ -186,6 +186,7 @@ export interface ModelComparison {
ICON?: number;
GEM?: number;
JMA?: number;
LGBM?: number;
MGM?: number;
NWS?: number;
}