gpt-5.4-mini @ medium · api

apimedium
config
gpt-5.4-mini-eff-medium--api--official--dev
batch
2026-07-19--unified
transport
openai-official-api
protocol
api · metered
served model
gpt-5.4-mini-2026-03-17
采集于
2026年7月18日 11:54 · N=4
variant
live
slot 0 · P-q · sandboxed iframe
gpt-5.4-mini @medium · api P-q slot 0 截图

截图是 similarity 通道测量时的原始像素。运行 live 会在 sandboxed iframe 中重新执行原始输出;渲染结果取决于你的浏览器和字体,不保证与测量像素一致。

similarity 邻居

限于 session 2026-07-19--unified

similarity 衡量本 session 内的趋同程度 —— 不是质量。

Fidelity —— 卡片展示的数据对不对?

  • namenot-foundtext-present-no-name-hit
  • conditionmismatchother-wmo-code
  • datenot-foundno-parseable-date
  • max tempnot-foundno-temperature-candidate
  • min tempnot-foundno-temperature-candidate
  • hourlynot-foundcoverage · 0 命中 · 0 不符 · 24 未展示
  • request sidematch0 处违规

extractor fidelity-extractor-v1+Berlin-2026-07-15

源码 —— 原始模型输出,一字节未改

下载 card.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Weather Card</title>
  <style>
    :root{
      --bg0:#07101f;
      --bg1:#0b1630;
      --bg2:#0f1f3e;
      --card:rgba(10, 18, 36, 0.66);
      --card-strong:rgba(12, 20, 41, 0.82);
      --stroke:rgba(255,255,255,0.12);
      --stroke-strong:rgba(255,255,255,0.18);
      --text:#f4f7ff;
      --muted:#9fb0d0;
      --muted2:#7285a8;
      --accent1:#7ad7ff;
      --accent2:#7f7bff;
      --accent3:#93f0d2;
      --shadow:0 24px 80px rgba(0,0,0,.42);
      --bar-fill:linear-gradient(180deg, rgba(255,255,255,.95), rgba(255,255,255,.68));
      --bar-glow:rgba(255,255,255,.14);
      --theme-label:rgba(255,255,255,.08);
    }

    *{box-sizing:border-box}
    html,body{height:100%}
    body{
      margin:0;
      overflow:hidden;
      font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      color:var(--text);
      background:
        radial-gradient(1200px 700px at 15% 10%, rgba(114, 168, 255, 0.22), transparent 55%),
        radial-gradient(1000px 600px at 85% 18%, rgba(149, 104, 255, 0.18), transparent 52%),
        radial-gradient(900px 600px at 65% 90%, rgba(64, 193, 255, 0.12), transparent 58%),
        linear-gradient(145deg, var(--bg0), var(--bg1) 48%, var(--bg2));
    }

    body::before,
    body::after{
      content:"";
      position:fixed;
      inset:auto;
      pointer-events:none;
      filter: blur(18px);
      opacity:.8;
    }
    body::before{
      width:420px;
      height:420px;
      left:-120px;
      top:-100px;
      background: radial-gradient(circle at 30% 30%, rgba(122, 215, 255, .28), rgba(122, 215, 255, 0) 70%);
    }
    body::after{
      width:520px;
      height:520px;
      right:-180px;
      bottom:-170px;
      background: radial-gradient(circle at 50% 50%, rgba(127, 123, 255, .22), rgba(127, 123, 255, 0) 68%);
    }

    .shell{
      position:relative;
      z-index:1;
      width:100%;
      height:100%;
      display:grid;
      place-items:center;
      padding:20px;
    }

    .card{
      width:min(1160px, calc(100vw - 40px));
      height:min(740px, calc(100vh - 40px));
      border:1px solid var(--stroke);
      border-radius:30px;
      background:
        linear-gradient(180deg, rgba(255,255,255,.08), rgba(255,255,255,.02)),
        linear-gradient(160deg, rgba(11,18,34,.84), rgba(9,14,28,.72));
      box-shadow:var(--shadow);
      backdrop-filter: blur(18px);
      -webkit-backdrop-filter: blur(18px);
      overflow:hidden;
      position:relative;
    }

    .card::before{
      content:"";
      position:absolute;
      inset:0;
      background:
        radial-gradient(650px 240px at 16% 0%, rgba(255,255,255,.11), transparent 58%),
        radial-gradient(560px 240px at 86% 8%, rgba(122,215,255,.11), transparent 56%),
        linear-gradient(180deg, rgba(255,255,255,.04), transparent 24%);
      pointer-events:none;
    }

    .inner{
      position:relative;
      z-index:1;
      height:100%;
      display:grid;
      grid-template-rows:auto 1fr;
      padding:26px;
      gap:22px;
    }

    .topbar{
      display:flex;
      align-items:flex-start;
      justify-content:space-between;
      gap:18px;
    }

    .brand{
      display:flex;
      align-items:center;
      gap:12px;
      min-width:0;
    }

    .dot{
      width:14px;
      height:14px;
      border-radius:999px;
      background:linear-gradient(135deg, var(--accent1), var(--accent2));
      box-shadow:0 0 0 6px rgba(255,255,255,.05), 0 0 30px rgba(122,215,255,.34);
      flex:0 0 auto;
    }

    .brand-copy{
      display:flex;
      flex-direction:column;
      gap:3px;
      min-width:0;
    }

    .kicker{
      text-transform:uppercase;
      letter-spacing:.28em;
      color:var(--muted2);
      font-size:11px;
      font-weight:700;
      line-height:1;
    }

    .headline{
      font-size:18px;
      font-weight:700;
      line-height:1.1;
      white-space:nowrap;
      overflow:hidden;
      text-overflow:ellipsis;
    }

    .status{
      display:flex;
      align-items:center;
      gap:10px;
      flex-wrap:wrap;
      justify-content:flex-end;
    }

    .pill{
      display:inline-flex;
      align-items:center;
      gap:8px;
      padding:10px 14px;
      border-radius:999px;
      background:rgba(255,255,255,.06);
      border:1px solid var(--stroke);
      color:var(--text);
      font-size:13px;
      font-weight:600;
      letter-spacing:.01em;
      box-shadow:inset 0 1px 0 rgba(255,255,255,.06);
      white-space:nowrap;
    }

    .pill.subtle{
      color:var(--muted);
      font-weight:500;
      background:rgba(255,255,255,.04);
    }

    .content{
      display:grid;
      grid-template-columns: 350px minmax(0, 1fr);
      gap:22px;
      min-height:0;
    }

    .panel{
      border:1px solid var(--stroke);
      background:
        linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.02)),
        rgba(6, 10, 20, 0.24);
      border-radius:24px;
      box-shadow:inset 0 1px 0 rgba(255,255,255,.04);
      overflow:hidden;
      min-height:0;
    }

    .summary{
      display:flex;
      flex-direction:column;
      padding:22px;
      gap:18px;
    }

    .icon-wrap{
      display:flex;
      align-items:center;
      gap:18px;
    }

    .icon-badge{
      width:96px;
      height:96px;
      border-radius:26px;
      background:
        radial-gradient(circle at 30% 24%, rgba(255,255,255,.16), transparent 56%),
        linear-gradient(160deg, rgba(255,255,255,.10), rgba(255,255,255,.04));
      border:1px solid rgba(255,255,255,.14);
      box-shadow:0 16px 34px rgba(0,0,0,.18), inset 0 1px 0 rgba(255,255,255,.06);
      display:grid;
      place-items:center;
      flex:0 0 auto;
      position:relative;
      overflow:hidden;
    }

    .icon-badge::after{
      content:"";
      position:absolute;
      inset:auto -20% -36% -20%;
      height:65%;
      background:linear-gradient(180deg, transparent, rgba(255,255,255,.12));
      transform:rotate(-8deg);
    }

    .icon-badge svg{
      width:66px;
      height:66px;
      position:relative;
      z-index:1;
    }

    .location{
      min-width:0;
      flex:1;
      display:flex;
      flex-direction:column;
      gap:8px;
    }

    .location h1{
      margin:0;
      font-size:33px;
      line-height:1.02;
      letter-spacing:-0.04em;
      white-space:nowrap;
      overflow:hidden;
      text-overflow:ellipsis;
    }

    .date-line{
      display:flex;
      flex-wrap:wrap;
      gap:8px 10px;
      align-items:center;
      color:var(--muted);
      font-size:14px;
      font-weight:500;
    }

    .date-line .iso{
      color:var(--muted2);
      font-variant-numeric: tabular-nums;
    }

    .summary-stack{
      display:grid;
      gap:14px;
    }

    .range-card{
      padding:18px 18px 16px;
      border-radius:20px;
      background:linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.03));
      border:1px solid rgba(255,255,255,.10);
    }

    .range-label{
      color:var(--muted);
      font-size:12px;
      text-transform:uppercase;
      letter-spacing:.18em;
      margin-bottom:10px;
      font-weight:700;
    }

    .range-value{
      display:flex;
      align-items:flex-end;
      gap:10px;
      margin-bottom:6px;
    }

    .max-temp{
      font-size:60px;
      font-weight:800;
      letter-spacing:-0.06em;
      line-height:0.9;
      background: linear-gradient(180deg, #ffffff, rgba(255,255,255,.72));
      -webkit-background-clip:text;
      background-clip:text;
      color:transparent;
      font-variant-numeric: tabular-nums;
    }

    .min-temp{
      font-size:25px;
      font-weight:700;
      color:var(--muted);
      letter-spacing:-0.03em;
      margin-bottom:8px;
      font-variant-numeric: tabular-nums;
    }

    .condition{
      font-size:16px;
      color:var(--text);
      font-weight:600;
      line-height:1.35;
    }

    .meta-grid{
      display:grid;
      grid-template-columns:1fr 1fr;
      gap:12px;
    }

    .meta{
      padding:14px 16px;
      border-radius:18px;
      background:rgba(255,255,255,.04);
      border:1px solid rgba(255,255,255,.09);
    }

    .meta .label{
      display:block;
      font-size:11px;
      text-transform:uppercase;
      letter-spacing:.18em;
      color:var(--muted2);
      margin-bottom:7px;
      font-weight:700;
    }

    .meta .value{
      font-size:14px;
      font-weight:600;
      color:var(--text);
      line-height:1.35;
      font-variant-numeric: tabular-nums;
    }

    .chart{
      display:flex;
      flex-direction:column;
      padding:22px 22px 18px;
      gap:16px;
      min-height:0;
    }

    .chart-head{
      display:flex;
      align-items:flex-start;
      justify-content:space-between;
      gap:14px;
    }

    .chart-title{
      display:flex;
      flex-direction:column;
      gap:5px;
    }

    .chart-title h2{
      margin:0;
      font-size:18px;
      letter-spacing:-0.02em;
      line-height:1.2;
    }

    .chart-title p{
      margin:0;
      color:var(--muted);
      font-size:13px;
      line-height:1.35;
    }

    .legend{
      display:flex;
      align-items:center;
      gap:8px;
      color:var(--muted);
      font-size:12px;
      white-space:nowrap;
      padding-top:4px;
    }

    .legend-swatch{
      width:12px;
      height:12px;
      border-radius:999px;
      background:linear-gradient(135deg, var(--accent1), var(--accent2));
      box-shadow:0 0 18px rgba(122,215,255,.25);
    }

    .hourly-grid{
      position:relative;
      display:grid;
      grid-template-columns:repeat(24, minmax(0, 1fr));
      gap:8px;
      min-height:0;
      align-items:end;
      flex:1;
      padding:14px 10px 10px;
      border-radius:22px;
      background:
        linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,255,255,.02)),
        rgba(255,255,255,.02);
      border:1px solid rgba(255,255,255,.08);
      overflow:hidden;
    }

    .hour-cell{
      display:flex;
      flex-direction:column;
      justify-content:flex-end;
      align-items:center;
      gap:8px;
      height:100%;
      min-height:0;
      padding:6px 0;
    }

    .hour-top,
    .hour-temp{
      width:100%;
      text-align:center;
      font-variant-numeric: tabular-nums;
      line-height:1;
      white-space:nowrap;
      overflow:hidden;
      text-overflow:ellipsis;
    }

    .hour-top{
      font-size:11px;
      color:var(--muted2);
      font-weight:700;
      letter-spacing:.07em;
    }

    .hour-temp{
      font-size:12px;
      color:var(--text);
      font-weight:700;
    }

    .bar-track{
      position:relative;
      width:100%;
      height:246px;
      border-radius:14px;
      display:flex;
      align-items:flex-end;
      justify-content:center;
      padding:8px 0;
      background:linear-gradient(180deg, rgba(255,255,255,.025), rgba(255,255,255,.01));
      overflow:hidden;
    }

    .bar-track::before{
      content:"";
      position:absolute;
      inset:0;
      background:
        linear-gradient(180deg, transparent 0, transparent calc(100% - 1px), rgba(255,255,255,.08) calc(100% - 1px), rgba(255,255,255,.08) 100%);
      opacity:.35;
      pointer-events:none;
    }

    .bar-fill{
      width:78%;
      border-radius:10px 10px 4px 4px;
      background:
        linear-gradient(180deg, rgba(255,255,255,.95), rgba(255,255,255,.72));
      box-shadow:0 0 22px var(--bar-glow);
      position:relative;
      min-height:4px;
      transition:height .35s ease;
    }

    .bar-fill::after{
      content:"";
      position:absolute;
      inset:auto 0 0 0;
      height:100%;
      border-radius:inherit;
      background:linear-gradient(180deg, rgba(255,255,255,.24), transparent);
      pointer-events:none;
    }

    .footer-note{
      display:flex;
      justify-content:space-between;
      align-items:center;
      gap:12px;
      color:var(--muted2);
      font-size:12px;
      padding-top:2px;
    }

    .footer-note strong{
      color:var(--muted);
      font-weight:600;
    }

    .loading,
    .error-state{
      position:absolute;
      inset:0;
      display:grid;
      place-items:center;
      padding:24px;
      text-align:center;
    }

    .loading-card,
    .error-card{
      width:min(560px, 100%);
      border-radius:24px;
      padding:28px;
      border:1px solid rgba(255,255,255,.12);
      background:rgba(7, 12, 24, .70);
      box-shadow:var(--shadow);
      backdrop-filter: blur(16px);
    }

    .spinner{
      width:42px;
      height:42px;
      border-radius:50%;
      margin:0 auto 16px;
      border:3px solid rgba(255,255,255,.14);
      border-top-color:rgba(255,255,255,.86);
      animation:spin 0.9s linear infinite;
    }

    @keyframes spin{to{transform:rotate(360deg)}}

    .loading-card h2,
    .error-card h2{
      margin:0 0 8px;
      font-size:22px;
      letter-spacing:-0.02em;
    }

    .loading-card p,
    .error-card p{
      margin:0;
      color:var(--muted);
      line-height:1.5;
      font-size:14px;
    }

    .error-card{
      border-color:rgba(255, 120, 120, .22);
      background:rgba(33, 10, 18, .68);
    }

    @media (max-width: 1100px){
      .card{height:auto; min-height:calc(100vh - 40px)}
      .content{grid-template-columns:1fr}
      body{overflow:auto}
    }
  </style>
</head>
<body>
  <div class="shell">
    <main class="card" id="card" aria-live="polite">
      <div class="inner" id="app">
        <div class="topbar">
          <div class="brand">
            <div class="dot" aria-hidden="true"></div>
            <div class="brand-copy">
              <div class="kicker">Weather card</div>
              <div class="headline" id="headline">Loading weather…</div>
            </div>
          </div>
          <div class="status">
            <div class="pill subtle" id="sourcePill">UTC</div>
            <div class="pill" id="endpointPill">Fetching</div>
          </div>
        </div>

        <div class="content">
          <section class="panel summary" aria-label="Weather summary">
            <div class="icon-wrap">
              <div class="icon-badge" id="iconBadge" aria-hidden="true"></div>
              <div class="location">
                <h1 id="locationName">Berlin</h1>
                <div class="date-line">
                  <span id="humanDate">Today</span>
                  <span class="iso" id="isoDate">2026-01-01</span>
                </div>
              </div>
            </div>

            <div class="summary-stack">
              <div class="range-card">
                <div class="range-label">Daily temperatures</div>
                <div class="range-value">
                  <div class="max-temp" id="maxTemp">—</div>
                </div>
                <div class="min-temp" id="minTemp">—</div>
                <div class="condition" id="conditionText">Weather data will appear here.</div>
              </div>

              <div class="meta-grid">
                <div class="meta">
                  <span class="label">Coordinates</span>
                  <div class="value" id="coordsText">—</div>
                </div>
                <div class="meta">
                  <span class="label">Source</span>
                  <div class="value" id="sourceText">—</div>
                </div>
                <div class="meta">
                  <span class="label">Latitude</span>
                  <div class="value" id="latText">—</div>
                </div>
                <div class="meta">
                  <span class="label">Longitude</span>
                  <div class="value" id="lonText">—</div>
                </div>
              </div>
            </div>
          </section>

          <section class="panel chart" aria-label="Hourly temperatures">
            <div class="chart-head">
              <div class="chart-title">
                <h2>Hourly temperatures</h2>
                <p>UTC, one value per hour for the requested date.</p>
              </div>
              <div class="legend"><span class="legend-swatch"></span> temperature</div>
            </div>

            <div class="hourly-grid" id="hourlyGrid"></div>

            <div class="footer-note">
              <div><strong>Weather condition:</strong> <span id="conditionSmall">—</span></div>
              <div><strong>Date:</strong> <span id="dateSmall">—</span></div>
            </div>
          </section>
        </div>
      </div>

      <div class="loading" id="loadingState">
        <div class="loading-card">
          <div class="spinner" aria-hidden="true"></div>
          <h2>Loading weather data</h2>
          <p>Fetching a single-day forecast or archive in UTC.</p>
        </div>
      </div>
    </main>
  </div>

  <script>
    (function () {
      const defaultLat = 52.52;
      const defaultLon = 13.405;
      const defaultName = "Berlin";

      const qs = new URLSearchParams(location.search);

      function parseNumber(v, fallback) {
        const n = Number.parseFloat(v);
        return Number.isFinite(n) ? n : fallback;
      }

      function isValidISODate(v) {
        return /^\d{4}-\d{2}-\d{2}$/.test(v) && !Number.isNaN(Date.parse(v + "T00:00:00Z"));
      }

      function todayUTC() {
        return new Date().toISOString().slice(0, 10);
      }

      const lat = parseNumber(qs.get("lat"), defaultLat);
      const lon = parseNumber(qs.get("lon"), defaultLon);
      const name = (qs.get("name") || defaultName).trim() || defaultName;
      const date = isValidISODate(qs.get("date") || "") ? qs.get("date") : todayUTC();
      const utcToday = todayUTC();
      const endpoint = date < utcToday ? "/api/om/archive" : "/api/om/forecast";

      const els = {
        card: document.getElementById("card"),
        app: document.getElementById("app"),
        loading: document.getElementById("loadingState"),
        headline: document.getElementById("headline"),
        sourcePill: document.getElementById("sourcePill"),
        endpointPill: document.getElementById("endpointPill"),
        iconBadge: document.getElementById("iconBadge"),
        locationName: document.getElementById("locationName"),
        humanDate: document.getElementById("humanDate"),
        isoDate: document.getElementById("isoDate"),
        maxTemp: document.getElementById("maxTemp"),
        minTemp: document.getElementById("minTemp"),
        conditionText: document.getElementById("conditionText"),
        conditionSmall: document.getElementById("conditionSmall"),
        coordsText: document.getElementById("coordsText"),
        sourceText: document.getElementById("sourceText"),
        latText: document.getElementById("latText"),
        lonText: document.getElementById("lonText"),
        hourlyGrid: document.getElementById("hourlyGrid"),
        dateSmall: document.getElementById("dateSmall")
      };

      document.title = `${name} — Weather`;

      function setTheme(kind) {
        const themes = {
          sunny: ["#ffd66b", "#ff9f47", "#ffecad"],
          partly: ["#8fd5ff", "#7a7cff", "#d7f0ff"],
          cloudy: ["#91a6c7", "#708ab2", "#d2def1"],
          foggy: ["#b7c2d9", "#8fa0bf", "#e5edf8"],
          rainy: ["#73b8ff", "#5a77ff", "#d8ecff"],
          snowy: ["#8ef0ff", "#6dc3ff", "#e0fbff"],
          stormy: ["#a48bff", "#664aff", "#eadfff"]
        };
        const t = themes[kind] || themes.cloudy;
        document.documentElement.style.setProperty("--accent1", t[0]);
        document.documentElement.style.setProperty("--accent2", t[1]);
        document.documentElement.style.setProperty("--accent3", t[2]);
        document.documentElement.style.setProperty("--bar-glow", hexToRgba(t[0], 0.22));
      }

      function hexToRgba(hex, alpha) {
        const h = hex.replace("#", "");
        const bigint = parseInt(h.length === 3 ? h.split("").map(ch => ch + ch).join("") : h, 16);
        const r = (bigint >> 16) & 255;
        const g = (bigint >> 8) & 255;
        const b = bigint & 255;
        return `rgba(${r}, ${g}, ${b}, ${alpha})`;
      }

      function fmtTemp(n) {
        if (!Number.isFinite(n)) return "—";
        const rounded = Math.round(n * 10) / 10;
        return `${Number.isInteger(rounded) ? rounded.toFixed(0) : rounded.toFixed(1)}°C`;
      }

      function fmtHour(iso) {
        const d = new Date(iso);
        if (Number.isNaN(d.getTime())) return "--";
        return String(d.getUTCHours()).padStart(2, "0");
      }

      function formatFullDate(iso) {
        const d = new Date(`${iso}T00:00:00Z`);
        if (Number.isNaN(d.getTime())) return iso;
        return new Intl.DateTimeFormat("en-US", {
          weekday: "long",
          year: "numeric",
          month: "long",
          day: "numeric",
          timeZone: "UTC"
        }).format(d);
      }

      function weatherMeta(code) {
        const c = Number(code);
        const common = { kind: "cloudy", label: "Unknown conditions", icon: cloudySvg() };

        if (c === 0) return { kind: "sunny", label: "Clear sky", icon: sunSvg() };
        if (c === 1) return { kind: "partly", label: "Mainly clear", icon: partlySvg() };
        if (c === 2) return { kind: "partly", label: "Partly cloudy", icon: partlySvg() };
        if (c === 3) return { kind: "cloudy", label: "Overcast", icon: cloudSvg() };
        if (c === 45 || c === 48) return { kind: "foggy", label: c === 45 ? "Fog" : "Depositing rime fog", icon: fogSvg() };
        if ([51, 53, 55, 56, 57, 61, 63, 65, 66, 67, 80, 81, 82].includes(c)) {
          return { kind: "rainy", label: rainLabel(c), icon: rainSvg() };
        }
        if ([71, 73, 75, 77, 85, 86].includes(c)) {
          return { kind: "snowy", label: snowLabel(c), icon: snowSvg() };
        }
        if ([95, 96, 99].includes(c)) return { kind: "stormy", label: stormLabel(c), icon: stormSvg() };

        return common;
      }

      function rainLabel(c) {
        if ([51, 53, 55].includes(c)) return "Drizzle";
        if ([56, 57].includes(c)) return "Freezing drizzle";
        if ([61, 63, 65].includes(c)) return "Rain";
        if ([66, 67].includes(c)) return "Freezing rain";
        return [80, 81, 82].includes(c) ? "Rain showers" : "Rain";
      }

      function snowLabel(c) {
        if ([71, 73, 75].includes(c)) return "Snow fall";
        if (c === 77) return "Snow grains";
        return "Snow showers";
      }

      function stormLabel(c) {
        if (c === 95) return "Thunderstorm";
        if (c === 96) return "Thunderstorm with slight hail";
        return "Thunderstorm with hail";
      }

      function sunSvg() {
        return `
          <svg viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
            <circle cx="48" cy="48" r="16" fill="rgba(255,255,255,.18)" stroke="rgba(255,255,255,.95)" stroke-width="3"/>
            <g stroke="rgba(255,255,255,.95)" stroke-width="3" stroke-linecap="round">
              <path d="M48 13v10"/>
              <path d="M48 73v10"/>
              <path d="M13 48h10"/>
              <path d="M73 48h10"/>
              <path d="M24 24l7 7"/>
              <path d="M65 65l7 7"/>
              <path d="M24 72l7-7"/>
              <path d="M65 31l7-7"/>
            </g>
          </svg>`;
      }

      function partlySvg() {
        return `
          <svg viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
            <g opacity=".95">
              <circle cx="35" cy="35" r="13" fill="rgba(255,255,255,.18)" stroke="rgba(255,255,255,.95)" stroke-width="3"/>
              <g stroke="rgba(255,255,255,.95)" stroke-width="3" stroke-linecap="round">
                <path d="M35 13v8"/>
                <path d="M35 49v8"/>
                <path d="M13 35h8"/>
                <path d="M49 35h8"/>
                <path d="M20 20l6 6"/>
                <path d="M44 44l6 6"/>
                <path d="M20 50l6-6"/>
                <path d="M44 26l6-6"/>
              </g>
            </g>
            <path d="M31 69h29c8.2 0 14.5-5.8 14.5-13.3S68.2 42.4 60 42.4c-2.2 0-4.3.5-6.2 1.3C51 39 45.8 36 40 36c-9.8 0-17.7 7-18.5 16.1C15 53.3 10.5 58.6 10.5 65c0 6 4.9 11 11 11H31"
                  fill="rgba(255,255,255,.14)" stroke="rgba(255,255,255,.95)" stroke-width="3.2" stroke-linejoin="round"/>
          </svg>`;
      }

      function cloudSvg() {
        return `
          <svg viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
            <path d="M29 69h35c10 0 18-7 18-16.5S74 36 64 36c-2.8 0-5.4.6-7.8 1.7C53.6 31.1 46.7 26.5 38.7 26.5c-12.2 0-22.1 9.2-22.8 20.7C9.5 49.3 5 54.8 5 61.5 5 67.8 10 73 16.2 73H29"
                  fill="rgba(255,255,255,.16)" stroke="rgba(255,255,255,.95)" stroke-width="3.2" stroke-linejoin="round"/>
          </svg>`;
      }

      function rainSvg() {
        return `
          <svg viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
            <path d="M26 55h32c10 0 18-7 18-16.5S72 22 62 22c-2.8 0-5.4.6-7.8 1.7C51.6 17.1 44.7 12.5 36.7 12.5c-12.2 0-22.1 9.2-22.8 20.7C6.5 35.3 2 40.8 2 47.5 2 53.8 7 59 13.2 59H26"
                  fill="rgba(255,255,255,.14)" stroke="rgba(255,255,255,.95)" stroke-width="3.2" stroke-linejoin="round"/>
            <g stroke="rgba(122,215,255,.98)" stroke-width="3.5" stroke-linecap="round">
              <path d="M28 66l-4 10"/>
              <path d="M46 66l-4 10"/>
              <path d="M64 66l-4 10"/>
            </g>
          </svg>`;
      }

      function snowSvg() {
        return `
          <svg viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
            <path d="M26 52h32c10 0 18-7 18-16.5S72 19 62 19c-2.8 0-5.4.6-7.8 1.7C51.6 14.1 44.7 9.5 36.7 9.5c-12.2 0-22.1 9.2-22.8 20.7C6.5 32.3 2 37.8 2 44.5 2 50.8 7 56 13.2 56H26"
                  fill="rgba(255,255,255,.14)" stroke="rgba(255,255,255,.95)" stroke-width="3.2" stroke-linejoin="round"/>
            <g stroke="rgba(155, 240, 255, .98)" stroke-width="3" stroke-linecap="round">
              <path d="M28 66v12"/>
              <path d="M22 72h12"/>
              <path d="M44 66v12"/>
              <path d="M38 72h12"/>
              <path d="M60 66v12"/>
              <path d="M54 72h12"/>
            </g>
          </svg>`;
      }

      function fogSvg() {
        return `
          <svg viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
            <path d="M26 40c0-9 7.3-16.3 16.3-16.3 7.2 0 13.3 4.6 15.6 11 1.3-.4 2.8-.6 4.2-.6 7.7 0 13.9 6.2 13.9 13.9S69.8 62 62.1 62H24.6C15.9 62 9 55.1 9 46.4 9 39.4 14.1 33.5 20.9 32.2c1.2-7 6.9-12.2 14-12.2"
                  fill="rgba(255,255,255,.12)" stroke="rgba(255,255,255,.92)" stroke-width="3.1" stroke-linejoin="round"/>
            <g stroke="rgba(255,255,255,.9)" stroke-width="3.4" stroke-linecap="round" opacity=".9">
              <path d="M18 72h60"/>
              <path d="M24 82h48"/>
              <path d="M14 62h68"/>
            </g>
          </svg>`;
      }

      function stormSvg() {
        return `
          <svg viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
            <path d="M26 54h32c10 0 18-7 18-16.5S72 21 62 21c-2.8 0-5.4.6-7.8 1.7C51.6 16.1 44.7 11.5 36.7 11.5c-12.2 0-22.1 9.2-22.8 20.7C6.5 34.3 2 39.8 2 46.5 2 52.8 7 58 13.2 58H26"
                  fill="rgba(255,255,255,.14)" stroke="rgba(255,255,255,.95)" stroke-width="3.2" stroke-linejoin="round"/>
            <path d="M42 59l-7 14h8l-4 13 15-19h-9l4-8"
                  fill="rgba(255, 221, 105, .9)" stroke="rgba(255,255,255,.92)" stroke-width="1.6" stroke-linejoin="round"/>
          </svg>`;
      }

      function renderHourly(hourly, minTemp, maxTemp) {
        const times = Array.isArray(hourly?.time) ? hourly.time : [];
        const temps = Array.isArray(hourly?.temperature_2m) ? hourly.temperature_2m : [];
        const count = Math.min(times.length, temps.length, 24);
        const pad = Math.max(1.5, (maxTemp - minTemp) * 0.16);
        const lo = minTemp - pad;
        const hi = maxTemp + pad;
        const range = Math.max(0.0001, hi - lo);

        els.hourlyGrid.innerHTML = "";

        for (let i = 0; i < count; i++) {
          const t = Number(temps[i]);
          const norm = Math.min(100, Math.max(0, ((t - lo) / range) * 100));
          const hour = fmtHour(times[i]);
          const fullLabel = `${hour}:00 — ${fmtTemp(t)}`;

          const cell = document.createElement("div");
          cell.className = "hour-cell";
          cell.title = fullLabel;
          cell.innerHTML = `
            <div class="hour-top">${hour}</div>
            <div class="bar-track">
              <div class="bar-fill" style="height:${Math.max(4, norm)}%;"></div>
            </div>
            <div class="hour-temp">${fmtTemp(t)}</div>
          `;
          els.hourlyGrid.appendChild(cell);
        }

        for (let i = count; i < 24; i++) {
          const cell = document.createElement("div");
          cell.className = "hour-cell";
          cell.innerHTML = `
            <div class="hour-top">--</div>
            <div class="bar-track"><div class="bar-fill" style="height:4%;opacity:.25"></div></div>
            <div class="hour-temp">—</div>
          `;
          els.hourlyGrid.appendChild(cell);
        }
      }

      function showError(message) {
        document.getElementById("loadingState").style.display = "none";
        els.app.innerHTML = `
          <div class="topbar">
            <div class="brand">
              <div class="dot" aria-hidden="true"></div>
              <div class="brand-copy">
                <div class="kicker">Weather card</div>
                <div class="headline">Weather unavailable</div>
              </div>
            </div>
            <div class="status">
              <div class="pill subtle">UTC</div>
              <div class="pill">Error</div>
            </div>
          </div>
          <div class="error-state">
            <div class="error-card">
              <h2>Could not load weather data</h2>
              <p>${escapeHtml(message || "The weather service returned no usable data.")}</p>
            </div>
          </div>
        `;
      }

      function escapeHtml(str) {
        return String(str)
          .replaceAll("&", "&amp;")
          .replaceAll("<", "&lt;")
          .replaceAll(">", "&gt;")
          .replaceAll('"', "&quot;")
          .replaceAll("'", "&#39;");
      }

      async function main() {
        try {
          const url = new URL(endpoint, location.origin);
          const sp = url.searchParams;
          sp.set("latitude", String(lat));
          sp.set("longitude", String(lon));
          sp.set("daily", "temperature_2m_max,temperature_2m_min,weather_code");
          sp.set("hourly", "temperature_2m");
          sp.set("timezone", "UTC");
          sp.set("temperature_unit", "celsius");
          sp.set("start_date", date);
          sp.set("end_date", date);

          els.endpointPill.textContent = endpoint.includes("archive") ? "Archive" : "Forecast";
          els.sourceText.textContent = endpoint;
          els.coordsText.textContent = `${lat.toFixed(3)}, ${lon.toFixed(3)}`;
          els.latText.textContent = lat.toFixed(3);
          els.lonText.textContent = lon.toFixed(3);
          els.locationName.textContent = name;
          els.humanDate.textContent = formatFullDate(date);
          els.isoDate.textContent = date;
          els.dateSmall.textContent = date;
          els.sourcePill.textContent = "UTC";

          const controller = new AbortController();
          const timeout = setTimeout(() => controller.abort(), 12000);

          const res = await fetch(url.toString(), {
            signal: controller.signal,
            headers: { "Accept": "application/json" }
          });

          clearTimeout(timeout);

          if (!res.ok) throw new Error(`Weather request failed with status ${res.status}.`);

          const data = await res.json();

          const daily = data && data.daily;
          const hourly = data && data.hourly;
          const max = daily?.temperature_2m_max?.[0];
          const min = daily?.temperature_2m_min?.[0];
          const code = daily?.weather_code?.[0];

          if (!Number.isFinite(max) || !Number.isFinite(min) || !hourly) {
            throw new Error("Weather response was missing the expected temperature data.");
          }

          const meta = weatherMeta(code);
          setTheme(meta.kind);

          document.body.style.background =
            `radial-gradient(1200px 700px at 15% 10%, ${hexToRgba(getComputedStyle(document.documentElement).getPropertyValue('--accent1').trim() || '#7ad7ff', 0.20)}, transparent 55%),
             radial-gradient(1000px 600px at 85% 18%, ${hexToRgba(getComputedStyle(document.documentElement).getPropertyValue('--accent2').trim() || '#7f7bff', 0.16)}, transparent 52%),
             radial-gradient(900px 600px at 65% 90%, rgba(64, 193, 255, 0.12), transparent 58%),
             linear-gradient(145deg, var(--bg0), var(--bg1) 48%, var(--bg2))`;

          els.loading.style.display = "none";
          els.headline.textContent = `${name} — ${date}`;
          els.iconBadge.innerHTML = meta.icon;
          els.maxTemp.textContent = fmtTemp(max);
          els.minTemp.textContent = `Low ${fmtTemp(min)}`;
          els.conditionText.textContent = meta.label;
          els.conditionSmall.textContent = meta.label;
          els.endpointPill.textContent = endpoint.includes("archive") ? "Archive" : "Forecast";

          const latlon = `${lat.toFixed(3)}, ${lon.toFixed(3)}`;
          els.coordsText.textContent = latlon;
          els.sourceText.textContent = endpoint;
          els.latText.textContent = lat.toFixed(3);
          els.lonText.textContent = lon.toFixed(3);

          renderHourly(hourly, min, max);
        } catch (err) {
          showError(err && err.message ? err.message : "The weather data could not be loaded.");
        }
      }

      main();
    })();
  </script>
</body>
</html>

L1 —— 廉价的确定性描述量

bytes 总计34,284html / css / js3,664 / 13,281 / 17,339
dom 节点69dom 深度11
css 规则72含 js
brightness33.2contrast13.7
colorfulness16.7留白82.8%

该 slot 的 telemetry

prompt tokens312completion tokens23,897
total tokens24,209wall115.8 s
costrequest id
config.json587 B
{
  "N": 4,
  "auth": {
    "credential_ref": "WCB_OPENAI_OFFICIAL_KEY",
    "method": "api-key"
  },
  "billing": "metered",
  "config_id": "gpt-5.4-mini-eff-medium--api--official--dev",
  "effort": "medium",
  "family": "gpt",
  "m": {
    "min": 4,
    "q": 4
  },
  "model_id": "gpt-5.4-mini",
  "protocol": "api",
  "served_model": "gpt-5.4-mini-2026-03-17",
  "telemetry": {
    "completion_tokens": 157566,
    "cost_usd": null,
    "prompt_tokens": 2464,
    "total_tokens": 160030,
    "wall_ms": 787555
  },
  "transport": "openai-official-api",
  "vendor_sanction_ref": null
}
send-log4.7 KB
{
  "N": 4,
  "batch_id": "2026-07-18--official-gpt",
  "config_id": "gpt-5.4-mini-eff-medium--api--official--dev",
  "positions": [
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-17T19:56:15.902123+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-17T19:55:23.564159+00:00"
        }
      ],
      "block_index": 0,
      "model_reaching_attempt_index": 0,
      "slot_index": 0,
      "terminal_state": "valid",
      "variant": "P-min"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-17T19:58:15.219380+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-17T19:56:19.467255+00:00"
        }
      ],
      "block_index": 0,
      "model_reaching_attempt_index": 0,
      "slot_index": 0,
      "terminal_state": "valid",
      "variant": "P-q"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-17T19:59:22.708375+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-17T19:58:19.604412+00:00"
        }
      ],
      "block_index": 1,
      "model_reaching_attempt_index": 0,
      "slot_index": 1,
      "terminal_state": "valid",
      "variant": "P-min"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-17T20:02:13.259618+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-17T19:59:26.127010+00:00"
        }
      ],
      "block_index": 1,
      "model_reaching_attempt_index": 0,
      "slot_index": 1,
      "terminal_state": "valid",
      "variant": "P-q"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-17T20:05:04.153718+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-17T20:02:17.042142+00:00"
        }
      ],
      "block_index": 2,
      "model_reaching_attempt_index": 0,
      "slot_index": 2,
      "terminal_state": "valid",
      "variant": "P-q"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-17T20:06:53.882894+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-17T20:05:07.580138+00:00"
        }
      ],
      "block_index": 2,
      "model_reaching_attempt_index": 0,
      "slot_index": 2,
      "terminal_state": "valid",
      "variant": "P-min"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-17T20:08:00.901075+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-17T20:06:57.743819+00:00"
        }
      ],
      "block_index": 3,
      "model_reaching_attempt_index": 0,
      "slot_index": 3,
      "terminal_state": "valid",
      "variant": "P-q"
    },
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-17T20:08:57.206266+00:00",
          "http_status": 200,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-17T20:08:04.538786+00:00"
        }
      ],
      "block_index": 3,
      "model_reaching_attempt_index": 0,
      "slot_index": 3,
      "terminal_state": "valid",
      "variant": "P-min"
    }
  ],
  "retry_policy": {
    "max_unreachable_retries": 5,
    "rate_limit_backoff": {
      "max_attempts": 4,
      "max_total_ms": 60000
    }
  }
}