Spaces:
Running
Running
| <html> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>Live WebApp Viewer</title> | |
| <style> | |
| body { margin: 0; font-family: Arial, sans-serif; background: #f5f5f5; } | |
| .container { width: 100vw; padding: 10px; box-sizing: border-box; } | |
| .loading { text-align: center; padding: 50px; font-size: 18px; color: #666; } | |
| .main-title { | |
| text-align: center; | |
| margin-bottom: 20px; | |
| padding: 0 20px; | |
| } | |
| .main-title h1 { | |
| font-size: 48px; | |
| font-weight: 800; | |
| margin: 0 0 8px 0; | |
| letter-spacing: -1px; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| .main-title p { | |
| font-size: 20px; | |
| margin: 0; | |
| color: #666; | |
| font-weight: 400; | |
| line-height: 1.4; | |
| } | |
| .stats-header { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| padding: 30px 20px; | |
| text-align: center; | |
| margin-bottom: 30px; | |
| border-radius: 12px; | |
| box-shadow: 0 8px 32px rgba(0,0,0,0.1); | |
| } | |
| .stats-header p { | |
| font-size: 16px; | |
| margin: 0 0 20px 0; | |
| opacity: 0.9; | |
| font-weight: 400; | |
| line-height: 1.5; | |
| } | |
| .win-stats { | |
| display: flex; | |
| justify-content: center; | |
| gap: 50px; | |
| margin-top: 20px; | |
| flex-wrap: wrap; | |
| } | |
| .stat { | |
| font-size: 16px; | |
| background: rgba(255,255,255,0.15); | |
| padding: 12px 20px; | |
| border-radius: 8px; | |
| backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255,255,255,0.2); | |
| } | |
| .stat .model { | |
| font-weight: 600; | |
| display: block; | |
| margin-bottom: 4px; | |
| } | |
| .stat .wins { | |
| color: #4ade80; | |
| font-weight: 700; | |
| font-size: 18px; | |
| } | |
| .app-section { margin-bottom: 30px; background: white; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); overflow: hidden; } | |
| .description-header { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| padding: 20px 15px; | |
| text-align: center; | |
| font-size: 18px; | |
| font-weight: 600; | |
| letter-spacing: -0.3px; | |
| } | |
| .evaluation-section { background: #f8f9fa; border-bottom: 1px solid #eee; padding: 15px; } | |
| .evaluation-result { background: #d4edda; border: 1px solid #c3e6cb; border-radius: 4px; padding: 12px; margin-bottom: 10px; } | |
| .eval-label { font-size: 12px; color: #666; margin-bottom: 5px; } | |
| .winner { color: #155724; font-weight: bold; margin-bottom: 5px; } | |
| .reason { color: #155724; } | |
| .view-eval-btn { background: #007bff; color: white; border: none; padding: 5px 10px; border-radius: 3px; cursor: pointer; margin-top: 10px; font-size: 12px; } | |
| .full-evaluation { background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 4px; padding: 15px; margin-top: 10px; display: none; } | |
| .thinking-content { max-height: 300px; overflow-y: auto; font-size: 14px; line-height: 1.5; white-space: pre-wrap; text-align: left; color: #495057; } | |
| .implementations { display: grid; grid-template-columns: 1fr 1fr; gap: 0; } | |
| .impl-panel { border-right: 1px solid #eee; } | |
| .impl-panel:last-child { border-right: none; } | |
| .impl-header { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| padding: 12px 15px; | |
| font-weight: 600; | |
| text-align: center; | |
| font-size: 15px; | |
| letter-spacing: -0.2px; | |
| } | |
| .iframe-container { height: 600px; } | |
| iframe { width: 100%; height: 100%; border: none; transform: scale(1); transform-origin: top left; } | |
| .error { color: red; text-align: center; padding: 20px; } | |
| /* Large screens - even bigger */ | |
| @media (min-width: 1400px) { | |
| .iframe-container { height: 700px; } | |
| } | |
| /* Medium screens */ | |
| @media (max-width: 1200px) { | |
| .iframe-container { height: 500px; } | |
| } | |
| /* Small screens - stack vertically */ | |
| @media (max-width: 768px) { | |
| .implementations { grid-template-columns: 1fr; } | |
| .impl-panel { border-right: none; border-bottom: 1px solid #eee; } | |
| .impl-panel:last-child { border-bottom: none; } | |
| .iframe-container { height: 400px; } | |
| .container { padding: 5px; } | |
| .description-header { padding: 10px; font-size: 14px; } | |
| } | |
| </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 { | |
| // Look for "chosen:" and "reason:" patterns | |
| 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'; | |
| } | |
| } | |
| 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(); | |
| // Calculate win rates | |
| const winStats = calculateWinRates(data.rows); | |
| container.innerHTML = ` | |
| <div class="main-title"> | |
| <h1>JSVibes</h1> | |
| <p>Vibe testing open models for simple but useful code tasks</p> | |
| </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> | |
| `; | |
| data.rows.forEach((row, index) => { | |
| const app = row.row; | |
| // Clean HTML content by removing markdown code blocks | |
| 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(/```$/, ''); | |
| } | |
| // Parse evaluation data | |
| 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.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); | |
| }); | |
| } | |
| // Load apps when page loads | |
| loadAppsFromHuggingFace(); | |
| </script> | |
| </body> | |
| </html> |