Download index.html from punab3/posee: direct link, hf CLI and curl.
- Browser
- Download file 6.37 kB
-
https://huggingface.co/spaces/punab3/posee/resolve/main/index.html
- Command line
-
hf download hf://spaces/punab3/posee/index.html
-
curl -L -o index.html https://huggingface.co/spaces/punab3/posee/resolve/main/index.html
6.37 kB
| <html lang="id"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>AI Pose Recognition with Audio</title> | |
| <style> | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| text-align: center; | |
| background-color: #1a1a1a; | |
| color: white; | |
| padding: 20px; | |
| } | |
| h2 { color: #00d4ff; } | |
| #canvas-container { | |
| position: relative; | |
| display: inline-block; | |
| border: 5px solid #333; | |
| border-radius: 15px; | |
| overflow: hidden; | |
| background: #000; | |
| } | |
| #label-container { | |
| margin-top: 20px; | |
| display: flex; | |
| justify-content: center; | |
| gap: 15px; | |
| } | |
| #label-container div { | |
| background: #333; | |
| padding: 10px 20px; | |
| border-radius: 8px; | |
| font-size: 18px; | |
| min-width: 120px; | |
| } | |
| button { | |
| padding: 15px 35px; | |
| font-size: 18px; | |
| font-weight: bold; | |
| cursor: pointer; | |
| background: linear-gradient(45deg, #00d4ff, #0056b3); | |
| color: white; | |
| border: none; | |
| border-radius: 50px; | |
| transition: 0.3s; | |
| margin-bottom: 20px; | |
| box-shadow: 0 4px 15px rgba(0, 212, 255, 0.3); | |
| } | |
| button:hover { | |
| transform: scale(1.05); | |
| box-shadow: 0 6px 20px rgba(0, 212, 255, 0.5); | |
| } | |
| .active-pose { | |
| border: 2px solid #00d4ff ; | |
| background: #0056b3 ; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <h2>AI Pose Detector: Peace, Mantap, Metal</h2> | |
| <p>Pastikan kamera aktif dan tekan tombol di bawah:</p> | |
| <button type="button" onclick="init()">MULAI KAMERA</button> | |
| <div id="status"></div> | |
| <div id="canvas-container"> | |
| <canvas id="canvas"></canvas> | |
| </div> | |
| <div id="label-container"></div> | |
| <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.3.1/dist/tf.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@teachablemachine/pose@0.8/dist/teachablemachine-pose.min.js"></script> | |
| <script type="text/javascript"> | |
| // Link model dari Teachable Machine kamu | |
| const URL = "https://teachablemachine.withgoogle.com/models/0Y2ifsgF4/"; | |
| let model, webcam, ctx, labelContainer, maxPredictions; | |
| // Persiapan Audio | |
| const sounds = { | |
| "peace": new Audio("mp3peace.mp3"), | |
| "mantap": new Audio("mp3mantap.mp3"), | |
| "metal": new Audio("mp3metal.mp3") | |
| }; | |
| let lastPlayedPose = ""; // Mencegah suara terulang terus menerus | |
| let silenceTimer; // Timer untuk meriset status suara | |
| async function init() { | |
| const modelURL = URL + "model.json"; | |
| const metadataURL = URL + "metadata.json"; | |
| // Load model | |
| model = await tmPose.load(modelURL, metadataURL); | |
| maxPredictions = model.getTotalClasses(); | |
| // Setup Webcam | |
| const size = 400; | |
| const flip = true; | |
| webcam = new tmPose.Webcam(size, size, flip); | |
| await webcam.setup(); | |
| await webcam.play(); | |
| window.requestAnimationFrame(loop); | |
| // Setup UI | |
| const canvas = document.getElementById("canvas"); | |
| canvas.width = size; canvas.height = size; | |
| ctx = canvas.getContext("2d"); | |
| labelContainer = document.getElementById("label-container"); | |
| labelContainer.innerHTML = ""; // Bersihkan container | |
| for (let i = 0; i < maxPredictions; i++) { | |
| labelContainer.appendChild(document.createElement("div")); | |
| } | |
| } | |
| async function loop(timestamp) { | |
| webcam.update(); | |
| await predict(); | |
| window.requestAnimationFrame(loop); | |
| } | |
| async function predict() { | |
| const { pose, posenetOutput } = await model.estimatePose(webcam.canvas); | |
| const prediction = await model.predict(posenetOutput); | |
| for (let i = 0; i < maxPredictions; i++) { | |
| const className = prediction[i].className; // Nama class asli: peace, mantap, metal | |
| const probability = prediction[i].probability; | |
| const element = labelContainer.childNodes[i]; | |
| element.innerHTML = `${className}: ${(probability * 100).toFixed(0)}%`; | |
| // Logika Suara dan Highlight UI | |
| if (probability > 0.90) { // Ambang batas 90% yakin | |
| element.classList.add("active-pose"); | |
| // Mainkan suara jika pose berubah | |
| if (lastPlayedPose !== className) { | |
| playAudio(className); | |
| } | |
| } else { | |
| element.classList.remove("active-pose"); | |
| } | |
| } | |
| drawPose(pose); | |
| } | |
| function playAudio(poseName) { | |
| const soundKey = poseName.toLowerCase(); | |
| if (sounds[soundKey]) { | |
| // Stop suara lain yang sedang main (opsional) | |
| Object.values(sounds).forEach(s => { | |
| s.pause(); | |
| s.currentTime = 0; | |
| }); | |
| // Putar suara baru | |
| sounds[soundKey].play().catch(e => console.log("Izin audio diperlukan")); | |
| lastPlayedPose = poseName; | |
| // Reset 'lastPlayedPose' setelah 3 detik diam agar bisa bunyi lagi | |
| clearTimeout(silenceTimer); | |
| silenceTimer = setTimeout(() => { | |
| lastPlayedPose = ""; | |
| }, 3000); | |
| } | |
| } | |
| function drawPose(pose) { | |
| if (webcam.canvas) { | |
| ctx.drawImage(webcam.canvas, 0, 0); | |
| if (pose) { | |
| const minPartConfidence = 0.5; | |
| tmPose.drawKeypoints(pose.keypoints, minPartConfidence, ctx); | |
| tmPose.drawSkeleton(pose.keypoints, minPartConfidence, ctx); | |
| } | |
| } | |
| } | |
| </script> | |
| </body> | |
| </html> |