|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<title>Live WebApp Viewer</title> |
|
<style> |
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap'); |
|
|
|
:root { |
|
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
|
--secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); |
|
--accent-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); |
|
--dark-bg: #0a0a0a; |
|
--card-bg: #ffffff; |
|
--text-primary: #1a1a1a; |
|
--text-secondary: #666666; |
|
--text-muted: #888888; |
|
--border-color: #e5e7eb; |
|
--shadow-sm: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); |
|
--shadow-md: 0 4px 6px rgba(0,0,0,0.07), 0 1px 3px rgba(0,0,0,0.06); |
|
--shadow-lg: 0 10px 25px rgba(0,0,0,0.1), 0 4px 10px rgba(0,0,0,0.06); |
|
--shadow-xl: 0 20px 40px rgba(0,0,0,0.1), 0 8px 20px rgba(0,0,0,0.08); |
|
--border-radius: 16px; |
|
--border-radius-sm: 12px; |
|
--border-radius-lg: 24px; |
|
} |
|
|
|
* { |
|
box-sizing: border-box; |
|
} |
|
|
|
body { |
|
margin: 0; |
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; |
|
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); |
|
color: var(--text-primary); |
|
line-height: 1.6; |
|
-webkit-font-smoothing: antialiased; |
|
-moz-osx-font-smoothing: grayscale; |
|
} |
|
|
|
.container { |
|
width: 100vw; |
|
padding: 20px; |
|
box-sizing: border-box; |
|
max-width: 1400px; |
|
margin: 0 auto; |
|
} |
|
|
|
.loading { |
|
text-align: center; |
|
padding: 80px 20px; |
|
font-size: 18px; |
|
color: var(--text-secondary); |
|
font-weight: 500; |
|
} |
|
|
|
|
|
.main-title { |
|
text-align: center; |
|
margin-bottom: 40px; |
|
padding: 0 20px; |
|
} |
|
|
|
.main-title h1 { |
|
font-size: clamp(36px, 8vw, 64px); |
|
font-weight: 900; |
|
margin: 0 0 16px 0; |
|
letter-spacing: -2px; |
|
background: var(--primary-gradient); |
|
-webkit-background-clip: text; |
|
-webkit-text-fill-color: transparent; |
|
background-clip: text; |
|
position: relative; |
|
} |
|
|
|
.main-title h1::after { |
|
content: ''; |
|
position: absolute; |
|
bottom: -8px; |
|
left: 50%; |
|
transform: translateX(-50%); |
|
width: 60px; |
|
height: 4px; |
|
background: var(--accent-gradient); |
|
border-radius: 2px; |
|
} |
|
|
|
.main-title p { |
|
font-size: clamp(16px, 4vw, 22px); |
|
margin: 0 0 20px 0; |
|
color: var(--text-secondary); |
|
font-weight: 400; |
|
line-height: 1.5; |
|
max-width: 600px; |
|
margin-left: auto; |
|
margin-right: auto; |
|
} |
|
|
|
.aisheets-credit { |
|
font-size: 14px; |
|
color: var(--text-muted); |
|
margin-top: 16px; |
|
font-weight: 500; |
|
} |
|
|
|
.aisheets-credit a { |
|
color: #667eea; |
|
text-decoration: none; |
|
font-weight: 600; |
|
transition: all 0.3s ease; |
|
padding: 4px 8px; |
|
border-radius: 6px; |
|
background: rgba(102, 126, 234, 0.1); |
|
} |
|
|
|
.aisheets-credit a:hover { |
|
color: #764ba2; |
|
background: rgba(118, 75, 162, 0.1); |
|
transform: translateY(-1px); |
|
} |
|
|
|
|
|
.stats-header { |
|
background: var(--card-bg); |
|
color: var(--text-primary); |
|
padding: 40px 30px; |
|
text-align: center; |
|
margin-bottom: 40px; |
|
border-radius: var(--border-radius-lg); |
|
box-shadow: var(--shadow-xl); |
|
border: 1px solid rgba(255,255,255,0.8); |
|
backdrop-filter: blur(20px); |
|
} |
|
|
|
.stats-header p { |
|
font-size: 16px; |
|
margin: 0 0 30px 0; |
|
color: var(--text-secondary); |
|
font-weight: 500; |
|
line-height: 1.6; |
|
} |
|
|
|
.win-stats { |
|
display: flex; |
|
justify-content: center; |
|
gap: 30px; |
|
margin-top: 30px; |
|
flex-wrap: wrap; |
|
} |
|
|
|
.stat { |
|
font-size: 16px; |
|
background: var(--primary-gradient); |
|
padding: 20px 30px; |
|
border-radius: var(--border-radius-sm); |
|
color: white; |
|
box-shadow: var(--shadow-md); |
|
transition: all 0.3s ease; |
|
border: 1px solid rgba(255,255,255,0.2); |
|
} |
|
|
|
.stat:hover { |
|
transform: translateY(-2px); |
|
box-shadow: var(--shadow-lg); |
|
} |
|
|
|
.stat .model { |
|
font-weight: 600; |
|
display: block; |
|
margin-bottom: 8px; |
|
font-size: 14px; |
|
opacity: 0.9; |
|
} |
|
|
|
.stat .wins { |
|
color: #4ade80; |
|
font-weight: 800; |
|
font-size: 24px; |
|
text-shadow: 0 1px 2px rgba(0,0,0,0.1); |
|
} |
|
|
|
|
|
.toc-container { |
|
background: var(--card-bg); |
|
border-radius: var(--border-radius-lg); |
|
box-shadow: var(--shadow-xl); |
|
margin-bottom: 40px; |
|
padding: 30px; |
|
border: 1px solid rgba(255,255,255,0.8); |
|
backdrop-filter: blur(20px); |
|
} |
|
|
|
.toc-title { |
|
font-size: 20px; |
|
font-weight: 700; |
|
margin-bottom: 20px; |
|
color: var(--text-primary); |
|
text-align: center; |
|
cursor: pointer; |
|
user-select: none; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
gap: 12px; |
|
padding: 12px; |
|
border-radius: var(--border-radius-sm); |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.toc-title:hover { |
|
background: rgba(102, 126, 234, 0.1); |
|
color: #667eea; |
|
transform: translateY(-1px); |
|
} |
|
|
|
.toc-content { |
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); |
|
overflow: hidden; |
|
} |
|
|
|
.toc-content.collapsed { |
|
max-height: 0; |
|
margin-bottom: 0; |
|
} |
|
|
|
.toc-content.expanded { |
|
max-height: none; |
|
margin-bottom: 20px; |
|
} |
|
|
|
.toc-grid { |
|
display: grid; |
|
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); |
|
gap: 16px; |
|
} |
|
|
|
.toc-item { |
|
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); |
|
border: 1px solid var(--border-color); |
|
border-radius: var(--border-radius-sm); |
|
padding: 20px; |
|
cursor: pointer; |
|
transition: all 0.3s ease; |
|
text-decoration: none; |
|
color: inherit; |
|
position: relative; |
|
overflow: hidden; |
|
} |
|
|
|
.toc-item::before { |
|
content: ''; |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
height: 3px; |
|
background: var(--accent-gradient); |
|
transform: scaleX(0); |
|
transition: transform 0.3s ease; |
|
} |
|
|
|
.toc-item:hover { |
|
background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%); |
|
border-color: #667eea; |
|
transform: translateY(-4px); |
|
box-shadow: var(--shadow-lg); |
|
} |
|
|
|
.toc-item:hover::before { |
|
transform: scaleX(1); |
|
} |
|
|
|
.toc-number { |
|
font-weight: 700; |
|
color: #667eea; |
|
margin-right: 12px; |
|
font-size: 16px; |
|
} |
|
|
|
.toc-description { |
|
font-size: 15px; |
|
line-height: 1.5; |
|
display: -webkit-box; |
|
-webkit-line-clamp: 2; |
|
-webkit-box-orient: vertical; |
|
overflow: hidden; |
|
font-weight: 500; |
|
} |
|
|
|
|
|
.app-section { |
|
margin-bottom: 40px; |
|
background: var(--card-bg); |
|
border-radius: var(--border-radius-lg); |
|
box-shadow: var(--shadow-xl); |
|
overflow: hidden; |
|
border: 1px solid rgba(255,255,255,0.8); |
|
backdrop-filter: blur(20px); |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.app-section:hover { |
|
transform: translateY(-2px); |
|
box-shadow: 0 25px 50px rgba(0,0,0,0.15), 0 10px 25px rgba(0,0,0,0.1); |
|
} |
|
|
|
.description-header { |
|
background: var(--primary-gradient); |
|
color: white; |
|
padding: 25px 20px; |
|
text-align: center; |
|
font-size: 18px; |
|
font-weight: 700; |
|
letter-spacing: -0.3px; |
|
position: relative; |
|
} |
|
|
|
.description-header::after { |
|
content: ''; |
|
position: absolute; |
|
bottom: 0; |
|
left: 0; |
|
right: 0; |
|
height: 1px; |
|
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent); |
|
} |
|
|
|
|
|
.evaluation-section { |
|
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%); |
|
border-bottom: 1px solid var(--border-color); |
|
padding: 20px; |
|
} |
|
|
|
.evaluation-result { |
|
background: linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%); |
|
border: 1px solid #86efac; |
|
border-radius: var(--border-radius-sm); |
|
padding: 20px; |
|
margin-bottom: 15px; |
|
box-shadow: var(--shadow-sm); |
|
} |
|
|
|
.eval-label { |
|
font-size: 12px; |
|
color: var(--text-muted); |
|
margin-bottom: 8px; |
|
font-weight: 600; |
|
text-transform: uppercase; |
|
letter-spacing: 0.5px; |
|
} |
|
|
|
.winner { |
|
color: #166534; |
|
font-weight: 800; |
|
margin-bottom: 8px; |
|
font-size: 16px; |
|
} |
|
|
|
.reason { |
|
color: #166534; |
|
font-weight: 500; |
|
} |
|
|
|
.view-eval-btn { |
|
background: var(--primary-gradient); |
|
color: white; |
|
border: none; |
|
padding: 8px 16px; |
|
border-radius: var(--border-radius-sm); |
|
cursor: pointer; |
|
margin-top: 12px; |
|
font-size: 13px; |
|
font-weight: 600; |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.view-eval-btn:hover { |
|
transform: translateY(-1px); |
|
box-shadow: var(--shadow-md); |
|
} |
|
|
|
.full-evaluation { |
|
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); |
|
border: 1px solid #fbbf24; |
|
border-radius: var(--border-radius-sm); |
|
padding: 20px; |
|
margin-top: 15px; |
|
display: none; |
|
box-shadow: var(--shadow-sm); |
|
} |
|
|
|
.thinking-content { |
|
max-height: 300px; |
|
overflow-y: auto; |
|
font-size: 14px; |
|
line-height: 1.6; |
|
white-space: pre-wrap; |
|
text-align: left; |
|
color: #92400e; |
|
font-weight: 500; |
|
} |
|
|
|
|
|
.implementations { |
|
display: grid; |
|
grid-template-columns: 1fr 1fr; |
|
gap: 0; |
|
} |
|
|
|
.impl-panel { |
|
border-right: 1px solid var(--border-color); |
|
position: relative; |
|
} |
|
|
|
.impl-panel:last-child { |
|
border-right: none; |
|
} |
|
|
|
.impl-header { |
|
background: var(--secondary-gradient); |
|
color: white; |
|
padding: 16px 20px; |
|
font-weight: 700; |
|
text-align: center; |
|
font-size: 16px; |
|
letter-spacing: -0.2px; |
|
position: relative; |
|
} |
|
|
|
.impl-header::after { |
|
content: ''; |
|
position: absolute; |
|
bottom: 0; |
|
left: 0; |
|
right: 0; |
|
height: 1px; |
|
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent); |
|
} |
|
|
|
.iframe-container { |
|
height: 600px; |
|
background: #f8fafc; |
|
position: relative; |
|
} |
|
|
|
.iframe-container::before { |
|
content: ''; |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
height: 1px; |
|
background: linear-gradient(90deg, transparent, var(--border-color), transparent); |
|
} |
|
|
|
iframe { |
|
width: 100%; |
|
height: 100%; |
|
border: none; |
|
transform: scale(1); |
|
transform-origin: top left; |
|
} |
|
|
|
.error { |
|
color: #ef4444; |
|
text-align: center; |
|
padding: 40px 20px; |
|
font-weight: 600; |
|
} |
|
|
|
|
|
@media (min-width: 1400px) { |
|
.iframe-container { height: 700px; } |
|
.container { padding: 30px; } |
|
} |
|
|
|
@media (max-width: 1200px) { |
|
.iframe-container { height: 500px; } |
|
.win-stats { gap: 20px; } |
|
.stat { padding: 16px 24px; } |
|
} |
|
|
|
@media (max-width: 768px) { |
|
.implementations { grid-template-columns: 1fr; } |
|
.impl-panel { border-right: none; border-bottom: 1px solid var(--border-color); } |
|
.impl-panel:last-child { border-bottom: none; } |
|
.iframe-container { height: 400px; } |
|
.container { padding: 15px; } |
|
.description-header { padding: 20px 15px; font-size: 16px; } |
|
.toc-grid { grid-template-columns: 1fr; } |
|
.win-stats { gap: 15px; } |
|
.stat { padding: 15px 20px; } |
|
.main-title h1 { font-size: 48px; } |
|
.main-title p { font-size: 18px; } |
|
} |
|
|
|
|
|
::-webkit-scrollbar { |
|
width: 8px; |
|
} |
|
|
|
::-webkit-scrollbar-track { |
|
background: #f1f5f9; |
|
border-radius: 4px; |
|
} |
|
|
|
::-webkit-scrollbar-thumb { |
|
background: var(--primary-gradient); |
|
border-radius: 4px; |
|
} |
|
|
|
::-webkit-scrollbar-thumb:hover { |
|
background: var(--secondary-gradient); |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="container"> |
|
<div id="apps-container" class="loading">Loading apps from Hugging Face...</div> |
|
</div> |
|
|
|
<script> |
|
function parseEvaluation(evalText) { |
|
if (!evalText) return null; |
|
|
|
try { |
|
|
|
const chosenMatch = evalText.match(/chosen:\s*(.+?)(?:\n|$)/i); |
|
const reasonMatch = evalText.match(/reason:\s*(.+?)(?:\n|$)/is); |
|
|
|
if (chosenMatch) { |
|
return { |
|
winner: chosenMatch[1].trim(), |
|
reason: reasonMatch ? reasonMatch[1].trim() : '', |
|
fullEval: evalText |
|
}; |
|
} |
|
|
|
return null; |
|
} catch (e) { |
|
console.error('Error parsing evaluation:', e); |
|
return null; |
|
} |
|
} |
|
|
|
function createEvaluationSection(evaluation, index) { |
|
const winner = evaluation.winner.toLowerCase().includes('kimi') ? 'Kimi-K2' : |
|
evaluation.winner.toLowerCase().includes('qwen') ? 'Qwen3-Coder' : |
|
evaluation.winner; |
|
|
|
return ` |
|
<div class="evaluation-section"> |
|
<div class="eval-label">(Kimi-K2 judge)</div> |
|
<div class="evaluation-result"> |
|
<div class="winner">🏆 Winner: ${winner}</div> |
|
<button class="view-eval-btn" onclick="toggleFullEval(${index})">View Reason</button> |
|
</div> |
|
<div class="full-evaluation" id="full-eval-${index}"> |
|
<div class="thinking-content">${evaluation.reason}</div> |
|
</div> |
|
</div> |
|
`; |
|
} |
|
|
|
function calculateWinRates(rows) { |
|
let kimiWins = 0; |
|
let qwenWins = 0; |
|
let ties = 0; |
|
let totalEvaluated = 0; |
|
|
|
rows.forEach(row => { |
|
const evaluation = parseEvaluation(row.row['r1-evaluation'] || ''); |
|
if (evaluation) { |
|
totalEvaluated++; |
|
const winner = evaluation.winner.toLowerCase(); |
|
if (winner.includes('kimi')) { |
|
kimiWins++; |
|
} else if (winner.includes('qwen')) { |
|
qwenWins++; |
|
} else { |
|
ties++; |
|
} |
|
} |
|
}); |
|
|
|
const kimiRate = totalEvaluated > 0 ? Math.round((kimiWins / totalEvaluated) * 100) : 0; |
|
const qwenRate = totalEvaluated > 0 ? Math.round((qwenWins / totalEvaluated) * 100) : 0; |
|
|
|
return { |
|
kimi: kimiWins, |
|
qwen: qwenWins, |
|
ties: ties, |
|
kimiRate: kimiRate, |
|
qwenRate: qwenRate, |
|
total: totalEvaluated |
|
}; |
|
} |
|
|
|
function toggleFullEval(index) { |
|
const fullEval = document.getElementById(`full-eval-${index}`); |
|
|
|
if (fullEval.style.display === 'block') { |
|
fullEval.style.display = 'none'; |
|
} else { |
|
fullEval.style.display = 'block'; |
|
} |
|
} |
|
|
|
function scrollToApp(index) { |
|
const appSection = document.getElementById(`app-${index}`); |
|
if (appSection) { |
|
appSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
|
} |
|
} |
|
|
|
function toggleTOC() { |
|
const tocContent = document.getElementById('toc-content'); |
|
const tocTitle = document.getElementById('toc-title'); |
|
const isCollapsed = tocContent.classList.contains('collapsed'); |
|
|
|
if (isCollapsed) { |
|
tocContent.classList.remove('collapsed'); |
|
tocContent.classList.add('expanded'); |
|
tocTitle.innerHTML = '📋 List of Apps ▼'; |
|
} else { |
|
tocContent.classList.remove('expanded'); |
|
tocContent.classList.add('collapsed'); |
|
tocTitle.innerHTML = '📋 List of Apps ▶'; |
|
} |
|
} |
|
|
|
async function loadAppsFromHuggingFace() { |
|
const container = document.getElementById('apps-container'); |
|
|
|
const response = await fetch('https://datasets-server.huggingface.co/rows?dataset=dvilasuero/JSVibes&config=default&split=train&offset=0&length=50'); |
|
const data = await response.json(); |
|
|
|
|
|
const winStats = calculateWinRates(data.rows); |
|
|
|
container.innerHTML = ` |
|
<div class="main-title"> |
|
<h1>JSVibes</h1> |
|
<p>Vibe testing open models for simple but useful (web) code tasks</p> |
|
<div class="aisheets-credit"> |
|
Built with <a href="https://huggingface.co/spaces/aisheets/sheets" target="_blank">AISheets</a> |
|
</div> |
|
</div> |
|
<div class="stats-header"> |
|
<p style="font-size: 14px; opacity: 0.8;">Automatically evaluated by Kimi K2 as a judge. Judgments are imperfect, test them yourself!</p> |
|
<div class="win-stats"> |
|
<div class="stat"> |
|
<span class="model">Kimi-K2</span> |
|
<span class="wins">${winStats.kimi} wins</span> |
|
<div style="font-size: 14px; opacity: 0.8;">${winStats.kimiRate}%</div> |
|
</div> |
|
<div class="stat"> |
|
<span class="model">Qwen3-Coder</span> |
|
<span class="wins">${winStats.qwen} wins</span> |
|
<div style="font-size: 14px; opacity: 0.8;">${winStats.qwenRate}%</div> |
|
</div> |
|
<div class="stat"> |
|
<span class="model">Ties</span> |
|
<span class="wins">${winStats.ties}</span> |
|
</div> |
|
</div> |
|
</div> |
|
<div class="toc-container"> |
|
<div class="toc-title" id="toc-title" onclick="toggleTOC()">📋 List of Apps ▶</div> |
|
<div class="toc-content collapsed" id="toc-content"> |
|
<div class="toc-grid" id="toc-grid"> |
|
<!-- TOC items will be populated here --> |
|
</div> |
|
</div> |
|
</div> |
|
`; |
|
|
|
|
|
const tocGrid = document.getElementById('toc-grid'); |
|
data.rows.forEach((row, index) => { |
|
const app = row.row; |
|
const tocItem = document.createElement('div'); |
|
tocItem.className = 'toc-item'; |
|
tocItem.onclick = () => scrollToApp(index); |
|
tocItem.innerHTML = ` |
|
<div> |
|
<span class="toc-number">#${index + 1}</span> |
|
<span class="toc-description">${app.description || 'No description available'}</span> |
|
</div> |
|
`; |
|
tocGrid.appendChild(tocItem); |
|
}); |
|
|
|
data.rows.forEach((row, index) => { |
|
const app = row.row; |
|
|
|
|
|
let kimiHtml = app['kimi-k2'] || ''; |
|
let qwenHtml = app['qwen3-coder'] || ''; |
|
|
|
if (kimiHtml.startsWith('```html')) { |
|
kimiHtml = kimiHtml.replace(/```html\n?/, '').replace(/```$/, ''); |
|
} |
|
if (qwenHtml.startsWith('```html')) { |
|
qwenHtml = qwenHtml.replace(/```html\n?/, '').replace(/```$/, ''); |
|
} |
|
|
|
|
|
const evaluation = parseEvaluation(app['r1-evaluation'] || ''); |
|
if (!evaluation && app['r1-evaluation']) { |
|
console.log(`Failed to parse evaluation for app ${index}:`, app['r1-evaluation']); |
|
} |
|
|
|
const section = document.createElement('div'); |
|
section.className = 'app-section'; |
|
section.id = `app-${index}`; |
|
section.innerHTML = ` |
|
<div class="description-header"> |
|
${index + 1}. ${app.description || 'No description available'} |
|
</div> |
|
${evaluation ? createEvaluationSection(evaluation, index) : ''} |
|
<div class="implementations"> |
|
<div class="impl-panel"> |
|
<div class="impl-header">Kimi-K2</div> |
|
<div class="iframe-container"> |
|
<iframe srcdoc="${kimiHtml.replace(/"/g, '"')}"></iframe> |
|
</div> |
|
</div> |
|
<div class="impl-panel"> |
|
<div class="impl-header">Qwen3-Coder</div> |
|
<div class="iframe-container"> |
|
<iframe srcdoc="${qwenHtml.replace(/"/g, '"')}"></iframe> |
|
</div> |
|
</div> |
|
</div> |
|
`; |
|
|
|
container.appendChild(section); |
|
}); |
|
} |
|
|
|
|
|
loadAppsFromHuggingFace(); |
|
</script> |
|
</body> |
|
</html> |