gpt-5.4-mini @ high · cursor
cursorhigh
- config
- gpt-5.4-mini-eff-high--cli--cursor--dev
- batch
- 2026-07-19--unified
- transport
- cursor-agent-cli-isolated-home
- protocol
- cli · plan
- served model
- gpt-5.4-mini-high
- 采集于
- 2026年7月18日 11:54 · N=2
variant
live
slot 0 · P-q · sandboxed iframe

截图是 similarity 通道测量时的原始像素。运行 live 会在 sandboxed iframe 中重新执行原始输出;渲染结果取决于你的浏览器和字体,不保证与测量像素一致。
similarity 邻居本 session 没有 similarity 数据 —— 这个 batch 没有计算 pairs。
Fidelity —— 卡片展示的数据对不对?
- namematch
- conditionmatch
- datematch
- max tempambiguousinsufficient-distinct-temperature-nodes
- min tempambiguousinsufficient-distinct-temperature-nodes
- hourlyambiguouscoverage · 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" />
<meta name="color-scheme" content="dark" />
<title>Weather Card</title>
<style>
:root {
--accent-1: #8fd3ff;
--accent-2: #678dff;
--accent-3: #8b63ff;
--accent-rgb: 143, 211, 255;
--accent2-rgb: 103, 141, 255;
--accent3-rgb: 139, 99, 255;
--bg: #08101f;
--panel: rgba(11, 17, 33, 0.72);
--panel-strong: rgba(13, 19, 38, 0.88);
--text: #eef3ff;
--muted: rgba(235, 242, 255, 0.72);
--muted-2: rgba(235, 242, 255, 0.5);
--border: rgba(255, 255, 255, 0.11);
--border-soft: rgba(255, 255, 255, 0.07);
--shadow: rgba(0, 0, 0, 0.38);
}
* {
box-sizing: border-box;
}
html, body {
width: 100%;
height: 100%;
}
body {
margin: 0;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: var(--text);
background:
radial-gradient(circle at 12% 16%, rgba(var(--accent-rgb), 0.18), transparent 28%),
radial-gradient(circle at 82% 18%, rgba(var(--accent2-rgb), 0.14), transparent 24%),
radial-gradient(circle at 52% 92%, rgba(var(--accent3-rgb), 0.12), transparent 26%),
linear-gradient(145deg, #050914 0%, #09101d 38%, #0d1428 72%, #11193a 100%);
overflow: hidden;
}
.scene {
position: relative;
min-height: 100%;
display: grid;
place-items: center;
padding: 32px;
isolation: isolate;
}
.grid-overlay {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.035) 1px, transparent 1px);
background-size: 56px 56px;
mask-image: radial-gradient(circle at center, black 0%, black 58%, transparent 100%);
opacity: 0.45;
pointer-events: none;
z-index: -2;
}
.orb {
position: absolute;
border-radius: 999px;
filter: blur(18px);
pointer-events: none;
opacity: 0.9;
z-index: -1;
}
.orb.one {
width: 360px;
height: 360px;
left: -90px;
top: 72px;
background: radial-gradient(circle, rgba(var(--accent-rgb), 0.32) 0%, rgba(var(--accent-rgb), 0.02) 72%, transparent 78%);
}
.orb.two {
width: 300px;
height: 300px;
right: 72px;
top: 30px;
background: radial-gradient(circle, rgba(var(--accent2-rgb), 0.24) 0%, rgba(var(--accent2-rgb), 0.02) 72%, transparent 78%);
}
.orb.three {
width: 420px;
height: 420px;
right: 120px;
bottom: -160px;
background: radial-gradient(circle, rgba(var(--accent3-rgb), 0.18) 0%, rgba(var(--accent3-rgb), 0.02) 72%, transparent 78%);
}
.card {
position: relative;
width: min(1180px, calc(100vw - 48px));
min-height: 708px;
padding: 30px;
border-radius: 32px;
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.03)),
var(--panel);
border: 1px solid var(--border);
box-shadow:
0 34px 90px var(--shadow),
inset 0 1px 0 rgba(255, 255, 255, 0.08);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
overflow: hidden;
}
.card::before {
content: "";
position: absolute;
inset: 0;
background:
radial-gradient(circle at 16% 14%, rgba(var(--accent-rgb), 0.12), transparent 24%),
radial-gradient(circle at 84% 12%, rgba(255, 255, 255, 0.06), transparent 22%),
linear-gradient(135deg, rgba(255, 255, 255, 0.03), transparent 45%);
pointer-events: none;
}
.header {
position: relative;
z-index: 1;
margin-bottom: 26px;
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
border-radius: 999px;
border: 1px solid rgba(var(--accent-rgb), 0.32);
background: rgba(var(--accent-rgb), 0.08);
color: rgba(245, 248, 255, 0.86);
font-size: 12px;
letter-spacing: 0.18em;
text-transform: uppercase;
}
.title-row {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 20px;
margin-top: 18px;
}
h1 {
margin: 0;
font-size: clamp(44px, 5vw, 66px);
line-height: 0.96;
letter-spacing: -0.06em;
text-wrap: balance;
}
.date-label {
margin: 12px 0 0;
font-size: 18px;
line-height: 1.35;
color: var(--muted);
}
.submeta {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 18px;
}
.chip {
display: inline-flex;
align-items: center;
gap: 8px;
min-height: 38px;
padding: 0 14px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border-soft);
color: rgba(242, 247, 255, 0.84);
font-size: 13px;
letter-spacing: 0.02em;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
.source-pill {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 40px;
padding: 0 14px;
border-radius: 999px;
border: 1px solid rgba(var(--accent-rgb), 0.28);
background: rgba(var(--accent-rgb), 0.08);
color: rgba(248, 251, 255, 0.9);
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.16em;
white-space: nowrap;
}
.content {
position: relative;
z-index: 1;
display: grid;
grid-template-columns: 360px 1fr;
gap: 22px;
align-items: stretch;
}
.summary-panel,
.hourly-panel {
border-radius: 28px;
border: 1px solid var(--border-soft);
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.03)),
var(--panel-strong);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.05),
0 18px 40px rgba(0, 0, 0, 0.18);
}
.summary-panel {
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 24px;
min-height: 560px;
overflow: hidden;
}
.icon-shell {
width: 184px;
height: 184px;
border-radius: 42px;
display: grid;
place-items: center;
background:
radial-gradient(circle at 28% 24%, rgba(255, 255, 255, 0.12), transparent 35%),
linear-gradient(180deg, rgba(var(--accent-rgb), 0.16), rgba(255, 255, 255, 0.03));
border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.08),
0 22px 45px rgba(0, 0, 0, 0.18);
}
.icon-shell svg {
width: 132px;
height: 132px;
overflow: visible;
filter: drop-shadow(0 18px 24px rgba(0, 0, 0, 0.28));
}
.summary-copy {
margin-top: 22px;
}
.big-temp {
margin: 0;
font-size: clamp(58px, 6vw, 86px);
line-height: 0.92;
letter-spacing: -0.07em;
font-weight: 700;
font-variant-numeric: tabular-nums;
background: linear-gradient(90deg, var(--accent-1), #ffffff 72%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
text-wrap: balance;
}
.condition {
margin-top: 10px;
font-size: 22px;
line-height: 1.25;
color: rgba(244, 248, 255, 0.92);
text-wrap: balance;
}
.detail-note {
margin-top: 10px;
color: var(--muted-2);
font-size: 14px;
line-height: 1.5;
}
.stats {
display: grid;
gap: 12px;
margin-top: 26px;
}
.stat {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
min-height: 54px;
padding: 0 16px;
border-radius: 18px;
background: rgba(6, 11, 22, 0.42);
border: 1px solid rgba(255, 255, 255, 0.06);
}
.stat span {
font-size: 13px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: rgba(236, 242, 255, 0.62);
}
.stat strong {
font-size: 20px;
line-height: 1;
font-variant-numeric: tabular-nums;
}
.hourly-panel {
display: flex;
flex-direction: column;
min-height: 560px;
padding: 22px;
}
.section-head {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 18px;
margin-bottom: 18px;
}
.section-head h2 {
margin: 0;
font-size: 28px;
line-height: 1;
letter-spacing: -0.04em;
}
.section-head p {
margin: 8px 0 0;
color: var(--muted);
font-size: 14px;
line-height: 1.45;
}
.legend {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 10px 14px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border-soft);
color: rgba(243, 247, 255, 0.82);
font-size: 13px;
white-space: nowrap;
}
.legend-swatch {
width: 14px;
height: 14px;
border-radius: 50%;
background: linear-gradient(180deg, var(--accent-1), var(--accent-2));
box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.12);
}
.chart-shell {
flex: 1;
min-height: 0;
border-radius: 22px;
background: rgba(5, 10, 20, 0.28);
border: 1px solid rgba(255, 255, 255, 0.05);
padding: 14px 10px 10px;
overflow: auto;
scrollbar-color: rgba(var(--accent-rgb), 0.55) rgba(255, 255, 255, 0.06);
scrollbar-width: thin;
}
.chart {
display: grid;
grid-template-columns: repeat(24, minmax(38px, 1fr));
gap: 10px;
min-width: 980px;
align-items: end;
padding: 0 4px 8px;
}
.hour {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
gap: 8px;
min-height: 100%;
min-width: 0;
text-align: center;
color: rgba(243, 247, 255, 0.86);
font-variant-numeric: tabular-nums;
}
.hour .temp {
font-size: 13px;
font-weight: 600;
letter-spacing: 0.01em;
min-height: 16px;
color: rgba(248, 251, 255, 0.92);
}
.track {
position: relative;
width: 100%;
height: 220px;
border-radius: 999px;
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.03));
border: 1px solid rgba(255, 255, 255, 0.06);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
overflow: hidden;
}
.fill {
position: absolute;
left: 5px;
right: 5px;
bottom: 5px;
border-radius: 999px;
background: linear-gradient(180deg, var(--accent-1), var(--accent-2) 58%, var(--accent-3) 100%);
box-shadow: 0 10px 24px rgba(var(--accent2-rgb), 0.28);
min-height: 10px;
}
.hour.is-max .fill {
background: linear-gradient(180deg, #ffe29d, #ffaf63 58%, #ff7363 100%);
box-shadow: 0 10px 24px rgba(255, 164, 98, 0.3);
}
.hour.is-min .fill {
background: linear-gradient(180deg, #d8f6ff, #97d6ff 58%, #6d9dff 100%);
box-shadow: 0 10px 24px rgba(123, 186, 255, 0.28);
}
.hour.is-now .track {
border-color: rgba(var(--accent-rgb), 0.48);
box-shadow:
0 0 0 1px rgba(var(--accent-rgb), 0.14),
inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
.hour.is-now .temp {
color: var(--accent-1);
}
.hour .time {
font-size: 12px;
color: rgba(236, 242, 255, 0.62);
letter-spacing: 0.08em;
}
.footnote {
margin-top: 14px;
color: var(--muted-2);
font-size: 13px;
line-height: 1.5;
}
.message {
margin-top: 18px;
position: relative;
z-index: 1;
padding: 16px 18px;
border-radius: 18px;
border: 1px solid rgba(255, 116, 116, 0.26);
background: rgba(88, 18, 34, 0.42);
color: rgba(255, 230, 234, 0.96);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
font-size: 15px;
line-height: 1.45;
}
.message small {
display: block;
margin-top: 4px;
color: rgba(255, 230, 234, 0.78);
}
.hidden {
display: none;
}
@media (max-width: 1100px) {
body {
overflow: auto;
}
.scene {
min-height: auto;
padding: 20px;
}
.card {
width: min(1180px, calc(100vw - 20px));
}
.content {
grid-template-columns: 1fr;
}
.summary-panel {
min-height: auto;
}
}
</style>
</head>
<body>
<div class="scene">
<div class="grid-overlay"></div>
<div class="orb one"></div>
<div class="orb two"></div>
<div class="orb three"></div>
<main class="card" id="app" aria-live="polite">
<section class="header">
<div class="eyebrow">Weather Snapshot</div>
<div class="title-row">
<div>
<h1 id="locationName">Berlin</h1>
<p class="date-label" id="dateLabel">Loading date...</p>
</div>
<div class="source-pill" id="sourcePill">Loading</div>
</div>
<div class="submeta">
<div class="chip" id="coordsChip">52.5200, 13.4050</div>
<div class="chip" id="utcChip">UTC day</div>
</div>
</section>
<section class="content">
<div class="summary-panel">
<div>
<div class="icon-shell" id="iconShell" aria-hidden="true"></div>
<div class="summary-copy">
<div class="big-temp" id="bigTemp">--</div>
<div class="condition" id="conditionText">Loading weather data...</div>
<div class="detail-note" id="detailNote">Fetching daily highs, lows, and hourly temperatures.</div>
</div>
</div>
<div class="stats">
<div class="stat">
<span>High</span>
<strong id="highTemp">--</strong>
</div>
<div class="stat">
<span>Low</span>
<strong id="lowTemp">--</strong>
</div>
<div class="stat">
<span>Range</span>
<strong id="rangeTemp">--</strong>
</div>
</div>
</div>
<div class="hourly-panel">
<div class="section-head">
<div>
<h2>Hourly temperatures</h2>
<p id="hourlyMeta">Waiting for data...</p>
</div>
<div class="legend">
<span class="legend-swatch"></span>
<span>Temperature</span>
</div>
</div>
<div class="chart-shell">
<div class="chart" id="hourlyChart"></div>
</div>
<div class="footnote" id="sourceNote">
Same-origin Open-Meteo compatible API. All times are shown in UTC.
</div>
</div>
</section>
<div class="message hidden" id="message" role="status" aria-live="polite"></div>
</main>
</div>
<script>
(function () {
const params = new URLSearchParams(window.location.search);
function utcTodayISO() {
return new Date().toISOString().slice(0, 10);
}
function isIsoDate(value) {
return /^\d{4}-\d{2}-\d{2}$/.test(value || '');
}
function normalizeDate(value) {
const today = utcTodayISO();
if (!isIsoDate(value)) return today;
const test = new Date(value + 'T00:00:00Z');
return Number.isFinite(test.getTime()) ? value : today;
}
function normalizeNumber(value, fallback) {
const n = Number.parseFloat(value);
return Number.isFinite(n) ? n : fallback;
}
function hexToRgb(hex) {
const cleaned = String(hex).replace('#', '').trim();
const expanded = cleaned.length === 3
? cleaned.split('').map((ch) => ch + ch).join('')
: cleaned;
const n = Number.parseInt(expanded, 16);
return [
(n >> 16) & 255,
(n >> 8) & 255,
n & 255
].join(', ');
}
function setTheme(colors) {
const root = document.documentElement.style;
root.setProperty('--accent-1', colors[0]);
root.setProperty('--accent-2', colors[1]);
root.setProperty('--accent-3', colors[2]);
root.setProperty('--accent-rgb', hexToRgb(colors[0]));
root.setProperty('--accent2-rgb', hexToRgb(colors[1]));
root.setProperty('--accent3-rgb', hexToRgb(colors[2]));
}
function themeForCode(code) {
if (code === 0) return ['#ffe08c', '#ffb25c', '#ff7363'];
if (code >= 1 && code <= 3) return ['#98d9ff', '#6d8eff', '#8d6bff'];
if (code === 45 || code === 48) return ['#d8e7ff', '#9aa8c5', '#6d7b96'];
if (code >= 51 && code <= 57) return ['#95e8ff', '#64a6ff', '#7d75ff'];
if (code >= 61 && code <= 67) return ['#7fd9ff', '#5e90ff', '#6f68ff'];
if (code >= 71 && code <= 77) return ['#d4f5ff', '#a2d8ff', '#7eaaff'];
if (code >= 80 && code <= 86) return ['#8ee9e1', '#68bfff', '#6f86ff'];
if (code >= 95) return ['#f4aad6', '#a77bff', '#546cff'];
return ['#8fd3ff', '#678dff', '#8b63ff'];
}
function weatherFamily(code) {
if (code === 0) return 'clear';
if (code >= 1 && code <= 3) return 'cloudy';
if (code === 45 || code === 48) return 'fog';
if (code >= 51 && code <= 57) return 'drizzle';
if (code >= 61 && code <= 67) return 'rain';
if (code >= 71 && code <= 77) return 'snow';
if (code >= 80 && code <= 86) return 'showers';
if (code >= 95) return 'storm';
return 'cloudy';
}
function weatherDescription(code) {
switch (code) {
case 0: return 'Clear sky';
case 1: return 'Mainly clear';
case 2: return 'Partly cloudy';
case 3: return 'Overcast';
case 45: return 'Fog';
case 48: return 'Depositing rime fog';
case 51: return 'Light drizzle';
case 53: return 'Drizzle';
case 55: return 'Dense drizzle';
case 56: return 'Freezing drizzle';
case 57: return 'Dense freezing drizzle';
case 61: return 'Slight rain';
case 63: return 'Rain';
case 65: return 'Heavy rain';
case 66: return 'Freezing rain';
case 67: return 'Heavy freezing rain';
case 71: return 'Slight snow fall';
case 73: return 'Snow fall';
case 75: return 'Heavy snow fall';
case 77: return 'Snow grains';
case 80: return 'Slight rain showers';
case 81: return 'Rain showers';
case 82: return 'Violent rain showers';
case 85: return 'Slight snow showers';
case 86: return 'Heavy snow showers';
case 95: return 'Thunderstorm';
case 96: return 'Thunderstorm with slight hail';
case 99: return 'Thunderstorm with heavy hail';
default: return 'Weather code ' + code;
}
}
function formatDegrees(value) {
const rounded = Math.round(value * 10) / 10;
return Number.isInteger(rounded) ? rounded.toFixed(0) + '°C' : rounded.toFixed(1) + '°C';
}
function formatTempLabel(value) {
const rounded = Math.round(value * 10) / 10;
return Number.isInteger(rounded) ? rounded.toFixed(0) + '°' : rounded.toFixed(1) + '°';
}
function formatDateLabel(dateStr) {
return new Intl.DateTimeFormat('en-GB', {
timeZone: 'UTC',
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
}).format(new Date(dateStr + 'T00:00:00Z'));
}
function formatHourLabel(isoTime) {
return new Intl.DateTimeFormat('en-GB', {
timeZone: 'UTC',
hour: '2-digit',
minute: '2-digit',
hourCycle: 'h23'
}).format(new Date(isoTime));
}
function iconMarkup(family) {
const cloud = `
<circle cx="44" cy="58" r="16" fill="white" fill-opacity="0.92"></circle>
<circle cx="62" cy="48" r="22" fill="white" fill-opacity="0.96"></circle>
<circle cx="82" cy="60" r="14" fill="white" fill-opacity="0.92"></circle>
<rect x="34" y="56" width="58" height="24" rx="12" fill="white" fill-opacity="0.95"></rect>
`;
if (family === 'clear') {
return `
<svg viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
<g stroke="white" stroke-opacity="0.38" stroke-width="4" stroke-linecap="round">
<path d="M60 10v14"></path>
<path d="M60 96v14"></path>
<path d="M10 60h14"></path>
<path d="M96 60h14"></path>
<path d="M24 24l10 10"></path>
<path d="M86 86l10 10"></path>
<path d="M24 96l10-10"></path>
<path d="M86 34l10-10"></path>
</g>
<circle cx="60" cy="60" r="22" fill="#ffd86d"></circle>
<circle cx="60" cy="60" r="14" fill="#fff7d0" fill-opacity="0.92"></circle>
</svg>
`;
}
if (family === 'cloudy') {
return `
<svg viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="44" cy="48" r="14" fill="#ffd76a" fill-opacity="0.8"></circle>
<g stroke="white" stroke-opacity="0.28" stroke-width="3.5" stroke-linecap="round">
<path d="M26 28l8 8"></path>
<path d="M18 46h11"></path>
<path d="M28 64l8-8"></path>
</g>
${cloud}
</svg>
`;
}
if (family === 'fog') {
return `
<svg viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
${cloud}
<g stroke="#d6e7ff" stroke-opacity="0.76" stroke-width="4" stroke-linecap="round">
<path d="M28 84h64"></path>
<path d="M20 94h48"></path>
<path d="M40 104h52"></path>
</g>
</svg>
`;
}
if (family === 'drizzle' || family === 'rain' || family === 'showers') {
return `
<svg viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
${cloud}
<g stroke="#8fdfff" stroke-width="4" stroke-linecap="round">
<path d="M42 88c0 0-4 5-4 9a4 4 0 0 0 8 0c0-4-4-9-4-9Z" fill="#8fdfff"></path>
<path d="M60 90c0 0-4 5-4 9a4 4 0 0 0 8 0c0-4-4-9-4-9Z" fill="#8fdfff"></path>
<path d="M78 88c0 0-4 5-4 9a4 4 0 0 0 8 0c0-4-4-9-4-9Z" fill="#8fdfff"></path>
</g>
</svg>
`;
}
if (family === 'snow') {
return `
<svg viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
${cloud}
<g stroke="#d8f6ff" stroke-width="3.5" stroke-linecap="round">
<path d="M42 86v12"></path>
<path d="M36 92h12"></path>
<path d="M38 88l8 8"></path>
<path d="M46 88l-8 8"></path>
<path d="M60 88v12"></path>
<path d="M54 94h12"></path>
<path d="M56 90l8 8"></path>
<path d="M64 90l-8 8"></path>
<path d="M78 86v12"></path>
<path d="M72 92h12"></path>
<path d="M74 88l8 8"></path>
<path d="M82 88l-8 8"></path>
</g>
</svg>
`;
}
if (family === 'storm') {
return `
<svg viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
${cloud}
<path d="M64 82l-8 16h10l-4 14 18-24H70l7-6Z" fill="#ffd76a"></path>
<g stroke="#bca8ff" stroke-opacity="0.8" stroke-width="3.5" stroke-linecap="round">
<path d="M42 90v9"></path>
<path d="M84 90v9"></path>
</g>
</svg>
`;
}
return `
<svg viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
${cloud}
</svg>
`;
}
function setMessage(text, detail) {
const message = document.getElementById('message');
message.innerHTML = '';
const line = document.createElement('div');
line.textContent = text;
message.appendChild(line);
if (detail) {
const small = document.createElement('small');
small.textContent = detail;
message.appendChild(small);
}
message.classList.remove('hidden');
}
function clearMessage() {
const message = document.getElementById('message');
message.classList.add('hidden');
message.innerHTML = '';
}
function fail(reason) {
document.getElementById('sourcePill').textContent = 'Unavailable';
document.getElementById('conditionText').textContent = 'Weather data could not be loaded.';
document.getElementById('detailNote').textContent = 'Please check the location, date, or API availability.';
document.getElementById('bigTemp').textContent = '--';
document.getElementById('highTemp').textContent = '--';
document.getElementById('lowTemp').textContent = '--';
document.getElementById('rangeTemp').textContent = '--';
document.getElementById('hourlyMeta').textContent = 'No hourly data available.';
document.getElementById('hourlyChart').innerHTML = '';
setMessage('Weather data could not be loaded.', reason || 'The page was unable to fetch the requested forecast or archive data.');
}
function render(data, meta) {
const daily = data && data.daily ? data.daily : {};
const hourly = data && data.hourly ? data.hourly : {};
const maxValues = Array.isArray(daily.temperature_2m_max) ? daily.temperature_2m_max : [];
const minValues = Array.isArray(daily.temperature_2m_min) ? daily.temperature_2m_min : [];
const codeValues = Array.isArray(daily.weather_code) ? daily.weather_code : [];
const hourlyTimes = Array.isArray(hourly.time) ? hourly.time : [];
const hourlyTemps = Array.isArray(hourly.temperature_2m) ? hourly.temperature_2m : [];
if (!maxValues.length || !minValues.length || !codeValues.length || !hourlyTimes.length || !hourlyTemps.length) {
throw new Error('Incomplete weather payload.');
}
const max = Number(maxValues[0]);
const min = Number(minValues[0]);
const code = Number(codeValues[0]);
if (!Number.isFinite(max) || !Number.isFinite(min) || !Number.isFinite(code)) {
throw new Error('Invalid numeric weather values.');
}
const family = weatherFamily(code);
setTheme(themeForCode(code));
const todayUTC = utcTodayISO();
const requestedDate = meta.requestedDate;
const dateLabel = formatDateLabel(requestedDate);
const endpointLabel = requestedDate < todayUTC ? 'Archive API' : 'Forecast API';
document.title = meta.locationName + ' • ' + dateLabel;
document.getElementById('locationName').textContent = meta.locationName;
document.getElementById('dateLabel').textContent = dateLabel;
document.getElementById('sourcePill').textContent = endpointLabel;
document.getElementById('coordsChip').textContent =
meta.latitude.toFixed(4) + ', ' + meta.longitude.toFixed(4);
document.getElementById('utcChip').textContent = 'UTC day';
document.getElementById('bigTemp').textContent = formatDegrees(max);
document.getElementById('conditionText').textContent = weatherDescription(code);
document.getElementById('detailNote').textContent =
'Open-Meteo compatible data for ' + dateLabel + '.';
document.getElementById('highTemp').textContent = formatDegrees(max);
document.getElementById('lowTemp').textContent = formatDegrees(min);
document.getElementById('rangeTemp').textContent = formatDegrees(max - min);
document.getElementById('hourlyMeta').textContent =
'24 hourly values from 00:00 to 23:00 UTC.';
document.getElementById('sourceNote').textContent =
'Same-origin ' + endpointLabel + '. All values are in UTC and Celsius.';
document.getElementById('iconShell').innerHTML = iconMarkup(family);
const chart = document.getElementById('hourlyChart');
chart.innerHTML = '';
const tempMin = Math.min.apply(null, hourlyTemps.map(Number));
const tempMax = Math.max.apply(null, hourlyTemps.map(Number));
const spread = Math.max(tempMax - tempMin, 1);
const maxIndex = hourlyTemps.findIndex((value) => Number(value) === tempMax);
const minIndex = hourlyTemps.findIndex((value) => Number(value) === tempMin);
const currentUTC = new Date();
const nowHour = currentUTC.getUTCHours();
const isToday = requestedDate === todayUTC;
const fragment = document.createDocumentFragment();
for (let i = 0; i < Math.min(hourlyTimes.length, hourlyTemps.length); i++) {
const time = hourlyTimes[i];
const temp = Number(hourlyTemps[i]);
if (!Number.isFinite(temp)) continue;
const normalized = (temp - tempMin) / spread;
const height = 14 + normalized * 176;
const hour = document.createElement('div');
hour.className = 'hour';
if (i === maxIndex) hour.classList.add('is-max');
if (i === minIndex) hour.classList.add('is-min');
if (isToday && new Date(time).getUTCHours() === nowHour) hour.classList.add('is-now');
hour.title = formatHourLabel(time) + ' • ' + formatDegrees(temp);
const tempLabel = document.createElement('div');
tempLabel.className = 'temp';
tempLabel.textContent = formatTempLabel(temp);
const track = document.createElement('div');
track.className = 'track';
const fill = document.createElement('div');
fill.className = 'fill';
fill.style.height = height + 'px';
track.appendChild(fill);
const timeLabel = document.createElement('div');
timeLabel.className = 'time';
timeLabel.textContent = formatHourLabel(time);
hour.appendChild(tempLabel);
hour.appendChild(track);
hour.appendChild(timeLabel);
fragment.appendChild(hour);
}
chart.appendChild(fragment);
clearMessage();
}
async function loadWeather() {
const locationName = (params.get('name') || 'Berlin').trim() || 'Berlin';
const latitude = normalizeNumber(params.get('lat'), 52.52);
const longitude = normalizeNumber(params.get('lon'), 13.405);
const requestedDate = normalizeDate(params.get('date'));
const today = utcTodayISO();
const endpoint = requestedDate < today ? '/api/om/archive' : '/api/om/forecast';
document.getElementById('locationName').textContent = locationName;
document.getElementById('dateLabel').textContent = formatDateLabel(requestedDate);
document.getElementById('coordsChip').textContent =
latitude.toFixed(4) + ', ' + longitude.toFixed(4);
document.getElementById('sourcePill').textContent =
requestedDate < today ? 'Archive API' : 'Forecast API';
const url = new URL(endpoint, window.location.origin);
url.searchParams.set('latitude', String(latitude));
url.searchParams.set('longitude', String(longitude));
url.searchParams.set('daily', 'temperature_2m_max,temperature_2m_min,weather_code');
url.searchParams.set('hourly', 'temperature_2m');
url.searchParams.set('timezone', 'UTC');
url.searchParams.set('temperature_unit', 'celsius');
url.searchParams.set('start_date', requestedDate);
url.searchParams.set('end_date', requestedDate);
try {
const controller = new AbortController();
const timeout = window.setTimeout(() => controller.abort(), 12000);
const response = await fetch(url.toString(), {
signal: controller.signal,
headers: {
'Accept': 'application/json'
}
});
window.clearTimeout(timeout);
if (!response.ok) {
throw new Error('Request failed with status ' + response.status + '.');
}
const payload = await response.json();
render(payload, {
locationName,
latitude,
longitude,
requestedDate
});
} catch (error) {
fail(error && error.message ? error.message : 'Unexpected network failure.');
}
}
loadWeather();
})();
</script>
<noscript>
<div style="position: fixed; inset: auto 24px 24px 24px; padding: 16px 18px; border-radius: 18px; background: rgba(88, 18, 34, 0.42); border: 1px solid rgba(255, 116, 116, 0.26); color: rgba(255, 230, 234, 0.96); font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;">
Weather data could not be loaded.
</div>
</noscript>
</body>
</html>L1 —— 廉价的确定性描述量
| bytes 总计 | 33,990 | html / css / js | 3,139 / 12,720 / 18,131 |
|---|---|---|---|
| dom 节点 | 57 | dom 深度 | 9 |
| css 规则 | 60 | 含 js | 是 |
| brightness | 44.8 | contrast | 35.4 |
| colorfulness | 27.4 | 留白 | 75.3% |
该 slot 的 telemetry
| prompt tokens | 16,119 | completion tokens | 29,476 |
|---|---|---|---|
| total tokens | 45,595 | wall | 198.7 s |
| cost | — | request id | — |
config.json572 B
{
"N": 2,
"auth": {
"credential_ref": "WCB_NONE",
"method": "oauth-login"
},
"billing": "plan",
"config_id": "gpt-5.4-mini-eff-high--cli--cursor--dev",
"effort": "high",
"family": "gpt",
"m": {
"min": 2,
"q": 2
},
"model_id": "gpt-5.4-mini",
"protocol": "cli",
"served_model": "gpt-5.4-mini-high",
"telemetry": {
"completion_tokens": 91090,
"cost_usd": null,
"prompt_tokens": 60867,
"total_tokens": 151957,
"wall_ms": 603658
},
"transport": "cursor-agent-cli-isolated-home",
"vendor_sanction_ref": null
}send-log2.5 KB
{
"N": 2,
"batch_id": "2026-08-13--cursor-s0",
"config_id": "gpt-5.4-mini-eff-high--cli--cursor--dev",
"positions": [
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-08-12T22:25:43.349997+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-08-12T22:22:24.668061+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-08-12T22:26:37.280049+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-08-12T22:25:47.020375+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-08-12T22:27:17.833011+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-08-12T22:26:40.983821+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-08-12T22:32:39.939016+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-08-12T22:27:22.068951+00:00"
}
],
"block_index": 1,
"model_reaching_attempt_index": 0,
"slot_index": 1,
"terminal_state": "valid",
"variant": "P-q"
}
],
"retry_policy": {
"max_unreachable_retries": 5,
"rate_limit_backoff": {
"max_attempts": 4,
"max_total_ms": 60000
}
}
}