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

渲染不确定 — 同一份输入重复渲染会得到不同像素(随机/时间相关的内容),因此视觉通道对这张卡的读数不如其他卡稳定。
截图是 similarity 通道测量时的原始像素。运行 live 会在 sandboxed iframe 中重新执行原始输出;渲染结果取决于你的浏览器和字体,不保证与测量像素一致。
similarity 邻居
最近
gemini-3.8-flash @medium · agy0.76gemini-3.8-flash @high · agy0.75gemini-3.7-flash @medium · agy0.75gemini-3.7-flash @high · agy0.75gemini-3.6-flash @low · cursor0.74最远
north-mini-code-free · api0.51grok-4.6 @medium · grok-cli0.51claude-haiku-4-5 @max · CC0.52claude-sonnet-4 · cursor0.53claude-opus-4-8 @max · CC0.53限于 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, height=800, initial-scale=1.0">
<title>Weather Dashboard</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
width: 1280px;
height: 800px;
margin: 0 auto;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background-color: #0b1329;
color: #f1f5f9;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
}
.app-card {
width: 1280px;
height: 800px;
padding: 32px 40px;
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
background: radial-gradient(circle at 20% 20%, rgba(30, 58, 138, 0.4) 0%, transparent 50%),
radial-gradient(circle at 80% 80%, rgba(88, 28, 135, 0.3) 0%, transparent 50%),
#0b132b;
transition: background 0.8s ease-in-out;
}
.app-card.theme-sunny {
background: radial-gradient(circle at 15% 15%, rgba(245, 158, 11, 0.25) 0%, transparent 45%),
radial-gradient(circle at 85% 75%, rgba(14, 165, 233, 0.25) 0%, transparent 45%),
#0b1528;
}
.app-card.theme-cloudy {
background: radial-gradient(circle at 20% 20%, rgba(100, 116, 139, 0.3) 0%, transparent 50%),
radial-gradient(circle at 80% 80%, rgba(30, 41, 59, 0.5) 0%, transparent 50%),
#0f172a;
}
.app-card.theme-rain {
background: radial-gradient(circle at 20% 20%, rgba(14, 165, 233, 0.3) 0%, transparent 50%),
radial-gradient(circle at 80% 80%, rgba(15, 23, 42, 0.6) 0%, transparent 50%),
#081226;
}
.app-card.theme-snow {
background: radial-gradient(circle at 20% 20%, rgba(56, 189, 248, 0.3) 0%, transparent 50%),
radial-gradient(circle at 80% 80%, rgba(165, 243, 252, 0.15) 0%, transparent 50%),
#081d34;
}
.app-card.theme-thunder {
background: radial-gradient(circle at 20% 20%, rgba(168, 85, 247, 0.3) 0%, transparent 50%),
radial-gradient(circle at 80% 80%, rgba(234, 179, 8, 0.2) 0%, transparent 50%),
#0a081a;
}
.header {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}
.location-info {
display: flex;
align-items: center;
gap: 16px;
}
.location-icon {
width: 44px;
height: 44px;
border-radius: 12px;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.12);
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(12px);
color: #38bdf8;
}
.location-details {
display: flex;
flex-direction: column;
gap: 2px;
}
.location-name {
font-size: 32px;
font-weight: 700;
letter-spacing: -0.5px;
color: #ffffff;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
.location-coords {
font-size: 13px;
color: #94a3b8;
font-weight: 500;
}
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
.date-badge {
display: flex;
align-items: center;
gap: 8px;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.12);
padding: 8px 18px;
border-radius: 20px;
backdrop-filter: blur(12px);
font-size: 14px;
font-weight: 600;
color: #e2e8f0;
}
.api-badge {
font-size: 12px;
font-weight: 600;
padding: 6px 14px;
border-radius: 20px;
display: flex;
align-items: center;
gap: 6px;
letter-spacing: 0.3px;
}
.api-badge.forecast {
background: rgba(16, 185, 129, 0.15);
border: 1px solid rgba(16, 185, 129, 0.3);
color: #34d399;
}
.api-badge.archive {
background: rgba(245, 158, 11, 0.15);
border: 1px solid rgba(245, 158, 11, 0.3);
color: #fbbf24;
}
.dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: currentColor;
}
.hero-section {
display: grid;
grid-template-columns: 1.25fr 1fr;
gap: 24px;
margin-top: 12px;
margin-bottom: 12px;
}
.glass-card {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 24px;
padding: 24px 32px;
backdrop-filter: blur(16px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.25);
}
.weather-hero-card {
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
}
.hero-left {
display: flex;
flex-direction: column;
gap: 6px;
}
.weather-condition-title {
font-size: 24px;
font-weight: 600;
color: #e2e8f0;
text-transform: capitalize;
}
.wmo-code-sub {
font-size: 13px;
color: #94a3b8;
}
.temp-range-container {
display: flex;
align-items: center;
gap: 20px;
margin-top: 10px;
}
.temp-primary {
font-size: 68px;
font-weight: 800;
letter-spacing: -2px;
background: linear-gradient(180deg, #ffffff 0%, #cbd5e1 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
line-height: 1;
}
.hi-low-pills {
display: flex;
flex-direction: column;
gap: 8px;
}
.temp-pill {
display: flex;
align-items: center;
gap: 8px;
font-size: 15px;
font-weight: 700;
padding: 6px 12px;
border-radius: 12px;
}
.temp-pill.high {
background: rgba(239, 68, 68, 0.15);
border: 1px solid rgba(239, 68, 68, 0.25);
color: #fca5a5;
}
.temp-pill.low {
background: rgba(59, 130, 246, 0.15);
border: 1px solid rgba(59, 130, 246, 0.25);
color: #93c5fd;
}
.hero-right-icon {
width: 140px;
height: 140px;
display: flex;
align-items: center;
justify-content: center;
filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.35));
}
.stats-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
.stat-card {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 20px;
padding: 18px 20px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.stat-label {
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.8px;
color: #94a3b8;
display: flex;
align-items: center;
gap: 6px;
}
.stat-value {
font-size: 22px;
font-weight: 700;
color: #f8fafc;
margin-top: 6px;
}
.stat-sub {
font-size: 12px;
color: #64748b;
margin-top: 2px;
}
.chart-section {
position: relative;
display: flex;
flex-direction: column;
gap: 12px;
}
.section-title {
font-size: 13px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
color: #94a3b8;
display: flex;
align-items: center;
justify-content: space-between;
}
.chart-wrapper {
position: relative;
width: 100%;
height: 180px;
background: rgba(15, 23, 42, 0.4);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 20px;
padding: 8px 0;
overflow: hidden;
}
#tempChart {
width: 100%;
height: 100%;
display: block;
}
.chart-point {
transition: r 0.15s ease, fill 0.15s ease;
cursor: pointer;
}
.chart-point:hover, .chart-point.active {
r: 7;
fill: #ffffff !important;
stroke-width: 3;
}
.chart-tooltip {
position: absolute;
padding: 6px 12px;
background: rgba(15, 23, 42, 0.95);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 10px;
font-size: 12px;
font-weight: 700;
color: #ffffff;
pointer-events: none;
opacity: 0;
transform: translate(-50%, -120%);
transition: opacity 0.15s ease, transform 0.15s ease;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
white-space: nowrap;
z-index: 10;
}
.hourly-carousel {
display: flex;
gap: 10px;
overflow-x: auto;
padding-bottom: 4px;
scrollbar-width: none;
}
.hourly-carousel::-webkit-scrollbar {
display: none;
}
.hourly-card {
min-width: 80px;
flex: 1;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.07);
border-radius: 16px;
padding: 12px 8px;
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
transition: all 0.2s ease;
cursor: pointer;
}
.hourly-card:hover, .hourly-card.active {
background: rgba(255, 255, 255, 0.12);
border-color: rgba(255, 255, 255, 0.25);
transform: translateY(-2px);
}
.hourly-time {
font-size: 12px;
font-weight: 600;
color: #94a3b8;
}
.hourly-temp {
font-size: 15px;
font-weight: 700;
color: #ffffff;
}
.hourly-bar-bg {
width: 24px;
height: 4px;
border-radius: 2px;
background: rgba(255, 255, 255, 0.1);
overflow: hidden;
margin-top: 2px;
}
.hourly-bar-fill {
height: 100%;
border-radius: 2px;
background: linear-gradient(90deg, #38bdf8, #f59e0b);
}
.error-container {
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
height: 100%;
gap: 20px;
padding: 40px;
background: rgba(15, 23, 42, 0.85);
border: 1px solid rgba(239, 68, 68, 0.3);
border-radius: 28px;
backdrop-filter: blur(20px);
}
.error-icon {
width: 64px;
height: 64px;
color: #ef4444;
}
.error-title {
font-size: 26px;
font-weight: 700;
color: #f8fafc;
}
.error-message {
font-size: 15px;
color: #94a3b8;
max-width: 550px;
line-height: 1.6;
}
.error-url {
font-family: monospace;
font-size: 12px;
background: rgba(0, 0, 0, 0.4);
padding: 8px 14px;
border-radius: 8px;
color: #fca5a5;
word-break: break-all;
}
.app-content {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
}
</style>
</head>
<body>
<div class="app-card" id="appCard">
<div class="error-container" id="errorContainer">
<svg class="error-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="8" x2="12" y2="12"></line>
<line x1="12" y1="16" x2="12.01" y2="16"></line>
</svg>
<div class="error-title">Weather Data Unavailable</div>
<div class="error-message" id="errorMessage">Unable to load weather data for the specified parameters.</div>
<div class="error-url" id="errorUrl"></div>
</div>
<div class="app-content" id="appContent">
<header class="header">
<div class="location-info">
<div class="location-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path>
<circle cx="12" cy="10" r="3"></circle>
</svg>
</div>
<div class="location-details">
<div class="location-name" id="locationName">Berlin</div>
<div class="location-coords" id="locationCoords">52.52° N, 13.41° E</div>
</div>
</div>
<div class="header-right">
<div class="date-badge" id="dateBadge">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
<line x1="16" y1="2" x2="16" y2="6"></line>
<line x1="8" y1="2" x2="8" y2="6"></line>
<line x1="3" y1="10" x2="21" y2="10"></line>
</svg>
<span id="formattedDate">2026-08-13</span>
</div>
<div class="api-badge forecast" id="apiBadge">
<span class="dot"></span>
<span id="apiBadgeText">Forecast API</span>
</div>
</div>
</header>
<section class="hero-section">
<div class="glass-card weather-hero-card">
<div class="hero-left">
<div class="weather-condition-title" id="weatherCondition">Partly Cloudy</div>
<div class="wmo-code-sub" id="wmoCodeSub">WMO Code: 2</div>
<div class="temp-range-container">
<div class="temp-primary" id="tempPrimary">24.5°C</div>
<div class="hi-low-pills">
<div class="temp-pill high">
<span>↑</span>
<span id="maxTemp">24.5°C</span>
</div>
<div class="temp-pill low">
<span>↓</span>
<span id="minTemp">14.2°C</span>
</div>
</div>
</div>
</div>
<div class="hero-right-icon" id="weatherIconContainer"></div>
</div>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-label">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
Peak Warmest Hour
</div>
<div class="stat-value" id="peakWarmHour">15:00</div>
<div class="stat-sub" id="peakWarmTemp">24.5°C</div>
</div>
<div class="stat-card">
<div class="stat-label">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
Coolest Hour
</div>
<div class="stat-value" id="coolestHour">05:00</div>
<div class="stat-sub" id="coolestTemp">14.2°C</div>
</div>
<div class="stat-card">
<div class="stat-label">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>
Daily Temp Range
</div>
<div class="stat-value" id="tempDelta">10.3°C</div>
<div class="stat-sub">Max minus Min</div>
</div>
<div class="stat-card">
<div class="stat-label">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20M2 12h20"/></svg>
Timezone & Units
</div>
<div class="stat-value">UTC / °C</div>
<div class="stat-sub">Celsius Standard</div>
</div>
</div>
</section>
<section class="chart-section">
<div class="section-title">
<span>Hourly Temperature Trend (24 Hours)</span>
<span style="font-size: 11px; font-weight: 500; color: #64748b;">Hover points for details</span>
</div>
<div class="chart-wrapper">
<div class="chart-tooltip" id="chartTooltip"></div>
<svg id="tempChart" viewBox="0 0 1200 180" preserveAspectRatio="none">
<defs>
<linearGradient id="chartGradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#38bdf8" stop-opacity="0.35"/>
<stop offset="100%" stop-color="#38bdf8" stop-opacity="0.0"/>
</linearGradient>
</defs>
<g id="chartGridLines"></g>
<path id="chartArea" fill="url(#chartGradient)"/>
<path id="chartLine" fill="none" stroke="#38bdf8" stroke-width="3.5" stroke-linecap="round"/>
<g id="chartPoints"></g>
<g id="chartLabels"></g>
</svg>
</div>
</section>
<section class="hourly-carousel" id="hourlyCarousel"></section>
</div>
</div>
<script>
const WMO_MAP = {
0: { label: 'Clear Sky', theme: 'sunny', icon: 'sun' },
1: { label: 'Mainly Clear', theme: 'sunny', icon: 'cloud-sun' },
2: { label: 'Partly Cloudy', theme: 'cloudy', icon: 'cloud-sun' },
3: { label: 'Overcast', theme: 'cloudy', icon: 'cloud' },
45: { label: 'Foggy', theme: 'cloudy', icon: 'fog' },
48: { label: 'Depositing Rime Fog', theme: 'cloudy', icon: 'fog' },
51: { label: 'Light Drizzle', theme: 'rain', icon: 'rain-light' },
53: { label: 'Moderate Drizzle', theme: 'rain', icon: 'rain-light' },
55: { label: 'Dense Drizzle', theme: 'rain', icon: 'rain' },
56: { label: 'Light Freezing Drizzle', theme: 'snow', icon: 'snow' },
57: { label: 'Dense Freezing Drizzle', theme: 'snow', icon: 'snow' },
61: { label: 'Slight Rain', theme: 'rain', icon: 'rain-light' },
63: { label: 'Moderate Rain', theme: 'rain', icon: 'rain' },
65: { label: 'Heavy Rain', theme: 'rain', icon: 'rain-heavy' },
66: { label: 'Light Freezing Rain', theme: 'snow', icon: 'snow' },
67: { label: 'Heavy Freezing Rain', theme: 'snow', icon: 'snow' },
71: { label: 'Slight Snow Fall', theme: 'snow', icon: 'snow' },
73: { label: 'Moderate Snow Fall', theme: 'snow', icon: 'snow' },
75: { label: 'Heavy Snow Fall', theme: 'snow', icon: 'snow' },
77: { label: 'Snow Grains', theme: 'snow', icon: 'snow' },
80: { label: 'Slight Rain Showers', theme: 'rain', icon: 'rain-light' },
81: { label: 'Moderate Rain Showers', theme: 'rain', icon: 'rain' },
82: { label: 'Violent Rain Showers', theme: 'rain', icon: 'rain-heavy' },
85: { label: 'Slight Snow Showers', theme: 'snow', icon: 'snow' },
86: { label: 'Heavy Snow Showers', theme: 'snow', icon: 'snow' },
95: { label: 'Thunderstorm', theme: 'thunder', icon: 'thunder' },
96: { label: 'Thunderstorm with Hail', theme: 'thunder', icon: 'thunder' },
99: { label: 'Heavy Thunderstorm', theme: 'thunder', icon: 'thunder' },
};
function getWeatherInfo(code) {
if (code !== undefined && code !== null && WMO_MAP[code]) {
return WMO_MAP[code];
}
return { label: 'Weather Code ' + (code ?? 'N/A'), theme: 'cloudy', icon: 'cloud-sun' };
}
function getWeatherIconSVG(iconName) {
switch (iconName) {
case 'sun':
return `<svg viewBox="0 0 100 100" class="weather-svg">
<defs>
<radialGradient id="sunGlow" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#fbbf24"/>
<stop offset="100%" stop-color="#f59e0b"/>
</radialGradient>
</defs>
<circle cx="50" cy="50" r="22" fill="url(#sunGlow)"/>
<g stroke="#fbbf24" stroke-width="4.5" stroke-linecap="round" opacity="0.9">
<line x1="50" y1="12" x2="50" y2="20"/>
<line x1="50" y1="80" x2="50" y2="88"/>
<line x1="12" y1="50" x2="20" y2="50"/>
<line x1="80" y1="50" x2="88" y2="50"/>
<line x1="23" y1="23" x2="29" y2="29"/>
<line x1="71" y1="71" x2="77" y2="77"/>
<line x1="23" y1="77" x2="29" y2="71"/>
<line x1="71" y1="29" x2="77" y2="23"/>
</g>
</svg>`;
case 'cloud-sun':
return `<svg viewBox="0 0 100 100" class="weather-svg">
<defs>
<linearGradient id="cloudGrad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#f8fafc"/>
<stop offset="100%" stop-color="#cbd5e1"/>
</linearGradient>
</defs>
<circle cx="38" cy="38" r="16" fill="#fbbf24"/>
<path d="M 30 68 L 72 68 A 14 14 0 0 0 72 40 A 18 18 0 0 0 38 38 A 16 16 0 0 0 30 68 Z" fill="url(#cloudGrad)"/>
</svg>`;
case 'cloud':
return `<svg viewBox="0 0 100 100" class="weather-svg">
<defs>
<linearGradient id="cloudGrad2" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#e2e8f0"/>
<stop offset="100%" stop-color="#94a3b8"/>
</linearGradient>
</defs>
<path d="M 26 72 L 74 72 A 16 16 0 0 0 74 40 A 20 20 0 0 0 36 36 A 18 18 0 0 0 26 72 Z" fill="url(#cloudGrad2)"/>
</svg>`;
case 'rain-light':
case 'rain':
case 'rain-heavy':
return `<svg viewBox="0 0 100 100" class="weather-svg">
<defs>
<linearGradient id="rainCloud" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#cbd5e1"/>
<stop offset="100%" stop-color="#64748b"/>
</linearGradient>
</defs>
<path d="M 26 58 L 74 58 A 16 16 0 0 0 74 26 A 20 20 0 0 0 36 22 A 18 18 0 0 0 26 58 Z" fill="url(#rainCloud)"/>
<g stroke="#38bdf8" stroke-width="3.5" stroke-linecap="round">
<line x1="35" y1="66" x2="30" y2="78"/>
<line x1="50" y1="66" x2="45" y2="78"/>
<line x1="65" y1="66" x2="60" y2="78"/>
${iconName === 'rain-heavy' ? '<line x1="42" y1="72" x2="37" y2="84"/><line x1="57" y1="72" x2="52" y2="84"/>' : ''}
</g>
</svg>`;
case 'snow':
return `<svg viewBox="0 0 100 100" class="weather-svg">
<defs>
<linearGradient id="snowCloud" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#f1f5f9"/>
<stop offset="100%" stop-color="#94a3b8"/>
</linearGradient>
</defs>
<path d="M 26 56 L 74 56 A 16 16 0 0 0 74 24 A 20 20 0 0 0 36 20 A 18 18 0 0 0 26 56 Z" fill="url(#snowCloud)"/>
<g fill="#7dd3fc" text-anchor="middle" font-size="16" font-family="sans-serif">
<text x="35" y="76">❄</text>
<text x="50" y="80">❄</text>
<text x="65" y="76">❄</text>
</g>
</svg>`;
case 'thunder':
return `<svg viewBox="0 0 100 100" class="weather-svg">
<defs>
<linearGradient id="thunderCloud" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#475569"/>
<stop offset="100%" stop-color="#1e293b"/>
</linearGradient>
</defs>
<path d="M 26 54 L 74 54 A 16 16 0 0 0 74 22 A 20 20 0 0 0 36 18 A 18 18 0 0 0 26 54 Z" fill="url(#thunderCloud)"/>
<polygon points="52,48 40,68 50,68 44,88 62,62 50,62" fill="#facc15"/>
</svg>`;
case 'fog':
default:
return `<svg viewBox="0 0 100 100" class="weather-svg">
<defs>
<linearGradient id="fogCloud" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#e2e8f0"/>
<stop offset="100%" stop-color="#94a3b8"/>
</linearGradient>
</defs>
<path d="M 26 50 L 74 50 A 16 16 0 0 0 74 18 A 20 20 0 0 0 36 14 A 18 18 0 0 0 26 50 Z" fill="url(#fogCloud)"/>
<g stroke="#94a3b8" stroke-width="4" stroke-linecap="round" opacity="0.8">
<line x1="25" y1="62" x2="75" y2="62"/>
<line x1="30" y1="72" x2="70" y2="72"/>
<line x1="20" y1="82" x2="80" y2="82"/>
</g>
</svg>`;
}
}
function parseParams() {
const urlParams = new URLSearchParams(window.location.search);
const latParam = urlParams.get('lat');
const lonParam = urlParams.get('lon');
const nameParam = urlParams.get('name');
const dateParam = urlParams.get('date');
const lat = (latParam !== null && latParam.trim() !== '') ? latParam.trim() : '52.52';
const lon = (lonParam !== null && lonParam.trim() !== '') ? lonParam.trim() : '13.405';
const name = (nameParam && nameParam.trim() !== '') ? nameParam.trim() : 'Berlin';
const now = new Date();
const todayUtc = now.toISOString().split('T')[0];
const date = (dateParam && dateParam.trim() !== '') ? dateParam.trim() : todayUtc;
return { lat, lon, name, date, todayUtc };
}
function showError(message, requestUrlStr) {
document.getElementById('appContent').style.display = 'none';
const errContainer = document.getElementById('errorContainer');
errContainer.style.display = 'flex';
document.getElementById('errorMessage').textContent = message;
if (requestUrlStr) {
document.getElementById('errorUrl').textContent = 'Request URL: ' + requestUrlStr;
}
}
async function init() {
const { lat, lon, name, date, todayUtc } = parseParams();
const isArchive = date < todayUtc;
const endpoint = isArchive ? '/api/om/archive' : '/api/om/forecast';
const requestUrl = new URL(endpoint, window.location.origin);
requestUrl.searchParams.set('latitude', lat);
requestUrl.searchParams.set('longitude', lon);
requestUrl.searchParams.set('daily', 'temperature_2m_max,temperature_2m_min,weather_code');
requestUrl.searchParams.set('hourly', 'temperature_2m');
requestUrl.searchParams.set('timezone', 'UTC');
requestUrl.searchParams.set('temperature_unit', 'celsius');
requestUrl.searchParams.set('start_date', date);
requestUrl.searchParams.set('end_date', date);
const requestUrlStr = requestUrl.toString();
try {
const response = await fetch(requestUrlStr);
if (!response.ok) {
throw new Error(`Server returned HTTP status ${response.status}`);
}
const data = await response.json();
if (!data || !data.daily || !data.hourly) {
throw new Error('Invalid or incomplete weather data payload from API.');
}
renderApp(data, { lat, lon, name, date, endpoint, isArchive });
} catch (err) {
showError(`Could not load weather data: ${err.message}`, requestUrlStr);
}
}
function renderApp(data, config) {
const { name, lat, lon, date, endpoint, isArchive } = config;
document.getElementById('locationName').textContent = name;
const latNum = parseFloat(lat);
const lonNum = parseFloat(lon);
const latStr = !isNaN(latNum) ? `${Math.abs(latNum).toFixed(2)}° ${latNum >= 0 ? 'N' : 'S'}` : lat;
const lonStr = !isNaN(lonNum) ? `${Math.abs(lonNum).toFixed(2)}° ${lonNum >= 0 ? 'E' : 'W'}` : lon;
document.getElementById('locationCoords').textContent = `${latStr}, ${lonStr}`;
let dateDisplay = date;
try {
const dParts = date.split('-');
if (dParts.length === 3) {
const dObj = new Date(Date.UTC(parseInt(dParts[0]), parseInt(dParts[1]) - 1, parseInt(dParts[2])));
dateDisplay = dObj.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric', timeZone: 'UTC' });
}
} catch (e) {}
document.getElementById('formattedDate').textContent = dateDisplay;
const apiBadge = document.getElementById('apiBadge');
const apiBadgeText = document.getElementById('apiBadgeText');
if (isArchive) {
apiBadge.className = 'api-badge archive';
apiBadgeText.textContent = 'Archive API';
} else {
apiBadge.className = 'api-badge forecast';
apiBadgeText.textContent = 'Forecast API';
}
const daily = data.daily;
const maxTemp = (daily.temperature_2m_max && daily.temperature_2m_max[0] !== undefined) ? daily.temperature_2m_max[0] : null;
const minTemp = (daily.temperature_2m_min && daily.temperature_2m_min[0] !== undefined) ? daily.temperature_2m_min[0] : null;
const wmoCode = (daily.weather_code && daily.weather_code[0] !== undefined) ? daily.weather_code[0] : (daily.weathercode ? daily.weathercode[0] : 0);
const hourly = data.hourly;
const hourlyTimes = hourly.time || [];
const hourlyTemps = hourly.temperature_2m || [];
if (hourlyTemps.length === 0) {
showError('No hourly temperature records found for this date.');
return;
}
const actualMaxTemp = maxTemp !== null ? maxTemp : Math.max(...hourlyTemps);
const actualMinTemp = minTemp !== null ? minTemp : Math.min(...hourlyTemps);
const weatherInfo = getWeatherInfo(wmoCode);
const appCard = document.getElementById('appCard');
appCard.className = `app-card theme-${weatherInfo.theme}`;
document.getElementById('weatherCondition').textContent = weatherInfo.label;
document.getElementById('wmoCodeSub').textContent = `WMO Code: ${wmoCode}`;
document.getElementById('maxTemp').textContent = `${actualMaxTemp.toFixed(1)}°C`;
document.getElementById('minTemp').textContent = `${actualMinTemp.toFixed(1)}°C`;
document.getElementById('tempPrimary').textContent = `${actualMaxTemp.toFixed(1)}°C`;
document.getElementById('weatherIconContainer').innerHTML = getWeatherIconSVG(weatherInfo.icon);
let maxHourIdx = 0;
let minHourIdx = 0;
for (let i = 0; i < hourlyTemps.length; i++) {
if (hourlyTemps[i] > hourlyTemps[maxHourIdx]) maxHourIdx = i;
if (hourlyTemps[i] < hourlyTemps[minHourIdx]) minHourIdx = i;
}
const getHourStr = (idx) => {
if (hourlyTimes[idx]) {
const tPart = hourlyTimes[idx].split('T')[1];
if (tPart) return tPart.substring(0, 5);
}
return `${String(idx).padStart(2, '0')}:00`;
};
document.getElementById('peakWarmHour').textContent = getHourStr(maxHourIdx);
document.getElementById('peakWarmTemp').textContent = `${hourlyTemps[maxHourIdx].toFixed(1)}°C`;
document.getElementById('coolestHour').textContent = getHourStr(minHourIdx);
document.getElementById('coolestTemp').textContent = `${hourlyTemps[minHourIdx].toFixed(1)}°C`;
const delta = actualMaxTemp - actualMinTemp;
document.getElementById('tempDelta').textContent = `${delta.toFixed(1)}°C`;
renderChartAndCarousel(hourlyTemps, hourlyTimes, actualMaxTemp, actualMinTemp);
}
function renderChartAndCarousel(temps, times, dayMax, dayMin) {
const paddingLeft = 40;
const paddingRight = 40;
const paddingTop = 30;
const paddingBottom = 30;
const chartWidth = 1200;
const chartHeight = 180;
const minT = Math.min(...temps);
const maxT = Math.max(...temps);
const rangeT = (maxT - minT) || 10;
const padMin = minT - rangeT * 0.15;
const padMax = maxT + rangeT * 0.15;
const points = temps.map((temp, i) => {
const x = paddingLeft + (i / (temps.length - 1 || 1)) * (chartWidth - paddingLeft - paddingRight);
const y = paddingTop + (1 - (temp - padMin) / (padMax - padMin)) * (chartHeight - paddingTop - paddingBottom);
const hourStr = times[i] ? (times[i].split('T')[1] || `${String(i).padStart(2, '0')}:00`).substring(0, 5) : `${String(i).padStart(2, '0')}:00`;
return { x, y, temp, hourStr, index: i };
});
let pathD = `M ${points[0].x.toFixed(1)} ${points[0].y.toFixed(1)}`;
for (let i = 0; i < points.length - 1; i++) {
const p0 = points[i === 0 ? i : i - 1];
const p1 = points[i];
const p2 = points[i + 1];
const p3 = points[i + 2 < points.length ? i + 2 : i + 1];
const cp1x = p1.x + (p2.x - p0.x) / 6;
const cp1y = p1.y + (p2.y - p0.y) / 6;
const cp2x = p2.x - (p3.x - p1.x) / 6;
const cp2y = p2.y - (p3.y - p1.y) / 6;
pathD += ` C ${cp1x.toFixed(1)} ${cp1y.toFixed(1)}, ${cp2x.toFixed(1)} ${cp2y.toFixed(1)}, ${p2.x.toFixed(1)} ${p2.y.toFixed(1)}`;
}
document.getElementById('chartLine').setAttribute('d', pathD);
const areaD = `${pathD} L ${points[points.length - 1].x.toFixed(1)} ${chartHeight - paddingBottom} L ${points[0].x.toFixed(1)} ${chartHeight - paddingBottom} Z`;
document.getElementById('chartArea').setAttribute('d', areaD);
const gridG = document.getElementById('chartGridLines');
const labelsG = document.getElementById('chartLabels');
gridG.innerHTML = '';
labelsG.innerHTML = '';
[0.1, 0.5, 0.9].forEach(ratio => {
const gy = paddingTop + ratio * (chartHeight - paddingTop - paddingBottom);
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', paddingLeft);
line.setAttribute('y1', gy);
line.setAttribute('x2', chartWidth - paddingRight);
line.setAttribute('y2', gy);
line.setAttribute('stroke', 'rgba(255,255,255,0.06)');
line.setAttribute('stroke-dasharray', '4 4');
gridG.appendChild(line);
});
const pointsG = document.getElementById('chartPoints');
pointsG.innerHTML = '';
const tooltip = document.getElementById('chartTooltip');
const carousel = document.getElementById('hourlyCarousel');
carousel.innerHTML = '';
points.forEach((p, i) => {
if (i % 3 === 0 || i === points.length - 1) {
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
text.setAttribute('x', p.x);
text.setAttribute('y', chartHeight - 10);
text.setAttribute('fill', '#64748b');
text.setAttribute('font-size', '11');
text.setAttribute('font-weight', '600');
text.setAttribute('text-anchor', 'middle');
text.textContent = p.hourStr;
labelsG.appendChild(text);
}
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.setAttribute('cx', p.x.toFixed(1));
circle.setAttribute('cy', p.y.toFixed(1));
circle.setAttribute('r', '4');
circle.setAttribute('fill', p.temp === dayMax ? '#ef4444' : (p.temp === dayMin ? '#3b82f6' : '#38bdf8'));
circle.setAttribute('class', 'chart-point');
circle.setAttribute('id', `pt-${i}`);
circle.addEventListener('mouseenter', () => {
circle.classList.add('active');
const card = document.getElementById(`hcard-${i}`);
if (card) card.classList.add('active');
const percentX = (p.x / chartWidth) * 100;
const percentY = (p.y / chartHeight) * 100;
tooltip.style.left = `${percentX}%`;
tooltip.style.top = `${percentY}%`;
tooltip.textContent = `${p.hourStr} — ${p.temp.toFixed(1)}°C`;
tooltip.style.opacity = '1';
});
circle.addEventListener('mouseleave', () => {
circle.classList.remove('active');
const card = document.getElementById(`hcard-${i}`);
if (card) card.classList.remove('active');
tooltip.style.opacity = '0';
});
pointsG.appendChild(circle);
const hCard = document.createElement('div');
hCard.className = 'hourly-card';
hCard.id = `hcard-${i}`;
const fillPercent = Math.max(10, Math.min(100, ((p.temp - minT) / (rangeT || 1)) * 100));
hCard.innerHTML = `
<div class="hourly-time">${p.hourStr}</div>
<div class="hourly-temp">${p.temp.toFixed(1)}°</div>
<div class="hourly-bar-bg">
<div class="hourly-bar-fill" style="width: ${fillPercent}%"></div>
</div>
`;
hCard.addEventListener('mouseenter', () => {
circle.classList.add('active');
hCard.classList.add('active');
const percentX = (p.x / chartWidth) * 100;
const percentY = (p.y / chartHeight) * 100;
tooltip.style.left = `${percentX}%`;
tooltip.style.top = `${percentY}%`;
tooltip.textContent = `${p.hourStr} — ${p.temp.toFixed(1)}°C`;
tooltip.style.opacity = '1';
});
hCard.addEventListener('mouseleave', () => {
circle.classList.remove('active');
hCard.classList.remove('active');
tooltip.style.opacity = '0';
});
carousel.appendChild(hCard);
});
}
window.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>L1 —— 廉价的确定性描述量
| bytes 总计 | 37,282 | html / css / js | 6,334 / 10,756 / 20,192 |
|---|---|---|---|
| dom 节点 | 97 | dom 深度 | 11 |
| css 规则 | 59 | 含 js | 是 |
| brightness | 35.1 | contrast | 23.5 |
| colorfulness | 28.5 | 留白 | 65.9% |
该 slot 的 telemetry
| prompt tokens | 114,000 | completion tokens | 60,518 |
|---|---|---|---|
| total tokens | 174,518 | wall | 240.3 s |
| cost | — | request id | — |
config.json589 B
{
"N": 2,
"auth": {
"credential_ref": "WCB_NONE",
"method": "oauth-login"
},
"billing": "plan",
"config_id": "gemini-3.6-flash-eff-high--cli--cursor--dev",
"effort": "high",
"family": "gemini",
"m": {
"min": 2,
"q": 2
},
"model_id": "gemini-3.6-flash",
"protocol": "cli",
"served_model": "gemini-3.6-flash-high",
"telemetry": {
"completion_tokens": 156603,
"cost_usd": null,
"prompt_tokens": 266288,
"total_tokens": 422891,
"wall_ms": 636760
},
"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": "gemini-3.6-flash-eff-high--cli--cursor--dev",
"positions": [
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-08-13T01:20:56.868273+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-08-13T01:16:56.532288+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-13T01:22:32.570263+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-08-13T01:21:00.271043+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-13T01:24:40.529753+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-08-13T01:22:35.478802+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-13T01:27:42.932878+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-08-13T01:24:43.849348+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
}
}
}