"use client"; import { useEffect, useState } from "react"; import { RefreshCcw } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { opsApi } from "@/lib/ops-api"; import type { SystemStatusPayload } from "@/types/ops"; import Link from "next/link"; function StatRow({ label, value }: { label: string; value: React.ReactNode }) { return (
{label} {value}
); } interface CityAccuracy { city_id: string; name: string; deb?: { hit_rate: number; mae: number; total_days: number; details_str: string; } | null; mu?: { mae: number; hit_rate: number; brier_score: number | null; total_days: number; details_str: string; } | null; } export function TrainingPageClient() { const [loading, setLoading] = useState(true); const [status, setStatus] = useState(null); const [accuracy, setAccuracy] = useState(null); const load = async () => { setLoading(true); try { const [s, accData] = await Promise.all([ opsApi.systemStatus() as Promise, opsApi.trainingAccuracy().catch(() => ({ accuracy: [] })) ]); setStatus(s); setAccuracy(accData.accuracy); } catch { /* */ } setLoading(false); }; useEffect(() => { void load(); }, []); if (loading) return
加载中...
; if (!status) return
加载失败
; const td = status.training_data; const truth = td?.truth_records; const features = td?.training_features; const coverage = td?.city_coverage; const modelCities = td?.model_cities; return (

训练数据

真值记录 训练特征 城市覆盖
{modelCities ? (
最强城市 {modelCities.strongest?.length ? (
    {modelCities.strongest.map((c, i) => (
  • {c.city} 真值:{c.truth_rows ?? "—"} 特征:{c.feature_rows ?? "—"}
  • ))}
) : 无数据}
覆盖缺口 {modelCities.gaps?.length ? (
{modelCities.gaps.map((c) => ( {c} ))}
) : 无缺口}
) : null} 模型融合与预测准确率效果 (DEB & 概率引擎)
{accuracy && accuracy.length > 0 ? ( accuracy.map((row) => ( )) ) : ( )}
城市 DEB 结算命中 DEB MAE DEB 天数 概率 μ 结算命中 概率 μ MAE Brier Score 概率天数
{row.name} {row.city_id} {row.deb ? ( = 80 ? "bg-green-500/15 text-green-400" : row.deb.hit_rate >= 60 ? "bg-yellow-500/15 text-yellow-400" : "bg-red-500/15 text-red-400" }`}> {row.deb.hit_rate.toFixed(0)}% ) : ( )} {row.deb ? `${row.deb.mae.toFixed(1)}°` : "—"} {row.deb ? row.deb.total_days : "—"} {row.mu ? ( = 80 ? "bg-green-500/15 text-green-400" : row.mu.hit_rate >= 60 ? "bg-yellow-500/15 text-yellow-400" : "bg-red-500/15 text-red-400" }`}> {row.mu.hit_rate.toFixed(0)}% ) : ( )} {row.mu ? `${row.mu.mae.toFixed(1)}°` : "—"} {row.mu && row.mu.brier_score !== null ? ( {row.mu.brier_score.toFixed(3)} ) : ( "—" )} {row.mu ? row.mu.total_days : "—"}
无有效准确率记录,请确认 daily_records.json 中已有历史结算数据。
真值历史浏览

按城市和日期筛选查看历史真值记录。

打开真值历史 →
); }