kimi-k2.5 · go
go
- config
- kimi-k2.5--opencode-go--dev
- batch
- 2026-07-19--unified
- transport
- opencode-go-gateway
- protocol
- api · plan
- served model
- kimi-k2.5
- 采集于
- 2026年7月18日 11:54 · N=2
variant
live
slot 0 · P-q · sandboxed iframe

截图是 similarity 通道测量时的原始像素。运行 live 会在 sandboxed iframe 中重新执行原始输出;渲染结果取决于你的浏览器和字体,不保证与测量像素一致。
similarity 邻居
最近
claude-sonnet-4-6 @max · kiro0.72gpt-5.6-sol @xhigh · codex-oauth0.69claude-opus-4-8 @low · kiro0.66gpt-5.4 @none · api0.66grok-4.5 @low · api0.66最远
gpt-5.6-terra @medium · kiro0.36gpt-5.6-luna @medium · codex-oauth0.39gpt-5.6-luna @high · kiro0.39gpt-5.5 @low · codex-oauth0.41gpt-5.6-luna @low · codex-oauth0.42限于 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=1280, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Weather Card</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
width: 1280px;
height: 800px;
overflow: hidden;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
body {
background: #070B14;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
/* ── Animated deep ocean background ── */
.bg-orb {
position: absolute;
border-radius: 50%;
filter: blur(120px);
opacity: 0.35;
pointer-events: none;
animation: orbFloat 20s ease-in-out infinite;
}
.bg-orb.orb-1 {
width: 700px;
height: 700px;
background: radial-gradient(circle, #1a5f9e 0%, transparent 70%);
top: -150px;
left: -100px;
animation-duration: 24s;
}
.bg-orb.orb-2 {
width: 600px;
height: 600px;
background: radial-gradient(circle, #0d8b6d 0%, transparent 70%);
bottom: -100px;
right: -80px;
animation-duration: 28s;
animation-delay: -8s;
}
.bg-orb.orb-3 {
width: 500px;
height: 500px;
background: radial-gradient(circle, #2e3a87 0%, transparent 70%);
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
animation-duration: 32s;
animation-delay: -15s;
opacity: 0.2;
}
.bg-mesh {
position: absolute;
inset: 0;
background:
radial-gradient(ellipse at 20% 30%, rgba(26,95,158,0.12) 0%, transparent 50%),
radial-gradient(ellipse at 80% 70%, rgba(13,139,109,0.08) 0%, transparent 50%),
radial-gradient(ellipse at 50% 50%, rgba(46,58,135,0.06) 0%, transparent 60%);
pointer-events: none;
}
.grain {
position: absolute;
inset: 0;
opacity: 0.03;
pointer-events: none;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
background-repeat: repeat;
background-size: 256px 256px;
}
@keyframes orbFloat {
0%, 100% { transform: translate(0, 0) scale(1); }
25% { transform: translate(40px, -30px) scale(1.05); }
50% { transform: translate(-20px, 20px) scale(0.95); }
75% { transform: translate(30px, 40px) scale(1.02); }
}
/* ── Glass card ── */
.card-container {
position: relative;
z-index: 10;
width: 720px;
height: 520px;
background: rgba(16, 24, 45, 0.55);
backdrop-filter: blur(40px) saturate(1.4);
-webkit-backdrop-filter: blur(40px) saturate(1.4);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 32px;
box-shadow:
0 32px 80px rgba(0, 0, 0, 0.5),
0 0 0 1px rgba(255, 255, 255, 0.04) inset,
0 1px 0 rgba(255, 255, 255, 0.08) inset;
display: flex;
flex-direction: column;
overflow: hidden;
}
.card-shine {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 50%;
background: linear-gradient(180deg, rgba(255,255,255,0.04) 0%, transparent 100%);
border-radius: 32px 32px 0 0;
pointer-events: none;
}
/* ── Loading ── */
.loading-overlay {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 100;
background: rgba(16, 24, 45, 0.8);
backdrop-filter: blur(20px);
border-radius: 32px;
transition: opacity 0.6s ease;
}
.loading-overlay.hidden {
opacity: 0;
pointer-events: none;
}
.spinner-ring {
width: 56px;
height: 56px;
border: 2.5px solid rgba(255, 255, 255, 0.06);
border-top-color: rgba(100, 180, 255, 0.9);
border-right-color: rgba(100, 180, 255, 0.4);
border-radius: 50%;
animation: spin 1.2s cubic-bezier(0.4, 0.15, 0.6, 0.85) infinite;
position: relative;
}
.spinner-ring::after {
content: '';
position: absolute;
inset: -6px;
border-radius: 50%;
border: 1px solid rgba(100, 180, 255, 0.1);
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.loading-text {
margin-top: 20px;
color: rgba(255,255,255,0.45);
font-size: 13px;
font-weight: 400;
letter-spacing: 0.08em;
text-transform: uppercase;
}
/* ── Error ── */
.error-state {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 90;
padding: 60px;
text-align: center;
display: none;
}
.error-state.active {
display: flex;
}
.error-icon {
width: 64px;
height: 64px;
margin-bottom: 24px;
opacity: 0.5;
}
.error-state h2 {
color: rgba(255, 255, 255, 0.8);
font-size: 20px;
font-weight: 500;
margin-bottom: 10px;
}
.error-state p {
color: rgba(255, 255, 255, 0.35);
font-size: 14px;
line-height: 1.6;
}
/* ── Card header ── */
.card-header {
padding: 32px 36px 0;
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.location-block {
flex: 1;
}
.location-name {
color: #fff;
font-size: 28px;
font-weight: 600;
letter-spacing: -0.02em;
line-height: 1.2;
text-shadow: 0 2px 12px rgba(0,0,0,0.3);
}
.date-display {
color: rgba(255,255,255,0.45);
font-size: 14px;
font-weight: 400;
margin-top: 5px;
letter-spacing: 0.02em;
}
.weather-icon-wrap {
width: 80px;
height: 80px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.weather-icon-wrap svg {
width: 64px;
height: 64px;
filter: drop-shadow(0 4px 16px rgba(0,0,0,0.3));
}
/* ── Hero temperature ── */
.hero-section {
padding: 16px 36px 0;
display: flex;
align-items: flex-end;
gap: 16px;
}
.temp-main {
color: #fff;
font-size: 96px;
font-weight: 200;
line-height: 0.9;
letter-spacing: -0.04em;
font-variant-numeric: tabular-nums;
text-shadow: 0 4px 24px rgba(0,0,0,0.25);
}
.temp-main sup {
font-size: 32px;
font-weight: 300;
color: rgba(255,255,255,0.5);
vertical-align: super;
margin-left: 2px;
}
.temp-side {
display: flex;
flex-direction: column;
gap: 6px;
padding-bottom: 18px;
}
.condition-text {
color: rgba(255,255,255,0.85);
font-size: 18px;
font-weight: 500;
letter-spacing: -0.01em;
text-shadow: 0 2px 8px rgba(0,0,0,0.2);
}
.temp-range {
color: rgba(255,255,255,0.45);
font-size: 13px;
font-weight: 400;
letter-spacing: 0.01em;
}
.temp-range .hi {
color: rgba(255, 160, 122, 0.85);
}
.temp-range .lo {
color: rgba(135, 206, 250, 0.85);
}
/* ── Divider ── */
.divider {
height: 1px;
margin: 28px 36px 0;
background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.1) 30%, rgba(255,255,255,0.1) 70%, transparent 100%);
position: relative;
}
.divider::after {
content: '';
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 6px;
height: 6px;
background: rgba(255,255,255,0.15);
border-radius: 50%;
}
/* ── Chart section ── */
.chart-section {
flex: 1;
padding: 20px 36px 24px;
display: flex;
flex-direction: column;
min-height: 0;
}
.chart-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 14px;
}
.chart-title {
color: rgba(255,255,255,0.35);
font-size: 11px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.14em;
}
.chart-legend {
display: flex;
align-items: center;
gap: 6px;
}
.legend-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: rgba(100, 200, 255, 0.8);
box-shadow: 0 0 6px rgba(100, 200, 255, 0.4);
}
.legend-label {
color: rgba(255,255,255,0.3);
font-size: 11px;
font-weight: 400;
}
.chart-wrap {
flex: 1;
position: relative;
min-height: 0;
}
.chart-canvas {
width: 100%;
height: 100%;
display: block;
}
/* ── Hourly strip ── */
.hourly-strip {
padding: 0 36px 24px;
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.hour-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
}
.hour-label {
color: rgba(255,255,255,0.35);
font-size: 11px;
font-weight: 500;
font-variant-numeric: tabular-nums;
letter-spacing: 0.02em;
}
.hour-temp {
color: rgba(255,255,255,0.6);
font-size: 13px;
font-weight: 500;
font-variant-numeric: tabular-nums;
}
/* ── Responsive ── */
@media (max-width: 750px) {
.card-container {
width: calc(100vw - 40px);
height: auto;
min-height: 480px;
}
.temp-main {
font-size: 72px;
}
.location-name {
font-size: 22px;
}
}
</style>
</head>
<body>
<div class="bg-orb orb-1"></div>
<div class="bg-orb orb-2"></div>
<div class="bg-orb orb-3"></div>
<div class="bg-mesh"></div>
<div class="grain"></div>
<div class="card-container" id="card">
<div class="card-shine"></div>
<div class="loading-overlay" id="loading">
<div class="spinner-ring"></div>
<div class="loading-text">Fetching weather data</div>
</div>
<div class="error-state" id="error">
<svg class="error-icon" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="1.5">
<circle cx="12" cy="12" r="10"/>
<path d="M12 8v4M12 16h.01"/>
</svg>
<h2>Unable to load weather data</h2>
<p>We couldn't retrieve the forecast for this location.<br>Please check your connection and try again.</p>
</div>
<div class="card-header" id="header">
<div class="location-block">
<div class="location-name" id="locName">--</div>
<div class="date-display" id="dateDisp">--</div>
</div>
<div class="weather-icon-wrap" id="weatherIcon"></div>
</div>
<div class="hero-section">
<div class="temp-main" id="avgTemp">--<sup>°C</sup></div>
<div class="temp-side">
<div class="condition-text" id="condition">--</div>
<div class="temp-range">
<span class="hi" id="maxTemp">--</span> / <span class="lo" id="minTemp">--</span>
</div>
</div>
</div>
<div class="divider"></div>
<div class="chart-section">
<div class="chart-header">
<div class="chart-title">Hourly Temperature</div>
<div class="chart-legend">
<div class="legend-dot"></div>
<div class="legend-label">Temperature °C</div>
</div>
</div>
<div class="chart-wrap">
<canvas class="chart-canvas" id="chartCanvas"></canvas>
</div>
</div>
<div class="hourly-strip" id="hourlyStrip"></div>
</div>
<script>
(function() {
// ── Helpers ──
function getParam(name, fallback) {
const params = new URLSearchParams(window.location.search);
const v = params.get(name);
return (v !== null && v !== '') ? v : fallback;
}
function fmtDate(d) {
return d.getFullYear() + '-' +
String(d.getMonth()+1).padStart(2,'0') + '-' +
String(d.getDate()).padStart(2,'0');
}
function fmtDisplayDate(iso) {
const d = new Date(iso + 'T00:00:00Z');
const opts = { weekday:'long', year:'numeric', month:'long', day:'numeric', timeZone:'UTC' };
return d.toLocaleDateString('en-US', opts);
}
function isPastDate(iso) {
const today = fmtDate(new Date());
return iso < today;
}
// ── Weather icon SVGs ──
const wmoIcons = {
0: '<svg viewBox="0 0 64 64" fill="none"><circle cx="32" cy="32" r="14" fill="url(#sunGrad)" filter="url(#glow)"/><defs><radialGradient id="sunGrad" cx="50%" cy="50%"><stop offset="0%" stop-color="#FFE082"/><stop offset="100%" stop-color="#FFB300"/></radialGradient><filter id="glow"><feGaussianBlur stdDeviation="4" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter></svg>',
1: '<svg viewBox="0 0 64 64" fill="none"><circle cx="32" cy="32" r="12" fill="url(#sunGrad)"/><ellipse cx="38" cy="36" rx="10" ry="6" fill="rgba(255,255,255,0.35)"/><defs><radialGradient id="sunGrad" cx="50%" cy="50%"><stop offset="0%" stop-color="#FFE082"/><stop offset="100%" stop-color="#FFB300"/></radialGradient></defs></svg>',
2: '<svg viewBox="0 0 64 64" fill="none"><circle cx="28" cy="28" r="10" fill="url(#sunGrad)"/><ellipse cx="36" cy="34" rx="14" ry="8" fill="rgba(255,255,255,0.5)"/><ellipse cx="38" cy="38" rx="12" ry="7" fill="rgba(255,255,255,0.3)"/><defs><radialGradient id="sunGrad" cx="50%" cy="50%"><stop offset="0%" stop-color="#FFE082"/><stop offset="100%" stop-color="#FFB300"/></radialGradient></defs></svg>',
3: '<svg viewBox="0 0 64 64" fill="none"><ellipse cx="32" cy="32" rx="18" ry="10" fill="rgba(255,255,255,0.6)"/><ellipse cx="28" cy="36" rx="14" ry="8" fill="rgba(255,255,255,0.4)"/><ellipse cx="36" cy="30" rx="12" ry="7" fill="rgba(255,255,255,0.5)"/></svg>',
45: '<svg viewBox="0 0 64 64" fill="none"><path d="M20 36 Q24 28, 32 32 Q40 36, 44 28" stroke="rgba(200,200,200,0.6)" stroke-width="2" fill="none" stroke-linecap="round"/><path d="M18 42 Q22 34, 30 38 Q38 42, 42 34" stroke="rgba(180,180,180,0.4)" stroke-width="2" fill="none" stroke-linecap="round"/></svg>',
48: '<svg viewBox="0 0 64 64" fill="none"><path d="M20 36 Q24 28, 32 32 Q40 36, 44 28" stroke="rgba(200,200,200,0.6)" stroke-width="2" fill="none" stroke-linecap="round"/><circle cx="24" cy="44" r="1.5" fill="rgba(200,200,200,0.5)"/><circle cx="32" cy="48" r="1.5" fill="rgba(200,200,200,0.5)"/><circle cx="40" cy="44" r="1.5" fill="rgba(200,200,200,0.5)"/></svg>',
51: '<svg viewBox="0 0 64 64" fill="none"><ellipse cx="32" cy="28" rx="16" ry="8" fill="rgba(200,210,230,0.5)"/><path d="M24 40 L22 46M32 40 L30 46M40 40 L38 46" stroke="rgba(150,180,220,0.7)" stroke-width="2" stroke-linecap="round"/></svg>',
53: '<svg viewBox="0 0 64 64" fill="none"><ellipse cx="32" cy="28" rx="16" ry="8" fill="rgba(180,190,210,0.6)"/><path d="M22 40 L20 48M30 40 L28 48M38 40 L36 48M46 40 L44 48" stroke="rgba(130,160,200,0.8)" stroke-width="2" stroke-linecap="round"/></svg>',
55: '<svg viewBox="0 0 64 64" fill="none"><ellipse cx="32" cy="28" rx="16" ry="8" fill="rgba(160,170,190,0.7)"/><path d="M20 40 L18 48M28 40 L26 48M36 40 L34 48M44 40 L42 48" stroke="rgba(110,140,180,0.9)" stroke-width="2.5" stroke-linecap="round"/></svg>',
61: '<svg viewBox="0 0 64 64" fill="none"><ellipse cx="32" cy="26" rx="16" ry="8" fill="rgba(180,190,210,0.6)"/><path d="M24 38 L22 48M32 38 L30 48M40 38 L38 48" stroke="rgba(100,160,255,0.8)" stroke-width="2" stroke-linecap="round"/></svg>',
63: '<svg viewBox="0 0 64 64" fill="none"><ellipse cx="32" cy="26" rx="16" ry="8" fill="rgba(160,170,190,0.7)"/><path d="M22 38 L20 48M30 38 L28 48M38 38 L36 48M46 38 L44 48" stroke="rgba(90,150,245,0.85)" stroke-width="2" stroke-linecap="round"/></svg>',
65: '<svg viewBox="0 0 64 64" fill="none"><ellipse cx="32" cy="26" rx="16" ry="8" fill="rgba(140,150,170,0.8)"/><path d="M20 38 L18 48M28 38 L26 48M36 38 L34 48M44 38 L42 48" stroke="rgba(80,140,235,0.9)" stroke-width="2.5" stroke-linecap="round"/></svg>',
71: '<svg viewBox="0 0 64 64" fill="none"><ellipse cx="32" cy="26" rx="16" ry="8" fill="rgba(200,210,230,0.6)"/><text x="22" y="48" fill="rgba(220,230,255,0.8)" font-size="14" font-family="sans-serif">*</text><text x="30" y="52" fill="rgba(220,230,255,0.8)" font-size="14" font-family="sans-serif">*</text><text x="38" y="48" fill="rgba(220,230,255,0.8)" font-size="14" font-family="sans-serif">*</text></svg>',
73: '<svg viewBox="0 0 64 64" fill="none"><ellipse cx="32" cy="26" rx="16" ry="8" fill="rgba(190,200,220,0.7)"/><text x="18" y="48" fill="rgba(210,220,250,0.85)" font-size="16" font-family="sans-serif">*</text><text x="26" y="52" fill="rgba(210,220,250,0.85)" font-size="16" font-family="sans-serif">*</text><text x="34" y="48" fill="rgba(210,220,250,0.85)" font-size="16" font-family="sans-serif">*</text><text x="42" y="52" fill="rgba(210,220,250,0.85)" font-size="16" font-family="sans-serif">*</text></svg>',
75: '<svg viewBox="0 0 64 64" fill="none"><ellipse cx="32" cy="26" rx="16" ry="8" fill="rgba(170,180,200,0.8)"/><text x="16" y="48" fill="rgba(200,210,240,0.9)" font-size="18" font-family="sans-serif">*</text><text x="24" y="54" fill="rgba(200,210,240,0.9)" font-size="18" font-family="sans-serif">*</text><text x="32" y="48" fill="rgba(200,210,240,0.9)" font-size="18" font-family="sans-serif">*</text><text x="40" y="54" fill="rgba(200,210,240,0.9)" font-size="18" font-family="sans-serif">*</text><text x="48" y="48" fill="rgba(200,210,240,0.9)" font-size="18" font-family="sans-serif">*</text></svg>',
95: '<svg viewBox="0 0 64 64" fill="none"><ellipse cx="32" cy="26" rx="16" ry="8" fill="rgba(140,150,170,0.7)"/><path d="M28 36 L32 44 L30 44 L34 52" stroke="rgba(255,220,100,0.9)" stroke-width="2.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>',
96: '<svg viewBox="0 0 64 64" fill="none"><ellipse cx="32" cy="26" rx="16" ry="8" fill="rgba(130,140,160,0.7)"/><path d="M28 36 L32 44 L30 44 L34 52" stroke="rgba(255,220,100,0.9)" stroke-width="2.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/><circle cx="24" cy="48" r="1.5" fill="rgba(100,160,255,0.8)"/><circle cx="40" cy="50" r="1.5" fill="rgba(100,160,255,0.8)"/></svg>',
99: '<svg viewBox="0 0 64 64" fill="none"><ellipse cx="32" cy="26" rx="16" ry="8" fill="rgba(120,130,150,0.8)"/><path d="M26 36 L30 44 L28 44 L32 52" stroke="rgba(255,210,80,0.95)" stroke-width="3" fill="none" stroke-linecap="round" stroke-linejoin="round"/><circle cx="20" cy="48" r="2" fill="rgba(90,150,245,0.85)"/><circle cx="44" cy="50" r="2" fill="rgba(90,150,245,0.85)"/></svg>',
};
function getWmoIcon(code) {
if (wmoIcons[code]) return wmoIcons[code];
if (code >= 80 && code <= 82) return wmoIcons[61] || wmoIcons[51];
if (code >= 85 && code <= 86) return wmoIcons[71] || wmoIcons[51];
if (code >= 95 && code <= 99) return wmoIcons[95];
return wmoIcons[3];
}
const wmoLabels = {
0:'Clear sky', 1:'Mainly clear', 2:'Partly cloudy', 3:'Overcast',
45:'Fog', 48:'Depositing rime fog',
51:'Light drizzle', 53:'Moderate drizzle', 55:'Dense drizzle',
61:'Slight rain', 63:'Moderate rain', 65:'Heavy rain',
71:'Slight snow', 73:'Moderate snow', 75:'Heavy snow',
80:'Slight rain showers', 81:'Moderate rain showers', 82:'Violent rain showers',
85:'Slight snow showers', 86:'Heavy snow showers',
95:'Thunderstorm', 96:'Thunderstorm with hail', 99:'Thunderstorm with heavy hail',
};
function getWmoLabel(code) {
return wmoLabels[code] || 'Unknown';
}
// ── Canvas chart ──
function drawChart(hourlyData, min, max) {
const canvas = document.getElementById('chartCanvas');
const rect = canvas.getBoundingClientRect();
const dpr = window.devicePixelRatio || 1;
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
const ctx = canvas.getContext('2d');
ctx.scale(dpr, dpr);
const W = rect.width, H = rect.height;
const padL = 8, padR = 8, padT = 24, padB = 8;
ctx.clearRect(0, 0, W, H);
const range = max - min || 1;
const n = hourlyData.length;
function x(i) {
return padL + (W - padL - padR) * (i / (n - 1 || 1));
}
function y(t) {
return padT + (H - padT - padB) * (1 - (t - min) / range);
}
// Gradient fill
const grad = ctx.createLinearGradient(0, padT, 0, H - padB);
grad.addColorStop(0, 'rgba(100, 200, 255, 0.25)');
grad.addColorStop(0.5, 'rgba(100, 200, 255, 0.08)');
grad.addColorStop(1, 'rgba(100, 200, 255, 0.0)');
// Build smooth path
const points = hourlyData.map((d, i) => ({ x: x(i), y: y(d.t) }));
ctx.beginPath();
ctx.moveTo(points[0].x, H - padB);
for (let i = 0; i < points.length; i++) {
ctx.lineTo(points[i].x, points[i].y);
}
ctx.lineTo(points[points.length - 1].x, H - padB);
ctx.closePath();
ctx.fillStyle = grad;
ctx.fill();
// Glow line
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
for (let i = 1; i < points.length; i++) {
const prev = points[i - 1], curr = points[i];
const cpx = (prev.x + curr.x) / 2;
ctx.quadraticCurveTo(prev.x, prev.y, cpx, (prev.y + curr.y) / 2);
}
ctx.lineTo(points[points.length - 1].x, points[points.length - 1].y);
ctx.strokeStyle = 'rgba(100, 210, 255, 0.85)';
ctx.lineWidth = 2.5;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.shadowColor = 'rgba(100, 210, 255, 0.5)';
ctx.shadowBlur = 12;
ctx.stroke();
ctx.shadowBlur = 0;
// Dots with glow
points.forEach((p, i) => {
const isPeak = i === 0 || i === points.length - 1 || (i > 0 && i < points.length - 1 && p.y <= points[i-1].y && p.y <= points[i+1].y);
const isValley = i > 0 && i < points.length - 1 && p.y >= points[i-1].y && p.y >= points[i+1].y;
if (isPeak || isValley) {
ctx.beginPath();
ctx.arc(p.x, p.y, 5, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(100, 210, 255, 0.3)';
ctx.fill();
ctx.beginPath();
ctx.arc(p.x, p.y, 3, 0, Math.PI * 2);
ctx.fillStyle = '#64D2FF';
ctx.shadowColor = 'rgba(100, 210, 255, 0.6)';
ctx.shadowBlur = 8;
ctx.fill();
ctx.shadowBlur = 0;
// Temp labels at peaks/valleys
ctx.fillStyle = isPeak ? 'rgba(255,255,255,0.7)' : 'rgba(255,255,255,0.5)';
ctx.font = '500 11px Inter, sans-serif';
ctx.textAlign = 'center';
ctx.fillText(Math.round(hourlyData[i].t) + '\xB0', p.x, p.y - (isPeak ? 14 : -20));
}
});
// X-axis faint grid
ctx.strokeStyle = 'rgba(255,255,255,0.03)';
ctx.lineWidth = 1;
for (let i = 0; i < n; i += 3) {
ctx.beginPath();
ctx.moveTo(x(i), padT);
ctx.lineTo(x(i), H - padB);
ctx.stroke();
}
}
// ── Hourly strip ──
function renderHourly(hourlyData) {
const strip = document.getElementById('hourlyStrip');
strip.innerHTML = '';
const indices = [0, 3, 6, 9, 12, 15, 18, 21, 23];
indices.forEach(i => {
if (i >= hourlyData.length) return;
const h = hourlyData[i];
const el = document.createElement('div');
el.className = 'hour-item';
el.innerHTML =
'<div class="hour-label">' + h.label + '</div>' +
'<div class="hour-temp">' + Math.round(h.t) + '\xB0</div>';
strip.appendChild(el);
});
}
// ── Main ──
async function init() {
const lat = getParam('lat', '52.52');
const lon = getParam('lon', '13.405');
const name = getParam('name', 'Berlin');
const date = getParam('date', fmtDate(new Date()));
const locEl = document.getElementById('locName');
const dateEl = document.getElementById('dateDisp');
const avgEl = document.getElementById('avgTemp');
const condEl = document.getElementById('condition');
const maxEl = document.getElementById('maxTemp');
const minEl = document.getElementById('minTemp');
const iconEl = document.getElementById('weatherIcon');
const loadEl = document.getElementById('loading');
const errEl = document.getElementById('error');
locEl.textContent = name;
dateEl.textContent = fmtDisplayDate(date);
const endpoint = isPastDate(date) ? '/api/om/archive' : '/api/om/forecast';
const url = endpoint +
'?latitude=' + encodeURIComponent(lat) +
'&longitude=' + encodeURIComponent(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 {
const res = await fetch(url);
if (!res.ok) throw new Error('HTTP ' + res.status);
const data = await res.json();
// Validate structure
if (!data.daily || !data.daily.time || !data.daily.time.length) {
throw new Error('Missing daily data');
}
if (!data.hourly || !data.hourly.time || !data.hourly.time.length) {
throw new Error('Missing hourly data');
}
const max = data.daily.temperature_2m_max[0];
const min = data.daily.temperature_2m_min[0];
const code = data.daily.weather_code[0];
const avg = ((max + min) / 2);
// Filter hourly for the requested date
const datePrefix = date + 'T';
const hourly = [];
for (let i = 0; i < data.hourly.time.length; i++) {
if (data.hourly.time[i].startsWith(datePrefix)) {
const h = parseInt(data.hourly.time[i].slice(11, 13), 10);
const label = (h === 0 ? '12am' : h < 12 ? h + 'am' : h === 12 ? '12pm' : (h - 12) + 'pm');
hourly.push({ t: data.hourly.temperature_2m[i], label });
}
}
if (!hourly.length) throw new Error('No hourly data for date');
// Compute chart range with padding
const hTemps = hourly.map(h => h.t);
const hMin = Math.min(...hTemps), hMax = Math.max(...hTemps);
const cMin = hMin - 1, cMax = hMax + 1;
avgEl.innerHTML = Math.round(avg) + '<sup>°C</sup>';
condEl.textContent = getWmoLabel(code);
maxEl.innerHTML = 'H: ' + Math.round(max) + '°';
minEl.innerHTML = 'L: ' + Math.round(min) + '°';
iconEl.innerHTML = getWmoIcon(code);
drawChart(hourly, cMin, cMax);
renderHourly(hourly);
loadEl.classList.add('hidden');
} catch (e) {
console.error('Weather load error:', e);
loadEl.classList.add('hidden');
errEl.classList.add('active');
}
}
init();
})();
</script>
</body>
</html>L1 —— 廉价的确定性描述量
| bytes 总计 | 28,123 | html / css / js | 2,227 / 9,939 / 15,957 |
|---|---|---|---|
| dom 节点 | 48 | dom 深度 | 7 |
| css 规则 | 60 | 含 js | 是 |
| brightness | 24.1 | contrast | 11.8 |
| colorfulness | 17.6 | 留白 | 96.6% |
该 slot 的 telemetry
| prompt tokens | 313 | completion tokens | 9,825 |
|---|---|---|---|
| total tokens | 10,138 | wall | 56.2 s |
| cost | — | request id | — |
config.json543 B
{
"N": 2,
"auth": {
"credential_ref": "WCB_OPENCODE_KEY",
"method": "oauth-login"
},
"billing": "plan",
"config_id": "kimi-k2.5--opencode-go--dev",
"effort": null,
"family": "kimi",
"m": {
"min": 2,
"q": 2
},
"model_id": "kimi-k2.5",
"protocol": "api",
"served_model": "kimi-k2.5",
"telemetry": {
"completion_tokens": 53519,
"cost_usd": null,
"prompt_tokens": 1236,
"total_tokens": 54755,
"wall_ms": 328614
},
"transport": "opencode-go-gateway",
"vendor_sanction_ref": null
}send-log2.4 KB
{
"N": 2,
"batch_id": "2026-07-18--dev-go-extra",
"config_id": "kimi-k2.5--opencode-go--dev",
"positions": [
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-18T00:11:29.297828+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-18T00:10:33.099603+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-18T00:12:18.082759+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-18T00:11:35.472106+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-18T00:13:20.076716+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-18T00:12:22.512124+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-18T00:16:15.946285+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-18T00:13:23.699888+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
}
}
}