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

截图是 similarity 通道测量时的原始像素。运行 live 会在 sandboxed iframe 中重新执行原始输出;渲染结果取决于你的浏览器和字体,不保证与测量像素一致。
similarity 邻居
最近
gemini-3.6-flash @low · api0.71gemini-3.8-flash @low · agy0.69gemini-3.5-flash @minimal · api0.68gemini-3.7-flash @medium · agy0.68claude-sonnet-5-thinking @low · cursor0.68最远
north-mini-code-free · api0.51gpt-6-astra · codex0.53gpt-5.6-terra @none · cursor-xl0.53claude-fable-5-1 @max · CC0.53cursor-grok-4.6 @xhigh · cursor-xl0.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 Card</title>
<style>
:root {
--bg-gradient-clear-day: linear-gradient(135deg, #0284c7 0%, #38bdf8 50%, #bae6fd 100%);
--bg-gradient-clear-night: linear-gradient(135deg, #0f172a 0%, #1e1b4b 50%, #312e81 100%);
--bg-gradient-cloudy: linear-gradient(135deg, #334155 0%, #475569 50%, #94a3b8 100%);
--bg-gradient-rainy: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #475569 100%);
--bg-gradient-snowy: linear-gradient(135deg, #1e293b 0%, #475569 50%, #cbd5e1 100%);
--bg-gradient-thunder: linear-gradient(135deg, #090d16 0%, #1e1b4b 50%, #2e1065 100%);
--glass-bg: rgba(255, 255, 255, 0.12);
--glass-bg-hover: rgba(255, 255, 255, 0.18);
--glass-border: rgba(255, 255, 255, 0.22);
--glass-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.35), 0 0 0 1px rgba(255, 255, 255, 0.15);
--text-main: #ffffff;
--text-muted: rgba(255, 255, 255, 0.7);
--text-dim: rgba(255, 255, 255, 0.5);
--accent-pill: rgba(255, 255, 255, 0.18);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
-webkit-font-smoothing: antialiased;
}
body {
width: 1280px;
height: 800px;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: var(--bg-gradient-clear-day);
color: var(--text-main);
display: flex;
align-items: center;
justify-content: center;
transition: background 1s ease-in-out;
user-select: none;
}
/* Weather Background Ambient Overlay */
.ambient-overlay {
position: absolute;
inset: 0;
pointer-events: none;
background: radial-gradient(circle at 50% 20%, rgba(255,255,255,0.15) 0%, transparent 60%);
z-index: 0;
}
/* Main Container */
.app-card {
position: relative;
z-index: 1;
width: 1080px;
height: 640px;
background: var(--glass-bg);
backdrop-filter: blur(40px) saturate(180%);
-webkit-backdrop-filter: blur(40px) saturate(180%);
border: 1px solid var(--glass-border);
border-radius: 36px;
box-shadow: var(--glass-shadow);
display: flex;
flex-direction: column;
padding: 40px 48px;
justify-content: space-between;
animation: fadeIn 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes fadeIn {
from { opacity: 0; transform: scale(0.97) translateY(10px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
/* Top Section: Header & Current Conditions */
.card-top {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.location-info {
display: flex;
flex-direction: column;
gap: 6px;
}
.location-name {
font-size: 42px;
font-weight: 700;
letter-spacing: -0.8px;
line-height: 1.1;
text-shadow: 0 2px 10px rgba(0,0,0,0.15);
}
.date-badge {
display: inline-flex;
align-items: center;
gap: 8px;
background: var(--accent-pill);
padding: 6px 14px;
border-radius: 20px;
font-size: 14px;
font-weight: 500;
color: var(--text-muted);
width: fit-content;
border: 1px solid rgba(255, 255, 255, 0.15);
}
.coordinates {
font-size: 13px;
color: var(--text-dim);
margin-top: 4px;
letter-spacing: 0.2px;
}
.weather-summary {
display: flex;
align-items: center;
gap: 24px;
}
.weather-icon-wrapper {
width: 100px;
height: 100px;
display: flex;
align-items: center;
justify-content: center;
filter: drop-shadow(0 10px 15px rgba(0,0,0,0.2));
}
.weather-icon-svg {
width: 100%;
height: 100%;
}
.temp-high-low {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
}
.condition-text {
font-size: 22px;
font-weight: 600;
text-align: right;
letter-spacing: -0.3px;
}
.temp-range {
display: flex;
align-items: center;
gap: 12px;
font-size: 20px;
font-weight: 500;
}
.temp-high {
color: #ffffff;
display: flex;
align-items: center;
gap: 4px;
}
.temp-low {
color: var(--text-muted);
display: flex;
align-items: center;
gap: 4px;
}
/* Middle Section: Metrics / Highlight Cards */
.card-middle {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
margin: 20px 0;
}
.metric-card {
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 20px;
padding: 16px 20px;
display: flex;
flex-direction: column;
gap: 8px;
transition: background 0.3s ease;
}
.metric-card:hover {
background: var(--glass-bg-hover);
}
.metric-label {
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.8px;
color: var(--text-muted);
font-weight: 600;
display: flex;
align-items: center;
gap: 6px;
}
.metric-value {
font-size: 24px;
font-weight: 700;
letter-spacing: -0.5px;
}
/* Bottom Section: Hourly Forecast Chart & Cards */
.card-bottom {
display: flex;
flex-direction: column;
gap: 12px;
background: rgba(0, 0, 0, 0.12);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 24px;
padding: 20px;
}
.hourly-title {
font-size: 14px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.8px;
color: var(--text-muted);
display: flex;
justify-content: space-between;
align-items: center;
}
.hourly-scroll-container {
display: flex;
gap: 12px;
overflow-x: auto;
padding-bottom: 4px;
scroll-behavior: smooth;
}
.hourly-scroll-container::-webkit-scrollbar {
height: 4px;
}
.hourly-scroll-container::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.05);
border-radius: 2px;
}
.hourly-scroll-container::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
border-radius: 2px;
}
.hourly-item {
flex: 0 0 calc((100% - (12 * 11px)) / 12);
min-width: 68px;
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 16px;
padding: 12px 8px;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
transition: all 0.2s ease;
}
.hourly-item:hover {
background: rgba(255, 255, 255, 0.15);
transform: translateY(-2px);
}
.hourly-time {
font-size: 13px;
font-weight: 500;
color: var(--text-muted);
}
.hourly-temp {
font-size: 16px;
font-weight: 700;
}
.hourly-bar-wrapper {
width: 100%;
height: 36px;
display: flex;
align-items: flex-end;
justify-content: center;
}
.hourly-bar {
width: 6px;
border-radius: 3px;
background: linear-gradient(to top, rgba(255,255,255,0.3), rgba(255,255,255,0.9));
transition: height 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
/* State Views: Loading, Error */
.state-view {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
text-align: center;
gap: 16px;
padding: 40px;
}
.spinner {
width: 48px;
height: 48px;
border: 4px solid rgba(255, 255, 255, 0.2);
border-top-color: #ffffff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.error-icon {
width: 64px;
height: 64px;
color: #f87171;
}
.error-title {
font-size: 24px;
font-weight: 700;
}
.error-message {
font-size: 16px;
color: var(--text-muted);
max-width: 500px;
line-height: 1.5;
}
.hidden {
display: none !important;
}
</style>
</head>
<body>
<div class="ambient-overlay"></div>
<div class="app-card">
<!-- Loading State -->
<div id="loading-state" class="state-view">
<div class="spinner"></div>
<div style="font-size: 18px; font-weight: 500; color: var(--text-muted);">Fetching weather data...</div>
</div>
<!-- Error State -->
<div id="error-state" class="state-view hidden">
<svg class="error-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
<div class="error-title">Unable to Load Weather Data</div>
<div class="error-message" id="error-details">The weather information for this location could not be fetched. Please check your query parameters or try again later.</div>
</div>
<!-- Main Content State -->
<div id="weather-content" class="hidden" style="display: flex; flex-direction: column; height: 100%; justify-content: space-between;">
<!-- Top Section -->
<div class="card-top">
<div class="location-info">
<div class="location-name" id="ui-location-name">Berlin</div>
<div class="date-badge">
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
</svg>
<span id="ui-date">Thu, Aug 13, 2026</span>
</div>
<div class="coordinates" id="ui-coords">52.5200° N, 13.4050° E</div>
</div>
<div class="weather-summary">
<div class="weather-icon-wrapper" id="ui-weather-icon">
<!-- Dynamic SVG -->
</div>
<div class="temp-high-low">
<div class="condition-text" id="ui-condition">Clear Sky</div>
<div class="temp-range">
<span class="temp-high" title="Maximum Temperature">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M5 15l7-7 7 7"/>
</svg>
<span id="ui-temp-max">--</span>°C
</span>
<span class="temp-low" title="Minimum Temperature">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M19 9l-7 7-7-7"/>
</svg>
<span id="ui-temp-min">--</span>°C
</span>
</div>
</div>
</div>
</div>
<!-- Middle Highlights Section -->
<div class="card-middle">
<div class="metric-card">
<div class="metric-label">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/>
</svg>
Peak Temp
</div>
<div class="metric-value" id="ui-peak-temp">--°C</div>
</div>
<div class="metric-card">
<div class="metric-label">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3"/>
</svg>
Lowest Temp
</div>
<div class="metric-value" id="ui-lowest-temp">--°C</div>
</div>
<div class="metric-card">
<div class="metric-label">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
</svg>
Daily Mean
</div>
<div class="metric-value" id="ui-mean-temp">--°C</div>
</div>
<div class="metric-card">
<div class="metric-label">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
Data Source
</div>
<div class="metric-value" id="ui-source-type">--</div>
</div>
</div>
<!-- Bottom Hourly Section -->
<div class="card-bottom">
<div class="hourly-title">
<span>Hourly Temperature Overview</span>
<span style="font-weight: 400; text-transform: none; font-size: 12px;" id="ui-hourly-count">24 Hours (UTC)</span>
</div>
<div class="hourly-scroll-container" id="ui-hourly-container">
<!-- Hourly items populated via JS -->
</div>
</div>
</div>
</div>
<script>
// Weather Code Mappings WMO
const WMO_CODES = {
0: { label: 'Clear Sky', icon: 'clear', bg: 'var(--bg-gradient-clear-day)' },
1: { label: 'Mainly Clear', icon: 'clear', bg: 'var(--bg-gradient-clear-day)' },
2: { label: 'Partly Cloudy', icon: 'cloudy', bg: 'var(--bg-gradient-cloudy)' },
3: { label: 'Overcast', icon: 'overcast', bg: 'var(--bg-gradient-cloudy)' },
45: { label: 'Foggy', icon: 'fog', bg: 'var(--bg-gradient-cloudy)' },
48: { label: 'Depositing Rime Fog', icon: 'fog', bg: 'var(--bg-gradient-cloudy)' },
51: { label: 'Light Drizzle', icon: 'rain', bg: 'var(--bg-gradient-rainy)' },
53: { label: 'Moderate Drizzle', icon: 'rain', bg: 'var(--bg-gradient-rainy)' },
55: { label: 'Dense Drizzle', icon: 'rain', bg: 'var(--bg-gradient-rainy)' },
56: { label: 'Freezing Drizzle', icon: 'rain', bg: 'var(--bg-gradient-snowy)' },
57: { label: 'Dense Freezing Drizzle', icon: 'rain', bg: 'var(--bg-gradient-snowy)' },
61: { label: 'Slight Rain', icon: 'rain', bg: 'var(--bg-gradient-rainy)' },
63: { label: 'Moderate Rain', icon: 'rain', bg: 'var(--bg-gradient-rainy)' },
65: { label: 'Heavy Rain', icon: 'rain', bg: 'var(--bg-gradient-rainy)' },
66: { label: 'Light Freezing Rain', icon: 'rain', bg: 'var(--bg-gradient-snowy)' },
67: { label: 'Heavy Freezing Rain', icon: 'rain', bg: 'var(--bg-gradient-snowy)' },
71: { label: 'Slight Snow Fall', icon: 'snow', bg: 'var(--bg-gradient-snowy)' },
73: { label: 'Moderate Snow Fall', icon: 'snow', bg: 'var(--bg-gradient-snowy)' },
75: { label: 'Heavy Snow Fall', icon: 'snow', bg: 'var(--bg-gradient-snowy)' },
77: { label: 'Snow Grains', icon: 'snow', bg: 'var(--bg-gradient-snowy)' },
80: { label: 'Slight Rain Showers', icon: 'rain', bg: 'var(--bg-gradient-rainy)' },
81: { label: 'Moderate Rain Showers', icon: 'rain', bg: 'var(--bg-gradient-rainy)' },
82: { label: 'Violent Rain Showers', icon: 'rain', bg: 'var(--bg-gradient-rainy)' },
85: { label: 'Slight Snow Showers', icon: 'snow', bg: 'var(--bg-gradient-snowy)' },
86: { label: 'Heavy Snow Showers', icon: 'snow', bg: 'var(--bg-gradient-snowy)' },
95: { label: 'Thunderstorm', icon: 'thunder', bg: 'var(--bg-gradient-thunder)' },
96: { label: 'Thunderstorm with Hail', icon: 'thunder', bg: 'var(--bg-gradient-thunder)' },
99: { label: 'Thunderstorm with Heavy Hail', icon: 'thunder', bg: 'var(--bg-gradient-thunder)' }
};
// SVG Icons
const SVG_ICONS = {
clear: `<svg class="weather-icon-svg" viewBox="0 0 64 64" fill="none">
<circle cx="32" cy="32" r="14" fill="#FDB813" />
<g stroke="#FDB813" stroke-width="3" stroke-linecap="round">
<line x1="32" y1="6" x2="32" y2="12" />
<line x1="32" y1="52" x2="32" y2="58" />
<line x1="6" y1="32" x2="12" y2="32" />
<line x1="52" y1="32" x2="58" y2="32" />
<line x1="13.6" y1="13.6" x2="17.8" y2="17.8" />
<line x1="46.2" y1="46.2" x2="50.4" y2="50.4" />
<line x1="13.6" y1="50.4" x2="17.8" y2="46.2" />
<line x1="46.2" y1="17.8" x2="50.4" y2="13.6" />
</g>
</svg>`,
cloudy: `<svg class="weather-icon-svg" viewBox="0 0 64 64" fill="none">
<circle cx="24" cy="24" r="10" fill="#FDB813" />
<path d="M46 44C49.866 44 53 40.866 53 37C53 33.35 50.2 30.35 46.6 30.05C45.3 24.3 40.2 20 34 20C26.8 20 21 25.8 21 33C17.1 33.4 14 36.7 14 40.6C14 44.7 17.3 48 21.4 48H46" fill="#E2E8F0" opacity="0.9"/>
<path d="M44 46C47.3 46 50 43.3 50 40C50 36.9 47.6 34.3 44.5 34C43.4 29 39 25.3 33.7 25.3 C27.5 25.3 22.5 30.3 22.5 36.5C19.1 36.8 16.5 39.7 16.5 43.1C16.5 46.7 19.4 49.5 23 49.5H44" fill="#FFFFFF"/>
</svg>`,
overcast: `<svg class="weather-icon-svg" viewBox="0 0 64 64" fill="none">
<path d="M48 42C51.3 42 54 39.3 54 36C54 32.9 51.6 30.3 48.5 30C47.4 25 43 21.3 37.7 21.3C31.5 21.3 26.5 26.3 26.5 32.5C23.1 32.8 20.5 35.7 20.5 39.1C20.5 42.7 23.4 45.5 27 45.5H48" fill="#CBD5E1"/>
<path d="M40 48C43.3 48 46 45.3 46 42C46 38.9 43.6 36.3 40.5 36C39.4 31 35 27.3 29.7 27.3C23.5 27.3 18.5 32.3 18.5 38.5C15.1 38.8 12.5 41.7 12.5 45.1C12.5 48.7 15.4 51.5 19 51.5H40" fill="#FFFFFF"/>
</svg>`,
fog: `<svg class="weather-icon-svg" viewBox="0 0 64 64" fill="none">
<path d="M40 32C43.3 32 46 29.3 46 26C46 22.9 43.6 20.3 40.5 20C39.4 15 35 11.3 29.7 11.3C23.5 11.3 18.5 16.3 18.5 22.5C15.1 22.8 12.5 25.7 12.5 29.1C12.5 32.7 15.4 35.5 19 35.5H40" fill="#E2E8F0" opacity="0.8"/>
<line x1="14" y1="42" x2="50" y2="42" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
<line x1="18" y1="48" x2="46" y2="48" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
<line x1="22" y1="54" x2="42" y2="54" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
</svg>`,
rain: `<svg class="weather-icon-svg" viewBox="0 0 64 64" fill="none">
<path d="M44 38C47.3 38 50 35.3 50 32C50 28.9 47.6 26.3 44.5 26C43.4 21 39 17.3 33.7 17.3C27.5 17.3 22.5 22.3 22.5 28.5C19.1 28.8 16.5 31.7 16.5 35.1C16.5 38.7 19.4 41.5 23 41.5H44" fill="#CBD5E1"/>
<g stroke="#38BDF8" stroke-width="3" stroke-linecap="round">
<line x1="22" y1="46" x2="18" y2="54" />
<line x1="32" y1="46" x2="28" y2="54" />
<line x1="42" y1="46" x2="38" y2="54" />
</g>
</svg>`,
snow: `<svg class="weather-icon-svg" viewBox="0 0 64 64" fill="none">
<path d="M44 36C47.3 36 50 33.3 50 30C50 26.9 47.6 24.3 44.5 24C43.4 19 39 15.3 33.7 15.3C27.5 15.3 22.5 20.3 22.5 26.5C19.1 26.8 16.5 29.7 16.5 33.1C16.5 36.7 19.4 39.5 23 39.5H44" fill="#E2E8F0"/>
<circle cx="22" cy="46" r="2.5" fill="#FFFFFF"/>
<circle cx="32" cy="48" r="2.5" fill="#FFFFFF"/>
<circle cx="42" cy="46" r="2.5" fill="#FFFFFF"/>
<circle cx="27" cy="55" r="2.5" fill="#FFFFFF"/>
<circle cx="37" cy="55" r="2.5" fill="#FFFFFF"/>
</svg>`,
thunder: `<svg class="weather-icon-svg" viewBox="0 0 64 64" fill="none">
<path d="M44 34C47.3 34 50 31.3 50 28C50 24.9 47.6 22.3 44.5 22C43.4 17 39 13.3 33.7 13.3C27.5 13.3 22.5 18.3 22.5 24.5C19.1 24.8 16.5 27.7 16.5 31.1C16.5 34.7 19.4 37.5 23 37.5H44" fill="#64748B"/>
<path d="M30 36L22 48H31L28 58L40 44H31L34 36H30Z" fill="#FACC15" stroke="#EAB308" stroke-width="1.5" stroke-linejoin="round"/>
</svg>`
};
// Helper Function: Format Date string
function formatDateDisplay(dateStr) {
try {
const parts = dateStr.split('-');
if (parts.length === 3) {
const year = parseInt(parts[0], 10);
const month = parseInt(parts[1], 10) - 1;
const day = parseInt(parts[2], 10);
const dateObj = new Date(Date.UTC(year, month, day));
return dateObj.toLocaleDateString('en-US', {
weekday: 'short',
year: 'numeric',
month: 'short',
day: 'numeric',
timeZone: 'UTC'
});
}
} catch (e) {
console.error("Date formatting error", e);
}
return dateStr;
}
// Main App Initialization
async function initApp() {
const loadingEl = document.getElementById('loading-state');
const errorEl = document.getElementById('error-state');
const contentEl = document.getElementById('weather-content');
const errorDetailsEl = document.getElementById('error-details');
try {
const urlParams = new URLSearchParams(window.location.search);
// Extract Query Parameters
const lat = urlParams.get('lat') !== null ? urlParams.get('lat') : '52.52';
const lon = urlParams.get('lon') !== null ? urlParams.get('lon') : '13.405';
const name = urlParams.get('name') || 'Berlin';
// Today in UTC YYYY-MM-DD
const nowUTC = new Date();
const todayStr = nowUTC.toISOString().split('T')[0];
const requestedDate = urlParams.get('date') || todayStr;
// Determine API Endpoint based on date comparison
const isPast = requestedDate < todayStr;
const apiPath = isPast ? '/api/om/archive' : '/api/om/forecast';
// Construct API URL
const apiUrl = new URL(apiPath, window.location.origin);
apiUrl.searchParams.set('latitude', lat);
apiUrl.searchParams.set('longitude', lon);
apiUrl.searchParams.set('daily', 'temperature_2m_max,temperature_2m_min,weather_code');
apiUrl.searchParams.set('hourly', 'temperature_2m');
apiUrl.searchParams.set('timezone', 'UTC');
apiUrl.searchParams.set('temperature_unit', 'celsius');
apiUrl.searchParams.set('start_date', requestedDate);
apiUrl.searchParams.set('end_date', requestedDate);
// Fetch Weather Data
const response = await fetch(apiUrl.toString());
if (!response.ok) {
throw new Error(`HTTP ${response.status}: Failed to fetch weather data`);
}
const data = await response.json();
// Validate API response structure
if (!data || (!data.daily && !data.hourly)) {
throw new Error("Invalid or empty response structure received from weather API.");
}
// Parse Daily Values
const tempMax = (data.daily && data.daily.temperature_2m_max && data.daily.temperature_2m_max[0] !== undefined)
? Math.round(data.daily.temperature_2m_max[0])
: '--';
const tempMin = (data.daily && data.daily.temperature_2m_min && data.daily.temperature_2m_min[0] !== undefined)
? Math.round(data.daily.temperature_2m_min[0])
: '--';
const weatherCode = (data.daily && data.daily.weather_code && data.daily.weather_code[0] !== undefined)
? data.daily.weather_code[0]
: 0;
const wmoInfo = WMO_CODES[weatherCode] || { label: 'Clear Sky', icon: 'clear', bg: 'var(--bg-gradient-clear-day)' };
// Parse Hourly Values
let hourlyTemps = [];
let hourlyTimes = [];
if (data.hourly && Array.isArray(data.hourly.temperature_2m)) {
hourlyTemps = data.hourly.temperature_2m;
hourlyTimes = data.hourly.time || [];
}
// Populate UI Elements
document.getElementById('ui-location-name').textContent = name;
document.getElementById('ui-date').textContent = formatDateDisplay(requestedDate);
const latNum = parseFloat(lat);
const lonNum = parseFloat(lon);
const latStr = isNaN(latNum) ? lat : `${Math.abs(latNum).toFixed(4)}° ${latNum >= 0 ? 'N' : 'S'}`;
const lonStr = isNaN(lonNum) ? lon : `${Math.abs(lonNum).toFixed(4)}° ${lonNum >= 0 ? 'E' : 'W'}`;
document.getElementById('ui-coords').textContent = `${latStr}, ${lonStr}`;
document.getElementById('ui-condition').textContent = wmoInfo.label;
document.getElementById('ui-temp-max').textContent = tempMax;
document.getElementById('ui-temp-min').textContent = tempMin;
document.getElementById('ui-weather-icon').innerHTML = SVG_ICONS[wmoInfo.icon] || SVG_ICONS.clear;
// Apply Dynamic Background
document.body.style.background = wmoInfo.bg;
// Calculate Highlights
let peakTemp = tempMax !== '--' ? tempMax : '--';
let lowestTemp = tempMin !== '--' ? tempMin : '--';
let meanTemp = '--';
if (hourlyTemps.length > 0) {
const validTemps = hourlyTemps.filter(t => t !== null && !isNaN(t));
if (validTemps.length > 0) {
const maxVal = Math.max(...validTemps);
const minVal = Math.min(...validTemps);
const sumVal = validTemps.reduce((a, b) => a + b, 0);
peakTemp = Math.round(maxVal);
lowestTemp = Math.round(minVal);
meanTemp = (sumVal / validTemps.length).toFixed(1);
}
}
document.getElementById('ui-peak-temp').textContent = `${peakTemp}°C`;
document.getElementById('ui-lowest-temp').textContent = `${lowestTemp}°C`;
document.getElementById('ui-mean-temp').textContent = meanTemp !== '--' ? `${meanTemp}°C` : '--°C';
document.getElementById('ui-source-type').textContent = isPast ? 'Historical' : 'Forecast';
// Render Hourly Section
const hourlyContainer = document.getElementById('ui-hourly-container');
hourlyContainer.innerHTML = '';
if (hourlyTemps.length > 0) {
const validTemps = hourlyTemps.filter(t => t !== null && !isNaN(t));
const minH = validTemps.length ? Math.min(...validTemps) : 0;
const maxH = validTemps.length ? Math.max(...validTemps) : 1;
const rangeH = (maxH - minH) || 1;
hourlyTemps.forEach((temp, idx) => {
const rawTime = hourlyTimes[idx];
let timeLabel = `${String(idx).padStart(2, '0')}:00`;
if (rawTime && rawTime.includes('T')) {
timeLabel = rawTime.split('T')[1].substring(0, 5);
}
const formattedTemp = temp !== null && temp !== undefined ? Math.round(temp) : '--';
// Bar Height Percentage (between 20% and 100%)
let barHeightPercent = 50;
if (temp !== null && !isNaN(temp)) {
barHeightPercent = Math.round(20 + ((temp - minH) / rangeH) * 80);
}
const hourlyItem = document.createElement('div');
hourlyItem.className = 'hourly-item';
hourlyItem.innerHTML = `
<div class="hourly-time">${timeLabel}</div>
<div class="hourly-bar-wrapper">
<div class="hourly-bar" style="height: ${barHeightPercent}%;"></div>
</div>
<div class="hourly-temp">${formattedTemp}°</div>
`;
hourlyContainer.appendChild(hourlyItem);
});
document.getElementById('ui-hourly-count').textContent = `${hourlyTemps.length} Hours (UTC)`;
} else {
hourlyContainer.innerHTML = `<div style="width: 100%; text-align: center; color: var(--text-muted); padding: 20px;">No hourly data available for this date.</div>`;
}
// Show Content View
loadingEl.classList.add('hidden');
contentEl.classList.remove('hidden');
} catch (err) {
console.error("Error loading weather data:", err);
loadingEl.classList.add('hidden');
errorDetailsEl.textContent = `The weather information could not be loaded (${err.message || 'Data fetch failed'}). Please verify your query settings or endpoint response.`;
errorEl.classList.remove('hidden');
}
}
// Run on Load
window.addEventListener('DOMContentLoaded', initApp);
</script>
</body>
</html>L1 —— 廉价的确定性描述量
| bytes 总计 | 28,703 | html / css / js | 5,559 / 8,282 / 14,862 |
|---|---|---|---|
| dom 节点 | 66 | dom 深度 | 10 |
| css 规则 | 46 | 含 js | 是 |
| brightness | 70.5 | contrast | 22.2 |
| colorfulness | 16.7 | 留白 | 37.9% |
该 slot 的 telemetry
| prompt tokens | 108,218 | completion tokens | 22,158 |
|---|---|---|---|
| total tokens | 130,376 | wall | 90.6 s |
| cost | — | request id | — |
config.json597 B
{
"N": 2,
"auth": {
"credential_ref": "WCB_NONE",
"method": "oauth-login"
},
"billing": "plan",
"config_id": "gemini-3.6-flash-eff-minimal--cli--cursor--dev",
"effort": "minimal",
"family": "gemini",
"m": {
"min": 2,
"q": 2
},
"model_id": "gemini-3.6-flash",
"protocol": "cli",
"served_model": "gemini-3.6-flash-minimal",
"telemetry": {
"completion_tokens": 43248,
"cost_usd": null,
"prompt_tokens": 131622,
"total_tokens": 174870,
"wall_ms": 205308
},
"transport": "cursor-agent-cli-isolated-home",
"vendor_sanction_ref": null
}send-log2.5 KB
{
"N": 2,
"batch_id": "2026-08-13--cursor-s2",
"config_id": "gemini-3.6-flash-eff-minimal--cli--cursor--dev",
"positions": [
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-08-13T02:04:22.670984+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-08-13T02:02:52.088052+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-13T02:05:10.876296+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-08-13T02:04:26.056863+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-13T02:05:42.939196+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-08-13T02:05:14.221325+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-13T02:06:27.399386+00:00",
"http_status": null,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-08-13T02:05:46.202773+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
}
}
}