移除未使用的 Groq 和 Meteoblue 服务代码及配置

This commit is contained in:
2569718930@qq.com
2026-05-19 00:05:07 +08:00
parent 19bd8f3636
commit b93a75516d
28 changed files with 215 additions and 1417 deletions
-137
View File
@@ -2,7 +2,6 @@ import { Locale } from "@/lib/i18n";
import {
AiAnalysisStructured,
CityDetail,
HistoryPoint,
NearbyStation,
} from "@/lib/dashboard-types";
import {
@@ -1715,142 +1714,6 @@ export function getShortTermNowcastLines(
return rows;
}
export function getHistorySummary(
history: HistoryPoint[],
cityLocalDate?: string | null,
) {
const toFinite = (value: unknown): number | null => {
const numeric = Number(value);
return Number.isFinite(numeric) ? numeric : null;
};
const isExcludedModel = (name: string) =>
String(name || "").toLowerCase().includes("meteoblue");
const cutoff = new Date();
cutoff.setHours(0, 0, 0, 0);
cutoff.setDate(cutoff.getDate() - 14);
const recentData = history.filter((row) => {
if (!row?.date) return false;
const rowDate = new Date(`${row.date}T00:00:00`);
return !Number.isNaN(rowDate.getTime()) && rowDate >= cutoff;
});
const settledData = recentData.filter((row) => {
if (!row?.date) return false;
return cityLocalDate
? row.date < cityLocalDate
: row.date < new Date().toISOString().slice(0, 10);
});
const comparableSettledData = settledData.filter((row) => {
const actual = toFinite(row.actual);
const deb = toFinite(row.deb);
return actual != null && deb != null;
});
let hits = 0;
const debErrors: number[] = [];
const modelErrors: Record<string, number[]> = {};
comparableSettledData.forEach((row) => {
const actual = toFinite(row.actual);
const deb = toFinite(row.deb);
if (actual == null || deb == null) return;
debErrors.push(Math.abs(actual - deb));
if (wuRound(actual) === wuRound(deb)) {
hits += 1;
}
const forecasts = row.forecasts || {};
Object.entries(forecasts).forEach(([modelName, modelValue]) => {
if (isExcludedModel(modelName)) return;
const mv = toFinite(modelValue);
if (actual == null || mv == null) return;
if (!modelErrors[modelName]) {
modelErrors[modelName] = [];
}
modelErrors[modelName].push(Math.abs(actual - mv));
});
});
const modelMaeList = Object.entries(modelErrors)
.map(([name, errors]) => ({
mae:
errors.length > 0
? errors.reduce((sum, value) => sum + value, 0) / errors.length
: Number.POSITIVE_INFINITY,
model: name,
sampleCount: errors.length,
}))
.filter((row) => Number.isFinite(row.mae) && row.sampleCount > 0)
.sort((a, b) => a.mae - b.mae);
const primaryModelMaeList = modelMaeList.filter((row) => row.sampleCount >= 2);
const bestModel = (primaryModelMaeList[0] || modelMaeList[0]) ?? null;
const bestModelName = bestModel?.model || null;
const bestModelMae = bestModel ? Number(bestModel.mae.toFixed(1)) : null;
const bestModelSeries = recentData.map((row) =>
bestModelName ? toFinite(row.forecasts?.[bestModelName]) : null,
);
let debWinDaysVsBest = 0;
let debVsBestComparableDays = 0;
if (bestModelName) {
comparableSettledData.forEach((row) => {
const actual = toFinite(row.actual);
const deb = toFinite(row.deb);
const bestModelVal = toFinite(row.forecasts?.[bestModelName]);
if (actual == null || deb == null || bestModelVal == null) return;
debVsBestComparableDays += 1;
if (Math.abs(deb - actual) <= Math.abs(bestModelVal - actual)) {
debWinDaysVsBest += 1;
}
});
}
const mgmSettledCount = settledData.reduce((count, row) => {
return toFinite(row.mgm) != null ? count + 1 : count;
}, 0);
const mgmSeriesComplete =
settledData.length >= 2 && mgmSettledCount === settledData.length;
const mgmSeries = mgmSeriesComplete
? recentData.map((row) => row.mgm ?? null)
: recentData.map(() => null);
return {
dates: recentData.map((row) => row.date),
debMae: debErrors.length
? Number(
(
debErrors.reduce((sum, value) => sum + value, 0) / debErrors.length
).toFixed(1),
)
: null,
debs: recentData.map((row) => row.deb),
bestModelName,
bestModelMae,
bestModelSeries,
modelMaeRanks: modelMaeList.map((row) => ({
model: row.model,
mae: Number(row.mae.toFixed(1)),
sampleCount: row.sampleCount,
})),
debWinDaysVsBest,
debVsBestComparableDays,
debWinRateVsBest:
debVsBestComparableDays > 0
? Number(((debWinDaysVsBest / debVsBestComparableDays) * 100).toFixed(0))
: null,
hitRate: debErrors.length
? Number(((hits / debErrors.length) * 100).toFixed(0))
: null,
mgmSeriesComplete,
mgms: mgmSeries,
recentData,
settledCount: comparableSettledData.length,
actuals: recentData.map((row) => row.actual),
};
}
function toFiniteNumber(value: unknown): number | null {
const numeric = Number(value);