claude-opus-5-5 @ high · CC
CChigh
- config
- claude-opus-5-5-eff-high--cli--claude-code--dev
- batch
- 2026-07-19--unified
- transport
- claude-code-cli-headless
- protocol
- cli · plan
- served model
- claude-opus-5-5
- 采集于
- 2026年7月18日 11:54 · N=2
variant
live
slot 0 · P-q · sandboxed iframe

截图是 similarity 通道测量时的原始像素。运行 live 会在 sandboxed iframe 中重新执行原始输出;渲染结果取决于你的浏览器和字体,不保证与测量像素一致。
similarity 邻居
最近
claude-fable-5 @max · cursor-xl0.71claude-opus-5 @low · cursor-xl0.71claude-opus-5-thinking @low · cursor0.70claude-opus-5-5 @xhigh · CC0.69claude-opus-5-thinking @low · cursor-xl0.69最远
deepseek-v4-pro · opencode0.51minimax-m2.5 · kiro0.51grok-4.3 @low · api0.51qwen3.6-plus · go0.52gpt-5.1 · cursor0.52限于 session 2026-07-19--unified
similarity 衡量本 session 内的趋同程度 —— 不是质量。
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">
<title>Weather</title>
<style>
:root {
--bg: linear-gradient(165deg, #334155 0%, #64748b 55%, #cbd5e1 100%);
--badge: linear-gradient(145deg, #334155, #64748b);
--ink: #0f172a;
--ink-2: #334155;
--muted: #64748b;
--faint: #94a3b8;
--line: rgba(15, 23, 42, 0.08);
}
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
padding: 24px;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Inter, Roboto, "Helvetica Neue", Arial, sans-serif;
color: var(--ink);
background: var(--bg);
background-attachment: fixed;
-webkit-font-smoothing: antialiased;
overflow-x: hidden;
position: relative;
}
body::before, body::after {
content: "";
position: fixed;
border-radius: 50%;
pointer-events: none;
filter: blur(60px);
z-index: 0;
}
body::before {
width: 520px; height: 520px;
top: -180px; left: -120px;
background: rgba(255, 255, 255, 0.22);
}
body::after {
width: 460px; height: 460px;
bottom: -200px; right: -100px;
background: rgba(255, 255, 255, 0.16);
}
.card {
position: relative;
z-index: 1;
width: 1040px;
max-width: 100%;
padding: 34px 44px 30px;
border-radius: 28px;
background: rgba(255, 255, 255, 0.88);
-webkit-backdrop-filter: blur(24px) saturate(140%);
backdrop-filter: blur(24px) saturate(140%);
box-shadow:
0 40px 90px -30px rgba(15, 23, 42, 0.55),
0 12px 30px -12px rgba(15, 23, 42, 0.25),
inset 0 0 0 1px rgba(255, 255, 255, 0.6);
}
/* Header */
.head {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 24px;
}
.eyebrow {
font-size: 12px;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--muted);
margin: 0 0 8px;
}
h1 {
margin: 0;
font-size: 36px;
line-height: 1.1;
font-weight: 700;
letter-spacing: -0.025em;
color: var(--ink);
overflow-wrap: anywhere;
}
.date {
margin: 8px 0 0;
font-size: 16px;
color: var(--muted);
font-weight: 500;
}
.chips { display: flex; gap: 8px; flex-shrink: 0; margin-top: 4px; }
.chip {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 7px 12px;
border-radius: 999px;
font-size: 12.5px;
font-weight: 500;
color: var(--ink-2);
background: rgba(241, 245, 249, 0.9);
border: 1px solid var(--line);
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.chip svg { width: 13px; height: 13px; color: var(--faint); }
/* Hero */
.hero {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: 28px;
margin-top: 28px;
}
.badge {
width: 112px; height: 112px;
border-radius: 30px;
background: var(--badge);
display: grid;
place-items: center;
box-shadow: 0 16px 30px -14px rgba(15, 23, 42, 0.6), inset 0 1px 0 rgba(255,255,255,0.25);
}
.badge svg { width: 78px; height: 78px; overflow: visible; }
.cond {
margin: 0;
font-size: 32px;
font-weight: 650;
letter-spacing: -0.02em;
line-height: 1.15;
}
.summary {
margin: 10px 0 0;
font-size: 15px;
color: var(--muted);
line-height: 1.5;
}
.summary strong { color: var(--ink-2); font-weight: 600; }
.tiles { display: flex; gap: 12px; }
.tile {
width: 156px;
padding: 16px 18px 14px;
border-radius: 18px;
background: rgba(248, 250, 252, 0.95);
border: 1px solid var(--line);
}
.tile-label {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
}
.arrow {
width: 20px; height: 20px;
border-radius: 7px;
display: grid;
place-items: center;
color: #fff;
}
.arrow svg { width: 12px; height: 12px; }
.tile-value {
margin-top: 10px;
font-size: 40px;
font-weight: 650;
letter-spacing: -0.03em;
line-height: 1;
font-variant-numeric: tabular-nums;
color: var(--ink);
}
.tile-value .unit {
font-size: 18px;
font-weight: 500;
color: var(--faint);
margin-left: 2px;
letter-spacing: 0;
vertical-align: 16px;
}
/* Chart */
.chart-wrap {
margin-top: 28px;
padding-top: 20px;
border-top: 1px solid var(--line);
}
.chart-head {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 6px;
}
.chart-title { margin: 0; font-size: 15px; font-weight: 650; color: var(--ink); }
.chart-note { font-size: 12.5px; color: var(--faint); }
.chart { display: block; width: 100%; height: auto; user-select: none; }
.chart text { font-family: inherit; font-variant-numeric: tabular-nums; }
.chart .rt { font-size: 13px; font-weight: 600; fill: #475569; transition: fill .12s; }
.chart .rh { font-size: 11px; font-weight: 500; fill: var(--faint); transition: fill .12s; }
.chart .rt.on { fill: var(--ink); }
.chart .rh.on { fill: var(--ink-2); }
.chart .tick { font-size: 11px; fill: #a3b0c2; }
.chart .ext { font-size: 12px; font-weight: 700; fill: var(--ink); paint-order: stroke; stroke: #fff; stroke-width: 4px; stroke-linejoin: round; }
.chart .now-l { font-size: 10.5px; font-weight: 700; letter-spacing: .08em; fill: var(--muted); }
.chart .hl { transition: opacity .12s; }
.no-hourly {
height: 180px;
display: grid;
place-items: center;
color: var(--muted);
font-size: 14px;
border-radius: 16px;
background: rgba(248, 250, 252, 0.9);
border: 1px dashed rgba(15, 23, 42, 0.12);
}
/* Loading */
.sk {
background: linear-gradient(90deg, #e9eef5 25%, #f6f8fb 50%, #e9eef5 75%);
background-size: 200% 100%;
animation: shimmer 1.4s ease-in-out infinite;
border-radius: 10px;
}
.badge.sk { border-radius: 30px; box-shadow: none; }
.tile.sk { height: 100px; border: 0; }
@keyframes shimmer { 0% { background-position: 100% 0; } 100% { background-position: -100% 0; } }
/* Error */
.error {
margin-top: 28px;
min-height: 380px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
border-radius: 20px;
background: rgba(248, 250, 252, 0.9);
border: 1px solid var(--line);
padding: 40px;
}
.err-icon {
width: 72px; height: 72px;
border-radius: 22px;
display: grid;
place-items: center;
background: #fef2f2;
color: #dc2626;
margin-bottom: 20px;
}
.err-icon svg { width: 36px; height: 36px; }
.error h2 { margin: 0; font-size: 22px; font-weight: 650; letter-spacing: -0.015em; }
.error p { margin: 10px 0 0; max-width: 520px; color: var(--muted); font-size: 15px; line-height: 1.55; }
.error button {
margin-top: 24px;
font: inherit;
font-size: 14px;
font-weight: 600;
color: #fff;
background: var(--ink);
border: 0;
border-radius: 12px;
padding: 11px 20px;
cursor: pointer;
transition: transform .12s, box-shadow .12s;
box-shadow: 0 8px 18px -8px rgba(15, 23, 42, 0.6);
}
.error button:hover { transform: translateY(-1px); }
.error button:focus-visible { outline: 3px solid #93c5fd; outline-offset: 2px; }
.fade { animation: fade .45s ease both; }
@keyframes fade { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
@media (prefers-reduced-motion: reduce) {
.sk, .fade { animation: none; }
}
</style>
</head>
<body>
<main class="card" aria-labelledby="loc">
<header class="head">
<div>
<p class="eyebrow" id="eyebrow"> </p>
<h1 id="loc"></h1>
<p class="date" id="date"></p>
</div>
<div class="chips">
<span class="chip" id="coords">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 21s-7-6.2-7-11.5A7 7 0 0 1 19 9.5C19 14.8 12 21 12 21z"/><circle cx="12" cy="9.5" r="2.5"/></svg>
<span></span>
</span>
<span class="chip">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
UTC
</span>
</div>
</header>
<section id="content" aria-live="polite"></section>
</main>
<script>
(function () {
"use strict";
// ---------- Parameters ----------
const qs = new URLSearchParams(location.search);
const todayUTC = new Date().toISOString().slice(0, 10);
function numParam(key, def, lo, hi) {
const raw = qs.get(key);
if (raw === null || raw.trim() === "") return def;
const n = Number(raw);
return Number.isFinite(n) && n >= lo && n <= hi ? n : def;
}
function validDate(s) {
if (!s || !/^\d{4}-\d{2}-\d{2}$/.test(s)) return false;
const d = new Date(s + "T00:00:00Z");
return !isNaN(d) && d.toISOString().slice(0, 10) === s;
}
const lat = numParam("lat", 52.52, -90, 90);
const lon = numParam("lon", 13.405, -180, 180);
const nameRaw = (qs.get("name") || "").trim();
const name = nameRaw || "Berlin";
const dateParam = (qs.get("date") || "").trim();
const date = validDate(dateParam) ? dateParam : todayUTC;
const isPast = date < todayUTC;
const isToday = date === todayUTC;
// ---------- Formatting ----------
function fmt(v, digits) {
const r = Number(v.toFixed(digits));
const s = (Object.is(r, -0) || r === 0 ? 0 : r).toFixed(digits);
return s.replace("-", "\u2212");
}
function esc(s) {
return String(s).replace(/[&<>"']/g, c => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]));
}
const pad2 = n => String(n).padStart(2, "0");
const longDate = new Date(date + "T00:00:00Z").toLocaleDateString("en-GB", {
weekday: "long", day: "numeric", month: "long", year: "numeric", timeZone: "UTC"
});
const dayDiff = Math.round((Date.parse(date) - Date.parse(todayUTC)) / 86400000);
let eyebrow;
if (dayDiff === 0) eyebrow = "Today";
else if (dayDiff === 1) eyebrow = "Tomorrow \u00b7 Forecast";
else if (dayDiff === -1) eyebrow = "Yesterday \u00b7 Historical";
else if (dayDiff > 1) eyebrow = "Forecast \u00b7 in " + dayDiff + " days";
else eyebrow = "Historical \u00b7 " + Math.abs(dayDiff).toLocaleString("en-GB") + " days ago";
const coordText = Math.abs(lat).toFixed(2) + "\u00b0 " + (lat >= 0 ? "N" : "S") + ", " +
Math.abs(lon).toFixed(2) + "\u00b0 " + (lon >= 0 ? "E" : "W");
document.title = name + " \u2014 Weather, " + longDate;
document.getElementById("loc").textContent = name;
document.getElementById("date").textContent = longDate;
document.getElementById("eyebrow").textContent = eyebrow;
document.querySelector("#coords span").textContent = coordText;
// ---------- Conditions & themes ----------
const WMO = {
0: ["Clear sky", "clear"], 1: ["Mainly clear", "clear"], 2: ["Partly cloudy", "partly"], 3: ["Overcast", "cloudy"],
45: ["Fog", "fog"], 48: ["Depositing rime fog", "fog"],
51: ["Light drizzle", "drizzle"], 53: ["Moderate drizzle", "drizzle"], 55: ["Dense drizzle", "drizzle"],
56: ["Light freezing drizzle", "drizzle"], 57: ["Dense freezing drizzle", "drizzle"],
61: ["Slight rain", "rain"], 63: ["Moderate rain", "rain"], 65: ["Heavy rain", "rain"],
66: ["Light freezing rain", "rain"], 67: ["Heavy freezing rain", "rain"],
71: ["Slight snowfall", "snow"], 73: ["Moderate snowfall", "snow"], 75: ["Heavy snowfall", "snow"], 77: ["Snow grains", "snow"],
80: ["Slight rain showers", "rain"], 81: ["Moderate rain showers", "rain"], 82: ["Violent rain showers", "rain"],
85: ["Slight snow showers", "snow"], 86: ["Heavy snow showers", "snow"],
95: ["Thunderstorm", "storm"], 96: ["Thunderstorm with slight hail", "storm"], 99: ["Thunderstorm with heavy hail", "storm"]
};
const THEMES = {
neutral: ["#334155", "#64748b", "#cbd5e1"],
clear: ["#1c64d1", "#4f9ef5", "#ffd98a"],
partly: ["#2f6db8", "#6fa5dd", "#d6e5f4"],
cloudy: ["#4b5b70", "#8494aa", "#cdd6e0"],
fog: ["#6c7985", "#9ea9b3", "#dde2e7"],
drizzle: ["#3a5876", "#6a8aab", "#b7c9da"],
rain: ["#1b3553", "#395f86", "#86a3c1"],
snow: ["#5f88b3", "#9dbfe0", "#e4eef8"],
storm: ["#1b1836", "#37315c", "#6c6890"]
};
function applyTheme(key) {
const c = THEMES[key] || THEMES.neutral;
const root = document.documentElement.style;
root.setProperty("--bg", "linear-gradient(165deg, " + c[0] + " 0%, " + c[1] + " 55%, " + c[2] + " 100%)");
root.setProperty("--badge", "linear-gradient(145deg, " + c[0] + ", " + c[1] + ")");
}
// ---------- Icons ----------
function cloud(fill, tx, ty, s) {
return '<g transform="translate(' + tx + ' ' + ty + ') scale(' + s + ')" fill="' + fill + '">' +
'<circle cx="22" cy="36" r="10"/><circle cx="34" cy="28" r="13"/><circle cx="45" cy="35" r="10"/>' +
'<rect x="12" y="34" width="43" height="12" rx="6"/></g>';
}
function sun(cx, cy, r) {
let rays = "";
for (let i = 0; i < 8; i++) {
const a = i * Math.PI / 4;
const x1 = cx + Math.cos(a) * (r + 5), y1 = cy + Math.sin(a) * (r + 5);
const x2 = cx + Math.cos(a) * (r + 10), y2 = cy + Math.sin(a) * (r + 10);
rays += '<line x1="' + x1.toFixed(1) + '" y1="' + y1.toFixed(1) + '" x2="' + x2.toFixed(1) + '" y2="' + y2.toFixed(1) + '"/>';
}
return '<g stroke="#fde68a" stroke-width="3.2" stroke-linecap="round">' + rays + '</g>' +
'<circle cx="' + cx + '" cy="' + cy + '" r="' + r + '" fill="#fbbf24"/>' +
'<circle cx="' + (cx - r * 0.3) + '" cy="' + (cy - r * 0.3) + '" r="' + (r * 0.45) + '" fill="#fcd34d" opacity=".8"/>';
}
function icon(group) {
let body;
switch (group) {
case "clear": body = sun(32, 32, 12); break;
case "partly": body = sun(23, 23, 9) + cloud("#fff", 8, 10, 0.9); break;
case "cloudy": body = cloud("rgba(255,255,255,.55)", -2, -4, 0.8) + cloud("#fff", 6, 8, 0.9); break;
case "fog": body = cloud("#fff", 0, -8, 1) +
'<g stroke="rgba(255,255,255,.85)" stroke-width="3.5" stroke-linecap="round"><line x1="12" y1="46" x2="48" y2="46"/><line x1="20" y1="54" x2="56" y2="54"/></g>'; break;
case "drizzle": body = cloud("#fff", 0, -8, 1) +
'<g stroke="#dbeafe" stroke-width="3" stroke-linecap="round"><line x1="22" y1="45" x2="21" y2="49"/><line x1="33" y1="49" x2="32" y2="53"/><line x1="44" y1="45" x2="43" y2="49"/><line x1="27" y1="55" x2="26" y2="59"/><line x1="39" y1="55" x2="38" y2="59"/></g>'; break;
case "rain": body = cloud("#fff", 0, -8, 1) +
'<g stroke="#bfdbfe" stroke-width="3.5" stroke-linecap="round"><line x1="23" y1="45" x2="19" y2="56"/><line x1="34" y1="45" x2="30" y2="56"/><line x1="45" y1="45" x2="41" y2="56"/></g>'; break;
case "snow": body = cloud("#fff", 0, -8, 1) +
'<g fill="#fff"><circle cx="22" cy="47" r="2.7"/><circle cx="34" cy="50" r="2.7"/><circle cx="46" cy="47" r="2.7"/><circle cx="28" cy="57" r="2.7"/><circle cx="40" cy="57" r="2.7"/></g>'; break;
case "storm": body = cloud("#e2e8f0", 0, -8, 1) +
'<polygon points="35,38 25,52 32,52 27,63 42,46 34,46 39,38" fill="#facc15" stroke="#f59e0b" stroke-width="1" stroke-linejoin="round"/>'; break;
default: body = cloud("rgba(255,255,255,.9)", 0, -2, 1) +
'<text x="34" y="44" text-anchor="middle" font-size="16" font-weight="700" fill="#64748b" font-family="inherit">?</text>';
}
return '<svg viewBox="0 0 64 64" aria-hidden="true">' + body + '</svg>';
}
const ARROW_UP = '<svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 10V2M2.5 5.5 6 2l3.5 3.5"/></svg>';
const ARROW_DOWN = '<svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2v8M2.5 6.5 6 10l3.5-3.5"/></svg>';
// ---------- Temperature colour scale ----------
const TSTOPS = [[-20, "#6366f1"], [-5, "#3b82f6"], [4, "#06b6d4"], [12, "#10b981"], [19, "#eab308"], [26, "#f97316"], [34, "#dc2626"]];
function hexRgb(h) { const n = parseInt(h.slice(1), 16); return [n >> 16, (n >> 8) & 255, n & 255]; }
function tempColor(t) {
if (t <= TSTOPS[0][0]) return TSTOPS[0][1];
for (let i = 1; i < TSTOPS.length; i++) {
if (t <= TSTOPS[i][0]) {
const [t0, c0] = TSTOPS[i - 1], [t1, c1] = TSTOPS[i];
const k = (t - t0) / (t1 - t0), a = hexRgb(c0), b = hexRgb(c1);
return "rgb(" + a.map((v, j) => Math.round(v + (b[j] - v) * k)).join(",") + ")";
}
}
return TSTOPS[TSTOPS.length - 1][1];
}
// ---------- Chart ----------
function monoPath(p) {
const n = p.length;
const f = v => v.toFixed(1);
if (n === 1) return "M" + f(p[0][0]) + "," + f(p[0][1]);
const dx = [], m = [], t = [];
for (let i = 0; i < n - 1; i++) {
dx[i] = p[i + 1][0] - p[i][0];
m[i] = (p[i + 1][1] - p[i][1]) / dx[i];
}
t[0] = m[0]; t[n - 1] = m[n - 2];
for (let i = 1; i < n - 1; i++) {
if (m[i - 1] * m[i] <= 0) t[i] = 0;
else t[i] = 3 * (dx[i - 1] + dx[i]) / ((2 * dx[i] + dx[i - 1]) / m[i - 1] + (dx[i] + 2 * dx[i - 1]) / m[i]);
}
let d = "M" + f(p[0][0]) + "," + f(p[0][1]);
for (let i = 0; i < n - 1; i++) {
d += "C" + f(p[i][0] + dx[i] / 3) + "," + f(p[i][1] + t[i] * dx[i] / 3) + " " +
f(p[i + 1][0] - dx[i] / 3) + "," + f(p[i + 1][1] - t[i + 1] * dx[i] / 3) + " " +
f(p[i + 1][0]) + "," + f(p[i + 1][1]);
}
return d;
}
function buildChart(byHour) {
const W = 952, H = 250, pl = 40, pr = 6, pt = 36, pb = 176;
const colW = (W - pl - pr) / 24;
const X = h => pl + (h + 0.5) * colW;
const vals = byHour.filter(v => v != null);
const lo = Math.min(...vals), hi = Math.max(...vals);
const span = Math.max(hi - lo, 4);
const yMin = lo - span * 0.2, yMax = hi + span * 0.25;
const Y = t => pb - (t - yMin) / (yMax - yMin) * (pb - pt);
let s = "";
// defs
let stops = "";
for (let k = 0; k <= 6; k++) {
stops += '<stop offset="' + (k / 6).toFixed(3) + '" stop-color="' + tempColor(yMax - k / 6 * (yMax - yMin)) + '"/>';
}
s += '<defs>' +
'<linearGradient id="lg" gradientUnits="userSpaceOnUse" x1="0" y1="' + pt + '" x2="0" y2="' + pb + '">' + stops + '</linearGradient>' +
'<linearGradient id="fg" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#fff" stop-opacity=".32"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient>' +
'<mask id="fm"><rect x="0" y="' + pt + '" width="' + W + '" height="' + (pb - pt) + '" fill="url(#fg)"/></mask>' +
'</defs>';
// gridlines
const step = [1, 2, 5, 10, 20].find(st => (yMax - yMin) / st <= 4.5) || 20;
for (let v = Math.ceil(yMin / step) * step; v <= yMax; v += step) {
const y = Y(v).toFixed(1);
s += '<line x1="' + pl + '" x2="' + (W - pr) + '" y1="' + y + '" y2="' + y + '" stroke="rgba(15,23,42,.06)" stroke-width="1"/>';
s += '<text class="tick" x="' + (pl - 10) + '" y="' + (Number(y) + 4) + '" text-anchor="end">' + fmt(v, 0) + '\u00b0</text>';
}
s += '<line x1="' + pl + '" x2="' + (W - pr) + '" y1="' + pb + '" y2="' + pb + '" stroke="rgba(15,23,42,.1)" stroke-width="1"/>';
// hover highlight column (behind line)
s += '<rect class="hl" id="hlCol" x="0" y="' + (pt - 26) + '" width="' + colW.toFixed(1) + '" height="' + (H - pt + 22) + '" rx="10" fill="rgba(15,23,42,.045)" opacity="0"/>';
// "now" marker
if (isToday) {
const now = new Date();
const hf = now.getUTCHours() + now.getUTCMinutes() / 60 - 0.5;
const nx = Math.min(Math.max(X(hf), pl), W - pr).toFixed(1);
s += '<line x1="' + nx + '" x2="' + nx + '" y1="' + (pt - 12) + '" y2="' + pb + '" stroke="#64748b" stroke-width="1.2" stroke-dasharray="3 4" opacity=".6"/>';
s += '<text class="now-l" x="' + nx + '" y="' + (pt - 18) + '" text-anchor="middle">NOW</text>';
}
// segments
const segs = [];
let cur = [];
for (let h = 0; h < 24; h++) {
if (byHour[h] != null) cur.push([X(h), Y(byHour[h])]);
else if (cur.length) { segs.push(cur); cur = []; }
}
if (cur.length) segs.push(cur);
segs.forEach(seg => {
const d = monoPath(seg);
if (seg.length > 1) {
s += '<path d="' + d + 'L' + seg[seg.length - 1][0].toFixed(1) + ',' + pb + 'L' + seg[0][0].toFixed(1) + ',' + pb + 'Z" fill="url(#lg)" mask="url(#fm)"/>';
s += '<path d="' + d + '" fill="none" stroke="url(#lg)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>';
}
});
// dots
const hiH = byHour.indexOf(hi), loH = byHour.indexOf(lo);
for (let h = 0; h < 24; h++) {
const t = byHour[h];
if (t == null || h === hiH || h === loH) continue;
s += '<circle cx="' + X(h).toFixed(1) + '" cy="' + Y(t).toFixed(1) + '" r="2.4" fill="#fff" stroke="' + tempColor(t) + '" stroke-width="1.6"/>';
}
[[hiH, hi, -14], [loH, lo, 22]].forEach(([h, t, off], i) => {
if (i === 1 && loH === hiH) return;
const x = X(h), y = Y(t);
s += '<circle cx="' + x.toFixed(1) + '" cy="' + y.toFixed(1) + '" r="5" fill="' + tempColor(t) + '" stroke="#fff" stroke-width="2.2"/>';
const tx = Math.min(Math.max(x, pl + 18), W - pr - 18);
s += '<text class="ext" x="' + tx.toFixed(1) + '" y="' + (y + off).toFixed(1) + '" text-anchor="middle">' + fmt(t, 1) + '\u00b0</text>';
});
// hover dot
s += '<circle class="hl" id="hlDot" cx="0" cy="0" r="6" fill="#fff" stroke="#0f172a" stroke-width="2.4" opacity="0"/>';
// hourly value row
for (let h = 0; h < 24; h++) {
const x = X(h).toFixed(1), t = byHour[h];
s += '<text class="rt" data-h="' + h + '" x="' + x + '" y="214" text-anchor="middle">' + (t == null ? "\u2013" : fmt(t, 0) + "\u00b0") + '</text>';
s += '<text class="rh" data-h="' + h + '" x="' + x + '" y="236" text-anchor="middle">' + pad2(h) + '</text>';
}
// interaction overlay
s += '<rect id="hit" x="' + pl + '" y="0" width="' + (W - pl - pr) + '" height="' + H + '" fill="transparent"/>';
const label = "Hourly temperatures in degrees Celsius: " +
byHour.map((t, h) => pad2(h) + ":00 " + (t == null ? "no data" : fmt(t, 1) + "\u00b0")).join(", ");
const svg = '<svg class="chart" id="chart" viewBox="0 0 ' + W + ' ' + H + '" role="img" aria-label="' + esc(label) + '">' + s + '</svg>';
function wire() {
const el = document.getElementById("chart");
const col = document.getElementById("hlCol"), dot = document.getElementById("hlDot");
const hit = document.getElementById("hit");
let active = -1;
function set(h) {
if (h === active) return;
el.querySelectorAll(".on").forEach(n => n.classList.remove("on"));
active = h;
if (h < 0) { col.setAttribute("opacity", "0"); dot.setAttribute("opacity", "0"); return; }
col.setAttribute("x", (pl + h * colW).toFixed(1));
col.setAttribute("opacity", "1");
const t = byHour[h];
if (t != null) {
dot.setAttribute("cx", X(h).toFixed(1));
dot.setAttribute("cy", Y(t).toFixed(1));
dot.setAttribute("stroke", tempColor(t));
dot.setAttribute("opacity", "1");
} else dot.setAttribute("opacity", "0");
el.querySelectorAll('[data-h="' + h + '"]').forEach(n => n.classList.add("on"));
}
hit.addEventListener("pointermove", e => {
const r = el.getBoundingClientRect();
const sx = (e.clientX - r.left) * W / r.width;
set(Math.max(0, Math.min(23, Math.floor((sx - pl) / colW))));
});
hit.addEventListener("pointerleave", () => set(-1));
}
return { svg, wire };
}
// ---------- Views ----------
const content = document.getElementById("content");
function renderLoading() {
applyTheme("neutral");
content.innerHTML =
'<div class="hero" aria-hidden="true">' +
'<div class="badge sk"></div>' +
'<div><div class="sk" style="width:260px;height:32px"></div><div class="sk" style="width:400px;max-width:100%;height:16px;margin-top:16px"></div></div>' +
'<div class="tiles"><div class="tile sk"></div><div class="tile sk"></div></div>' +
'</div>' +
'<div class="chart-wrap" aria-hidden="true">' +
'<div class="chart-head"><h2 class="chart-title">Hourly temperature</h2><span class="chart-note">Loading\u2026</span></div>' +
'<div class="sk" style="height:244px;border-radius:16px;margin-top:10px"></div>' +
'</div>' +
'<p class="sr-only">Loading weather data\u2026</p>';
}
function renderError(msg) {
applyTheme("neutral");
content.innerHTML =
'<div class="error fade" role="alert">' +
'<div class="err-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 18h10a4 4 0 0 0 .5-7.97A6 6 0 0 0 6.1 9.1 4.5 4.5 0 0 0 7 18z"/><path d="M12 10.5v3"/><path d="M12 16.2h.01"/></svg></div>' +
'<h2>Weather data couldn\u2019t be loaded</h2>' +
'<p>' + esc(msg) + '</p>' +
'<button type="button" id="retry">Try again</button>' +
'</div>';
document.getElementById("retry").addEventListener("click", load);
}
function renderData(d) {
const info = d.code != null && WMO[d.code] ? WMO[d.code] : null;
const condName = info ? info[0] : (d.code != null ? "Weather code " + d.code : "Condition unavailable");
const group = info ? info[1] : "unknown";
applyTheme(info ? group : "neutral");
const has = d.byHour.some(v => v != null);
let summary;
if (has) {
const vals = d.byHour.filter(v => v != null);
const hH = d.byHour.indexOf(Math.max(...vals)), lH = d.byHour.indexOf(Math.min(...vals));
summary = 'Warmest around <strong>' + pad2(hH) + ':00</strong>, coolest around <strong>' + pad2(lH) + ':00</strong> UTC.' +
' A daily swing of <strong>' + fmt(d.max - d.min, 1) + '\u00b0C</strong>.';
} else {
summary = 'A daily swing of <strong>' + fmt(d.max - d.min, 1) + '\u00b0C</strong>. Hourly detail is unavailable.';
}
const chart = has ? buildChart(d.byHour) : null;
content.innerHTML =
'<div class="hero fade">' +
'<div class="badge">' + icon(group) + '</div>' +
'<div><p class="cond">' + esc(condName) + '</p><p class="summary">' + summary + '</p></div>' +
'<div class="tiles">' +
'<div class="tile"><div class="tile-label"><span class="arrow" style="background:' + tempColor(d.max) + '">' + ARROW_UP + '</span>High</div>' +
'<div class="tile-value">' + fmt(d.max, 1) + '<span class="unit">\u00b0C</span></div></div>' +
'<div class="tile"><div class="tile-label"><span class="arrow" style="background:' + tempColor(d.min) + '">' + ARROW_DOWN + '</span>Low</div>' +
'<div class="tile-value">' + fmt(d.min, 1) + '<span class="unit">\u00b0C</span></div></div>' +
'</div>' +
'</div>' +
'<div class="chart-wrap fade" style="animation-delay:.08s">' +
'<div class="chart-head"><h2 class="chart-title">Hourly temperature</h2><span class="chart-note">\u00b0C \u00b7 hours in UTC</span></div>' +
(chart ? chart.svg : '<div class="no-hourly" role="note">Hourly temperatures are not available for this date.</div>') +
'</div>';
if (chart) chart.wire();
}
// ---------- Data ----------
let controller = null;
async function load() {
if (controller) controller.abort();
controller = new AbortController();
const ctrl = controller;
const timer = setTimeout(() => ctrl.abort(), 15000);
renderLoading();
const endpoint = isPast ? "/api/om/archive" : "/api/om/forecast";
const url = endpoint +
"?latitude=" + encodeURIComponent(String(lat)) +
"&longitude=" + encodeURIComponent(String(lon)) +
"&daily=temperature_2m_max,temperature_2m_min,weather_code" +
"&hourly=temperature_2m" +
"&timezone=UTC" +
"&temperature_unit=celsius" +
"&start_date=" + date +
"&end_date=" + date;
try {
let res;
try {
res = await fetch(url, { signal: ctrl.signal, headers: { Accept: "application/json" } });
} catch (e) {
if (ctrl !== controller) return;
throw new Error(e && e.name === "AbortError"
? "The weather service took too long to respond."
: "The weather service could not be reached. Check your connection and try again.");
}
let body = null;
try { body = await res.json(); } catch (_) { body = null; }
if (ctrl !== controller) return;
if (!res.ok || !body || body.error) {
const reason = body && body.reason ? body.reason : "The weather service responded with status " + res.status + ".";
throw new Error(reason);
}
const daily = body.daily;
if (!daily || !Array.isArray(daily.time)) throw new Error("The response did not include daily weather data.");
const idx = daily.time.indexOf(date);
if (idx < 0) throw new Error("No weather data was returned for " + longDate + ".");
const pick = (arr) => Array.isArray(arr) && typeof arr[idx] === "number" && isFinite(arr[idx]) ? arr[idx] : null;
const max = pick(daily.temperature_2m_max);
const min = pick(daily.temperature_2m_min);
const code = pick(daily.weather_code);
if (max == null || min == null) {
throw new Error("Temperature data for " + longDate + " is not available" + (isPast ? " yet in the historical archive." : "."));
}
const byHour = new Array(24).fill(null);
const hourly = body.hourly;
if (hourly && Array.isArray(hourly.time) && Array.isArray(hourly.temperature_2m)) {
hourly.time.forEach((t, i) => {
if (typeof t !== "string" || t.slice(0, 10) !== date) return;
const h = parseInt(t.slice(11, 13), 10);
const v = hourly.temperature_2m[i];
if (h >= 0 && h < 24 && typeof v === "number" && isFinite(v)) byHour[h] = v;
});
}
renderData({ max, min, code, byHour });
} catch (err) {
if (ctrl !== controller) return;
renderError((err && err.message) || "An unexpected error occurred.");
} finally {
clearTimeout(timer);
}
}
load();
})();
</script>
</body>
</html>L1 —— 廉价的确定性描述量
| bytes 总计 | 31,026 | html / css / js | 1,125 / 7,746 / 22,155 |
|---|---|---|---|
| dom 节点 | 25 | dom 深度 | 7 |
| css 规则 | 64 | 含 js | 是 |
| brightness | 196.3 | contrast | 53.5 |
| colorfulness | 29.2 | 留白 | 59.3% |
该 slot 的 telemetry
| prompt tokens | 2 | completion tokens | 27,930 |
|---|---|---|---|
| total tokens | 27,932 | wall | 240.8 s |
| cost | — | request id | — |
config.json573 B
{
"N": 2,
"auth": {
"credential_ref": "WCB_NONE",
"method": "oauth-login"
},
"billing": "plan",
"config_id": "claude-opus-5-5-eff-high--cli--claude-code--dev",
"effort": "high",
"family": "claude",
"m": {
"min": 2,
"q": 2
},
"model_id": "claude-opus-5-5",
"protocol": "cli",
"served_model": "claude-opus-5-5",
"telemetry": {
"completion_tokens": 83857,
"cost_usd": null,
"prompt_tokens": 8,
"total_tokens": 83865,
"wall_ms": 698803
},
"transport": "claude-code-cli-headless",
"vendor_sanction_ref": null
}send-log2.5 KB
{
"N": 2,
"batch_id": "2026-09-23--cc-opus55",
"config_id": "claude-opus-5-5-eff-high--cli--claude-code--dev",
"positions": [
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-09-23T02:08:09.260744+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-09-23T02:04:08.492482+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-09-23T02:09:32.611296+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-09-23T02:08:15.164155+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-09-23T02:10:50.674120+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-09-23T02:09:35.876846+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-09-23T02:16:01.092510+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-09-23T02:10:55.310170+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
}
}
}