CoolFace
Apppublic

Javare/Local_AI_WebGPU

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
index.html251 linesDownload Raw Back to root
1<!DOCTYPE html>2<html lang="fr">3  <head>4    <meta charset="UTF-8" />5    <meta name="viewport" content="width=device-width, initial-scale=1.0" />6    <title>Local AI WebGPU - Benchmark</title>7    8    <script type="module" crossorigin src="/assets/index-Btti6dN2.js"></script>9    <link rel="stylesheet" crossorigin href="/assets/index-CjAcR-nm.css">10    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>11 12    <style>13      .benchmark-sidebar {14        position: fixed; top: 0; right: 0; width: 420px; height: 100vh;15        background: #ffffff; box-shadow: -4px 0 25px rgba(0,0,0,0.15);16        z-index: 999999; font-family: system-ui, -apple-system, sans-serif;17        display: flex; flex-direction: column; color: #2d3748; border-left: 1px solid #e2e8f0;18      }19      .benchmark-header { background: #1a202c; color: white; padding: 15px; text-align: center; margin: 0; font-size: 1.2rem; }20      .benchmark-content { padding: 15px; overflow-y: auto; flex: 1; }21      .form-group { margin-bottom: 10px; display: flex; flex-direction: column; gap: 4px; }22      .form-group label { font-size: 0.85rem; font-weight: 600; color: #4a5568; }23      .form-group input, .form-group select { padding: 8px 12px; border: 1px solid #cbd5e0; border-radius: 6px; font-size: 0.9rem; background: #f7fafc; }24      .power-selector { display: flex; gap: 10px; margin-top: 4px; }25      .power-btn { flex: 1; padding: 10px; border: 2px solid #e2e8f0; border-radius: 6px; background: #fff; cursor: pointer; font-weight: bold; font-size: 0.85rem; display: flex; justify-content: center; gap: 6px; }26      .power-btn.active { border-color: #3182ce; background: #ebf8ff; color: #2b6cb0; }27      28      .leaderboard-table { width: 100%; border-collapse: collapse; margin-top: 10px; font-size: 0.78rem; }29      .leaderboard-table th, .leaderboard-table td { padding: 6px 4px; text-align: left; border-bottom: 1px solid #e2e8f0; }30      .leaderboard-table th { background-color: #edf2f7; font-weight: 700; color: #4a5568; }31      .badge-top { background: #ecc94b; color: #744210; padding: 1px 4px; border-radius: 4px; font-weight: bold; }32      .text-muted { color: #718096; font-size: 0.72rem; }33      body { margin-right: 420px !important; }34    </style>35 36    <script>37      let selectedPower = '🔌 Secteur';38      let startTime = 0;39      let minTpsRecorded = Infinity;40      let maxTpsRecorded = 0;41      let tokenLabels = [];42      let tpsData = [];43 44      function setPower(type) {45          selectedPower = type;46          document.getElementById('btnSecteur').classList.toggle('active', type === '🔌 Secteur');47          document.getElementById('btnBatterie').classList.toggle('active', type === '🔋 Batterie');48      }49 50      // Interception du Web Worker51      const OriginalWorker = window.Worker;52      window.Worker = function(...args) {53          const worker = new OriginalWorker(...args);54          55          worker.addEventListener('message', function(e) {56              const data = e.data;57              58              if (data && data.status === 'start') {59                  startTime = performance.now();60                  minTpsRecorded = Infinity;61                  maxTpsRecorded = 0;62                  tokenLabels = [];63                  tpsData = [];64                  if (window.tpsChart) {65                      window.tpsChart.data.labels = [];66                      window.tpsChart.data.datasets[0].data = [];67                      window.tpsChart.update();68                  }69              }70              71              if (data && data.status === 'update' && data.tps !== undefined) {72                  const currentTps = data.tps;73                  const currentTokens = data.numTokens;74 75                  // On commence à enregistrer min/max après 5 tokens pour éviter le lag de départ76                  if (currentTokens > 5) {77                      if (currentTps > maxTpsRecorded) maxTpsRecorded = currentTps;78                      if (currentTps < minTpsRecorded) minTpsRecorded = currentTps;79                  }80 81                  tokenLabels.push(currentTokens);82                  tpsData.push(parseFloat(currentTps.toFixed(2)));83                  if (window.tpsChart) {84                      window.tpsChart.data.labels = tokenLabels;85                      window.tpsChart.data.datasets[0].data = tpsData;86                      window.tpsChart.update('none');87                  }88              }89 90              if (data && data.status === 'complete') {91                  const totalTime = (performance.now() - startTime) / 1000;92                  const totalTokens = data.numTokens || tokenLabels.length;93                  const finalAvgTps = totalTokens / totalTime;94                  95                  if (minTpsRecorded === Infinity) minTpsRecorded = finalAvgTps;96 97                  // Envoi des statistiques complètes au serveur98                  saveScore(minTpsRecorded, maxTpsRecorded, finalAvgTps, totalTokens, totalTime);99              }100          });101          102          return worker;103      };104 105      async function loadLeaderboard() {106          try {107              const response = await fetch('/api/scores');108              const scores = await response.json();109              const tbody = document.getElementById('leaderboardBody');110              tbody.innerHTML = '';111              112              if(!scores || scores.length === 0) {113                  tbody.innerHTML = '<tr><td colspan="5" style="text-align:center; color:#888;">Aucun score.</td></tr>';114                  return;115              }116              117              scores.forEach((item, index) => {118                  const row = document.createElement('tr');119                  const isTop3 = index < 3 ? `<span class="badge-top">🥇 ${index + 1}</span>` : index + 1;120                  121                  row.innerHTML = `122                      <td>${isTop3}</td>123                      <td><strong>${item.config}</strong><br><span class="text-muted">${item.browser} • ${item.power}</span></td>124                      <td>Min: ${item.min_tps.toFixed(1)}<br>Max: <strong>${item.max_tps.toFixed(1)}</strong></td>125                      <td style="color: #2b6cb0; font-weight: bold;">${item.avg_tps.toFixed(1)} tps</td>126                      <td>${item.total_tokens} tok<br><span class="text-muted">en ${item.duration.toFixed(1)}s</span></td>127                  `;128                  tbody.appendChild(row);129              });130          } catch (error) {131              console.error("Erreur chargement classement:", error);132          }133      }134 135      async function saveScore(minTps, maxTps, avgTps, totalTokens, duration) {136          const type = document.getElementById('deviceType').value;137          const model = document.getElementById('deviceModel').value || "Inconnu";138          const os = document.getElementById('osType').value;139          const browser = document.getElementById('browserType').value;140          141          const configString = `${type} [${os}] (${model})`;142          143          const payload = {144              config: configString, browser: browser, power: selectedPower,145              min_tps: minTps, max_tps: maxTps, avg_tps: avgTps,146              total_tokens: parseInt(totalTokens), duration: parseFloat(duration)147          };148 149          try {150              await fetch('/api/score', {151                  method: 'POST',152                  headers: { 'Content-Type': 'application/json' },153                  body: JSON.stringify(payload)154              });155              loadLeaderboard(); 156          } catch (error) {157              console.error("Erreur envoi score:", error);158          }159      }160 161      document.addEventListener("DOMContentLoaded", () => {162          loadLeaderboard();163          const ctx = document.getElementById('stressTestChart').getContext('2d');164          window.tpsChart = new Chart(ctx, {165              type: 'line',166              data: { labels: [], datasets: [{ label: 'tps', data: [], borderColor: '#3182ce', tension: 0.1, pointRadius: 0, borderWidth: 2 }] },167              options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true } } }168          });169      });170    </script>171  </head>172  <body>173 174    <div id="root"></div>175 176    <div class="benchmark-sidebar">177      <h3 class="benchmark-header">⚡ WebGPU Stress Test</h3>178      179      <div class="benchmark-content">180        <div class="form-group">181          <label>Type d'appareil</label>182          <select id="deviceType">183            <option value="🖥️ UC (Bureau)">🖥️ UC (Bureau)</option>184            <option value="💻 Laptop">💻 Laptop</option>185            <option value="🖥️ All in One">🖥️ All in One</option>186            <option value="📱 Tablette">📱 Tablette</option>187            <option value="📱 SmartPhone">📱 SmartPhone</option>188          </select>189        </div>190 191        <div class="form-group">192          <label>Modèle (CPU / GPU / Modèle exact)</label>193          <input type="text" id="deviceModel" placeholder="Ex: RTX 4070 / Apple M3 / Galaxy S26" required>194        </div>195 196        <div class="form-group">197          <label>Système d'exploitation (OS)</label>198          <select id="osType">199            <option value="Windows">Windows</option>200            <option value="macOS">macOS</option>201            <option value="Linux">Linux</option>202            <option value="Android">Android</option>203            <option value="iOS">iOS</option>204          </select>205        </div>206 207        <div class="form-group">208          <label>Navigateur Internet</label>209          <select id="browserType">210            <option value="Chrome">Chrome</option>211            <option value="Firefox">Firefox</option>212            <option value="Edge">Edge</option>213            <option value="Brave">Brave</option>214            <option value="Safari">Safari</option>215            <option value="Opera">Opera</option>216          </select>217        </div>218 219        <div class="form-group">220          <label>Source d'alimentation</label>221          <div class="power-selector">222            <button type="button" class="power-btn active" id="btnSecteur" onclick="setPower('🔌 Secteur')">🔌 Secteur</button>223            <button type="button" class="power-btn" id="btnBatterie" onclick="setPower('🔋 Batterie')">🔋 Batterie</button>224          </div>225        </div>226 227        <hr style="border: 0; border-top: 1px solid #e2e8f0; margin: 10px 0;">228 229        <div style="height: 110px; position: relative; margin-bottom: 10px;">230          <canvas id="stressTestChart"></canvas>231        </div>232 233        <h4 style="margin: 10px 0 5px 0; color: #1a202c;">🏆 TOP 10 Global</h4>234        <table class="leaderboard-table">235          <thead>236            <tr>237              <th style="width: 8%">Rg</th>238              <th style="width: 42%">Configuration</th>239              <th style="width: 20%">TPS (Min/Max)</th>240              <th style="width: 15%">Moyenne</th>241              <th style="width: 15%">Tokens/Tps</th>242            </tr>243          </thead>244          <tbody id="leaderboardBody">245            </tbody>246        </table>247      </div>248    </div>249 250  </body>251</html>