Spaces:
Running
Running
Download index.html from NeverBlufff/teambpc: direct link, hf CLI and curl.
- Browser
- Download file 16.4 kB
-
https://huggingface.co/spaces/NeverBlufff/teambpc/resolve/main/index.html
- Command line
-
hf download hf://spaces/NeverBlufff/teambpc/index.html
-
curl -L -o index.html https://huggingface.co/spaces/NeverBlufff/teambpc/resolve/main/index.html
16.4 kB
| <html lang="fr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Poker GTO Trainer - Scanner</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary: #2563eb; | |
| --secondary: #1e40af; | |
| --dark: #1e293b; | |
| --darker: #0f172a; | |
| --light: #f8fafc; | |
| --success: #10b981; | |
| --danger: #ef4444; | |
| --warning: #f59e0b; | |
| } | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; | |
| background-color: var(--darker); | |
| color: white; | |
| } | |
| .camera-container { | |
| position: relative; | |
| width: 100%; | |
| max-width: 500px; | |
| margin: 0 auto; | |
| height: 70vh; | |
| overflow: hidden; | |
| border-radius: 12px; | |
| background-color: black; | |
| } | |
| .camera-preview { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| } | |
| .scan-overlay { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| background-color: rgba(0, 0, 0, 0.5); | |
| } | |
| .scan-guide { | |
| width: 80%; | |
| height: 120px; | |
| border: 2px dashed var(--primary); | |
| border-radius: 8px; | |
| margin-bottom: 20px; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| color: white; | |
| font-weight: bold; | |
| } | |
| .capture-btn { | |
| position: absolute; | |
| bottom: 30px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| width: 70px; | |
| height: 70px; | |
| background-color: white; | |
| border-radius: 50%; | |
| border: 4px solid var(--primary); | |
| cursor: pointer; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| } | |
| .capture-btn::after { | |
| content: ''; | |
| width: 50px; | |
| height: 50px; | |
| background-color: var(--primary); | |
| border-radius: 50%; | |
| } | |
| .result-container { | |
| display: none; | |
| padding: 20px; | |
| background-color: var(--dark); | |
| border-radius: 12px; | |
| margin-top: 20px; | |
| } | |
| .card-display { | |
| width: 80px; | |
| height: 120px; | |
| background-color: white; | |
| border-radius: 8px; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| font-size: 24px; | |
| font-weight: bold; | |
| color: black; | |
| margin: 0 auto; | |
| position: relative; | |
| } | |
| .card-display::before { | |
| content: attr(data-suit); | |
| position: absolute; | |
| top: 5px; | |
| left: 5px; | |
| font-size: 16px; | |
| } | |
| .card-display::after { | |
| content: attr(data-suit); | |
| position: absolute; | |
| bottom: 5px; | |
| right: 5px; | |
| font-size: 16px; | |
| transform: rotate(180deg); | |
| } | |
| .heart, .diamond { | |
| color: red; | |
| } | |
| .spade, .club { | |
| color: black; | |
| } | |
| .action-buttons { | |
| display: flex; | |
| gap: 10px; | |
| margin-top: 20px; | |
| } | |
| .btn { | |
| padding: 12px 20px; | |
| border-radius: 8px; | |
| font-weight: bold; | |
| border: none; | |
| cursor: pointer; | |
| flex: 1; | |
| text-align: center; | |
| } | |
| .btn-primary { | |
| background-color: var(--primary); | |
| color: white; | |
| } | |
| .btn-secondary { | |
| background-color: var(--dark); | |
| color: white; | |
| border: 1px solid var(--primary); | |
| } | |
| .btn-danger { | |
| background-color: var(--danger); | |
| color: white; | |
| } | |
| .accuracy-meter { | |
| height: 10px; | |
| background-color: #334155; | |
| border-radius: 5px; | |
| margin-top: 10px; | |
| overflow: hidden; | |
| } | |
| .accuracy-fill { | |
| height: 100%; | |
| background-color: var(--success); | |
| width: 90%; | |
| } | |
| .card-grid { | |
| display: grid; | |
| grid-template-columns: repeat(4, 1fr); | |
| gap: 10px; | |
| margin-top: 20px; | |
| } | |
| .card-option { | |
| padding: 10px; | |
| border: 1px solid #334155; | |
| border-radius: 8px; | |
| text-align: center; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .card-option:hover { | |
| background-color: #334155; | |
| } | |
| .card-option.selected { | |
| background-color: var(--primary); | |
| border-color: var(--primary); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="min-h-screen flex flex-col"> | |
| <!-- Header --> | |
| <div class="bg-dark p-4 flex items-center justify-between"> | |
| <button class="text-white"> | |
| <i class="fas fa-arrow-left"></i> | |
| </button> | |
| <h1 class="text-xl font-bold">Scanner des cartes</h1> | |
| <div class="w-6"></div> <!-- Spacer for balance --> | |
| </div> | |
| <!-- Main Content --> | |
| <div class="flex-1 p-4"> | |
| <!-- Camera Preview --> | |
| <div class="camera-container" id="cameraContainer"> | |
| <video id="cameraPreview" class="camera-preview" autoplay playsinline></video> | |
| <div class="scan-overlay"> | |
| <div class="scan-guide">Placez les cartes dans ce cadre</div> | |
| </div> | |
| <button class="capture-btn" id="captureBtn"></button> | |
| </div> | |
| <!-- Result Display --> | |
| <div class="result-container" id="resultContainer"> | |
| <h2 class="text-xl font-bold mb-4">Résultat de l'analyse</h2> | |
| <div class="flex items-center justify-center gap-4 mb-6"> | |
| <div class="card-display" id="card1" data-rank="A" data-suit="♠"> | |
| A<span class="spade">♠</span> | |
| </div> | |
| <div class="card-display" id="card2" data-rank="K" data-suit="♥"> | |
| K<span class="heart">♥</span> | |
| </div> | |
| </div> | |
| <div class="bg-slate-700 p-4 rounded-lg"> | |
| <h3 class="font-bold mb-2">Action recommandée</h3> | |
| <p class="text-green-400 font-bold text-lg mb-2">Open Raise (92%)</p> | |
| <div class="accuracy-meter"> | |
| <div class="accuracy-fill"></div> | |
| </div> | |
| <p class="text-sm text-slate-300 mt-2">Confiance de l'analyse: 90%</p> | |
| </div> | |
| <div class="mt-6"> | |
| <h3 class="font-bold mb-2">Autres options possibles</h3> | |
| <div class="card-grid"> | |
| <div class="card-option">Call (8%)</div> | |
| <div class="card-option">Fold (0%)</div> | |
| <div class="card-option">3-Bet (45%)</div> | |
| <div class="card-option">4-Bet (12%)</div> | |
| </div> | |
| </div> | |
| <div class="action-buttons mt-6"> | |
| <button class="btn btn-secondary" id="rescanBtn"> | |
| <i class="fas fa-redo mr-2"></i>Rescanner | |
| </button> | |
| <button class="btn btn-primary" id="saveResultBtn"> | |
| <i class="fas fa-save mr-2"></i>Sauvegarder | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Alternative Upload --> | |
| <div class="mt-6 text-center"> | |
| <p class="text-slate-400 mb-3">Ou sélectionnez une image depuis votre galerie</p> | |
| <button class="btn btn-secondary" id="uploadBtn"> | |
| <i class="fas fa-upload mr-2"></i>Choisir une image | |
| </button> | |
| <input type="file" id="fileInput" accept="image/*" class="hidden"> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Camera and scan functionality | |
| let stream = null; | |
| const cameraContainer = document.getElementById('cameraContainer'); | |
| const cameraPreview = document.getElementById('cameraPreview'); | |
| const captureBtn = document.getElementById('captureBtn'); | |
| const resultContainer = document.getElementById('resultContainer'); | |
| const rescanBtn = document.getElementById('rescanBtn'); | |
| const saveResultBtn = document.getElementById('saveResultBtn'); | |
| const uploadBtn = document.getElementById('uploadBtn'); | |
| const fileInput = document.getElementById('fileInput'); | |
| // Start camera | |
| async function startCamera() { | |
| try { | |
| stream = await navigator.mediaDevices.getUserMedia({ | |
| video: { | |
| facingMode: 'environment', | |
| width: { ideal: 1280 }, | |
| height: { ideal: 720 } | |
| }, | |
| audio: false | |
| }); | |
| cameraPreview.srcObject = stream; | |
| cameraContainer.style.display = 'block'; | |
| resultContainer.style.display = 'none'; | |
| } catch (err) { | |
| console.error("Error accessing camera:", err); | |
| alert("Impossible d'accéder à la caméra. Veuillez vérifier les permissions."); | |
| // Fallback to upload | |
| uploadBtn.click(); | |
| } | |
| } | |
| // Capture photo | |
| function capturePhoto() { | |
| const canvas = document.createElement('canvas'); | |
| canvas.width = cameraPreview.videoWidth; | |
| canvas.height = cameraPreview.videoHeight; | |
| const ctx = canvas.getContext('2d'); | |
| // Draw image with crop to guide area | |
| const guideSize = Math.min(cameraPreview.videoWidth * 0.8, cameraPreview.videoHeight * 0.5); | |
| const x = (cameraPreview.videoWidth - guideSize) / 2; | |
| const y = (cameraPreview.videoHeight - guideSize) / 2; | |
| ctx.drawImage(cameraPreview, x, y, guideSize, guideSize, 0, 0, canvas.width, canvas.height); | |
| // Stop camera | |
| stopCamera(); | |
| // Show result | |
| analyzeImage(canvas.toDataURL('image/jpeg')); | |
| } | |
| // Stop camera | |
| function stopCamera() { | |
| if (stream) { | |
| stream.getTracks().forEach(track => track.stop()); | |
| stream = null; | |
| } | |
| } | |
| // Analyze image (simulated with better card recognition) | |
| function analyzeImage(imageData) { | |
| // Hide camera and show result | |
| cameraContainer.style.display = 'none'; | |
| resultContainer.style.display = 'block'; | |
| // Simulate card recognition with more realistic results | |
| const sampleCards = [ | |
| { rank: 'A', suit: '♠', suitClass: 'spade' }, | |
| { rank: 'K', suit: '♥', suitClass: 'heart' }, | |
| { rank: 'Q', suit: '♦', suitClass: 'diamond' }, | |
| { rank: 'J', suit: '♣', suitClass: 'club' }, | |
| { rank: 'T', suit: '♠', suitClass: 'spade' }, | |
| { rank: '9', suit: '♥', suitClass: 'heart' } | |
| ]; | |
| // Randomly select two different cards | |
| const card1 = sampleCards[Math.floor(Math.random() * sampleCards.length)]; | |
| let card2; | |
| do { | |
| card2 = sampleCards[Math.floor(Math.random() * sampleCards.length)]; | |
| } while (card1.rank === card2.rank && card1.suit === card2.suit); | |
| // Update card displays | |
| document.getElementById('card1').setAttribute('data-rank', card1.rank); | |
| document.getElementById('card1').setAttribute('data-suit', card1.suit); | |
| document.getElementById('card1').innerHTML = `${card1.rank}<span class="${card1.suitClass}">${card1.suit}</span>`; | |
| document.getElementById('card2').setAttribute('data-rank', card2.rank); | |
| document.getElementById('card2').setAttribute('data-suit', card2.suit); | |
| document.getElementById('card2').innerHTML = `${card2.rank}<span class="${card2.suitClass}">${card2.suit}</span>`; | |
| // Determine action based on cards (simplified poker logic) | |
| let action, percentage; | |
| if (card1.rank === 'A' || card2.rank === 'A') { | |
| action = "Open Raise"; | |
| percentage = "92%"; | |
| } else if (card1.rank === card2.rank) { | |
| action = "3-Bet"; | |
| percentage = "85%"; | |
| } else if (card1.suitClass === card2.suitClass) { | |
| action = "Call"; | |
| percentage = "75%"; | |
| } else { | |
| action = "Fold"; | |
| percentage = "60%"; | |
| } | |
| document.querySelector('.text-green-400').textContent = `${action} (${percentage})`; | |
| } | |
| // Handle file upload | |
| function handleFileUpload(event) { | |
| const file = event.target.files[0]; | |
| if (file) { | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| // Hide camera and show result | |
| cameraContainer.style.display = 'none'; | |
| resultContainer.style.display = 'block'; | |
| // Analyze the uploaded image | |
| analyzeImage(e.target.result); | |
| }; | |
| reader.readAsDataURL(file); | |
| } | |
| } | |
| // Initialize app | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Start camera automatically | |
| startCamera(); | |
| // Capture button | |
| captureBtn.addEventListener('click', capturePhoto); | |
| // Rescan button | |
| rescanBtn.addEventListener('click', function() { | |
| startCamera(); | |
| }); | |
| // Save result button | |
| saveResultBtn.addEventListener('click', function() { | |
| alert("Résultat sauvegardé dans votre historique"); | |
| }); | |
| // Upload button | |
| uploadBtn.addEventListener('click', function() { | |
| fileInput.click(); | |
| }); | |
| // File input change | |
| fileInput.addEventListener('change', handleFileUpload); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=NeverBlufff/teambpc" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |